为什么文本相似度使用余弦相似度?

最近离职了,刚好有时间研究一些之间没有钻研过的内容。某天洗澡的时候忽然想到余弦相似度的问题,为什么它在NLP中广泛被使用,这次研究一下。

余弦相似度主要体现的是两个向量在方向上的差异,而对它们的模大小不做要求。计算公式是:$ \text{cosine_similarity}(\mathbf{A}, \mathbf{B}) = \frac{\mathbf{A} \cdot \mathbf{B}}{|\mathbf{A}| |\mathbf{B}|} $。

不用向量的大小来计算相似度有一个好处,如果我们有两个文档,其中一个文档中的Token多,另一个Token少,那么内容多的文档,向量的大小会比内容少的文档的向量更大,如果使用向量大小作为相似度的计算参数之一,可能会导致计算出来的相似度差距过大,而这并不代表两个文档并不相似。

与之对比的是欧式距离,也就是两个向量的距离上的绝对差异。它体现的是两者之间距离相近的程度。

假如有两个向量,两个人对APP的使用次数与使用时长分别表示为(1,10)和(10,100)。它们的余弦相似度较小,代表这两个人的行为是相同的,然而事实是不同的,两个人的活跃度有着极大的差异,第二个人的活跃度更高,这时就需要使用欧氏距离进行对比。

不过欧式距离也会收到度量的影响。例如当用户1给Item1和Item2分别打分2和4分,用户2给Item1和Item2分别打分4和8分。两者的打分尺度并不一致,这时使用欧式距离计算两个用户的相似度会无法得到有效的结果,就需要进行标准化。

另外,当向量进行归一化后,欧式距离与余弦相似度存在转换关系$ \text{euc}(a, b) = 2 \left( 1 - \cos(a, b) \right) $。这其实能说明一定它们之间的关系。

点积

上面说的余弦相似度完全不考虑向量的长度,事实上能够使用点积来将向量长度的信息一起涵盖入相似度的计算。点积的计算公式是向量夹角的余弦值乘以两个向量的长度得到。当两个向量完全相同时,点积达到最大值。当两者垂直时,点积为0。

点积如何影响相似度度量?

例如正在计算一组研究论文的相似度。研究论文嵌入向量的长度与被引用次数成正比。

高被引次数(较长的向量)的论文与其他高被引论文的点积相似度得分更高,因为它们的量级对结果的贡献更大。低被引次数(较短的向量)的论文与高被引次数的论文的点积相似度得分较低,因为它们的量级较小。

高维空间与维度灾难

随着维度的增长,向量之间的差距会逐渐减小,这时候相似度会趋向于零,导致计算相似度的意义不大。这种情况被称为维度灾难。

根据定义,维度灾难指对于已知样本数目,存在一个特征数目的最大值,当实际使用的特征数目超过这个最大值时,分类器的性能不是得到改善,而是退化,这一现象被命名为Hughes影响或Hughes现象。这也是为什么高维下,相似度计算的作用会被无限降低。发现这一现象后,出现了一系列降维算法,这就是后话了。

不过,在高维下,余弦相似度的计算比欧式距离的效果要更好,这就是为什么在嵌入向量的计算中更多的使用余弦相似度。

还有另外一种解释,是从模型训练的角度出发解释维度灾难:在训练样本的时候,在样本数目不变的情况下,随着维度的增高,我们的模型效果会随着维度的增高而降低。也就是说,如果想要达到相同的模型效果,在使用高维度时所需要的样本数量要比低维度的样本数量大的多。

从深度学习思考余弦相似度

知乎上有一个答主提到了一点,假如我们有一个分类模型,并且用于一个线性层作为最终输出的分类头,我们可以看到,实际上这个线性层在做的事就是将权重和输入的嵌入做点积计算,这和余弦相似度是一致的。

你可以理解训练一个分类模型的过程(已有特征提取的话)就是为每一个类都学出来一个这个类的embedding(线性层的w)。

2024/6/22 于苏州