范数与距离
风控系统盯着一笔交易的特征向量,只问一句话:「它离正常交易的中心有多远?」超过阈值,拦截。上一章我们量了「方向像不像」,这一章补上另一半度量衡:「多长」与「多远」。听起来像小学问题——拿尺子量呗——但线性代数会告诉你:尺子不止一把,而且选哪把尺子,会实实在在地改变模型的性格:一把让权重普遍变小,另一把让权重大批归零。这就是正则化的几何真相,也是本章的终点站。
L2:从点积里出生的那把尺
「长度」的正式名字叫范数(norm),记作 ‖v‖。最正统的一把尺,上一章结尾已经埋好了:向量点乘自己,得到长度的平方——那么开个根号就是长度本身:
这叫 L2 范数(欧几里得范数),就是勾股定理的 n 维版:‖(3, 4)‖₂ = √(9+16) = 5。你直觉里的「箭头长度」「直线距离」,说的都是它。下标 2 的来历:每个分量先平方(2 次方),加完再开 2 次方根。这个命名格式马上要开枝散叶。
一把尺子不够用
想象你在只能横平竖直行走的棋盘街区里叫车。从 (0,0) 到 (3,4),直线距离 5 公里是给乌鸦用的;出租车得实打实开 3 + 4 = 7 公里。这把「按分量绝对值相加」的尺子叫 L1 范数,别名曼哈顿范数——纽约的街道网格就是它的老家:
再想象一个只关心「最坏情况」的质检员:一个零件有 n 项误差指标,他只看最大的那项。这是 L∞ 范数(最大范数):‖v‖∞ = max|vᵢ|。三把尺子量同一支箭 (3, 4):L1 说 7,L2 说 5,L∞ 说 4。都对——它们只是对「大分量该多受重视」持不同意见:L1 一视同仁,L2 偏爱惩罚大分量(平方放大),L∞ 只看最大的。这个「意见分歧」正是后面正则化戏码的伏笔。
看一把尺子的性格,最好的办法是画它的单位圆:所有「长度恰好为 1」的点组成的图形。L2 的单位圆是正经的圆;L1 的是一个顶点朝上下左右的菱形(|x|+|y|=1);L∞ 的是一个正方形(max=1 意味着某个分量顶到 ±1)。菱形有四个尖角戳在坐标轴上——请盯住这几个尖角,本章结尾它们会解释「为什么 L1 正则化能让权重稀疏」这个面试高频题。
顺带备案「尺子资格证」:一个函数配叫范数,要满足三条公理——① 非负,且只有零向量长度为零;② 数乘齐次:‖kv‖ = |k|·‖v‖,箭头拉长两倍,长度翻倍;③ 三角不等式:‖u+v‖ ≤ ‖u‖+‖v‖,两边之和大于第三边。L1、L2、L∞ 全部持证上岗,它们是同一族尺子(Lp 范数)在 p = 1、2、∞ 处的三个代表。
三把尺子的大小关系
同一支向量在三把尺子下的读数,永远遵守一条链:‖v‖∞ ≤ ‖v‖₂ ≤ ‖v‖₁。直觉:最大分量(L∞)只是 L2 求和里的一项,当然不超过总和的根;而平方求和开根,又不会超过绝对值直接相加(想想 (3,4):5 ≤ 7)。差距能有多大也有账可算——n 维空间里 L1 最多是 L2 的 √n 倍。这些不等式看似掉书袋,实际用途是估界:论文里「由范数等价性可知」这种一笔带过的话,背后就是这条链;工程上想快速判断「误差最坏多大」,常拿最好算的 L∞ 或 L1 去卡 L2 的上下界。
归一化:只留方向,不留长度
把向量除以自己的 L2 范数,得到方向不变、长度为 1 的单位向量:
这个动作叫归一化(normalization),上一章算余弦相似度时已经偷偷用过。工程上有个不起眼但会咬人的细节:如果 v 恰好(或数值上几乎)是零向量,除法会爆出 NaN。所以实战代码几乎总写成 v / (norm + 1e-8),那个 1e-8 叫 epsilon,是深度学习代码里出镜率最高的魔法数字之一——你在 LayerNorm、Adam 优化器的公式里都会看到它蹲在分母上防爆。
距离:差向量的长度
有了范数,「两点有多远」水到渠成:距离就是差向量的范数。
还记得第 02 章说 v − w 是「从 w 指向 v 的箭」吗?它的长度自然就是两箭尖的距离。K 近邻分类、K-means 聚类、异常检测的「离群分数」,底层都是这条公式在跑。
这里有一个考验理解的好问题:第 04 章的余弦相似度和这里的欧氏距离,是两套独立的班子吗?对归一化之后的向量,不是——展开算一下(用 ‖v−w‖² = (v−w)·(v−w) 逐项拆开,练手极佳):
单位球面上,欧氏距离和余弦相似度单调等价:余弦越大,距离越近,排序结果一模一样。这就是为什么向量数据库敢说「我们支持余弦/欧氏/点积三种度量」——对归一化后的库,三者选谁,top-k 结果都相同,选最快的那个(点积)就好。看穿这层等价,你就不会被文档里的度量选项吓到。
你写触摸事件时早就用过范数,而且用的是它的「省电版」。判断手指是不是拖动:dx*dx + dy*dy > touchSlop * touchSlop——比较的是 L2 范数的平方,刻意不开根号,因为 sqrt 贵而平方比较等价(两边都单调)。这个「能用平方就不开根号」的习惯在 AI 代码里同样通行:K-means 聚类的距离比较、负采样的筛选,都用平方距离。另外 ViewConfiguration.getScaledTouchSlop() 本质是给「移动向量的范数」设阈值——和风控拦截可疑交易,是同一个 if 语句。
写成代码:norm 一族
import numpy as np v = np.array([3.0, -4.0]) np.linalg.norm(v) # 5.0 默认 L2 np.linalg.norm(v, ord=1) # 7.0 L1 np.linalg.norm(v, ord=np.inf) # 4.0 L∞ v_hat = v / (np.linalg.norm(v) + 1e-8) # 归一化,防零除 # 批量距离:100 个查询点 × 5000 个库点,一行,无循环 Q = np.random.randn(100, 64) X = np.random.randn(5000, 64) d2 = ((Q[:, None, :] - X[None, :, :]) ** 2).sum(axis=-1) # d2.shape == (100, 5000),每格 = 一对点的平方距离
最后三行值得多看一眼:Q[:, None, :] 把两批向量的形状错开,让 NumPy 的广播机制自动完成「每个对每个」的配对——没有写任何 for 循环,却算了五十万对距离。这种「用形状表达算法」的写法是 AI 代码的标准腔调,第 19 章会把它彻底讲透;现在看不懂细节没关系,先记住感受:形状对了,循环就消失了。
误差也要选尺子:MSE 与 MAE
范数的第一大用途是量向量,第二大用途是量错误。模型预测了一串数,真实答案是另一串数,两串数的差还是一个向量——「模型错得多离谱」就是这个误差向量的范数。机器学习的「训练」,一言以蔽之就是调参数,让误差向量的某个范数变小;所以选哪个范数当损失函数,等于给整场训练定宪法。选 L2(平方误差,MSE)还是 L1(绝对误差,MAE),模型性格立刻分岔:
- MSE(L2 派):平方放大大误差,模型会拼命讨好离群点——错 10 的代价是错 1 的一百倍。数据干净时收敛快而稳;数据里有脏点时,一粒老鼠屎能拖歪整锅粥(下一卷第 14 章的 Demo 里你能亲手拖出这个效果)。
- MAE(L1 派):错 10 的代价就是错 1 的十倍,对离群点脱敏,但在误差接近零处梯度不平滑,优化器走到终点附近会「抖」。
没有普适赢家,只有场景匹配。实践里还有个折中派 Huber 损失:误差小时按 L2 算(平滑好优化),误差大时切换成 L1(不被离群点绑架),两头的好处都要。这是本书第一次展示一个贯穿 AI 工程的元定律:你选的度量,就是你给模型立的价值观;模型的一切「性格问题」,先回头检查度量。
正则化:给权重的范数上税
现在到本章的高潮。训练模型时,人们常在损失函数里加一项「权重范数的惩罚」:
为什么要惩罚权重的长度?直觉:权重越大,模型对输入的微小变化反应越剧烈——回忆神经元是点积机器,w 越长,同样的输入扰动造成的输出摆动越大。这种「神经质」通常意味着模型在死记硬背训练数据(过拟合)。L2 惩罚像一根拴在原点的橡皮筋,训练的每一步都把权重往回拽一点,拽出一个更「淡定」的模型。PyTorch 优化器里的 weight_decay 参数,就是这根橡皮筋的松紧度 λ。
那换成 L1 惩罚呢?奇妙的事情发生了:权重会被推成稀疏的——大批分量精确地变成 0。几何解释正是单位圆的形状:优化相当于在「误差等高线」和「范数约束圈」之间找相切点。L2 的约束圈是光滑的圆,切点可以停在任何角度,权重通常「都小但都非零」;L1 的约束圈是带尖角的菱形,尖角戳在坐标轴上,等高线十有八九撞在尖角上——而尖角处恰好某些坐标为零。于是 L1 正则化天然做特征选择:不重要的特征,权重直接清零。经典的 Lasso 回归、模型剪枝的部分套路,靠的都是这几个尖角。
范数在深度学习里的岗位远不止正则化:① LayerNorm / RMSNorm:Transformer 每层都要把激活向量按范数缩放一遍,防止数值随深度漂移——大模型结构图里那些 Norm 块,干的就是「量长度、再统一长度」;② 梯度裁剪:梯度向量的范数超过阈值就整体缩短,防训练爆炸,一行 clip_grad_norm_ 救过无数炼丹师;③ embedding 的模长信息:上一章说过长度可能携带置信度;④ 谱范数约束(第 17 章见)稳住生成对抗网络。你从此可以在任何模型代码里玩「找范数」游戏,命中率极高。
预告:矩阵也要量身高
既然向量能量长度,矩阵行不行?行,而且卷四、卷五会用到,这里先挂个号。最直接的一把叫 Frobenius 范数:把矩阵里所有元素平方求和开根——相当于把矩阵拉直成长向量后取 L2。它量的是「这堆参数整体有多大」,weight decay 惩罚的 ‖W‖² 就是它的平方。另一把更精妙的叫谱范数:matrix 作为变换,「最多能把一支单位向量拉长几倍」——量的是放大能力而不是参数体积。两把尺子量同一个矩阵可以给出很不同的读数,而「放大能力」那把,要等第 17 章的 SVD 登场才能算——奇异值 σ₁ 就是它。先混个脸熟。
高维的坏消息:距离在退化
卷一收尾前,把第 04 章那个高维冷知识补上阴暗面。在高维空间里,不仅随机方向趋于正交,距离也在失效:对很多分布,随着维度升高,「离你最近的点」和「离你最远的点」的距离之比趋近于 1——人人都差不多远,「最近邻」的含金量被稀释。这叫距离集中现象,是「维度诅咒」的一张面孔。
高维还有个亲戚现象叫球壳集中:高维标准正态分布的样本,几乎全部落在半径 ≈ √n 的一层薄壳上,球心附近反而空空荡荡——「高维的橘子,皮就是全部果肉」。所以「高维空间里两个随机向量:方向几乎垂直、长度几乎相同、彼此距离几乎相等」这三件事是一体的。对直觉的杀伤力在于:我们脑补的「点云中心密、边缘疏」图像在高维完全失真,任何依赖这个图像的推理(比如「取平均向量当类中心一定安全」)都要重新审视。
这解释了 AI 工程的几个「潜规则」:原始像素空间里做最近邻搜索效果稀烂(百万维,距离已死),必须先用模型把数据压到几百维的 embedding 空间再谈相似度;向量数据库的维度常见 384~1536,不是越大越好;聚类算法在超高维上普遍摆烂,先降维(第 18 章 PCA)再聚类是标准流程。度量不是免费的,维度会向它收税——记住这句,能帮你避开很多「为什么我的相似度搜索不准」的深夜。
回到风控:量纲这只拦路虎
兑现开头的场景前,还得排掉一颗雷。交易特征向量长这样:(金额 = 8500 元, 距上次交易 = 3 小时, 设备风险分 = 0.7)。直接算欧氏距离?金额一项的数值天然比另两项大三个数量级,距离读数几乎完全由金额说了算——设备风险分再异常也翻不了案。不同量纲的特征混在一支向量里,任何范数都会被大数值的维度绑架。
标准解法分两级。入门级:标准化,每个特征减去均值、除以标准差,让所有维度都以「几个标准差」为单位说话——预处理代码里的 StandardScaler 干的就是这个。进阶级:马氏距离(Mahalanobis distance),不但统一量纲,还把「特征之间的相关性」也考虑进去:金额大和深夜交易若总是结伴出现,它们联手的异常就不该被重复计分。马氏距离的公式里坐着一个协方差矩阵的逆——零件要到第 18 章 PCA 才配齐,先在这里立个路标:风控系统真正用的那把尺,是被数据分布校准过的 L2。
「归一化」这个词在 AI 语境里严重超载,至少四个不同动作共用它:把向量除以范数(本章)、把特征缩放到 [0,1](数据预处理的 min-max)、把一层激活值标准化(BatchNorm/LayerNorm)、把分数变概率(softmax)。读文档时务必先确认说的是哪一个——「记得先 normalize」这句话,四种理解会导向四种代码。
① 算 (1, −2, 2) 的 L1、L2、L∞ 范数;
② 为什么触摸判定比较平方距离而不开根号?这个技巧对余弦相似度排序适用吗?
③ 老板要求「模型权重尽量多归零好压缩」,你在损失里加 L1 还是 L2?一句几何理由?
④ 已知两支单位向量余弦相似度 0.8,它们的欧氏距离是多少?(用本章那条 2−2cos 公式)
⑤ 为什么在 4096 维原始特征上直接跑 K-means 往往效果差?
小结:卷一收官
范数是尺子,L1/L2/L∞ 是三把性格迥异的持证尺子,单位圆分别长成菱形、圆形与正方形;归一化抹掉长度只留方向,单位球面上余弦与欧氏距离暗中等价,所以向量库选度量常常只是选口味;量纲不齐的特征要先标准化,否则大数值维度会绑架整把尺子;误差度量和正则化本质都是「给某个向量的范数记账」,L2 拽小权重、L1 的菱形尖角把权重戳成稀疏;高维会向一切距离收税,方向趋于正交、长度趋于相同、远近趋于无差别,所以先降维再谈相似,是高维世界的礼仪。至此,卷一的家当配齐了:向量(对象)、线性组合与张成(生成)、点积(夹角)、范数(长度)——一套完整的「空间语言」。下一卷,主角换人:我们要引入一种会扭动整个空间的对象。你将看到,那个被你背了四年的「矩阵」,真实身份从来不是数字表格——它是一份变换的说明书,而它的每一列,写的正是「基向量将被送往何处」。