Series · Linear Algebra · Chapter 11

矩阵微积分与优化 -- 从梯度到反向传播

调淋浴水温就是一个最小号的神经网络训练:根据误差去调一个参数。矩阵微积分把这件事推广到上亿个参数,优化算法则是把它做下去的引擎。本章从标量梯度讲到 Jacobian、Hessian、反向传播、凸优化与 Adam。

从淋浴龙头讲起

每天早上你都在训练一个微型神经网络。水太凉,于是你拧一下旋钮——一个参数;过一秒钟你感受到新的水温——误差信号;再拧一下。三四次之后你就收敛了。

现代深度学习是同一件事,规模放大七个数量级。“旋钮"变成了一个动辄几千万到上亿条目的矩阵$W$;“误差"变成了一个标量损失$L$。但提的问题完全一样:对每一个参数,应该往哪个方向、用多大幅度去推? 答案藏在一个对象里:梯度$\partial L / \partial W$。

本章从零搭起这个对象,再把它真正用起来。

你将学到什么

  • 梯度——标量对向量的导数,以及它为什么"指向上坡”
  • 方向导数——任意方向上的坡度,以及"最速下降"的几何意义
  • Jacobian 矩阵——向量函数的导数,链式法则的基本拼块
  • Hessian 矩阵——二阶导数矩阵,用来判别临界点类型
  • 矩阵导数——你真正会用到的迹和行列式公式
  • 链式法则与反向传播——同一个法则,递归地走遍计算图
  • 凸优化——把"搜索"变成"顺坡而下"的关键性质
  • 优化器全家桶——梯度下降、牛顿法、SGD、动量、Adam

前置知识

  • 一元微积分(导数与链式法则)
  • 向量与点积(第 1 章)
  • 矩阵乘法(第 3 章)
  • 对称矩阵与正定性(第 8 章)

梯度:多维世界里的"坡度”

从一维到多维

你在开一家奶茶店。利润$f$取决于价格$x_1$和广告投入$x_2$。你想知道:稍微改一下价格、或稍微加点广告预算,利润会怎么变?

两个偏导数各回答了半个问题:

-$\partial f/\partial x_1$——固定广告,价格每涨 1 元利润变多少; -$\partial f/\partial x_2$——固定价格,广告每加 1 元利润变多少。

把它们打包成一个向量,就得到梯度

$$ \nabla f = \begin{pmatrix} \partial f/\partial x_1 \\ \partial f/\partial x_2 \end{pmatrix} $$

对一般的$f: \mathbb{R}^n \to \mathbb{R}$:

$$ \nabla f(\vec{x}) = \begin{pmatrix} \partial f/\partial x_1 \\ \vdots \\ \partial f/\partial x_n \end{pmatrix} \in \mathbb{R}^n $$

为什么必须打包成这样:三条几何含义

梯度不只是"偏导数的堆叠",它的"打包方式"正是被三条几何含义所决定的。

1. 方向。 梯度指向函数增长最快的方向。在所有可能的单位方向里,沿$\nabla f$方向走带来最大的增量;反方向走则带来最大的减量——这一句话就是梯度下降算法的全部理论依据。

2. 大小。$\|\nabla f\|$是这个最快方向上的增长率。梯度大,说明此处地势陡,挪一小步函数值就会有大变化;梯度近零,说明你站在了平地或者临界点附近。

3. 正交性。 梯度垂直于等值集$\{\vec{y}: f(\vec{y}) = f(\vec{x})\}$。地形图上的等高线连成一条条"高度不变的线",而梯度永远垂直于这些等高线,正对着上坡方向。

梯度即最速上升方向:左边是 3D 碗状曲面,右边是带梯度场的等高线图

三个值得背下来的例子

下面三个公式后续到处都会用到,建议直接背下来。

线性函数$f(\vec{x}) = \vec{a}^T\vec{x}$,则$\nabla f = \vec{a}$。

图像是一个超平面,$\vec{a}$是它的法向量,也就是函数增长最快的方向。

