☰
二次型梯度推导全解:从三种方法到数值验证
2026/10/2 10:08:51 网站建设 项目流程

二次型 x^TAx 的梯度推导,几乎是我见过的机器学习入门者翻车率最高的一块内容。矩阵的写法看起来特别简洁,一个表达式 x^TAx 就结束了,但真让你对 x 求导的时候,很多人的第一反应是去翻矩阵求导公式表,翻到了又不知道该用哪一条,对着 (A + A^T)x 和 2Ax 这两个结果陷入沉思——到底哪个是对的?还有一批人干脆把矩阵求导当成普通标量求导来做,习惯性写出 2Ax 就收工,完全没注意到 A 不一定对称这件事。

这篇文章我就把这件“小事”彻底掰开揉碎,从偏导的原始定义一路推到位,给出三种不同的推导方法,再配合数值实验验证和常见错误盘点。写完了你就会发现,二次型梯度真的不值得害怕,搞懂一次之后,往后遇到各种矩阵求导都能顺藤摸瓜。

1. 先搞清楚我们到底在求什么

1.1 二次型的长相和适用场景

所谓二次型,指的就是 f(x) = x^TAx 这种形式的标量函数,其中 x 是 n 维列向量,A 是 n×n 的实矩阵,函数值本身是一个实数。

这类表达式在机器学习里出现频率高得吓人。最小二乘法的损失函数 ||y - Xw||² 展开之后就是二次型,岭回归加的正则项 λw^Tw 也是二次型(等价于 A 为单位阵的二次型),高斯分布的概率密度函数里指数部分同样包含二次型 (x-μ)^TΣ^{-1}(x-μ),更不用说 PCA、LDA、逻辑回归的牛顿法迭代里,Hessian 矩阵相关的运算处处都是二次型的影子。

既然二次型无处不在,求它关于 x 的梯度自然就成了绕不开的基本功。所谓梯度,就是 ∂f/∂x 这个向量,它的第 k 个分量是 ∂f/∂x_k。

1.2 这里有一个最容易被忽略的关键点

写 x^TAx 的时候,A 可能对称,也可能不对称,而绝大多数教材里为了推导方便都直接假设 A 对称。这个假设不是没有代价的——它会把公式的形状从 (A + A^T)x 简化成 2Ax,导致很多人只记住了后者,却忘了它成立的前提。

我的建议是,第一遍学的时候,不要先假设对称,直接对一般的 A 做推导。先把 (A + A^T)x 这个最一般的形式推出来,然后再看对称条件下它如何退化。这样你在脑子里留下的是一棵完整的知识树,而不是一堆孤立的内存碎片。

2. 第一遍推:用分量展开打底,理解最原始的偏导过程

这个方法不花哨,但最朴素可信。它完全绕开矩阵求导的任何规则,只用多元微积分里偏导数的定义。

2.1 把二次型彻底展开成求和形式

设 x = (x₁, x₂, ..., xₙ)^T,A = (a_ij)。那么:

f(x) = x^TAx = Σᵢ Σⱼ x_i a_ij x_j

这里的下标 i 是行索引,j 是列索引。展开之后每一项是 a_ij x_i x_j,扫过所有 (i,j) 组合。

举个例子,n=2 的时候展开是这样:

f(x) = a₁₁x₁² + a₁₂x₁x₂ + a₂₁x₂x₁ + a₂₂x₂²

注意 a₁₂x₁x₂ 和 a₂₁x₂x₁ 不是合并同类项的关系,它们对应的矩阵位置不同、系数不同,虽然 x₁x₂ 和 x₂x₁ 在数值上相等,但系数分别来自矩阵的不同位置,所以必须分开写。这是分量展开和平时处理对称二次型最大的一个感受差异。

2.2 对第 k 个分量求偏导

现在固定 k,我们对 x_k 求偏导。关键在于:求和号里面哪些项包含 x_k ?

逐项翻一遍,包含 x_k 的项只可能出现在两种情况下:

  • i = k 的时候,x_i 就是 x_k,所以所有 a_kj x_k x_j 这些项都跟 x_k 有关,j 从 1 到 n 遍历。
  • j = k 的时候,x_j 就是 x_k,所以所有 a_ik x_i x_k 这些项也都跟 x_k 有关,i 从 1 到 n 遍历。

