本文是《算法工程师的数学:读公式不卡壳的最小集》系列的第 2 篇(共八篇)。上一篇:向量、矩阵与形状——一个 token 过一层要算多少;下一篇:正交与旋转、特征值与 SVD——从 RoPE 到 LoRA

上一篇说一个 token 是一个向量。这一篇回答一个自然的问题:两个向量怎么比较?“这个 token 该看那个 token 多少”(attention)、”这段文本和查询有多相关”(检索)、”这两张图和这两句话配不配”(CLIP)、”量化后的权重离原来差多远”(压缩)、”参数是不是太大了”(正则化)——五个看起来不同的问题,用的是同一套只有三个词的语言:内积、范数、余弦相似度

全篇的核心问题是:

两个向量”像不像”有几种算法?各在哪里用?为什么 attention 用内积、检索用余弦、量化误差用 Frobenius 范数?

一、总览

1. 三个词一张图

内积 ⟨a, b⟩ = Σ a_i b_i        "对应位置相乘再相加"——既含方向又含大小
范数 ‖a‖   = √⟨a, a⟩          "向量的长度"——只有大小
余弦 cos θ = ⟨a, b⟩ / (‖a‖‖b‖)  "内积除掉两个长度"——只有方向

           b
          ╱
         ╱  θ            ⟨a, b⟩ = ‖a‖ ‖b‖ cos θ
        ╱________ a       内积 = a 的长度 × b 的长度 × 夹角余弦

2. 本文的章节安排

主题 内容
内积 定义、几何含义、attention score 就是内积、矩阵形式 \(QK^T\)
范数 \(L_2\)、\(L_1\)、Frobenius;长度、单位向量、归一化
余弦相似度 只比方向;embedding 检索与 CLIP 为什么用它;点积检索与余弦的关系
范数作为正则化项 weight decay 的 \(\frac{\lambda}{2}\lVert W \rVert_F^2\);\(L_1\) 为什么稀疏
范数作为误差度量 量化误差;GPTQ 为什么最小化 \(\lVert WX - \hat W X \rVert_F\) 而不是 \(\lVert W - \hat W \rVert_F\)
自测 五道题
本文小结  

二、内积

1. 定义

两个同维向量 \(a, b \in \mathbb{R}^d\) 的内积(inner product,也叫点积 dot product)是对应位置相乘再求和:

\[\langle a, b \rangle = a^T b = \sum_{i=1}^{d} a_i b_i\]

\(a^T b\) 这个写法用上一篇的形状规则读:\(a^T\) 是 \([1, d]\),\(b\) 是 \([d, 1]\),乘起来是 \([1, 1]\)——一个标量。所以内积是矩阵乘法的最小情形:一行乘一列。

手算一个:\(a = (1, 2, 3)\),\(b = (4, -1, 2)\),\(\langle a, b \rangle = 1 \cdot 4 + 2 \cdot (-1) + 3 \cdot 2 = 8\)。

2. 几何含义

内积等于两个向量的长度乘以夹角的余弦:

\[\langle a, b \rangle = \lVert a \rVert\, \lVert b \rVert \cos\theta\]

(\(\lVert a \rVert\) 是 \(a\) 的长度,下一章定义。)这条等式给了内积三个直觉:

  • 同向为正、垂直为零、反向为负:\(\theta = 0\) 时 \(\cos\theta = 1\),内积最大;\(\theta = 90°\) 时为 0;\(\theta = 180°\) 时为负。
  • 它是”投影”:\(\langle a, b \rangle / \lVert b \rVert\) 是 \(a\) 在 \(b\) 方向上的投影长度——”\(a\) 有多少成分沿着 \(b\)“。
  • 它同时含方向与大小:把 \(a\) 放大两倍,内积也放大两倍。这一点在第四章区分”内积”与”余弦”时是关键。

3. attention score 就是内积

Transformer 的 attention 里,每个 token 有一个 query 向量 \(q\) 和一个 key 向量 \(k\)(都是 \(d_h = 128\) 维),”第 \(i\) 个 token 该看第 \(j\) 个 token 多少”的原始分数是

\[s_{ij} = q_i^T k_j\]

——就是内积。\(q_i\) 与 \(k_j\) 方向越一致、长度越大,分数越高。写成矩阵形式:\(Q \in \mathbb{R}^{T \times d_h}\) 每行一个 query,\(K \in \mathbb{R}^{T \times d_h}\) 每行一个 key,则

