watch: PyTorch - 刘二 08 | Load Datasets

工具类:

Dataset 用于构造数据集,可以用索引取出数据

DataLoader: 取出一个 mini-batch,做训练

“Batch” 是把全部数据输入神经网络,计算预测值,这样可以充分发挥向量计算的并行性,速度很快,但是可能到达鞍点,无法继续训练。可以利用数据的噪声避免停留在鞍点上,从而达到全局最优,所以需要1个样本,1个样本地计算,叫作随机梯度下降SGD,性能较好但是训练时间太长。所以采用 “mini-batch” 来平衡速度和性能。(通常把mini-batch叫做batch)

Epoch: 训练轮数,所有的样本都做过一次前馈和反馈

Batch-size: 每次训练使用的样本量,经过一次前馈、反馈和更新

Iteration:迭代次数,分了几个batch

DataLoader: 对支持索引,支持获取其长度的数据集进行加载,生成一个 iterable loader, 对数据分组,每次迭代给出一个batch的X和y,并自动转换成Tensor。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import torch 
from torch.utils.data import Dataset #抽象类,不能实例化,只能被它的子类继承
from torch.utils.data import DataLoader #加载, 划分数据

class DiabetesDataset(Dataset): #自定义的类继承自Dataset
    def __init__(self):
        pass            #
    def __getitem__(self, index):   #使对象支持下标操作,根据索引返回数据
        pass

    def __len__(self):  #返回数据集的条数
        pass

dataset = DiabetesDataset() #实例化数据集,支持索引数据和获取长度

train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=2)  #实例化加载器, 洗牌使每次epoch的数据都不一样,使用2个并行进程读取数据

加载数据有两种方式,如果数据量小,直接把所有的数据加载进内存,之后使用getitem读取;当数据集很大时,需要将其拆分成小文件,在__init__方法中初始化列表,把小文件名放入列表中;有时标签也很大,比如对图片的每个像素预测语义信息,y的维度与x相同,所以也需要拆分,文件名放入列表。在需要使用某数据的时候,用__getitem__方法读取。

pytorch 0.4中出现一个问题:由于windows 和 linux的多进程库不同,spawn与fork不同。Windows下需要把迭代的loader封装起来,不能直接“顶格”写

1
2
3
4
5
6
train_loader = DataLoder(...)

if __name__ == '__main__':
    for epoch in range(100):
        for i, data in enumerate (train_loader, 0):
            ...

加载糖尿病数据集:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import numpy as np
import torch 
from torch.utils.data import Dataset, 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__():
        return self.len

data = DiabetesDataset('diabetes.csv.gz')

train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=2)


for epoch in range(100):
    for i, data in enumerate(train_loader, 0):  #迭代加载器,enumerate获得第几次迭代,x和y的元组放入data
        inputs, labels = data   #取出样本和标签
        y_pred = model(inputs)  #计算预测值
        loss = criterion(y_pred, labels)    #计算损失
        optimizer.zero_grad()   #梯度清零
        loss.backward()         #反向传播
        optimizer.step()        #更新梯度