其余 i ≠ k 且 j ≠ k 的项完全不包含 x_k,求偏导时直接归零。

所以:

∂f/∂x_k = ∂/∂x_k [ Σⱼ a_kj x_k x_j + Σᵢ a_ik x_i x_k ]

接下来要小心一点。第一项里,x_k 和 x_j 都可能是同一个变量(当 j=k 时),但我们按乘积的求导法则老老实实处理,不需要额外分类讨论,法则会自动覆盖这些情况:

∂/∂x_k (a_kj x_k x_j) = a_kj x_j + a_kj x_k δ_kj

其中 δ_kj 是克罗内克符号(当 k=j 时为1,否则为0)。

但为了更直观一点,另一种做法是直接在求和层面做。我们把偏导符号放进求和号里:

∂f/∂x_k = Σⱼ a_kj (∂(x_k x_j)/∂x_k) + Σᵢ a_ik (∂(x_i x_k)/∂x_k)

对第一项里的乘积 x_k x_j 求导,如果 j ≠ k,只有 x_k 在变化,导数为 x_j;如果 j = k,x_k x_j 变成 x_k²,导数为 2x_k。用式子统一表示就是:

∂(x_k x_j)/∂x_k = x_j + x_k δ_kj

同理:

∂(x_i x_k)/∂x_k = x_i + x_k δ_ik

但等一下,如果我们把这两项合在一起看,其实有个更简洁的操作——不拆分 δ,直接用链式法则:

Σⱼ a_kj x_j + Σᵢ a_ik x_i

等等,我需要验证这个结果是否精确成立。让我们再推导一次,中间不丢项。

回到:

∂f/∂x_k = Σⱼ a_kj ∂(x_k x_j)/∂x_k + Σᵢ a_ik ∂(x_i x_k)/∂x_k

= Σⱼ a_kj (x_j + x_k δ_kj) + Σᵢ a_ik (x_i + x_k δ_ik)

= Σⱼ a_kj x_j + x_k Σⱼ a_kj δ_kj + Σᵢ a_ik x_i + x_k Σᵢ a_ik δ_ik

= Σⱼ a_kj x_j + a_kk x_k + Σᵢ a_ik x_i + a_kk x_k

= Σⱼ a_kj x_j + Σᵢ a_ik x_i + 2a_kk x_k

嗯,这里出现了额外的 2a_kk x_k。这和前面说的 (A x)_k + (A^T x)_k 是不是一致呢?

(Ax)_k = Σⱼ a_kj x_j

(A^T x)_k = Σᵢ (A^T)_ki x_i = Σᵢ a_ik x_i

所以 (Ax)_k + (A^T x)_k = Σⱼ a_kj x_j + Σᵢ a_ik x_i

问题来了,我上面推导得到的是 Σⱼ a_kj x_j + Σᵢ a_ik x_i + 2a_kk x_k,但这里没有两个 a_kk x_k 啊——等等,让我重新审视一下。对于 k=j 的那个特例,当我写 a_kj x_j 时,它已经包含了 a_kk x_k;对于 i=k 的那个特例,a_ik x_i 已经包含了 a_kk x_k。所以总和 Σⱼ a_kj x_j + Σᵢ a_ik x_i 在 k 处的问题中已经包含了两次 a_kk x_k——最后两项中的 x_i 和 x_j 实际上就是同一个分量。

让我重新更仔细地检查一下:

f(x) = Σ_{i=1}^n Σ_{j=1}^n a_ij x_i x_j

只看包含 x_k 的项。i=k 时:Σ_j a_kj x_k x_j;j=k 时:Σ_i a_ik x_i x_k。合起来是:

含 x_k 的部分 = Σ_j a_kj x_k x_j + Σ_i a_ik x_i x_k

注意,这里 (i=k, j=k) 这一项被算了两次:一次是 a_kk x_k x_k 在第一个求和中(i=k, j=k),另一次是 a_kk x_k x_k 在第二个求和中(j=k, i=k)。但这两个实际上是同一项!因为它们都代表 a_kk x_k²。

所以在展示数学关系时,拆分“包含 x_k 的项”会重复计算 a_kk x_k²。解决这个问题的标准方法是:只需直接利用微分,或者推导更干净。或者灵活利用对称指标。让我使用更干净的方法:

