使用的Pytorch
包
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
Dataset
构造数据集DataLoader
拿出数据集中的Mini-Batch
基本概念
使用Mini-Batch
时,训练步骤要写成一个嵌套的循环
for epoch in range(training_epochs):
for i in range(total_batch):
每一次迭代为一个epoch
,在每一个epoch
中,要跑一层Mini-Batch
-
epoch
:当所有的训练样本,都进行了一次 前向传播和反向传播,即所有的样本都进行了一次训练,这个过程叫做一个epoch
-
Batch-Size
:每次训练时,所用的样本数量,即一次前馈、反馈、更新时所用的样本数量大小 -
Iteration
:指Batch
分成了多少个,即上述代码块内层循环了多少次例如一共10000个样本,每个
Batch
大小为1000,则Iteration
大小为10
具体使用
当Dataset
提供数据集,DataLoader
在知道索引和长度时,可以随机(指定参数shuffle=True
)在整个数据集中拿出来一个Mini-Batch
例如,当batch_size = 2, shuffle=True
时,
- 会先把数据集打乱,即
shuffle
操作 - 然后进行
batch
划分,生成一个可迭代的batch
,即loader
操作
每一次迭代过程中,给出的是一个batch
import torch
import torch.utils.data import Dataset
import torch.utils.data import DataLoader
## Dataset是一个抽象类 不能实例化 因此需要先继承Dataset 写一个他的子类
class DiabetesDataset(Dataset):
def __init__(self):
pass
def __getitem(self, index): # 魔法方法 能够支持下标操作
pass
def __len__(self): # 魔法方法 返回数据条数
pass
dataset = DiabetsDataset()
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True,num_workers=2)
在dataset
类里,一般有两种初始化方法
- 在
__init__()
里把数据集全部读入到内存里,适用于数据集本身容量不大的情况 - 当读取的数据集比较大时,例如图像的数据,会先将数据打包成文件,然后
__init__()
中初始化一个列表list
,将数据文件的信息(索引或者文件名)放在列表里。每次需要使用时,通过列表内存取的信息再去读取
dataloader
参数说明:
dataset
:给出数据集batch_size
:指定批量大小shuffle
:是否打乱数据集num_workers
:读取数据时是否需要多线程并行化
代码实现
以糖尿病分类的数据集为样例
import numpy as np
import matplotlib.pyplot as plt
import torch
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
########## 数据集的构建 ##########
class DiabetesDataset(Dataset):
def __init__(self, filepath):
xy = np.loadtxt(filepath, delimiter=',',dtype=np.float32)
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
dataset = DiabetesDataset('./dataset/diabetes.csv')
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)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 1)
self.sigmoid = torch.nn.Sigmoid()
self.activate = torch.nn.ReLU()
def forward(self, x):
x = self.activate(self.linear1(x))
x = self.activate(self.linear2(x))
x = self.sigmoid(self.linear3(x))
return x
model = Model()
########## 设置损失函数和优化器 ###########
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr = 0.01)
########## 模型训练 ##########
if __name__ == '__main__':
loss_history = []
epoch_history = []
for epoch in range(1000):
loss_iterations_history = []
for index, data in enumerate(train_loader, 0): # 使用enumerate 返回下标和值 追踪
inputs, labels = data # data是一个元组 (x, y)
## 前馈计算
y_pred = model(inputs)
loss = criterion(y_pred, labels)
print(epoch, index, loss.item())
loss_iterations_history.append(loss.item())
## 反向传播
optimizer.zero_grad()
loss.backward()
## 更新参数
optimizer.step()
epoch_history.append(epoch)
loss_history.append(np.mean(loss_iterations_history))
plt.plot(epoch_history, loss_history)
plt.xlabel('epoch')
plt.ylabel("loss")
plt.grid()
plt.show()
将
num_workers
设置为0时运行速度较快