平方范数$f(\vec{x}) = \|\vec{x}\|^2 = \vec{x}^T\vec{x}$,则$\nabla f = 2\vec{x}$。

一个以原点为底的"碗",梯度从原点辐射向外,正好和"远离最小值的方向"一致。

一般二次型$f(\vec{x}) = \vec{x}^TA\vec{x}$,$A$对称,则$\nabla f = 2A\vec{x}$。

本书后面碰到的所有二次损失,归根到底都是这个公式。如果$A$不对称,把它替换成$\tfrac{1}{2}(A+A^T)$即可——梯度本来也只看到对称部分。


方向导数:不一定要走最陡的路

你不一定非得正对着山顶往上爬。方向导数告诉你在任意单位方向$\vec{d}$上的坡度:

$$ D_{\vec{d}}f = \nabla f \cdot \vec{d} = \|\nabla f\| \cos\theta $$

其中$\theta$是$\nabla f$与$\vec{d}$的夹角。三个角度值最关键:

-$\theta = 0°$(沿梯度方向):增量最大,等于$\|\nabla f\|$; -$\theta = 90°$(沿等高线):函数值不变; -$\theta = 180°$(逆梯度方向):减量最大,等于$-\|\nabla f\|$。

最后一行就是梯度下降的理论根据:要让$f$下降得最快,就沿$-\nabla f$方向走。


Jacobian:向量进,向量出

当输出也是向量时,单个梯度就不够用了——你需要一整张矩阵,每一项对应一对(输入,输出)。

一个做菜的类比

三种调料用量$(x_1, x_2, x_3)$同时影响三个口味指标$(f_1, f_2, f_3)$:咸度、甜度、辣度。一共有$3 \times 3 = 9$个"输入$j$对输出$i$影响多大"的关系。把它们排进一张$3 \times 3$矩阵,就是 Jacobian。

定义

对$\vec{f}: \mathbb{R}^n \to \mathbb{R}^m$,Jacobian 矩阵是一张$m \times n$的矩阵:

$$ J = \frac{\partial \vec{f}}{\partial \vec{x}} = \begin{pmatrix} \partial f_1/\partial x_1 & \cdots & \partial f_1/\partial x_n \\ \vdots & \ddots & \vdots \\ \partial f_m/\partial x_1 & \cdots & \partial f_m/\partial x_n \end{pmatrix} $$

第$i$行就是$f_i$的梯度;$(i,j)$位置回答的是"输入$j$动一下,输出$i$跟着动多少"。

几何含义:最佳线性近似

在$\vec{x}_0$附近,Jacobian 就是$\vec{f}$的最佳线性近似:

$$ \vec{f}(\vec{x}_0 + \Delta\vec{x}) \approx \vec{f}(\vec{x}_0) + J\,\Delta\vec{x} $$

形象一点:Jacobian 描述了函数如何"局部地拉伸/扭曲空间"。输入空间里一个小方块,经过函数后变成一个小平行四边形,而$J$正是那次形变的矩阵。

经典例子:极坐标

变换$(r, \theta) \to (x, y) = (r\cos\theta, r\sin\theta)$的 Jacobian 是

$$ J = \begin{pmatrix} \cos\theta & -r\sin\theta \\ \sin\theta & r\cos\theta \end{pmatrix} $$

它的行列式$\det(J) = r$——这正是把$dx\,dy$换成$r\,dr\,d\theta$时多出来的那个$r$。微积分课上这个$r$像是凭空冒出来的,这里它被你亲手算出来了。


Hessian:曲率,与临界点分类

梯度告诉你坡度,Hessian 告诉你坡度本身怎么变——也就是曲率

定义

对$f: \mathbb{R}^n \to \mathbb{R}$,Hessian 是一张$n \times n$的二阶偏导矩阵:

$$ H = \begin{pmatrix} \partial^2 f/\partial x_1^2 & \cdots & \partial^2 f/\partial x_1 \partial x_n \\ \vdots & \ddots & \vdots \\ \partial^2 f/\partial x_n \partial x_1 & \cdots & \partial^2 f/\partial x_n^2 \end{pmatrix} $$

