1. 一元泰勒不够用的时候,二元展开是怎么被逼出来的
1.1 一个从曲面拟合说起的小场景
前两年帮朋友处理一批实验数据,测的是某块板材在受热之后表面上不同位置的温度。变量有两个:横向坐标 x 和纵向坐标 y,输出是温度 T。实测点大概有几十个,分布稀疏又不均匀,中间还缺了几块。当时的想法很朴素——能不能用一个局部公式把任意一点附近的温度近似出来,从而把缺失区域补上、把噪声压一压。
第一反应当然是泰勒展开。问题在于,我脑子里那套熟练的公式只有一元版本:f(x0+h) ≈ f(x0) + f'(x0)h + f''(x0)h²/2。它擅长处理"一个自变量、一个小增量"的局部近似,而且好用到几乎不用动脑。可眼下的温度是 T(x, y),两个自变量同时变化,一元公式连门都进不去。
这就是二元函数的泰勒展开出场的地方。它做的事情说穿了很朴素:用某个已知点附近的函数值、一阶偏导数、二阶偏导数,拼出一个多项式,去逼近该点邻域内的真实函数值。看起来只是把一元公式"多抄一个变量",但真的动手之后你会发现,多出来的东西远比想象中多——交叉项、海森矩阵、二次型符号、展开点平移,每一项都能让人在深夜对着草稿纸发呆。
1.2 一元搬到二元,多出来的麻烦在哪
一元泰勒展开之所以简单,是因为自变量的变化方向只有一个。h 可以是正的也可以是负的,但方向就那一条线,函数沿着这条线变化,用导数描述它的快慢就够了。
二元就不一样了。在点 (x0, y0) 附近,你可以往 x 方向走,可以往 y 方向走,也可以斜着走,方向有无穷多个。而且不同方向上的变化速率往往差得很远。多元微积分用方向导数把这件事统一起来:任意方向上的变化率,等于梯度向量在该方向上的投影。这是二元泰勒展开一阶项能够写得那么紧凑的根本原因。
第二个麻烦是交叉项。一元的二阶项只有 f''(x0)h² 这一项,二元的二阶项却有 fxx h²、2fxy hk、fyy k² 三项。中间那一项带着 2 倍系数,是新手最容易写漏的地方。它不是凑数的,而是来自 (h∂/∂x + k∂/∂y)² 的二项式展开,后面第三章会把这个来源彻底讲清楚。
第三个麻烦是几何直觉。一元展开的几何图像是切线,二元展开的一阶图像是切平面,二阶则涉及曲面的弯曲方式——是朝上鼓、朝下凹,还是像马鞍一样一边翘一边垂。这套几何直觉恰恰是判断极值的关键,也是很多教材跳过、但实际用起来最值钱的部分。
1.3 这篇内容适合谁看,能拿到什么
我把话说明白:这篇不是替教材讲定义,而是把二元泰勒展开当成一个干活的工具来拆。适合三类人。
第一类是在准备考试、对公式能背下来但总觉得没吃透的人。我会把每一项系数的来历拆开,尤其是那个 1/2 和那个 2 到底怎么来的。第二类是做数值计算、优化、信号处理、图像处理的工程人。你们真正需要的不是公式本身,而是"什么时候展开到一阶够用、什么时候必须上二阶""误差量级怎么估""海森矩阵什么时候会骗人"。第三类是做数据拟合和误差分析的人,你们会用到一阶展开做灵敏度传播,这部分我在第六章给了完整的用法。
我自己的经验是,二元泰勒展开最容易翻车的地方从来不是推导,而是在非原点展开时忘了平移、把 h 和 k 当成变量本身。这两种错误在第5章的踩坑清单里会重点点名。
2. 先看骨架:二元函数泰勒展开到底长什么样
2.1 一阶项:切平面与梯度
把结论先摆出来。设 f(x, y) 在点 P0 = (x0, y0) 的某个邻域内有一阶连续偏导数,记增量 h = x - x0,k = y - y0,那么一阶展开是:
f(x0 + h, y0 + k) = f(x0, y0) + fx(x0, y0)·h + fy(x0, y0)·k + o(√(h² + k²))
写成向量形式就是 f(P0 + d) ≈ f(P0) + ∇f(P0)ᵀd,其中 d = (h, k)。
这个式子的几何含义非常直观:右边是关于 h、k 的一次多项式,它在三维空间里表示一张平面,而且这张平面在 P0 处与曲面相切,所以叫切平面。梯度 ∇f = (fx, fy) 决定这张平面往哪个方向倾斜得最厉害。
这里有个很实用的推论:方向导数 D_u f = ∇f · u(u 是单位方向向量)。也就是说,只要知道两个偏导数,任意方向的变化率都能算出来,不需要重新求导。这个结论在做灵敏度分析时极其省事,因为你可以直接比较不同方向上"函数对扰动的敏感程度"。
一阶展开的误差量级是 √(h²+k²) 的高阶小量,说白了就是"离得越近越准"。实际使用时,如果 h 和 k 都在 0.01 量级、函数又比较光滑,一阶展开的误差通常在 1e-4 上下,很多粗算场合够用了。
2.2 二阶项:那个容易被写漏的交叉项
一阶不够用的时候就要加二阶项。设 f 在 P0 邻域内有二阶连续偏导数,二阶展开是:
f(x0 + h, y0 + k) = f0 + fx·h + fy·k + (1/2)[fxx·h² + 2fxy·h·k + fyy·k²] + R2
四个系数里,fxx、fyy、fxy 都在 P0 点取值。注意两个容易出错的地方:
第一,交叉项前面的 2 不能省。它的来源是 (h∂x + k∂y)² = h²∂x² + 2hk∂x∂y + k²∂y²,就是初中二项式定理那一套。有人觉得"反正小量,2 无所谓",这是错的——交叉项在很多场景下恰恰是最大的一项,尤其在 fxx 和 fyy 都很小、但混合偏导不小的时候(比如 f = xy 这种双线性型)。
第二,每个二阶项前面都有 1/2。这来自一维泰勒公式里的 1/2!,扩展到二元就是每个二阶项的系数统一是 1/2。写成矩阵形式之后,这个 1/2 会跑到矩阵外面,看起来更整齐。
顺带说一句克莱罗定理:只要二阶混合偏导连续,就有 fxy = fyx。这个条件在绝大多数工程函数里都成立,所以海森矩阵是对称矩阵,这也让后面的二次型分析变得简单。
2.3 矩阵写法与余项,以及各阶项的分工
把 h、k 塞进向量 d = (h, k)ᵀ,二阶展开的矩阵形式是:
f(P0 + d) = f(P0) + ∇f(P0)ᵀd + (1/2)dH(P0)d + R2
其中 H 是海森矩阵:
H = [ fxx fxy ] [ fxy fyy ]
这个写法不只是好看。它把"二阶项"变成了一个二次型 dᵀHd,而二次型的符号完全由矩阵 H 的特征值决定。这一步转化,直接打通了"泰勒展开"和"极值判定"之间的关系,也是第四章的核心。
余项 R2 有拉格朗日形式:R2 = (1/6)(h∂x + k∂y)³ f(x0 + θh, y0 + θk),其中 0 < θ < 1。它表示"用二阶多项式代替真实函数"所欠下的账,量级是 O((√(h²+k²))³)。这个三次方关系后面会变成一个非常实用的自检工具。
| 展开阶数 | 代表项 | 误差量级 | 典型用途 |
|---|---|---|---|
| 零阶 | f(x0, y0) | O(1) | 粗略估值 |
| 一阶 | fx h + fy k | O(‖d‖²) | 切平面近似、误差传播、灵敏度 |
| 二阶 | (1/2)dᵀHd | O(‖d‖³) | 极值判定、牛顿法、亚像素定位 |
| 三阶及以上 | 高阶偏导组合 | 更小 | 二阶失效的退化情形 |
这张表建议直接记在脑子里。很多人做数值实验时误差压不下去,第一反应是换算法,其实往往是展开阶数和步长没配对——步长取 0.1 却只展开到一阶,误差当然下不来。
3. 把二元问题压成一元:最省脑子的推导路径
3.1 构造函数 g(t) = f(x0 + th, y0 + tk)
硬啃二元泰勒公式的二项式展开会很痛苦。我推荐一条几乎不费脑子的路子:把二元压成一元。
在 P0 附近固定一个方向 d = (h, k),然后只沿着这条直线走。定义一个单变量函数:
g(t) = f(x0 + th, y0 + tk),t ∈ [0, 1]
这样 g(0) = f(P0),g(1) = f(P0 + d)。二元问题瞬间变成一个一元问题,而一元泰勒公式你早就滚瓜烂熟了:
g(1) = g(0) + g'(0) + g''(0)/2! + g'''(θ)/3!
接下来只要把 g 的各阶导数用 f 的偏导数表示出来就行。这靠链式法则:
g'(t) = fx(x0+th, y0+tk)·h + fy(x0+th, y0+tk)·k g''(t) = fxx·h² + 2fxy·h·k + fyy·k² g'''(t) = fxxx·h³ + 3fxxy·h²k + 3fxyy·hk² + fyyy·k³
把 t = 0 代进去,得到的就是标准的二元泰勒展开。整个过程没有任何需要"灵光一闪"的地方,就是老实求导。
这条路径的价值不只是推导方便。它还顺手解释了一个问题:二元泰勒展开本质上就是"沿着某条直线看过去,函数的表现和一元函数完全一样"。你之所以能对无穷多个方向统一处理,是因为 h 和 k 是先固定的,方向被包进了 (h, k) 的比例里。
3.2 二项式系数为什么跑进了公式里
仔细看 g'''(t) 的系数:1、3、3、1,标准的二项式系数。g''(t) 的系数是 1、2、1。这不是巧合。
如果把求导操作写成一个"算子",定义 D = h·∂/∂x + k·∂/∂y,那么 g 的各阶导数恰好是 Dⁿf 代入 t = 0。而 Dⁿ 的展开就是二项式定理:
D² = h²∂x² + 2hk∂x∂y + k²∂y² D³ = h³∂x³ + 3h²k∂x²∂y + 3hk²∂x∂y² + k³∂y³
所以二元泰勒公式也可以写成一个非常紧凑的"算子形式":
f(P0 + d) = Σ (1/n!)·(h∂x + k∂y)ⁿ f(P0) + Rn
这个写法在理论推导里很常见,但真正干活的时候我建议还是用展开后的显式形式,因为算子形式不方便代入具体数值。
顺便说一句:一元的 1/n! 在二元里完整保留下来了。展开到二阶是 1/2!,展开到三阶是 1/6。有人会把二阶项的 1/2 和三阶项的 1/6 记混,最简单的方法就是回到 g(t) 的一元公式上去核对。
3.3 手算两个例子把公式钉死
例一:f(x, y) = e·sin y,在原点展开到二阶。
先求各阶偏导在 (0,0) 的值:
- f(0,0) = e⁰·sin 0 = 0
- fx = eˣ sin y → 0
- fy = eˣ cos y → 1
- fxx = eˣ sin y → 0
- fxy = eˣ cos y → 1
- fyy = -eˣ sin y → 0
代入二阶公式:
f ≈ 0 + 0·x + 1·y + (1/2)[0·x² + 2·1·xy + 0·y²] = y + xy
用一个独立的办法验证:eˣ = 1 + x + x²/2 + …,sin y = y - y³/6 + …,两者相乘,取到总次数为 2 的项,只有 y 和 xy。结果完全一致。
再做一次数值核对。取 x = y = 0.1:
真值 e^0.1·sin 0.1 = 1.1051709 × 0.0998334 ≈ 0.110334
近似值 y + xy = 0.1 + 0.01 = 0.11
误差约 3.3×10⁻⁴。而理论上的三阶项是 (x²/2)y - y³/6 = 0.0005 - 0.0001667 ≈ 0.000333,正好把误差解释掉。这个吻合程度说明展开是对的。
例二:f(x, y) = x² + xy + y²,在点 (1, 2) 展开到二阶。
注意这里是非原点展开,必须用 h = x - 1、k = y - 2,而不是直接用 x、y。这是新手最高频的错误。
- f(1,2) = 1 + 2 + 4 = 7
- fx = 2x + y → 4
- fy = x + 2y → 5
- fxx = 2,fxy = 1,fyy = 2(都是常数)
代入公式:
f ≈ 7 + 4h + 5k + (1/2)[2h² + 2·1·hk + 2k²] = 7 + 4h + 5k + h² + hk + k²
现在直接展开原函数验证:
(1+h)² + (1+h)(2+k) + (2+k)² = 1 + 2h + h² + 2 + k + 2h + hk + 4 + 4k + k² = 7 + 4h + 5k + h² + hk + k²
两项一模一样。这个例子的意义在于:对于二次多项式,二阶泰勒展开是精确的,余项为零。这个性质后来会变成我最常用的自检手段——写完展开式,先拿一个二次多项式试一遍,如果对不上,百分之百是系数写错了。
4. 用它判断极值:海森矩阵的完整判定流程
4.1 为什么二次型的符号决定一切
极值判定的逻辑,说白了就是一句话:在驻点附近,一阶项消失,函数的增减完全由二阶项决定。
设 P0 是驻点,即 fx = fy = 0。此时泰勒展开变成:
f(P0 + d) - f(P0) = (1/2)dHd + R2
当 d 足够小的时候,三次及以上的余项可以忽略,差值的符号就由二次型 dᵀHd 决定。而二次型的符号问题,是线性代数里的老问题:它完全由 H 的特征值决定。
- 两个特征值都大于 0:H 正定,dᵀHd > 0,函数在 P0 处取极小值
- 两个特征值都小于 0:H 负定,dᵀHd < 0,取极大值
- 一正一负:H 不定,dᵀHd 可正可负,是鞍点
- 至少一个特征值为 0:退化,二阶展开失效
手算特征值麻烦,所以实际用的时候走行列式路线更方便。对二阶矩阵 H = [[a, b], [b, c]],有:
- det H = ac - b² > 0 且 a > 0 → 极小
- det H = ac - b² > 0 且 a < 0 → 极大
- det H = ac - b² < 0 → 鞍点
- det H = ac - b² = 0 → 失效,需更高阶
这里的 a 就是 fxx。注意 det H > 0 时 a 和 c 同号(因为 ac = b² + det H > b² ≥ 0),所以只看 a 的符号就够了。
提示:det H > 0 且 a = 0 是不可能出现的,因为此时 ac - b² = -b² ≤ 0,与 det H > 0 矛盾。有人担心"a 正好为 0 怎么办",不用担心,这种情况已经被 det H 的符号排除了。
4.2 完整案例走一遍:f(x, y) = x³ - 3xy + y³
这是极值判定的经典练习题,因为它同时包含鞍点和极值点,覆盖面很全。完整流程如下。
第一步,求驻点。令两个偏导为零:
fx = 3x² - 3y = 0 → y = x² fy = -3x + 3y² = 0 → x = y²
把第一式代入第二式:x = (x²)² = x⁴,即 x(x³ - 1) = 0,得 x = 0 或 x = 1。对应 y = 0 或 y = 1。所以驻点是 (0, 0) 和 (1, 1)。
第二步,求二阶偏导。fxx = 6x,fxy = -3,fyy = 6y。
第三步,逐点判定。
在 (0, 0):a = 0,b = -3,c = 0。det H = 0×0 - 9 = -9 < 0,鞍点。
在 (1, 1):a = 6,b = -3,c = 6。det H = 36 - 9 = 27 > 0,且 a = 6 > 0,极小值点。极小值为 f(1,1) = 1 - 3 + 1 = -1。
整个过程没有用到任何超纲技巧,就是求偏导、解方程组、算行列式。真正花时间的是解方程那一步,这也是最容易算错的地方。我的习惯是解完之后把驻点代回两个偏导方程各验一遍,五秒钟的事,能省掉后面十分钟的白算。
4.3 判定失效的三种情况
二阶判定不是万能的,有三种情况需要特别小心。
第一种:det H = 0。典型例子是 f = x³ + y³,在原点处 fx = fy = 0,H 是全零矩阵,det H = 0。实际上原点是鞍点,但二阶信息完全看不出来,必须展开到三阶。三阶项是 x³ + y³,沿 x 轴正向为正,沿 x 轴负向为负,符号不定,所以是鞍点。
第二种:det H = 0 但不是鞍点。比如 f = x²y²,在原点 H 也是全零,可实际上 f ≥ 0 处处成立,原点是无条件极小值。这种情况的麻烦在于,你需要找到某个偶次阶的项来确认符号。x²y² 是四次项,展开到四阶才能看出来。
第三种:驻点根本不存在,但极值在边界上。二元函数的极值可能在区域边界取得,这时候求偏导为零的方法直接失效。处理办法是把边界参数化,例如约束 x² + y² = 1 时令 x = cos θ、y = sin θ,把它化成一元问题;或者用拉格朗日乘数法引进约束。这部分属于约束优化范畴,跟泰勒展开是配套使用的工具,不是替代关系。
我的经验是,拿到一道极值题,先扫一眼最高次项的奇偶性。如果函数里出现三次项,就要警惕鞍点;如果二阶导在驻点处全为零,直接跳到三阶甚至四阶去看,不要在二阶上死磕。
| 情形 | det H | fxx | 结论 |
|---|---|---|---|
| 极小值 | > 0 | > 0 | 二阶信息足够 |
| 极大值 | > 0 | < 0 | 二阶信息足够 |
| 鞍点 | < 0 | 任意 | 二阶信息足够 |
| 需更高阶 | = 0 | 任意 | 展开到三阶或更高 |
5. 踩过的坑:二元泰勒展开最容易翻车的地方
5.1 错误清单与后果对照
我在帮别人看计算稿的时候,遇到的问题高度集中在下面这几种。整理成表格,方便对照排查。
| 典型错误 | 表现 | 后果 | 正确做法 |
|---|---|---|---|
| 漏掉交叉项系数 2 | 写成 fxy·hk | 二阶项严重偏小 | 统一用算子展开核对 |
| 漏掉 1/2 | 二阶项整体放大一倍 | 近似值偏大 | 回到一元公式核对 |
| 非原点展开直接用 x、y | 展开点没平移 | 结果完全错误 | 先设 h = x - x0, k = y - y0 |
| 混淆 h 与 x | 把增量当变量 | 公式含义错乱 | 明确 h、k 是小增量 |
| 海森矩阵写成非对称 | fxy 与 fyx 位置颠倒 | 特征值算错 | 除极端情况外 H 对称 |
| 直接套一元极值结论 | 用 f'' > 0 判极小 | 结论错误 | 必须先算 det H |
第三行那个错误我见过太多次,尤其是从一元公式直接往二元迁移的时候。一元泰勒展开的展开点常常是 0,所以 (x - 0) 和 x 长得一样,久而久之就形成了"变量本身就是增量"的错觉。一旦展开点不是 0,这个错觉就会带来灾难性后果。
5.2 误差估计与阶数取舍的实操判断
余项公式 R2 = (1/6)(h∂x + k∂y)³ f(ξ, η) 在实际计算里没法直接用,因为 ξ、η 未知。但可以估一个上界:
|R2| ≤ (1/6)·M·(|h| + |k|)³
其中 M 是三阶偏导在展开邻域内的最大绝对值。这个上界通常偏保守,但用来判断"阶数够不够"完全够用。
举个例子。某函数的三阶偏导在邻域内最大约为 10,步长 h = k = 0.05。上界约为 (1/6)×10×(0.1)³ ≈ 1.7×10⁻³。如果目标精度是 10⁻³,这个展开刚够;如果目标是 10⁻⁵,那二阶展开远远不够,要么把步长缩到 0.01,要么加三阶项。
我在实践中总结出一套粗略的经验阈值,仅供参考:
- 步长在 0.1 量级、函数光滑:二阶展开误差约在 10⁻³ 到 10⁻⁴
- 步长在 0.01 量级:二阶展开误差约在 10⁻⁶ 到 10⁻
- 需要 10⁻⁹ 以上精度:步长要缩到 10⁻³,同时考虑浮点舍入误差反噬
最后一条值得强调。总能听到"步长越小越准"的说法,这在纯数学上成立,但在计算机上不成立。当 h 小到 10⁻⁸ 量级时,计算 f(x0+h) - f(x0) 会产生严重的相减抵消误差,反而把精度毁掉。泰勒展开在数值计算里有一个最优步长,通常落在 10⁻⁵ 到 10⁻⁸ 之间,具体取决于函数值的量级和机器的有效位数。这是从纸面公式走到实际代码时必然会撞上的一堵墙。
5.3 三个自检手段,写完公式先跑一遍
手段一:令 k = 0,退化成一元。如果你写的二元展开式在 k = 0 时不能退化成正确的一元泰勒公式,那它一定是错的。这是个五秒钟的检查,我几乎每次都做。
以 f = eˣ sin y 为例,令 k = 0 意味着 y 固定在 0。展开式变成 0 + 0·x + 0 + 0,而 f(x, 0) = eˣ·0 = 0 恒成立,一致。
手段二:用二次多项式验证。拿 f = x² + xy + y² 或 f = 2x² - 3xy + y² 这类函数试。二阶泰勒展开对二次多项式必须精确等于原函数,任何偏差都说明系数有问题。这个手段能同时查出漏 2、漏 1/2、平移错误三类问题。
手段三:步长减半,看误差缩小几倍。这是最硬的验证。方法如下:取一个已知真值的点,分别用步长 d 和 d/2 计算二阶展开的误差,两个误差之比应该在 8 附近(因为误差是三次量级,步长减半 → 误差缩小 2³ = 8 倍)。如果比值接近 4,说明你的误差其实是二次量级,多半是二阶项写错了或者漏了;如果接近 2,说明一阶项就有问题。
我用 f = eˣ cos y 在原点做了实测。展开到二阶是 1 + x + (1/2)(x² - y²)。
取 x = y = 0.2 时,真值 e^0.2·cos 0.2 ≈ 1.197052,展开值 1.2,误差约 -2.95×10⁻³。
取 x = y = 0.1 时,真值 e^0.1·cos 0.1 ≈ 1.099650,展开值 1.1,误差约 -3.50×10⁻。
比值 2.95/0.35 ≈ 8.4,非常接近 8,确认二阶展开无误。顺手提一句,两次误差都是负号,说明三阶项主导,这与 (1/6)(x³ - 3xy²) 的符号分析完全一致。这种"误差符号也符合理论"的细节,能让人对自己的计算更有信心。
注意:这条自检的前提是函数足够光滑、步长足够小、真值计算精度足够高。如果函数在展开点附近有奇点或不连续,误差比值的规律会被破坏,这时候要先检查函数本身。
6. 工程里的延伸用法:公式之外的真正价值
6.1 牛顿法:二阶展开的迭代求解版本
解方程 f(x) = 0 的一元牛顿法是 x_{n+1} = x_n - f/f'。这个公式的来源就是一阶泰勒展开:把 f 在 x_n 附近线性化,令线性部分为零,解出下一个点。
二元的情形是一元思路的直接推广,但形式变了。
解方程组时,设 F(x, y) = (u(x, y), v(x, y)),要求 F = 0。线性化之后得到的是雅可比矩阵 J = [[ux, uy], [vx, vy]],迭代式是 d = -J⁻¹F,然后 (x, y) ← (x, y) + d。注意这里用的是一阶展开,因为目标是解方程而不是找极值。
求极值时情况不同,需要的是二阶展开。目标函数 f 在 x_n 附近二阶近似后,令梯度为零,得到迭代式:
x_{n+1} = x_n - H⁻¹∇f
这是一元公式 x_{n+1} = x_n - f'/f'' 的二元版本。它的收敛速度是二次的,非常快,但代价是每步都要计算并求逆海森矩阵,在变量多的时候计算量巨大。工程上常用的拟牛顿法(如 BFGS)就是想办法用迭代更新的方式近似 H⁻¹,避免每步求逆。
我在做参数反演的时候试过两种方案:一阶梯度下降迭代几百次收敛,用海森信息的牛顿法十几步就收敛了。但牛顿法在海森矩阵接近奇异或者非正定时会剧烈震荡甚至发散,所以实际代码里几乎都要加阻尼或线搜索。二阶展开给出的不只是更快的收敛,还有对"当前点曲率有多大"的定量描述,这个信息可以用来动态调整步长,比盲目设固定学习率靠谱得多。
6.2 最小二乘与曲面拟合
回到第一章那个温度场的例子。假设要拟合的模型是 T(x, y),实测点有噪声,用最小二乘求解时需要构造残差平方和 S(θ) = Σ (T_i - f(x_i, y_i; θ))²,其中 θ 是模型参数——这里 θ 往往本身就是二维或多维的。
对 S 做二阶泰勒展开,就得到高斯-牛顿法的框架。核心近似的思路是:残差在小扰动下近似线性,于是 S 的海森矩阵可以用 JᵀJ 近似,其中 J 是残差对参数的雅可比矩阵。这一步"用一阶导数拼出二阶信息"的做法,正是泰勒展开在工程优化中最广泛的落地形式之一。它省掉了二阶偏导的计算,代价是在残差较大的时候近似不够准,收敛会变慢。
我自己写曲面拟合代码时,第一步永远是把 f 在初值点附近展开,检查梯度和海森矩阵是否合理。如果海森矩阵出现负特征值,说明初值选得不好或者模型本身有问题,这时候直接跑迭代只会浪费机时。
6.3 误差传播与灵敏度分析
一阶泰勒展开在实验数据处理里有个更朴素但更常用的身份:误差传播公式。
如果 z = f(x, y),而 x 和 y 分别有测量误差 Δx、Δy,那么:
Δz ≈ fx·Δx + fy·Δy
这个式子的推导就是一元泰勒展开的二元版本——把 f 在测量点附近线性化,忽略高阶项。它有两个重要推论。
第一,各方向的贡献可以线性叠加,这让你能快速判断哪个变量的测量误差是主要矛盾。如果 fx 比 fy 大一个量级,那改善 y 的测量精度基本没用,钱要花在 x 上。
第二,相对误差可以写成弹性形式。两边除以 z,得到 Δz/z ≈ (x·fx/f)·(Δx/x) + (y·fy/f)·(Δy/y),括号里那两项就是弹性,表示"x 变化 1%,z 变化百分之几"。这个形式在做成本模型、收益模型时特别顺手。
需要提醒的是,这个线性叠加只在误差很小、函数接近线性的时候成立。如果 fx 本身随位置剧烈变化,或者 Δx 已经大到一阶近似失效,就必须用二阶展开甚至直接做蒙特卡洛模拟。判断标准很简单:把测量值代入展开式,如果二阶项和一阶项量级相当,一阶误差传播就不能用了。
6.4 图像处理里的亚像素定位
这是二元泰勒展开最"不显眼但极其关键"的应用场景之一。
在图像里找特征点(比如角点、斑点)时,算法先做整数像素级别的搜索,找到响应值最大的那个像素。但真正的峰值几乎不可能刚好落在一个整数像素上,它藏在两个或四个像素之间。这时候就要用二阶泰勒展开,把响应函数 R(x, y) 在候选点附近展开:
R(x, y) ≈ R0 + ∇R·d + (1/2)dH d
然后令梯度为零,解出偏移量 d = -H⁻¹∇R。求出来的 d 通常是 (0.3, -0.7) 这样的亚像素量,把候选点坐标加上它就得到亚像素精度的位置。
这一步在相机标定、双目测距、模板匹配里都绕不开。我对这套流程的体会是:整数像素的精度决定了能不能找到特征,亚像素的精度决定了测量结果的重复性。同一批标定板拍十张图,如果只做整数像素定位,重复性可能在 0.5 像素上下;加上二阶展开的亚像素修正,重复性通常能压到 0.05 像素以内,差了一个数量级。
代价是海森矩阵必须足够准。图像数据有噪声,直接对差分结果求二阶导会把噪声放大。常见做法是先做高斯平滑或者用尺度参数控制差分间隔,再算二阶偏导。这一步的取舍跟前面讲的"步长过大过小都不行"是同一个道理。
7. 常见追问的直接回答
写到这儿,把平时被问得最多的几个问题一次性答完,都是实操中真会卡住人的。
问:展开到二阶够不够,什么时候必须上三阶?
答:看目的。做近似计算,如果步长在 0.01 以内、函数光滑,二阶基本够用。做极值判定,只要 det H ≠ 0,二阶就足够给出结论。只有 det H = 0 的退化情形才需要三阶。另外做高精度数值算法时,三阶项常被用来构造误差修正项,这时候不是"够不够"的问题,而是"要不要顺便修掉"的问题。
问:海森矩阵算出来非对称怎么办?
答:先检查是不是算错了。在绝大多数工程函数里,只要二阶偏导连续,海森矩阵必然对称。如果确实非对称,说明函数在该点附近的二阶偏导不连续,或者包含了分段逻辑、绝对值、饱和等不光滑结构,这时候泰勒展开的适用性要重新评估。
问:展开点选在哪里比较好?
答:选在你要研究的位置,或者已知函数值、导数信息最可靠的位置。测量数据做拟合时,选在数据最密集、噪声最小的区域中心。展开点离评估点越远,误差越大,而且误差是按距离的三次方增长的,所以离得远的时候千万别指望二阶展开还能准。
问:和一元泰勒展开的心智模型差别最大的地方在哪?
答:一元展开只有一个方向,二维及以上的展开必须把方向包含进去。这就导致了两个后果:一是每一项都要带上方向分量(h 或 k),二是要处理混合项。我自己的心智模型是:二元泰勒展开 = 沿任意方向的一元泰勒展开,把所有方向的贡献一次性打包处理。
问:为什么要用矩阵形式而不是标量形式?
答:因为矩阵形式把方向信息剥离出去了,剩下纯粹的"函数在当前点的曲率结构"——也就是海森矩阵。分析这个矩阵的特征值,就能判断极值、估计条件数、设计迭代步长。这跟一元里"看 f'' 的符号"是一回事,只是维度上去了,需要的工具从"符号"变成了"特征值"。
最后分享一个我自己的习惯。每次写完一个二元泰勒展开式,我都会做三件事:先令 k = 0 看能不能退回一元,再拿一个二次多项式验证精确性,最后挑两个小步长做数值对比看误差比值是否接近 8。这三步加起来不超过三分钟,但帮我挡掉了无数次把错误公式带进后续计算的事故。公式记不住不要紧,这套自检流程记住了,出错概率会低很多。