f = Σ_i Σ_j a_ij x_i x_j

∂f/∂x_k = Σ_i Σ_j a_ij (δ_ik x_j + x_i δ_jk)

其中 δ_ik 表示 i=k,δ_jk 表示 j=k。

= Σ_j a_kj x_j + Σ_i a_ik x_i

啊,这样一步就正确多了!根本不需要只提取 x_k 的项,可以直接用线性导数的分配性质。

所以 ∂f/∂x_k = Σ_j a_kj x_j + Σ_i a_ik x_i = (Ax)_k + (A^T x)_k

这就给出了梯度 ∇f = (A + A^T)x。

现在让我修正文本。在推导之前我从求和开始,必须使用指示函数/δ符号方法,这可以避免重复计数,并有效解释与“提取相关项但核算两次”之间的差异。

写正文时我将以此为准:

f(x) = Σ_i Σ_j a_ij x_i x_j

对 x_k 求偏导:

∂f/∂x_k = Σ_i Σ_j a_ij (∂(x_i x_j)/∂x_k) = Σ_i Σ_j a_ij (δ_ik x_j + x_i δ_jk)

= Σ_j a_kj x_j + Σ_i a_ik x_i = (Ax)_k + (A^T x)_k

这个干净。但要注意,不要落入把含 x_k 的项进行分离并计数两次的陷阱。我会指出这与可能出现的不仔细展开不同。

2.3 区分两个求和项

上面第一项 Σ_j a_kj x_j,它是矩阵 A 第 k 行和 x 做内积,正是 (Ax) 的第 k 个分量;第二项 Σ_i a_ik x_i,它是 A 第 k 列和 x 做内积,也正是 (A^T x) 的第 k 个分量。

所以完整梯度是:

∇f(x) = Ax + A^T x = (A + A^T)x

到这里,第一遍推导完成。整个过程只有一个关键操作:对乘积 x_i x_j 求偏导然后用克罗内克 δ 做筛选。熟练之后这个过程非常机械,不容易错。

3. 第二遍推:用矩阵微分,简单到有点怀疑人生

分量展开虽然直观,但遇到更复杂的矩阵表达式时展开会变得越来越繁琐。这时候就应该切换到矩阵微分的语言。这一部分的核心思想是:先算 df,再把 df 改写成某个向量与 dx 的内积。

3.1 微分的两个基本规则

矩阵微分有两条规则特别常用:

  • 乘积法则:d(XY) = (dX)Y + X(dY),对矩阵和向量都成立。
  • 转置和微分可交换:d(X^T) = (dX)^T。

另外还有一个很重要的约定:对于一个标量函数 f(x),它的微分可以写成 df = ∇f^T dx,这里的 ∇f 就是我们要求的梯度向量。

3.2 直接对 x^TAx 取微分

令 f = x^TAx,则:

df = d(x^T)Ax + x^T d(Ax)

第一项 d(x^T) = (dx)^T,第二项 d(Ax) = A dx(A 是常矩阵,不参与微分)。所以:

df = (dx)^T A x + x^T A dx

现在看第一项 (dx)^T A x。它是一个标量,标量的转置等于自己,所以:

(dx)^T A x = ((dx)^T A x)^T = x^T A^T dx

这里要把转置的运算顺序捋清楚:(dx)^T A x 是一个 1×1 的矩阵,也就是一个数,它的转置就是本身,而转置之后括号里的次序会反过来:(dx)^T A x 的转置是 x^T A^T dx。这样两个项现在都写成了 x^T 某某 dx 的形式:

df = x^T A^T dx + x^T A dx = x^T (A^T + A) dx

等等,更正确的是写成 x^T(A^T + A)dx。另外注意,x^T(A^T + A)dx 也是一个标量,所以可以随意重新排列(实际上顺序已经自然了)。

根据 df = ∇f^T dx,我们比较两个式子:

∇f^T dx = x^T(A^T + A)dx

由于 dx 是任意方向,我们可以得出结论:

∇f = (A + A^T) x

这样整个推导只有四五行。实际上这里需要一点严格的推理:选择 dx = e_i(第 i 个单位向量),就可以从 ∇f^T dx = x^T(A^T + A)dx 对所有的 dx 成立中推出行的等价性,但习惯上我们会直接识别出来。

