数值线性代数(一):高斯消元、LU 分解与「不要显式求逆」

9001 字
45 分钟
数值线性代数(一):高斯消元、LU 分解与「不要显式求逆」

AI 生成内容声明

背景:浮点文章的下一个问题#

上一篇《浮点数与数值稳定性》回答了”误差从哪里来”:表示误差、舍入误差、消去误差,以及一个统一框架——条件数 κ\kappa 衡量”输入误差会被放大多少倍”。那篇文章里条件数只出现了一页半:定义了 κ=σmax/σmin\kappa = \sigma_{max}/\sigma_{min},给了误差放大不等式,然后就收尾了。

但”误差会被放大”只是故事的一半。给定一个方程组 Ax=bAx = b,我们实际用什么算法去解?这个问题在你看论文、写 kernel 时躲不掉:

  • GPU 上解线性方程组:cuSOLVER 提供 getrf / getrs / potrf 一整套例程,它们是 LAPACK 的 GPU 移植——为什么接口是”分解+求解”两步,而不是一个”求逆”函数一步到位?
  • 部署管线里的矩阵运算:MLA 的矩阵吸收是把小矩阵进去而不是求;LoRA 权重合并是加法;量化反量化是逐元素对角操作——这些操作全是”良态”的,而”求逆”被刻意回避了。
  • 数值线性代数本身:高斯消元为什么必须换主元?为什么对称正定矩阵有专属分解?为什么最小二乘要用 QR 而不用正规方程?

这一篇是”数值线性代数”系列的第一篇,专注回答:如何稳定、高效地求解 Ax=bAx = b。规划如下:

  • (一)本篇:范数与条件数补全 → 高斯消元与主元策略 → LU 分解 → 分解谱系(Cholesky / QR / SVD)→ “不要显式求逆”的数值哲学;
  • (二):QR 分解、Householder 变换与最小二乘问题;
  • (三):迭代法——共轭梯度与大规模稀疏系统,条件数如何决定迭代次数。

下面从最能冲击直觉的现象开始。

一个反直觉的现象:Hilbert 矩阵#

考虑 n×nn \times nHilbert 矩阵,第 ii 行第 jj 列的元素是

Hij=1i+j1,i,j=1,2,,nH_{ij} = \frac{1}{i + j - 1}, \qquad i, j = 1, 2, \dots, n

它的性质好得过分:对称、所有元素为正、且是对称正定矩阵(对任意非零向量 xx 都有 xTHx>0x^T H x > 0,因为它来自内积 01p(t)q(t)dt\int_0^1 p(t)q(t)\,dt 的 Gram 矩阵)。按常识,这样的矩阵应该非常好解。

现在取 n=31n = 31,构造右端项 b=H1b = H \cdot \mathbf{1}(即 1=(1,1,,1)T\mathbf{1} = (1, 1, \dots, 1)^T 是精确解),然后让一个”普通求解器”用浮点算术去解。结果如下:

31×31 Hilbert 矩阵病态方程组:蓝线是理想解(全 1),红线是普通求解器用浮点算术算出的解,锯齿状抖动剧烈
31×31 Hilbert 矩阵病态方程组:蓝线是理想解(全 1),红线是普通求解器用浮点算术算出的解,锯齿状抖动剧烈

图里蓝线是理想解 xi=1x_i = 1,红线是求解器算出来的解——锯齿状、来回震荡、幅度巨大。图源是 MathWorks 官方博客 Cleve’s Corner 上 Rondall Jones 的客座文章 ARLS, Automatically Regularized Least Squares,原文特意注明”这张图已经算温和了:震荡幅度经常以百万计,而不是比真解大一点”。这个例子里红色震荡的规模是 10610^6 量级——一个元素全为正数、对称正定、看起来人畜无害的方程组,解出来却完全不能用。

求解器错了吗?没有。是问题本身病态:Hilbert 矩阵的条件数随 nn 指数爆炸,κ(Hn)\kappa(H_n) 大致按 e3.5ne^{3.5n} 增长。n=31n = 31 时条件数在 104010^{40} 量级,而双精度机器精度 ϵ2.2×1016\epsilon \approx 2.2 \times 10^{-16},于是 κϵ1024\kappa \cdot \epsilon \approx 10^{24}——误差放大的倍数远远盖过浮点能提供的精度,任何算法、任何机器都解不出有用的结果。这个例子说明”问题病态”和”算法不稳”是两件独立的事,这正是本篇要反复使用的框架。

要理解这图,先补两样东西:度量误差的尺子(范数),以及误差被放大的倍数(条件数)。

范数:给向量和矩阵一把”尺子”#

“解的误差是 10310^{-3}“——这句话需要一个度量长度的方法。你其实早就会用范数,只是不知道这个词:向量的欧氏长度、余弦相似度公式里的分母,都是范数。数值线性代数里我们需要向量范数矩阵范数两把尺子。

向量范数:从 L2 到 Lp#

你已经掌握的欧氏长度就是 L2 范数:

x2=ixi2=x,x\|x\|_2 = \sqrt{\sum_i x_i^2} = \sqrt{\langle x, x \rangle}

其中 x,y=ixiyi\langle x, y \rangle = \sum_i x_i y_i 是内积,余弦相似度 cosθ=x,y/(x2y2)\cos\theta = \langle x, y \rangle / (\|x\|_2 \|y\|_2) 用的就是它。一般地,LpL_p 范数定义为

xp=(ixip)1/p\|x\|_p = \left( \sum_i |x_i|^p \right)^{1/p}

