梯度下降与优化器
第 5 章的反向传播能算出「每个权重该为错误负多大责任」,但知道责任之后呢?答案是朝责任的反方向挪一小步,然后重复几万次。这个笨办法叫梯度下降——它是整个深度学习真正的发动机。
6.1 蒙眼下山:一个贯穿全书的比喻
想象你被蒙上眼睛,放到一座山的半山腰,目标是走到谷底。你看不见整座山,但你能做一件事:用脚踩一踩周围的地面,感受哪个方向最陡。于是策略显而易见:找到脚下最陡的下坡方向,朝那边迈一小步,再感受一次,再迈一步……直到四面八方都是上坡,你就到了(某个)谷底。
把「山」换成损失函数,把「你的位置」换成当前的权重,把「最陡的下坡方向」换成负梯度方向——这就是梯度下降,一个字都不差。梯度 ∇L 指向损失上升最快的方向,所以要往它的反方向走:
w ← w − η · ∇L(w)其中 η(eta)是学习率,就是你每一步迈多大。∇L 由反向传播提供(第 5 章),η 由你来定——而第六章的半部血泪史,都写在这个小小的 η 上。
梯度下降 = 蒙眼下山:看不清全局,就看脚下;每步都朝最陡的下坡方向挪一点,重复到哪儿都是上坡为止。
6.2 学习率:一步迈多大
下山故事里唯一没说清的是「一小步」到底是多小。这个选择只有四种命运,而且泾渭分明:
- 太小:方向完全正确,但步子像蜗牛。会到谷底,只是你可能等不到那天。
- 合适:步子大而不失控,损失快速下降,稳稳收敛。
- 太大:一步跨过谷底,在两边山壁之间来回弹跳,损失迟迟降不下去。
- 巨大:每跳一步都比上一步更远,直接飞出山谷——损失爆炸,训练发散。
用最简单的损失函数 L(w) = w2 就能把这四种命运全部演出来。它的梯度是 2w,更新规则是 w ← w − 2ηw = w·(1 − 2η)。当 η > 1 时,|1 − 2η| > 1,每一步都在放大——数学上必然发散。在下面的演示里亲手验证:
演示 1 · 学习率的四种命运
调 η 看命运w 从 4 出发。发散时轨迹会飞出画面——这正是真实训练里「loss 突然变成 NaN」的样子。换成平缓的 L = w²/20 再看看:同样的 η 忽然变得「龟速」了,因为坡度本身变缓了。
注意一件事:没有「万能的好学习率」。同一个 η = 0.25,在 L = w² 上恰到好处,在 L = w²/20 上就慢得让人着急。坡度越缓的曲面需要越大的步子——这也是为什么学习率永远是训练时第一个要调的超参数。
对 L = w² 而言,|1 − 2η| 决定了命运的全部:小于 1 收敛,等于 1 原地弹跳,大于 1 发散。真实网络的损失曲面没有这么整齐的解析式,但「存在一个临界学习率,过了就炸」这件事普遍成立——所以工程上常用「先小后大慢慢试」或学习率搜索来找它。
6.3 优化器进化史:从裸走到自适应
朴素的梯度下降(SGD,随机梯度下降)就是「裸走」:每步只信当下的梯度。它够用,但在真实地形上经常难堪——狭长的山谷里来回震荡,浅坑里爬不出来,鞍点(一个方向是谷底、另一个方向是山顶的点)附近磨磨蹭蹭。于是人们给它加了两次重大升级:
Momentum(动量):给下山者加上「惯性」。不再只看脚下这一步的梯度,而是让之前几步的方向也参与投票——像滚下山的雪球,越滚越有自己的主意:
v ← β · v + ∇L(w) , w ← w − η · vβ 通常取 0.9:新方向里九成是「惯性」,一成是「脚下的新情报」。效果立竿见影——在狭长山谷里,左右震荡的分量互相抵消,沿谷方向的分量持续累加;遇到浅坑,积累的动量直接把它冲过去。
Adam:思路再进一步——给每个参数单独配一个学习率。它同时追踪梯度的一阶平均(m,类似动量)和二阶平均(v,梯度有多「抖」),再用前者除以后者的平方根:梯度一直很大的参数,步子自动调小;梯度稀稀拉拉的参数,步子自动放大。还加上偏差修正(开头几步 m、v 都偏小,要补偿)和一个防除零的小常数 ε = 10−8:
w ← w − η · m̂ / (√v̂ + ε)Adam 几乎不挑学习率(0.001 起步通常就能用),在各种地形上都表现稳健,是今天默认的首选优化器。口说无凭,让三位选手在同一片地形上赛跑:
演示 2 · 优化器地形赛
三种地形三位选手从同一起点(黑点)同时出发。为公平起见,每种地形给三者的默认学习率都单独调过:椭圆碗 η = 0.10 / 0.02 / 0.20,Rosenbrock η = 0.0008 / 0.00015 / 0.30,鞍点 η = 0.015 / 0.006 / 0.04(依次对应 SGD / Momentum / Adam)。赛完换块地形再赛一场,感受会完全不同。
椭圆碗 L = x² + 8y²:沿 y 方向的坡度是 x 方向的 8 倍,裸走的 SGD 会在陡壁上 zigzag。
几个值得回放的画面:椭圆碗里 SGD 的锯齿(陡方向震荡、缓方向爬行)正是 Momentum 要治的病;Rosenbrock 香蕉谷里那条又窄又弯的谷底会让大个子步伐吃尽苦头,Adam 的逐参数步长优势最明显;鞍点 L = x² − y² 没有谷底(往 y 方向一路向下),看点是「谁在鞍点附近磨蹭最久」——SGD 往往在原地徘徊很久,而 Adam 会把那个微弱的逃逸梯度放大,最早溜走。
6.4 mini-batch:为什么故意用「不准」的梯度
还有一个反直觉的细节:训练时几乎从不用全部数据算梯度,而是每次随机抽一小批(mini-batch,常见 32~256 条)算一个「带噪声的梯度」。原因有三:
- 算得动:几百万条数据全算一遍梯度才能走一步?一步都嫌贵。一小批就能给出方向大致正确的估计。
- 走得快:同样的数据量,小批量能走几百步,全量只能走一步——参数更新的频率远比单步的精度值钱。
- 噪声是特性,不是缺陷:每批数据带来的梯度抖动,相当于给下山路上随机推你几把。浅坑、鞍点这类「梯度几乎为零的陷阱」,噪声能把你晃出来;完美精确的全量梯度反而会在那里躺平。
mini-batch 的梯度像「抽样民调」:单次不准,但便宜、高频、方向大体正确,附赠的随机抖动还能帮你逃离浅坑和鞍点。这就是「随机梯度下降」里「随机」二字的来历。
6.5 最后一步:让学习率慢慢变小
训练后期,mini-batch 的噪声会让参数在最优点附近一直小幅抖动,无法落稳。标准做法是学习率衰减:随着训练进行,按阶梯、指数或余弦曲线把 η 逐步调小——前期大步快跑,后期小步落脚。一句话记住它:先求快,再求稳。
别拿验证集(更不要拿测试集)来调学习率、挑优化器。每看它一眼、按它改一次超参数,你就朝它泄漏了一点信息,调到最后它就不再能代表「没见过的数据」。超参在训练集 + 验证集上定,测试集一辈子只碰一次——第 7 章讲过拟合时会看到这条纪律的全部理由。
梯度下降 = 沿负梯度方向反复挪小步;学习率决定每一步的命运:太小龟速、合适收敛、太大震荡、巨大发散。优化器三代同堂:SGD 裸走、Momentum 加惯性冲浅坑抑震荡、Adam 给每个参数自适应步长(默认首选)。mini-batch 用噪声换速度和逃离陷阱的能力;训练后期记得衰减学习率。调超参只看训练集和验证集,别碰测试集。