矩阵行列式求导和矩阵的逆的求导,这两个公式我每隔一段时间就要重新推一遍。不是公式本身有多难,而是记号约定、是否套 trace、转置放在哪里,稍微混一点就会出大错。网上搜索能捡到一片 $d\det(A)=\det(A)\operatorname{tr}(A^{-1}dA)$ 和 $d(A^{-1})=-A^{-1}(dA)A^{-1}$,但真到用的时候——比如多元正态分布的协方差矩阵求极大似然、非线性最小二乘的灵敏度分析——很多人依然会栽在细节上。这篇笔记算是我自己的完整推导记录,也希望能帮你少走两次弯路。适用人群:学多元统计、做机器学习推导、写数值优化代码,以及任何需要手工处理矩阵微分的同学。
1. 为什么要单独写行列式求导和逆矩阵求导这篇笔记
1.1 这两个公式出现在哪里
先别急着背公式,先看看它们到底在哪些地方反复出现。我自己接触最多的场景就是多元统计和机器学习:多元正态分布的密度函数里有 $(\det\Sigma)^{-1/2}$ 和 $(x-\mu)^T\Sigma^{-1}(x-\mu)$,要做极大似然估计,就绕不开对 $\log\det\Sigma$ 和对 $\Sigma^{-1}$ 求导。
另一个高频场景是数值优化。很多迭代算法需要对目标函数里的参数求梯度,只要参数是以矩阵形式进入目标函数,比如协方差矩阵、精度矩阵、状态转移矩阵,最后都会落到行列式和逆矩阵的导数上。控制理论里对可观测性/可控性格拉姆矩阵做灵敏度分析,连续介质力学里对变形梯度 $\mathbf{F}$ 的行列式 $J=\det\mathbf{F}$ 求时间导数,也都是同一套公式。
这些场景看起来跨度很大,但数学结构完全一样。我列一个简单的对照表:
| 场景 | 需要求导的对象 | 常见目的 |
|---|---|---|
| 多元正态极大似然 | $\log\det\Sigma$、$\Sigma^{-1}$ | 估计协方差矩阵 |
| 非线性最小二乘 | $J(\theta)=\det(A(\theta))$ | 参数灵敏度 |
| 变分推断/信息几何 | $\log\det$ 的二阶方向导数 | 自然梯度、Fisher信息 |
| 连续介质力学 | $\frac{d}{dt}\det\mathbf{F}$ | 体积变化率 |
1.2 关于记号约定,先说清楚
矩阵求导最容易出事的不是求导本身,而是“你说的梯度和我说的是不是同一个”。这里我先做一个统一约定,后面所有推导都按这个来。
设 $f(A)$ 是矩阵 $A$ 的标量函数。我定义梯度矩阵 $G$ 的第 $(i,j)$ 个元素为
$$ G_{ij}=\frac{\partial f(A)}{\partial A_{ij}}. $$
这时,$f$ 的全微分可以写成
$$ df=\sum_{i,j}\frac{\partial f}{\partial A_{ij}}dA_{ij} =\sum_{i,j}G_{ij}dA_{ij} =\operatorname{tr}(G^T dA). $$
这是“分母布局”。有的教材和论文用的是分子布局,那个梯度矩阵相当于我这里 $G^T$,于是它们会写 $df=\operatorname{tr}(G dA)$。如果你同时参考好几本书,很可能会发现同一个公式在两个地方差一个转置。不要急,先确认对方用的哪种布局。
矩阵值函数的微分不套 trace。比如 $A^{-1}$ 的微分 $d(A^{-1})$ 是一个完整的 $n\times n$ 矩阵,不是标量,直接写矩阵等式就好。
2. 行列式导数的完整推导:从多线性到雅可比公式
2.1 从行列式的逐列微分切入
很多教材直接把雅可比公式拍出来,然后说“容易验证”。但对初学者来说,这个“容易”往往没那么容易。我习惯从行列式最本质的性质——多线性——出发推导。
设 $A$ 的列向量是 $a_1,\dots,a_n$,那么
$$ \det(A)=\det(a_1,\dots,a_n). $$
行列式作为每一列的函数是线性的。对 $A$ 做微小扰动,相当于把每一列都加一个微小量 $da_1,\dots,da_n$,于是
$$ \det(a_1+da_1,\dots,a_n+da_n) $$
展开后,一阶项就是“只有一列被扰动”的所有情形之和:
$$ d\det(A)=\sum_{j=1}^{n}\det(a_1,\dots,da_j,\dots,a_n). $$
现在处理其中第 $j$ 项。$\det(a_1,\dots,da_j,\dots,a_n)$ 沿着第 $j$ 列做拉普拉斯展开。设 $C_{ij}$ 是 $A$ 的第 $(i,j)$ 个代数余子式,那么这一项等于
$$ \sum_{i=1}^{n}C_{ij},dA_{ij}. $$
对所有 $j$ 求和,得到
$$ d\det(A)=\sum_{i,j}C_{ij},dA_{ij}. $$
这个式子已经很有用了,但它是一个双重求和。用矩阵迹来整理会更漂亮。设 $C=(C_{ij})$ 是代数余子式矩阵,则
$$ \sum_{i,j}C_{ij}dA_{ij}=\operatorname{tr}(C^T dA). $$
而伴随矩阵 $ \mathrm{adj}(A) $ 的定义就是代数余子式矩阵的转置,即
$$ \operatorname{adj}(A)=C^T. $$
因此行列式的微分可以写成
$$ d\det(A)=\operatorname{tr}\big(\operatorname{adj}(A),dA\big). $$
这个公式不要求 $A$ 可逆,只要 $A$ 是方阵就成立。这一点很重要,因为有些场合行列式求导发生在奇异矩阵附近。
2.2 可逆矩阵版本:雅可比公式
如果 $A$ 可逆,伴随矩阵可以写成
$$ \operatorname{adj}(A)=\det(A)A^{-1}. $$
代入上面的公式,立刻得到
$$ d\det(A)=\det(A)\operatorname{tr}(A^{-1}dA). $$
这就是 Jacobi 公式。如果 $A$ 是单参数矩阵值函数 $A(t)$,那么两边同时除以 $dt$,得到
$$ \frac{d}{dt}\det(A(t))=\det(A(t))\operatorname{tr}\left(A(t)^{-1}\frac{dA(t)}{dt}\right). $$
注意这里 $\operatorname{tr}$ 千万不能丢。$\det(A)$ 是标量,$\det(A)A^{-1}$ 是矩阵,只有套上 trace 之后右边才是标量。很多推导写着写着就把 trace 弄丢了,最后梯度直接变成一个矩阵,维度全乱。
另外,trace 有循环性质:
$$ \operatorname{tr}(A^{-1}dA)=\operatorname{tr}(dA,A^{-1}). $$
这在链式法则或整理梯度时非常方便。你可以把 $dA$ 在 trace 里挪到最右边,也可以挪到最左边,取决于后续想怎么读梯度。
2.3 偏导形式和 2×2 手算验证
从上面的推导还能直接读出逐元素偏导:
$$ \frac{\partial \det(A)}{\partial A_{ij}}=C_{ij}. $$
也就是说,行列式对某个元素的偏导就是那个位置的代数余子式。这句话好记,但要注意下标顺序。
拿 $2\times 2$ 矩阵手算一遍最有感觉。设
$$ A=\begin{bmatrix}a&b\ c&d\end{bmatrix}, $$
则
$$ \det(A)=ad-bc. $$
代数余子式为
$$ C_{11}=d,\quad C_{12}=-c,\quad C_{21}=-b,\quad C_{22}=a. $$
所以梯度矩阵
$$ G=\begin{bmatrix}d&-c\ -b&a\end{bmatrix}. $$
用 $df=\operatorname{tr}(G^T dA)$ 验证:
$$ G^T dA=\begin{bmatrix}d&-b\ -c&a\end{bmatrix} \begin{bmatrix}da&db\ dc&dd\end{bmatrix} $$
取 trace 得到
$$ d,da - b,dc - c,db + a,dd. $$
这正好是 $d(ad-bc)$ 的展开:
$$ d(ad-bc)=a,dd+d,da-b,dc-c,db. $$
完全一致。你也可以用 $\det(A)\operatorname{tr}(A^{-1}dA)$ 再算一遍,结果相同。这个手算过程我建议每个人都做一次,做完之后对“ trace 为什么出现在公式里”会有非常直观的理解。
再做一个退化检查。令 $A=tI_n$,则 $\det(A)=t^n$,直接求导是 $n t^{n-1}$。用雅可比公式:
$$ \frac{d}{dt}\det(tI_n)=t^n\operatorname{tr}\left((tI_n)^{-1}I_n\right)=t^n\operatorname{tr}(t^{-1}I_n)=t^n\cdot \frac{n}{t}=n t^{n-1}. $$
一致。
2.4 奇异矩阵附近怎么办
雅可比公式需要 $A^{-1}$,但如果 $A$ 恰好奇异,$A^{-1}$ 不存在。这时不要慌,回到伴随矩阵版本:
$$ d\det(A)=\operatorname{tr}\big(\operatorname{adj}(A)dA\big). $$
$\operatorname{adj}(A)$ 即使 $A$ 奇异也可能非零。比如 $A$ 的秩为 $n-1$ 时,伴随矩阵的秩为 $1$,仍然能提供有效的一阶信息。我在做某些连续介质力学推导时就遇到过在奇异点附近求行列式导数的情况,如果死记 $A^{-1}$ 版本就会直接卡住。
3. 逆矩阵导数的推导与组合用法
3.1 从恒等式出发的推导
矩阵逆的导数推导比行列式简单,重点在理解结构。最基本的出发点是恒等式:
$$ A A^{-1}=I. $$
两边同时取微分。注意矩阵乘法不交换,所以用乘积法则时必须保持顺序:
$$ (dA)A^{-1}+A,d(A^{-1})=0. $$
目标是解出 $d(A^{-1})$,所以在上式两边左乘 $A^{-1}$:
$$ d(A^{-1})=-A^{-1}(dA)A^{-1}. $$
整个过程不到三行,但结果非常关键。$dA$ 必须夹在两个 $A^{-1}$ 中间,不能和任何一个交换位置。
如果只看第 $(i,j)$ 个元素,可以写成
$$ d\left(A^{-1}\right){ij}=-\sum{p,q}\left(A^{-1}\right){ip}(dA){pq}\left(A^{-1}\right)_{qj}. $$
这个分量形式在推导某些带指标的计算时很有用。
单参数情形同样常见:
$$ \frac{d}{dt}A(t)^{-1}=-A(t)^{-1}\frac{dA(t)}{dt}A(t)^{-1}. $$
3.2 为什么 dA 在中间,而不是在两边
初学者最容易问的问题是:标量函数 $(1/x)'=-1/x^2$,矩阵版本为什么不是 $-A^{-2}dA$ 或者 $-dA,A^{-2}$?
原因是矩阵乘法不交换。$(A^{-1})^2$ 这类写法有歧义,必须先说明到底是谁乘以谁。从推导过程看,$A^{-1}$ 同时出现在 $I=AA^{-1}$ 等式的两端,微分后一个因子来自左边的 $A^{-1}$,一个因子来自右边的 $A^{-1}$,所以天然形成三明治结构:
$$ d(A^{-1})=-A^{-1},(dA),A^{-1}. $$
如果你能从 $AA^{-1}=I$ 重新推出这个公式,就不会记反。我在下面列几个常见错误版本,大家可以对照:
| 错误写法 | 问题 |
|---|---|
| $-A^{-1}A^{-1}dA$ | 顺序不对,矩阵不可交换时结果不同 |
| $-dA,A^{-1}A^{-1}$ | 同样顺序不对 |
| $-A^{-2}dA$ | 记号有歧义,且丢失了右侧因子 |
| $-A^{-1}A' A^{-1}$ 写成 $-A'A^{-2}$ | 单参数情形也不能随意合并 |
3.3 和行列式公式组合使用的例子
行列式导数和逆矩阵导数很少孤立出现,更多时候是组合在一起用。举三个我常用的例子。
第一个例子:对二次型求导。设 $f(A)=u^T A^{-1}v$,其中 $u,v$ 是常向量。由逆矩阵导数公式:
$$ df=-u^T A^{-1}(dA)A^{-1}v. $$
右边是标量。利用“标量等于自身的迹”这个技巧:
$$ -u^T A^{-1}(dA)A^{-1}v=-\operatorname{tr}\left(A^{-1}v u^T A^{-1}dA\right). $$
于是按照前面约定的布局,梯度就是
$$ \nabla_A f=-A^{-1}vu^T A^{-1}. $$
这个结果在多元正态分布的二次型求导里几乎天天用。
第二个例子:对 $\det(A^{-1})$ 求导。直接利用行列式乘法性质,$\det(A^{-1})=1/\det(A)$。对它求导:
$$ d\det(A^{-1})=-\frac{1}{\det(A)^2}d\det(A)=-\det(A)^{-1}\operatorname{tr}(A^{-1}dA). $$
从另一个角度验证:把 $A^{-1}$ 整体看成新的矩阵 $B$,用行列式导数公式:
$$ d\det(B)=\det(B)\operatorname{tr}(B^{-1}dB). $$
这里 $B=A^{-1}$,$B^{-1}=A$,$dB=d(A^{-1})$,于是
$$ d\det(A^{-1})=\det(A^{-1})\operatorname{tr}\left(A,d(A^{-1})\right). $$
代入逆矩阵导数公式:
$$ \operatorname{tr}\left(A,\big(-A^{-1}dA A^{-1}\big)\right)=-\operatorname{tr}(dA,A^{-1})=-\operatorname{tr}(A^{-1}dA). $$
再乘以 $\det(A^{-1})=\det(A)^{-1}$,得到同样结果。两条路都能走通,说明公式之间是自洽的。
第三个例子:$\log\det A$ 的导数。当 $\det A>0$ 时:
$$ d\log\det A=\frac{d\det A}{\det A}=\operatorname{tr}(A^{-1}dA). $$
这个公式在极大似然估计和凸优化里出场率极高。它的二阶方向导数也很有意思。给定方向矩阵 $V$,定义
$$ g(t)=\log\det(A+tV), $$
则
$$ g'(t)=\operatorname{tr}\left((A+tV)^{-1}V\right). $$
再用一次逆矩阵导数公式:
$$ g''(0)=\operatorname{tr}\left(-A^{-1}V A^{-1}V\right)=-\operatorname{tr}(A^{-1}V A^{-1}V). $$
注意这里 trace 内部的矩阵顺序是 $A^{-1},V,A^{-1},V$,不能合并成 $A^{-2}V^2$。这个二阶结构在自然梯度、Fisher信息矩阵、流形优化中会反复出现。
4. 标准场景演示:多元正态极大似然中两个公式的联合使用
4.1 问题设定与目标函数
前面讲了不少公式,现在放到一个完整场景里看它们怎么配合。考虑 $N$ 个 $p$ 维样本 $x_1,\dots,x_N$ 独立同分布于 $N(\mu,\Sigma)$,其中 $\Sigma$ 是正定对称矩阵。写出负对数似然:
$$ L=\frac{N}{2}\log\det(2\pi\Sigma)+\frac12\sum_{i=1}^{N}(x_i-\mu)^T\Sigma^{-1}(x_i-\mu). $$
常数项可以先拆开:$\det(2\pi\Sigma)=(2\pi)^p\det\Sigma$,第一项变成
$$ \frac{N}{2}\left(p\log(2\pi)+\log\det\Sigma\right). $$
所以真正需要求导的部分只有 $\log\det\Sigma$ 和 $\Sigma^{-1}$ 组成的二次型。
4.2 对 $\Sigma$ 的微分过程
先处理第一项。由上一节,
$$ d\left(\frac{N}{2}\log\det\Sigma\right) =\frac{N}{2}\operatorname{tr}(\Sigma^{-1}d\Sigma). $$
再处理二次型。记 $q_i=x_i-\mu$,则
$$ d\left(q_i^T\Sigma^{-1}q_i\right) =q_i^T,d(\Sigma^{-1}),q_i =-q_i^T\Sigma^{-1}d\Sigma,\Sigma^{-1}q_i. $$
这里用到了逆矩阵导数公式,$d\Sigma$ 仍然夹在两个 $\Sigma^{-1}$ 中间。接下来把右边标量写成迹:
$$ -q_i^T\Sigma^{-1}d\Sigma,\Sigma^{-1}q_i =-\operatorname{tr}\left(\Sigma^{-1}q_iq_i^T\Sigma^{-1}d\Sigma\right). $$
对所有样本求和,令
$$ S=\sum_{i=1}^{N}q_iq_i^T, $$
则二次型部分的微分为
$$ -\frac12\operatorname{tr}\left(\Sigma^{-1}S\Sigma^{-1}d\Sigma\right). $$
合并两项:
$$ dL=\operatorname{tr}\left[\left(\frac{N}{2}\Sigma^{-1}-\frac12\Sigma^{-1}S\Sigma^{-1}\right)d\Sigma\right]. $$
4.3 对称约束是隐形的坑
这里有一个非常容易忽略的细节。$\Sigma$ 是对称矩阵,所以 $d\Sigma$ 不能取任意的 $p\times p$ 矩阵,它必须是对称矩阵。也就是说,虽然括号里的矩阵
$$ G_0=\frac{N}{2}\Sigma^{-1}-\frac12\Sigma^{-1}S\Sigma^{-1} $$
看起来是“梯度”,但它只在 $d\Sigma$ 的对称方向上才有意义。
更严谨的做法是投影。因为 $\operatorname{tr}(G_0 d\Sigma)$ 只依赖于 $G_0$ 的对称部分,所以有效梯度是
$$ G=\frac{G_0+G_0^T}{2}. $$
幸运的是,这里 $S$ 本身是对称的,$\Sigma^{-1}$ 也是对称的,所以 $\Sigma^{-1}S\Sigma^{-1}$ 依然对称,$G_0$ 已经是对称矩阵,不需要额外投影。但如果换一个非对称的中间矩阵,或者约束是低三角矩阵、稀疏矩阵,投影步骤就不能省。
令梯度为零,得到得分方程:
$$ \frac{N}{2}\Sigma^{-1}-\frac12\Sigma^{-1}S\Sigma^{-1}=0. $$
左乘 $\Sigma$、右乘 $\Sigma$,得到 $N\Sigma=S$,于是
$$ \hat\Sigma=\frac{1}{N}S. $$
这就是样本协方差矩阵。整个过程里,$\log\det$ 的导数负责第一项,逆矩阵的导数负责第二项,trace 的循环把二次型求和整理成矩阵形式,三个工具缺一不可。
4.4 从得分方程到迭代更新的延伸
并不是所有协方差结构问题都能解析求解。比如假设 $\Sigma$ 带有参数结构 $\Sigma(\theta)$,那就需要用梯度下降或自然梯度做数值迭代。这时你写出的迭代式往往长这样:
$$ \theta\leftarrow \theta-\eta ,G(\theta). $$
如果 $G$ 不对称,更新后的 $\Sigma(\theta)$ 很容易偏离对称正定矩阵。所以我在实际写代码时一定会检查 $G^T=G$,并在每一轮迭代里对 $G$ 做对称化处理。
还有一个更漂亮的联系:如果使用自然梯度,度量张量来自 $\log\det\Sigma$ 的二阶方向导数,也就是
$$ -\operatorname{tr}(\Sigma^{-1}d\Sigma,\Sigma^{-1}d\Sigma). $$
这正好是前面推导的二阶导数结构。行列式导数、逆矩阵导数、Fisher信息这几个概念在这里形成了闭环,这也是我为什么坚持要亲手推一遍而不是直接背公式的原因。
5. 最容易出错的细节、三条验证法则和踩坑记录
5.1 踩坑实录:我犯过的四类错误
第一个坑是布局混淆。有一段时间我习惯把 $\frac{\partial\det A}{\partial A}$ 直接写成 $\operatorname{adj}(A)$,因为 $2\times2$ 例子里代数余子式矩阵和伴随矩阵长得非常像。但严格来说,$\partial\det A/\partial A_{ij}=C_{ij}$,梯度矩阵是 $C$,不是 $C^T$。写成 $df=\operatorname{tr}(G^T dA)$ 时,这里的 $G$ 才是 $C$,而 $d\det A=\operatorname{tr}(\operatorname{adj}(A)dA)$。稍微对不上就看错。
第二个坑是丢 trace。行列式导数是标量,但推导中间会出现矩阵乘积。如果最后写成 $d\det A=\det(A)A^{-1}dA$ 这种形式,右边是个矩阵,维度对不上。正确写法必须套 trace:
$$ d\det A=\det(A)\operatorname{tr}(A^{-1}dA). $$
我后来每次都先检查“等式右边是不是标量”,能过滤掉大部分这类错误。
第三个坑是逆矩阵导数里 $dA$ 的位置。错误的写法有很多种,比如 $-dA,A^{-1}A^{-1}$,或者 $-A^{-1}A^{-1}dA$。正确写法是
$$ d(A^{-1})=-A^{-1}(dA)A^{-1}. $$
我自己的记忆方法是“从 $AA^{-1}=I$ 出发推导”,而不是硬背公式。只要推一遍,位置就永远错不了。
第四个坑是奇异矩阵还硬用 $A^{-1}$ 公式。求行列式导数时,如果 $A$ 不可逆,必须回到伴随矩阵版本。很多数值问题会在奇异点附近计算灵敏度,这时候 $A^{-1}$ 版本直接报错。
5.2 三条验证法则
我现在每次写完一个矩阵求导公式,都会用下面三条法则快速检查。
维度法则:先看等式两边维度是否一致。$d\det A$ 是标量,右边全乘起来也必须是标量,所以 trace 不能丢;$d(A^{-1})$ 是 $n\times n$ 矩阵,右边三个矩阵相乘也是 $n\times n$。检查维度能暴露一半以上的低级错误。
退化法则:把矩阵取成对角阵或者 $A=tI$,看公式能不能退化成普通的标量导数。比如 $A=\operatorname{diag}(\lambda_1,\dots,\lambda_n)$ 时,
$$ d\det A=\det(A)\sum_i\frac{d\lambda_i}{\lambda_i}, $$
而 $d(A^{-1})=\operatorname{diag}\left(-d\lambda_i/\lambda_i^2\right)$,和直接对每个 $\lambda_i$ 求导完全一致。这个检验成本极低,值得每次都做。
数值差分法则:如果还不放心,直接上数值差分。取一个 $3\times3$ 可逆矩阵 $A$,对某个元素 $A_{ij}$ 加一个小扰动 $h$,用中心差分
$$ \frac{f(A+hE_{ij})-f(A-hE_{ij})}{2h} $$
和解析公式对比。$h$ 取 $10^{-6}$ 左右,一般能精确到小数点后好几位。这套方法能验证任何矩阵求导公式,不只是行列式和逆矩阵。
5.3 用符号计算快速验证公式
除了数值差分,还可以用符号计算做精确验证。以 SymPy 为例,验证 $2\times2$ 行列式对每个元素的偏导:
import sympy as sp a, b, c, d = sp.symbols("a b c d", real=True) A = sp.Matrix([[a, b], [c, d]]) detA = A.det() # 行列式对每个元素的偏导 grad = sp.Matrix([[sp.diff(detA, a), sp.diff(detA, b)], [sp.diff(detA, c), sp.diff(detA, d)]]) print(grad)输出结果就是
$$ \begin{bmatrix}d&-c\ -b&a\end{bmatrix}. $$
你可以用同样的方式验证逆矩阵的导数:先构造符号矩阵,再计算 $A^{-1}$,对某个参数求导后和 $-A^{-1}(\partial A/\partial t)A^{-1}$ 对比。符号计算的价值在于它能精确验证你的手推过程,尤其是当矩阵规模变大、符号变多之后,人工检查容易漏项。
最后分享一个我的工作习惯:遇到矩阵求导,第一步永远先写微分式,不要急着写元素偏导;第二步用 trace 循环把 $dA$ 挪到最右边;第三步做维度检查和退化检查。习惯之后,行列式求导和逆矩阵求导就是两个能直接落笔的公式,而不是两个背了又忘的公式。如果哪次又拿不准,就老老实实从 $\det$ 的多线性或者 $AA^{-1}=I$ 重新推一遍。推导五分钟,排错两小时,这笔账怎么算都值。