目录
本讲介绍
上讲回顾
mini-batch中的概念
DataLoader功能
代码框架分析
例子:糖尿病代码分析
准备数据集
训练过程部分:
整个架构
本讲介绍
用于加载数据的两个工具类:
Dataset:构造数据集,支持索引
DataLoader:主要目标是拿出Mini-Batch,在训练时能快速使用
上讲回顾
从两个方面考虑:
- 运算速度,能否利用GPU并行计算的能力
- 有无随机性,能否利用随机性跨越鞍点,使优化的性能更好
上讲使用的糖尿病数据集,在做前馈时将所有数据都放进去了,即Batch。1√,2×
如果使用随机梯度下降SGD(权重的更新公式中只使用一个样本)。1×,2√
所以为了均衡性能和训练时间,以后采用mini-batch

mini-batch中的概念
一个epoch:所有训练样本都进行了一次前馈和一次反馈
batch-size:每次训练(一次前馈 一次反馈 一次更新)时所用的样本数量
iterations:所有样本数 ➗ batch-size

DataLoader功能

代码框架分析
- Dataset是一个抽象类,不能实例化对象,我们从这个类中继承,定义自己的类。
- __init__函数中处理数据,有两种方式,当数据量小的时候可以全加载进来,都读在内存中;当数据集很大(如图像数据集有几十G时),可以将其打包在py文件中,在此处只做初始化,定义一些读写(搞个列表,里面写文件名 标签名)等等
- DataLoader可实例化对象。DataLoader is a class to help us loading data in Pytorch.
- DataLoader 需要获取DataSet提供的索引[i]和len;用来帮助我们加载数据,比如说做shuffle(提高数据集的随机性),batch_size(拿出Mini-Batch进行训练)。它帮我们自动完成这些工作。
- __getitem__目的是为支持下标(索引)操作,这是一个魔法方法
- num_workers 是读数据集时是否需要并行化(多线程)

__init__函数中的两种数据集读取形式

windows操作系统中,pytorch 0.4版本下会报错,解决办法是把代码封装起来。


例子:糖尿病代码分析
准备数据集
- 由于数据集很小,把所有数据都加载在内存中了,属于前文提到的第一种方式。
- xy.shape 输出(759, 9) shape[0]输出759
- 用DataLoader来构造加载器,取名为train_loader
- 这里从trainloader拿出来的就是Dataset里面自己实现的__getitem__的返回值。每次得到的是x[i] 和 y[i] ,dataloader根据参数batch_size将它们一条条排成矩阵后,自动转换为Tensor格式

训练过程部分:
- enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。Python enumerate() 函数 | 菜鸟教程 (runoob.com)
- 这里从trainloader拿出来的就是Dataset里面自己实现的__getitem__的返回值。每次得到的是x[i] 和 y[i] ,dataloader根据参数batch_size将它们一条条排成矩阵后,自动转换为Tensor格式
- 这样就用了mini-batch!!!!哈哈哈

整个架构
还是四步,2、3部分没改
这样就比较标准的完成了用神经网络对糖尿病数据集进行分类的程序

torchvision还提供了很多别的数据集,mnist数据集的dataset讲解,需要到时候再来看
PIL Image --> Tensor,用到transform.ToTensor()


代码
import torch
import numpy as np
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
'''
Dataset是一个抽象函数,不能直接实例化,所以我们要创建一个自己类,继承Dataset
继承Dataset后我们必须实现三个函数:
__init__()是初始化函数,之后我们可以提供数据集路径进行数据的加载
__getitem__()帮助我们通过索引找到某个样本
__len__()帮助我们返回数据集大小
'''
class DiabetesDataset(Dataset):
def __init__(self,filepath):
xy = np.loadtxt(filepath,delimiter=',',dtype=np.float32)
#shape本身是一个二元组(x,y)对应数据集的行数和列数,这里[0]我们取行数,即样本数
self.len = xy.shape[0]
self.x_data = torch.from_numpy(xy[:, :-1])
self.y_data = torch.from_numpy(xy[:, [-1]])
def __getitem__(self, index):
return self.x_data[index],self.y_data[index]
def __len__(self):
return self.len
#定义好DiabetesDataset后我们就可以实例化他了
dataset = DiabetesDataset('PyTorch_exercise\diabetes.csv.gz')
#我们用DataLoader为数据进行分组,batch_size是一个组中有多少个样本,shuffle表示要不要对样本进行随机排列
#一般来说,训练集我们随机排列,测试集不。num_workers表示我们可以用多少进程并行的运算
train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=0)
class Model(torch.nn.Module):
def __init__(self):#构造函数
super(Model,self).__init__()
self.linear1 = torch.nn.Linear(8, 6)#8维到6维
self.linear2 = torch.nn.Linear(6, 4)#6维到4维
self.linear3 = torch.nn.Linear(4, 1)#4维到1维
self.sigmoid = torch.nn.Sigmoid()#因为他里边也没有权重需要更新,所以要一个就行了,单纯的算个数
def forward(self, x):#构建一个计算图,就像上面图片画的那样
x = self.sigmoid(self.linear1(x))
x = self.sigmoid(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
model = Model()#实例化模型
criterion = torch.nn.BCELoss(reduction='mean')
#model.parameters()会扫描module中的所有成员,如果成员中有相应权重,那么都会将结果加到要训练的参数集合上
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)#lr为学习率
if __name__=='__main__':#if这条语句在windows系统下一定要加,否则会报错
for epoch in range(100):
for i,data in enumerate(train_loader,0):#取出一个batch
#prepare data
inputs,labels = data#将输入的数据赋给inputs,结果赋给labels
#Forward
y_pred = model(inputs)
loss = criterion(y_pred,labels)
print(epoch,i,loss.item())
#Backward
optimizer.zero_grad()
loss.backward()
#update
optimizer.step()作业是 在kaggle里用 Titanic数据集,用dataloader建分类器完成预测任务
Titanic - Machine Learning from Disaster | Kaggle
















