JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

导数与梯度:斜率这个想法

导数不过是曲线在某一点的陡峭程度;梯度则是同一个想法在许多旋钮上同时展开,指向上坡的方向。两者合起来,就是让模型得以学习的指南针——这里只讲直觉,不需要证明。

斜率不过是「变化有多快」

先把「微积分」这个词放一边。想象你在徒步,低头看脚下:地面是平的、缓缓上升的,还是陡峭攀升的?那种感觉——再往前迈一步,你的高度变化多少——就是斜率导数不过就是这个斜率,在曲线上某一个点处测出来的值。如果一个函数 f 把输入 x 变成输出,它的导数告诉你:把 x 轻轻推动一点点,输出会移动多少、朝哪个方向?

让导数成为「某一点的斜率」而不是「某一段的斜率」,靠的是把步子缩到几乎消失。在曲线上取相邻的两点,画出它们之间的直线,读出它的倾斜:上升量除以前进量。现在把第二个点不断地往第一个点靠近。这条直线就不再是粗略的平均,而变成精确的切线——也就是曲线在那一点的斜率。那个极限处的倾斜,就是导数。

把符号和大小当成仪表盘来读。导数为正,意味着你向右移动时曲线在上升;为负则在下降;为零则是平的——一个山峰、一个山谷,或者一段暂时的平台。数值大表示陡,数值小表示几乎水平。这就是导数全部的「情绪内容」:朝哪个方向、有多用力。

从一个旋钮到许多个:梯度

单个导数回答的是一个输入的问题。但真正的模型有成千上万、甚至上亿个可调的数字——它的权重参数。想象一台调音台,上面是一大排推子,还有一个你想往下压的输出表(误差)。对每一个推子,你都能问同一个小问题:如果我只推动这一个,表会往哪边动、动多少?做这件事时,把其他所有推子都按住不动——这种一次只动一个推子的斜率,就是偏导数

现在把所有这些「一次一个」的斜率收集成一张清单——每个推子对应一个数字。这张清单就是梯度。因为它不过是一摞带着长度和方向的数字,所以它是一个向量,正是你在前面向量那篇里见过的那种对象;正是这种向量视角,让我们能一次性谈论所有旋钮,而不必一个一个地折腾。

这里有一个值得记住的事实:梯度指向上升最陡的方向。在雾里站在山坡上,梯度就是那根指南针,告诉你「此刻沿这个确切的方向走,爬得最快」。它的长度告诉你这条最快上坡有多陡。而相反的方向——负梯度——指向最快*下山*的路。那个朝下的箭头,正是梯度对学习重要的全部原因。

链式法则:相乘的斜率

真正的模型不是单个函数;它们是函数套在函数里面。原始输入喂给一层,那一层的输出喂给下一层,最后的输出再喂给误差。要学习,我们需要那个最终误差对深埋其中某个旋钮的斜率。链式法则正是让我们拿到它的规则,而它的想法简单得几乎令人尴尬:当变化沿着一条链条传递时,它们的斜率会相乘

想象一组齿轮。如果大齿轮每转 1 圈,中齿轮转 2 圈;中齿轮每转 1 圈,小齿轮转 3 圈,那么大齿轮每转 1 圈,小齿轮就转 3 × 2 = 6 圈。你是通过把链条上各处的局部比率相乘,得到了整体比率。链式法则对斜率说的正是这件事:末端对起点的敏感度,等于每一环对它前一环敏感度的乘积。

这种相乘也解释了为什么深层网络会很娇气。如果许多环节各自的斜率都小于 1,那么随着链条变长,乘积会朝零收缩,最早的那些层几乎感受不到误差——这就是著名的梯度消失问题。如果环节大于 1,乘积反而可能爆炸。链式法则对这两种情况都很诚实:它只如实报告相乘的结果,哪怕答案小得或大得令人头疼。

对于一个真实的网络,你几乎永远不会用手去套链式法则。软件会为每一个运算建立一张计算图,再倒着走一遍,自动把局部斜率相乘——这种技术叫自动微分,也是反向传播背后的引擎。你的任务不是手摇代数,而是信任它算出的结果;并且在训练卡住时,能认出背后悄悄作祟的,正是这条相乘斜率的链条。

为什么梯度驱动学习

现在一切都对上了。「学习」意味着调节旋钮,让模型的错误变小。我们用一个损失函数来度量这些错误——它是一个数字,模型对的时候低,错的时候高。全部权重合在一起,定义出一片广阔、起伏的曲面,叫做损失地形,其中海拔就是损失。训练就是在那片曲面上寻找一处低谷,而梯度是我们唯一用来判断哪边是下坡的感官。

这个配方简单得近乎可笑。算出梯度(哪边是上坡),把它反过来朝下,迈一小步,然后重复。这个循环就是梯度下降,几乎训练每一个现代模型的主力。每步的大小由一个叫学习率的旋钮决定:太小,学习就爬行;太大,你就一步跨过山谷,来回乱弹。大多数网络用的是一个廉价、带噪声的版本,每次只用少量样本来迈步——随机梯度下降——它更快,而且很奇妙地,往往泛化得更好。

# one step of learning, in four honest lines
loss      = compute_loss(model, batch)   # how wrong are we?
grad      = gradient(loss, model.weights) # which way is uphill?
model.weights -= learning_rate * grad     # step the opposite way
# ...repeat thousands of times until loss stops dropping
训练循环的精神内核:度量误差,找出上坡的梯度,再把权重往下坡轻推。所有更花哨的东西,都是对这四行的精化。

对它能带来什么,要诚实。梯度下降可靠地找到的是一处*低*点,而不是*最低*点——这片地形里布满了局部极小与鞍点,那里斜率是平的,但你并不在谷底。对于较简单模型那种碗形的、的损失,这没问题;但对于深层网络,根本谈不上保证,我们歪打正着掉进去的那些谷底通常够用,这是实践中的一点小小奇迹(而非定理)。

带着往后走的东西

要读懂这条阶梯后面的内容,你一个导数都不用手算。你需要的是那幅画面:导数是曲线在一点处的斜率,梯度把许多旋钮的这些斜率收集起来并指向上坡,链式法则把斜率穿过层层套叠的函数相乘,而学习不过是反着梯度一次次往下坡迈步。记住这四句话,后面那些笨重的机器,就会像一位你早已认识的朋友。

  1. 导数 = 一点处的斜率:当你推动一个输入时,输出朝哪个方向、以多陡的程度移动。
  2. 梯度 = 一个偏导数向量,每个旋钮一项;它指向上升最陡的方向,所以它的相反方向指向下坡。
  3. 链式法则 = 斜率沿着函数链相乘;这正是反向传播所自动化的事。
  4. 学习 = 沿着负梯度一小步一小步地走,直到损失不再下降——并接受它落入的是一处不错的谷底,而非完美的那个。

最后一句对炒作的提醒:梯度里没有魔法。它给模型的是一种方向感,而不是理解。梯度无法告诉你数据是否有偏、损失是否在度量正确的东西,也无法告诉你更低的误差是否意味着真正的智能。它是一个绝妙而简单的指南针——而指南针的好坏,取决于你拿它对着的那张地图。保留这份怀疑;在这条阶梯上方的每一级,它都会帮到你。