一句话版:当你要解一个对称正定(SPD)的线性方程 A x = b Ax=b Ax=b(或等价最小化二次函数)而矩阵又很大很稀疏 时,共轭梯度法 能做到"只用矩阵--向量乘 、占用内存小、收敛快**",并且第 k k k 次迭代给出在 Krylov 子空间里的"最优"解。
1. 任务与直觉:顺着"最圆的路"下山
-
问题 :解 A x = b Ax=b Ax=b,其中 A ∈ R n × n A\in\mathbb{R}^{n\times n} A∈Rn×n 对称且正定(Symmetric Positive Definite, SPD)。
-
等价优化:
min x ϕ ( x ) = 1 2 x ⊤ A x − b ⊤ x . \min_{x} \; \phi(x)=\tfrac12 x^\top A x - b^\top x. xminϕ(x)=21x⊤Ax−b⊤x.
这是一个"碗口向上"的二次凸函数。
类比 :普通梯度下降像在"狭长的峡谷"里之字形走;共轭梯度 会为你挑选一组"互不干扰 "的下山方向(在 A A A-度量下彼此正交),这样每条方向只走一次就不回头,因此比最速下降快得多。
2. 核心思想:A-共轭方向与 Krylov 子空间
-
A-共轭(A-正交) :两方向 p i , p j p_i,p_j pi,pj 若 p i ⊤ A p j = 0 p_i^\top A p_j=0 pi⊤Apj=0( i ≠ j i\neq j i=j),称它们 A-共轭。
与欧氏正交不同,这里用的是 A A A 诱导的内积 ⟨ u , v ⟩ A = u ⊤ A v \langle u,v\rangle_A=u^\top A v ⟨u,v⟩A=u⊤Av。
-
Krylov 子空间 :以初始残差 r 0 = b − A x 0 r_0=b-Ax_0 r0=b−Ax0 为种子,
K k ( A , r 0 ) = span { r 0 , A r 0 , A 2 r 0 , ... , A k − 1 r 0 } . \mathcal{K}_k(A,r_0)=\text{span}\{r_0,Ar_0,A^2r_0,\ldots,A^{k-1}r_0\}. Kk(A,r0)=span{r0,Ar0,A2r0,...,Ak−1r0}.
CG 的第 k k k 次迭代给出的 x k x_k xk 是在 K k \mathcal{K}_k Kk 中使 ϕ ( x ) \phi(x) ϕ(x) 最小的点。
-
一次一维最优 :每一步都在当前搜索方向 p k p_k pk 上做精确线搜索 ,因此更新幅度 α k \alpha_k αk 有闭式。
3. 公式与算法:三行更新,快到飞起
设 r k = b − A x k r_k=b-Ax_k rk=b−Axk 为残差, p k p_k pk 为搜索方向,初始 x 0 x_0 x0 任取, r 0 = b − A x 0 r_0=b-Ax_0 r0=b−Ax0, p 0 = r 0 p_0=r_0 p0=r0。则
α k = r k ⊤ r k p k ⊤ A p k , x k + 1 = x k + α k p k , r k + 1 = r k − α k A p k , \alpha_k=\frac{r_k^\top r_k}{p_k^\top A p_k},\quad x_{k+1}=x_k+\alpha_k p_k,\quad r_{k+1}=r_k-\alpha_k A p_k, αk=pk⊤Apkrk⊤rk,xk+1=xk+αkpk,rk+1=rk−αkApk,
β k + 1 = r k + 1 ⊤ r k + 1 r k ⊤ r k , p k + 1 = r k + 1 + β k + 1 p k . \beta_{k+1}=\frac{r_{k+1}^\top r_{k+1}}{r_k^\top r_k},\quad p_{k+1}=r_{k+1}+\beta_{k+1} p_k. βk+1=rk⊤rkrk+1⊤rk+1,pk+1=rk+1+βk+1pk.
- 每步只需 :一次 A p k A p_k Apk 的矩阵--向量乘,外加几个向量内积与 SAXPY(线性组合)。
- 存储量 : O ( n ) O(n) O(n) 级别,只需 3--4 个向量。
否
是
初始化 x0
计算 r0=b-Ax0
设置 p0=r0
收敛?
计算 Ap=A p
计算 alpha, 更新 x 与 r
计算 beta, 更新 p
输出解 x
说明:每次循环只做一次稀疏矩阵--向量乘(SpMV),因此适合大规模稀疏问题与"矩阵--自由(只提供 A·v 算子)"场景。
4. 为什么快:误差界与"κ 的平方根"
令误差 KaTeX parse error: Undefined control sequence: \* at position 11: e_k=x_k-x^\̲*̲,在 A A A-范数下有经典界
∥ e k ∥ A ≤ 2 ( κ − 1 κ + 1 ) k ∥ e 0 ∥ A , κ = λ max ( A ) λ min ( A ) . \|e_k\|A \le 2\Big(\frac{\sqrt{\kappa}-1}{\sqrt{\kappa}+1}\Big)^k \|e_0\|A,\quad \kappa=\frac{\lambda{\max}(A)}{\lambda{\min}(A)}. ∥ek∥A≤2(κ +1κ −1)k∥e0∥A,κ=λmin(A)λmax(A).
- 对比最速下降 :最速下降的收敛比率是 κ − 1 κ + 1 \frac{\kappa-1}{\kappa+1} κ+1κ−1(更慢),而 CG 是它的"平方根改良"。
- 理论上 n n n 步精确到达 :无限精度下, n n n 维 SPD 系统,CG 最多 n n n 步得到精确解。
- 实践中 :有限精度 + 条件数大 → 需要更多步,预条件能显著提速(见 §6)。
5. 与最速下降的关系(顺便复习 5-3)
- 最速下降:每次沿负梯度方向做一维最优,但下一步可能"走回老路"。
- 共轭梯度 :构造一组 A-共轭 的方向,保证每条方向只用一次,因此"不会拉扯前功尽弃"。
6. 预条件共轭梯度(PCG):把峡谷"拉圆"
当 A A A 条件数很大,收敛变慢。找一个 SPD 的预条件器 M ≈ A M\approx A M≈A(或者近似 A − 1 A^{-1} A−1),改造系统为
M − 1 A x = M − 1 b . M^{-1}Ax=M^{-1}b. M−1Ax=M−1b.
实践算法写成:把残差 r k r_k rk 经过"预条件求解" M z k = r k M z_k=r_k Mzk=rk,再用 z k z_k zk 替换各处的 r k r_k rk。
-
PCG 更新(只写关键差异):
α k = r k ⊤ z k p k ⊤ A p k , β k + 1 = r k + 1 ⊤ z k + 1 r k ⊤ z k , p k + 1 = z k + 1 + β k + 1 p k . \alpha_k=\frac{r_k^\top z_k}{p_k^\top A p_k},\quad \beta_{k+1}=\frac{r_{k+1}^\top z_{k+1}}{r_k^\top z_k},\quad p_{k+1}=z_{k+1}+\beta_{k+1}p_k. αk=pk⊤Apkrk⊤zk,βk+1=rk⊤zkrk+1⊤zk+1,pk+1=zk+1+βk+1pk.
-
预条件器选择(从轻到重)
- Jacobi/对角缩放 : M = diag ( A ) M=\text{diag}(A) M=diag(A),零成本起步。
- 不完全 Cholesky (IC) :稀疏近似 A ≈ L L ⊤ A\approx LL^\top A≈LL⊤,求解 M z = r Mz=r Mz=r 只需三角回代。
- 块对角/多级(AMG):更强但实现复杂,图拉普拉斯与 PDE 常用。
直觉:预条件把"细长的谷底"拉"圆",让 κ \kappa κ 变小,从而指数级加速收敛。
7. 与机器学习/大模型的连接
-
最小二乘 / 线性回归 :解 min ∥ X w − y ∥ 2 2 \min\|Xw-y\|_2^2 min∥Xw−y∥22 的正规方程 ( X ⊤ X ) w = X ⊤ y (X^\top X)w=X^\top y (X⊤X)w=X⊤y 是 SPD。
-
不建议显式形成 X ⊤ X X^\top X X⊤X(会使条件数平方),而是用矩阵--自由方式:
- 给定向量 v v v,实现 A v = ( X ⊤ X ) v = X ⊤ ( X v ) A v=(X^\top X) v = X^\top(X v) Av=(X⊤X)v=X⊤(Xv)。
- 这就是CGNR/CGNE 或直接用 LSQR/LSMR(数值更稳)。
-
-
核方法 / 高斯过程 :核矩阵 K + λ I K+\lambda I K+λI 是 SPD,PCG 是核回归、GP 拟合的重要求解器(配合 MVM 加速、近似核)。
-
图学习 / 图拉普拉斯 :解 L x = b Lx=b Lx=b( L L L SPD),CG + 预条件(如 AMG)是标准配置。
-
二阶方法的内循环 :在逻辑回归/深度学习的牛顿/拟牛顿中,需要解 H Δ = − g H \Delta=-g HΔ=−g( H H H 近似 SPD),可用PCG 作为内层线性求解器。
-
大模型训练 :在分布式二阶近似 (K-FAC、Shampoo 等)里,也常见到"预条件 + 共轭"的影子。
8. 实现要点与数值细节
-
矩阵--自由 :只实现
Av(v),不要显式存 A A A。稀疏或算子形式都可。 -
停止准则 : ∥ r k ∥ 2 / ∥ b ∥ 2 ≤ tol \|r_k\|_2/\|b\|_2 \le \text{tol} ∥rk∥2/∥b∥2≤tol 或 ∥ r k ∥ M ≤ tol \|r_k\|_M \le \text{tol} ∥rk∥M≤tol。
-
重启与正交丢失 :有限精度下 A-共轭会逐渐被破坏;可周期重启 (重新置 p = r p=r p=r),或保存/再正交化(成本较高)。
-
非 SPD 的情况:
- 非对称:用 GMRES/BiCGSTAB;
- 对称但不定:用 MINRES 或 SYMMLQ。
-
溢出与稳健 :向量内积和标量更新要用双精度;必要时做残差替换 (间或重新计算 r k = b − A x k r_k=b-Ax_k rk=b−Axk)。
9. 迷你代码(矩阵--自由 + 预条件,NumPy 伪码)
python
import numpy as np
def pcg(Av, b, Msolve=None, x0=None, tol=1e-8, maxit=None):
"""
Av: 函数,返回 A @ v
Msolve:函数,解 M z = r 的近似(预条件器),默认为恒等
"""
n = len(b)
if x0 is None: x = np.zeros(n)
else: x = x0.copy()
if Msolve is None: Msolve = lambda r: r
if maxit is None: maxit = 2*n
r = b - Av(x)
z = Msolve(r)
p = z.copy()
rz_old = np.dot(r, z)
bnorm = np.linalg.norm(b)
if bnorm == 0: bnorm = 1.0
for k in range(maxit):
Ap = Av(p)
alpha = rz_old / np.dot(p, Ap)
x += alpha * p
r -= alpha * Ap
if np.linalg.norm(r) / bnorm < tol:
break
z = Msolve(r)
rz_new = np.dot(r, z)
beta = rz_new / rz_old
p = z + beta * p
rz_old = rz_new
return x, k
-
Jacobi 预条件 :
Msolve = lambda r: r / diagA(元素除法)。 -
矩阵--自由示例(正规方程):
pythonAv = lambda v: X.T @ (X @ v) + lam * v b = X.T @ y避免显式形成 X ⊤ X X^\top X X⊤X。
10. 小示例(思路版)
-
数据 X ∈ R 10 6 × 100 X\in\mathbb{R}^{10^6\times 100} X∈R106×100 稀疏,求岭回归:
- 设
Av(v)=X.T @ (X @ v) + lam * v,b=X.T @ y。 Msolve用diag(X.T@X)+lam的对角近似(可用一次遍历估出对角)。tol=1e-6,几十到上百步内即可得到可用精度的解。
- 设
11. 选择线性求解器的"路线图"
对称正定
对称不定
非对称
是
否
待解方程 Ax=b
矩阵类型
共轭梯度
MINRES
GMRES 或 BiCGSTAB
条件数大?
加预条件: Jacobi IC AMG
直接 CG
考虑右预条件
说明:先辨别矩阵类型,再选 Krylov 方法;条件数大就上预条件。
12. 常见坑与排错
-
用在非 SPD 上 → 可能发散或震荡。
- 排错:先检查对称性与正定性;若不满足,改用 GMRES/MINRES。
-
形成 X ⊤ X X^\top X X⊤X → 条件数平方放大、数值不稳。
- 排错:用矩阵--自由 v ↦ X ⊤ ( X v ) v\mapsto X^\top(Xv) v↦X⊤(Xv) 或直接 LSQR。
-
A-共轭丢失 → 收敛变慢。
- 排错:周期性重算残差、降低容差、改进预条件。
-
预条件过强/过弱:
- 过强:构造和求解 M z = r Mz=r Mz=r 太贵;过弱:加速有限。
- 折中:先用对角/块对角,必要时 IC/AMG。
-
停止准则过松/过严:
- 过松:解不够准;过严:迭代时间长。
- 建议:相对残差 \|r\|_2/\|b\|_2 + 任务容忍度。
13. 练习(含提示)
-
从最优性推导 α k , β k \alpha_k,\beta_k αk,βk:
- 用一维最优 min α ϕ ( x k + α p k ) \min_\alpha \phi(x_k+\alpha p_k) minαϕ(xk+αpk) 导出 α k \alpha_k αk;
- 用 A-共轭与残差正交性导出 β k + 1 \beta_{k+1} βk+1 的闭式。
-
误差界 :证明二次型上 ∥ e k ∥ A \|e_k\|_A ∥ek∥A 的收敛率与 κ \sqrt{\kappa} κ 有关。
-
PCG 收敛改善 :随机生成条件数为 10 4 10^4 104 的 SPD 矩阵,对比无预条件 vs Jacobi vs IC。
-
矩阵--自由 :在稀疏 X X X 的岭回归上,用
Av(v)=X.T@(X@v)+lam*v实现 PCG,画迭代次数--容差曲线。 -
非 SPD 场景:在对称不定矩阵上尝试 CG 与 MINRES,对比收敛行为。
-
残差替换 :实现"每 10 次迭代重算一次 r = b − A x r=b-Ax r=b−Ax"的变体,观察稳定性变化。
14. 小结
- 共轭梯度 专治 SPD + 大规模稀疏 的线性系统:矩阵--自由、每步只要一次 SpMV、内存友好。
- 收敛速度由条件数主导 ,PCG 能显著加速;与最速下降相比,CG 的收敛因子相当于取了平方根。
- 在 ML/GP/图学习/二阶优化的内循环中,CG/PCG 是可靠"工作马"。
- 工程要点:矩阵--自由实现、恰当预条件、稳健停止准则、周期重启 。
记住这句:"能 CG 就别 LU,能 PCG 就别裸跑。"