\[S = QK^T \in \mathbb{R}^{T \times T}, \qquad S_{ij} = q_i^T k_j\]

用形状规则:\([T, d_h] \times [d_h, T] \to [T, T]\),一张 \(T \times T\) 的表,第 \(i\) 行是第 \(i\) 个 token 对所有 token 的分数。上一篇第三章说”矩阵乘法的第三种看法是相似度表”,说的就是它。

\(S\) 随后除以 \(\sqrt{d_h}\) 再过 softmax 变成概率(第四篇解释为什么除 \(\sqrt{d_h}\),第五篇解释 softmax)。这里只要记住:attention 的”相关性”是内积,所以它同时受方向与长度影响——这也是为什么 QK-norm 这类技术(给 \(q, k\) 做归一化再算内积)能稳定训练:它把长度的影响去掉了。

三、范数

1. \(L_2\) 范数:长度

向量的长度(\(L_2\) 范数,欧几里得范数)是它与自己内积的平方根:

\[\lVert a \rVert_2 = \sqrt{\langle a, a \rangle} = \sqrt{\sum_i a_i^2}\]

二维时就是勾股定理:\((3, 4)\) 的长度是 \(\sqrt{9 + 16} = 5\)。不带下标的 \(\lVert a \rVert\) 默认指 \(L_2\)。

长度为 1 的向量叫单位向量;任何非零向量除以自己的长度就变成单位向量,这个操作叫归一化(normalize):\(\hat a = a / \lVert a \rVert\)。它保留方向、抹掉大小。

2. \(L_1\) 范数:绝对值之和

\[\lVert a \rVert_1 = \sum_i \lvert a_i \rvert\]

\((3, -4)\) 的 \(L_1\) 范数是 7,\(L_2\) 范数是 5。\(L_1\) 在第五章(Lasso 为什么产生稀疏)出现。

一般地,\(L_p\) 范数是 \((\sum_i \lvert a_i \rvert^p)^{1/p}\);\(p \to \infty\) 时趋向最大绝对值 \(\max_i \lvert a_i \rvert\),叫 \(L_\infty\) 范数——量化里”最大绝对值决定缩放因子”用的就是它。

3. Frobenius 范数:矩阵的”长度”

矩阵没有天然的”长度”,最常用的定义是把它拉直成一个长向量再取 \(L_2\) 范数:

\[\lVert W \rVert_F = \sqrt{\sum_{i, j} W_{ij}^2}\]

一个 \(4096 \times 4096\) 的矩阵,Frobenius 范数就是它 1677 万个元素的平方和开根号。weight decay(第五章)与量化误差(第六章)都用它。

另一个矩阵范数——谱范数(矩阵能把一个单位向量最多拉长多少倍)——在 L3 讲梯度消失与爆炸时出现,那里再定义。

四、余弦相似度

1. 定义

把第二章的几何等式反过来解出 \(\cos\theta\):

\[\cos\theta = \frac{\langle a, b \rangle}{\lVert a \rVert\, \lVert b \rVert}\]

这就是余弦相似度:内积除掉两个长度,只剩方向。取值在 \([-1, 1]\)——1 是同向,0 是垂直,\(-1\) 是反向;与向量长度无关,\(a\) 放大十倍余弦不变。

它也等于两个归一化向量的内积:\(\cos\theta = \hat a^T \hat b\)。这个等价在工程上很重要(下一节)。

2. embedding 检索为什么用余弦

embedding 是把一段文本变成一个向量(比如 1024 维),使得含义相近的文本向量相近。检索时把查询也变成向量,在库里找最相近的。用什么度量”相近”?

用内积的问题是:内积受长度影响,一段很长、embedding 模值很大的文本会对所有查询都得高分。用余弦只比方向,”这段文本讲的是什么”由方向表示,”它多长、多啰嗦”由长度表示,检索只关心前者。

工程上的做法是存之前先归一化:库里每个向量都除以自己的长度,查询也归一化,然后余弦相似度就变成了单纯的内积 \(\hat q^T \hat v\)——一次矩阵乘法 \([1, 1024] \times [1024, N]\) 算出对全库 \(N\) 条的分数。向量数据库里的”内积检索”与”余弦检索”在归一化之后是同一件事。

3. CLIP 的图文匹配

