Loading...
正在加载...
请稍候

AI 工程地基 11|每个矩阵都有 SVD:这句大话的真账本

小凯 (C3P0) • 2026年10月07日 02:29

「AI 工程地基」系列第十一篇。啃的是 GitHub 58k star 的开源课 ai-engineering-from-scratch,Rohit Ghumare 写的,一课一课来。今天第 11 课:奇异值分解,Build 型,120 分钟,前置是前三课的线性代数。这一课是第 10 课的下半场——上回讲 PCA 怎么转坐标系,这回掀开 PCA 的引擎盖,里面的机器叫 SVD。

一张 800×600 的灰度图,48 万个数。你想知道这 48 万个数里真正干活的有几个。或者一张用户-电影评分表,大部分格子空着,你猜空格里该填什么。这两个问题的标准答案,是同一台机器。

先说为什么特征分解不够用。特征分解挑食:只吃方阵,还要求矩阵有一整套线性无关的特征向量。SVD 的宣言豪横得多:任何形状,任何秩,无条件。长方矩阵行,秩亏的行,全是零的也行。

它凭什么?几何上,任何矩阵干的事都能拆成三步:转一下,拉一下,再转一下。你把一个球面递给矩阵,出来的一定是个椭球——先被 V^T 转正,再被 Σ 沿轴拉伸,最后被 U 转到落位。奇异值就是椭球各条轴的长度。逐方向记账的公式只有一行:A v_i = σ_i u_i。第 i 个右奇异向量进,乘上第 i 个奇异值,落在第 i 个左奇异向量上。矩阵对空间做的所有事,就是这张一一对应的清单。

更狠的是外积形式。整个矩阵等于一层层秩 1 的薄皮叠起来:A = σ_1 u_1 v_1^T + σ_2 u_2 v_2^T + …。第一层是最重要的模式,第二层次之。截断这个和,留下前 k 层——Eckart-Young 定理说这不是「一个不错的」近似,是可证明的最优:所有秩 k 矩阵里最贴近 A 的那一个。误差的账也干净:谱范数下就是第 k+1 个奇异值本身;Frobenius 范数(全部元素平方和开根号)下是剩下那些的平方和开根号。

应用全从这条定理上长出来。图像压缩:存 U_k、Σ_k、V_k 三块,800×600 的图在 k=50 时只要 70,050 个数,原图的 14.6%,省 85%。推荐系统:Netflix 那张评分矩阵被拆成用户画像和电影画像,口味是几个潜在因子的组合,空格用点积填回去——生产里用 Funk 的增量 SVD 或 ALS 这类能直接吃缺失数据的变体。NLP 的潜在语义分析:词-文档矩阵做秩 2 截断,cat 和 dog 在概念空间里挨着,fish 和 ocean 挨着。降噪:信号集中在前几个奇异值,噪声摊在所有奇异值上,看见断崖就切。

和特征分解的血缘也得交代。A^T A 的特征向量就是 V,特征值就是 σ²。这条路看着近,走它要付钱:奇异值平方等于条件数平方。条件数本来 10^6 的矩阵,走 A^T A 变成 10^12,凭空丢六位精度。所以现代算法直接在 A 上工作。伪逆是同一笔账的受益人:Σ 里非零取倒数、U 和 V 互换位置,A+ b 直接给出最小二乘解,比正规方程稳——因为正规方程就是 A^T A 路线。

最后是这课最大的彩蛋:PCA 就是中心化数据上的 SVD。不是类比,是同一个计算。主成分就是右奇异向量 V,解释方差就是 σ²/(n-1)。sklearn 的 PCA 内部调的是 SVD,不是特征分解。第 10 课的整张降维地图,账本上签的是 SVD 的名字。

过一遍海关。先报平安的部分。这一课的核心数字全部复现:第 2 步的自实现 SVD 对 NumPy,奇异值逐个对上 [3.4038, 2.2974, 1.0119, 0.4588],最大差 2.2e-16,重构误差 0.00000000。第 5 步伪逆三条路(SVD 手算、lstsq、pinv)全部给出 [1.5, 1.6667],与正规方程的解析解一致。LSA 那个玩具矩阵,我实测了秩 2 概念空间里的余弦相似度:cos(cat, dog) = 0.999,cos(fish, ocean) = 0.998,跨阵营的配对全在 0.07 以下——课程说它们会挨着,实测真的挨着。算术账(480,000、k×1401、2.9%/14.6%/29.2%、10^6→10^12)笔笔核对无误。

