VOL.III · 空间CH 12( 12 , 24 )

秩:信息的真实维度

Netflix 的评分矩阵有几千万行(用户)、几万列(影片),名义上是个天文数字的表格。但 2006 年那场著名的百万美元推荐算法大赛,冠军方案的核心假设只有一句话:这张巨表的秩,大概只有几十。人类的观影品味翻来覆去就那几十种成分,那张巨表只是薄薄的信息摊出来的大饼。「名义尺寸」与「真实信息量」之间的这道巨大落差,线性代数用一个字度量——(rank)。它是上一章「独立人数」的可计算版,是低秩压缩与 LoRA 的理论地基,也是这一卷最有工程分量的概念。

列空间零空间低秩压缩

秩:独立列的人数

定义直接续接上一章:把矩阵看成一排列向量(第 06 章:列 = 基向量的去向),秩 = 这些列里线性无关的最大人数 = 列们张成的子空间(列空间,column space)的维度。上一章代码里那个「名义 3 列、rank 2」的身高体重表,就是列空间只有 2 维——三根柱子里有一根是影子。秩的取值范围一目了然:从 0(零矩阵,一无所有)到 min(m, n)(顶配),顶配的矩阵称为满秩,寒酸的称为降秩亏秩

用变换的语言再说一遍更有画面:列空间是「所有可能的输出 Ax」组成的领土(Ax 是列的配方组合,跑遍所有配方,得到的正是列的张成)。于是秩 = 输出领土的维度 = 这台机器实际能产出多少维的花样。第 09 章「Ax = b 有没有解」的列图像也顺势有了标准术语:有解 ⇔ b 落在列空间里;秩越低,列空间越薄,合法的 b 越稀罕。一个 1000×1000 的矩阵,若秩只有 3,那它再怎么折腾,输出永远趴在一张 3 维的薄板上——999 维的输出空间里,绝大部分地址永远无人问津。

先备案一个安静的奇迹:行秩恒等于列秩。把矩阵横着看(一摞行向量)数出的独立人数,和竖着看数出的,永远相同——哪怕矩阵是 3×10000 的极端瘦长形。这不显然(行住在 ℝ¹⁰⁰⁰⁰、列住在 ℝ³,两个完全不同的世界!),证明要借第 17 章 SVD 才最透亮,但结论可以先用:说「秩」不必声明行列,它是矩阵本身的属性。顺带的推论:rank ≤ min(行数, 列数),3×10000 的矩阵秩至多 3。

零空间:被压死者名单

秩量的是「活着到达输出」的维度,它的镜像概念量「死在路上」的:零空间(null space,也叫核 kernel)= 所有被 A 送到零向量的输入 x 的集合(Ax = 0 的解集)。上一章「配出零的非零配方」在这里落了户:列相关 ⇔ 零空间里有非零居民。第 09 章的函数语言里它已客串过:零空间只剩 {0},变换才是单射、才不撞车。零空间自身是个子空间(两个被压死的向量相加还是被压死——线性!),它的维度俗称「零度」(nullity),量的是输入中被彻底抹除的自由度

两本账合起来,是一条优美的守恒律,秩-零度定理:

rank(A) + nullity(A) = nn = 输入维度(列数)

读法:输入的每一个自由度,要么活着到达输出(计入秩),要么被压死在路上(计入零度),没有第三种下场,也没有一个能溜号。像质量守恒一样朴素:信息不会失踪,只会改判去向。用它口算几个例子:2×2 矩阵把平面压成直线(秩 1),则必有 1 维的输入被抹除——正是 Demo 里那条「整条线被压到原点」的方向;3×2 矩阵(平面进三维)秩至多 2,若秩恰为 2,零度为 0,没有输入被压死——升维不丢信息,第 06 章的「贴画」承诺兑现;而任何「输入维度 > 输出维度」的矩阵(比如 2×3,三维拍到平面),零度至少 3 − 2 = 1,必然有输入被压死——降维必丢信息,这次是定理,不是修辞。

◈ 几何直觉

