背景

以前在存储EMBEDDING模型输出向量的时候,由于不同模型输出的向量维度不同,而向量数据库同一个表只能存储同一维度长度的向量,当时使用的方案是直接在向量后面补0来拓展。
最近在思考这样做为什么不会影响相似度的计算,同时研究了一下余弦相似度计算公式的推导过程。

向量长度

一维向量的长度

对于向量 x=(x)x = (x)

它的长度是 x=x\|x\| = |x|

二维向量的长度

对于向量 x=(x1,x2)x = (x_1, x_2)

1
2
3
4
5
6
7
8
9
(x1, x2)
*
|\
| \
x2 | \ ||x||
| \
|____\
x1

它的长度是 x=x12+x22\|x\| = \sqrt{x_1^2 + x_2^2}

三维向量的长度

对于向量 x=(x1,x2,x3)x = (x_1, x_2, x_3)

它的长度是 x=x12+x22+x32\|x\| = \sqrt{x_1^2 + x_2^2 + x_3^2}

n维向量的长度

对于向量 x=(x1,x2,...,xn)x = (x_1, x_2, ..., x_n)

它的长度是 x=x12+x22+...+xn2\|x\| = \sqrt{x_1^2 + x_2^2 + ... + x_n^2}

这一定义也被称为向量的 L2 范数(Euclidean Norm)

向量点积公式

点积定义分为几何定义和代数定义两种,两种可以相互推导。
https://zh.wikipedia.org/wiki/点积#代数定义

余弦相似度计算

两个向量之间的余弦值可以通过 欧几里得点积公式 求出:

AB=ABcosθA \cdot B = \|A\| \cdot \|B\| \cdot \cos\theta

其中,θ\theta 表示向量 AA 与向量 BB 之间的夹角。

推导一下可得:

similarity=cos(θ)=ABAB=i=1nAi×Bii=1n(Ai)2×i=1n(Bi)2\text{similarity} = \cos(\theta) = \frac{A \cdot B}{\|A\| \cdot \|B\|} = \frac{\sum_{i=1}^{n} A_i \times B_i} {\sqrt{\sum_{i=1}^{n} (A_i)^2} \times \sqrt{\sum_{i=1}^{n} (B_i)^2}}

其中:

  • AiA_i 表示向量 AA 在第 ii 个维度上的分量
  • BiB_i 表示向量 BB 在第 ii 个维度上的分量
  • nn 为向量的维度数

将分子与分母中的求和项显式展开,可得:

i=1nAiBi=A1B1+A2B2++AnBn\sum_{i=1}^{n} A_i B_i = A_1 B_1 + A_2 B_2 + \cdots + A_n B_n

i=1n(Ai)2=A12+A22++An2\sum_{i=1}^{n} (A_i)^2 = A_1^2 + A_2^2 + \cdots + A_n^2

i=1n(Bi)2=B12+B22++Bn2\sum_{i=1}^{n} (B_i)^2 = B_1^2 + B_2^2 + \cdots + B_n^2

可以看到,余弦相似度的计算仅依赖于各维度对应分量的乘积和平方和

不影响相似度计算的向量维度拓展方法

假设原始向量为 nn 维:

A=(A1,A2,,An),B=(B1,B2,,Bn)A = (A_1, A_2, \dots, A_n), \quad B = (B_1, B_2, \dots, B_n)

为了统一向量维度,在末尾补 0 将其扩展到 mm 维(m>nm > n):

A=(A1,A2,,An,0,,0mn)A' = (A_1, A_2, \dots, A_n, \underbrace{0, \dots, 0}_{m-n})

B=(B1,B2,,Bn,0,,0mn)B' = (B_1, B_2, \dots, B_n, \underbrace{0, \dots, 0}_{m-n})

扩维后的点积为:

AB=i=1mAiBi=i=1nAiBi+i=n+1m00=i=1nAiBi\begin{aligned} A' \cdot B' &= \sum_{i=1}^{m} A'_i B'_i \\ &= \sum_{i=1}^{n} A_i B_i + \sum_{i=n+1}^{m} 0 \cdot 0 \\ &= \sum_{i=1}^{n} A_i B_i \end{aligned}

可以看到补 0 的维度不会对点积产生任何贡献

扩维后的向量长度为:

A=i=1m(Ai)2=i=1nAi2+i=n+1m02=i=1nAi2=A\begin{aligned} \|A'\| &= \sqrt{\sum_{i=1}^{m} (A'_i)^2} \\ &= \sqrt{\sum_{i=1}^{n} A_i^2 + \sum_{i=n+1}^{m} 0^2} \\ &= \sqrt{\sum_{i=1}^{n} A_i^2} = \|A\| \end{aligned}

由上述展开可以看出,向量补 0 扩维不会改变点积结果,

因此 对于同一个模型输出的向量,通过填0改变向量的长度,因此不会影响余弦相似度的计算结果。