大模型通识 / AI 理论基础
8. 训练究竟在做什么:梯度下降、反向传播与参数更新
原文备份 · 第 9 / 14 篇 · 查看极客时间原知识库 ↗
本篇目录 · 10 节
来源:AI 理论基础
复习助手想估计读完一篇笔记需要多久。我们先用一个极简模型:笔记长度乘以一个系数,就得到预测时长。
假设一篇 2000 字的笔记,目标阅读时长是 6 分钟。当前模型的系数是“每千字 1 分钟”,于是预测只有 2 分钟。它偏低了,接下来应该怎么改?
这个小问题,人可以直接把系数改成 3。但上一篇的网络已经有多个参数,大模型的参数更多;每个参数又通过不同计算影响最终结果。训练需要一套能够重复执行的方法,计算哪些参数该怎样调整。
本篇把这套过程拆成四步:前向计算、计算损失、计算梯度、更新参数。我们会真正算出几次更新,但全部使用教学构造的数据与公式,不代表对真实阅读时长或大模型做了实验。你不需要安装软件,也不用先掌握微积分;涉及导数的地方会解释它在回答什么问题。
先把“要改什么”和“按什么改”分开
给笔记长度换一个便于手算的单位:x=字数÷1000,所以 2000 字对应 x=2。模型暂时没有偏置,只有一个参数 w:
预测时长 ŷ = w × x
目标时长 y = 6
损失 L = (ŷ - y)²
ŷ 读作“y 帽”,这里只表示预测值,与目标 y 区分。损失沿用第 06 篇的平方误差;因为当前只有一个样本,不需要另外求平均。时长以分钟计,损失单位就是分钟的平方。
当 w=1 时:
预测:ŷ = 1 × 2 = 2
损失:L = (2 - 6)² = 16
输入 x 和目标 y 在这次训练计算中固定。我们要改的是参数 w,希望改完以后,按同一条损失规则重新计算的结果更小。
这与修改标签凑出低损失完全不同。训练目标是调整模型,让它适应提供的数据,而不是把“6 分钟”偷偷改成它已经预测的“2 分钟”。
梯度:轻轻改动参数,损失会怎样变化
先试着把 w 从 1 增加到 1.01:
新预测:1.01 × 2 = 2.02
新损失:(2.02 - 6)² = 15.8404
参数增加 0.01,损失下降 0.1596。两者的变化量相除,得到约 -15.96。这提示我们:在当前点附近,稍微增加 w,损失会降低。
如果考察越来越小的参数改动,就得到这里所说的导数:损失相对于这个参数的局部变化率。对有许多参数的模型,每次固定其他参数,分别考察一个参数的这种变化率,再组成一组数,就是损失相对于参数的梯度,gradient。
本例的精确计算规则是:
损失对 w 的梯度 g = 2 × (w×x - y) × x
代入 w=1、x=2、y=6:
g = 2 × (2 - 6) × 2 = -16
暂时不会推导也没关系。记住它告诉我们的方向:梯度为负,表示在这个点附近增加 w 会降低损失;梯度为正,则减小 w 是局部下降方向。这里的“附近”很重要,不能据此断言参数增加得越多越好。Google:梯度下降与平方误差的参数导数
梯度不是损失本身。损失 16 描述当前计分,梯度 -16 描述当前对参数变化的敏感程度,恰好绝对值相同只是这个算例的巧合。它也不是模型用语言写下的一段“反省”。
梯度下降:按方向走多远
最基础的更新规则叫作梯度下降,gradient descent:
新参数 = 旧参数 - 学习率 × 梯度
学习率,learning rate,控制更新幅度,常用希腊字母 η 表示。这里先取 η=0.1:
新 w = 1 - 0.1 × (-16) = 2.6
新预测 = 2.6 × 2 = 5.2
新损失 = (5.2 - 6)² = 0.64
减去一个负数,参数反而增大,这正是我们需要的方向。下一步必须在新参数处重新计算梯度,不能一直重复使用最初的 -16:
新梯度 = 2 × (5.2 - 6) × 2 = -3.2
再更新 w = 2.6 - 0.1 × (-3.2) = 2.92
把过程列成表,就能看出训练循环在做什么:
| 完成的更新次数 | 参数 w | 当前预测时长 | 当前损失 |
|---|---|---|---|
| 0 | 1 | 2 | 16 |
| 1 | 2.6 | 5.2 | 0.64 |
| 2 | 2.92 | 5.84 | 0.0256 |
| 3 | 2.984 | 5.968 | 0.001024 |
对于这一个样本,理想的系数是 3,我们的更新正在接近它。这还没有证明“所有笔记每千字都需要 3 分钟”,只证明这条规则在当前样本上逐步降低了损失。
学习率通常由训练设置指定,属于超参数;w 则是被优化的模型参数。软件可以按计划改变学习率,但它与普通梯度更新中的权重仍是不同角色。Google:学习率与其他超参数
同一个梯度,步子太大也会走错
都从 w=1、梯度=-16 出发,换几个学习率,看看一次更新后的结果:
| 学习率 | 更新后的 w | 更新后的预测 | 更新后的损失 |
|---|---|---|---|
| 0.01 | 1.16 | 2.32 | 13.5424 |
| 0.10 | 2.60 | 5.20 | 0.64 |
| 0.30 | 5.80 | 11.60 | 31.36 |
0.01 让损失有所下降,但这一步改善较小;0.30 则跨过了合适位置,新的预测过高,损失甚至比原来的 16 更大。
所以“沿下降方向更新”和“更新之后一定下降”不能混为一谈。方向是局部信息,步幅还需要合适。这里的 0.1 也不是通用推荐值:输入单位、损失缩放、网络结构和更新算法改变后,合适的数值都可能不同。
在深层网络里,损失随参数变化的形状远比本例复杂。梯度下降也不承诺找到全局最好的参数。看到梯度接近 0,需要结合更多信息判断,不能仅凭这一点认定已经获得最好的模型。
多层网络里的梯度,怎样算回去
前面的模型只有一个参数,公式很短。现在增加一层,但暂时不加非线性,方便看清梯度沿途怎样传递:
输入 x → h = a×x → 预测 ŷ = b×h → 损失 L = (ŷ-y)²
a、b 是两个不同层的权重,均暂取 1;这里的 b 是乘法权重,不是上一篇公式中的偏置。仍用 x=2、y=6,前向结果就是 h=2、ŷ=2、L=16。
先看离损失最近的一步:预测值稍微增加时,损失怎样变?平方误差对预测值的变化率是 2×(ŷ-y),当前为 -8。
再往前看:
- 改变
b,会先通过ŷ=b×h影响预测。在当前h=2的位置,预测对b的变化率是 2。因此损失对b的梯度是-8×2=-16。 - 改变
a,要经过a → h → ŷ → L。沿途的变化率分别是x=2、b=1、-8,相乘得到损失对a的梯度-8×1×2=-16。
这种把沿途变化率连接起来的规则叫作链式法则。在这个例子中,我们可以把它读成“参数先影响中间值,中间值再影响预测,预测最后影响损失”。
反向传播,backpropagation,就是沿计算关系反向组织这些梯度计算的方法。它从损失开始,逐步计算更早的中间值和参数如何影响损失,复用已经算出的结果;如果一个参数通过多条路径影响损失,就需要汇总这些路径的贡献。《动手学深度学习》:反向传播与计算图
上一篇说过,纯线性层可以合并。本例保留两层只是为了展示链式计算,不是为了增加表达能力。实际网络有激活函数时,也要把相应的局部变化率纳入链条。
反向传播不需要让每个隐藏单元先得到一个人工标签,也不是把正确答案“倒着塞回去”。它计算的是给定损失对各参数的梯度。
反向传播和更新参数,是两件事
这几个词经常同时出现,但职责不同:
| 环节 | 做什么 | 是否已经改变参数 |
|---|---|---|
| 前向传播 | 用当前参数计算中间值和预测 | 没有 |
| 计算损失 | 对照目标,给本次预测计分 | 没有 |
| 反向传播 | 计算损失对参数的梯度 | 通常还没有 |
| 优化器更新 | 使用梯度和更新规则修改参数 | 是 |
优化器,optimizer,是执行参数更新规则的组件。最简单的更新可以用刚才的梯度下降公式;其他优化器还可能利用历史梯度等信息,不必都严格等于这一条公式。
现代深度学习框架可以自动记录运算关系并计算梯度,这叫作自动微分。例如 PyTorch 的自动微分教程把梯度计算展示为单独一步;得到梯度,并不等于已经执行参数更新。自动微分也不同于对每个参数都加一点、重新试跑整个模型的数值差分方法。PyTorch:Automatic Differentiation with torch.autograd
本篇一开始把 w 增加 0.01,是为了帮助理解变化率,不是在建议大型网络按这种方式逐个试探所有参数。
把训练循环画完整,就会看到目标和参数进入了不同的位置:
取一批输入和目标
↓
当前参数 → 前向计算 → 预测 → 与目标比较 → 损失
↑ ↓
└──────── 优化器更新 ← 参数梯度 ← 反向传播
然后取下一批数据,用更新后的参数重新计算。
为什么训练常常一批一批进行
真实训练通常不会只看一篇笔记。若有大量样本,每更新一次都计算全部数据,可能太慢;每次只看一个样本,又可能难以充分利用硬件。小批量,mini-batch,是一次处理一组样本的常见折中。
例如,一批里有 20 篇笔记,可以先得到各样本损失,再对它们求平均并计算梯度。对于这种平均损失,其梯度也相应汇总了这些样本的贡献。有些样本希望参数变大,有些希望变小,合在一起决定这一步的更新。《动手学深度学习》:小批量随机梯度下降
假设训练集恰有 100 篇,每批 20 篇,每批更新一次,不重复抽样、不跨批累计梯度:
处理 1 批并更新一次:1 个优化步骤,step
100 篇全部处理一次:1 轮,epoch
这个例子中:1 epoch = 5 个更新步骤
这是特定设置下的对应关系,不是通用等式。有些系统会把多批梯度累计后才更新,也有持续采样的数据流,因此阅读日志时要看具体定义。
换了一批数据,计算的损失也换了样本依据。它偶尔比上一批高,并不足以证明训练出故障。应结合一段时间的趋势和固定评估数据判断,而不是要求每一批的数字都严格下降。
训练不稳定,不一定只是学习率的问题
前面的“大步跨过目标”解释了一种常见问题。深层网络还可能遇到梯度消失或梯度爆炸:沿多层传播以后,某些梯度变得极小,参数几乎不动;或者变得过大,更新幅度失控。初始化方式、激活函数和网络结构都会影响这些现象。《动手学深度学习》:数值稳定性与初始化
作为应用开发者,先能区分现象与结论即可:
| 现象 | 可能需要检查的方向 |
|---|---|
| 损失持续剧烈增大 | 学习率、梯度大小、异常输入与数值计算 |
| 损失长期几乎不变 | 参数是否真的在更新、梯度是否过小、设置是否合适 |
| 训练损失下降,实际笔记效果却变差 | 数据代表性、过拟合、训练目标与任务是否一致 |
这张表不是凭曲线确诊原因的规则。尤其是最后一种情况,可能训练本身运行正常,只是它优化的内容没有转化成我们想要的能力。下一篇会专门讨论泛化和过拟合。
使用模型时,为什么通常没有这一整套循环
在通常的推理过程中,我们加载已经训练好的参数,把新输入送进去,计算输出。中间值会变化,但不会因为这次回答自动执行上述参数更新。
复习助手把你的新笔记作为参考资料,模型据此生成卡片,属于使用输入信息;把新笔记整理为训练样本,再计算损失、梯度并更新参数,则属于另一条训练流程。是否保存聊天记录、是否以后把反馈用于训练,又是产品和数据流程的安排,不能仅从“它记住了上一句话”推断。
同样,推理模型生成较长的思考过程,或者 Agent 多次调用工具,也不能因此就叫作反向传播。多做几次计算与改变模型参数,是两个不同维度。
理解检查:轮到你更新参数
- 沿用
ŷ=w×x、L=(ŷ-y)²,令x=2、y=6、w=4。梯度是多少?学习率为 0.1 时,新参数和新损失是多少? - 反向传播已算出梯度,但没有执行任何参数更新规则。能否说权重已经学到了这批数据?
- 在本篇 100 篇、每批 20 篇、每批更新一次的设置下,完成 3 个 epoch,共更新多少次?
- 某一批损失比上一批高,是否足以证明学习率太大?
- 用户上传一篇笔记后,模型能回答其中的新信息,是否证明其权重刚刚改变?
第 1 题: 当前预测为 8,梯度为 2×(8-6)×2=8。新参数 4-0.1×8=3.2,新预测为 6.4,新损失为 0.4²=0.16。梯度为正,所以本次更新减小参数。
第 2 题: 不能。梯度是更新依据;按题设,权重还没有改变。需要区分“算出该怎么改”与“真正改了参数”。
第 3 题: 每轮 5 次,3 轮共 15 次。这个答案依赖题目约定,若使用梯度累计等设置就要重新计算。
第 4 题: 不足以。不同批次可能难度不同,随机更新也可能有波动,需要观察趋势和相关训练状态。
第 5 题: 不能。新笔记可能只是进入了本次上下文,模型用已有参数处理了新输入;有无参数更新,要看是否实际运行了训练流程。
到这里,数据、表示、网络、损失与参数更新已经连成一条线。下一篇要问一个更贴近使用的问题:模型在练习材料上越来越熟练,为什么遇到新笔记还是会出错?
上一篇:07|神经网络与深度学习:多层计算怎样形成能力
下一篇:09|学会与背会有什么区别:泛化、过拟合与分布变化
返回:第一部分大纲