讲解稿 · 第 03 章 第 03 节:多元微积分¶
口播时长:约 15–20 分钟|建议语速:中速偏慢,公式处停顿两拍|字数:约 4200 字
开场钩子(约 1.5 分钟)¶
好,先问你一个生活场景。
你正在学车,副驾坐着教练。你刚把车开出停车场,速度表从 0 跳到 30 km/h。教练看了你一眼,没夸你起步稳,而是问了一句——"现在踩油门的脚感、方向盘转角、刹车踏板位置,这三个数同时在变,你得一个一个盯着。哪个先动?哪个动得最猛?"
你说,"哦,我盯速度表就够了。"
教练摇头:"不对。在市区里,速度表只是十几个变量中的一个。方向盘回正了没?油门深度变没变?跟车间距缩没缩?你现在不是开直线,你是开很多根线同时在动的车。"
你刚才脑子里冒出来的那种"好多个东西一起在变、我想知道每个单独怎么变、还关心它们一起怎么变"的感觉,就是今天我们要聊的事。
我们前两节讲的是单变量微积分——一个输入、一个输出、问"这一刻变多快"。这在数学上干净,在真实世界里却几乎用不上。机器学习里没有哪个模型只有一个参数。一个神经网络动辄百万个权重,每一个权重都是一根旋钮,每一根旋钮都在动。我们要学的,是怎么同时盯住几百万根旋钮——这就是多元微积分要做的事。
好,进多元的世界。
复习昨日 & 今日路线(约 40 秒)¶
上一节我们讲了微分学——单变量函数的导数、极限、链式法则。一个输入,一个输出,切线斜率就完事了。
今天反过来:多输入。一个函数可以同时吃两个、三个、十万个变量。我们要回答五个层层递进的问题:
- 固定其他变量、只动一个时,函数怎么变?——这是偏导数。
- 这么多偏导数怎么打包?——打包成梯度。
- 如果函数同时吐出好几个值呢?——打包成雅可比矩阵。
- 想知道斜率怎么随位置变?——海森矩阵。
- 多层函数套起来怎么从一头传到另一头?——多元链式法则,这就是反向传播。
下节我们讲积分学,把"累积"这个另一半拉回来。
核心概念一:偏导数 —— 把多变量伪装回单变量(约 3 分钟)¶
偏导数 (partial derivative) 是今天最朴素的工具。
一句话定义:对谁求导,谁是变量;其余的全部按常数对待。
举个具体例子。取 \(f(x, y) = x^2 y + 3x - 2y\)。
求 \(\partial f / \partial x\) 时,把 \(y\) 当常量。\(x^2 y\) 对 \(x\) 求导得 \(2xy\)(\(y\) 是常数,拿出去),\(3x\) 求导得 \(3\),\(-2y\) 对 \(x\) 求导得 \(0\)(它是常数项)。所以:
求 \(\partial f / \partial y\) 时反过来——把 \(x\) 当常数。\(x^2 y\) 对 \(y\) 求导得 \(x^2\)(\(x^2\) 是常数),\(3x\) 求导得 \(0\),\(-2y\) 求导得 \(-2\)。所以:
数字锚点:把 \((x, y) = (1, 2)\) 代入。\(\partial f / \partial x = 2 \cdot 1 \cdot 2 + 3 = 7\),\(\partial f / \partial y = 1^2 - 2 = -1\)。这两个数告诉我们:在点 \((1, 2)\) 处,\(x\) 方向动一小步,\(f\) 大约增 7 倍;\(y\) 方向动一小步,\(f\) 大约减 1。
但偏导数有几何陷阱,你必须警惕。
反例(Ch02 经验沉淀的纯净反例):\(f(x, y) = x^2\)。它的偏导数 \(\partial f / \partial y = 0\)——意思是"沿 \(y\) 方向走,\(f\) 不变"。但 \(f\) 仍然依赖 \(y\),因为 \(y\) 在定义域里。事实上 \(f(x, y) = x^2\) 沿 \(y\) 方向走确实不变,但这种不变不是"函数跟 \(y\) 无关",而是"沿着等高线走"。这个反例提醒你——偏导数为零不等于函数不依赖那个变量,它只等于"沿那个轴走,函数值当前是平的"。
几何上理解偏导数:对 \(x\) 求偏导,等于用一张平行于 \(xz\) 平面的刀,在某个固定的 \(y\) 处切开三维曲面,看切出来那条曲线的斜率。\(y\) 取 \(1\)、取 \(2\)、取 \(3\),每次切开看斜率,斜率还不一样——这就是为什么偏导数一般是 \((x, y)\) 的函数,而不是一个常数。
一句话总结:偏导数 = 假装其他变量是常量,回到你最熟的单变量求导。
核心概念二:梯度 —— 把所有偏导打包成一个向量(约 3 分钟)¶
偏导数一个一个算,太散。我们打包。
梯度 (gradient) 就是把所有偏导塞进一个向量:
数字锚点:\(f(x, y) = x^2 + y^2\)。\(\partial f / \partial x = 2x\),\(\partial f / \partial y = 2y\),所以 \(\nabla f = (2x, 2y)\)。在点 \((1, 2)\) 处:\(\nabla f(1, 2) = (2, 4)\)。这两个数就是两半步叠加出来的总方向。
梯度有两个工程上极有用的性质,要分别理解。
第一个性质,方向。梯度指向函数值上升最快的方向。直觉是:登山者站在山坡上,往哪个方向迈步,海拔上升最快?答案就是梯度方向。换句话说——梯度是"最陡上坡"。这跟导数"局部斜率"是一回事,只是维度高了。
第二个性质,大小。\(\|\nabla f\|\) 是这个最陡方向的上升速率。\(\nabla f(1, 2) = (2, 4)\),\(\|\nabla f(1, 2)\| = \sqrt{4 + 16} = \sqrt{20} \approx 4.47\)。这个数告诉我们:在点 \((1, 2)\) 沿最陡上坡走单位长度,\(f\) 大约涨 4.47 个单位。梯度越大,地形越陡。
既然梯度是上坡,那反方向 \((-\nabla f)\) 就是下坡——通向下山、通向更低的函数值。这个观察虽然简单,却撑起了整个机器学习的训练算法——梯度下降:每一步往 \(-\nabla f\) 方向走一小段,反复迭代直到找到谷底。这件事我们会在 Ch03 §05 优化那一节正式展开。
⏸️ 暂停思考 · 第一次
想想 \(f(x, y) = x^2 + y^2\) 在原点 \((0, 0)\) 处的梯度是多少? ——\(\nabla f(0, 0) = (0, 0)\)。这就是临界点 (critical point):梯度为零意味着所有方向都没有"上坡",原地是平的。对 \(f = x^2 + y^2\) 来说,原点恰好是碗底,是全局最小。对其他函数,临界点也可能是山顶或鞍点——怎么区分?这就要等海森矩阵出场了。
一句话总结:梯度是偏导的打包向量,方向 = 最陡上坡,大小 = 上升速率。
核心概念三:方向导数与等高线 —— 沿任意方向的变化率(约 2 分钟)¶
偏导数只问"沿 \(x\) 轴怎么变、沿 \(y\) 轴怎么变"。但你可能想问"沿东北方向 45 度怎么变"。这就是方向导数 (directional derivative)。
定义:沿单位方向 \(\mathbf{u}\) 走,函数的变化率是 \(D_{\mathbf{u}} f = \nabla f \cdot \mathbf{u}\)——就是梯度与方向的点积。
数字锚点:\(f(x, y) = x^2 + y^2\),在 \((1, 2)\) 处沿 \(\mathbf{v} = (3, 4)\) 方向。先归一化:\(\mathbf{u} = (3/5, 4/5)\)。然后
即沿 \((3, 4)\) 方向每走一个单位,\(f\) 大约涨 \(4.4\) 个单位。
特别地,偏导数是方向导数的特例:\(\partial f / \partial x\) 就是 \(D_{\mathbf{e}_1} f\),其中 \(\mathbf{e}_1 = (1, 0)\)。
有个特别重要的几何对应——梯度总垂直于等高线。
等高线 (contour lines) 是函数值相同的点的连线。\(f(x, y) = x^2 + y^2\) 的等高线是以原点为中心的同心圆 \(x^2 + y^2 = c\)。梯度 \(\nabla f = (2x, 2y)\) 在点 \((x, y)\) 处,恰好沿径向指向圆外——也就是垂直于圆。
这里有三句话值得你背下来: - 等高线永不相交(同一个点不能同时有两个函数值)。 - 梯度总垂直于等高线,且从低值指向高值。 - 等高线密集的地方坡陡,稀疏的地方坡缓。
地图上的等高线你肯定见过——稀疏就是平原,密集就是悬崖。这跟梯度的大小直接对得上。
一句话总结:方向导数是"沿任意方向的变化率",等于梯度与单位方向的点积;梯度永远垂直于等高线。
核心概念四:雅可比矩阵 —— 输出也是向量怎么办(约 3 分钟)¶
到目前为止,函数都只输出一个数。但很多函数同时输出多个值。
比如 \(\mathbf{F}: \mathbb{R}^2 \to \mathbb{R}^2\),\(\mathbf{F}(x, y) = (x^2 + y,\ xy^2)\)——吃两个数、吐两个数。
雅可比矩阵 (Jacobian matrix) 把这种向量值函数的所有偏导打包成一个矩阵:
\(m\) 是输出维度,\(n\) 是输入维度。所以雅可比是 \(m \times n\) 的矩阵。每一行是某个输出分量的梯度。
数字锚点:\(\mathbf{F}(x, y) = (x^2 + y,\ xy^2)\),在 \((1, 2)\) 处:
第一行 \((2, 1)\) 是 \(f_1 = x^2 + y\) 的梯度,第二行 \((4, 4)\) 是 \(f_2 = xy^2\) 的梯度。在 \((1, 2)\) 处数值代入。
回引 Ch02 §04 · 第一处:还记得 Ch02 第一节我们说的"线性映射 = 矩阵"吗?雅可比是这个原理的完美兑现——在局部,\(\mathbf{F}\) 把一个微小的输入变化 \(\mathrm{d}\mathbf{x}\) 映射成输出变化 \(\mathrm{d}\mathbf{y} = J\,\mathrm{d}\mathbf{x}\)。也就是说,雅可比就是向量值函数的"局部线性映射"——Ch02 那个"线性映射两条公理 + 一个必然推论"在这里活生生地工作着。
雅可比还有一个特别有用的副产品:雅可比行列式 (determinant of Jacobian)。它衡量变换在局部把空间拉伸或压缩了多少。\(\det J = 2\),意思是面积缩放 \(2\) 倍——一小块面积经过 \(\mathbf{F}\) 之后变成原来 \(2\) 倍大。\(\det J = 0\) 意味着变换把空间压扁了(回忆 Ch02 行列式为零 = 奇异、不可逆)。
还有一个更炸裂的事实——复合变换的雅可比等于各层雅可比的矩阵乘法。这跟 Ch02 的矩阵乘法规则完全对接——后面多元链式法则那一节,我们再正式展开这个等式的力量。
一句话总结:雅可比是向量值函数的局部线性映射;行 = 输出分量,列 = 输入分量;复合 = 矩阵乘。
核心概念五:海森矩阵 —— 曲率到哪儿看(约 3 分钟)¶
梯度告诉你"这里陡不陡、往哪边走"。但陡度本身也会随位置变——你站在山坡上,斜率往前走一段会变陡、变缓、甚至反过来。海森 (Hessian) 就是这个"斜率的斜率"——二阶偏导。
对标量函数 \(f(x_1, \ldots, x_n)\),海森是一个 \(n \times n\) 矩阵:
数字锚点:\(f(x, y) = x^3 + 2xy^2 - y^3\)。梯度 \((3x^2 + 2y^2, 4xy - 3y^2)\);对梯度再求偏导:
代入 \((1, 2)\):$$ H = \begin{bmatrix} 6 & 8 \ 8 & -8 \end{bmatrix} $$。对角元是"沿某方向移动时,该方向斜率的变化率";非对角元是"沿一个方向移动时,另一个方向斜率的变化率"。
克莱罗定理 (Clairaut's theorem) 保证:只要二阶偏导连续,混合偏导就相等,\(\partial^2 f / \partial x \partial y = \partial^2 f / \partial y \partial x\)。所以海森是对称矩阵——回忆 Ch02 §02,对称矩阵的礼物是"实特征值 + 正交特征向量"。这是个免费赠送:海森自动有正交的特征方向,可以拿来当坐标系。
海森的最大用处是判断临界点的类型——梯度为零的地方到底长什么样:
- \(H\) 正定(所有特征值为正)→ 局部极小。曲面在所有方向都向上弯,像一只碗。\(f = x^2 + y^2\) 在原点就是这样。
- \(H\) 负定(所有特征值为负)→ 局部极大。曲面向下弯,像倒扣的碗。\(f = -x^2 - y^2\) 在原点是这样。
- \(H\) 有正有负 → 鞍点 (saddle point)。某些方向上升、某些方向下降,像山间垭口。\(f = x^2 - y^2\) 在原点就是这样。
数字锚点:\(f = x^2 - y^2\),\(\nabla f = (2x, -2y)\),在原点 \(\nabla f = (0, 0)\)——是临界点。海森 $$ H = \begin{bmatrix} 2 & 0 \ 0 & -2 \end{bmatrix} $$,特征值 \(2\) 和 \(-2\),一正一负,所以是鞍点。
⏸️ 暂停思考 · 第二次
想想 \(f(x, y) = x^2 + y^3\) 在 \((0, 0)\) 处是什么点? ——\(\nabla f = (2x, 3y^2)\),\(\nabla f(0, 0) = (0, 0)\) 是临界点。$$ H = \begin{bmatrix} 2 & 0 \ 0 & 6y \end{bmatrix} $$,代入原点 $$ H = \begin{bmatrix} 2 & 0 \ 0 & 0 \end{bmatrix} $$。特征值 \(2, 0\)——不是正定、不是负定、也不是有正有负。海森判定失效!要看更高阶项才能确定——这就是为什么"用二阶判定就够了"是有适用边界的。
一句话总结:海森是斜率的斜率,对称;通过特征值判断临界点是碗底、碗顶还是马鞍。
核心概念六:多元链式法则 —— 反向传播的地基(约 3 分钟)¶
回引 Ch02 §04 · 第二处:Ch02 第一节我们学过矩阵乘法——"左行乘右列"。今天我们要看到,那个矩阵乘法正好是复合函数雅可比的运算。这是 Ch02 矩阵乘法在 Ch03 多元微积分里最华丽的一次应用。
先把单变量链式法则复习一下(Ch03 §01 学过的):\(f(g(x))\) 的导数是 \(f'(g(x)) \cdot g'(x)\)——外层的导数乘以内层的导数。
多元版本加了一项"路径"。如果 \(z = f(x, y)\),而 \(x = g(t), y = h(t)\),那么 \(z\) 是 \(t\) 的复合函数,对 \(t\) 求导:
从 \(t\) 到 \(z\) 一共有两条路径:\(t \to x \to z\) 和 \(t \to y \to z\)。每条路径贡献一项——沿这条路径的偏导,乘以中间变量对 \(t\) 的导数。所有项加起来,就是 \(\mathrm{d}z/\mathrm{d}t\)。
数字锚点:\(z = x^2 y + 3x - y^2\),\(x = \cos(t), y = \sin(t)\)。代入:\(\partial z / \partial x = 2xy + 3\),\(\partial z / \partial y = x^2 - 2y\)。然后
代入 \(t = \pi/2\)(即 \(x = 0, y = 1\)):\((2 \cdot 0 \cdot 1 + 3)(-1) + (0^2 - 2 \cdot 1)(0) = -3 + 0 = -3\)。即在 \(t = \pi/2\) 处,\(z\) 关于 \(t\) 的瞬时变化率是 \(-3\)。
更一般的写法——用矩阵描述——这就是全导数 (total derivative):
其中 \(J_f\) 是 \(f\) 关于中间变量的雅可比,\(J_{\mathbf{g}}\) 是中间变量关于最终输入的雅可比。雅可比 @ 雅可比 = 复合函数的雅可比。这是 Ch02 §04 矩阵乘法的 Ch03 应用——用一次矩阵乘法,把整条链上的所有局部信息合起来。
这个式子是反向传播 (backpropagation) 的数学地基。深度神经网络就是一条长长的复合函数链;要算损失对每个权重的导数,就从输出层往输入层反着套用这条规则,每一层把当地的雅可比乘进去。
自动微分 —— 为什么 PyTorch 不靠符号也不靠数值(约 1.5 分钟)¶
你可能会问:手算链式法则很烦,能不能让计算机做?三种主流做法:
- 数值微分:\(f'(x) \approx [f(x+h) - f(x-h)] / (2h)\)。简单,但有噪声、不精确(\(h\) 取小了浮点误差爆,取大了截断误差爆)。
- 符号微分:用代数规则推出精确公式。精确,但表达式会爆炸式增长——一个稍微复杂点的函数,展开后能写出几页纸。
- 自动微分 (Automatic Differentiation, autodiff):追踪运算链,每一步把当地的导数乘进去。高效、精确——这正是 JAX、PyTorch、TensorFlow 用的方法。它给出精确数值,但不产生臃肿的符号表达式。
代码层面你只要一行:jax.grad(f) 算梯度、jax.jacobian(F) 算雅可比、jax.hessian(f) 算海森。原文 §03 给了一个最简单的反向传播实现——一个 Var 类,记录值与"如何把梯度回传"。那个 12 行代码就是 PyTorch autograd 的祖爷爷。
一句话总结:自动微分是链式法则的程序化实现,PyTorch 的 autograd 引擎就是这条规则的高效版本。
一个走完全程的例子(约 2.5 分钟)¶
好,咱们把整节串起来。
任务:训练一个最简单的神经网络——单输入 \(x\)、单权重 \(w\)、单输出 \(f(x, w) = (wx - 1)^2\)。损失就是 \(f\) 本身。给定一个数据点 \((x, y) = (2, 1)\),目标是最小化损失(让 \(wx\) 接近 \(1\))。
第一步:算梯度(用偏导)。\(f = (wx - 1)^2\),对 \(w\) 求偏导(把 \(x\) 当常数):\(\partial f / \partial w = 2(wx - 1) \cdot x\)。代入 \(w = 0, x = 2\):\(2 \cdot (0 \cdot 2 - 1) \cdot 2 = -4\)。即当前权重下,损失对权重的偏导是 \(-4\)。
第二步:解释方向。梯度(这里只有一个分量)\(\partial f / \partial w = -4\),方向是"负号"——意思是损失随 \(w\) 增加而减小。沿 \(w\) 增大方向走,下坡。 这是梯度下降的核心直觉。
第三步:算海森,看曲率。\(\partial^2 f / \partial w^2 = 2x^2 = 8\)。一阶导数本身随 \(w\) 怎么变?每增加 \(\Delta w\),一阶导增加 \(8 \cdot \Delta w\)。海森是正数,所以这个临界点是局部极小——碗底。
第四步:用链式法则手算反向传播。换个写法:\(f\) 是三层复合——\(z_1 = wx, z_2 = z_1 - 1, f = z_2^2\)。从输出往输入反着算:
- \(\partial f / \partial z_2 = 2 z_2 = -2\)。
- \(\partial z_2 / \partial z_1 = 1\),所以 \(\partial f / \partial z_1 = (-2) \cdot 1 = -2\)。
- \(\partial z_1 / \partial w = x = 2\),所以 \(\partial f / \partial w = (-2) \cdot 2 = -4\)。
跟第一步手算偏导完全一致 ✓。
第五步:梯度下降更新。学习率 \(\eta = 0.1\),新权重 \(w_{\text{new}} = w - \eta \cdot (\partial f / \partial w) = 0 - 0.1 \cdot (-4) = 0.4\)。新损失 \(f(2, 0.4) = (0.8 - 1)^2 = 0.04\),比 \(w = 0\) 时的 \(1\) 小了 \(25\) 倍——下坡成功了。
整条链上的五个工具——偏导、梯度、海森、链式法则、自动微分——全部出场。你刚才做的,就是每一个 PyTorch 训练循环内部正在做的事。
易错点回头看(约 1 分钟)¶
三条最常翻车的地方。
-
很多人以为:偏导数为零就意味着函数不依赖那个变量。其实是:偏导数为零只意味着"沿那个轴走,当前点是平的"。反例:\(f(x, y) = x^2\),\(\partial f / \partial y = 0\),但 \(f\) 的定义域明明包含 \(y\);沿 \(y\) 方向走 \(f\) 保持不变(这就是"沿等高线走")。Ch02 沉淀的统一反例——\(f = x^2\)——在这里继续发挥作用。
-
很多人以为:梯度就是导数的复数。其实是:梯度是所有偏导打包成的向量,每个分量对应一个变量。反例:\(f(x, y) = x^2 + y^2\),梯度是 \((2x, 2y)\)——两个分量,方向指向最陡上坡。偏导数 \(\partial f / \partial x = 2x\) 只是一个分量,丢掉了一半信息。
-
很多人以为:临界点一定是极小或极大。其实是:还有鞍点,而且用海森判定还会失效。反例:\(f = x^2 - y^2\),原点 \((0,0)\) 满足 \(\nabla f = 0\),海森特征值 \((2, -2)\),判定为鞍点——既不是极大也不是极小。更糟的是 \(f = x^2 + y^3\),海森判定失效,要看更高阶项才知道是极小。所以"梯度为零 + 海森正定 → 极小"这个判定公式是有适用边界的。
与下节的钩子(约 30 秒)¶
今天我们把"变化率"这件工具从单变量推广到了多变量。下一节——03.04 函数逼近——我们把工具倒过来用:已知一个函数,怎么用简单的东西(多项式、三角函数)去逼近它?这就是泰勒展开和傅里叶分析。你会看到,泰勒展开其实就是把"高阶导数"——海森的延伸——当成积木,一块一块把函数在某个点附近搭起来。
带着今天的梯度、雅可比、海森,咱们下节见。