3.3 为什么这个方法更值得推荐

分量展开适合第一次理解“梯度到底是什么”,但一旦理解了,日常推导我强烈建议用微分法。原因有两个。

第一,微分法不用记忆任何复杂的矩阵求导公式表,只需要知道 d(XY) 和标量转置这两个规则,很多看起来吓人的公式都可以在 30 秒内推出来。第二,微分法不容易出错,因为它把每一步的变形都限制在微分的框架里,不像查公式表那样容易代错参数。

我再补充一点经验之谈:用微分法的时候,有一个习惯非常重要——每次推完都把结果转换成“df = 某向量^T dx”的标准形式。这个习惯能帮你少踩很多坑,因为矩阵求导最混乱的地方就在于分子分母布局,到底是行向量还是列向量、要不要转置,全在这个环节出问题。而统一用 df = ∇f^T dx 的形式之后,你的梯度向量永远是列向量,不会有任何歧义。

4. 第三遍推:A 对称(或者被强行对称)

4.1 对称矩阵条件下的退化公式

在机器学习的绝大多数模型里,出现在二次型位置的矩阵要么天然对称,要么被刻意改造成对称形式。比如最小二乘的目标函数:

L(w) = ||y - Xw||² = (y - Xw)^T(y - Xw)

展开后二次项是 w^T(X^TX)w,这里的 X^TX 天然对称。又比如高斯分布的指数部分 (x-μ)^TΣ^{-1}(x-μ),协方差矩阵的逆 Σ^{-1} 也是对称的。所以当 A 对称时:

(A + A^T) = 2A

∇f = 2Ax

这就是大家最熟悉的 2Ax 的由来。但你要时刻记得,它成立的前提是 A 对称。如果 A 不对称,梯度就是 (A + A^T)x,不是 2Ax——尽管有时候你硬写成 2Ax,在对称部分相同的情况下恰好碰对了,但中间的推理是有漏洞的。

4.2 如果一个矩阵不对称的二次型“看起来”该对称怎么办

实际工程里有一个非常常见的情况:你拿到一个表达式 x^TMx,其中 M 并不是对称矩阵,但这个二次型本身在数学上等于 x^T[(M+M^T)/2]x。因为对于标量,有:

x^TMx = (x^TMx)^T = x^TM^Tx

所以 x^TMx = x^T[(M + M^T)/2]x。也就是说,决定一个二次型数值的只有矩阵的对称部分 (M+M^T)/2,反对称部分对二次型值没有贡献。因此在求梯度的时候,如果方便,可以先把 M 替换成它的对称化版本,再用 2Ax 的公式。但用 (M+M^T)x 直接算结果也完全一样,两种方式殊途同归。

4.3 一个典型的“陷阱”:A 不对称时的 2Ax 幻觉

我见过不少同学在试卷或者代码里写出 ∇(x^TAx) = 2Ax,然后怎么验都不对。问题出在哪?本质上是把 A 默认为对称了。一个特别容易踩坑的例子是:

A = [[0, 1], [0, 0]]

x = (1, 2)^T

那么 x^TAx = x₁x₂ = 2。用 2Ax 算梯度 = 2 [0,1],[0,0] ^T = (4, 0)^T。但用数值差分检验一下,∂f/∂x₁ 应该等于 x₂ = 2,∂f/∂x₂ 应该等于 x₁ = 1。显然 (4, 0)^T 是完全错的。用正确公式 (A+A^T)x = [0,1],[1,0] ^T = (2,1)^T,和数值差分完全吻合。

这个例子我在文章和教学里反复用,因为它能瞬间击碎“二次型梯度就是 2Ax”的错误直观。

5. 数值验证:用有限差分把你的推导结果当场抓住

5.1 中心差分公式和验证步骤

即使推导过程看起来天衣无缝,我仍然强烈建议在上代码之前先做一次数值验证。因为公式推导可能犯错误,而数值差分是独立于符号推导的第二道安全网。中心差分公式如下:

∂f/∂x_k ≈ (f(x + h e_k) - f(x - h e_k)) / (2h)

其中 e_k 是第 k 个标准基向量,h 取一个很小的值,比如 10^{-7} 或者 10^{-6}。

