MATH ML Learning Lab
04 / 09
第 4 步 · 万能分解与低秩压缩

SVD 奇异值分解与低秩近似Singular Value Decomposition & Low-Rank Approximation

特征分解只对方阵有效,而且未必有实特征值;SVD 却对任何长方矩阵都成立 —— 它把任何变换统一成「旋转 → 沿轴缩放 → 再旋转」三步。奇异值的大小顺序告诉你哪些方向值得保留,于是图像压缩、去噪、PCA 的数值实现、乃至大模型的 LoRA 微调,全都落在同一句话上:留下能量最大的前 k 张卡片。

25 分钟
阅读 + 实操
3 个
交互演示
进阶
难度

奇异值与低秩 · 交互演示

最大奇异值 σ₁3.00
最小奇异值 σ₂1.00
中间步骤仅缩放
① SVD 三步曲:先旋转 Vᵀ → 再沿坐标轴按 σ 缩放 → 最后旋转 U。看背景网格与单位圆如何一步步变成椭圆
第一步旋转角 θ_v 0.0° 第三步旋转角 θ_u 0.0° 当前步骤 ③ U
点「播放三步曲」看完整过程。对称矩阵的 θ_u 与 θ_v 相等,两步旋转互相抵消 —— 这就是 ch03 里「只拉伸不偏转」的画面;换成剪切或旋转,两个角不再相等,你看到的就是特征分解给不出的那部分。秩 1 矩阵会把整个平面压成一条线,中间那步的 σ₂ 会变成 0。
② 低秩压缩:左为原图(64×48 灰度矩阵,3072 个数字),右为只保留前 k 个奇异值的重构结果
秩 k 8 保留数字 904 占原存储 29% 保留能量 89% 相对误差 11%
③ 奇异值能量谱:灰柱子是被丢弃的尾部(高度用平方根刻度,否则小奇异值看不见),紫线是累计能量
灰柱子的能量平方和,就是实验 ② 里那个相对误差 —— 这不是巧合,而是 Eckart-Young 定理:截断 SVD 是所有秩不超过 k 的矩阵里误差最小的那一个。噪声加进来以后,能量会摊到每一根柱子上,所以砍掉尾部就等于丢掉噪声。
保留秩 k 8
把 k 从 1 拉到 32:轮廓、渐变与那根亮条最先回来,右下角的棋盘细纹最后才被还原。注意「保留数字」是 k×(m+n+1) 而不是 k×m×n —— 列向量与行向量各存 k 组,这才是压缩的来源。真实模型矩阵往往是 4096×4096,秩 8 只需 2×4096×8 个数,比例不到 0.4%(见下方 LoRA 计算器)。
④ LoRA 参数量对比:全量微调要改 d×d 个数,LoRA 只训练 B(d×r) 与 A(r×d)
全量微调 d×d
16.8M
LoRA 2×d×r
65.5K
维度 d 4096
秩 r 8
LoRA 不修改原来的权重 W₀,而是把它冻住、只训练一个低秩增量 ΔW = BA:B 是 d×r、A 是 r×d,两者的乘积秩最多是 r。初始化时 B = 0,所以训练起点与原来完全一致。为什么低秩可行?因为微调带来的变化 ΔW 经验上确实集中在少数方向上 —— 而按 Eckart-Young,秩 r 的最佳近似就是它的截断 SVD。

为什么学这步?

现实里的数据矩阵几乎从不铺满整个空间:一张照片的相邻像素高度相关,一批句子的词向量挤在少数几个方向上。SVD 给出的正是「数据到底活在几个方向上」的精确定量答案,而且它是唯一在误差意义下最优的降维方式 —— PCA 的工业实现(scikit-learn、numpy)几乎都用 SVD 而不是显式的协方差矩阵特征分解,正是为了避免把条件数平方。同样的数学还解释了大模型微调:LoRA 用两个细长的矩阵乘出增量的效果,参数量能少两个数量级。

📌 发生了什么

  • 任何 m×n 矩阵都能写成 UΣVᵀ:旋转 → 沿轴缩放 → 再旋转
  • 奇异值恒为非负数并按从大到小排列,它的平方等于 AᵀA 的特征值
  • 只保留前 k 个奇异值得到的低秩矩阵,是所有秩不超过 k 的矩阵里误差最小的

⚠️ 常见陷阱

  • 奇异值不能为负,也没有虚数:别拿 σ = −2 当例子(特征值才可以)
  • 秩亏时 u = A v / σ 会数值爆炸,必须按容差把过小的 σ 直接取 0
  • U 与 V 的列符号并不唯一((−U)Σ(−V)ᵀ 同样合法),几何上只有方向有意义

