面向机器学习的微积分 本节摘要:导数告诉你「哪边是下坡」——这就是神经网络学习所需的全部。你手上有百万个权重,每个都是一个旋钮;要训练模型,就得知道每个旋钮该往哪边拧一点点,好让误差下降。微积分给出的就是这个方向。本节从「导数是切线斜率」开始,逐步走到偏导数(每次只动一个变量)、梯度(把所有偏导数装进一个向量,指向最陡上升方向)、梯度下降(沿梯度的反方向走一步)。我们会区分数值导数(用小步长近似,任何函数通用)与解析导数(套规则手算,精确快速),推导机器学习里反复出现的那些导数(x²、wx+b、eˣ、ln x、sigmoid)。接着引入链式法则——反向传播的全部本质——以及刻画曲率的海森矩阵和局部多项式近似的泰勒展开,看清梯度下降、牛顿法、Adam 各自对应泰勒展开的哪一阶。
本节摘要:导数告诉你「哪边是下坡」——这就是神经网络学习所需的全部。你手上有百万个权重,每个都是一个旋钮;要训练模型,就得知道每个旋钮该往哪边拧一点点,好让误差下降。微积分给出的就是这个方向。本节从「导数是切线斜率」开始,逐步走到偏导数(每次只动一个变量)、梯度(把所有偏导数装进一个向量,指向最陡上升方向)、梯度下降(沿梯度的反方向走一步)。我们会区分数值导数(用小步长近似,任何函数通用)与解析导数(套规则手算,精确快速),推导机器学习里反复出现的那些导数(x²、wx+b、eˣ、ln x、sigmoid)。接着引入链式法则——反向传播的全部本质——以及刻画曲率的海森矩阵和局部多项式近似的泰勒展开,看清梯度下降、牛顿法、Adam 各自对应泰勒展开的哪一阶。最后从零写一个线性回归的梯度下降训练循环,用 30 行代码完成「预测—算损失—算梯度—更新权重」这套深度学习通用骨架。
对应原课程:Phase 01 · Lesson 04 ·
calculus-for-ml(原英文phases/01-math-foundations/04-calculus-for-ml/docs/en.md)。前置:第 1~3 节。
阅读完本节,你应当能够:
你有一个含百万权重的神经网络,每个权重都是旋钮。你要算出每个旋钮该往哪个方向转,才能让模型「稍微更对一点」。微积分给的就是这个方向。
没有微积分,训练神经网络只能乱试一通撞大运;有了导数,你精确知道每个权重如何影响误差——每次都把每个旋钮往正确方向拧。
导数度量变化率。对 y = f(x),f'(x) 告诉你:把 x 推一点,y 变多少。几何上,导数是该点切线的斜率。
f(x) = x²:
| x | f(x) | f'(x)(斜率) |
|---|---|---|
| 0 | 0 | 0(平,谷底) |
| 1 | 1 | 2 |
| 2 | 4 | 4 |
| 3 | 9 | 6 |
形式定义:
f'(x) = lim f(x + h) − f(x) h→0 ───────────────── h
代码里跳过极限,直接用很小的 h——这就是数值导数。
真实函数输入很多。神经网络损失依赖成千上万个权重。偏导数把其他变量都当常数,只对其中一个求导。
f(x, y) = x² + 3xy + y² df/dx = 2x + 3y (把 y 当常数) df/dy = 3x + 2y (把 x 当常数)
每个偏导回答:若我只拧这一个权重,损失变多少?
对 f(x, y, z),梯度是 ∇f = [df/dx, df/dy, df/dz]。梯度指向最陡上升方向;要最小化函数,就朝相反方向走。
f(x,y) = x² + y² 的等高线是同心圆,极小在 (0,0)。
| 点 | ∇f | −∇f(下降方向) |
|---|---|---|
| (1,1) | 2,2 | −2,−2 |
| (0,0) | 0,0 | [0,0] |
这就是梯度下降的图像:算梯度、取反、走一步。
训练神经网络就是优化。你有损失 L(w1, w2, …, wn),想最小化它。
梯度下降更新规则: w_new = w_old − learning_rate · dL/dw 对每个权重: 1. 算损失对该权重的偏导 2. 减去它的小倍数 3. 重复
学习率控制步长:太大冲过头,太小爬不动。梯度下降沿斜率下坡,可能困在局部极小——但在高维(百万权重)空间里,这几乎不是实际问题。
f(x)=x² 则 f'(x)=2x。精确、快。f'(x) ≈ f(x+h) − f(x−h) ──────────────── 2h h = 0.0001 实践中表现良好
数值法慢但对任何函数可用;解析法快但要手推。神经网络框架用第三条路:自动微分——机械地算出精确导数(见第 5 节)。
函数 导数 用途 ──── ──── ──── x² 2x 损失函数(MSE) wx + b 对 w 为 x 线性层(对权重的梯度) 对 b 为 1 线性层(对偏置的梯度) 对 x 为 w 线性层(对输入的梯度) eˣ eˣ softmax、注意力 ln x 1/x 交叉熵损失 1/(1+e⁻ˣ) f(x)(1−f(x)) sigmoid 激活
函数复合时,链式法则告诉你如何求导:
若 y = f(g(x)),则 dy/dx = f'(g(x)) · g'(x) 例:y = (3x + 1)² 外层:f(u) = u², f'(u) = 2u 内层:g(x) = 3x+1, g'(x) = 3 dy/dx = 2(3x+1)·3 = 6(3x+1)
神经网络是函数链:输入 → 线性 → 激活 → 线性 → 激活 → 损失。反向传播就是链式法则从输出反复作用到输入——这就是整个算法。
梯度告诉你斜率,海森告诉你曲率。海森是二阶偏导组成的矩阵。对 f(x, y):
H = | d²f/dx² d²f/dxdy | | d²f/dydx d²f/dy² |
在临界点(梯度为 0 处),海森告诉你它是什么:
| 海森性质 | 含义 | 曲面形状 |
|---|---|---|
| 正定(所有特征值 > 0) | 局部极小 | 朝上的碗 |
| 负定(所有特征值 < 0) | 局部极大 | 朝下的碗 |
| 不定(特征值有正有负) | 鞍点 | 马鞍形 |
例:f(x,y) = x² − y²(鞍面),H = diag(2, −2),特征值 2、−2 → 鞍点。
牛顿法用海森走出比梯度下降更好的步:
牛顿法:w_new = w_old − H⁻¹ · ∇f 梯度下降:w_new = w_old − lr · ∇f
牛顿法更快,因为海森「重缩放」梯度——陡的方向步小、平的方向步大。代价:N 个参数时海森是 N×N,百万参数模型要 1 万亿项矩阵,所以实际用近似(Adam、L-BFGS、自然梯度)。
| 方法 | 用什么 | 成本 | 收敛 |
|---|---|---|---|
| 梯度下降 | 仅一阶导 | 每步 O(N) | 慢(线性) |
| 牛顿法 | 完整海森 | 每步 O(N³) | 快(二次) |
| L-BFGS | 梯度历史近似海森 | 每步 O(N) | 中(超线性) |
| Adam | 每参数自适应率(对角海森近似) | 每步 O(N) | 中 |
| 自然梯度 | Fisher 信息矩阵(统计海森) | 每步 O(N²) | 快 |
💡 Adam 是深度学习的默认优化器——它通过跟踪每参数梯度的滑动均值与方差,廉价地近似二阶信息。
任何光滑函数都能在局部用多项式近似:
f(x+h) = f(x) + f'(x)·h + (1/2)·f''(x)·h² + (1/6)·f'''(x)·h³ + …
对 ML 的意义:
f(x+h) ≈ f(x) + f'(x)·h,最小化得 h = −lr·f'(x)。(1/2)f''(x)h²,最小化得 h = −f'(x)/f''(x)。| 近似阶 | 捕获什么 | 对应优化方法 |
|---|---|---|
| 0 阶(常数) | 仅数值 | 随机搜索 |
| 1 阶(线性) | 斜率 | 梯度下降 |
| 2 阶(二次) | 曲率 | 牛顿法 |
核心洞见:所有基于梯度的优化,本质上都是局部近似损失、再走到该近似的极小。
神经网络里变量会分叉与合并。前向传播一个简单例子:
反向传播从右到左算梯度:
每条箭头乘以局部导数。任一参数的梯度 = 从损失到该参数路径上所有局部导数之积。路径分叉合并时,把各贡献求和(多元链式法则)。反向传播的全部就是这件事:系统化地在计算图上从输出到输入应用链式法则。
当函数把向量映射成向量(如神经网络层),它的导数是矩阵。雅可比包含「每个输出对每个输入」的全部偏导。对 f: ℝⁿ → ℝᵐ,雅可比 J 是 m×n 矩阵,J[i][j] = dfᵢ/dxⱼ。你不会为神经网络手算雅可比(PyTorch 自动处理),但知道它存在,能帮你理解反向传播中的形状——若一层把 ℝⁿ 映到 ℝᵐ,其雅可比是 m×n,梯度经其转置反向流动。
完整源码见 phases/01-math-foundations/04-calculus-for-ml/code/。
def numerical_derivative(f, x, h=1e-7): return (f(x + h) - f(x - h)) / (2 * h)
def numerical_gradient(f, point, h=1e-7): grad = [] for i in range(len(point)): p_plus = list(point); p_plus[i] += h p_minus = list(point); p_minus[i] -= h grad.append((f(p_plus) - f(p_minus)) / (2 * h)) return grad
f(x) = x²x = 5.0; lr = 0.1 for step in range(20): grad = 2 * x x = x - lr * grad # 每步都更靠近 x=0
def f_2d(p): x, y = p return x**2 + y**2 point = [4.0, 3.0]; lr = 0.1 for step in range(30): grad = numerical_gradient(f_2d, point) point = [p - lr * g for p, g in zip(point, grad)]
def hessian_2d(f, x, y, h=1e-5): fxx = ( f(x+h,y) - 2*f(x,y) + f(x-h,y) ) / h**2 fyy = ( f(x,y+h) - 2*f(x,y) + f(x,y-h) ) / h**2 fxy = ( f(x+h,y+h) - f(x+h,y-h) - f(x-h,y+h) + f(x-h,y-h) ) / (4*h**2) return [[fxx, fxy], [fxy, fyy]] # 鞍面 x²−y² → H = [[2,0],[0,-2]](混合符号,鞍点) # 碗 x²+y² → H = [[2,0],[0,2]](全正,极小)
w = random.gauss(0, 1); b = random.gauss(0, 1); lr = 0.01 xs = [1.0, 2.0, 3.0, 4.0, 5.0] ys = [3.0, 5.0, 7.0, 9.0, 11.0] # 真值 y = 2x + 1 for epoch in range(200): dw = db = total_loss = 0 for x, y in zip(xs, ys): pred = w * x + b error = pred - y total_loss += error ** 2 dw += 2 * error * x # dL/dw(链式法则) db += 2 * error # dL/db dw /= len(xs); db /= len(xs); total_loss /= len(xs) w -= lr * dw; b -= lr * db
每个梯度训练循环都遵循这套模式:预测—算损失—算梯度—更新权重。
设计要点:这里
dw = 2·error·x是手推的解析梯度。第 5 节我们会用自动微分让框架替我们算,但底层就是这个链式法则。
NumPy 让同样的事更快、更简洁:
import numpy as np x = np.array([1,2,3,4,5], dtype=float); y = np.array([3,5,7,9,11], dtype=float) w, b = np.random.randn(), np.random.randn(); lr = 0.01 for epoch in range(200): pred = w * x + b error = pred - y dw = np.mean(2 * error * x) db = np.mean(2 * error) w -= lr * dw; b -= lr * db print(f"y = {w:.2f}x + {b:.2f}") # ≈ y = 2x + 1
PyTorch 把梯度计算自动化,但更新循环完全一样——只是 dw、db 不再手推。
本节是整个深度学习的算法地基。产物包括:
numerical_derivative、numerical_gradient、gradient_descent、hessian_2d,可作为后续章节的梯度校验(gradient check)工具——用数值梯度对照手写/自动微分梯度,排查 bug。源码见 phases/01-math-foundations/04-calculus-for-ml/code/。
numerical_second_derivative(f, x)(调用 numerical_derivative 两次),验证 x³ 在 x=2 处二阶导为 12。f(x,y) = (x−3)² + (y+1)² 的极小,从 (0,0) 出发,验证收敛到 (3, −1)。f(x) = x⁴ − 3x² 上比较有/无动量的收敛速度。w_new = w_old − lr·∇L,沿梯度的反方向走一步,这是神经网络训练的核心。下一节,我们把链式法则机械化——自动微分让框架精确、自动地算出任意复杂函数的梯度,这是 PyTorch/JAX 的核心引擎。