验证的步骤非常简单:

  1. 随机生成一个 x 和 A(注意要不要对称自己定)。
  2. 用解析公式计算梯度向量。
  3. 用中心差分逐分量计算数值梯度。
  4. 对比结果,看最大绝对误差是否在 10^{-6} 量级以下。

5.2 一份可以直接跑的验证小代码

下面我给一份示例代码。用 Python 的 numpy 写,实现了一个非对称矩阵的验证,代码里注释写清楚了每一步在做的事情。

import numpy as np def f(x, A): return x @ A @ x def grad_analytic(x, A): return (A + A.T) @ x def grad_numeric(x, A, h=1e-6): n = len(x) g = np.zeros(n) for k in range(n): e = np.zeros(n) e[k] = 1.0 fp = f(x + h * e, A) fm = f(x - h * e, A) g[k] = (fp - fm) / (2 * h) return g # 随机生成一个非对称矩阵和向量 rng = np.random.default_rng(42) A = rng.standard_normal((4, 4)) x = rng.standard_normal(4) g_ana = grad_analytic(x, A) g_num = grad_numeric(x, A) print("解析梯度:", g_ana) print("数值梯度:", g_num) print("最大误差:", np.max(np.abs(g_ana - g_num)))

跑出来的结果通常最大误差在 1e-8 量级,这主要取决于浮点精度和 h 的选取。如果哪天你发现解析结果和数值结果对不上,不用犹豫,基本可以断定是解析推导那一侧出了问题。

5.3 我和有限差分较劲的一次实际经历

有一次我在实现一个带约束的优化算法,目标函数里有一个非线性项,化简完出现了一坨矩阵表达式,我怀疑其中某个子块的转置放错了位置。当时整个公式很长,肉眼扫了三遍都没看出问题。后来就是用中心差分锁定了错误:解析梯度在第 3 个分量上始终差一个符号。一查代码,果然是某个矩阵乘法里把 A 写成了 A^T。从那以后我养成了一个习惯,凡是写好一个优化目标的梯度,上优化器之前必跑一次有限差分验证。

这个习惯也推荐给大家。尤其是当你用自动微分框架(比如 PyTorch、JAX)的时候,并不是说自动微分就不会错,而是当你自己手写了一个自定义的梯度函数时,数值差分是检验它正确性的最可靠手段。

6. 那些年我们一起踩过的坑:常见错误一览

6.1 误区一:无条件使用 2Ax

正如前面强调的,2Ax 只有在 A 对称时才成立。对于一般矩阵,必须用 (A + A^T)x。这个错误出现的频率有多高?我几乎在每一届初学者身上都见过,包括早期写代码的我自己。

如何避免?建议在正式推导或代码实现之前,先问自己一句:这里矩阵 A 是否对称?如果不对称,就用通用公式。

6.2 误区二:混淆梯度的方向和布局

矩阵求导有两种布局约定:分子布局和分母布局。如果你用的资料里混用了这两种,结果经常差一个转置。我在实践中的习惯是:坚持把梯度定义为列向量,也就是符合“一个普通函数对列向量 x 求导,得到列向量”的直觉。用微分法写 df = ∇f^T dx,天然就是这个布局,不用特意记。

6.3 误区三:忽略矩阵和向量的维度匹配

对标量函数 x^TAx,x 必须是 n×1,A 必须是 n×n,结果才是标量。但如果写成 x A x^T,那 x 就是 1×n 的行向量,得到的结果又是一个不同的标量,梯度的形状会跟着变化。初学者很容易在转置符号上犯迷糊,进而搞错整个二次型的形状。

一个小技巧:每次写完一个表达式,先检查各个矩阵/向量的维度能不能乘起来,最终的函数值是不是 1×1。这个检查在草稿阶段就要做,别等代码报错才回头。

6.4 一个容易忽略的细节:A 本身可能还依赖于 x

如果 A 里的元素也含 x,那就不能简单套 (A+A^T)x 了。比如 f(x) = x^TA(x)x,这时候需要对 A(x) 也求导,会牵扯出更高阶的张量运算。本文所有推导都假设 A 是常数矩阵。实际建模中如果 A 是 x 的函数,请务必回到最基本的微分定义,不要机械套公式。