常用的是三个特例:

  • p=1p = 1L1 范数 x1=ixi\|x\|_1 = \sum_i |x_i|,曼哈顿距离;
  • p=2p = 2L2 范数,欧氏距离,由内积诱导;
  • pp \to \inftyL∞ 范数 x=maxixi\|x\|_\infty = \max_i |x_i|,最大分量。

一个函数要被称为”范数”,必须满足三条公理:非负x0\|x\| \ge 0,等号当且仅当 x=0x = 0)、齐次cx=cx\|cx\| = |c|\,\|x\|)、三角不等式x+yx+y\|x + y\| \le \|x\| + \|y\|)。直觉上,范数就是”从原点量到 xx 的距离”。选择哪种范数取决于场景:稀疏向量常用 L1(压缩感知里是凸松弛),L2 在数值线性代数里最常用,原因是它是酉不变(unitary invariant)的:对任意正交矩阵 QQ(旋转/反射),Qx2=x2\|Qx\|_2 = \|x\|_2——旋转不改变长度,这使 L2 范数与矩阵分析配合得最干净。你之后会看到,正交矩阵不放大误差这件事,在 RoPE 那里还会再出现一次。

矩阵范数:单位球被拉伸的最长半径#

向量范数只能量”解”的长度,但误差分析里的放大倍数 κ\kappa 属于矩阵。定义矩阵的诱导范数(也叫算子范数)为

A=maxx0Axx=maxx=1Ax\|A\| = \max_{x \neq 0} \frac{\|Ax\|}{\|x\|} = \max_{\|x\| = 1} \|Ax\|

直观解释:把所有单位长度的向量 xx 扔进 AA,看输出最长能有多长,这个”最大拉伸倍数”就是 A\|A\|。其中由 L2 范数诱导出的 A2\|A\|_2谱范数,它有一个非常漂亮的身份:

A2=σmax(A)\|A\|_2 = \sigma_{max}(A)

AA最大奇异值。为什么?因为 Ax22=xTATAx\|Ax\|_2^2 = x^T A^T A x,而 ATAA^T A 是对称半正定矩阵,其特征值就是奇异值的平方 σi2\sigma_i^2;在特征向量方向上 xTATAxx^T A^T A x 取到最大,开根号就是 σmax\sigma_{max}

另一种常用矩阵范数是 Frobenius 范数,把矩阵当长向量:

AF=i,jaij2=iσi2\|A\|_F = \sqrt{\sum_{i,j} a_{ij}^2} = \sqrt{\sum_i \sigma_i^2}

注意它和谱范数的区别:Frobenius 范数等于奇异值平方和的平方根,谱范数等于最大奇异值——前者是”整体大小”,后者是”最强拉伸方向”。直觉上,AF\|A\|_F 像矩阵的”总能量”,A2\|A\|_2 像矩阵的”最大杠杆”。

铺垫:矩阵 = 线性变换的几何#

范数的几何解读依赖一个视角,这也是你数学档案里缺的一块:矩阵就是线性变换AA 把一个向量”送到”另一个向量,几何效果只有五种基本形态的组合:拉伸、压缩、旋转、反射、剪切。下图把同一张带方向箭头的方块在 5 种矩阵作用下的样子画了出来(图源:Greg Gundersen 的博客文章 The Singular Value Decomposition (SVD) 的 Figure 2):

线性变换的几何:同一方块在不同矩阵作用下的变形——拉伸、压缩、旋转、反射(翻转)与剪切
线性变换的几何:同一方块在不同矩阵作用下的变形——拉伸、压缩、旋转、反射(翻转)与剪切

从左到右五种变换分别对应:对角元 >1> 1 的对角矩阵(拉伸)、对角元 <1< 1 的对角矩阵(压缩)、正交矩阵(旋转)、带 1-1 特征值的正交矩阵(反射)、非对称的三角矩阵(剪切)。后面讲条件数、特征值、RoPE 旋转矩阵时,这套几何语言会反复用到。奇异值分解 A=UΣVTA = U\Sigma V^T 的几何含义就是:先旋转(VTV^T)、再沿坐标轴拉伸(Σ\Sigma)、最后再旋转(UU——任何线性变换都只是”转一下、拉一下、再转一下”。拉伸的倍数正是奇异值 σ1σ2σn\sigma_1 \ge \sigma_2 \ge \dots \ge \sigma_n

条件数:误差放大倍数的完整推导#

有了范数这把尺子,现在把上一篇只给出结论的误差放大不等式完整推导一遍。

AA 可逆,Ax=bAx = b 的精确解为 xx。现在右端项 bb 受到扰动 δb\delta b(例如测量误差、或者 bb 本身是浮点数),新方程组为

A(x+δx)=b+δbA(x + \delta x) = b + \delta b

两边相减得 Aδx=δbA\,\delta x = \delta b,即 δx=A1δb\delta x = A^{-1} \delta b。两边取范数:

δxA1δb\|\delta x\| \le \|A^{-1}\| \cdot \|\delta b\|

同时由 b=Axb = AxbAx\|b\| \le \|A\| \cdot \|x\|,即 1/xA/b1/\|x\| \le \|A\|/\|b\|。两个不等式相乘,把 δx/x\|\delta x\|/\|x\| 凑出来:

δxxAA1δbb\frac{\|\delta x\|}{\|x\|} \le \|A\| \cdot \|A^{-1}\| \cdot \frac{\|\delta b\|}{\|b\|}

这就是条件数不等式:左边是解的相对误差,右边是输入的相对误差乘以放大倍数。放大倍数记为

κ(A)=AA1\kappa(A) = \|A\| \cdot \|A^{-1}\|

在谱范数下,A2=σmax\|A\|_2 = \sigma_{max}A12=1/σmin\|A^{-1}\|_2 = 1/\sigma_{min}A1A^{-1} 的奇异值就是 AA 奇异值的倒数),所以

