数据加载器
简介
数据说深度学习的基础,我们解决的大多数深度学习问题都是需要数据的. 而每一种深度学习框架都对数据格式有自己的要求.因此, 本节我们主要讲解PyTorch对输入数据的格式要求,以及如何将现实中的数据处理成yTorch能够识别的数据集合.
技能点:
- 数据的分批
- 手写字符数据的分批
- 葡萄酒数据的分批
数据的分批
由于深度学习中的数据量一般都是极大的,我们无法一次性将所有数据全部加载到内存中.音痴在模型训练之前,一般我们都会对训练集进行分批,将数据随机分成等量的几份, 每次迭代只训练一份
# 循环训练
for epoch in range(num_epochs):
# 遍历所有批次的数据
for i in range(total_batches):
从上面的伪代码可以会看出:
- epoch 每增加一次,表示完成了所有数据的一次正向传播和反向传播
- total_batches表示分批后的数据集合
- i 每增加一次,表示完成了一批数据的一次正向传播和反向传播
那么如何对数据集合进行分批呢? 我们可以自己尝试编写数据分批的代码.
当然, PyTorch中也为我们提供了相应的接口, 我们可以很容易的实现数据分批的过程. PyTorch为我们提供了torch.utils.data.DataLoader加载器, 该加载器可以自动的将传入的数据进行打乱和分批.
DataLoader()的加载参数如下:
- dataset: 需要打乱的数据集
- batch_size: 每一批数据条数
- shuffle: True或者False, 表示是否将数据打乱后再分批
当然利用该加载器并不仅仅是对数据进行打乱和分批的操作,该加载器还可以对数据进行格式化处理,使其能够被放入后面的神经网络模型中.
接下来, 让我们首先利用该加载器对PyTorch中自带的数据集合MNIST进行分批操作
MNIST的分批
首先让我们加载PyTorch中自带的数据集合,该数据集合存在于torchvision.datasets中, 可以直接利用torchvision.datasets.MNIST获得:
import torch
import torchvision
# 将数据集合下载到指定的目录下
train_dataset = torchvision.datasets.MNIST(root="./data",
train=True,
transform=torchvision.transforms.ToTensor(),
download=False)
print(train_dataset)
显示其中的一条数据看一下
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
data,label = train_dataset[0]
print("第一个数据对应的标签名称:",label)
# 原始数据是归一化后的数据,因此这里需要反归一化
img = np.array(data)*255
img = img.reshape(28,28).astype(np.uint8)
plt.imshow(img,"gray")
plt.show()
该数据集合的分批步骤很简单, 只需要将我们得到的数据集合传入DataLoader中即可:
from torch.utils.data import DataLoader
train_loader = DataLoader(dataset=train_dataset, batch_size=100, shuffle=True)
num_epochs = 1 # 迭代次数
for epoch in range(num_epochs):
for i, (inputs, labels) in enumerate(train_loader):
# 每 10 个批次展示一次
if (i+1) % 10 == 0:
print(
f'Epoch: {epoch+1}/{num_epochs},Step {i+1}/{len(train_dataset)/100}| Inputs {inputs.shape} | Labels {labels.shape}')
如上所示, 我们对MNIST数据集合进行分批, 且利用循环对其进行了遍历. 在模型训练时, 我们将内循环中的代码换乘模型训练的代码即可.
在DataLoader传入的参数值, 我们需要注意的是dataset参数.该参数是一个Dataset类,即只有继承了PyTorch中的Dataset接口的类,才能够被传入DataLoader中
因此, 针对我们自己的数据集合,我们就需要封装一个继承了Dataset的Python类. 这样, 我们才能够将其传入PyTorch之中, 进行数据的分批和模型的训练.
接下来, 我们再以葡萄酒的种类预测为例, 详细的阐述自定义数据应当如何进行封装和分批.
葡萄酒数据的分批
首先,我们先加载数据集合
import pandas as pd
df = pd.read_csv("./wine.csv")
第一列表示该条数据属于哪一种葡萄酒(0,1,2。而后面 13 列的数据表示的就是葡萄酒的每种化学成分的浓度。这些化学成分分别为:酒精 、苹果酸 、灰分 、灰分的碱度、镁 、总酚、 黄酮类化合物 、非类黄酮酚 、原花色素 、颜色强度 、色相 、稀释酒的 OD280/OD315 和脯氨酸
我们需要对这些数据进行分批, 那么我们就需要将该数据转为PyTorch认识的数据集合. 我们可以建立一个类WineDataset去继承Dataset
如果继承了Dataset类, 我们就必须实现下面三个函数:
__init__(self)
: 用于初始化类中所需要的一些变量__len__(self)
: 返回数据集合的长度, 即数据量大小__getitem__(self, index)
: 返回第index条数据
from torch.utils.data import Dataset
class WineDataset(Dataset):
# 建立一个数据集合
def __init__(self):
xy = pd.read_csv("./wine.csv")
self.n_samples = xy.shape[0]
# 将pandas类型的数据转换为numpy类型
self.x_data = torch.from_numpy(xy.values[:,1:])
self.y_data = torch.from_numpy(xy.values[:,[0]])
def __getitem__(self, index):
return self.x_data[index], self.y_data[index]
def __len__(self.n_samples)
return self.n_samples
至此,我们就将葡萄酒的数据包装成了Dataset,使用PyTorch能够识别出该数据集合.接下来, 我们只需要利用DataLoader加载该数据集合即可:
# 使用DataLoader去加载数据集合
from torch.utils.data import DataLoader
import math
# 传入加载器
train_loader = DataLoader(dataset=wineData,batch_size=4,shuffle=True)
# 分批训练
# 迭代次数
epoch_num = 5
total_samples = len(wineData)
print("total_samples:",total_samples)
# 开始训练
for epoch in range(epoch_num):
for i,(inputs,labels) in enumerate(train_loader):
print(i,labels)
从结果可以看出, 我们按照每个批次的batch_size, 将数据分成了45个批次, 并对这些数据进行了2次迭代. 由于数据总量不是batch_size的整数倍,因此最后一个批次的数据是有余数的
小结
本节主要阐述了数据分批的重要性.并以手写字符数据集合葡萄酒数据集为例, 阐述了如何将一个数据集合转成PyTorch能够使用的数据集