梯度是什么
从 Bit 到 AGI · 第二章:数学(Math) · 梯度是什么
矩阵乘法告诉我们前向怎么算:输入乘权重得到输出。但 70 亿个权重怎么学会正确值?答案是沿着梯度方向调整。本篇定义梯度——多元函数对各变量偏导数组成的向量——并量化一次反向传播里梯度张量的规模。
直觉:多维空间里的「最陡上坡方向」
你在山上,海拔是 。想知道往哪走上升最快——看梯度 ,它指向最陡的上坡方向;负梯度 指向最陡的下坡。
神经网络里,损失函数 的变量是所有权重 (可能 70 亿维)。梯度 告诉你:每个权重该增大还是减小、幅度多大,才能让损失下降最快。
定义
设 ,即 个输入、一个标量输出(典型如 loss)。梯度是:
- 每个分量是偏导数(下一篇详讲)。
- 梯度是向量,与输入 同维。
- 方向: 增长最快的方向;模长 表示该方向上的变化率。
对神经网络: 是所有参数拼成的向量, 与 同 shape 的梯度张量(PyTorch 里 param.grad)。
例子
例 1:二元函数
。偏导:,。
在点 :,模长 。
沿 方向(即 归一化后)走, 下降最快。
例 2:单层线性 + MSE loss
, 是标量权重。
若 、、,则 ,梯度 。更新 ( 为学习率), 增大以减小 loss。
import torch
x, y, w = torch.tensor(2.0), torch.tensor(5.0), torch.tensor(1.0, requires_grad=True)
loss = 0.5 * (y - w * x) ** 2
loss.backward()
print(w.grad.item()) # -6.0量化
| 场景 | 梯度规模 |
|---|---|
| 标量参数 | 1 个数 |
| 向量参数 | 个数,与 同 shape |
| 矩阵权重 | 张量 |
| LLaMA-7B 全部参数 | ≈ 7B 个梯度值,与参数量相同 |
| 反向传播显存 | 常需存激活 + 梯度,约为前向 activations 的 1–2 倍 |
梯度下降一步(SGD):
学习率 典型值: 到 (预训练);太大发散,太小收敛慢。
FLOPs:反向传播约为前向的 2 倍(链式法则,后面讲)。
工程视角:autograd 里的梯度
PyTorch 中 requires_grad=True 的张量参与运算时,框架构建动态计算图。loss.backward() 从 loss 节点反向遍历,每个 op 的 backward 把上游梯度乘以本地雅可比(链式法则),写入 .grad 字段。
梯度累积:loss = loss / accumulation_steps 多次 backward 再 optimizer.step(),等效更大 batch——显存不够时常见。.grad 在 step 前需 zero_grad(),否则梯度累加。
梯度检查点(activation checkpointing):不存全部中间激活,反向时重算前向——用 FLOPs 换显存,大模型训练标配。
Adam 更新不是直接用 ,而是维护一阶矩 、二阶矩 :
每个参数仍有「等效梯度方向」,只是自适应缩放。LLM 预训练 (而非默认 0.999)是经验调参,让二阶矩更快适应非平稳 loss landscape。
| 优化器 | 每参数额外状态 | 7B 训练显存增量(粗估) |
|---|---|---|
| SGD | 0 | 0 |
| AdamW | 参数量 fp32 | +≈56 GiB(m + v) |
常见误区
- 梯度 ≠ 参数:梯度是「该往哪改」的方向;参数是实际存储的权重值。
- 梯度为零 ≠ 最优:可能是鞍点或局部 plateau;也可能只是 ReLU 死区导致。
- 「梯度很大 = 学得快」:大梯度常需梯度裁剪(clip norm 1.0);Adam 等自适应优化器会缩放各维梯度。
动手试一试
def sgd_step(w: float, grad: float, lr: float = 0.01) -> float:
return w - lr * grad
w, grad = 1.0, -6.0
for t in range(5):
w = sgd_step(w, grad, lr=0.1)
grad = -(5 - w * 2) * 2 # 重新算梯度
print(f"t={t}, w={w:.3f}, grad={grad:.3f}")深入一层:方向与步长
梯度方向是最陡上升;负梯度是最陡下降——仅当度量是欧氏时成立。Adam 用自适应对角缩放,等价于在逐元素加权度量下走下降方向,不再严格是 的负梯度方向,但实践更好。
随机性:mini-batch 梯度 有方差,。大 batch 梯度准但易陷 sharp minima;小 batch 噪声大但泛化有时更好——LLM 预训练倾向大 batch + 大数据,另一套经验。
Nesterov momentum:「先动一步再看梯度」,收敛率在某些凸问题优于 vanilla GD。SGD + momentum 0.9 曾是 CV 标配;LLM 几乎全用 AdamW,但 momentum 思想仍在 里。
二阶曲率(直觉):。 正定且 是一牛顿步——LLM 算不起 ,但 Adam 对角 可看作对角 Hessian 的 crude 近似。
监控训练时同时看 loss 与 grad norm:loss 降、grad norm 升可能是 sharp 区域;两者都 explode 则立刻介入 clip / 降 lr。
分布式训练中的梯度
DDP:loss.backward() 后 all-reduce 各卡 .grad 求平均,等价大 batch 梯度。梯度范数在 reduce 前后可能差 因子——clip 通常在 reduce 之后做。
ZeRO-1/2/3 分片 optimizer state,不改变梯度数学,只改存储。混合精度:loss scaling 防 fp16 grad underflow;bf16 常不需 scale。
读者备忘
梯度 = 与参数同 shape 的「改正方向表」。 loss.backward() 填 .grad;optimizer.step() 用负梯度更新。7B 模型 = 7B 个梯度值;Adam 再存 2× fp32 状态。clip norm 1.0 是 LLM 训练常见默认值。若 grad is None,检查 requires_grad 与 detach。
本章内容面向程序员:公式可手推,数字可心算,代码可运行。遇到符号不熟时,先查本篇定义表,再查总结篇速查表,不必一次背熟全部细节。
复习建议:先通读直觉与定义,再跑代码块验证数字,最后看读者备忘与小结。与第一章的 float 数组、SIMD、GPU 并行对照阅读,印象更深。后续章节会在 Transformer、训练、推理中反复调用本章符号,值得在笔记里自建一张 shape/FLOPs 速查表。
小结
梯度 是各偏导数组成的向量,指向函数增长最快方向;训练时用负梯度更新参数以最小化 loss。PyTorch loss.backward() 自动算全网络梯度。参数量 = 梯度元素个数;反向 FLOPs ≈ 2× 前向。下一篇解释导数为何足以驱动学习——从一元切线近似到激活函数选型。
→ 下一篇:导数为什么可以学习