κ2(A)=σmaxσmin\kappa_2(A) = \frac{\sigma_{max}}{\sigma_{min}}

最大奇异值与最小奇异值之比。上一篇文章里你见过这个式子,现在它的每个成分都有了意义:σmax\sigma_{max} 是”最强的拉伸”,σmin\sigma_{min} 是”最弱的拉伸”,两者之比衡量这个矩阵把空间扭曲得多”扁”。

几何直觉:圆变成椭圆#

条件数的几何意义一张图就够。下图(图源同上,Greg Gundersen 的 SVD 文章 Figure 5)左边是单位圆,右边是这个圆被某个矩阵 AA 映射后的像:

单位圆被矩阵 A 映成椭圆:椭圆半长轴长度就是最大奇异值 σ_max,半短轴就是最小奇异值 σ_min,长短轴之比即条件数
单位圆被矩阵 A 映成椭圆:椭圆半长轴长度就是最大奇异值 σ_max,半短轴就是最小奇异值 σ_min,长短轴之比即条件数

单位圆上的所有向量 x=1\|x\| = 1AA 送到一个椭圆上,椭圆的两个半轴长度恰好是 σmax\sigma_{max}σmin\sigma_{min},方向是左奇异向量 u1,u2u_1, u_2。理由很直接:xx 沿右奇异向量 v1v_1 时,Ax=σ1u1Ax = \sigma_1 u_1,长度就是 σ1\sigma_1。于是:

  • 良态矩阵(κ1\kappa \approx 1:椭圆接近圆,所有方向的拉伸差不多,误差无论从哪个方向进来都不被放大;
  • 病态矩阵(κ1\kappa \gg 1:椭圆被压成”雪茄”甚至”针”,σmin\sigma_{min} 方向几乎被压扁。误差一旦落进这个方向,解就会飞出去——Hilbert 矩阵就是这么回事。

配合条件数不等式:δb\delta b 恰好落在 uminu_{min}(被压扁的方向)时,解的扰动 δx=A1δb\delta x = A^{-1}\delta b 落在 vminv_{min} 方向,被放大了 1/σmin1/\sigma_{min} 倍。

条件数的几个性质#

  • κ(A)1\kappa(A) \ge 1:因为 AA1AA1=I=1\|A\|\cdot\|A^{-1}\| \ge \|AA^{-1}\| = \|I\| = 1
  • 缩放不变κ(cA)=κ(A)\kappa(cA) = \kappa(A)。所以”行列式小”不是病态的判据——把 AA 整体乘 1000,行列式变 10610^6 倍,条件数纹丝不动。判断病态必须看比率,不是看绝对大小。
  • 正交矩阵 κ=1\kappa = 1:正交矩阵满足 QTQ=IQ^T Q = I,所有奇异值都是 1,圆映成圆。旋转/反射是最”温和”的矩阵,这也是为什么 RoPE 用旋转矩阵编码位置(第九节展开)。
  • 有效精度:双精度下 ϵ2.2×1016\epsilon \approx 2.2 \times 10^{-16},条件数 κ=10k\kappa = 10^k 意味着解要丢掉约 kk 位十进制有效数字。经验法则:κϵ1\kappa \cdot \epsilon \gtrsim 1 时,解基本是噪声。Hilbert 矩阵 n=31n=31κ1040\kappa \approx 10^{40}κϵ1024\kappa \epsilon \approx 10^{24},所以图里那根红线横七竖八——不是求解器的错,问题本身就没有可解性。

顺带把上一篇欠的账补上:κ\kappa 不仅衡量 Ax=bAx = b,对任意计算问题都能定义”问题条件数”。函数 ff 在输入 xx 处的条件数就是 f(x)x/f(x)|f'(x)| \cdot |x|/|f(x)|,衡量输入相对扰动引起的输出相对扰动。上一篇讲的”相近数相减”(catastrophic cancellation)本质上是减法 f(a,b)=abf(a,b) = a - baba \approx b 处条件数趋于无穷;在线 softmax 的重缩放则是把一个病态写法重排成良态写法。本篇聚焦矩阵版本。

高斯消元:人人都学过,却未必知道它有多脆弱#

消元过程与计算量#

高斯消元你课程里学过,这里从”数值稳定性”的角度重新看一遍。目标是把增广矩阵 [Ab][A \mid b] 通过行变换变成上三角 [Ub~][U \mid \tilde{b}],再回代求解。以 3×33 \times 3 为例:

A=(211460272)A = \begin{pmatrix} 2 & 1 & -1 \\ -4 & -6 & 0 \\ -2 & 7 & 2 \end{pmatrix}

第一步:用第 1 行消去第 2、3 行的第 1 列。乘数(multiplier)分别是 4/2=2-4/2 = -22/2=1-2/2 = -1,第 2 行减去 2-2 倍第 1 行(等价于加上 2 倍),第 3 行减去 1-1 倍第 1 行,得到

(211042081)\begin{pmatrix} 2 & 1 & -1 \\ 0 & -4 & -2 \\ 0 & 8 & 1 \end{pmatrix}

第二步:用第 2 行消第 3 行第 2 列,乘数 8/(4)=28/(-4) = -2,得到上三角 UU。回代两步即可求出 xx

kk 步消元要处理剩下的 nkn-k 行、每行约 nk+1n-k+1 个元素,所以总乘加次数约为

k=1n1(nk)(nk+1)13n3\sum_{k=1}^{n-1} (n-k)(n-k+1) \approx \frac{1}{3} n^3

每次乘加是 2 次浮点运算(乘+加),因此高斯消元的总计算量是 23n3\frac{2}{3} n^3 flops;回代只有 12n2\frac{1}{2} n^2,可以忽略。作为对比,矩阵乘法是 2n32n^3 flops——消元大约只有 GEMM 的三分之一,这是个”便宜”的算法。

致命弱点:除以小主元#

消元的关键操作是除以主元(对角线元素)。如果主元很小,会发生什么?用一个经典的教科书例子(几乎所有数值线性代数教材都会讲,比如 Trefethen & Bau 的《Numerical Linear Algebra》):

{0.0001x1+x2=1x1+x2=2\begin{cases} 0.0001\, x_1 + x_2 = 1 \\ x_1 + x_2 = 2 \end{cases}

精确解是 x10.9999x_1 \approx 0.9999x21.0001x_2 \approx 1.0001。现在假设我们只有三位十进制浮点精度10410^{-4} 量级机器精度,相当于”极寒版”的 FP16 环境,用来放大问题)。

不换行直接消:乘数 m=1/0.0001=10000m = 1 / 0.0001 = 10000。第二行减去 mm 倍第一行:(110000×1)x2=210000×1(1 - 10000 \times 1) x_2 = 2 - 10000 \times 1,即 9999x2=9998-9999 x_2 = -9998,三位精度舍入为 1.00×104x2=1.00×104-1.00 \times 10^4 \cdot x_2 = -1.00 \times 10^4,解得 x2=1.00x_2 = 1.00。回代:0.0001x1=11.00=00.0001 x_1 = 1 - 1.00 = 0,于是 x1=0x_1 = 0

结果:x1=0x_1 = 0,真解是 x11x_1 \approx 1——完全错了。 问题出在哪?第一步 210000×1=99982 - 10000 \times 1 = -9998 这一步:100001000011 相差四个数量级,大数加小数x1x_1 的信息直接舍入掉了(正是上一篇讲的”大数加小数丢精度”),于是 x1x_1 的信息在消元第一步就彻底消失。

先换行再消(把第一行和第二行交换):主元变成 11,乘数 m=0.0001m = 0.0001。第二行变为 (10.0001×1)x2=10.0001×2(1 - 0.0001 \times 1)x_2 = 1 - 0.0001 \times 2,即 0.9999x2=0.99980.9999 x_2 = 0.9998,三位精度下 x2=1.00x_2 = 1.00,回代 x1=21.00=1.00x_1 = 2 - 1.00 = 1.00

结果正确。 同样的机器、同样的精度,只是行交换了一下,结果从全错变全对。这就是部分主元(partial pivoting)的全部动机。

部分主元:把最大元换到对角线#

部分主元策略:消元到第 kk 步时,在 A[k:n,k]A[k:n, k](第 kk 列主元位置往下的所有元素)中挑绝对值最大的,把它所在的行和当前第 kk 行交换,再以它为除数。这样保证所有乘数满足 m1|m| \le 1

为什么”选最大的”?因为消元中真正危险的是除以很小的数:除数越小,舍入误差被放大的倍数越大。把主元选为列中绝对值最大者,就把每一步的放大倍数压到最小。而且行交换不改变方程组的解(只是重排方程顺序),换行是零成本、零风险的操作。

更严格的稳定性保证来自 Wilkinson 的经典分析:带部分主元的高斯消元是向后稳定的(第八节详细说),其误差界中的”增长因子”(growth factor)ρ=maxi,j,kuij/maxi,jaij\rho = \max_{i,j,k} |u_{ij}| / \max_{i,j} |a_{ij}| 在部分主元下通常很小(实践中 ρ\rho 很少超过 10),而不换主元时 ρ\rho 可以呈 2n12^{n-1} 指数爆炸——理论最坏情况由 Wilkinson 构造的特殊矩阵达到,工程上无主元消元是绝对禁区。

还有更强的完全主元(complete pivoting):每一步在右下角整个子矩阵里挑最大元。它理论上更稳,但每次要扫 O(n2)O(n^2) 个元素找最大值,总代价 O(n3)O(n^3) 的额外比较,几乎没人用——部分主元”够好且免费”,完全主元”略好但昂贵”,这是工程上经典的取舍。

LU 分解:消元过程的矩阵语言#

高斯消元做了 n1n-1 轮行变换,这些行变换在矩阵语言里就是左乘初等矩阵。把每轮消元的乘数记下来,你会发现整个消元过程可以被压缩成一句话:A=LUA = LU

从消元到分解#

E1,E2,,En1E_1, E_2, \dots, E_{n-1} 依次是各轮消元的行变换矩阵,消元完成后有

En1E2E1A=UE_{n-1} \cdots E_2 E_1 A = U

其中 UU 是上三角。把所有的 EE 移到右边:

A=(En1E1)1UA = (E_{n-1} \cdots E_1)^{-1} U

关键事实:初等行变换矩阵的逆不需要算,直接读出来EkE_k 的逆就是把第 kk 轮乘数的符号反过来,于是 (En1E1)1(E_{n-1}\cdots E_1)^{-1} 恰好是把各轮乘数(变号后)填到对角线下方的下三角矩阵 LL,且对角线全为 1:

L=(1m211mn1mn,n11),U=(u11u12u1nu22unn)L = \begin{pmatrix} 1 & & & \\ m_{21} & 1 & & \\ \vdots & & \ddots & \\ m_{n1} & \cdots & m_{n,n-1} & 1 \end{pmatrix}, \qquad U = \begin{pmatrix} u_{11} & u_{12} & \cdots & u_{1n} \\ & u_{22} & & \vdots \\ & & \ddots & \\ & & & u_{nn} \end{pmatrix}

验证一个 2×22 \times 2 例子:A=(2187)A = \begin{pmatrix} 2 & 1 \\ 8 & 7 \end{pmatrix},乘数 m21=8/2=4m_{21} = 8/2 = 4,消元得 U=(2103)U = \begin{pmatrix} 2 & 1 \\ 0 & 3 \end{pmatrix},于是

L=(1041),LU=(1041)(2103)=(2187)=AL = \begin{pmatrix} 1 & 0 \\ 4 & 1 \end{pmatrix}, \qquad LU = \begin{pmatrix} 1 & 0 \\ 4 & 1 \end{pmatrix}\begin{pmatrix} 2 & 1 \\ 0 & 3 \end{pmatrix} = \begin{pmatrix} 2 & 1 \\ 8 & 7 \end{pmatrix} = A \quad \checkmark

为什么这个平凡的重述如此重要?因为分解一次,可以反复使用

  • 求解 Ax=bAx = b 变成两步:先前代Ly=bLy = bO(n2)O(n^2),下三角从顶往下算),再回代Ux=yUx = yO(n2)O(n^2));
  • 换一个新的右端项 bb',只需要重做两次三角求解 O(n2)O(n^2)分解的 2n3/32n^3/3 不用重算