只要二阶偏导连续,Hessian 就是对称矩阵(Schwarz/Clairaut 定理)。这个对称性是后面一切讨论得以成立的基础——它让我们可以放心地谈$H$的特征值。

二阶 Taylor 展开

Hessian 出现在二阶 Taylor 展开里:

$$ f(\vec{x}_0 + \Delta\vec{x}) \approx f(\vec{x}_0) + \nabla f^T \Delta\vec{x} + \frac{1}{2}\Delta\vec{x}^T H \Delta\vec{x} $$

三项分别是:当前值、线性修正(梯度)、二次修正(曲率)。

临界点分类

在临界点($\nabla f = \vec{0}$)处,线性项消失,函数的局部行为完全由 Hessian 决定:

Hessian 性质临界点类型几何画面
正定($\lambda_i > 0$)局部极小碗底
负定($\lambda_i < 0$)局部极大山顶
不定(特征值正负都有)鞍点马鞍面
半定(有$\lambda_i = 0$)不能确定某些方向是"平的"

两个例子。$f(x,y) = x^2 + y^2$的 Hessian 是$\mathrm{diag}(2,2)$,正定,所以$(0,0)$是极小值点;$f(x,y) = x^2 - y^2$的 Hessian 是$\mathrm{diag}(2,-2)$,不定,所以$(0,0)$是鞍点。

Hessian 的特征值符号决定了临界点类型

为什么深度学习里要单独关心鞍点? 在高维非凸损失里,你随机碰到的"梯度为零"几乎一定是鞍点,而不是真正的极小值。现代优化器必须能穿过它们——这正是动量类方法盛行、而朴素牛顿法在深度网络里几乎没人用的原因。


矩阵导数:当参数本身是矩阵

神经网络里参数大多是矩阵(权重矩阵)。我们需要的是"标量损失对权重矩阵的导数"。

定义

对$f: \mathbb{R}^{m \times n} \to \mathbb{R}$:

$$ \frac{\partial f}{\partial X} = \begin{pmatrix} \partial f/\partial x_{11} & \cdots & \partial f/\partial x_{1n}\\ \vdots & \ddots & \vdots\\ \partial f/\partial x_{m1} & \cdots & \partial f/\partial x_{mn} \end{pmatrix} $$

结果与$X$同形。这个形状规则是本章最实用的"对错检查"——只要推导出来的答案形状不对,那一定是哪一步代数错了。

你真正会用到的几条恒等式

函数关于$X$的导数备注
$\text{tr}(AX)$$A^T$$X$的线性项
$\text{tr}(X^TAX)$$(A + A^T)X$$A$对称时退化为$2AX$
$\text{tr}(AXB)$$A^TB^T$三明治形式
$\det(X)$$\det(X)\, X^{-T}$行列式
$\ln\det(X)$$X^{-T}$极大似然估计里到处都是
$X^{-1}$(微分)$\partial(X^{-1}) = -X^{-1}(\partial X)X^{-1}$逆矩阵

迹之所以高频出现,是因为任何关于矩阵的标量函数都能写成迹的形式,而迹又满足循环不变性$\text{tr}(ABC) = \text{tr}(BCA) = \text{tr}(CAB)$,特别好用。完整公式表请参见 Petersen & Pedersen 的 Matrix Cookbook

向量和矩阵导数的形状规则速查表


链式法则与反向传播

矩阵形式的链式法则

设$\vec{u} = \vec{h}(\vec{x})$,$y = g(\vec{u})$且$g$为标量,则

$$ \frac{\partial (g \circ \vec{h})}{\partial \vec{x}} = J_h^T \nabla g $$

如果两段都是向量值函数,那么各阶段的 Jacobian 直接相乘

$$ J_{\text{total}} = J_k\,J_{k-1}\,\cdots\,J_1 $$

