首页 / 资讯中心 / 文章详情

黑塞矩阵全解析:从泰勒展开到二阶优化算法的进阶指南

黑塞矩阵全解析:从泰勒展开到二阶优化算法的进阶指南 ★ FEATURED ARTICLE
1. 为什么低阶信息救不了你一阶方法的尴尬1.1 一个常见场景梯度下降里的学习率为什么这么难调调过模型的人应该都有这种感受梯度下降里最玄学的参数就是学习率。设大了直接震荡甚至发散设小了半天收敛不动跑个几百轮loss还挂在高位下不去。我一开始也以为这纯粹是工程手感问题后来认真把多元函数的泰勒展开和黑塞矩阵吃透才发现“步长”这个参数背后其实有非常具体的二阶几何意义跟曲率是绑在一起的。先说一个一维的直觉例子。假设目标函数是 f(x)x²在某个点 x₀ 处做泰勒展开到二阶写出来是f(x) ≈ f(x₀) f(x₀)(x-x₀) ½f(x₀)(x-x₀)²对 f(x)x² 来说f2 恒成立。如果只保留一阶项你会得到一个直线近似它给出的唯一信息是“该往哪个方向走”完全没告诉你“该走多远”。所以梯度下降只能依赖外部指定的学习率 α迭代公式变成 x_{k1} x_k - 2αx_k (1-2α)x_k。这个递推收敛的条件是 |1-2α| 1也就是 0 α 1而系统自动给出的最优步长是 α 0.5。0.5 这个数字从哪来恰好就是 1/f。换句话说如果提前知道二阶导数是2就能一步到位求出全局最小点 x0根本不用试错。到了多元场景一阶信息变成梯度向量 g它同样只告诉你在当前点往哪个方向上升最快、下降最快。但每个维度的“陡峭程度”可能完全不一样有的方向很平缓有的方向很陡峭这时候一个统一的标量学习率就非常尴尬了。学习率调大陡峭方向会震荡调小平缓方向推进太慢。1.2 从“往哪走”升级到“走多远”二阶项带来的完整局部图像一阶泰勒展开本质上是拿一个切平面去近似原函数这个近似在小邻域内也许够用但稍微走远一点就失真了。我经常把一阶近似想象成站在山腰上只看脚下知道哪个方向是下坡但不知道坡面的弯曲程度。而二阶泰勒展开会把“弯曲程度”也纳入考量得到一个抛物面近似这个抛物面的开口方向、开口宽窄、各方向的曲率大小全部由黑塞矩阵编码。多元泰勒展开的完整形式以点 a 为基准对增量 Δx x - a 展开写出来是f(aΔx) ≈ f(a) gᵀΔx ½ΔxᵀHΔx这里 g 是一阶偏导组成的梯度向量H 就是黑塞矩阵。看到这个结构你会发现一阶项是一个线性函数二阶项是一个二次型。其实这就是多元函数的“二阶泰勒多项式”它相当于把一元情形里的“斜率”推广成梯度向量把“曲率”推广成一个矩阵。对于纯数学学习来说理解到这个公式也许就够了。但如果你跟我一样是做优化、做机器学习相关工作的光知道公式完全不够还得知道这个二次型怎么用、黑塞矩阵的每一项怎么算、以及它在具体算法里扮演什么角色。下面两节我会拆开讲。2. 多元泰勒展开从偏导到黑塞矩阵的每一块拼图2.1 梯度向量和黑塞矩阵的定义以及它们为什么长这样设 f(x₁, x₂, ..., xₙ) 是 n 元函数。梯度向量 g 就是所有一阶偏导数拼成的列向量g [∂f/∂x₁, ∂f/∂x₂, ..., ∂f/∂xₙ]ᵀ黑塞矩阵 H 则是所有二阶偏导数拼成的 n×n 矩阵第 i 行第 j 列的元素是 ∂²f/∂xᵢ∂xⱼ。这里很多人第一次接触会懵一下为什么二阶信息需要一个矩阵而不是一个向量原因其实很简单一元函数只有一个自变量二阶导数就是一个数多元函数有 n 个自变量任意两个自变量之间都可能存在“交叉弯曲”效应所以 n 个一阶偏导互相求导自然得到 n×n 个组合这个矩阵就是把这些组合整整齐齐排在一起的产物。举个具体的二元函数例子。取 f(x, y) x² 3xy y²在点 a(1,1) 处做二阶泰勒展开。先算梯度∂f/∂x 2x 3y代入 (1,1) 得 5∂f/∂y 3x 2y代入 (1,1) 也得 5所以 g [5, 5]ᵀ。再算黑塞矩阵∂²f/∂x² 2∂²f/∂y² 2∂²f/∂x∂y 3∂²f/∂y∂x 也等于 3所以 H [[2, 3], [3, 2]]注意交叉偏导和顺序无关这是个对称矩阵。把 f(1,1)5 代入二阶泰勒展开式得到f(1Δx, 1Δy) ≈ 5 5Δx 5Δy Δx² 3ΔxΔy Δy²你可以拿几个点验算一下比如 Δx0.1、Δy-0.1 时真实值算出来和近似值很贴近误差来自更高阶项这正是二阶泰勒展开“局部精确”的体现。2.2 混合偏导到底在描述什么交叉项不是添乱的很多人看到 3ΔxΔy 这个交叉项会感觉不自在直觉上觉得它打破了“x 方向和 y 方向各自独立”的清爽感。但它反映的恰恰是真实世界里最常见的现象方向之间互相耦合。想象你在山坡上如果地形是 x 方向和 y 方向独立叠加的比如 f(x,y)x²2y²那么沿 x 方向的弯曲和沿 y 方向的弯曲互不影响等高线是正椭圆黑塞矩阵是对角阵。一旦出现混合偏导非零说明沿着某个斜方向的曲率跟沿着坐标轴的曲率不再是简单叠加地形图上是扭曲的椭圆或马鞍形这就是现实世界绝大多数函数的常态。用把黑塞矩阵对角化来理解会更清楚。一个对称矩阵总可以写成特征分解H QΛQᵀ其中 Q 的列向量是特征向量Λ 是对角矩阵对角线是特征值。几何上特征向量指向曲面的“主轴方向”特征值就是这些方向上的二阶导数。所以黑塞矩阵虽然看起来有 n² 个元素但真正独立的信息是 n 个主轴方向的曲率加上这些主轴的方向。交叉项只是把主轴方向和坐标轴方向错开的一种编码方式。比如上面那个 H [[2,3],[3,2]]特征值分别是 5 和 -1对应特征方向是 (1,1) 和 (1,-1)。这说明沿着 45° 方向函数弯得非常陡沿着 -45° 方向则反向弯曲这就是一个典型鞍点的二阶特征某个方向上是谷底另一个方向上是峰顶。2.3 为什么泰勒展开通常只保留到二阶高阶项去哪了严格来说多元泰勒展开有无穷多项三阶、四阶项都存在为什么几乎所有优化理论都只讨论二阶因为二阶截断已经同时包含了“位置”、“方向”、“曲率”三类最关键的信息而三阶以上的项对应的张量结构非常复杂计算和存储成本成数量级上升实际工程收益却很低。更重要的是在极小点附近有一个非常有用的结论如果函数足够光滑在稳定点附近展开时一阶项为零二阶项成为主导。这意味着判断一个点是不是局部极小值几乎完全由黑塞矩阵决定。三阶项只在远离极值点的区域才有明显作用而优化算法通常也不会指望靠高阶项在远处“一步跳准”。自动微分工具出现之前手算黑塞矩阵是个费神活现在用自动微分框架几行代码就能拿到但后面会讲能拿到和能用好是两码事。3. 黑塞矩阵的几何信息凸性、极值点判定与“鞍点危机”3.1 特征值正负号决定了你是谷底、峰顶还是马鞍上的骑手把黑塞矩阵看作一个二次型后极值点判定就很直观了。设 x* 是梯度为零的点那么如果 H 正定所有特征值大于 0x* 是局部极小点曲面像一个开口向上的碗如果 H 负定所有特征值小于 0x* 是局部极大点曲面像一个倒扣的碗如果 H 特征值有正有负x* 是鞍点沿某些方向是谷沿另一些方向是岭如果 H 存在零特征值需要看更高阶项才能判断属于退化情况。我几年前第一次写优化算法时天真地以为梯度为零就是极小值结果碰到一个鞍点卡了半天。当时的目标函数是 f(x,y)x²-y²在 (0,0) 处梯度为零但黑塞矩阵是 diag(2,-2)特征值一正一负沿 y 方向随便走一步函数值都会下降根本不是一个稳定落脚处。事后反思如果当时哪怕写出黑塞矩阵看一眼特征值符号也不至于傻乎乎在鞍点附近反复横跳。这种例子在深度学习里太常见了高维损失面里鞍点比局部极小值多得多因为高维空间中“正好所有方向都是谷底”的概率极低。这也是为什么纯一阶的 SGD 在高维损失面上经常踌躇不前而动量、二阶近似等机制能帮助翻越鞍点区域的原因之一。3.2 正定矩阵判定从考试题到实际数据的距离判断一个对称矩阵是否正定教科书标准做法是检查所有顺序主子式的行列式是否为正。但对实际模型来说这个做法的计算成本和数值稳定性都不理想。工程上更常用的几个操作判据是判定方法优点缺点特征值全正最直观几何含义清楚n 大时特征分解开销高所有顺序主子式为正适合小规模手算数值误差敏感n 大时不可用Cholesky 分解成功速度较快工程常用只给“是/否”不给出曲率分布对所有方向 vvᵀHv 0抽样判定可用于高维严格来说要验证无穷多个方向对几十维、几百维的小问题直接用特征值最简单对几千维以上的大问题通常没人去算完整黑塞而是用拟牛顿方法或Conjugate Gradient去隐式利用二阶信息。这里提一句判定正定性时别忘了先检查对称性。因为数值舍入误差哪怕是自动微分也可能产生不对称的结果正规做法是先做 H ← (HHᵀ)/2 对称化再判定。3.3 用黑塞矩阵看等高线图和条件数我在实际用等高线图调试优化器时发现黑塞矩阵和等高线形状的联系非常直观可以用来反推优化难度。假设函数二阶近似是 ½ΔxᵀHΔx等高线就是一族椭圆椭圆的轴方向对应黑塞的特征向量轴长比例对应特征值之比。这个比值就是条件数数学上写 κ(H) λ_max / λ_min。当条件数接近 1 时等高线趋近圆梯度下降不需要调整学习率任何方向收敛速度都差不多当条件数很大时等高线是被压扁的狭长椭圆梯度方向几乎垂直于长轴方向普通梯度下降会沿着狭窄的谷壁来回震荡效率极低。这就是为什么“每个方向自适应学习率”的算法会比标准梯度下降舒服得多。后面讲 AdaGrad、RMSProp 这类算法时它们本质上都是在用梯度历史去近似黑塞矩阵的对角信息从而抵消不同方向上曲率差异带来的震荡。4. 黑塞矩阵在现代优化算法里到底被怎么“用起来”的4.1 牛顿法一步到位利用二阶信息的天才方案如果目标函数真的接近二次函数二阶泰勒展开几乎就是精确模型那么直接把模型求导令为零就能得到精确的牛顿迭代公式x_{k1} x_k - H(x_k)⁻¹ g(x_k)这个公式的意义是在当前点用抛物面拟合真实曲面然后直接跳到这个抛物面的顶点。沿着某个方向如果曲率大H⁻¹ 会把这个方向的步长缩小如果曲率小则会把步长放大。换句话说黑塞逆矩阵本质上是一个“方向感知的自适应学习率”。回到一维例子 f(x)x²梯度为 2x二阶导为 2一步更新得到 x₁ x₀ - 2x₀/2 0直接从任何初始点一步命中最小值。三维、多维也是同样的逻辑只要 H 可逆且局部近似足够准二阶方法可以极大减少迭代次数。当然代价也很明显需要存一个 n×n 矩阵需要求逆两者在大规模场景里都太奢侈。这也是为什么机器学习领域几乎不会直接上牛顿法。4.2 深度学习里为什么几乎没人直接算黑塞我见过不少入坑调参的人问既然牛顿法这么厉害为什么训练神经网络不用它答案很现实主要卡在三个点上。存储压力模型参数如果是 1e7 量级黑塞矩阵就是 1e14 个元素直接占 800TB 以上内存这显然不现实。求逆开销即使能存下求逆复杂度是 O(n³)整个训练过程完全不可接受。非凸性深度网络损失函数是高度非凸的黑塞矩阵在许多区域甚至不正定牛顿法对负曲率方向的处理很麻烦搞不好反而把参数推到鞍点或极大值附近。所以深度学习里主流还是一阶方法但一阶方法并非完全抛弃二阶信息。像 Adam 这类算法用梯度的一阶矩估计代替动量用梯度二阶矩估计去对不同维度的学习率做归一化本质上是把“黑塞矩阵对角成分”拿梯度平方历史来近似是一种廉价且鲁棒的二阶信息的偷师。4.3 拟牛顿、L-BFGS 与 CG用梯度差去“猜”黑塞真实世界里想获得完整黑塞又不付巨大代价主流思路是做近似。拟牛顿家族里的 BFGS 算法就是通过连续两次迭代的梯度差和目标函数值差不断修正一个对黑塞逆矩阵的近似完全不需要二阶偏导的计算。L-BFGS 更进一步只保留最近 m 步的修正对从而把空间复杂度压到 O(nm)实践里 m 取 1020 就通常够用。另一种思路是共轭梯度法。它不显式构造黑塞矩阵只在需要的时候计算 K 个方向的二次型乘积 Hv这个乘积可以用自动微分在 O(n) 时间内算出来比完整黑塞省太多。这类“Hessian-free”方法在神经网络的某些场景也火过一段时间原理上就是靠矩阵向量积避开存矩阵的坑。我用过一个中等规模的拟牛顿优化器调一个 50 维的参数问题效果非常明显。普通梯度下降需要上万步才能收敛的精度L-BFGS 几百步就到了而且不用调学习率。原因就在于它用“梯度变化规律”猜出了不同方向曲率差异等于隐式用上了黑塞的几何信息。4.4 算法选型速查什么时候该用哪种二阶信息方案问题规模目标函数形态推荐的二阶方案理由n 1e3凸或近似凸完整牛顿法或 BFGS黑塞可算可存收敛极快1e3 n 1e5中等规模非凸L-BFGS / CG空间开销可控导数可用自动微分n 1e6深度学习非凸SGD 动量 / Adam / RMSProp只保留对角近似鲁棒性优先黑塞奇异或不定任何规模加正则化或用 LM / 高斯牛顿保证迭代方向是下降方向这张表是我自己压过一段时间优化问题后的经验总结不一定对所有场景都最优但能帮你快速排除一些明显不合适的方案。比如我看过有人在一个 1 万维的问题上硬算完整黑塞结果光是矩阵求逆就跑了半小时纯粹是没想清楚开销结构。5. 实操经验算黑塞不难验黑塞和用黑塞才是分水岭5.1 用有限差分验证黑塞矩阵的正确性不管你是手推公式还是用自动微分拿到黑塞矩阵之后第一件事应该是验证它没错。一个非常可靠的验证手段是中心差分数值二阶导公式。对给定点 x方向和方向 j 的二次混合偏导可以写成∂²f/∂xᵢ∂xⱼ ≈ [f(xheᵢheⱼ) - f(xheᵢ-heⱼ) - f(x-heᵢheⱼ) f(x-heᵢ-heⱼ)] / (4h²)这个公式的意思是通过四个偏移点的函数值组合把一阶差分再差分一次得到二阶差商。对 ij 的情况等价于标准的二阶中心差分公式。我在项目里经常这样用自动微分算出一个 H再用有限差分去对比两边的数值差异应该在 h 缩小的过程中逐渐趋近于零。如果差异很大基本都是梯度和黑塞里面有一个写错了排查起来比闷头调参快得多。下面给一段 PyTorch 风格的示意代码展示怎么用自动微分直接拿黑塞矩阵import torch from torch.autograd.functional import hessian def f(x): # 输入 x 是一个二维向量 return x[0]**2 3 * x[0] * x[1] x[1]**2 x torch.tensor([1.0, 1.0], dtypetorch.float64) H hessian(f, x, create_graphFalse) print(H)输出会是一个 2×2 的矩阵对角线是 2 和 2非对角是 3。有限差分验证时选 h1e-5 量级通常能兼顾舍入误差和截断误差太大会有截断误差太小会踩到浮点精度的坑。5.2 数值上容易踩的坑对称性缺失、条件数爆炸和不定方向的修正实际计算黑塞矩阵时会发现数值结果即使来自同一个函数交叉偏导的两侧也可能差出小数点后十几位。这不是算法错了而是浮点运算在路径上有细微不同。所以在做任何正定性判断之前先把矩阵对称化。更麻烦的是条件数爆炸。我碰到过一次牛顿法直接发散的反直觉案例目标函数本身很光滑但真值最优解附近黑塞近似奇异求逆后数值巨大一步就把参数弹出十万八千里。后来加了个技巧在求逆前给黑塞对角线加一个小正数比如 H λI其中 λ 取 1e-4 量级相当于用一个微凸的修正来稳定迭代。这个方法在实现上叫“阻尼牛顿法”等价于在二阶模型和纯梯度方向之间做插值遇到震荡时非常实用。涉及梯度为零但特征值为负的方向时二阶模型会给出“沿负曲率方向下降”的重要提示。有些优化器直接利用负曲率方向去找鞍点出口但在最具体的基础实现里检查特征值符号至少能让你确认当前点到底是不是终点。5.3 我的经验结论黑塞矩阵是分析工具也是设计工具但别指望它包打天下在职场的日常开发里我越来越把黑塞矩阵当“低频分析工具”而不是“高频优化工具”。具体操作顺序通常是先用一阶优化器跑起来快速逼近较优区域在怀疑是极小值或鞍点的位置用自动微分算一次黑塞看特征值分布判断点的性质辅助决定是继续训练、换初始化还是直接停如果条件数过大考虑重新做特征缩放或换二阶近似方法。这套流程比起一上来就上重型二阶优化器要稳得多。因为完整的黑塞信息在十万维以上的非线性问题中本身就是个奢望能不能高效利用取决于你愿意投入多少计算预算。想明白这一点就不会再把黑塞矩阵当成魔法棒而是把它当成一把精度很高、但使用条件较多的手术刀。最后再分享一个顺手的小技巧如果你在调试自定义优化器时总开关在某些维度上无法收敛画一张当前点黑塞矩阵特征值随迭代次数的曲线图往往一眼就能看出是哪个方向在捣乱。比对着 loss 曲线瞎猜高效太多。
阅读完成 · 觉得有帮助?
咨询建站