带部分主元时,行交换记成一个置换矩阵 PP,分解写作 PA=LUPA = LU,求解流程变为 Ly=PbLy = PbUx=yUx = y。这就是 LAPACK 例程 getrf(分解,输出 L,U,PL, U, P)和 getrs(用分解结果求解)的由来——永远两步走,永远不显式求逆

为什么不显式求逆:成本与稳定性的双重理由#

把”求逆再相乘”和”LU 分解”对比,这是本系列最重要的工程结论,也是 John D. Cook 的经典博客文章 Don’t invert that matrix 的标题——不要对矩阵求逆。

  • 成本:显式求 A1A^{-1} 等价于解 nn 个右端项 AX=IA X = I,成本 O(n3)O(n^3)(约 2n32n^34n34n^3 flops,取决于实现),而 LU 分解只要 2n3/32n^3/3,再解任意多个右端项每个只需 O(n2)O(n^2)。对一个右端项来说,求逆贵 3 倍以上。
  • 稳定性:求逆本身是”解 nn 个方程组”,每一步都会引入舍入误差;求完逆再乘 bb,误差又被乘一遍。用 John Cook 的比喻:为了回答”这家餐厅有什么菜”,你把整本菜单背下来再逐页翻——直接把菜单翻到那一页(LU 求解)又快又稳。
  • 结构AA 如果稀疏、带状、对称正定,LLUU 会继承部分结构(比如 Cholesky 的 LL 保持带状),而 A1A^{-1} 几乎总是稠密的——求逆会破坏所有可以利用的结构。

