10 课 · 损失函数与梯度
LESSON 10 · 卷十 学会认错

模型怎么知道自己错了

前八课走的全是前向:数据从输入一路流到输出。 可模型里那几亿个数字是怎么变好的?它还一次都没学过。 这一课补上另一半:交叉熵(衡量它有多惊讶)、梯度(往哪个方向拧能少惊讶一点)、学习率(一次拧多大)。 这一课之后,「亲手把它训出来」的零件就齐了。

STAGE 01
有多惊讶
交叉熵 −log p
STAGE 02
只算答案
问题部分是送分题
STAGE 03
往哪拧
梯度 = 最陡的方向
STAGE 04
拧多大
学习率:步子大小

先滚一个球。下面是一座山谷:横轴是模型里的某一个参数 w, 纵轴是损失(越靠下越好)。小球站在山上,它要走到谷底。 点「让它滚下去」,或者自己一步一步点。

招牌动画蒙眼下山 —— 拖学习率,看小球是稳稳下去还是直接飞出去
现在:刚好
学习率(步子大小)0.10
试几个
w(模型的某个参数)20-1.5谷底 w=3
第几步
0
最多 40
现在站在哪
w = 0.0000
目标 w = 3
现在的损失
9.0000
= (w − 3
脚下的坡度(梯度)
-6.0000
下一步:w = 0.00000.10 × (-6.0000) = 0.6000
小球每一步只做三件事:算脚下的坡度(梯度 = -6,一开始是负的, 说明「往右走 loss 会变小」)、往反方向迈一步(w ← w − lr × 梯度)、重复
学习率就是「步子大小」:lr = 0.05 磨磨蹭蹭(要 56 步才到位)、lr = 0.1 稳稳收敛、 lr = 0.5 一步就落进谷底(这条抛物线恰好如此)、lr = 0.9 来回蹦(12 步里越过谷底 11 次)、 lr = 1.1 直接飞出去(30 步后跑到 3.00e+0)。 真实训练里没人这么试 —— 靠的是「学习率预热 + 衰减」(第 12 课)。
👆 换学习率、点「迈一步」,看脚印怎么走。 注意:梯度本身在告诉你方向和陡峭程度,学习率才是你踩油门的力度。 真实模型里有几亿个 w 同时在滚,但每一步的道理和这一个球一模一样。
小球每一步只做三件事:算脚下的坡度(梯度)、往反方向迈一步(w ← w − lr × 梯度)、重复。 学习率就是「步子大小」—— 拖到 0.9 会来回蹦,拖到 1.1 直接飞出画面。
图 10-1 · 梯度给「往哪走」,学习率给「走多大」;两者是两件事
损失告诉你错得多离谱
梯度告诉你往哪拧

三句话讲完这一课

  • 交叉熵 = −log(给正确答案的概率):给得越低,损失越大。 瞎猜的水平是 ln 20 = 2.995732 —— 第 3 课那条真实曲线的起点就是它。
  • 只在答案部分算损失:问题部分(「等于?」)是套话,预测它们等于做送分题 —— 那两个位置的损失正好是 0.000000。
  • 梯度给方向,学习率给步长:太小磨蹭(lr = 0.05 56 步)、刚好收敛(0.1 27 步)、太大震荡(0.9)、 再大发散(1.1)。
换个熟悉的地方想 · 蒙眼下山

你被蒙着眼放在山坡上,要走到谷底。你能做的只有一件事:用脚感受一下哪边最陡,然后往那个方向迈一步

脚下最陡的方向 = 梯度(往哪走损失降得最快)
这一步迈多大 = 学习率
每走一步,脚下的坡度都会变 → 所以要走很多步,而且越接近谷底步子越自然变小

真实模型里,这座山不是一维的,而是几亿维的(每个参数一个方向), 但道理完全一样:算梯度(反向传播,第 11 课)→ 迈一步(优化器,第 12 课)→ 重复。

第 1 站

损失:模型有多惊讶

第 9 课模型吐出来的是一张分布:20 个字各有一个概率。 怎么用一个数字概括「它这一把答得好不好」?

答案朴素得惊人:看它给正确答案打了多少概率, 然后取 −log。给得越高,损失越小;给得越低,损失越大。 这个名字叫交叉熵

核心实验交叉熵曲线 —— 拖概率,看损失怎么涨
模型给正确答案的概率25%
4.81%5%(瞎猜)100%0瞎猜 2.995732
25% → 损失 1.386294
交叉熵就是 −log(给正确答案的概率):给 100% 时损失 0, 给 50% 时 0.693147,给 25% 时 1.386294(= ln 4), 给 5% 时 2.995732 —— 正好是「瞎猜」的水平。

瞎猜为什么正好是这个数?词表里 20 个字,每个都给 1/20, 损失 = ln 20 = 2.995732 —— 第 3 课那条真实 loss 曲线的起点就是它。
概率 → 损失 对照表:
p = 1% → 4.605170
p = 5% → 2.995732
p = 10% → 2.302585
p = 25% → 1.386294
p = 50% → 0.693147
p = 90% → 0.105361
这一条曲线说明了损失的全部脾气:概率越低,损失涨得越凶(不是线性涨,是往无穷冲)。
为什么要用 log 而不是「1 − 概率」这种直白的差距? 因为训练时要靠梯度把参数拧回来(第 11 课):如果模型给正确答案的概率是 0.001,你希望梯度是很大的(赶紧改);log 恰好给了这种「越离谱、拉得越狠」的性质。 用 (1 − p) 的话,0.001 和 0.002 之间的差别几乎为零 —— 模型就学不动了。
注意曲线在左边陡得可怕:概率从 5% 掉到 1%,损失就从 2.995732 涨到 4.605170。 这就是「越离谱、拉得越狠」。
图 10-2 · −log p:给 100% 时损失 0;给 25% 时 1.386294(= ln 4);给 5% 时就是瞎猜
面试常问 · 为什么是交叉熵
  • 它等价于「最大似然」:让模型给正确答案的概率尽可能高, 数学上就等于让交叉熵尽可能低 —— 两条路是同一件事。
  • 为什么不用「1 − 概率」:那种差距太温和。概率 0.001 和 0.002 的差 几乎为零,梯度也就几乎为零,模型学不动。log 在接近 0 的地方陡得吓人, 正好提供「赶紧改」的推力。
  • 怎么读这个数2.995732 是瞎猜(ln 20); 0.69 大约相当于「给正确答案 50%」;0.1 相当于「给 90%」。 训练时盯着它掉就行。
  • 训练 loss 和考卷分数不是一回事:loss 是在训练集上算的, 掉到 0.002 只说明它背得熟(第 13 课)。
第 2 站

只在答案部分算损失

还有一件必须交代的工程细节。我们的任务是「猜下一个字」, 所以一句话里每一个位置都能算损失。但其中一大半是套话

核心实验逐字的损失 —— 哪些位置是送分题,哪些是真本事
问题部分权重0.00
样本:十五加一百一十五等于?一百三
1 个字「问题部分(套话)|模型给 11.7%|权重 0.00|已屏蔽
2 个字「问题部分(套话)|模型给 5.3%|权重 0.00|已屏蔽
3 个字「问题部分(套话)|模型给 18.0%|权重 0.00|已屏蔽
4 个字「问题部分(套话)|模型给 44.1%|权重 0.00|已屏蔽
5 个字「问题部分(套话)|模型给 10.6%|权重 0.00|已屏蔽
6 个字「问题部分(套话)|模型给 26.3%|权重 0.00|已屏蔽
7 个字「问题部分(套话)|模型给 11.7%|权重 0.00|已屏蔽
8 个字「问题部分(套话)|模型给 21.7%|权重 0.00|已屏蔽
9 个字「问题部分(套话)|模型给 100.0%|权重 0.00|已屏蔽
10 个字「?问题部分(套话)|模型给 100.0%|权重 0.00|已屏蔽
11 个字「答案部分|模型给 5.5%
2.891372
12 个字「答案部分|模型给 44.1%
0.818929
13 个字「答案部分|模型给 9.0%
2.403364
这句话一共 13 个「要被预测的位置」: 问题部分 10 个、答案部分 3 个。 (问题部分平均 1.486579、答案部分平均 2.037888。)
平均损失 =(答案 3 个全算 + 问题 10 个 × 权重 0.00)的加权平均
= (6.1136650.00 × 14.865792) ÷ (30.00 × 10) = 2.037888
权重 0(完全屏蔽问题部分)→ 平均损失 2.037888;权重 1(全都算)→ 1.613804。从 0 一路拖到 1,数字越来越好看 —— 但模型一点没变强, 只是卷子里多了几道送分题。
看清「第 9、10 个字」那两个位置:损失正好是 0.000000 —— 「等」后面永远接「于」、「于」后面永远接「?」,这是套话,模型闭着眼都能答对。 让它去预测这些字,等于让它做送分题:白花算力,还把「问题部分很轻松」的假象 混进了 loss 里。所以训练时把问题部分的损失权重设成 0,只盯答案那几个字。
👆 拖「问题部分权重」:问题那几条跟着缩 —— 它们对平均损失的分量就是「损失 × 权重」。 权重 0 时那几条直接归零(已屏蔽),平均损失就是答案部分的 2.037888; 一路拖到 1,平均损失掉到 1.613804。 条的长度 = 这个位置真正贡献给平均损失多少(答案部分的条明显更高,说明真正难的地方在这里)。真实训练时,屏蔽就是一个 mask:问题位置的损失权重设 0, 只对答案位置求平均 —— 这和第 7 课那块因果掩码是同一套思路(「不让它算不该算的」)。
切一下开关:把问题部分也算进去,平均损失从 2.037888 掉到 1.613804 —— 数字变好看,模型一点没变强
图 10-3 · 问题部分平均损失 1.486579、答案部分 2.037888; 「于」「?」那两个位置是 0.000000

样本「十五加一百一十五等于?一百三」一共 13 个要预测的位置, 答案从第 11 个字开始(「等于?」之后),只有 3 个。 训练时就把前面那 10 个位置的损失权重设成 0

这和「考试只批答案、不批题目」是一个意思。那如果不屏蔽,会有什么坏处?(想两条)
第 3 站

梯度:往哪拧

现在我们知道「错了多少」。接下来要回答的是:每个参数该往哪边挪?答案就是梯度 —— 损失对某个参数的斜率。

一维的例子(可以手算)

演示那座山谷是 loss(w) = (w − 3)²,最小值在 w = 3。 它的梯度是:

梯度 = 2 × (w − 3)

在 w = 0 处:梯度 = 2 × (0 − 3) = -6.0(负的 → 往右挪损失变小)
每一步:w ← w − 学习率 × 梯度 = 0 − 0.1 × (-6.0) = 0.600000

照着 lr = 0.1 走五步,每一步都能按计算器核对:

0 步:w = 0.000000,损失 = 9.000000,梯度 = -6.000000 → 下一步 w = 0.600000
1 步:w = 0.600000,损失 = 5.760000,梯度 = -4.800000 → 下一步 w = 1.080000
2 步:w = 1.080000,损失 = 3.686400,梯度 = -3.840000 → 下一步 w = 1.464000
3 步:w = 1.464000,损失 = 2.359296,梯度 = -3.072000 → 下一步 w = 1.771200
4 步:w = 1.771200,损失 = 1.509949,梯度 = -2.457600 → 下一步 w = 2.016960

看出来了:离谷底越远,梯度越大(步子越猛);越靠近谷底,梯度越小(自动刹车)。 这就是为什么梯度下降能稳稳收敛,不用人工调步子 —— 除非学习率太大。

核心实验红色切线 —— 拖小球,看「梯度」就是脚下这条线的斜率
小球位置 w0.00
试几个位置 
w(模型的某个参数)20-1.5谷底 w=3w = 0.00|切线斜率 = 梯度 = −6.00
小球站在哪
w = 0.00
谷底 w = 3
现在的损失
9.0000
= (w − 3
脚下的坡度(梯度 = 切线斜率)
−6.00
= 2 × (w − 3)
该往哪挪
往右 →
挪的方向 = 梯度的反方向
梯度就是斜率:把「梯度」想成小球脚下那条红线的陡峭程度 —— 陡 = 离谷底远、要大步;平 = 到谷底了、自动刹车。
梯度 = 2 × (w − 3) = 2 × (0.003) = −6.00; 损失 = (w − 3)² = (0.003)² = 9.000000。 切线斜率 = −6.00坡度很陡,往右挪损失会变小很多
👆 拖「小球位置 w」:小球在山上走,脚下那条红色切线跟着倾斜,它的斜率就是梯度。 在 w = 0 处切线很陡(斜率 −6,正是上面手算的那个数); 一路拖到 w = 3,切线变成一条水平线,斜率是 0 —— 到谷底了,不用再挪。 绿色的箭头指的是该挪的方向:梯度的反方向,也就是下坡方向。
先拖「小球位置 w」:小球在山上走,脚下那条红色切线跟着倾斜。 在 w = 0 处切线陡得很,斜率正好是上面手算出来的 −6.0;一路拖到 w = 3,切线变成一条水平线, 斜率是 0 —— 到谷底了,自动刹车
图 10-4 · 切线斜率 = 梯度 = 2(w − 3):离谷底越远越陡,到 w = 3 时变成水平

真实模型里没有「几亿维的山谷」这种图,但每个参数都在做同一件事:算自己那一维的斜率,往反方向挪一点点。 把「每个参数的斜率」一次算出来,就是反向传播(第 11 课)—— 它是把损失沿着网络一路往回传,用链式法则逐层求出每个参数的梯度。

第 4 站

学习率:拧多大

梯度告诉你方向,但迈多大一步是你定的。这个「步子大小」就是学习率, 它是训练里最要紧的一个旋钮。

学习率脾气收敛步数30 步后 w离目标多远0.05太磨蹭56 步2.87280.12720.1刚好27 步2.99630.00370.5刚好2 步3.00000.00000.9在震荡27 步2.99630.00371.1发散(越走越远)没收敛-709.1289712.1289
目标 w = 3。lr = 0.05 磨磨蹭蹭(56 步才到位); lr = 0.1 稳稳收敛(27 步); lr = 0.5 一步就落进谷底(这条抛物线恰好如此,纯属巧合); lr = 0.9 来回蹦;lr = 1.1 直接飞到 -7.09e+2
面试常问 · 学习率与 loss 曲线
  • 真实曲线长什么样:第 3 课那条记录是 2.995732 → 2.3768(1000 步) → 1.6222(30 万步)。一开始掉得飞快、后来几乎不动 —— 和山谷里那个小球一模一样(远处坡度大、近处坡度小)。
  • loss 变成 NaN 或者往上飞:十有八九是学习率太大(或者没做梯度裁剪)。 页首动画里 lr = 1.1 就是这种情况。
  • 真实训练怎么设:不用一个固定值,而是先预热再衰减 —— 开头几百步从很小的学习率慢慢升上去(防止一开始就把参数带偏), 之后慢慢降下来(让它在谷底附近细调)。第 12 课细讲。
  • 梯度裁剪:如果某一步的梯度特别大(比如遇到一个异常样本), 就把它的长度砍到一个上限再走 —— 相当于给油门装个限速器。

到这里,训练的四个零件就齐了:损失(错多少)、梯度(往哪拧)、学习率(拧多大)、循环(重复几万次)。 下一课把「梯度怎么一次算出来」这件事讲透(反向传播), 再下一课把整套训练循环装起来 —— 然后你就能亲手训出第 3 课那个模型了。

第 5 站 · 收官

把这一课钉在墙上

本课核心 · TAKEAWAY

训练就四件事:损失衡量「错得多离谱」——−log(模型给正确答案的概率),瞎猜的水平是 ln 20 = 2.995732,给 25% 时是 1.386294梯度告诉每个参数「往哪边挪损失会降得最快」;学习率决定「一次挪多大」——太小磨蹭、太大震荡甚至发散; 最后循环几万次。 两个容易被忽略的细节:问题部分的损失要屏蔽(那是送分题, 只会让数字好看),以及训练 loss 低 ≠ 模型好(它只说明背得熟)。 真实训练的 loss 曲线和页首那个小球是同一件事:一开始掉得飞快,后来几乎不动。

这一课你亲手做完了

  • 滚过小球:lr = 0.1 五步走到 w = 2.016960, 每一步都等于「w − lr × 梯度」(按计算器能核对)。
  • 试过五个学习率0.05 / 0.1 / 0.5 / 0.9 / 1.1 —— 磨蹭(56 步)/ 收敛(27 步)/ 一步到位 / 震荡(12 步越过谷底 11 次)/ 发散(-7.09e+2)。
  • 拖过交叉熵曲线:p = 25% → 1.386294(= ln 4); p = 5% → 2.995732(正好是瞎猜)。
  • 拆过一句话的损失:问题部分平均 1.486579、 答案部分平均 2.037888;「于」「?」两个位置是 0.000000。
  • 对照过真实曲线2.995732 → 2.3768(1000 步)→ 1.6222(30 万步)。

学习小测验

已完成 0 / 60.0%答对 0
还没提交过 —— 每题先选一个选项,再点「提交」,答完就能看到诊断。
Q1交叉熵损失算的是什么?
Q2词表里 20 个字,一个完全没训练的模型(每个字都猜 1/20)的损失是多少?
Q3为什么训练时要「只在答案部分算损失」,把问题部分屏蔽掉?
Q4「梯度」到底是什么?
Q5学习率设得太大,会发生什么?
Q6训练 loss 已经掉到 0.002,可考卷分数只有 66% 上不去。这说明什么?
NEXT · 第 11 课

反向传播:几亿个梯度怎么一次算出来

这一课我们说「梯度告诉每个参数往哪挪」,可一个 80 万参数的模型就有 80 万个方向, 几亿参数的模型有几亿个 —— 它们是怎么一次全算出来的? 下一课就讲这件事:链式法则(把导数一层层乘下去)、计算图(前向存下的中间结果怎么复用)、 以及为什么「loss.backward() 这一行就干完了全部」。

从零手册 —— 下一课:反向传播:几亿个梯度怎么一次算出来