基变换:换个坐标系看世界
今天 25°C,也是 77°F——温度只有一个,读数有两个。北京时间 20:00,东京时间 21:00——时刻只有一个,时区有两个。这一章把这个常识升级成线性代数的核心操作:同一支箭,在不同的基下有不同的坐标;基变换就是读数之间的汇率换算。它值得单独一章,因为「换个坐标系,问题会突然变得简单」是整个卷四的总战略——对角化、SVD、PCA,全是一次次精心挑选的换基;而大模型的 embedding 空间,就是机器自己发明、并且从不向人类报备的一套「私有时区」。
箭头是客观的,读数是相对的
第 02 章埋的那颗雷,现在正式引爆:「向量就是它的坐标」——错了半步。箭头是空间里的客观存在;坐标是某组基对它的描述,基一换,数字全换,箭头分毫未动。这个区分不是哲学洁癖:模型 A 和模型 B 各训练了一套词向量,「国王」在两边的坐标毫无共同点,但「国王−男人+女人≈女王」的几何关系两边都成立——可迁移的是关系,不是数字。分不清这两层的人,会在「为什么两次训练的 embedding 完全不同却都能用」这个问题上卡很久。
规矩立在前面:第 11 章已经给了这件事完整的法律框架:任何一组基下,每支箭都有唯一配方(坐标)。现在的问题只剩技术性的:两套配方之间怎么换算?
设新基是 {b₁, b₂}。把它们(在标准基下的坐标)按列拼成矩阵 B——这就是基变换矩阵。设某支箭在新基下的读数是 [p]B = (c₁, c₂),意思是「c₁ 份 b₁ 加 c₂ 份 b₂」。那么它的标准坐标就是把这份配方真的调出来:
注意方向,这是全章第一坑:乘 B 是「从新读数翻译回标准读数」——因为 B 的列本身就是用标准语言写的,「按配方组合 B 的列」(第 06 章)当然产出标准语言的结果。反过来,想从标准读数求新读数,就得撤销这次翻译:
不用背方向,用「量纲」自查:B 的列是新基向量,基向量越「长」,同一支箭需要的份数越少——所以求新读数要除以基的尺度,即乘 B⁻¹。就像换算英寸:厘米数除以 2.54,而不是乘。
玩法:紫色的 p 是那支「客观的箭」,灰网格是标准制度,青色斜网格是 {b₁, b₂} 立起来的新制度,青色虚线画出「先走几份 b₁、再走几份 b₂」的记账路径。三样东西都能拖,每一种拖法回答一个不同的问题:① 只拖 p:两套读数一起变——一个事实,两份报表;② 只拖 b₁ 或 b₂:标准读数纹丝不动,新读数全盘刷新——改的是制度,不是事实;③ 沿着青色网格线数格子,验证新读数确实是「沿 b₁ 几步、沿 b₂ 几步」;④ 把 b₁、b₂ 拖到几乎共线,看新读数飙到几十——快塌的制度,记账代价爆炸(第 09 章病态的另一现场);⑤ 把 b₁、b₂ 摆成垂直等长再拖 p,体会「好制度」下读数的安稳:这就是全世界偏爱标准正交基的手感版理由。
一次完整的手算
全书极少让你手算,这里破例一次,因为这个换算做过一遍就永远不慌。新基取 b₁ = (1, 1)、b₂ = (−1, 1)(一套逆时针转了 45° 且√2 倍放大的制度),箭 p 的标准读数 (3, 1)。基矩阵与它的逆(用第 09 章的二维公式,det = 2):
验算(兑现配方):2·(1,1) + (−1)·(−1,1) = (2+1, 2−1) = (3,1)。✓ 同一支箭:标准报表说 (3,1),新报表说 (2,−1)。读数变小了一号,和「量纲自查」的预言一致——新基向量长 √2 倍,份数自然缩水。把这组数字搬进 Demo 摆一摆,看两份读数同时亮出来——手算与拖拽对上的那一刻,「方向之谜」就此了结。
主动还是被动:一字之差的百年混乱
有一个困惑值得专门立牌:「旋转 45°」到底是把箭头转 45°(坐标系不动),还是把坐标系转 45°(箭头不动)?两者都合法,数字效果互为反向——箭头逆时针转 45°,读数的变化恰好等于坐标系顺时针转 45°。物理学管前者叫主动变换(active),后者叫被动变换(passive);无数教材、论文、图形库在这里各自为政,是「公式对着抄却出负号」的头号来源,也是图形程序员集体的童年阴影。
本书的约定一直是主动视角(第 06 章:矩阵抓着空间拧,坐标纸是观众);本章的基变换则是被动视角(箭头钉死,制度更换)。两副眼镜随时切换,靠一个问题定锚:「动的是世界,还是我的尺子?」写图形代码时这个问题极其具体:Canvas.rotate(45f) 转的是后续绘制内容的坐标系(被动——你随后画的「竖线」会歪),而给 View 设置 rotation = 45f 转的是 View 本身(主动)。分不清的下场,是转反方向再补一个负号了事——现在你可以优雅地分清了。
变换也要翻译:B⁻¹AB 三明治
坐标要换算,变换的说明书也要。假设某变换在标准基下的矩阵是 A,新制度的用户想要一份「用新读数直接算」的说明书 A′:输入新读数,输出新读数。没有捷径,只有一条三段式流水线——先翻译、再办事、再翻译回来:
从右往左(第 07 章的洋葱读法):B 把新读数翻成标准读数,A 在标准世界里干活,B⁻¹ 把结果翻回新读数。三段各司其职,没有一段可以省——直接拿 A 去乘新读数,等于拿着人民币价目表收美元,数字对不上是必然的。这个「三明治」结构在数学里叫相似变换,A 与 A′ 叫相似矩阵——它们数字长相可以天差地别,但描述的是同一个变换,只是各自效忠不同的坐标制度。相似矩阵共享一切「客观」性质:同样的行列式(面积倍数不因记账制度而变)、同样的秩、同样的特征值(下一章的主角)——这些量因此配称「不变量」,它们属于变换本身,不属于任何坐标系。
三明治的画面感可以更足:你是新制度的公民,手里的 A′ 就是「本地办事指南」;B⁻¹AB 说的是,任何本地指南都等价于「先出国(B)、在标准国办事(A)、再回国(B⁻¹)」。整个卷四的战略从这句话里长出来:与其在歪坐标里硬算复杂的 A′,不如去找一个让说明书变得极简(最好是对角!)的国度。那个国度的移民签证,叫特征向量。
为什么要折腾换基:三大动机
动机一:让矩阵变简单。同一个变换,换个基,说明书可能从密密麻麻变成寥寥几笔。举个立刻能想象的例子:「沿 45° 斜线镜像」在标准基下是个四个元素全非零的矩阵,但如果把基换成「沿镜面的方向 + 垂直镜面的方向」,说明书立刻变成 diag(1, −1)——镜面方向不动,垂直方向翻号,完事。极端目标是换到「特征基」让矩阵彻底对角化(第 16 章)——对角矩阵的一切特权(第 10 章)瞬间到账:幂好算、逆好求、行为全透明。「换基解题」是线性代数的第一心法:难的从来不是问题,是你看它的角度。
动机二:让数据变好压。数据云在标准基下可能斜着摊开、每个轴都有份量;转到「主轴基」后,方差集中到前几根轴,后面的轴薄得可以整根扔掉——这就是 PCA(第 18 章),YUV 之于 RGB(第 11 章)是它的手工版,上一章「奇异值衰减曲线」量的正是换到最优基后各轴的份量。压缩的本质是找到让信息「靠边坐」的基。
三个动机之上还悬着一条元定律,值得单独一段。物理学家早就发现:自然规律不在乎你选什么坐标系(伽利略的船舱、爱因斯坦的电梯),坐标是人的发明,规律属于世界;因此「换坐标不变的量」比坐标本身更真实。线性代数是这条哲学的初级教程:det、秩、特征值是变换的「物理量」,坐标只是报表格式。带着这个觉悟看机器学习也会通透很多——模型内部的坐标(神经元编号)是训练的偶然产物,值得研究的是那些换基不变的结构:子空间、谱、距离关系。追问「哪些量是坐标无关的」,是从会算到懂行的分水岭。
动机三:让语义变可读。模型的 4096 维激活,在默认坐标(神经元编号)下多半是一锅粥——单看第 217 号神经元,既管「猫」又管「税务」还管「悲伤」(第 11 章的叠加)。可解释性研究的一大流派,就是在给残差流找一组更会说话的基:稀疏自编码器(SAE)学出几万个方向,每个方向尽量只对应一个人类可读的概念——「金门大桥方向」「谄媚方向」。用本章的话说:解释一个模型 ≈ 为它的内部空间寻找语义对齐的基变换——模型不欠你一个可读的坐标系,可读性要自己去换。
史上最著名的换基:傅里叶
如果评选「一次换基创造的最大产值」,冠军毫无悬念:傅里叶变换。把一段音频看成向量(每毫秒一个采样值,第 02 章),它默认的基是「时间基」——每根轴代表一个时刻。傅里叶说:换一组基,用「各频率的正弦波」当基向量,同一段声音的读数就从「每时刻多响」变成「每音高多少份」。一段旋律,时间报表和频率报表,同一个客观对象。
换完基,奇迹排队发生:均衡器(EQ)= 在频率基下调几个系数;降噪 = 把高频轴的读数砍掉;MP3/JPEG 压缩 = 频率读数里人耳/人眼不敏感的那些轴,粗暴量化甚至归零(JPEG 用的 DCT 就是傅里叶的实数亲戚,第 11、12 章两次预告的「余弦基」);你手机相册每一张照片、每一段视频,都是被这次换基处理过才存下来的。这些操作在时间基下无从下手,在频率基下是逐分量的体力活——动机一(变简单)、动机二(好压缩)的百年老店。深度学习登场前,信号处理的半壁江山就是「傅里叶基下的线性代数」;登场后也没退休:位置编码的正弦波、扩散模型的频谱分析、语音模型的梅尔频谱,都是它的分号。
写成代码:换算与对齐
import numpy as np B = np.array([[1.0, -1.0], # 列 = 新基向量 [1.0, 1.0]]) p = np.array([3.0, 1.0]) coords = np.linalg.solve(B, p) # [2., -1.] 新读数(solve 不 inv!) B @ coords # [3., 1.] 兑现配方,回到标准 # 微型「空间对齐」:已知两套坐标下的同一批锚点,反求换基矩阵 X_old = np.random.randn(100, 2) # 100 个点的旧读数 theta = np.deg2rad(30) R_true = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]) X_new = X_old @ R_true.T # 新读数(被偷偷转了 30°) R_hat, _, _, _ = np.linalg.lstsq(X_old, X_new, rcond=None) np.allclose(R_hat.T, R_true) # True:汇率被反推出来了
第二段就是跨语言词向量对齐的两百维、三十万词版本的玩具模型:锚点(双语词对)+ 最小二乘(下一章!),解出两个私有坐标系之间的汇率。真实版会再加一步「强制正交化」(Procrustes 问题,用第 17 章的 SVD 一步到位)——本书的伏笔网又收紧了一格。
「两个 embedding 空间的对齐」是基变换的高频实战。经典案例:英语词向量空间和西班牙语词向量空间各自独立训练,坐标毫不相干,但研究者发现两团点云的形状惊人相似——于是用几百对已知译文当锚点,解一个「最优旋转」(正交的基变换,保持所有内部距离),就能把两个空间转到对齐,没见过的词也自动找到译文近邻。同样的手法用于:新旧版本模型的表示对接(model stitching)、多模态里图文空间的互译(CLIP 的双塔投影)、甚至神经科学里「人脑激活 vs 模型激活」的对齐分析。凡是「两套私有坐标系、一个共同世界」的场合,解法都是找那个 B。
你每天都在一摞坐标系里编程:屏幕坐标、window 坐标、View 本地坐标、Canvas 当前坐标——getLocationOnScreen()、MotionEvent.getRawX() vs getX() 的区别,就是「标准读数 vs 本地读数」。而 Canvas.save()/restore() 维护的正是一个基变换栈:每次 translate/rotate/scale 都在当前制度上再叠一层新制度,子 View 在自己的小世界里画画,浑然不知外面转了几道。「在本地坐标里画,让矩阵栈负责翻译」——UI 框架早就把 B⁻¹AB 的哲学做成了 API。
① 方向恒混淆:B 到底管哪边?一劳永逸的锚点:B 的列是新基向量(用标准语言写的),所以乘 B 的输出必然是标准语言——由此反推一切。② 三明治别拼反:B⁻¹AB 和 BAB⁻¹ 都出现在文献里,取决于作者把「翻译」定义成哪个方向,读论文先核对作者的约定,别默背。③ 汇率也有病态:新基快共线时 B⁻¹ 病态(Demo 玩法④),读数不可信;所以实践中偏爱正交基——B⁻¹ = Bᵀ,翻译零成本、零风险,这是标准正交基「特权」清单里最闪的一条。
① 新基 b₁=(2,0)、b₂=(0,1),箭 p 的标准读数 (4,3)——新读数是多少?(先直觉:b₁ 长一倍,第一个读数该变大还是变小?)
② 在 Demo 里把 b₁、b₂ 摆成互相垂直且等长,新读数与标准读数的换算发生了什么质变?
③ 为什么相似矩阵的 det 必然相等?可以用「面积倍数是客观事实」一句话答,也可以用 det 的乘法性硬算 B⁻¹AB 验证;
④ 为什么跨语言词向量对齐要限定「正交」变换,而不允许任意可逆矩阵?(提示:允许拉伸剪切会破坏什么?)
⑤ Canvas 上 rotate(45°) 后画了一个「竖直」矩形,屏幕上它是斜的——「竖直」这个词效忠于哪个基?
小结
箭头客观、读数相对;基变换矩阵 B 的列是新基向量,乘 B 兑现配方(新→标准),乘 B⁻¹ 查询读数(标准→新);「动世界」与「动尺子」是互为反向的两副眼镜,写图形代码前先问哪个在动;变换的翻译是三明治 B⁻¹AB,相似矩阵是同一变换的不同报表,det、秩、特征值是不随报表变化的硬通货;傅里叶用一次换基撑起了信号处理的半壁江山;换基的三大回报——矩阵变简单、数据变好压、语义变可读——分别指向对角化、PCA 与可解释性。「找一个好基」从此是你的主动策略,而不是被动接受的坐标纸;坐标无关的量才是值得研究的量,这条物理学家的信条同样适用于读模型。下一章就去找那个最好的基:有些方向,变换动不了它们的朝向,只能缩放——特征向量,变换自己泄露的天机。