数值上还有一个更微妙的点:A1A^{-1} 的条件数等于 AA 的条件数κ(A1)=κ(A)\kappa(A^{-1}) = \kappa(A),因为奇异值互为倒数),所以”先求逆再乘”并不会让问题变得更好;而直接 LU 求解只需承担一次”向后误差 × 条件数”。结论是明确的:工程代码里出现 inv(A) @ bA.inverse() 的地方,几乎都可以替换为分解求解,又稳又快。

与 GEMM 的联系:分块 LU#

GPU 上怎么把 LU 分解跑得快?答案是把消元分块化(blocked / panel factorization):每一轮对外层的 kk 列(panel)做一次小规模消元,然后用矩阵乘更新剩余的大块子矩阵 A22A22L21U12A_{22} \leftarrow A_{22} - L_{21} U_{12}。这一步是标准的 GEMM——正好复用你在这两篇《GPU GEMM 优化完全拆解(一)》《GPU GEMM 优化完全拆解(二)》里学到的分块、共享内存、寄存器分块技术。LAPACK 的 getrfDGETRF 的块化实现,cuSOLVER 的 cusolverDnDgetrf 是它的 GPU 版本——GPU 上 LU 的加速路径和 GEMM 是同一套打法。这也是为什么 ”23n3\frac{2}{3}n^3 的消元” 在硬件上能以接近 GEMM 的效率运行:大部分工作都被重构成了 GEMM。

分解的谱系:Cholesky、QR、SVD#

LU 不是唯一的分解。数值线性代数的核心智慧可以浓缩成一句口号:别直接操作矩阵,先把它分解成好处理的因子。选哪种分解取决于矩阵的结构和精度要求