把矩阵想成一台投影仪:输入空间里,有一部分方向被灯光「照到幕布上」(秩),另一部分方向恰好与光线平行、在幕布上缩成一个点(零空间)。守恒律说的是:光线方向数 + 幕布上的像的维度 = 输入总维度。顺带一提,「方阵满秩 ⇔ 可逆」现在有了第三种证法:满秩 ⇒ 零度为 0 ⇒ 没人被压死 ⇒ 单射,而方阵单射自动满射(第 09 章)⇒ 双射 ⇒ 可逆。行列式、秩、零空间三条线索在「可逆」这里会师。

半张地图:四个基本子空间

列空间与零空间还有两个孪生兄弟,凑成教科书说的「四个基本子空间」。把 A 转置(行变列),Aᵀ 的列空间就是 A 的行空间(行们张成的领土),Aᵀ 的零空间叫 A 的左零空间。全书不打算深挖后两个,但值得挂半张地图在这里,因为有一条关系美得该看一眼:行空间与零空间互相垂直——Ax 的每个分量是「A 的一行点积 x」,x 被压死(Ax = 0)恰好意味着 x 垂直于每一行,也就垂直于整个行空间。输入空间被切成两半:与行空间平行的部分活着通过,垂直的部分(零空间)原地蒸发。第 14 章的投影会把「垂直分解」这个动作变成日常工具,第 17 章的 SVD 则给四个子空间各配一组标准正交基,一次性把整张地图画完——现在只需存档:矩阵把输入空间「按垂直」劈成生与死两份

秩怎么算:从主元到奇异值

手工时代数秩靠高斯消元:消完元数「主元」(每行第一个非零位)的个数——每个主元代表一根真正独立的方向。这个方法逻辑正确,数值上却经不起浮点噪声(该是 0 的位置算出 10⁻¹⁶,主元凭空多一个)。现代做法一律走 SVD 路线,顺手玩一个 Netflix 迷你版:

toy_netflix.py
import numpy as np

# 捏一个「品味只有 2 种成分」的世界:动作片浓度 & 文艺片浓度
taste  = np.random.randn(100, 2)    # 100 个用户 × 2 维品味
flavor = np.random.randn(2, 50)     # 2 维气质 × 50 部影片
R = taste @ flavor                  # 100×50 的评分矩阵

np.linalg.matrix_rank(R)            # 2 —— 五千个格子,两维信息

R_noisy = R + 0.01 * np.random.randn(100, 50)
np.linalg.matrix_rank(R_noisy)      # 50!噪声把秩顶满了

s = np.linalg.svd(R_noisy, compute_uv=False)
(s > s[0] * 0.05).sum()             # 2 —— 阈值一卡,有效秩现形

这十行浓缩了本章的全部要点:构造(低秩世界)、诊断(名义秩 vs 有效秩)、以及为什么「秩」在实践里必须配阈值服用。把 0.01 的噪声调大调小,看有效秩什么时候开始糊——这是比任何习题都直观的「信噪」体感。真实的 Netflix Prize 冠军当然比这十行复杂(偏置项、时间效应、隐式反馈),但矩阵的骨架与这里一字不差。

低秩 = 可压缩:一笔参数账

秩的工程价值一半在这笔账上。第 07 章的外积视角说过:秩 1 矩阵 = 一支列向量乘一支行向量,m×n 的地盘、m+n 的信息;而秩 r 的矩阵总能写成 r 张秩一薄片的叠加,等价地:

Am×n = Bm×r · Cr×n秩 r ⇔ 能过一条 r 维的窄走廊

存储从 m×n 掉到 (m+n)×r,计算(乘一支向量)同步从 2mn 掉到 2(m+n)r。m = n = 4096、r = 8:参数 1678 万 → 6.6 万,缩水 254 倍。这个分解形状还给了秩第三种读法:信息流过一条宽度为 r 的走廊——先被 C 压进 r 维,再被 B 铺回 m 维。走廊多宽,信息最多多宽;这就是 rank(AB) ≤ min(rank A, rank B) 的直觉:串联的管道,流量由最细处决定。

