DATASET
自定义 Dataset 类必须实现三个函数:init、len 和 getitem。
-
__init__
init 函数在实例化 Dataset 对象时运行一次
-
__len__
len 函数返回数据集中样本的数量。
-
__getitem__
getitem 函数加载并返回给定索引
idx
处的数据集样本。
DATALOADER
是在dataloader处写batch_size的大小。
Dataset
一次检索一个数据集特征和标签样本。在训练模型时,我们通常希望以“小批量”的形式传递样本,并在每个时期重新排列数据以减少模型过拟合,并使用 Python 的 multiprocessing
来加速数据检索。
1. Dataset
与 DataLoader
的配合
Dataset
:Dataset
是一个抽象类,代表整个数据集。它的主要职责是定义如何获取数据集中的一个样本。通常,Dataset
只返回一个样本(包括特征和标签),每次调用__getitem__()
方法时返回一个单独的数据点。Dataset
让你可以灵活地控制数据的读取方式,例如从文件中读取、应用数据增强等。DataLoader
:DataLoader
是一个帮助类,用于将Dataset
中的样本批量化,并提供对这些批次的迭代访问。DataLoader
接受一个Dataset
对象,并在此基础上执行以下操作:- 批量化:将
Dataset
中的样本按照指定的批大小(batch_size
)分成一个个批次。 - 随机打乱:在每个 epoch 开始时,可以随机打乱数据顺序,避免模型过拟合。
- 并行加载:使用多线程或多进程来并行加载数据,提高加载效率。
- 迭代器支持:
DataLoader
提供了对数据的迭代器访问方式,使得可以在训练循环中轻松地逐批次获取数据。
- 批量化:将
2. 为什么 Dataset
每次只返回一个样本
- 灵活性:
Dataset
设计成每次返回一个样本的方式,使得它具有高度的灵活性。你可以定义任意复杂的逻辑来获取单个样本,比如从磁盘读取、应用图像增强、甚至从多个来源组合数据。 - 解耦设计:
Dataset
的设计关注于如何获取单个样本,而不关心如何组织或处理这些样本。这种解耦设计使得Dataset
只需专注于样本的获取,简化了代码复杂度。 - 更容易实现自定义数据处理:对于不同的数据集和任务,你可能需要对数据进行特殊的处理。通过让
Dataset
返回单个样本,你可以在__getitem__()
中实现这些自定义处理,而不用担心批量处理的复杂性。
3. DataLoader
的作用
DataLoader
的出现是为了弥补 Dataset
的单样本返回方式,使得在训练模型时能够高效地处理数据。DataLoader
会在训练时:
- 将多个样本组合成一个小批量:这种方式能充分利用 GPU 的并行计算能力,提高训练速度。
- 并行处理数据加载:通过多线程或多进程加速数据加载,减少训练过程中的等待时间。
- 为训练循环提供数据:在训练循环中,
DataLoader
提供一个简单的方式去遍历整个数据集的所有小批量数据。
DataLoader
是一个可迭代对象,它在一个简单的 API 中为我们抽象了这种复杂性。
super()
是 Python 中用于调用父类(超类)的一个内置函数。它允许你在子类中调用父类的方法,而不需要显式地引用父类名。super()
函数通常用于在子类中扩展父类的方法。
super()
函数的语法如下:
super(type, obj)
type
是子类的类型。obj
是子类的实例。
在 super(NeuralNet, self).__init__()
中:
NeuralNet
是子类的名称。self
是子类的实例。
super()
函数的参数是可选的,如果省略,super()
会自动查找当前类和实例,并调用其父类的方法。因此,super(NeuralNet, self).__init__()
可以简化为 super().__init__()
。
在深度学习中,将模型和数据移动到GPU上进行计算可以显著提高训练和推理的速度。以下是一些常见的场景和时机,可以将模型和数据移动到GPU上:
-
模型初始化时:
-
在创建模型实例后,可以使用
.to(device)
方法将模型移动到GPU上。例如:model = NeuralNet(input_size, hidden_size, num_classes) model.to(device)
-
这一步确保了模型的所有参数(权重和偏置)都在GPU上,以便在后续的训练过程中利用GPU进行计算。
-
-
数据加载时:
-
在加载数据时,可以使用
.to(device)
方法将数据移动到GPU上。例如,在PyTorch中,可以使用DataLoader
加载数据,并在数据加载时将数据移动到GPU上:dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True) for inputs, labels in dataloader: inputs = inputs.to(device) labels = labels.to(device) # 在这里进行前向传播、损失计算和反向传播等操作
-
这一步确保了输入数据和标签都在GPU上,以便在后续的计算过程中利用GPU进行计算。
-
-
模型推理时:
-
在进行模型推理(即预测新数据)时,通常也需要将输入数据移动到GPU上。例如:
inputs = inputs.to(device) outputs = model(inputs)
-
这一步确保了输入数据在GPU上,以便在后续的前向传播过程中利用GPU进行计算。
-
注意事项:
- 确保在运行代码之前,已经正确安装了支持GPU的深度学习框架(如PyTorch)。
- 确保在代码中定义了
device
变量,并且该变量已经正确设置为'cuda'
,以便将模型和数据移动到GPU上。 - 在进行模型推理时,通常不需要将模型移动到GPU上,因为模型已经在训练过程中在GPU上进行了优化。
是的,优化器通常需要访问模型的所有参数,以便在训练过程中更新这些参数。在PyTorch中,优化器通过 model.parameters()
方法获取模型的所有参数。
使用优化器,需要传递被优化的参数
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
在这个例子中,model.parameters()
返回模型的所有参数,包括权重和偏置。这些参数将被传递给优化器,以便在训练过程中进行更新。
为什么需要所有参数
- 参数更新:优化器的目标是通过调整模型参数来最小化损失函数。为了实现这一目标,优化器需要访问所有参数,以便在每次迭代中更新它们。
- 梯度计算:在反向传播过程中,需要计算损失函数对每个参数的梯度。优化器需要访问所有参数,以便计算和更新它们的梯度。
注意事项
- 确保在创建优化器时,传递给
model.parameters()
的参数是模型的所有参数。如果只传递部分参数,优化器将无法更新这些参数。 - 如果模型中包含多个子模块,可以使用
model.named_parameters()
方法获取所有参数的名称和值,以便更精细地控制优化过程。
通过传递模型的所有参数给优化器,可以确保在训练过程中正确地更新模型参数,从而最小化损失函数。
train_loader
是一个数据加载器对象,通常用于加载训练数据集。在 PyTorch 中,DataLoader
类用于将数据集分成多个批次(batch),并在每次迭代时返回一个批次的数据。DataLoader
返回的值取决于数据集和批处理设置。
常见的返回值
-
数据:
DataLoader
返回的每个批次通常包含两部分:输入数据和标签数据。例如,在图像分类任务中,输入数据是图像,标签数据是图像对应的类别标签。 -
索引:如果
train_loader
是从Dataset
对象创建的,并且Dataset
对象实现了__getitem__
方法,那么DataLoader
返回的每个批次还会包含一个索引列表,表示当前批次中每个数据在原始数据集中的位置。 -
采样权重:如果
train_loader
是从WeightedRandomSampler
对象创建的,那么DataLoader
返回的每个批次还会包含一个采样权重列表,表示当前批次中每个数据在原始数据集中的采样权重。
示例
假设 train_loader
是从 Dataset
对象创建的,并且 Dataset
对象实现了 __getitem__
方法,那么 DataLoader
返回的每个批次通常包含以下内容:
for i, (images, labels) in enumerate(train_loader):
# images 是输入数据,通常是一个张量
# labels 是标签数据,通常是一个张量
# i 是当前批次的索引
在这个例子中,images
和 labels
是当前批次的数据,i
是当前批次的索引。
注意事项
-
DataLoader
返回的值取决于数据集和批处理设置。如果数据集和批处理设置发生变化,DataLoader
返回的值也会发生变化。 -
在使用
DataLoader
时,通常需要遍历DataLoader
对象,以获取每个批次的数据。例如,可以使用for
循环遍历DataLoader
对象:for images, labels in train_loader: # 在这里进行前向传播、计算损失、反向传播和参数更新等操作
-
在训练神经网络时,通常会在每个批次结束后进行一些操作,如打印损失值、保存模型等。
enumerate()
是 Python 的内置函数,用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。 配合计数
这段代码是深度学习模型训练过程中的一部分,主要用于执行反向传播和优化步骤。具体来说,它实现了以下功能:
-
清空梯度:
optimizer.zero_grad()
这行代码的作用是清空之前计算的梯度。在每次迭代开始时,梯度需要被清零,否则梯度会累积,导致模型训练出现问题。 -
反向传播:
loss.backward()
这行代码执行反向传播算法。反向传播是深度学习模型训练的核心步骤之一,它通过计算损失函数相对于模型参数的梯度,来更新这些参数。这一步会自动计算损失函数相对于每个参数的梯度,并将这些梯度存储在参数的.grad
属性中。 -
优化参数:
optimizer.step()
这行代码使用优化器(如SGD、Adam等)来更新模型的参数。优化器根据之前计算得到的梯度来调整参数的值,以最小化损失函数。这一步会根据梯度下降算法或其他优化算法的规则,更新模型参数。
用途:
这段代码的用途是在训练深度学习模型时,通过反向传播和优化步骤,逐步调整模型参数,以最小化损失函数,从而提高模型的预测性能。
注意事项:
- 在每次迭代开始时,必须调用
optimizer.zero_grad()
来清空梯度,否则梯度会累积,导致模型参数更新错误。 loss.backward()
会自动计算梯度,但需要注意,如果模型中有复杂的操作(如自定义的torch.autograd.Function
),可能需要手动调用torch.autograd.backward
来计算梯度。optimizer.step()
会根据梯度更新模型参数,因此需要确保梯度计算和优化步骤的顺序正确。
torch.save
是 PyTorch 中用于保存对象到磁盘的函数。它接受以下参数: 用来保存state_dict存下ckpt
- obj:要保存的对象。这可以是任何 Python 对象,但通常是一个张量、模型的状态字典(state_dict)或其他 PyTorch 对象。
- f:文件名或文件对象。这可以是文件路径(字符串)或一个已经打开的文件对象。如果是一个文件路径,
torch.save
会自动创建文件。
criterion 评价标准,通常 item()
是PyTorch张量对象的一个方法,用于将单元素张量转换为Python标量(即一个数值)。如果张量包含多个元素,item()
会引发错误
transforms
模块
transforms
模块提供了许多常用的图像变换操作,如裁剪、缩放、旋转、翻转、归一化等。这些变换操作可以用于对图像数据进行预处理,以便在训练神经网络时使用。
常用的有transforms.ToTensor()
在深度学习中,反向传播(backpropagation)是一种计算梯度的方法,用于更新模型参数以最小化损失函数。优化器(如SGD、Adam等)则负责根据计算得到的梯度更新模型参数。
反向传播
反向传播的过程是这样的:
- 计算损失函数对于模型输出的梯度(通常使用链式法则)。
- 将这个梯度从输出层传播回输入层。
- 计算每个模型参数对于损失函数的梯度。
在PyTorch中,这个过程通常由loss.backward()
函数自动完成。这个函数会自动计算损失函数对于模型所有可导参数的梯度,并将这些梯度存储在参数的.grad
属性中。
梯度清零
在每次更新参数之前,我们需要将梯度清零。这是因为每次迭代中,我们都会计算新的损失函数对于模型参数的梯度。如果不将梯度清零,那么每次迭代中的梯度都会在前一次迭代的基础上累积,导致参数更新错误。
因此,在每次迭代开始时,我们首先调用optimizer.zero_grad()
来清零梯度。这样,我们就为新的梯度计算做好了准备。
优化器step
优化器负责根据计算得到的梯度更新模型参数。在PyTorch中,optimizer.step()
函数会自动更新模型参数。具体来说,它会遍历所有参数,并使用优化器的更新规则(如SGD的权重衰减、Adam的梯度平方平均等)来更新每个参数。
在调用optimizer.step()
之后,模型参数就会被更新,从而更接近损失函数的最小值。
综上所述,在深度学习模型训练过程中,loss.backward()
用于计算梯度,optimizer.zero_grad()
用于清零梯度,而optimizer.step()
用于更新模型参数。通过这样的流程,我们不断地逼近损失函数的最小值,从而优化模型。
optimizer.step 根据优化器的规则来进行模型参数的更新
这段代码是Python中PyTorch库中的一个函数,用于创建一个二维批量归一化(Batch Normalization)层。这个层通常用于加速神经网络的训练过程,特别是在深度学习中。
nn.BatchNorm2d(16)
的参数 16
表示该层的输入特征图的通道数为 16。nn.BatchNorm2d
函数的输入参数是一个整数,表示批量大小(batch size),这里设置为 16。批量归一化层的作用是对输入的特征图进行归一化处理,使得每个特征图的均值为 0,方差为 1。这样可以加速模型训练过程,提高模型的泛化能力。
在深度学习中,批量归一化层通常被应用于卷积神经网络(CNN)的卷积层之后,以加速模型训练过程。同时,批量归一化层也可以应用于其他类型的神经网络层之后,以提高模型的性能。
在使用批量归一化层时,需要注意以下几点:
- 批量归一化层需要与适当的激活函数(如 ReLU、tanh 等)一起使用,以保证模型的性能。
- 批量归一化层需要与适当的优化器(如 Adam、SGD 等)一起使用,以保证模型的训练效果。
- 批量归一化层需要与适当的损失函数(如交叉熵损失、均方误差损失等)一起使用,以保证模型的训练目标。
- 在训练过程中,批量归一化层的参数(如均值和方差)需要实时计算,以保证模型的实时性能。
总之,批量归一化层在深度学习中具有重要的意义,可以加速模型训练过程,提高模型的性能。