河流污染类比。 上游工厂排放变化$\delta_1$,中游浓度跟着变$\delta_2 = J_1 \delta_1$,下游生态指数再变$\delta_3 = J_2 \delta_2$。最终$\delta_3 = J_2 J_1 \delta_1$——一段一个矩阵,依次相乘。

反向传播:链式法则的高效实现

任何复合表达式——包括上千层的神经网络——都能拆成基本运算的有向无环图,称为计算图。反向传播就是在这张图上反向应用链式法则。

为什么要反向? 设有$n$个输入、$1$个输出(典型场景:百万参数、单标量损失)。

  • 前向模式(dual numbers)算的是 Jacobian-向量乘积$J\vec{v}$;要拿到所有梯度,得做$n$次。
  • 反向模式(反向传播)算的是向量-Jacobian 乘积$\vec{v}^TJ$;一次遍历就能拿到所有$n$个输入的梯度。

深度学习里"$n$“是"模型里所有参数”——反向模式比前向模式大约便宜上百万倍。这一比值,是深度学习在算力上能跑得动的唯一原因。

前向传播算值,反向传播沿同一张图把梯度传回去

全连接层的反向传播

这是最常见也最值得吃透的一段推导;如果本章只让你内化一个计算,就让它是这个。

前向:

$$ \vec{z} = W\vec{x} + \vec{b}, \qquad \vec{a} = \sigma(\vec{z})\quad(\text{逐元素}) $$

反向: 假设后续层已经把$\delta_a := \partial L / \partial \vec{a}$算好传过来。

  1. 穿过激活:$\delta_z = \delta_a \odot \sigma'(\vec{z})$($\odot$是逐元素乘)。
  2. 权重梯度:$\dfrac{\partial L}{\partial W} = \delta_z \vec{x}^T$。注意形状:上游信号与输入的外积,正好和$W$同形。
  3. 偏置梯度:$\dfrac{\partial L}{\partial \vec{b}} = \delta_z$。
  4. 回传给上一层:$\dfrac{\partial L}{\partial \vec{x}} = W^T\delta_z$。

PyTorch、JAX、TensorFlow 等所有现代框架,背后干的就是这一套,逐层执行。

常见激活函数及其导数

ReLU:$\sigma(z) = \max(0, z)$,$\sigma'(z) = 1$($z>0$)或 0。计算便宜、正区间不饱和。代价是负区间梯度恒为零,可能导致"死亡 ReLU"。

Sigmoid:$\sigma(z) = 1/(1+e^{-z})$,有一个优美的恒等式$\sigma'(z) = \sigma(z)(1 - \sigma(z))$。输出在$(0,1)$,可解释为概率。代价是两端饱和,导致深网中梯度消失。

Softmax + 交叉熵。 分类器输出端的标准搭配。这两者组合后的梯度极其干净:

$$ \frac{\partial L}{\partial \vec{z}} = \hat{\vec{y}} - \vec{y} $$

“预测概率减真实标签”——梯度局部、便宜、量级合适,这正是这种组合成为分类问题事实标准的原因。


凸优化:让一切变简单的那条性质

什么叫"凸"

函数$f$是凸的,当图像上任意两点的弦都在图像上方:

$$ f(\alpha\vec{x} + (1-\alpha)\vec{y}) \leq \alpha f(\vec{x}) + (1-\alpha)f(\vec{y}), \quad \alpha \in [0,1] $$

凸性之所以宝贵,靠的就是一句话:

定理: 凸函数的任何局部最小值都是全局最小值。

对凸问题来说,“优化器收敛到了一个局部极小值"就已经是全部故事——你完全不必担心被困在某个糟糕的低洼里。

三种等价刻画(针对$C^2$函数)

1.$f$是凸函数。 2. 图像在切平面上方:$f(\vec{y}) \geq f(\vec{x}) + \nabla f(\vec{x})^T(\vec{y} - \vec{x})$。 3. Hessian 处处半正定:$H(\vec{x}) \succeq 0$。

如果是严格凸,把$\succeq$换成$\succ$。

常见凸函数

