d2l:梯度
能够代表深度学习训练核心的概念之一是梯度(Gradient)。
D2L 学习过程中会涉及很多概念,例如线性回归、Softmax 回归、交叉熵、反向传播、SGD、自动求导等。表面上看,这些内容似乎彼此独立,但实际上,它们全部都围绕着梯度展开。
甚至可以说,深度学习的整个训练过程,本质上就是一个不断计算梯度、利用梯度、更新梯度、传播梯度的过程。
因此,如果不能从数学和工程两个角度真正理解梯度,那么后面的 CNN、Transformer、注意力机制、大模型训练都会变得非常模糊。
本文不局限于某段代码,而是从整个深度学习系统的角度,完整地梳理梯度。
1. 梯度最初来自哪里?
梯度最初来自微积分。
假设有一个函数:
它的图像是一条抛物线。
如果需要判断:
当 发生微小变化时,函数值 会如何变化?
就需要计算导数:
例如:
当:
那么:
这意味着,当 增加一个极小量时, 大约会增加 6 倍的变化量。
导数描述的是:
函数在某一点的瞬时变化率。
但是,深度学习中的参数并不只有一个。
例如,线性回归:
这里有三个参数:
此时,损失函数变成:
它是一个三元函数。
于是,普通导数就不够用了。
2. 偏导数:研究单个参数的影响
对于多变量函数:
可以分别研究每个参数。
固定其他参数,只改变:
得到:
同样:
以及:
分别表示:
- 对损失的影响
- 对损失的影响
- 对损失的影响
这就是偏导数。与基础微积分中常见的“对输入 求导”不同,模型训练时输入数据 通常已经确定,参数 才是需要优化的变量。为了寻找一组使预测结果接近真实标签的参数,需要计算损失函数对参数 的偏导数。
3. 梯度:所有偏导数组成的向量
把所有偏导数放到一起:
这就是梯度。
注意:
梯度不是一个数。
梯度是一个向量。
例如:
假设:
意味着:
- 增大时,损失快速增加
- 增大时,损失反而减小
- 增大时,损失缓慢增加
4. 梯度为什么能够指导训练?
假设损失函数是一个山谷:
山顶
▲
/ \
/ \
/ \
/ \
●---------→
山谷
当前位置:
●
梯度指向哪个方向?
答案是:
梯度永远指向函数增长最快的方向。
例如:
当前位置的梯度:
表示:
向右移动,损失增加。
向上移动,损失增加。
如果想让损失下降,怎么办?
只需要沿着梯度的反方向移动:
这就是梯度下降。
5. 梯度下降公式是怎么来的?
更新公式:
其中:
- 是参数
- 是学习率
- 是梯度
例如:
当前参数:
梯度:
学习率:
更新后:
得到:
6. 为什么不只使用梯度的符号?
这一问题是理解梯度下降的重要前提。
为什么不用:
而要使用完整的梯度?
假设:
两个参数:
梯度:
说明:
第一个方向离最优解非常远。
第二个方向离最优解已经很近。
如果只保留符号:
那么:
两个方向会被同等对待。
训练效率会非常低。
梯度的大小包含了重要的信息:
- 方向
- 距离
- 曲率信息
因此,梯度不仅告诉模型朝哪里走,还告诉模型走多远。
7. 为什么 SGD 有随机性,却仍然能够收敛?
完整损失:
真实梯度:
但是,每次训练只抽取一个小批量:
于是:
由于是随机采样:
每个批次的梯度都不完全一样。
例如:
真实梯度:
第一个批次:
第二个批次:
第三个批次:
虽然存在波动,但是:
也就是说:
随机梯度的期望等于真实梯度。
从长期来看,模型仍然沿着正确的方向移动。
8. 为什么神经网络需要反向传播?
假设:
一个两层网络:
其中:
第一层:
第二层:
损失:
现在需要求:
但是:
损失函数并不直接依赖于:
而是:
因此:
必须使用链式法则:
这个梯度的传播过程:
前向传播:
x
↓
隐藏层
↓
输出层
↓
Loss
-------------------
反向传播:
Loss
↑
输出层
↑
隐藏层
↑
x
这就是反向传播。
9. PyTorch 是如何实现梯度的?
很多人会误以为:
loss.backward()
是在计算梯度。
其实不是。
真正的流程是:
第一步,前向传播:
y_hat = net(X)
第二步,自动构建计算图:
X
↓
Linear
↓
ReLU
↓
Linear
↓
CrossEntropyLoss
PyTorch 会自动记录:
- 输入
- 输出
- 运算关系
第三步,调用:
loss.backward()
此时:
PyTorch 会从损失开始:
Loss
↑
Linear
↑
ReLU
↑
Linear
沿着计算图反向传播。
第四步,梯度被存储到:
parameter.grad
例如:
w.grad
b.grad
第五步,优化器更新参数:
optimizer.step()
等价于:
第六步,清空梯度:
optimizer.zero_grad()
因为 PyTorch 默认会累积梯度。
10. 从工程角度看,整个训练过程实际上只有六个步骤
数据
↓
DataLoader
↓
模型
↓
损失函数
↓
梯度
↓
优化器
↓
更新参数
↓
下一轮训练
D2L 第 3 章,其实就是在逐步封装这六个模块。
线性回归:
数据 → Linear → MSE → SGD
Softmax 回归:
数据 → Softmax → CrossEntropy → SGD
CNN:
数据 → Conv → CrossEntropy → Adam
Transformer:
数据 → Attention → CrossEntropy → AdamW
LLM:
Token → Transformer → CrossEntropy → AdamW
由此可以观察到一个现象:
后面的模型越来越复杂,但训练流程几乎没有变化。
变化的是:
- 模型结构
- 参数规模
- 数据规模
- 优化算法
不变的是:
Forward
↓
Loss
↓
Gradient
↓
Backward
↓
Optimizer
↓
Parameter Update
线性回归与 Softmax 回归不仅是两个具体模型,也用于建立深度学习训练系统的底层抽象。
在 CNN 和 Transformer 等模型中,梯度仍然承担相同作用:把预测误差转换成参数调整信号,并将该信号传递到网络中的每一个可学习参数。
关联文档
- d2l 学习笔记:深度学习模型训练过程的数学原理:说明梯度在完整模型训练闭环中的作用。
- 深度学习框架自动微分原理:理解计算图与自动微分如何计算参数梯度。
- d2l 学习笔记:简易线性模型实现:查看梯度下降在线性模型中的手动实现。
- 梯度详解:补充梯度的几何意义与常见计算方法。