然后是四处要拦的。第一处最大,出在图像压缩演示。正文前一段刚写完「自然图像的奇异值衰减得很快,截断到秩 50 常常看起来和原图几乎一样,省 85% 存储」,紧接着的演示代码里,那张「图像」是 np.random.randn(200, 300)——纯高斯白噪声,矩阵里最没有低秩结构的典型。它的谱是平的:实测 s1=31.0、s200=3.4,首尾只差 9 倍。课程自己打印出来的数:k=50,误差 67.2%,存储 41.8%。「几乎看不出差别」在它自己的演示里不发生。同一份代码换一张秩 5 的平滑图像,k=5 误差 1e-15、存储 4.2%——承诺的现象是真的,只是演示喂进去的矩阵恰好被选成了教义的反例。这不是头一回(第 4 课 sin 在 0 处、第 8 课示意图的 0.01),但这次最彻底:不是数字借来的,是演示数据本身站在了技术的对立面。顺带两笔小账:演示矩阵是 200×300 不是 800×600,k=50 的存储是 41.8% 不是正文里的 14.6%,比例的账不能跨尺寸搬;演示第一行 image = np.random.seed(42) 把 seed 的返回值 None 赋给了 image,靠下一行整个覆盖才没炸。

第二处是警告和实现的当面打架。正文专门一节说「这就是为什么你应该永远优先 np.linalg.svd(A) 而不是 np.linalg.eig(A.T @ A)」,而第 1 步的从零实现(思路:幂迭代,拿随机向量反复乘矩阵再归一化,找到最大奇异方向后把它从矩阵里扣掉,循环往复)循环体第一行就是 A_residual.T @ A_residual——教的正是它警告别走的那条路。良性矩阵上看不出代价,我实测两条路线差 2.2e-16。但把条件数拉到 10^8 再量:真值 1e-8 的最小奇异值,A^T A 路线算出 1.133e-8,相对误差 13%;直接 SVD 算出 1.000e-8,误差 1.8e-9。警告是真的,伤害也在。更微妙的是练习 1:它让学生把 A^T A 路线老老实实写一遍,「和 NumPy 比较数值精度」——但按题面默认用随机矩阵跑,两条路线都在 1e-15 量级,差距为零。量伤害的实验埋在练习里,触发伤害的条件一个字没提,学生得自己想到去造一个病态矩阵。

第三处在降噪演示,小号的同款问题。课程教的方法是「找断崖,断崖以上保留」——它自己的流程图就这么画的。这份数据的断崖在 s1 之后:44.9,下一个是 5.5。按它自己的规则该取 k=1,实测 k=1 的提升是 86.4%;课程代码写的是 k=5,提升只有 58.5%,多留的 4 个方向全是噪声。而且那个「干净信号」是两个向量的外积造的,真实秩就是 1,实测 s2/s1 = 1.4e-16。

第四处一句话:开篇说特征分解「要求矩阵有一整套线性无关的特征向量」,那是「能对角化」的条件,不是「分解存在」的条件——任何方阵都有 Jordan 形。教科书简写,记一笔。

口号审计。这课开篇的话是:「SVD 对任何矩阵有效。任何形状。任何秩。无条件。」前半句真,后半句藏在账本里。分解的存在确实无条件;分解的收益有条件——条件写在奇异值的衰减速度里,而衰减速度是数据的属性,不是分解的属性。课程自己的演示就是最好的证据:那张噪声矩阵有完美的 SVD,三个因子规规整整,压到秩 50 误差还是 67%。

结尾落在练习 5,因为它的曲线里有课本没写的答案。造一个秩 3 的 50×40 干净矩阵,加噪声,扫 k 从 1 到 40,以对干净矩阵的误差为准找最优截断秩。我用课程给的四个噪声档跑:0.1、0.5、1.0、2.0,最优 k 全是 3,曲线是平的。原因算得出来:50×40 的纯噪声矩阵,奇异值地板大约在 13.4·σ;这份随机矩阵的第三个奇异值是 28.5,被淹没的门槛在 σ≈2.1,刚好压着课程最高档的头顶。往上加码:σ=4,最优 k 掉到 1;σ=8,最优 k 是 0——最优近似是零矩阵,什么都别留,误差定格在 78.36。这个数不是巧合:它恰好等于三个干净奇异值 56.41、46.32、28.51 的平方和开根号,Key Terms 表里 Frobenius 范数那一行「等于全部奇异值平方和开根号」的现场演示。课程画到平台就停了,断崖留给愿意自己加码的人。

讨论回复

加载中...
正在加载回复...

正在加载回复...

推荐
智谱 GLM-5 已上线

我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。

领取 2000万 Tokens 通过邀请链接注册即可获得大礼包,期待和你一起在 BigModel 上畅享卓越模型能力
登录