函数凸性来源
$\vec{a}^T\vec{x} + b$仿射,既凸又凹
$\|\vec{x}\|_p$($p \geq 1$)三角不等式
$\vec{x}^TA\vec{x}$,$A \succeq 0$Hessian 是$2A \succeq 0$
$e^x$,$x \log x$二阶导数$> 0$
$-\log x$($x > 0$)对数似然损失的基础

凸碗 vs 非凸地形:只有左边那种能保证你找到的就是全局最优

KKT 条件

对带约束问题$\min f(\vec{x})$,s.t.$g_i(\vec{x}) \leq 0$与$h_j(\vec{x}) = 0$,KKT 条件是任何最优点必须满足的,当问题凸时也是充分条件

  1. 原问题可行:$g_i(\vec{x}^*) \leq 0$,$h_j(\vec{x}^*) = 0$。
  2. 对偶可行:$\mu_i \geq 0$。
  3. 互补松弛:$\mu_i\, g_i(\vec{x}^*) = 0$(不等式约束要么紧、要么对应乘子为零)。
  4. 驻点条件:$\nabla f + \sum_i \mu_i \nabla g_i + \sum_j \nu_j \nabla h_j = \vec{0}$。

KKT 是带约束优化的主力工具——而它背后的拉格朗日框架,也是 SVM、最大熵模型乃至 PCA 推导的统一出发点。


优化算法

梯度下降

$$ \vec{x}_{k+1} = \vec{x}_k - \alpha \nabla f(\vec{x}_k) $$

顺坡而下。步长$\alpha$是学习率:太小爬得慢,太大会发散。

对一个条件数为$\kappa$的凸二次函数,收敛率约为$\bigl(\tfrac{\kappa - 1}{\kappa + 1}\bigr)^k$——也就是说一个病态问题($\kappa \gg 1$)会慢得让人崩溃,且轨迹会沿着碗的长轴方向反复横跳。

梯度下降轨迹:左边良态、右边病态——明显的"之"字形抖动

牛顿法

$$ \vec{x}_{k+1} = \vec{x}_k - H^{-1}\nabla f(\vec{x}_k) $$

用二阶 Taylor 展开把$f$近似成二次函数,直接一步跳到那个二次函数的极值点。带来的是二次收敛:每次迭代正确数字位数大致翻倍。

代价是组装并求逆 Hessian 要$O(n^3)$,参数上百万时根本跑不起;而且对非凸损失,牛顿法可能会径直冲向鞍点甚至极大值——它只看"梯度为零”,并不挑类型。

牛顿法 vs 梯度下降:二次函数上牛顿法一步到位

随机梯度下降(SGD)

当损失是$N$个样本损失的均值$L = \tfrac{1}{N}\sum_i \ell_i$时,精确梯度要$O(N)$。改用单个样本(或小批量)的梯度:

$$ \vec{x}_{k+1} = \vec{x}_k - \alpha \nabla \ell_{i_k} $$

每步极便宜。注入的噪声还能帮你穿过窄鞍点和浅盆地——对非凸的深度学习来说,这是一种正面特性。

动量法(Momentum)

朴素 SGD 抖得厉害。动量法用过去梯度的指数滑动平均来"抚平"轨迹:

$$ \vec{v}_{k+1} = \beta\vec{v}_k + \nabla f(\vec{x}_k), \qquad \vec{x}_{k+1} = \vec{x}_k - \alpha\vec{v}_{k+1} $$

经典心象:一颗有质量的球沿坡滚下。惯性把路径磨圆,还能"冲过"小坑。

Adam

把动量(一阶矩)和自适应步长(二阶矩)合二为一:

$$ m_t = \beta_1 m_{t-1} + (1-\beta_1)\nabla f \qquad v_t = \beta_2 v_{t-1} + (1-\beta_2)(\nabla f)^2 $$$$ \vec{x}_{t+1} = \vec{x}_t - \frac{\alpha}{\sqrt{\hat{v}_t} + \epsilon}\hat{m}_t $$

