第 02 篇 · 第一部分 · 模型到底是个什么东西
模型是怎么"学会"的:损失函数、梯度下降与反向传播
上一篇把模型拆成了一系列可以调整的旋钮,可旋钮不会自己转。所谓"训练",本质就是反复试错,然后把误差一点点抹平。整个过程的骨架只有三样东西:一把量误差的尺子(损失函数)、一套找方向的走法(梯度下降)、和一台逆向追责的机器(反向传播)。把这三样串起来,你就看懂了训练的全貌。
一、学会 = 把误差压到最小
先想一个人是怎么学打靶的。第一枪打偏了,靶纸上留下一个洞,离靶心还有三厘米。你根据这个偏了多少、往哪偏,下一枪稍微调整一下手。打十枪,看十个洞整体偏在哪儿,再修一次。循环往复,洞就慢慢往靶心聚拢。
模型训练一模一样。它先任意给出一个取值,拿给的结果和正确答案比一比,算出差多远,再回过头调整自己那几百万个参数,让下一次的输出更接近正确答案。整件事里没有任何"智慧",只有"量差距、改参数"这一个动作,重复千百万遍。
所以训练的核心问题有两个:怎么量差距,怎么改参数。前者交给损失函数,后者交给梯度下降和反向传播。
二、损失函数:给模型的表现打分(MSE 与交叉熵)
要改进,得先能打分。衡量模型误差有多大的那个函数,就叫损失函数,也叫代价函数。它出现的理由很直白:没有一把统一的尺子,就没法比较两组参数谁更好。
做回归任务——预测房价、温度这类连续数值——常用的是均方误差(MSE)。把每个样本的预测值和真实值相减,取平方,再对所有样本求平均:
MSE = (1/n) · Σ (ŷi − yi)2取平方有两个好处。一是正负误差不会互相抵消——偏左三厘米和偏右三厘米都算错,不能无意中相互归零;二是偏差大的样本会被放大惩罚,让模型优先去修正那些误差最大的地方。平方的代价是对离群点敏感,数据里若有个别偏差极大的记录,整体就会被它带偏,这一点留到后面再谈。
做分类任务——判断这封邮件是不是垃圾、这张图是猫还是狗——常用的是交叉熵。模型对每个类别输出一个概率,交叉熵看的是"它给正确答案分了多少概率"。给得多,损失就小;给得少,损失就大。它对"自信却答错"惩罚得特别重——你很确信地判定这条是正常邮件、结果却是垃圾邮件时,交叉熵会记上一笔很大的损失。
选错损失函数是新手常犯的错误。用 MSE 去做分类,梯度往往偏小,学得慢还容易卡住;分类任务改用交叉熵,训练才会顺畅。损失函数要选对。
三、下山:梯度下降的直觉
有了损失这把尺子,训练就变成了一个寻优问题:找到一组参数,让损失最小。
想象你蒙着眼睛,被带到一座山上,任务是走到山谷最低处。你看不见全景,但能感觉到脚下哪边陡、哪边缓。梯度就是"最陡的那个方向",它告诉你:往哪个方向迈一步,损失上升得最快。那么反着走——朝梯度的相反方向迈步——损失就下降得最快。这就是梯度下降。
每一步都这样:算当前脚下的坡度,往低处挪一点,再算一次坡度,再挪。走的步数够多,就一点点滑到谷底。参数更新那一行,简单得出奇:
参数 ← 参数 − 学习率 × 梯度是的,就是这么个减法。深度学习听起来高深,训练循环里最核心的动作,简单说就是不停地做这道减法。
四、学习率:步子迈多大是门学问
公式里那个学习率,是全场最难调的一个超参数。它决定每一步迈多远,跟下山时步幅大小是一回事。
步子太大,你会一脚从山坡这边跨到对面山坡上,来来回回在谷底两侧上下震荡,永远落不下去,损失曲线在训练日志里剧烈波动。步子太小,方向对,可你进展缓慢,训练很久也到不了谷底,白白消耗算力。常见的学习率在 0.1 到 0.0001 之间,具体取多少得看任务。
实践中还有更周到的办法。学习率预热:刚开始用小步走,先稳住再放大,避免一开始就冲过头。学习率衰减:越靠近谷底步子收得越小,便于精确定位。还有一类叫 Adam 的自适应方法,它给每个参数单独配一个步幅——这个参数历史梯度大就压小一些,小就放宽一些,实践中常常比自己手动调整更省力。Adam 的原始论文是 2014 年的,到今天仍是常用的默认选择之一。
一句话记住:学习率调大,训练快但容易发散;调小,稳但慢。这是个权衡,没有万能值。
五、反向传播:误差怎么一层层追责
现在有了尺子和走法,还剩一个麻烦:一座网络动辄几十上百层、几亿个参数,每个参数各自的"坡度"从哪来?总不能一个参数一个参数地去试——试一次就要运行一遍前向,参数有十亿个,无论如何都算不完。
反向传播就是来解决这个麻烦的。它的思路是:误差产生于最顶端那一层的输出,然后像流水线上追责一样,一层一层往回倒推,算出每个参数对这次误差"该负多少责任",也就是各自的梯度。
类比一下工厂返工。总装线上出来的成品不合格,你不会把每个零件重新拆一遍找原因,而是沿着工序往回追:总装出了问题,说明某个部件尺寸不对;这个部件不对,说明上游的原材料有偏差。一层层往上追,每个环节的责任很快就算清了。反向传播干的正是这个——把最终那个误差,按贡献比例分摊回每一个权重。
它的关键之处在于一次前向、一次反向,就能拿到全部参数的梯度。相比"逐个参数试"的低效做法,效率高出许多个数量级。这是深度学习真正能够运行的前提。
六、链式法则:一句话讲清
反向传播背后其实只站着一个数学事实,叫链式法则。它的内容一句话就够:复合函数的导数,等于各层导数的乘积。
通俗地说:最终误差对某个早期参数的影响,等于这条因子链上每一环影响的连乘。前面那层的参数要影响结果,得先影响它后面一层的输出,再一层层传下去才能最终影响误差。每传一层,乘一个当地的变化率。
为什么会连乘,是理解后面所有"梯度问题"的钥匙。连乘意味着:只要每一环的系数平均小于 1,几十层乘下来,结果会指数级地趋近于零——这就是广为人知的梯度消失。反过来,系数普遍大于 1,就会指数级爆炸,称为梯度爆炸。深层网络难以训练的诸多根源,都藏在这连乘里。这一问题等讲到 RNN 时会重新计算一遍。
七、随机梯度下降与小批量:为什么要"分批"学
理论上,每次更新参数该拿全部样本算一遍总损失,方向最准。可现实里,训练集动辄上百万张图,每次更新都运行一遍全部数据,一步就要等很久,内存也承受不住。这种做法叫批量梯度下降,方向准确,但慢到难以使用。
于是有了随机梯度下降(SGD)的思路:不看完全部样本,而是每次随机抽取一个(或一小批)样本,就根据它计算梯度、走一步。方向当然不那么准,带着噪声,但胜在快,走的步数也多得多。实践中几乎不会真的"一次一个",普遍做法是取一小批——32、64、128 张样本拼成一个批量,一起算,一起更新。这叫小批量梯度下降,是今天训练的默认做法。
批量大小这个数也有讲究。批量太小,梯度噪声大,损失曲线抖得厉害;批量太大,单步方向更稳,但每步更贵,泛化性能有时反而会下降。它不是越大越好,得跟学习率搭配着调。为了加快收敛、少走弯路,实践中还会引入动量的思路——让这一步的更新保留上一步的方向,像滚下山坡的球顺着惯性往前冲,从而平滑地越过一些局部波动。
八、过拟合与欠拟合:背答案和懂道理的区别
损失降下来,不代表模型就学对了。这里有一对绕不开的孪生问题。
欠拟合:模型容量不足,或者根本没有学到东西。训练集上错,测试集上也错,两边都差。好比一个学生连课本上的例题都没弄懂,自然也做不出新题。解决办法通常是增加参数、增加层数、训练得更久一些。
过拟合:模型把训练集背了下来,包括里面的噪声和偶然。训练集上分数高得惊人,一换到没见过的测试集就表现骤降。像一个学生把练习册答案连同错别字一起背了,考试换个题就无从下手。这才是训练里更常见的敌人。
两者中间才是理想状态:训练和测试表现都好,而且差距小,说明模型学的是普适规律,不是死记硬背。判断过拟合有个朴素办法——盯着训练损失和验证损失这两条曲线:训练损失一路往下,验证损失却在某个点掉头往上,那个拐点就是过拟合开始的地方,就该及时停止训练。
对付过拟合有几套常用手段。增加数据量,是最根本的办法;正则化,在损失里加一项惩罚,抑制参数过大(L2 正则就是朝这个方向作用);Dropout,训练时随机把一部分神经元临时"断开",迫使网络不要过于依赖某几条路径;还有早停,就是前面说的,验证损失一旦上扬就停,不等到训练损失降到最低。这些手段的共同思路都是:不要让模型学得过死。
九、一轮训练在运行什么循环
把上面所有零件装回一台机器,训练的一小步长这样:
- 前向传播:把一小批数据喂进网络,逐层算到输出,拿到预测值;
- 算损失:用损失函数比较预测和真实标签,得到一个数;
- 反向传播:从这个数出发,逐层往回算出每个参数的梯度;
- 更新参数:按"参数 ← 参数 − 学习率 × 梯度"改一遍旋钮;
- 清空梯度,换下一批数据,回到第 1 步。
把训练集里所有样本都过一遍,叫一个epoch。数据里有几万个批量,一个 epoch 就要运行几万步。通常要运行几十到几百个 epoch,模型才收敛到一个不错的水平。至于开销:一个几亿参数的模型,在单张消费级显卡上一个 epoch 可能就要几十分钟;换成千亿参数的大模型,那就要成百上千张卡连续运行几周。
回过头看,训练其实没有魔法。它就是把"量差距、找方向、改参数"这件事,在几十亿个参数上、用几十亿个样本,重复做下去。真正了不起的不是这条循环本身,而是——我们竟然有办法让它稳定地运行完成。
参考资料
- David E. Rumelhart, Geoffrey E. Hinton, Ronald J. Williams, Learning representations by back-propagating errors, Nature, 1986. nature.com/articles/323533a0(反向传播的经典出处)
- Yann LeCun, Léon Bottou, Genevieve Orr, Klaus-Robert Müller, Efficient BackProp, 1998. yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf(手把手讲怎么把反向传播调利索)
- Ian Goodfellow, Yoshua Bengio, Aaron Courville, Deep Learning, MIT Press, 2016. www.deeplearningbook.org(第 6 章讲前向与反向,第 8 章讲优化)
- Diederik P. Kingma, Jimmy Ba, Adam: A Method for Stochastic Optimization, 2014. arXiv:1412.6980(自适应学习率的代表作)