分解适用条件计算量数值稳定性LAPACK / cuSOLVER 例程
LU + 部分主元(PA=LUPA=LU任意可逆方阵23n3\frac{2}{3}n^3向后稳定(主元保护)getrf / getrs
Cholesky(A=LLTA=LL^T对称正定13n3\frac{1}{3}n^3天然稳定,无需主元potrf / potrs
QR(A=QRA=QR任意矩阵(列满秩)2n32n^3(Householder)无条件向后稳定geqrf
SVD(A=UΣVTA=U\Sigma V^T任意矩阵4n3\gtrsim 4n^3最稳定、最贵gesvd / gesvdj

逐行解释:

  • CholeskyA=LLTA = LL^TLL 为下三角,无需主元也稳定——因为对称正定矩阵的所有顺序主子式为正,消元过程中主元天然远离零。计算量只有 LU 的一半(利用对称性),是”最便宜的好分解”。它出现在一切正定系统的求解里:协方差矩阵、正态分布的二次型、以及最小二乘的正规方程(不过正规方程本身条件数是原问题的平方,工程上通常用 QR 替代——这是下一篇的主题)。
  • QRA=QRA = QRQQ 正交、RR 上三角。Householder 变换把消元用的”初等行变换”换成正交变换,正交变换不放大误差κ=1\kappa=1),所以 QR 是求解最小二乘的标准选择。它比 LU 贵 3 倍,但换来的无条件稳定性值得。
  • SVD:最贵、最稳、信息最全。奇异值谱直接告诉你秩、条件数、低秩近似——你在 MLA 完全拆解 里见过的低秩压缩,数学基础就是”截断 SVD:砍掉小奇异值”。

这张表里 UU 的一列可以回答你之前一个疑问:为什么”矩阵求逆”在 LAPACK 里不是一个推荐接口?因为求逆 = 做一次 LU 分解 + 解 nn 个右端项,任何”直接求逆”的算法都不会比”分解 + 三角求解”更便宜或更稳。所有严肃的数值库都围绕分解设计,逆矩阵只是一个”概念对象”。

误差分析的视角:向后误差与 Wilkinson 公式#

解决了”怎么解”,还剩最后一个理论问题:浮点算法算出的解 x^\hat{x},到底错在哪?

朴素的想法是”算出 x^\hat{x} 后和真解 xx 比相对误差 x^x/x\|\hat{x} - x\|/\|x\|“——这叫向前误差(forward error)。但真解 xx 我们永远不知道,这个定义不可操作。数值分析用了一个巧妙的视角翻转——向后误差(backward error)

x^\hat{x} 是某个”邻近系统” (A+δA)x^=b(A + \delta A)\hat{x} = b精确解,其中 δA\|\delta A\| 很小。我们不去问”x^\hat{x} 离真解多远”,而是问”x^\hat{x} 精确地解了哪个问题,那个问题和原问题差多远”。

Wilkinson 的经典定理:带部分主元的高斯消元是向后稳定的——浮点消元算出的 x^\hat{x} 精确满足

(A+δA)x^=b,δAcnρϵA(A + \delta A)\hat{x} = b, \qquad \|\delta A\| \le c\, n\, \rho\, \epsilon\, \|A\|

其中 cc 是小常数,nn 是矩阵规模,ρ\rho 是增长因子,ϵ\epsilon 是机器精度。也就是说:算法本身几乎不引入误差——它引入的误差和一个”精确求解扰动后系统”的人一样多。

把向后误差和条件数乘起来,就得到总误差(Wilkinson 公式的通俗版本):

x^xxκ(A)(向后误差)=κ(A)O(nρϵ)\frac{\|\hat{x} - x\|}{\|x\|} \lesssim \kappa(A) \cdot (\text{向后误差}) = \kappa(A) \cdot O(n \rho \epsilon)

这个分解的价值在于责任划分:条件数 κ\kappa 是问题的属性(病态与否),nρϵn \rho \epsilon 是算法的属性(稳定与否)。Hilbert 矩阵的灾难来自前者——κ1040\kappa \approx 10^{40} 时,即使算法完美(向后误差仅 ϵ\epsilon 量级),总误差照样 102410^{24}。反过来,只要 κ\kappa 中等(比如 10310^3 以内),稳定算法在双精度下就能给出几乎全精度的解

工程上还要注意:κ\kappa 本身通常不精确计算(精确算要 SVD,太贵)。实际做法是用 O(n2)O(n^2) 的估计器:LAPACK/MATLAB 的 condest(1 范数条件数估计,Higham 设计),以及基于三角因子 RRtricond 类例程。Cleve Moler 2026 年 4 月的博客文章 Matrix Condition and the QR Decomposition 专门讲了这条路线:先做 QR 分解,再用三角矩阵条件数估计器估算 κ(R)=κ(A)\kappa(R) = \kappa(A)。下图的 3D 条形图来自该文,对比了多种测试矩阵(moler、parter、binomial、chebspec、cauchy 等 MATLAB Gallery 矩阵)在不同规模 nn 下的估计得分:

条件数估计的得分对比:对多种测试矩阵用 QR 三角因子估计条件数,得分 = 估计值/真值,越接近 1 越好;换列主元与否(两组柱)会影响估计质量
条件数估计的得分对比:对多种测试矩阵用 QR 三角因子估计条件数,得分 = 估计值/真值,越接近 1 越好;换列主元与否(两组柱)会影响估计质量

读图要点:每组柱状的高度是”估计得分” tricond/κtricond/\kappa,越接近 1 说明估计越准;图中可以看到不同矩阵、不同规模下估计质量的差异,以及是否启用列主元对估计的影响——这解释了为什么”带主元的 QR 三角因子估计”是生产级代码的标准做法。在推理系统里,这种估计器的意义在于诊断:当你怀疑某个矩阵运算结果可疑时,先估计条件数,再决定是怀疑算法还是怀疑问题本身。

现在回头看第一节的 Hilbert 图,可以把责任交代清楚了:红线抖动不是求解器质量差(它满足向后稳定性),而是 κϵ1024\kappa \cdot \epsilon \approx 10^{24}——问题本身没有可解性。对这种病态问题,数值方法能做的不是”更努力地解”,而是换问题:加正则化(把 Ax=bAx = b 换成 (A+pI)x=b(A + pI)x = b 之类的最小二乘变体,即 ARLS 文章里讲的 Tikhonov 正则化)、降低精度要求、或利用先验知识。这正是”ARLS, Automatically Regularized Least Squares”那篇文章的主题,也是数值线性代数与机器学习交汇的地方。

与 LLM 推理的五个连接#

这一节的目的是把前面所有数学落回你的方向。每个连接都是真实的工程事实,不是牵强附会。

1. RoPE 为什么数值友好:正交矩阵 κ = 1#

RoPE(旋转位置编码,论文 arXiv:2104.09864)把位置信息编码为对 qqkk 向量施加的旋转:2 维子空间上用 (cosθsinθsinθcosθ)\begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix} 旋转。这类旋转矩阵是正交矩阵QTQ=IQ^T Q = I,所有奇异值为 1,κ=1\kappa = 1

这意味着两件事:其一,旋转保长度Qx=x\|Qx\| = \|x\|),注意力点积的模长不受位置编码破坏;其二,误差不会被旋转放大——即使 FP16/BF16 下 qqkk 的表示有舍入误差,旋转也不会把它们放大 κ\kappa 倍。用前面的话说,RoPE 选择了一种”条件数最优”的线性变换。对比之下,如果位置编码用非正交矩阵(比如某些线性外推方案),数值风险是隐性的。

2. 在线 softmax 的重缩放:把病态重排成良态#

上一篇推导过在线 softmax:为防溢出,减去当前最大值 mm,用 exp(xim)\exp(x_i - m) 代替 exp(xi)\exp(x_i),再乘回重缩放因子。用本篇的语言:直接算 exp\exp 求和是病态写法(大数加小数),减去最大值把中间量压到 [0,1][0,1],等价于把一个 κ\kappa 巨大的求和重排成 κ1\kappa \approx 1 的良态求和——同一个数学对象,不同的计算顺序,条件数天差地别。FlashAttention 的数值重缩放(论文 arXiv:2205.14135)是同一思想的流式版本。这是”算法稳定性”最重要的工程模板:不改问题,只改写法。

3. 不显式求逆:MLA 吸收、LoRA 合并、量化#

你的方向上”求逆”出现的方式,全是被刻意回避的:

  • MLA 的矩阵吸收(详见《MLA 完全拆解》):把 WUKW^{UK} 吸收进 WQW^QWUW^U 吸收进 WOW^O,是把小矩阵到大权重里,是纯乘法重组,不涉及任何求逆;
  • LoRA 合并W=W0+BAW' = W_0 + BA,加法;
  • 量化/反量化:scale 因子是标量,x/sx / s 等价于乘 1/s1/s——1×1 的”对角矩阵求逆”是平凡且 κ=1\kappa = 1 的。

如果哪一天你在推理管线里看到显式 inv(),几乎都可以问一句:这里是不是可以用分解或直接重组替代?这是”Don’t invert that matrix”精神在 LLM 部署中的版本。

4. 奇异值谱与低秩压缩:σ_min 决定”可逆性”#

SVD 视角下,权重矩阵的低秩可压缩性来自奇异值谱衰减:大模型权重矩阵的奇异值通常快速衰减,σmin\sigma_{min} 接近零,因此矩阵”数值上不可逆”——但这恰恰是好事,说明它可以被低秩近似(截断 SVD 砍掉小奇异值方向)。MLA 的低秩 KV 压缩、SVD-LLM(arXiv:2403.17414,用 SVD 做 LLM 权重压缩)、XFP 那类码本量化,数学上都是同一个事实的利用:σmin\sigma_{min} 小 → 精确求逆无意义 → 但低秩/伪逆有意义。伪逆 A+=VΣ+UTA^{+} = V\Sigma^{+}U^TΣ+\Sigma^{+} 对非零奇异值取倒数)是”在秩亏矩阵上最有意义的求逆”——它恰好跳过 σ0\sigma \approx 0 的方向,等价于数值上最稳的逆。这也是为什么数值库提供 gesvd 而不是”安全求逆”。