梯度持续较大的参数会被自动调小步长;梯度小、不太动的参数则被调大。默认配置$\beta_1 = 0.9$、$\beta_2 = 0.999$、$\alpha = 10^{-3}$已经是当今大部分深度学习训练的"开箱即用"选择。


三个值得手算的应用

线性回归(闭式解)

目标:$L(\vec{w}) = \|X\vec{w} - \vec{y}\|^2$。

梯度:$\nabla L = 2X^T(X\vec{w} - \vec{y})$。

令其为零,就得到著名的正规方程

$$ \vec{w}^* = (X^TX)^{-1}X^T\vec{y} $$

之所以存在闭式解,正是因为损失是关于$\vec{w}$的凸二次函数。

岭回归

加上一个$\ell_2$正则项:$L(\vec{w}) = \|X\vec{w} - \vec{y}\|^2 + \lambda\|\vec{w}\|^2$,

$$ \vec{w}^* = (X^TX + \lambda I)^{-1}X^T\vec{y} $$

$\lambda I$把$X^TX$的每个特征值整体抬高$\lambda$,从而保证可逆,并把条件数压下来——这是上一章关于条件数那一套直觉的直接应用。

把 PCA 写成优化问题

PCA 可以表述为带约束的最大化问题:

$$ \max_{\|\vec{w}\|=1} \vec{w}^T\Sigma\vec{w} $$

构造拉格朗日$\vec{w}^T\Sigma\vec{w} - \lambda(\vec{w}^T\vec{w} - 1)$,对$\vec{w}$求导并令为零,得$\Sigma\vec{w} = \lambda\vec{w}$。正是因为 KKT 的驻点条件,PCA 才是一个特征值问题;其最优解就是$\Sigma$的最大特征值对应的特征向量。


公式速查表

向量导数

函数导数
$\vec{a}^T\vec{x}$$\vec{a}$
$\vec{x}^T\vec{x}$$2\vec{x}$
$\vec{x}^TA\vec{x}$($A$对称)$2A\vec{x}$
$\|\vec{x}\|_2$$\vec{x}/\|\vec{x}\|_2$

矩阵导数

函数导数
$\text{tr}(AX)$$A^T$
$\text{tr}(X^TAX)$$(A+A^T)X$
$\det(X)$$\det(X)\cdot X^{-T}$
$\ln\det(X)$$X^{-T}$

Python 实战

梯度检验

任何手推梯度的最佳调试工具:用中心差分对照一下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np

def gradient_check(f, grad_f, x, epsilon=1e-5):
    """用数值梯度检验解析梯度。"""
    analytical = grad_f(x)
    numerical = np.zeros_like(x)

    for i in range(len(x)):
        x_plus = x.copy(); x_plus[i] += epsilon
        x_minus = x.copy(); x_minus[i] -= epsilon
        numerical[i] = (f(x_plus) - f(x_minus)) / (2 * epsilon)

    rel_error = np.linalg.norm(analytical - numerical) / (
        np.linalg.norm(analytical) + np.linalg.norm(numerical) + 1e-10)
    return rel_error

# 测试 f(x) = x^T A x
A = np.array([[2, 1], [1, 3]], dtype=float)
f = lambda x: x @ A @ x
grad_f = lambda x: 2 * A @ x

x = np.array([1.0, 2.0])
print(f"相对误差:{gradient_check(f, grad_f, x):.2e}")  # 约 1e-10

相对误差小于$10^{-7}$算合格,小于$10^{-9}$算优秀。

比较 GD、Momentum、Adam

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import numpy as np
import matplotlib.pyplot as plt

