(课程笔记)深度学习入门 - 8 - DataLoader
一、DataLoader背景知识与概念
定义:DataLoader是 PyTorch 提供的一个数据加载器,用于对数据进行批量加载和处理。它在训练神经网络时起到了重要的作用。它存在于 torch.utils.data 包下,需要的时候应该在该包下导入DataLoader。
问题1:为什么需要DataLoader?
神经网络的训练过程通常需要大量的数据,而将所有数据一次性加载到内存中是不可行的。这时候就需要使用 DataLoader 将数据分成小批次进行加载。DataLoader 可以自动完成数据的批量加载、随机洗牌(shuffle)、并发预取等操作,从而提高模型训练的效率。
问题2:DataLoader有什么特点?
(1)批处理: DataLoader 可以将数据分成小批次进行加载,从而使得每次迭代都能处理多个数据样本。
(2)随机洗牌(shuffle): DataLoader 具有随机洗牌功能,可以在每个迭代之前将数据顺序打乱,从而减少模型对输入数据的依赖性。
(3)并发预取(prefetching): DataLoader 可以使用多线程或多进程来提前预取数据,充分利用 CPU 的性能,加速数据加载过程。
(4)方便的数据转换: DataLoader 可以通过自定义的数据转换函数对原始数据进行预处理,如裁剪、缩放、标准化等。
二、DataLoader的参数设计
1、DataLoader 的常用参数
dataset
: 指定数据集,通常是 torch.utils.data.Dataset
类的实例。
batch_size
: 每个批次的样本数量。
shuffle
: 是否对数据进行洗牌操作。
num_workers
: 加载数据时的并发线程或进程数。
drop_last
: 当数据样本数量不能被批次大小整除时,是否丢弃最后一个不完整的批次。
collate_fn
: 自定义的数据处理函数,用于将多个样本汇集到一个批次中。‘’
2、DataLoader的参数设计建议
在调整 DataLoader 的参数时,需要根据具体问题和数据集的特点进行考虑。以下是一些常见的调整方法:
(1)batch_size
:根据可用内存和模型的需求,增加或减少批次大小。较大的批次大小可以提高训练速度,但也可能会增加内存占用。
(2)shuffle
: 是否进行随机洗牌:对于训练数据,通常会设置为 True来减少模型对输入数据顺序的依赖性。对于验证和测试数据,通常会设置为False。
(3)num_workers
:根据计算机硬件的配置和数据加载的速度来设置,并发加载数据以加快训练速度。但是,过多的并行加载也可能会导致性能下降,因此需要进行适当的调整。
(4)drop_last
:默认情况下, DataLoader 不会丢弃最后一个不完整的批次。但是,在内存有限的情况下,如果内存无法容纳一个完整的批次,可以将 drop_last
设置为 True,丢弃最后一个不完整的批次。
三、用DataLoader实现神经网络训练
0、导包
import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
1、准备数据集与DataLoader
class DiabetesDataset(Dataset):
# DiabetesDataset类继承自torch.utils.data.Dataset
# 重写了__init__、__getitem__和__len__方法。
# 1、__init__方法:它加载了名为"diabetes.csv.gz"的数据文件
# 并将数据划分为输入特征(x_data)和目标标签(y_data)。
# x_data是除最后一列之外的所有列,y_data是最后一列。
# 同时,它还记录了数据集的长度。
# 2、__getitem__方法:用于获取指定索引的样本,返回的是该索引
# 处的输入特征和目标标签。
# 3、__len__方法:返回数据集的长度。
def __init__(self, filePath):
xy_data_set = np.loadtxt(filePath, delimiter=',', dtype=np.float32)
self.len = xy_data_set.shape[0]
self.x_data = torch.from_numpy(xy_data_set[:, :-1])
self.y_data = torch.from_numpy(xy_data_set[:, [-1]])
def __getitem__(self, index):
return self.x_data[index], self.y_data[index]
def __len__(self):
return self.len
# 最后,在创建了DiabetesDataset对象后,使用DataLoader对数据集
# 进行批处理,每批大小为32,打乱顺序,并开启2个工作进程。
dataset = DiabetesDataset("diabetes.csv.gz")
train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=2)
要使用DataLoader去训练神经网络,首先要构建一个类,让这个类继承至Dataset,在这个类中重写3个方法,分别是:init,getitem,len。它们的作用分别是:
(1)init:初始化代码,给定数据集的filePath,可以进行输入和输出的切割操作,并且记录了这个数据集有多少行,即:有多少个样本;
(2)getitem:主要是返回指定index处的输入特征以及输出标签值
(3)len:主要是返回数据集的样本数
完成类的编写后,利用其构造器,传入数据集的文件路径,生成一个Dataset的实例化对象,此时开始生成DataLoader对象,利用DataLoader类的构造器,传入代表数据集的变量(dataset=?),传入批量处理数据的容量(batch_size=?),决定是否打乱数据集的数据内容(shuffle=?),设置并行线程数量(num_workers=?),这样我们就得到了一个DataLoader对象,并已经设置好了它的参数。
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))
y_pred = self.sigmoid(self.linear3(x))
return y_pred
model = Model()
3、创建损失函数和优化器
BCE_Loss = torch.nn.BCELoss(reduction="mean")
SGD_optm = torch.optim.SGD(model.parameters(), lr=0.03)
4、开始训练
if __name__ == '__main__':
epochs = 100
# 设定训练的总轮数(epoch),每个epoch表示将整个数据集完整地通过模型一次。
for epoch in range(epochs):
# 使用enumerate函数遍历train_loader中的每个批次数据。
# enumerate(train_loader, 0)的返回结果是一个可迭代对象iteration
# 每次迭代会返回一个元组(index, dataTuple),其中包含了索引和对应的数据元组。
# i表示当前批次的索引,data包含当前批次的输入特征和目标标签。(索引从0开始)
for i, data in enumerate(train_loader, 0):
x_data, y_label = data
y_predict = model(x_data)
loss = BCE_Loss(y_predict, y_label)
print(f"Epoch = {epoch+1}, Part = {i}, Loss = {loss.item()}")
SGD_optm.zero_grad()
loss.backward()
SGD_optm.step()
这里需要注意的是:我们准备训练100轮,一轮训练32个试验数据,共计会训练3200个样本用于训练模型,循环开始时,我们需要用enumerate()函数把第一批得到的32个样本进行拆解,该函数需要传入一个DataLoader,再传入一个初始索引值,即:enumerate(train_loader , 0)。
传入参数后,该函数会返回2个结果,第一个是index值(本节初始index为0),第二个是data元组,里面包含了这一批量样本的输入特征与输出标签值,所以要用 x_data 和 y_label 来接收这个元组中的数据。
接收到数据后,就可以开始训练模型,以及计算损失函数了。
更多推荐
所有评论(0)