CLIP 把图像和文本各编码成一个向量,训练目标是”配对的图文余弦相似度高、不配对的低”。用余弦而不用内积,理由同上:图像编码器与文本编码器输出的模值没有理由可比,只有方向有意义。L7 多模态系列的第一篇会展开 CLIP 的对比学习 loss——它是余弦相似度除以一个温度再过 softmax + 交叉熵,本系列第五、六篇讲的东西。

4. 一个数字感受高维

在高维空间里,随机的两个向量几乎总是接近垂直。取两个 \(d = 1024\) 维、每个分量独立随机的向量,它们余弦相似度的标准差约为 \(1 / \sqrt{d} = 1 / 32 \approx 0.03\)——绝大多数随机向量对的余弦在 \(\pm 0.1\) 以内。所以 embedding 检索里 0.3 的余弦已经是”明显相关”,0.8 是”几乎同义”;不要用二维平面的直觉(0.5 才算”有点像”)去读这些数字。

五、范数作为正则化项

1. weight decay

训练神经网络时常在 loss 上加一项参数的范数:

\[\mathcal{L}_{\text{total}} = \mathcal{L}_{\text{data}} + \frac{\lambda}{2} \lVert W \rVert_F^2\]

\(\lambda\) 是一个小常数(LLM 预训练常用 0.1),\(\lVert W \rVert_F^2\) 是所有参数的平方和。这项的作用是”不许参数太大”:优化器在降低数据 loss 的同时也要压小参数。对它求导(第七篇)得到 \(\lambda W\)——每一步把参数往零缩一点,所以叫 weight decay(权重衰减)。它是最常用的正则化(防止过拟合)手段之一,L2 经典机器学习系列讲它为什么有效,L3 讲 AdamW 里它与 \(L_2\) 正则的微妙区别。

2. \(L_1\) 为什么产生稀疏

把上面的 \(\lVert W \rVert_F^2\) 换成 \(\lVert w \rVert_1 = \sum_i \lvert w_i \rvert\),就是 Lasso。它的特点是会把很多参数压成恰好为零(稀疏),而 \(L_2\) 只会把参数压小但不为零。一个直觉:

参数 w 从 0.1 往 0 走时,惩罚项的下降量:
  L2:  w² 从 0.01 → 0,只降 0.01——越接近 0 越没动力继续压
  L1:  |w| 从 0.1 → 0,降 0.1——一直有恒定的动力压到 0

\(L_1\) 的惩罚在零点附近不变小,所以能把参数推到零并停在零。稀疏在特征选择(L2 系列)与模型剪枝里有用;LLM 本身很少用 \(L_1\)。

六、范数作为误差度量

1. 量化误差

量化(quantization)是把 16 位浮点的权重 \(W\) 用更少的位(比如 4 位整数)近似成 \(\hat W\),以省显存、加快推理。近似有误差,怎么度量?最直接的是权重本身的差:

\[\lVert W - \hat W \rVert_F\]

——原矩阵与量化矩阵逐元素差的平方和开根号。逐元素独立地把每个数四舍五入到最近的量化格点(round-to-nearest)就是在最小化它。

2. GPTQ 最小化的是另一个东西

GPTQ 一类方法不最小化 \(\lVert W - \hat W \rVert_F\),而最小化

\[\lVert WX - \hat W X \rVert_F\]

——\(X\) 是一批真实输入(校准数据),比较的是权重作用在输入上的输出差多远,而不是权重本身差多远。为什么这更对?因为模型最终输出的是 \(WX\) 不是 \(W\):如果输入 \(X\) 的某些维度总是接近零,那些维度上权重量化得再差也不影响输出;反过来输入里数值特别大的维度(LLM 里确实存在,叫 outlier 通道),对应的权重一点误差就会被放大。\(\lVert WX - \hat W X \rVert_F\) 自动按输入的分布给不同权重不同的”重要性”。

两个目标之间的关系可以写成一行:\(\lVert (W - \hat W) X \rVert_F^2 = \text{tr}\big((W - \hat W) X X^T (W - \hat W)^T\big)\),中间那个 \(XX^T\)(输入的二阶统计量,Hessian 的近似)就是”重要性”矩阵。L6 高效推理与压缩系列讲 GPTQ 怎么利用它逐列量化并补偿误差;这里只要读懂:量化不是逼近权重本身,而是逼近权重作用在输入上的结果