5. 状态空间模型与线性注意力:特征值、分块消元与谱半径#

最后两个预告性的连接,细节留给后面的文章:

  • S4 论文(arXiv:2111.00396)明确讨论了数值问题:状态空间模型的 AA 矩阵直接对角化在长序列下数值不稳,原因是特征向量矩阵可能病态(κ\kappa 大),于是改用正规矩阵(正规矩阵可被正交对角化,特征向量矩阵 κ=1\kappa = 1)。这是”特征值问题也会病态”在 LLM 系统的真实案例,也是下一篇系列文章(特征值与谱)的引子。Mamba 的 ZOH 离散化要计算 (ΔA)1(eΔAI)ΔB(\Delta A)^{-1}(e^{\Delta A} - I) \Delta B——这个”除以 ΔA\Delta A“的小型矩阵运算在实现中同样用级数展开回避显式求逆。
  • RetNet 的分块并行(arXiv:2307.08621)在形式上与分块消元同构:序列被切成块,块内并行、块间递推,需要计算的块矩阵组合与分块高斯消元中的 Schur 补结构一致。分块、消元、递推这三件事在数值线性代数里本来就是一家。

GPU 实践:在 CUDA 里解线性方程组#

把本篇知识落到代码层面,几条可以直接用的建议:

  1. 用库,不要手写:解 Ax=bAx = b 用 cuSOLVER 的 cusolverDnDgetrf(LU 分解)+ cusolverDnDgetrs(求解),对称正定用 cusolverDnDpotrf/potrs。不要自己实现高斯消元——主元、分块、GEMM 化这些细节库都处理好了。
  2. 批量小矩阵:推理 kernel 里常见”对每个 token/每个样本解一个小系统”的需求,用 cuBLAS 的 batched 接口或 cuSOLVER 的 batched getrf,不要在一个 kernel 里串行解几百个小系统。
  3. 手写小矩阵求逆要警觉2×22 \times 23×33 \times 3 的显式逆矩阵公式(伴随矩阵除以行列式)偶尔手写进 kernel。除行列式等价于除以 σ1σ2\sigma_1\sigma_2,行列式接近零时误差爆炸——如果必须手写,先估 κ\kappa2×22 \times 2 可以快速估奇异值比),或者改用公式更稳的形式。
  4. 诊断先行:数值结果可疑时,先估计条件数再怀疑算法。用 condest 的思路(基于三角因子)在 GPU 上成本很低。

