深度学习中的矩阵求导基础
本文根据合集·深度学习中的数学 by 齐宪标系列视频整理。
阅读本文只需要一元函数微积分(导数与链式法则)和线性代数(矩阵乘法与转置)的基础。
在本文中,用小写字母表示标量,用粗体小写字母表示向量,用粗体大写字母表示矩阵;
表示元素全为 1 的列向量, 表示单位矩阵, 表示逐元素相乘(Hadamard 积)。
写在前面
训练神经网络,本质上是在不断微调网络中的海量参数,让损失函数尽可能小。现代神经网络的参数动辄百万甚至上千亿个,而指挥这场大规模微调的指挥棒,就是梯度:它告诉每一个参数应该往哪个方向调、调多快。
因此,如何对向量和矩阵求导,就成了理解深度学习训练过程绕不开的一关。本文从读者最熟悉的一元函数导数出发,循序渐进地完成三次推广:
- 一元函数 → 多元函数:偏导数、梯度、方向导数;
- 标量函数 → 向量函数:Jacobian 矩阵、Hessian 矩阵;
- 一元链式法则 → 矩阵链式法则:分子布局与分母布局,进而理解神经网络的反向传播。
在此基础上,本文再备齐常见网络层(全连接、激活、卷积、归一化)的导数积木,并把 Feed Forward 网络与自注意力块组装成端到端的反向传播。至于「为什么对输入求导」「梯度如何在层间传递」这些深入的问题,后文会在合适的地方娓娓道来。
从一元导数到偏导数
回顾:一元函数的导数
在高等数学和数学分析的课程中,我们知道一元函数
它的几何意义是函数图像在某点处切线的斜率,物理意义则是瞬时变化率。例如
偏导数:固定其他变量
多元函数的输入不止一个,例如
计算时,只需把其他自变量当作常数,按一元函数求导即可。
举一个贯穿全文的例子:
把
几何上,曲面
梯度与方向导数
给定一个多元函数
其梯度
对于多元函数而言,其梯度是一个和
而方向导数是指函数在某一点处,沿某一给定方向
当
特别地,当
梯度下降:梯度的用武之地
方向导数公式
,即 与梯度同向时,函数上升最快; ,即 与梯度反向时,函数下降最快。
所以,梯度方向是函数值上升最快的方向,负梯度方向是下降最快的方向。想让损失函数变小,就应该沿着负梯度方向更新参数:
这就是梯度下降法,其中
式中的
Jacobian 矩阵
前面讨论的都是「多个输入、一个输出」的标量函数。但在神经网络中,一层往往同时输出多个数,例如
向量函数的每一个分量
是一个
举一个具体的例子:
WARNING
注意:导数的「形状」取决于约定
Jacobian 矩阵的维度是
在文献中存在两种通行的记录方式:
- 分子布局:
就是 Jacobian 矩阵( ); - 分母布局:
取其转置( ),此时标量函数的导数恰好是与自变量同形状的列向量(梯度)。
本文约定:向量函数的导数按 Jacobian 矩阵(分子布局)记录;而标量函数对向量的导数按惯例写成列向量,即梯度(分母布局)。后文将看到,深度学习习惯使用分母布局来做链式法则,此时对 Jacobian 取转置即可。
Hessian 矩阵
给定一个多元函数
其 Hessian 矩阵定义为
Hessian 矩阵收集了所有的二阶偏导数,它是「梯度的导数」:一元情形下对应
在深度学习优化中,Hessian 矩阵描述了损失曲面在各点的曲率,是牛顿法等二阶优化方法的基础。不过由于它的元素个数是
导数的链式求导法则
回顾:一元链式法则
对于一元复合函数,例如
链式法则说的是:复合函数的导数等于各层函数导数的乘积。对于多层复合
其链式求导法则为
一元情形下,乘法交换律保证了这些因子随便怎么排都行。但如果自变量是一个向量或矩阵,因子变成了矩阵乘积,而矩阵乘法不满足交换律,于是「从哪头开始乘」就有了讲究——这就引出了分子表达式和分母表达式两种形式。
分子表达式和分母表达式
这里的分子和分母指的是原微商式
在分子布局下,
- 分子表达式是先求外层函数,然后逐层深入求导;
- 分母表达式是先求内层函数,然后逐层向外求导。
两者只差转置和因子排列顺序,数学上完全等价。但在深度学习中,一般采用分母表达式,原因有二:
- 损失函数
是标量,分母布局下 与 同形状(列向量),各层梯度的形状与参数矩阵的形状一致,便于直观理解和按形状更新参数; - 分母表达式的乘法要从右往左进行:先算
,再逐层左乘更内层的导数——这恰好是「从损失出发、逆着数据流方向」的计算顺序,这正是「反向传播」名字的由来,也与神经网络逐层的结构天然吻合。稍后我们就会看到这种表达方式的方便之处。
多项式向量函数的导数
多项式向量函数是指,每个因变量
一次齐次式
注意到,
这个结果直观看非常合理:
INFO
常用线性函数求导公式
第一条是标量函数的情形(分母布局下结果是与
二次齐次式(二次型)
推导虽然冗长,但每一步都只是「固定其他变量的一元求导」:
特别地,当
这与一元情形
常见神经网络层的导数计算
有了上面的基础工具,现在可以逐一计算深度学习中常见网络层的导数了。请特别留意一种反复出现的模式:每个复杂的层,拆开看都是「线性变换、矩阵乘法、逐元素函数」的组合,于是它们的导数都能用一次齐次式、二次型、矩阵乘法法则和对角 Jacobian 这几块积木拼出来;而 Softmax 这类「不逐元素」的函数,则需要单独推导。
另外提醒一句:本节中出现的「对输入求导」,如前所述都不是要优化输入本身,它们是反向传播让梯度「穿过」这一层的通道;每节里真正要被梯度下降更新的,是各层的可学习参数(权重矩阵、卷积核、
全连接层
一层全连接层的函数表达式为
它是一个典型的一次多项式向量函数(外加一个平移),其中
于是这一层出现了两个方向的导数,用途截然不同:
严格地说,
激活函数
以 ReLU 为例,其函数表达式为
其导函数为
神经网络中的激活函数是逐元素作用的,即
它是一个对角线上的元素可能为 0 或 1,而其他元素均为 0 的矩阵。
INFO
对角矩阵
事实上,任何逐元素函数的 Jacobian 都是对角矩阵,对角线上就是各分量的一元导数。例如常用的 Sigmoid 函数
矩阵乘法的导数
矩阵乘法是神经网络里的万金油:全连接层的
矩阵乘法是双变量函数,两个输入各有一条梯度通道。逐分量展开
两条通道的形状分别与
注意力中的缩放点积
Softmax 的导数
ReLU、Sigmoid 这类逐元素函数的 Jacobian 是对角阵,但 softmax 不是逐元素函数——它的分母
对它用一元商法则,可以算出
其中
读作:先算上游梯度按 softmax 权重的加权平均,再从每个分量中把它扣掉。当 softmax 逐行作用于矩阵时(
卷积层
深度学习中的卷积(实际上是互相关)也是线性运算。以一维离散卷积为例,设输入
对输入求导:既然是线性运算,就可以套用一次齐次式的结论。写成矩阵形式
是一个由卷积核平铺而成的带状矩阵,于是
对卷积核求导:关键在于权重共享——同一个
把这个和写完整就会发现:核的梯度等于输入与上游梯度做互相关。总结成一句话:
卷积的梯度仍然是卷积:输入的梯度用卷积核去卷上游梯度,卷积核的梯度用输入去卷上游梯度。
二维卷积只需把求和换成横纵两个方向,结论完全类似。(数学上严格的卷积要求先把核翻转
归一化层
不论是 BatchNorm 还是 LayerNorm,其函数形式都相同,都是将任何特征分布转化为均值为 0、方差为 1 的特征分布,区别只在于
其中,
整个函数是「中心化 → 缩放 → 仿射变换」的复合,我们分三步把它翻译成线性代数的语言,再求 Jacobian。
第一步:中心化。 分子是用线性代数表示为
记
第二步:方差。 分母的被开方数用线性代数表示为
记
第三步:求 Jacobian。 先逐分量考察
第一项的
最后,
直觉上,两项各有分工:第一项是「先减均值、再除以标准差」这条主路径的线性缩放;第二项则来自「分母
同样地,这里的 Jacobian 是梯度穿过归一化层的通道,而不是用来调整
深度神经网络的导数计算
到这里积木已经凑齐:线性层、矩阵乘法、Softmax、逐元素函数。这一节把它们组装成完整的深度网络:先用最简单的 Feed Forward 网络走一遍端到端的反向传播,再把整个自注意力块——它由多个运算复合而成、还带有分支,本身就是一个小型深度网络——组装出来。
先约定两个贯穿本节的比喻,把反向传播路径上的节点分成两类:
- 终点站:被梯度下降直接更新的参数(如
、 )。梯度抵达它们就算完成了使命,不再继续传递——优化器会拿着这个梯度对参数做一步更新。 - 换乘站:中间状态(如
、 这样的激活值,或输入 )。梯度在这里不作停留,而是借助链式法则「换乘」下一条支路,继续向更早的层传递;虽然 这类梯度也会被算出来,但它们只是过路的通道,不会被用于更新任何东西。
后文示意图中的蓝色节点就是换乘站,橙色节点就是终点站。
计算顺序上,本节沿用「分子表达式和分母表达式」一节的结论:采用分母表达式。原因有二:其一,损失
前馈网络
以一个两层前馈网络为例,输入
将其拆开成
其中
flowchart TD
X["$$\mathbf{x}$$(输入)"] --> G["$$\mathbf{g} = \mathbf{W}_{in}\mathbf{x} + \mathbf{b}_{in}$$"] --> H["$$\mathbf{h} = \mathrm{ReLU}(\mathbf{g})$$"] --> Y["$$\mathbf{y} = \mathbf{W}_{out}\mathbf{h} + \mathbf{b}_{out}$$"] --> L["$$L$$(损失)"]
L -.->|"$$\dfrac{\partial L}{\partial \mathbf{y}} = \mathbf{y} - \mathbf{t}$$"| Y
Y -.->|"$$\dfrac{\partial L}{\partial \mathbf{W}_{out}} = \dfrac{\partial L}{\partial \mathbf{y}}\mathbf{h}^{\top}$$"| WO["$$\mathbf{W}_{out}$$、$$\mathbf{b}_{out}$$(终点站)"]
Y -.->|"$$\dfrac{\partial L}{\partial \mathbf{h}} = \mathbf{W}_{out}^{\top}\dfrac{\partial L}{\partial \mathbf{y}}$$"| H
H -.->|"$$\dfrac{\partial L}{\partial \mathbf{g}} = \mathrm{diag}(\mathbf{g} > \mathbf{0})\dfrac{\partial L}{\partial \mathbf{h}}$$"| G
G -.->|"$$\dfrac{\partial L}{\partial \mathbf{W}_{in}} = \dfrac{\partial L}{\partial \mathbf{g}}\mathbf{x}^{\top}$$"| WI["$$\mathbf{W}_{in}$$、$$\mathbf{b}_{in}$$(终点站)"]
classDef terminal fill:#ffe6cc,stroke:#d79b00,color:#333;
classDef conduit fill:#dae8fc,stroke:#6c8ebf,color:#333;
class WO,WI terminal;
class G,H,Y conduit;上图中,实线是前向传播的数据流,虚线是反向传播的梯度流:蓝色节点是换乘站(中间状态),橙色节点是终点站(被梯度下降更新的参数),各条虚线上的梯度公式将在下文逐步推导。
训练时真正要求导的对象是标量损失
反向传播从损失出发,按分母表达式逐层向前(从右往左)传递梯度:
① 更靠近输出的参数
② 继续向内传给
③ 穿过激活函数到
④ 更靠近输入的参数
注意,沿途算出的
在 DNN 训练过程中,中间状态是需要存储在显存中的。可以认为,这里的
参数矩阵从后向前通过梯度下降算法进行更新,即先更新
自注意力
Feed Forward 网络是一条没有分叉的链,而自注意力块(Attention Block)更接近真实的深度网络:多个运算复合而成,输入还有分支。整个块的计算流程是
其中
flowchart TB
X["$$\mathbf{X}$$(输入,换乘站)"] -->|"$$\times\mathbf{W}_{Q}$$"| Q["$$\mathbf{Q}$$"]
X -->|"$$\times\mathbf{W}_{K}$$"| K["$$\mathbf{K}$$"]
X -->|"$$\times\mathbf{W}_{V}$$"| V["$$\mathbf{V}$$"]
Q -->|"$$\mathbf{Q}\mathbf{K}^{\top} / \sqrt{d_k}$$"| S["$$\mathbf{S}$$"]
K -->|"$$\mathbf{Q}\mathbf{K}^{\top} / \sqrt{d_k}$$"| S
S -->|"$$\mathrm{softmax}$$(逐行)"| A["$$\mathbf{A}$$"]
A -->|"$$\mathbf{A}\mathbf{V}$$"| O["$$\mathbf{O}$$"]
V -->|"$$\mathbf{A}\mathbf{V}$$"| O
O --> NEXT["后续层 → 损失"]
NEXT -.->|"$$\mathbf{G} = \dfrac{\partial L}{\partial \mathbf{O}}$$"| O
O -.->|"$$\dfrac{\partial L}{\partial \mathbf{V}} = \mathbf{A}^{\top}\mathbf{G}$$"| V
O -.->|"$$\dfrac{\partial L}{\partial \mathbf{A}} = \mathbf{G}\mathbf{V}^{\top}$$"| A
A -.->|"softmax 反向"| S
S -.->|"$$\dfrac{\partial L}{\partial \mathbf{Q}} = \dfrac{\partial L}{\partial \mathbf{S}}\mathbf{K} / \sqrt{d_k}$$"| Q
S -.->|"$$\dfrac{\partial L}{\partial \mathbf{K}} = \left(\dfrac{\partial L}{\partial \mathbf{S}}\right)^{\top}\mathbf{Q} / \sqrt{d_k}$$"| K
Q -.->|"$$\dfrac{\partial L}{\partial \mathbf{W}_{Q}} = \mathbf{X}^{\top}\dfrac{\partial L}{\partial \mathbf{Q}}$$"| WQ["$$\mathbf{W}_{Q}$$(终点站)"]
K -.->|"$$\dfrac{\partial L}{\partial \mathbf{W}_{K}} = \mathbf{X}^{\top}\dfrac{\partial L}{\partial \mathbf{K}}$$"| WK["$$\mathbf{W}_{K}$$(终点站)"]
V -.->|"$$\dfrac{\partial L}{\partial \mathbf{W}_{V}} = \mathbf{X}^{\top}\dfrac{\partial L}{\partial \mathbf{V}}$$"| WV["$$\mathbf{W}_{V}$$(终点站)"]
Q -.->|"$$\dfrac{\partial L}{\partial \mathbf{Q}}\mathbf{W}_{Q}^{\top}$$"| X
K -.->|"$$\dfrac{\partial L}{\partial \mathbf{K}}\mathbf{W}_{K}^{\top}$$"| X
V -.->|"$$\dfrac{\partial L}{\partial \mathbf{V}}\mathbf{W}_{V}^{\top}$$"| X
classDef terminal fill:#ffe6cc,stroke:#d79b00,color:#333;
classDef conduit fill:#dae8fc,stroke:#6c8ebf,color:#333;
class WQ,WK,WV terminal;
class X,Q,K,V,S,A,O conduit;上图中,实线是前向传播的数据流,虚线是反向传播的梯度流:
①
②
③
④ 三个线性层(终点站)。 套用全连接层的结论:
⑤ 分支汇合(换乘站)。
按「终点站与换乘站」的观点看:
小结
深度学习中的矩阵求导,主要是利用导数的链式法则,让输出(损失)对深度神经网络中的参数矩阵进行求导。在求导过程中,主要涉及两种情况:一是直接对参数矩阵求导(得到形如
把全文的积木总结成一张速查表:
| 运算 | 梯度(分母布局) | 关键词 |
|---|---|---|
| 一次齐次式 | ||
| 二次型 | ||
| 对角 Jacobian | ||
| 外积 | ||
| 卷积 | 梯度仍是卷积 | 权重共享、梯度累加 |
| 矩阵乘法 | ||
| 非逐元素 |
延伸阅读
- The Matrix Calculus You Need For Deep Learning,Terence Parr 与 Jeremy Howard 著,从 Chain Rules 的两种布局讲起,与本文互为补充。
- Ian Goodfellow、Yoshua Bengio 与 Aaron Courville 的《Deep Learning》第 6 章,介绍反向传播在深度学习框架中的工程实现。
本文根据合集·深度学习中的数学 by 齐宪标系列视频整理,由 AI 辅助补全与勘误。如有疏漏,欢迎指正。