本章小结

  • A = UΣVᵀ = Σ σᵢuᵢvᵢᵀ:把矩阵拆成按重要性排序的秩 1 卡片之和
  • σᵢ = √λᵢ(AᵀA),而且永远非负、降序;最大奇异值就是「最长拉伸倍数」
  • 截断 SVD 是最优低秩逼近:误差恰为尾部能量的平方根,这就是压缩、去噪与 LoRA 的共同依据

📐 为什么奇异值就是 AᵀA 特征值的算术平方根?

把 A = UΣVᵀ 代入 AᵀA。U 的列互相垂直(UᵀU 是单位矩阵),Σ 是对角矩阵,于是中间那一串会塌成 Σ²:

这正是对称矩阵的正交对角化:右奇异向量 vᵢ 是 AᵀA 的特征向量,σᵢ² 是对应的特征值,所以 σᵢ = √λᵢ(AᵀA)(算术平方根天然非负)。几何上,σ₁² 就是 A 把单位向量拉得最长的那条边的长度平方。但要注意:把这条式子当成算法是危险的 —— 形成 AᵀA 会把条件数平方,κ(AᵀA) = κ(A)²,量级很小的奇异值会先被舍入误差吃掉,这就是工业实现直接对 A 做 SVD 的原因。本章引擎用的是单侧 Jacobi:反复把 A 的两列旋转到互相垂直,转完之后列长就是奇异值,累积的旋转就是 V,全程不碰 AᵀA。

📉 Eckart-Young:为什么「砍掉尾部」是最优的?

A = Σ σᵢuᵢvᵢᵀ 说明矩阵是一叠秩 1 卡片,σᵢ 就是每张卡片的权重,而且已经按大小排好序。取前 k 张得到 A_k,误差正好是剩下卡片的能量:

右半边的不等式就是 Eckart-Young 定理:任何秩不超过 k 的矩阵都比 A_k 差,所以「砍掉最小的那些奇异值」不是一种启发式,而是最优策略。这也解释了去噪为什么有效:噪声的能量几乎均匀地摊在所有方向上(每张卡片都沾一点),而信号集中在最先的几张上 —— 砍掉尾部,丢掉的主要是噪声。反过来,如果数据本身就是高秩的(例如纯随机噪声图片),那就没有便宜的近似可用,这正是压缩前必须先看一眼能量谱的原因。

💻 单侧 Jacobi 与伪逆的核心

// 单侧 Jacobi:把 A 的每一对列旋转到互相垂直(节选自 svd-solver.ts)
function svdSweep(B, V, m, n, tol) {
  var rotations = 0;
  for (var p = 0; p < n - 1; p++) {
    for (var q = p + 1; q < n; q++) {
      var ap = colNorm2(B, m, n, p), aq = colNorm2(B, m, n, q);
      var gamma = colDot(B, m, n, p, q);      // 这一对列的内积
      if (Math.abs(gamma) <= tol * Math.sqrt(ap) * Math.sqrt(aq)) continue;
      var zeta = (aq - ap) / (2 * gamma);     // 使内积归零的旋转角
      var t = (zeta >= 0 ? 1 : -1) / (Math.abs(zeta) + Math.sqrt(1 + zeta * zeta));
      var c = 1 / Math.sqrt(1 + t * t), s = c * t;
      rotateColumns(B, V, m, n, p, q, c, s);  // 同时累积到 V 上
      rotations++;
    }
  }
  return rotations;                          // 本趟 0 次旋转 = 已收敛
}
// 转完所有趟之后:列长就是奇异值,B 除以列长就是 U,V 就是右奇异向量。
// 截断伪逆:小奇异值不能除,只能丢
function pseudoInverse(S, tol) {
  var cut = tol * S[0];                      // 相对容差,而不是绝对阈值
  return S.map(function (sig) { return sig <= cut ? 0 : 1 / sig; });
}

📚 参考文献与延伸阅读

  • Strang, Introduction to Linear Algebra, Ch. 7「Singular Value Decomposition」 — 把 A = UΣVᵀ 讲成旋转、缩放、再旋转的经典几何视角
  • Hastie, Tibshirani & Friedman (2009), The Elements of Statistical Learning, §14.5「Principal Components Analysis」 — 中心化数据矩阵的 SVD 与协方差矩阵特征分解的等价性
  • Golub & Van Loan, Matrix Computations, Ch. 2 §2.4-2.6 与 Ch. 8 — SVD 的存在性证明、单侧 Jacobi 算法与数值精度分析
  • Hu et al. (2021), LoRA: Low-Rank Adaptation of Large Language Models — 低秩更新在大模型微调中的工程落地;对照阅读 → ML 第 11 步 · PCA 降维DL 第 5 步 · 自编码器

📝 课后练习

检验你的理解——答对为止