小结#

这一篇的完整链条:误差来自浮点(上一篇)→ 误差被放大多少由条件数决定(本篇前段)→ 条件数巨大是问题属性,算法能控制的是”不添乱”(向后稳定)→ 高斯消元 + 部分主元是向后稳定的(本篇核心)→ 矩阵形式是 LU 分解 → 分解而不求逆,是所有数值库的设计哲学

五个必须带走的事实:

  1. 条件数 κ=σmax/σmin\kappa = \sigma_{max}/\sigma_{min} 是”误差放大倍数”,κϵ1\kappa \cdot \epsilon \gtrsim 1 时解就是噪声;正交矩阵 κ=1\kappa = 1
  2. 高斯消元本身脆弱(除以小主元放大误差),部分主元用”换行”这一零成本操作保证乘数 1\le 1,使算法向后稳定。
  3. 消元过程就是 LU 分解;分解一次 2n3/32n^3/3,之后每个右端项只要 O(n2)O(n^2)
  4. 分解谱系按”结构与精度”选择:正定用 Cholesky(n3/3n^3/3)、一般用 LU、最小二乘用 QR、诊断用 SVD;求逆总是更贵更差的选择。
  5. 工程判断框架:病态问题换问题(正则化/降维),稳定算法换写法(重排计算顺序),两件事不要混淆。

下一篇《数值线性代数(二)》将讨论 QR 分解与最小二乘:为什么正规方程 ATAx=ATbA^TAx = A^Tb 是陷阱(κ\kappa 平方),Householder 变换如何实现无条件稳定,以及最小二乘在你方向上的现身之处。再下一篇进入迭代法与共轭梯度κ\kappa 如何决定迭代次数,为什么大稀疏系统必须用迭代法。

参考资料#

  1. Greg Gundersen, “The Singular Value Decomposition (SVD)“——本篇两幅几何图的来源(Figure 2 线性变换、Figure 5 圆到椭圆)
  2. Cleve’s Corner: ARLS, Automatically Regularized Least Squares——31×31 Hilbert 矩阵病态演示图来源(MathWorks 官方博客,Rondall Jones 客座)
  3. Cleve’s Corner: Matrix Condition and the QR Decomposition——条件数估计得分对比图来源(MathWorks 官方博客,2026 年 4 月)
  4. John D. Cook, “Don’t invert that matrix”——“不要显式求逆”的经典论述
  5. Trefethen & Bau, Numerical Linear Algebra(SIAM,DOI 10.1137/1.9780898719574)——高斯消元、主元策略与向后误差的标准教材
  6. N. J. Higham, Accuracy and Stability of Numerical Algorithms(SIAM,DOI 10.1137/1.9780898718027)——误差分析与条件数估计(condest)的权威参考
  7. Goldberg, “What Every Computer Scientist Should Know About Floating-Point Arithmetic”——浮点算术与消去误差的经典文献
  8. NVIDIA cuSOLVER 官方文档——GPU 上 LU/Cholesky/QR/SVD 例程(getrf/getrs/potrf/geqrf/gesvd)
  9. RoPE 论文:RoFormer: Enhanced Transformer with Rotary Position Embedding(arXiv:2104.09864)——旋转矩阵正交性(κ=1)的来源
  10. FlashAttention 论文(arXiv:2205.14135)——在线 softmax 数值重缩放
  11. S4 论文:Efficiently Modeling Long Sequences with Structured State Spaces(arXiv:2111.00396)——状态空间模型中特征向量矩阵病态与正规矩阵的讨论
  12. Mamba 论文(arXiv:2312.00752)——SSM 离散化与矩阵指数计算
  13. RetNet 论文:Retentive Network: A Successor to Transformer for Large Language Models(arXiv:2307.08621)——分块并行表示与分块消元的类比
  14. SVD-LLM 论文:Singular Value Decomposition for LLM Compression(arXiv:2403.17414)——奇异值谱与权重压缩
  15. Trefethen 的牛津数值线性代数讲义主页——消元、分解与稳定性讲义

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

数值线性代数(一):高斯消元、LU 分解与「不要显式求逆」
https://pinghaoyang.com.cn/aigc/posts/numerical-linear-algebra-part-1/
作者
平昊阳
发布于
2026-08-24
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
平昊阳
乘长风,破巨浪, 展鸿图于未央!
--
总访问量
--
访客数
公告
欢迎来到我的个人博客!欢迎关注交流吖!
更多相关公告,见
社交-留言」。
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
站点统计
文章
66
分类
16
标签
93
总字数
477,284
运行时长
0
最后活动
0 天前

文章目录