低秩分解 B·C 还有个值得玩味的副作用:它不唯一——B·C = (BM)(M⁻¹C) 对任何可逆的 r×r 矩阵 M 都成立,「品味成分」的坐标系可以随意旋转。所以矩阵分解学出的隐因子没有天然的名字,你看到的「第 3 维≈动作片浓度」是人事后贴的标签,换个随机种子它可能变成第 7 维。这个「因子只定子空间、不定坐标」的现象,在词向量、PCA、autoencoder 里全都出现,提前知道能省掉很多「为什么复现不出同样的维度含义」的困惑。

Netflix 矩阵分解现在可以完整讲了:把评分矩阵近似成 B·C,B 的每行是一个用户的 r 维「品味向量」,C 的每列是一部影片的 r 维「气质向量」,预测评分 = 品味点积气质(第 04 章!)。训练就是找让已知评分误差最小的 B、C。「秩 r」的假设,本质是断言:人类品味的自由度只有 r。假设不完美,但足够真——这套矩阵分解统治了推荐系统十年,至今仍是各大厂召回层的基石之一;今天的「双塔模型」把 B、C 换成两个神经网络,骨架仍是「用户向量点积物品向量」,秩假设换了副皮囊继续营业。

◆ AI 连接

LoRA 的核心假设终于可以原文引用了:「预训练模型的权重更新具有低内在秩(low intrinsic rank)」——微调让 W 变成 W + ΔW,而实验发现 ΔW 用秩 8 甚至秩 4 的 B·A 形式就够用。为什么?一种直觉:预训练已经把「基」学好了(模型内部的语义方向),微调只是把少数几个方向重新组合、微调权重,自由度天然很低——像调音师只动几个推子,不重造调音台。于是 7B 模型的微调参数从 70 亿降到几百万,单卡可训。另外注意力头也是一条「窄走廊」:Q、K 把 4096 维压到每头 128 维再做点积——注意力分数矩阵天生是低秩瓶颈的产物,这个设计选择的得失,研究界至今还在争论。

秩当体检表:表示塌缩的诊断

秩还是深度学习的一件诊断工具。把一批样本喂给模型,收集某一层的输出(比如 1000 个样本 × 4096 维激活),摞成矩阵,量它的有效秩——这张「体检单」能查出几种病:

  • 表示塌缩(collapse):自监督学习的经典翻车姿势——模型发现「把所有输入都编码成同一个向量」能完美糊弄损失函数,于是表示矩阵的有效秩掉到个位数。SimSiam、BYOL 这些方法的种种「防塌缩」设计(stop-gradient、predictor),疗效都可以用「表示秩没有塌」来验收;有一族论文干脆直接把有效秩当训练监控指标。
  • 维度浪费:4096 维的层,表示有效秩只有 300——不一定是病(流形假设本来就预言内在维度低),但如果两层之间秩骤降,常提示信息瓶颈或者死神经元成片(ReLU 全负,输出恒零,整维躺平)。
  • 灾难性遗忘的前兆:持续学习里,新任务的梯度若始终落在旧表示的低秩子空间外,旧知识的方向就会被逐步覆写——「梯度投影」类方法(把新梯度投影到旧知识零空间里更新)直接用本章 + 下一章的语言设计算法。

这一小节的姿态比结论重要:「量一量激活矩阵的秩」是一个成本极低、信息量极高的调试动作,就像 Android 性能排查先抓一次 systrace。你以后训练模型遇到诡异行为,工具箱里多了一件趁手的。

数值秩:真实世界的秩长满毛边

理论的秩非黑即白:向量组要么相关要么无关。真实数据全是毛边:身高和体重不精确共线,但相关系数 0.9;传感器两路信号几乎重复,但各带噪声。严格地数,噪声让一切矩阵都「满秩」——每根列都被随机毛刺捅出了一点新方向,可那点「新」全是垃圾。所以工程上用数值秩:把矩阵的奇异值(第 17 章,可暂读作「各独立方向上的信号强度」)从大到小排,数「明显大于零」的有几个,微小的尾巴按噪声处理。np.linalg.matrix_rank 就是这么实现的:SVD + 阈值。