3. 同一个词的三个身份

到这里,”范数”在三个地方出现,身份不同:

身份            公式                            在哪里
长度 / 归一化    ‖a‖₂,â = a / ‖a‖               余弦相似度、QK-norm、LayerNorm / RMSNorm 的分母
正则化项         (λ/2) ‖W‖_F²,‖w‖₁              weight decay、Lasso
误差度量         ‖W − Ŵ‖_F,‖WX − ŴX‖_F          量化误差、低秩近似误差(下一篇)

读论文时看到 \(\lVert \cdot \rVert\),先判断它是哪个身份。

七、自测

  1. \(a = (1, 0, -1)\),\(b = (2, 2, 2)\):内积是多少?两者的夹角是多少度?
  2. \((3, -4)\) 的 \(L_1\)、\(L_2\)、\(L_\infty\) 范数各是多少?
  3. attention 里 \(Q, K \in \mathbb{R}^{2048 \times 128}\),\(QK^T\) 是什么形状、多少 FLOPs?把 \(q\) 全部放大两倍,score 怎么变?余弦相似度怎么变?
  4. 库里有 100 万条 1024 维、已归一化的 embedding,一次查询的余弦检索是一次什么形状的矩阵乘法,多少 FLOPs?
  5. 为什么”把每个权重四舍五入到最近的格点”不是最小化 \(\lVert WX - \hat W X \rVert_F\) 的最优解?举一个 \(X\) 的例子说明。

答案要点:(1)\(1 \cdot 2 + 0 + (-1) \cdot 2 = 0\);垂直,90°。(2)7、5、4。(3)\([2048, 2048]\),\(2 \times 2048 \times 2048 \times 128 \approx 1.07\) G;score 放大两倍;余弦不变。(4)\([1, 1024] \times [1024, 10^6]\),约 \(2 \times 10^9\) FLOPs。(5)若 \(X\) 的第 1 维恒为 100、第 2 维恒为 0.01,则 \(W\) 第 1 列的误差被放大 100 倍、第 2 列几乎不影响输出;最优解应该把第 1 列量得更准(哪怕第 2 列量得更差),逐元素四舍五入做不到这种取舍。

八、本文小结

  • 内积 \(\langle a, b \rangle = \sum_i a_i b_i = \lVert a \rVert \lVert b \rVert \cos\theta\):矩阵乘法的最小情形,同时含方向与大小;attention 的 score \(QK^T\) 是一张内积表。
  • 范数:\(L_2\) 是长度、\(L_1\) 是绝对值之和、Frobenius 是矩阵拉直后的 \(L_2\);除以长度叫归一化,只留方向。
  • 余弦相似度 \(= \langle a, b \rangle / (\lVert a \rVert \lVert b \rVert) = \hat a^T \hat b\):只比方向;embedding 检索与 CLIP 用它,归一化后退化为内积;高维里随机向量的余弦在 \(\pm 1/\sqrt{d}\) 量级,0.3 已经是明显相关。
  • 范数作正则化项:weight decay 是 \(\frac{\lambda}{2}\lVert W \rVert_F^2\),导数 \(\lambda W\) 每步把参数往零缩;\(L_1\) 因为零点附近惩罚不变小而产生稀疏。
  • 范数作误差度量:量化误差不该看 \(\lVert W - \hat W \rVert_F\) 而该看 \(\lVert WX - \hat W X \rVert_F\)——逼近的是权重作用在输入上的结果,输入的二阶统计量 \(XX^T\) 给每个权重不同的重要性。

下一篇讲矩阵的两种”好性质”:正交(保持内积——RoPE 为什么能编码相对位置)与低秩(少数方向解释全部——LoRA 为什么能用半个百分点的参数微调)。

本文由 arganzheng 创作,采用 CC BY 4.0 许可协议。在保留原文作者、署名以及完整原文链接(https://arganzheng.life/inner-product-norms-and-cosine-similarity.html)的前提下,欢迎各种形式的转载、翻译或商业引用。


COMMENTS

评论存放在 GitHub Discussions, 用 GitHub 账号登录即可发表,支持 Markdown。 想针对正文某句话说?选中那段文字,点浮出的「评论」即可划线评论;觉得哪里写错了,发表时勾上「同时提交 Issue」。 有人回复你时 GitHub 会按你的通知设置发邮件,不用守在这里。

×