本次我们要学会使用DataLoader数据加载器来对数据集进行mini_batch批处理,这样可以防止过拟合,以便有更好的泛化能力。
几个名词的解释:
epoch:指的是一次性训练全部样本的次数
total_size:全部的样本数
batch_size:指的是将全部样本分批训练,一批中的样本数
total_batch:指的是将全部样本分为多少批
来看下面这个例子:
total_size = 10000 有10000个样本,batch_size = 1000 将10000个样本分批,一批数据中有1000个样本,那么批数=total_batch=total_size/batch_size。那么将这10000个全部样本训练的次数就叫作epoch。
DataLoader(torch.utils.data.DataLoader)
DataLoader可以对数据进行分批,指定数据集的batch_size,并且可以随机打乱数据集。但是它所处理的数据集必须是torch.utils.data.Dataset的子类,并且实现三个魔法方法,分别是__init__(),__getitem(),__len__()。这样我们才可以对这个数据集采用数据加载器进行批处理操作。
因此,使用DataLoader时,我们必须先使数据集成为torch.nn.data.Dataset的子类。
代码如下:(非自带数据集)
import matplotlib.pyplot as plt
import numpy as np
import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import torch.nn.functional as F
# 1.准备数据集
# 实现Dataset的子类,并重写三个魔法方法,这样DataLoader才可以使用
class DiabetesDataset(Dataset):
def __init__(self, filepath):
x_y = np.loadtxt(filepath, delimiter=',', dtype=np.float32)
# 转化为张量
self.x_data = torch.from_numpy(x_y[:, :-1])
self.y_data = torch.from_numpy(x_y[:, [-1]])
self.len = x_y.shape[0]
# 获取第item个样本
def __getitem__(self, item):
return self.x_data[item], self.y_data[item]
# 获取总的样本数
def __len__(self):
return self.len
# 实现加载器
dataset = DiabetesDataset('../dataset/diabetes.csv.gz')
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=2)
还有一点要注意的就是在训练时是两层for循环嵌套,外循环是epoch训练全部样本的次数,内循环是训练一次全部样本的批次数。
代码的总步骤还是四步:
- 准备数据集
- 实现模型类
- 构造损失函数的优化器
- 训练周期
总的代码如下:
import matplotlib.pyplot as plt
import numpy as np
import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
import torch.nn.functional as F
# 1.准备数据集
# 实现Dataset的子类,并重写三个魔法方法,这样DataLoader才可以使用
class DiabetesDataset(Dataset):
def __init__(self, filepath):
x_y = np.loadtxt(filepath, delimiter=',', dtype=np.float32)
# 转化为张量
self.x_data = torch.from_numpy(x_y[:, :-1])
self.y_data = torch.from_numpy(x_y[:, [-1]])
self.len = x_y.shape[0]
# 获取第item个样本
def __getitem__(self, item):
return self.x_data[item], self.y_data[item]
# 获取总的样本数
def __len__(self):
return self.len
# 实现加载器
dataset = DiabetesDataset('../dataset/diabetes.csv.gz')
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=2)
# 2.实现模型类
# 这里不同的看第七讲作业
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = torch.nn.Linear(8, 6)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 1)
self.active = torch.nn.ReLU()
def forward(self, x):
x = self.active(self.linear1(x))
x = self.active(self.linear2(x))
x = F.sigmoid(self.linear3(x))
return x
# 3.构建损失函数和优化器
model = Model()
criterion = torch.nn.BCELoss(size_average=True)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
if __name__ == '__main__':
# 4.训练
epoch = 100 # 训练全部样本的次数
loss_list = []
for i in range(epoch):
# 全部样本分批的次数,train_loader会一批一批地分好
for idx, (inputs, labels) in enumerate(train_loader, 0):
# 正向
y_pred = model(inputs)
loss = criterion(y_pred, labels)
# 反向
optimizer.zero_grad()
loss.backward()
# 更新
optimizer.step()
print(f'epoch={i},batch={idx},loss={loss.item()}') # 输出第i次训练的第idx批的损失
loss_list.append(loss.item())
# 画图
plt.plot(np.arange(epoch), loss_list)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
损失图像如下图:
对torchvision.datasets自带数据集使用DataLoader数据加载器:
对torchvision.datasets中自带的数据集使用数据加载器DataLoader, 因为torchvision.datasets中的数据集本身是torch.utils.data.Dataset的子类,所以我们不需要继承Dataset重写那三种魔法就可以直接使用DataLoader
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision.datasets import MNIST
# 1.准备数据集
# 实现加载器
# # 这里我们使用MNIST手写数字识别,transform=transforms.ToTensor() 转换为张量
dataset_train = MNIST(root='../dataset/mnist', train=True, transform=transforms.ToTensor(), download=True)
train_loader = DataLoader(dataset=dataset_train, batch_size=128, shuffle=True, num_workers=2)
print(type(train_loader)) # <class 'torch.utils.data.dataloader.DataLoader'>
数据集链接:https://pan.baidu.com/s/14Gotj40NxzC1dM1reAfMlw
提取码:pig1