上一章的梯度下降只会做一件事:朝下坡方向挪一小步。 这一步太小就走得慢,太大就飞出去,而且在细长的峡谷里会来回撞墙。 优化器这一整个家族,就是在修这三个毛病。
把损失想象成一片山地,参数是你站的位置。梯度告诉你"哪边是下坡"。 朴素梯度下降的做法是:沿着梯度方向,走固定的一步。
| 毛病 | 长什么样 | 谁修好了它 |
|---|---|---|
| ① 峡谷震荡 | 地形像一条细长的沟。垂直方向很陡、水平方向很缓, 于是它在两侧墙之间来回弹,就是走不到尽头 | 动量 Momentum |
| ② 所有参数一个步长 | 有的参数已经很接近了、需要小步微调;有的还很远、需要大步赶路。 但学习率是全局的,一刀切 | 自适应方法 AdaGrad / RMSProp |
| ③ 学到的参数越来越大 | 训练久了权重数值膨胀,模型变得敏感、容易过拟合 |
朴素梯度下降 = 一个蒙着眼、步子固定的人下山。
动量 = 给他一个下坡的滑板,让他记住之前的惯性;
自适应 = 给每只脚单独配一个步长,陡的地方迈小步、缓的地方迈大步;
这个类比要当心一件事:「站住不动就说明到谷底了」是错的。 蒙着眼的人停下来,可能只是脚下这一小块恰好平,旁边就是下坡。 第 7 节那张三维图要拆掉的,就是这个假设。
互动 · 学习率的四种命运(四条线都是真的迭代出来的)
下面是一张典型的"细长峡谷"损失地形,等高线是椭圆。 五个优化器从同一个起点出发,看谁先到谷底(中心那个点)。
核心大图 · 五个优化器,同一片地形上谁先到
把学习率调到 0.05 附近:地形有很多个方向,每个方向叫一维,陡的那一维会弹过头。
SGD 一步就迈过了 1/λ,但误差每步只剩
|1 − 0.05 × 22| = 0.1,几下就压回去了。
一直在横跳的是动量那条线(粉线):它记着最近约 10 步的旧方向,摆很久才停。Adam 却笔直走过去。
拖到 0.1:SGD 直接飞出画面,Adam 依然稳。
SGD 横跳的门槛是 lr > 1/λ(λ 是这个方向的陡度,这里 λ = 22,
门槛落在 0.045 附近,低于它 SGD 不会过头)。
Adam 的稳是它成为默认优化器最主要的原因,另外它还不需要怎么调学习率、对稀疏梯度友好。
先别。它在中小规模上比 AdamW 快,但换它不只是换一个类名:更新规则本身不一样, 学习率和权重衰减的调法都得跟着重来。默认仍然写 AdamW。
上面那根滑块只让你看到一条线上的行为:动量锁死在 0.9,学习率从 0.002 划到 0.12。 但真实情况是这两个数是一对搭档:同一个学习率,配 0.5 的动量和配 0.99 的动量,结局可能完全不同。 只看一条线,你看不到边界在哪。
下面这张图把 192,896 种「学习率 × 动量」组合每一种都跑一遍重球法(Heavy Ball, 就是动量法:给梯度加一个速度): 从同一个起点出发,最多跑 400 步,然后按实测结果上色:是到了谷底、还在摆、还是炸了。 整张图一共执行了五千多万次梯度步——不是 192,896 × 400 ≈ 7,700 万: 炸了的格子提前退出,收敛和摆动的格子也各有各的步数。
互动 · 学习率 × 动量 相图:悬停看这一格的实测结果
正在把 19 万个格子各自跑 400 步……
发散边界可以提前算出来:能承受的学习率有上限,上限由「动量 β」和「最陡方向的陡度」一起决定。 一句话版本是「步长 × 陡度不能超过 2(1+β)」,两行代数就能从重球法的更新式解出来—— 完整推导在数学那节。
图上这根白虚线就是它,而实测的红绿分界正好落在它上面,偏差中位数不到 0.5%,最大不到 1.5%。 红绿是跑出来的:每一格从同一起点出发,最多跑 400 步,炸了的提前退出; |w| 冲过 1000 算炸、涂红,压到 10⁻³ 以下算收敛、涂绿。 这点偏差全部来自「400 步」这个预算:刚好压在边界上的格子要花很久才炸得起来。
β = 0 时上限是 0.091,β = 0.9 时上限是 0.173:
动量越大,能承受的学习率越大,整条边界被抬高了 (1+β) 倍。
所以「学习率大就必须配小动量」是错的。自己验一下:把鼠标停在 η = 0.12、β = 0 上,它是红的
(朴素 SGD 在这里直接炸);停在 η = 0.12、β = 0.9 上,它是绿的
(重球法稳稳收敛,400 步后 |w| 已经到 1e-9)。动量在「发不发散」这件事上是稳定剂,不是炸药。
代价在顶部那条黄带:把 β 推到 0.966 以上,学习率再小也进不了绿区。
这时两条「误差乘数」被挤成了共轭复数,每步只能把它们缩小 √β 倍:
β = 0.99 时每步只缩 0.5%,400 步才缩到 0.13,而「到谷底」要求缩到 10⁻³。
把 β²⁰⁰ = 10⁻³ 解出来正是 β = 0.966,实测黄带下沿在 0.9645(差不到一个格子)。
反过来,左下那片灰(太慢)的右边界随 β 上升一路往左收:β = 0 时要 η > 0.0177 才够快, β = 0.8 时只要 η > 0.0036,再往上这片灰就整条消失了。动量的本职工作就是把峡谷里那个慢方向推快。
所有优化器都只有一句核心更新公式:w ← w − η·g。 w 是权重(模型里那些可以调的数),g 是梯度(这一步该往哪边改、改多猛), η 是学习率(把梯度缩成实际的一步)。它们的区别,只是「步长」和「方向」这两项怎么算出来的。
把鼠标移到公式上,看它对应哪个参数
| 优化器 | 核心公式 | 动了几行 | 它修的毛病 |
|---|---|---|---|
| SGD | w ← w − η·g | — | 什么都没修(但它是最可靠的基线) |
| Momentum | v ← βv + g;w ← w − η·v | 加一个"速度"变量 | ① 峡谷震荡。β=0.9 意味着最近约 10 步的梯度在做平均(窗口 ≈ 1/(1−0.9) = 10) |
| AdaGrad | s ← s + g²;w ← w − η·g/√s | 给每个参数记一个历史平方和 | ② 一视同仁。但 s 只增不减,后期步长会趋近 0 |
| RMSProp | s ← ρs + (1−ρ)g²;w ← w − η·g/√s | 把累加改成滑动平均 | ② 的修好版本,不会越走越慢 |
| Adam | m,v 各一个滑动平均;w ← w − η·m̂/(√v̂+ε) | 动量 + 自适应,再加偏差修正 | ① + ② 全修。默认 β₁=0.9,β₂=0.999 |
| AdamW | w ← w − η·(m̂/(√v̂+ε) + λ_wd·w) | 把 |
③ 的正确修法。今天的事实标准 |
| Muon | 把梯度矩阵做正交化再更新 | 换掉更新方向本身 | 2024 年后开始流行,在中小规模上比 AdamW 更快 |
表里这几个符号先认一下:s、m、v 都是「过去梯度的滑动平均」——每步把新梯度掺一点进来,
旧的按比例慢慢忘掉;β、ρ 是那个「忘得多快」的比例(窗口约等于 1/(1−β))。
m̂、v̂ 是做了「偏差修正」之后的版本(开头几步平均得偏小,先拉回正确尺度),
ε 是防止除以 0 的小数。不用背细节,知道它们都在描述「最近的梯度大概多大」就够了。
地图 · 所有优化器只改两件事:方向怎么算、步长怎么算
越靠右,步长越是由每个参数自己定;越往下,方向越不只靠当前这一步的梯度。第 6 节的学习率调度和梯度裁剪,可以叠在任意一格上。
互动 · 换个优化器,显存要多占多少
λ_wd·w²,
权重越大、多交的钱越多,逼着网络把参数压小(《过拟合与正则化》细讲)。
Adam 最初把它混进了梯度里:g ← g + λ_wd·w。看起来和直接压参数是一回事,其实不是。
差别出在 Adam 会拿 √v 去缩放梯度。梯度一直很大的参数,√v 也大,混进来的那一份衰减就被一起缩得几乎看不见: 梯度越大,衰减反而越弱,正好和本意相反。
对比 · 同样的衰减系数,两个参数的衰减差多少
算给读者看:参数 A 的梯度大(|g| = 1,√v = 1),参数 B 的梯度小(|g| = 0.01,√v = 0.01)。 η = 3e-4、λ_wd = 0.1 时,解耦衰减两边都是 η·λ_wd = 3e-5; L2 混进梯度后衰减 = η·λ_wd/√v,B 是 A 的 100 倍(√v 差了 1 ÷ 0.01 = 100 倍),也就是 3e-3。
AdamW = Adam + 解耦的权重衰减(decoupled weight decay)。
2019 年正式发表(arXiv 2017 首发),今天几乎所有大模型的训练配方里写的都是它。
看到论文里写「AdamW, lr=3e-4, weight_decay=0.1」,这里的 0.1 是解耦
不会,两个数说的不是同一件事。解耦衰减是每一步直接把参数乘上 (1 − η·λ_wd),
强度由 η 和 λ_wd 的乘积决定;而 L2 系数进的是梯度,还要被 √v 再缩放一次。
同一句话里的两个数,只有在各自那套写法里才有意义。
换优化器只是旋钮之一。还有三样东西经常被当成配菜写在训练脚本的最后几行, 但它们改起结果来,往往比换优化器还多。
| 东西 | 干什么的 | 典型配方 |
|---|---|---|
| 学习率调度 | 训练过程中动态改学习率。开头要暖机、中间要大、结尾要收 | Linear Warmup + Cosine Decay |
| 梯度裁剪 | 梯度范数超过阈值就等比缩回去,防止一个坏 batch 把模型打飞 | clip = 1.0 |
| 批量大小 | batch 越大梯度越准,但会降低随机性、可能掉进尖极小值 | 大 batch 配大学习率(线性缩放) |
别在「选哪个优化器」上花太多时间:先把学习率、调度这些旋钮调对,再考虑换。 新手先用这一套默认配方:AdamW + lr=3e-4 + warmup + cosine + clip 1.0。 跑通之后如果效果不好,顺序是:先动学习率(×3 或 ÷3 各试一次)→ 再动 warmup 的长度 → 最后才换优化器。
互动 · 学习率调度:三种「怎么花学习率」
互动 · 梯度裁剪:一个坏 batch 最多造成什么
前面六节讲了七个优化器,还有配在旁边的学习率调度、梯度裁剪和批量大小。看起来花样很多, 但所有优化器都只有一条式子:新位置 = 老位置 − 步长 × 方向。 区别只在「方向」那一项怎么算出来。把这条式子看懂,第 4 节那张谱系表就变成了一句注释。
梯度涨一万倍,谁跟着涨?
把三条线对照着看,整条谱系就一句话:灰线改的是「方向怎么算」,绿线改的是「步长怎么算」。 这两个正交的改动,就是整条优化器谱系。
微型图解 · m̂ 到底是什么:它是「最近多少步的平均」
这条式子有三件事没写出来。① 它只描述一步。真实的训练是它跑几百万次, 每一步的 g 都来自不同的 mini-batch,所以第 7~9 节说的「停住」, 指的是它在同一个 batch 的固定损失面上停住,而真实损失面每步都在动。 ② 它没写「方向」背后的几何。决定哪个方向是上坡的,是 Hessian: 一张「每两个方向之间的弯曲程度」拼成的 n×n 表。而这条式子里一个二阶量都没有 (Adam 的 v̂ 只是它的粗糙代理)。 ③ 它没有「什么时候停」这一项。停止是外层的事, 第 6 节那三件事一定要写进训练脚本,原因就在这。
第 3 节那条白虚线不是试出来的。在二次地形 L = ½λw² 上(谷底在 0,误差 e 就是 w 本身),
重球法每一步都是线性的。v 可以用相邻两步的 w 表示(把 w ← w − ηv 反着解),
代回 v ← βv + ∇L(w),就得到误差自己的一行递推:
上一步的误差传到这一步,只会被乘上一个固定的倍数。按「每步乘同一个倍数 z」去试: 设 eₜ = zᵗ,代进去,z 就必须满足一条二次方程:
两条根的乘积是 β,和是 1+β−ηλ。误差要一步步缩小,两条根就必须都待在单位圆里: 复数平面上以原点为心、半径为 1 的那个圈;谁出了圈,误差就被放大。 为什么只剩一个条件?两根之积 = β,而 β 本来小于 1——「乘起来不放大」已经保证; 会出圈的只能是其中一根,而它出圈时必是 z = −1(z = +1 代入方程左边等于 ηλ,不为 0)。 把 z = −1 代进去,方程左边 = 2(1+β) − ηλ,要求它大于 0,就是:
顺带解释了顶上那条黄带:当 ηλ 落在 (1−√β)² 到 (1+√β)² 之间,两条根被挤成了共轭复数—— 一对模长相等的复数。它们的模长被钉死在 √β,不会炸,但每一步只缩 √β:β 一接近 1,就慢得走不到。
这里 λ 是曲率;一维里曲率就是 Hessian 的特征值(第 7 节展开)。最陡的那个方向(λ = 22) 最先出事,所以整张相图的发散边界就是 η = 2(1+β)/λ——第 3 节那根白虚线。 边界不是经验之谈,是能解出来的。
上半章在想「怎么走得更快」;下半章问一个更根本的问题:停下来,就一定到了谷底吗? 前面六节默默假设了「你停下来的地方真的无路可走」。这一节把这个假设拆掉: 大量「停住」的地方,其实旁边就有下坡路,只是从你现在这个角度看,它长得像一个坑。
两座山之间的垭口(山道上最低的那个口子)。
沿山脊量:垭口是最低点,你前后都往上,看起来「已经到坑底了」。
横着量:垭口是最高点,随便往哪边迈一步,就能一路滑到山下。
你停在那儿不动,不是因为无路可走,是因为你只沿着山脊量了方向。
这种点有个名字:鞍点(saddle point),马鞍上「前后往下、左右往上」的那个位置。
下面两个画布画的是同一片地形、同一个点、同一组数。 那个 +0.05(x⁴+y⁴) 只在远处起作用:没有它,球会一路滚到无穷远;中心这一带的形状还是马蹄形。 左边那张可以拖着转;右边跟着一个「切哪个方向」的滑块。 同一个点,沿不同方向量出来的曲率会从 +2.00 经过 0,一路变成 −2.00。
同一片地形、同一个点:左边看得出它没卡住,右边看不出来
可拖拽旋转的三维鞍面(按住 Ctrl/⌘ 滚滚轮可以缩放;手机上是两根手指拖)。 绿、粉两条线是 Hessian 的两个特征方向(这张脸上只弯不拐的那几个主方向): 绿的那个向上弯、粉的那个向下弯。同一张脸上,一个方向向上、一个方向向下,这就是鞍点。 琥珀色的那条是当前切片的切痕。
同一片地形的一个二维切片:沿琥珀色切痕切开,横轴是在这个方向上的位置 t。
小球就是左边那颗球,t = 球·u 是它在切片方向上的真实分量——
点积算的就是「把位移投影到切口方向上,还剩多长」(现场算出来的)。
读数里的 uᵀHu 是「沿这个方向 u 切一刀,这一刀的弯曲程度」。
把「切哪个方向」拖回 0°,然后点「轻推一下」:
左边那颗球沿着粉色的方向滑走了,而且越滑越快,最后落在远处一个真的坑里;
右边那颗球却在坑底一动不动:它的位移恰好垂直于这一刀,投影出来就是 0。
在左边你看得出来它没卡住;在右边你看不出来。
而教科书、论文、博客里画的损失地形,几乎都是右边这种二维切片。
再把方向拖到 90° 看一遍:这一刀里原点变成了坡,而且远处真的有一个坑(球最后就停在那儿)。
「这个点到底是坑还是坡」有一个能算的判据:把上面说的那张 Hessian 表拿出来, 看它的特征值(各个主方向上的弯曲量),就能给这个点定性。
把鼠标移到公式上,看它对应左边三维图里的哪一块
| 特征值 λ | 曲率 | 这个点是什么 | 在本章这片地形上(真算出来的) |
|---|---|---|---|
| λ₁…λₙ 全为正 | 每个方向都向上 | 局部极小 | 球最后停下的地方:+2.00 / +4.00 |
| λ₁…λₙ 全为负 | 每个方向都向下 | 局部极大 | 把上面那张脸倒过来 |
| 符号混合(有正有负) | 有的方向向上、有的向下 | 鞍点 | 原点:+2.00 / −2.00 |
| 全部 ≈ 0 | 一片几乎水平 | 平坦区(退化) | 训练中途最常见的「停住」,梯度接近 0 但没到坑底 |
互动 · 四个滑块位:λ₁、λ₂ 决定这个点到底是什么
判据只有一句话:只要有一个方向是向下的,它就不是坑。
全正才算局部极小,有正有负就是鞍点,两个都约等于 0 是退化(平坦区)。换成好算的写法:2×2 的情况看行列式
det H = λ₁λ₂——行列式说的是这张表把一小块面积放大几倍,两个方向一正一负、乘出来就是负数,
所以 λ₁λ₂ < 0 就是鞍点。
这一章反复用到「二阶导」,地基在《数学急救包》的「导数与偏导」那一节,
看到 ∂²L/∂w² 发懵就回去看一眼。
在二维里,「有正有负」听起来像个巧合。在 n 维里它是默认结果,理由朴素得有点滑稽: 想在某个点卡住,必须让每一个方向都向上。 方向越多,同时满足越难。而且不是「难一点」,是指数级地难。
下面这张图真的在采样:对每个维度 n,随机生成 4000 个点, 每个方向独立地有 p 的概率向上,然后数一数「一个下坡方向都没有」的比例。 两根滑块可以调,调完立刻重跑。
互动 · 数一数「无路可走」的点有多少(4000 次真采样)
| 模型 | 参数个数 n | 「所有方向都向上」的概率(p = 0.5) | 换句话说 |
|---|---|---|---|
| 上一章那个 2→3→1 的小网络 | 13 | 1 / 8192 ≈ 1.2e-4 | 掷 13 次硬币全是正面,还有可能 |
| LeNet-5(读手写数字的小网络) | 6 万 | 10−18,062 | 写出来是一页纸的数字,但已经写得出 |
| ResNet-50(常用图像骨干网络) | 2560 万 | 10−7,706,368 | 这个指数比整本《战争与和平》的字符数还多 |
| GPT-3(大语言模型) | 1750 亿 | 10−52,680,000,000 | 宇宙里的原子数大约是 1080,差得没法比 |
① 这个模型是简化的。「每个方向独立、概率 p」是最简单的假设,真实网络的 Hessian 不是随机矩阵。 但结论的方向是稳的:在高维里要所有方向同时向上,代价是指数级的。
② 不是说坑不存在。有工作(Choromanska 等 2015)指出:深层网络的局部极小值大多和全局最优差不多好, 差的那一小撮才值得担心。所以准确的说法是:「卡住」多数不是卡在坑里,而不是「坑不存在」。
现在回头看第 2 节那张五个优化器赛跑的图。它比的是「陡的方向上稳不稳」;
这一节补上另一半:平坦的方向上快不快。
做法很直接:把这片鞍点地形整体乘一个系数 γ(γ 越小,地形越平、
实测 · 地形越平,谁越慢?(每条线都是真的迭代出来的)
| 地形缩放 γ | 朴素 SGD | 动量 β = 0.9 | Adam |
|---|
三者的
| 方法 | 实测斜率 | 为什么 |
|---|---|---|
| 朴素 SGD | −1.00 | 步长正比于梯度,梯度小就真的迈不动:地形每平 10 倍,它就慢 10 倍(逃逸步数正比于 1/γ) |
| 动量 β = 0.9 | −0.90 | 最近约 10 步的梯度被攒起来了,平坦方向的小梯度也能推出路程。它不改变 1/γ 这个量级,但稳定地比 SGD 好一截 |
| Adam | 0.00 | 分母 √v 把 γ 约掉了:γ 把梯度乘 1000 倍,v 就乘 100 万倍,开根号又回到 1000 倍。√v 是「对角 Hessian 的粗糙代理」,它把陡度除掉,平地和陡地走一样的步子 |
因为还有第三个免费的帮手:小批量的随机噪声(就是《梯度下降与反向传播》里说的 SGD 噪声)。 它每一步都在给参数一个随机扰动,本身就足以把球从鞍点推出去,所以用 SGD 的人不需要更强的逃逸机制。 但噪声不可控,Adam 的逃逸是可控的,这是它成为默认选项的原因。
互动 · 鞍点旁边那颗球:一点噪声就能把它送走
「哪些方向向上」这件事,一阶方法(只看梯度)是看不见的: 鞍点处梯度就是 0,它长得和平坦区一模一样。 真正知道答案的是二阶信息。那为什么没人用它?
| 东西 | 数量级 | 结论 |
|---|---|---|
| 梯度 ∇L | n 个数 | 算得动,也是今天所有优化器唯一在读的东西 |
| Hessian H | n² 个数 | 1 亿参数的模型 → 1016 个数 ≈ 40 PB(FP32),存不下也算不动 |
| 只取对角 | n 个数 | 这是工程上的折中,Adam 的 √v 就在近似它 |
| 低秩 / 分块近似 | n·k 个数 | K-FAC、Sophia、Shampoo 走的路:省内存,但实现复杂、多一堆超参数 |
互动 · 一阶信息和二阶信息,差了多少个数
| 它不成立的地方 | 什么时候真的会痛 | 说明 |
|---|---|---|
| 凸问题里没有鞍点 | 你在线性回归、逻辑回归、SVM 上跑优化器 | 那类损失的坑就是真的坑,这一章讲的东西在那里不重要。 传统机器学习课里「局部极小」是个大问题,深度学习里不是 |
| 「鞍点」不是唯一让你慢的东西 | 训练停住了,你默认它是鞍点 | 高原、病态的条件数,以及梯度噪声太大和没退火的学习率,都长得很像「卡住」,病因却完全不同。 《症状与病因》讲的就是怎么把它们分开 |
| 三维只是少撒一点谎 | 你把那张三维图当成高维的缩略图 | 真实的优化发生在几亿维里,那里连「方向」这个词的直觉都不再适用 |
这一章有上下两个半场:上半场把优化器铺成一整张谱系,下半场问「停住是不是真的到了谷底」。 两个半场各自收一句话。
回到第 7 节那张三维图,把「切哪个方向」拖回 0°,再点一下「轻推一下」: 同一刀的两边,你能看见的东西完全不一样。
那点差别就是这一章的全部结论。如果刚才你没有想指着某个东西说这句话, 这一节对你就是没用的,回图上再拖一次。
| 线 | 为什么不是它 |
|---|---|
| ① 表达力 vs 泛化 | 鞍点是优化的性质,不是「模型能表达什么」的性质 |
| ③ 规模会赢 | 沾边:参数量越大,鞍点越多于极小值。 但真正的机制是维度,不是规模本身 |
| ⑤ 高维里的低维 | 沾边:鞍点比极小值多,是高维几何的直接后果—— 「所有方向都向上」是一件指数级不可能的事。但它服务的是「拧得动」,不是「数据挤在低维曲面上」 |
| ⑦ 拧得动 | ✅ 这章的位置:几千亿个旋钮为什么拧得动—— 高维损失曲面里几乎每个点都是鞍点,真正的坑少到可以忽略,所以顺着坡走就够 |
| 暗线 | 这一章的回答 |
|---|---|
| A 信息流动 | 形状:梯度是 n 个数(和参数同形),Hessian 是 n×n,从向量变成矩阵,信息量是平方级的爆炸。 这一章所有的图都在做同一件事:把 n 维压到 2 维或 3 维给你看,而压缩本身就是信息丢失 |
| B 什么被牺牲了 | 牺牲了「停住 = 到达」这个判断。你必须接受「梯度为 0 有四种解释」 (极小、极大、鞍点、平坦区),并且承认你几乎没法分辨自己遇到的是哪一种 |
| C 参数账本 | 算力/显存:一阶方法要 n 个数的梯度,二阶方法要 n² 个数的 Hessian。 1750 亿参数的模型:光梯度就 1750 亿个数(≈700 GB,FP32),已经是很重的一笔账; Hessian 是 1022 个数,这是二阶方法在深度学习里彻底出局的原因 |
| D 跑在什么上 | 显存:一阶优化器每一步只是几次逐元素运算(乘、加、除),算力不是瓶颈; 瓶颈是显存能放下多少份状态——Adam 要多存 m、v 两份,连参数、梯度一起一个参数 16 字节(第 4 节那个滑块)。 「换个优化器就 OOM」撞的就是这堵墙 |
| E 它假设了什么 | 假设了「损失面是连续可微的、且 Hessian 的特征值有确定符号」。 ReLU 网络在拐点处二阶导不存在、批量噪声又让每个 batch 的损失面都不同, 这一章的精确图象只在「同一个 batch 的固定损失面」上成立 |
| F 违背了哪个直觉 | 「停下来了,说明到坑底了」。 这是关于优化最顽固的错误直觉。真相是:梯度为零只说明这个方向上平, 换个方向可能一路往下,而且高维里这种情况是绝大多数 |
它接住了上一章的什么:《梯度下降与反向传播》算出了一个方向(梯度), 但没说这个方向什么时候会骗人。这一章说的就是它骗人的那一种情况。
它给后面的章留了什么:既然「停住」不一定是到坑底, 那怎么让模型少在平坦区浪费时间?两条路:一条是《过拟合与正则化》说的 「给参数系一根橡皮筋」(把地形本身往好的方向改), 另一条是《初始化与训练稳定性》说的「一开始就别站到坏地方」。
上半场:一整条优化器谱系,翻来覆去只改「方向」和「步长」两个旋钮。
落到代码里,它们全都是 torch.optim 后面换个名字,所以别在「选哪个」上纠结:
默认用 AdamW + warmup + cosine + 梯度裁剪就够了。
下半场:停下来不等于到了谷底——高维里几乎总有一条下坡路,你只是从二维切片上看不见。
上面讲的都是「够用」的版本。想往下挖,这里有三个入口, 它们不是必修内容,是给想再往前走一步的读者准备的。