机器学习的训练过程,从最朴素的线性回归到 GPT,本质上都是同一件事:
定义一个表示「模型预测有多错」的数 L,然后调整参数让它变小。
「调整参数让它变小」听起来抽象——但只要你能算出 L 对每个参数的导数,你就知道每个参数往哪个方向动会让 L 变小。整个深度学习的训练循环就两步:
- 算损失 L 对所有参数的梯度 ∇L。
- 把参数往 −∇L 方向挪一小步。
这就是梯度下降。理解它需要的微积分,只是导数和链式法则两件事的几何化。这篇我们就把它们画出来。
导数 f′(x0) 就是函数 f 在 x0 这个点的切线的斜率。
定义式:
f′(x0)=h→0limhf(x0+h)−f(x0)
公式里的「极限」「无穷小」让人头大,但几何上就是一句话:把切线斜率代数化。
拖动下面的圆点感受一下:
导数(斜率)
f′(x) = 0.92
正 → 这里在上升
拖动小圆点。彩色那条线就是该点的切线——它的斜率就是导数。
几个值得留意的事实:
- 导数 大于 0 → 函数在这里上升(往右走 f 增加)。
- 导数 小于 0 → 函数在这里下降。
- 导数 等于 0 → 切线水平 → 极大值、极小值或者鞍点。
最后一条是优化的核心:所有的最小值都满足 f′(x)=0。所以要找最小值,就是去找导数等于零的地方。
ML 里的损失函数不是 1 维的,而是依赖几千万、几亿个参数。一个 n 元函数 L(w1,w2,…,wn) 没有「斜率」这种单一的数——但它有 n 个偏导数:
∂wi∂L
意思就是「假装其他参数全冻住,只动 wi,L 的斜率是多少」。
把这些偏导数打包成一个向量,就是梯度:
∇L=(∂w1∂L,∂w2∂L,…,∂wn∂L)
这就是这篇最关键的一句话:
梯度 ∇L 指向 L 在当前位置上升最快的方向,大小是上升的速率。
所以反过来,−∇L 就是下降最快的方向——这就是「下山最陡的路」。
为什么是「最陡」?直观地说: 沿任意方向 u(单位向量)走一小步,L 的变化率是 ∇L⋅u。两个向量点积在它们方向一致时最大,所以 u=∇L/∣∇L∣ 时上升最快,u=−∇L/∣∇L∣ 时下降最快。
还有一个免费的几何事实:梯度永远垂直于等高线。这一点在下面的动图里直接能看到。
知道了「最陡的下山方向」,算法就只剩一行:
w←w−η⋅∇L(w)
η 是学习率(learning rate)——一步迈多大。
但「迈多大」是个真问题。点一下画布换起点,拖一下学习率滑块感受:
损失函数
L(x, y) = 0.3·x² + 1.5·y²
椭圆形山谷,最小值在原点(紫色圆心)
✦ 点击画布换起点
✦ 拖动滑块改学习率
✦ 路径每次重新跑 30 步
紫色椭圆是等高线——同一圈上 L 相同。 负梯度永远垂直于等高线指向「内圈」——这就是下山的路。
三种典型情形:
- η 太小 → 每步几乎不动,一万步还没下到谷底。
- η 合适 → 沿着「最陡的弧线」平滑收敛。
- η 太大 → 一步直接跨过山谷,反弹到对面甚至越冲越远(发散)。
而且——注意上面这个椭圆形山谷:轨迹经常是 Z 字形的。原因是 y 方向比 x 方向陡得多,负梯度大部分指向「垂直于谷底的方向」,而不是「沿着谷底的方向」。这是普通梯度下降的老毛病,也是后来 momentum、Adam 等优化器要解决的问题。
神经网络是函数的层层嵌套。一个三层网络的输出大概长这样:
y^=f3(f2(f1(x;w1);w2);w3)
想算 L 对最深一层参数 w1 的偏导,得穿过 f2 和 f3 才能到 w1。链式法则就是这件事的数学:
∂w1∂L=∂f3∂L⋅∂f2∂f3⋅∂f1∂f2⋅∂w1∂f1
把它读作「敏感度的传递」会更直观:w1 抖一下 → f1 抖一下 → f2 跟着抖 → f3 跟着抖 → L 跟着抖。每一段的「抖动放大倍数」就是局部的偏导,把它们乘起来就是端到端的敏感度。
这就是反向传播(backpropagation) 的全部秘密——从输出端往输入端,把局部导数一段一段乘回去。PyTorch、JAX 这些框架的核心其实就是: 自动帮你把这条乘法链算出来。