0%

PyTorch训练

PyTorch训练全流程:从微分原理到梯度下降的完整实现

深度学习模型的训练过程,本质上是一个不断自我修正的闭环系统。在这个系统中,权重和偏置是模型需要学习的核心参数,损失函数是衡量模型表现的标尺,而反向传播与梯度下降则是驱动模型优化的引擎。理解这些组件如何协同工作,是掌握PyTorch的关键。

模型参数:权重与偏置的数学本质

在神经网络中,权重和偏置是模型内部的可学习参数,它们决定了输入数据如何被变换以产生预测结果。

权重是连接神经元之间的参数,本质上是输入特征对输出结果的贡献系数。在全连接层中,若输入特征为x,权重为w,则权重决定了输入信号在传递到下一层时的缩放比例。权重矩阵的数值大小和分布直接影响模型的表达能力和复杂度。

偏置是每个神经元自带的可学习参数,用于在加权求和后提供线性偏移量。其数学表达式为z = w^T x + b,其中b的存在使得激活函数可以在非原点位置产生响应。合理的偏置初始化可以使神经元在训练初期保持活跃状态。

在PyTorch中,这些参数被封装在nn.Module的子类中,通过model.parameters()可以获取所有需要训练的权重和偏置。

训练数据:训练值与目标值的角色

训练过程依赖于成对的数据:训练值和目标值。

训练值是模型的输入数据,通常表示为X。在图像分类任务中,训练值可能是像素矩阵;在回归任务中,可能是特征向量。训练值经过模型的前向传播,产生预测结果。

目标值是训练数据对应的真实标签,通常表示为y。它是模型学习的”标准答案”,用于与模型的预测结果进行比较。目标值的质量直接决定了模型学习的方向。

在训练循环中,训练值和目标值通常以批次(batch)的形式被加载到内存中,以便进行高效的并行计算。

损失函数:衡量模型表现的标尺

损失函数是连接模型预测与真实标签的桥梁,它量化了模型预测值与目标值之间的差异。损失值越小,说明模型的预测越接近真实值。

常见的损失函数包括均方误差和交叉熵损失。均方误差常用于回归问题,计算预测值与目标值之差的平方。交叉熵损失常用于分类问题,衡量预测概率分布与真实概率分布的差异。

在PyTorch中,损失函数通常被实例化为一个对象,如nn.MSELoss()nn.CrossEntropyLoss(),然后在训练循环中被调用以计算损失值。

反向传播与梯度下降:模型优化的引擎

反向传播和梯度下降是模型学习的核心机制,它们共同完成了从误差计算到参数更新的全过程。

反向传播利用链式法则,从损失值开始,沿着网络从输出层向输入层反向传递,计算每个参数对于总误差的梯度。这个过程回答了”每个参数应该为多少误差负责”的问题。

梯度下降是优化器利用反向传播计算出的梯度,按照某种策略来更新网络的权重和偏置,目标是使损失函数的值最小化。常见的优化器包括随机梯度下降和Adam。

微分在训练中的核心作用

微分在训练中的作用体现在梯度计算环节。当损失函数计算出预测值与目标值的差异后,需要知道每个权重和偏置对总误差的贡献程度,这就需要对损失函数关于每个参数求偏导。

以简单的线性模型y = wx + b为例,损失函数L = (y_pred - y_true)²。为了更新权重w,需要计算∂L/∂w;为了更新偏置b,需要计算∂L/∂b。这些偏导数就是梯度,它们指示了参数应该调整的方向和幅度。

PyTorch的torch.autograd模块自动完成了这些微分计算。当调用loss.backward()时,系统会自动构建计算图,应用链式法则,计算出所有参数的梯度,并存储在参数的.grad属性中。

实战:完整的训练循环解析

让我们通过一个完整的训练循环,看看这些组件如何协同工作。

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
31
32
33
34
import torch


# 准备数据
# x是输入 y是目标值
x = torch.tensor([[1.0],[2.0],[3.0],[4.0]])
y = torch.tensor([[2.0],[4.0],[6.0],[8.0]]) # 理想关系是 y = 2x

# 定义模型
# 输入是一维,输出是一维
model = torch.nn.Linear(1,1)
# 定义损失函数 均方误差
loss = torch.nn.MSELoss()
# 定义优化器 随机梯度下降,学习率为0.01
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)

# 训练模型
epochs = 1000
for epoch in range(epochs):
# 前向传播
y_pred = model(x)
# 计算损失
l = loss(y_pred,y)
# 清空梯度( 先把上一轮的 .grad 归零,pytorch默认是累加梯度,如果不清零,会造成梯度爆炸)
optimizer.zero_grad()
# 反向传播(计算梯度,此时梯度被累加到 .grad 中)
l.backward()
# 更新参数(优化器读取 .grad,更新权重 w)
optimizer.step()


if (epoch+1) % 100 == 0:
print(f'epoch {epoch+1}, loss {l.item()}')
print(f'w:{model.weight.item()}, b:{model.bias.item()}') # w会无限接近于2,b无限接近于0

在这个训练循环中,我们可以看到:

训练值X通过模型的前向传播产生预测值y_pred。损失函数计算预测值y_pred与目标值y之间的差异,得到损失值loss。反向传播计算损失值对模型参数(权重和偏置)的梯度,这个过程用到了微分。优化器根据梯度更新权重和偏置,使损失值逐渐减小。

通过成千上万次的迭代,模型的权重和偏置不断调整,最终使预测值越来越接近目标值,完成模型的学习过程。

关键细节与避坑指南

在实战中,有几个个细节决定了训练的成败:

  • 梯度清零是必须的。PyTorch 的设计哲学是允许梯度累加,这在处理超大模型显存不足(需要模拟大 Batch Size)时很有用。但在常规训练中,如果不执行 optimizer.zero_grad(),梯度会不断叠加,导致参数更新方向错误,模型无法收敛。

  • 动态图的优势。PyTorch 的计算图是动态构建的,这意味着你可以在循环、条件判断中使用 Python 原生的控制流,而不需要像 TensorFlow 1.x 那样构建静态图。这让调试变得异常轻松。

结语

深度学习模型的训练是一个精密的协同过程。权重和偏置是模型需要学习的知识,训练值和目标值是学习的素材,损失函数是学习的标尺,而反向传播与梯度下降则是学习的方法。微分作为梯度计算的核心,连接了损失函数与参数更新,是整个训练流程的数学基础。理解这些组件的角色和相互作用,是掌握PyTorch深度学习框架的关键。

欢迎关注我的其它发布渠道