从一个问题开始
如果把多元损失函数 f(x1,x2,…,xn) 想象成地形险峻的庞大山脉,身处迷雾中的我们该如何找到下山最快、最陡峭的方向?
答案就是梯度向量(Gradient Vector)。梯度指针永远指向高度增加最快的方向,因此它的反方向就是最陡下降方向。这一章我们将推导梯度、方向导数、Jacobian 矩阵与 Hessian 二阶曲率矩阵,并用 Matplotlib 绘制损失面的等高线与梯度轨迹。
初学者直觉:迷雾中盲人的罗盘 (The Blind Hiker)
想象你被困在一座大山中,四周是大雾什么也看不见,脚下是一块不平坦的斜坡:
- 你向四周各个方向探出脚去踩一踩,找到坡度最陡峭向上的方向——这就是梯度 ∇f 的方向。
- 为了尽快走到山谷底部,你转过身,沿着坡度最陡峭向下的方向走一步——这就是负梯度 −∇f。
点击放大查看图:迷雾中山坡上的梯度向量与最陡下降方向罗盘示意图
1. 梯度向量与方向导数
1.1 梯度向量 (Gradient)
对 n 元标量函数 f(x1,x2,…,xn),把所有偏导数组合成一个列向量,即为梯度向量 ∇f:
∇f(x)=∂x1∂f∂x2∂f⋮∂xn∂f
1.2 方向导数与“最陡”证明
沿任意单位方向向量 v(∥v∥2=1)的方向导数为:
Dvf(x)=∇f(x)Tv=∥∇f(x)∥2∥v∥2cos(θ)
当 θ=0∘(v 与 ∇f 同向)时,cos(θ)=1,方向导数达到最大值!这严密证明了:梯度向量 ∇f 的方向就是函数值增长最快的方向。
2. Jacobian 矩阵、Hessian 矩阵与凸性
2.1 Jacobian 矩阵 (一阶导数矩阵)
对向量输入向量输出的映射 f:Rn→Rm,其一阶偏导数构成 m×n 的 Jacobian 矩阵 J:
Jij=∂xj∂fi
2.2 Hessian 矩阵 (二阶导数与曲率)
标量函数 f(x) 的所有二阶偏导数构成 n×n 的对称 Hessian 矩阵 H:
Hij=∂xi∂xj∂2f
Hessian 矩阵描述了山坡的弯曲程度(曲率)。
2.3 凸函数 (Convex Function) 与鞍点
如果函数的 Hessian 矩阵在全域都是半正定矩阵(H⪰0,即所有特征值 ≥0),则该函数为凸函数。
凸函数具备极佳的性质:任何局部最小值(Local Minimum)必定是全局最小值(Global Minimum)!
点击放大查看图:鞍点马鞍面与凸函数碗状极小值 3D 曲面对比图
存在多个局部极小值
与鞍点 (Saddle Points)
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
3. 手算演练
手算练习:求解梯度向量与 Hessian 矩阵
给定二维损失函数 f(x1,x2)=x12+3x1x2+2x22:
- 第一步:求一阶偏导,构造梯度向量 ∇f:
∂x1∂f=2x1+3x2
∂x2∂f=3x1+4x2
梯度向量:∇f(x1,x2)=[2x1+3x23x1+4x2]。
- 第二步:在点 (x1=1,x2=2) 处计算梯度值与最陡下降方向:
∇f(1,2)=[2(1)+3(2)3(1)+4(2)]=[811]
最陡下降方向(负梯度):−∇f(1,2)=[−8−11]。
- 第三步:求二阶偏导,构造 Hessian 矩阵 H:
H11=∂x12∂2f=∂x1∂(2x1+3x2)=2
H12=∂x1∂x2∂2f=∂x2∂(2x1+3x2)=3
H21=∂x2∂x1∂2f=∂x1∂(3x1+4x2)=3
H22=∂x22∂2f=∂x2∂(3x1+4x2)=4
得出 Hessian 矩阵:H=[2334]。
- 第四步:判断 Hessian 矩阵的行列式与曲率:
det(H)=(2×4)−(3×3)=8−9=−1<0
由于行列式小于 0,特征值一正一负,说明原点是一个**鞍点(Saddle Point)**而非极小值点!
4. 动手实战:二维损失面等高线与梯度箭头可视化
下面的代码演示如何利用 NumPy 计算二维二次损失面 f(x,y)=x2+3y2 的梯度场,并模拟梯度下降的迭代轨迹:
import numpy as np
# 1. 定义损失函数及其梯度向量
def loss_func(x1: float, x2: float) -> float:
return x1**2 + 3.0 * x2**2
def grad_loss(x1: float, x2: float) -> np.ndarray:
return np.array([2.0 * x1, 6.0 * x2])
# 2. 模拟梯度下降轨迹
x_current = np.array([4.0, 3.0]) # 初始点
learning_rate = 0.1
trajectory = [x_current.copy()]
for step in range(10):
g = grad_loss(x_current[0], x_current[1])
x_current = x_current - learning_rate * g
trajectory.append(x_current.copy())
trajectory = np.array(trajectory)
print("初始点 (x1, x2):", trajectory[0])
print("第 5 步轨迹点:", np.round(trajectory[5], 4))
print("第 10 步轨迹点:", np.round(trajectory[10], 4))
print("第 10 步 Loss 值:", np.round(loss_func(trajectory[-1, 0], trajectory[-1, 1]), 6))
5. 常见错误与避坑指南
|
| 参数越更新 Loss 越大 | 更新方向是否写反 | 记住参数更新公式是 wnew=w−η∇f(减去梯度),而不是加上梯度 |
| Hessian 矩阵计算耗时极高 | 参数维度是否巨大 | 在深度学习中,千万级别的参数量无法显式存储 N×N 的 Hessian 矩阵,工程上采用一阶优化或 Hessian-Free 近似 |
| 误认为所有驻点 (∇f=0) 都是极小值 | 是否为鞍点或极大值 | 驻点可能为鞍点,必须通过 Hessian 矩阵特征值的正负或高阶采样来诊断 |
检查清单 (Checklist)
自测题
- 给定 f(x,y)=x3+2xy−y2,计算其在点 (1,2) 处的梯度向量 ∇f(1,2)。
- 解释:为什么鞍点(Saddle Point)在某些方向上梯度的偏导为 0,但它既不是极小值也不是极大值?
- 如果一个二维函数的 Hessian 矩阵为 H=[4006],它是凸函数吗?
- 【代码阅读题】在梯度下降迭代中,如果把
learning_rate 设置得过大(例如 1.5),轨迹点 x_current 会发生什么现象?
点击查看参考答案
- ∂x∂f=3x2+2y⟹3(1)2+2(2)=7;∂y∂f=2x−2y⟹2(1)−2(2)=−2。梯度向量为 [7,−2]T。
- 因为在鞍点处一阶偏导数均等于 0,但在某些切面方向上它是极小值,在另一些切面方向上它是极大值(类似于马鞍的形状)。
- 矩阵 H 的特征值分别为 4 和 6(均大于 0),为严格正定矩阵,因此该函数是严格凸函数。
- 轨迹点会在山谷两侧剧烈震荡并迅速发散到无穷大(
NaN 或 Inf)。
下一步
进入下一个专项 ,学习批量 Gradient Descent、随机 SGD 与 Mini-batch 批次更新及学习率收敛性。
参考资料
- :第 5.1-5.3 节 梯度向量与高阶导数。
- :梯度的本质与动画。
- :梯度与凸优化工程直觉。