这带来一个观念升级:秩在实践中不是一个整数,而是一条衰减曲线——奇异值谱掉得多快,信息就集中得多狠。「有效秩 20 的一亿维矩阵」这句话的含义是:前 20 个方向扛了绝大部分能量,剩下的可以扔。第 17 章的图像压缩 Demo 会把这条曲线画给你看,拖一根滑杆亲手选「留几个方向」。

顺便把上一章遗留的「几乎相关怎么办」正式收编:一组向量「几乎相关」⇔ 它们拼成的矩阵最小奇异值接近零 ⇔ 衰减曲线的尾巴贴地。条件数(最大奇异值 ÷ 最小奇异值)就是这条尾巴的体检读数——上一章代码里那行 s[0] / s[-1],现在你知道它在量什么了。理论问「秩是几」,工程问「曲线多陡」,两个问题共用一套奇异值语言。

▸ Android 类比

你其实见过秩一矩阵的「实物」:LinearGradient 着色器画出的渐变图。一张从左到右由暗变亮的灰度渐变,第 (i, j) 像素值 = 行权重 × 列亮度,整张图 = 一支列向量外积一支行向量——如假包换的秩一矩阵,信息量 = 宽 + 高,而非宽 × 高。反过来,一张真实照片秩很高,但奇异值衰减很快(自然图像的规律),所以「有损压缩」有利可图。JPEG 用的是 DCT 基而非 SVD(为了全图统一、硬件友好),但「把能量集中到少数方向、砍掉长尾」的哲学同宗同源。

⚠ 坑

秩 ≠ 非零元素个数:全 1 矩阵(每个元素都是 1)非零元拉满,秩却是 1(所有列相同);对角矩阵 diag(1,2,3) 只有 3 个非零元,秩 3。秩数的是方向,不是数字。② 秩没有连续性:矩阵元素抖动 10⁻¹⁵,秩可以从 1 跳到 2——这正是必须用「阈值化的数值秩」的原因,也是为什么不要在代码里写 if rank(A) == k 这种脆皮判断。③ rank(A + B) ≤ rank(A) + rank(B),但没有下界保证:两张秩 5 的薄片相加可以恰好抵消成零矩阵。低秩结构在加法下不保值,在乘法下不增值——记这两条,读矩阵分解论文时够用。

✋ 动手自测

① 全 1 的 5×5 矩阵秩是多少?它的列空间和零空间各长什么样?

② 一个 4×6 矩阵秩最多几?若秩为 4,零度是多少,几维输入被压死?

③ 4096×4096、秩 16 的矩阵用 B·C 形式存,参数量与压缩比?

④ 为什么 LoRA 把 A 初始化为随机、B 初始化为零?(提示:训练开始时 ΔW 应该是什么?)

⑤ 你的评分矩阵 matrix_rank 返回 998(接近满),但前 30 个奇异值占了 99% 能量——这矩阵到底「秩几」?两种答案各在什么意义上正确?

小结

秩 = 独立列的人数 = 列空间(输出领土)的维度,行秩列秩恒等,取值 0 到 min(m,n);零空间收容被压死的输入,秩-零度定理是维度的质量守恒;秩 r ⇔ 矩阵能过 r 维窄走廊 ⇔ (m+n)r 的存储,低秩因此即压缩,推荐系统与 LoRA 都押注「人类品味/微调更新的自由度很低」;真实数据的秩长满噪声毛边,工程用奇异值阈值数「有效方向」。秩还能给模型做体检:表示塌缩、死神经元、遗忘风险,一行 matrix_rank 起查。你可能注意到「奇异值」已经被预支了三次——它是卷四的主角,行秩等于列秩、四个子空间的全图、有效秩的曲线,全要靠它一锤定音。但在见它之前,还差两块地基:同一支箭在不同基下的读数怎么换算(下一章),以及「够不着时怎么办」的投影术(第 14 章)。