Pytorch实现Dataset数据集导入 必要性解释及代码实操

初学者学习Pytorch系列

第一篇 Pytorch初学简单的线性模型 代码实操
第二篇 Pytorch实现逻辑斯蒂回归模型 代码实操
第三篇 Pytorch实现多特征输入的分类模型 代码实操
第四篇 Pytorch实现Dataset数据集导入 必要性解释及代码实操



前言

  1. 本文在第三篇文章的数据基础上,加上Dataset的数据导入功能。并阐述了为什么使用Dataset及代码实操。

一、先上代码

代码如下(解释已经写在代码中):

import numpy as np
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("../data/diabetes.csv.gz")
train_loader = DataLoader(dataset=dataset, shuffle=True, batch_size=32, num_workers=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.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")
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

if __name__ == '__main__':
    for epoch in range(100):
        for i, data in enumerate(train_loader, 0):
            inputs, labels = data	# 这里获取就是我们定义的getitem函数
            y_pred = model(inputs)
            loss = criterion(y_pred, labels)
            print(epoch, i, loss.item())
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()



二、必要性解释

首先,要认识到深度学习使用到的三种基本的样本学习方式

1. 批量梯度下降(Batch Gradient Descent)

此方式是在每一个epoch的学习中,使用所有的样本进行计算loss,求平均值进行更新。

优点:可以使用电脑CPU或GPU的并行计算能力,速度较快
缺点:训练出的模型性能可能没有随机梯度下降训练出来的好

2. 随机梯度下降(Stochastic Gradient Descent)

此方式是在每一个epoch的学习中,在对每一个样本计算完loss的时候,就进行参数的迭代更新。

优点:训练出的模型性能比较好,可以跨越训练中的鞍点(函数到达鞍点处,梯度为零,可能一直处在鞍点附近,没有到达最优点)
缺点:训练速度较慢,因为每一次只有一个样本

3. 小批量梯度下降(Mini-batch Gradient Descent)

此方式是在每一个epoch的学习中,对本一定数量的样本计算loss,进行参数的迭代更新。即epoch中多次迭代,但是迭代次数没随机梯度下降多。

优点:能更好地兼顾随机梯度下降和梯度下降的优点

三、代码编写

  1. 首先我们要从torch.utils.data导入Dataset、DataLoader这两个类,Dataset是一个抽象类,需要作为父类被继承。
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类,需要编写以上三个魔法方法,以便后面配合DataLoader的使用。

  1. 实现DataLoader类
train_loader = DataLoader(dataset=dataset, shuffle=True, batch_size=32, num_workers=2) 

在使用DataLoader类的时候,需要传入我们已经实现的dataset类,作为输入。

  • shuffle表示是否在每一轮epoch训练中,要不要对训练集进行随机排列打乱==(不打乱的情况下,模型学到的可能只是数据次序,并未学到有用的信息,比如数据进行了排序,可能会导致模型在分类问题中,一会过拟合这个类别,一会过拟合那个)==
  • batch_size代表mini-batch的大小,为自定义数值
  • num_workers是加载数据(batch)的线程数目(可参考下面文章)
  • num_workers线程
  1. 文中在epoch循环前加上了if name == ‘main’:
    这是因为window和Linux系统多进程的不同,DataLoader在window中运行需要包裹起来,所以使用上面的语句。

  2. 下面的代码变化不大,新手对python不熟悉,可能会对for i, data in enumerate(train_loader, 0): 这个循环不太理解,其实i代表就是轮数,这是python枚举的语法

四、疑问

小批量体现在哪?

我们在代码中让每一个epoch中,每一个DataLoader训练输出loss损失。

print(epoch, i, loss.item())

结果如下:

0 0 0.6875641345977783
0 1 0.6793625950813293
0 2 0.6869551539421082
0 3 0.691533625125885
0 4 0.6870102286338806
0 5 0.6823495626449585
0 6 0.6845288872718811
0 7 0.6837712526321411
0 8 0.681125819683075
0 9 0.6887457370758057
0 10 0.683203399181366
0 11 0.6830952167510986
0 12 0.6772065162658691
0 13 0.6679650545120239
0 14 0.6759853363037109
0 15 0.6785972118377686
0 16 0.6714340448379517
0 17 0.6844414472579956
0 18 0.6739678382873535
0 19 0.6733191013336182
0 20 0.6691502928733826
0 21 0.6798030734062195
0 22 0.6758182644844055
0 23 0.6541876792907715
1 0 0.6665661334991455
1 1 0.6571947932243347
1 2 0.6955416202545166
1 3 0.6735390424728394
1 4 0.6644106507301331
1 5 0.6822395324707031
1 6 0.6772632002830505
1 7 0.663568377494812
1 8 0.662426233291626
1 9 0.6763331890106201
1 10 0.6614290475845337
1 11 0.6709282398223877
1 12 0.6913875937461853
1 13 0.6553581357002258
1 14 0.6650232076644897
1 15 0.6750929951667786
1 16 0.6478442549705505
1 17 0.6746488809585571
1 18 0.6802167296409607
1 19 0.6801486611366272
1 20 0.6685871481895447
1 21 0.6740914583206177
1 22 0.6854969263076782
1 23 0.6770240068435669

是不是觉得为什么只有23轮?我们不是在DataLoader中设置了32轮吗?
这是因为我们使用小批量梯度下降,DataLoader已经帮我们分好组了,打开我们的数据集会发现有759条数据,batch_size为32,759/32=23.7,所以从0-23,有24个分组,每组DataLoader都帮我们分好了,它内部是用一组数据去计算的。


总结

以上就是今天要讲的内容,介绍了pytorch实现Dataset。讲解过程属于个人理解,如表述有误,请谅解。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值