DataLoader 和 Dataset
神经网络训练的第一步往往是数据集的加载和处理,当然,我们可以自己手动完成,但这也往往给我们带来了诸多的不便,尤其是当数据集比较大的时候,比如shuffle操作,batch操作等等,甚至更加高级的图片预处理操作。
幸运的是,pytorch为我们提供了用于数据加载和处理的DataLoader和Dataset类,Dataset是一个包装类,用来将数据包装为Dataset类,然后传入DataLoader中,我们再使用DataLoader这个类来更加快捷的对数据进行操作。DataLoader是另一个比较重要的类,它为我们提供的常用操作有:batch_size(每个batch的大小), shuffle(是否进行shuffle操作), num_workers(加载数据的时候使用几个子进程)。
下面,我们就以mnist为例,演示一下如何使用这两个类进行自定义数据集的加载。
将数据包装成Dataset类
要使用Dataset类对数据集进行封装,你需要自己定义一个class,里面至少包含3个函数:
init:传入数据,或者像下面一样直接在函数里加载数据
len:返回这个数据集一共有多少个item
getitem:返回一条训练或测试数据,并将其转换成tensor
具体代码如下:
class MNIST_DATASET(Dataset):
def __init__(self):
path=".\mnist.npz"
f=np.load(path)
train_X, train_y = f['x_train'], f['y_train']
f.close()
train_X = train_X.astype('float32')
train_X /= 255
train_y = train_y.astype('int64')
self.image= torch.from_numpy(train_X.reshape(-1,1,28,28))
self.label= torch.from_numpy(train_y)
def __getitem__(self, index):
image=self.image[index]
label=self.label[index]
return image,label
def __len__(self):
return len(self.label)
class TEST_DATASET(Dataset):
def __init__(self):
path=".\mnist.npz"
f=np.load(path)
test_X, test_y = f['x_test'], f['y_test']
f.close()
test_X = test_X.astype('float32')
test_X /= 255
test_y = test_y.astype('int64')
self.image= torch.from_numpy(test_X.reshape(-1,1,28,28))
self.label= torch.from_numpy(test_y)
def __getitem__(self, index):
image=self.image[index]
label=self.label[index]
return image,label
def __len__(self):
return len(self.label)
dataloader的使用
主要的参数包括
dataset:传入的数据,也就是我们上边写的Dataset类
shuffle = True:是否打乱数据
batch_size:batch大小
等等
下面是本代码使用dataloader的一个例子:
train_dataset=MNIST_DATASET()
test_dataset=TEST_DATASET()
trainloader=DataLoader(train_dataset, batch_size=32,shuffle=True)
testloader=DataLoader(test_dataset, batch_size=32,shuffle=True)
在训练中加载数据集
for epoch in range(4):
for i,data in enumerate(trainloader):
x,y=data
x=x.to('cuda')
y=y.to('cuda')
out = net(x)
loss = F.cross_entropy(out, y) # 计算两者的误差
optimizer.zero_grad() # 清空上一步的残余更新参数值
loss.backward() # 误差反向传播, 计算参数更新值
optimizer.step() # 将参数更新值施加到 net 的 parameters 上
train_loss.append(loss.item())
if i % 10 == 0:
print(epoch, i, np.mean(train_loss))
train_loss=[]
使用torchversion.transforms对数据进行预处理
除了上面的Dataset和Dataloader之外,我们还可以使用torchversion中的transforms对数据进行预处理,下面是一些典型的例子。
# 我们这里还是对MNIST进行处理,初始的MNIST是 28 * 28,我们把它处理成 96 * 96 的torch.Tensor的格式
from torchvision import transforms as transforms
import torchvision
from torch.utils.data import DataLoader
# 图像预处理步骤
transform = transforms.Compose([
transforms.Resize(96), # 缩放到 96 * 96 大小
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 归一化
])
DOWNLOAD = True
BATCH_SIZE = 32
train_dataset = torchvision.datasets.MNIST(root='./data/', train=True, transform=transform, download=DOWNLOAD)
train_loader = DataLoader(dataset=train_dataset,
batch_size=BATCH_SIZE,
shuffle=True)
print(len(train_dataset))
print(len(train_loader))