def optimize_comparison():
    """在二维各向异性二次函数上对比 GD、Momentum、Adam。"""
    A = np.array([[10, 0], [0, 1]])  # 条件数 = 10
    f = lambda x: 0.5 * x @ A @ x
    grad = lambda x: A @ x

    methods = {
        'GD': {'lr': 0.1},
        'Momentum': {'lr': 0.1, 'beta': 0.9},
        'Adam': {'lr': 0.3, 'beta1': 0.9, 'beta2': 0.999}
    }

    x0 = np.array([5.0, 5.0])
    paths = {}

    for name, p in methods.items():
        x, v, m, vv = x0.copy(), np.zeros(2), np.zeros(2), np.zeros(2)
        path = [x.copy()]
        for t in range(1, 50):
            g = grad(x)
            if name == 'GD':
                x = x - p['lr'] * g
            elif name == 'Momentum':
                v = p['beta'] * v + g
                x = x - p['lr'] * v
            elif name == 'Adam':
                m = p['beta1'] * m + (1-p['beta1']) * g
                vv = p['beta2'] * vv + (1-p['beta2']) * g**2
                m_hat = m / (1 - p['beta1']**t)
                v_hat = vv / (1 - p['beta2']**t)
                x = x - p['lr'] * m_hat / (np.sqrt(v_hat) + 1e-8)
            path.append(x.copy())
        paths[name] = np.array(path)

    fig, ax = plt.subplots(figsize=(8, 6))
    t = np.linspace(-6, 6, 100)
    X, Y = np.meshgrid(t, t)
    Z = 0.5 * (A[0,0]*X**2 + A[1,1]*Y**2)
    ax.contour(X, Y, Z, levels=20, alpha=0.5)
    for name, path in paths.items():
        ax.plot(path[:, 0], path[:, 1], 'o-', markersize=3, label=name)
    ax.legend(); ax.set_aspect('equal')
    ax.set_title('二次函数上的优化轨迹')
    plt.show()

optimize_comparison()

练习题

热身

  1. 计算$f(\vec{x}) = 3x_1^2 + 2x_1x_2 + x_2^2$的梯度。
  2. 找出$f(x,y) = x^3 - 3xy + y^3$的所有临界点,并用 Hessian 逐个分类。
  3. 从偏导定义出发,证明$\nabla(\vec{x}^TA\vec{x}) = (A + A^T)\vec{x}$。

进阶

  1. 推导两层神经网络$f = \sigma_2(W_2\sigma_1(W_1\vec{x} + \vec{b}_1) + \vec{b}_2)$的完整反向传播公式,每一步都标清楚形状。
  2. 证明牛顿法在任意二次函数上一步收敛到最优解。
  3. 用"弦在图像上方"的定义证明:凸函数的任何局部极小值都是全局极小值。

编程

  1. 实现上面的梯度检验函数,并在三个不同函数(其中至少一个含矩阵参数)上验证。
  2. 从零实现 SGD、Momentum、Adam,在 Rosenbrock 函数上比较收敛轨迹并画出来。
  3. 用纯 numpy 实现一个两层神经网络,在二维玩具分类数据集上手写反向传播(不许用任何自动微分框架)。

本章小结

概念关键事实在 ML 中的角色
梯度最速上升方向驱动梯度下降
Jacobian最佳线性近似链式法则的基本拼块
Hessian曲率矩阵判别临界点类型
链式法则Jacobian 相乘反向传播的内核
凸性局部极小 = 全局极小大量损失函数的保证
Adam自适应学习率深度学习默认优化器

最重要的一句话:对一个有上百万参数、单个标量损失的模型,一次反向传播能同时算出所有参数的梯度。 本章其它一切内容,都是为了让这一句话变得精确、可信。


系列导航

参考资料

  • Petersen, K. B. & Pedersen, M. S. The Matrix Cookbook. 矩阵导数恒等式的标准参考。
  • Goodfellow, I., Bengio, Y. & Courville, A. (2016). Deep Learning, 第 6 章——反向传播详解。
  • Boyd, S. & Vandenberghe, L. (2004). Convex Optimization——凸性、拉格朗日、KKT 的标准教材。
  • Nocedal, J. & Wright, S. (2006). Numerical Optimization——牛顿、拟牛顿、信赖域的经典参考。
  • Kingma, D. P. & Ba, J. (2015). “Adam: A Method for Stochastic Optimization.” ICLR.

Liked this piece?

Follow on GitHub for the next one — usually one a week.

GitHub