6.5 一个进阶提醒:链式法则里藏着的转置

在多层复合函数里,比如 f(g(x)),其中 g 把 x 映射成另一个向量,那么用链式法则时通常会遇到雅可比矩阵。这时候如果雅可比矩阵被写成行优先或者列优先,梯度方向很可能就反了。我的建议是每次遇到链式法则,都完整写出维度,再决定要不要转置,不要凭感觉。

7. 二次型梯度在几个经典模型里的实战应用

7.1 最小二乘线性回归

线性回归的目标函数是:

L(w) = ||y - Xw||² = y^Ty - 2w^TX^Ty + w^TX^TXw

只看最后一项,它是 w^T(X^TX)w 的形式,而 X^TX 是对称矩阵,因此:

∂(w^TX^TXw)/∂w = 2X^TXw

中间项的梯度是 -2X^Ty,常数项为 0。合起来:

∇L(w) = 2X^TXw - 2X^Ty

令梯度等于 0,就得到了正规方程 X^TXw = X^Ty。整个过程用二次型梯度做,不用展开任何求和符号,几行就写完了。

7.2 岭回归

岭回归在最小二乘的基础上加了一个 L2 正则项:

L(w) = ||y - Xw||² + λ||w||²

第二项可以写成 w^T(λI)w,这是 A = λI 的二次型。因为 I 对称,梯度为 2λw。加上前面的梯度,得到:

∇L(w) = 2(X^TX + λI)w - 2X^Ty

令梯度为 0,得到 (X^TX + λI)w = X^Ty。这就是岭回归的闭合解形式。

7.3 瑞利商和对称特征值问题

瑞利商 R(x) = (x^TAx)/(x^Tx) 是另一处二次型梯度频繁登场的地方,A 通常设对称。对它用商法则:

∇R = [2Ax(x^Tx) - 2x(x^TAx)] / (x^Tx)²

令梯度为 0,得到 Ax = (x^TAx)/(x^Tx) x,也就是特征方程 Ax = λx 的形式。这说明瑞利商的驻点就是特征向量。二次型梯度的推导在这里直接通向特征值问题的变分描述,是理论推导中一个非常经典的应用场景。

7.4 高斯分布的最大似然

多元高斯分布的对数似然里有这样一项:

-1/2 (x - μ)^T Σ^{-1} (x - μ)

它也是一个二次型,只不过变量是 (x - μ)。如果对 μ 求梯度,会涉及链式法则:

∂/∂μ [(x-μ)^TΣ^{-1}(x-μ)] = -2Σ^{-1}(x-μ)

这个结果在推导高斯分布的 MLE 或者变分推断时经常用到。别看它简单,如果布局搞错,符号就会反,后续整个推导都会跟着崩。

8. 我的经验与建议:怎么把二次型梯度内化成直觉

推了三种方法,写了那么多,最后我想分享几条个人体会。

第一,矩阵求导不是一个需要死记硬背的东西。你只需要记住几条规则:乘积法则、标量转置不变性,以及 df = ∇f^T dx 这个统一格式,几乎所有常见的向量/矩阵求导都可以现场推出来。这个方法我在工作中用了很多年,从未失效。

第二,遇到不对就上数值验证。面对一个很长的梯度公式,与其盯着屏幕逐行检查,不如花五分钟跑一个有限差分。数值差分不看你的推理过程,只看你的最终结果对不对,它是全世界最公道的裁判。

第三,在推导前先理清你处理的对象到底是不是对称的。这个习惯虽然简单,但能帮你规避最多一半的求导错误。每次写完 x^TAx,都问一句:“这里的 A 是常数吗?是对称的吗?”然后选择对应的公式,这几乎成为我在白板上推公式时的口头禅。

最后,二次型梯度只是一个起点。一旦彻底掌握了这类推导,你会发现逻辑回归的 Hessian、牛顿法里的二阶项、各种正则项的梯度,全都变成同一套方法下的简单应用题。这才是这个知识点真正的价值,它不是一道孤立的考试题,而是一把能打开很多后续推导之门的钥匙。

希望这篇推导整理能帮你少走一些弯路。如果你看完之后自己动手在纸上推一遍,再跑一遍数值验证的代码,这个知识点就彻底长在你身上了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询