一句直觉

把词变成向量后,同义词可能隔得很远,非同义词可能挤在一起,而完全不同的词余弦相似度也可能很高——这不是 Bug,是高维空间的固有几何特性。

向量化(Embedding)是现代 NLP 和 AI 应用的基石。你写一段文本,模型把它映射成一个高维向量(通常是几百到几千维),然后通过计算向量间的余弦相似度来判断语义相似性。这套逻辑支撑着 RAG、语义搜索、文本聚类、推荐系统等几乎所有 AI 应用。

但如果你在实际项目中使用过向量搜索,大概率遇到过以下反直觉的情况:

你期望 实际结果
“汽车”和”轿车”余弦很高 余弦只有 0.52,还不如”汽车”和”冰箱”的 0.61
“苹果”和”香蕉”余弦很低 余弦高达 0.78,因为它俩频繁出现在”水果”语境中
“成功”和”失败”余弦很低 余弦 0.89,在嵌入空间里几乎挨着

更诡异的是:有时候随便选两个完全不搭边的词(如”量子”和”披萨”),余弦相似度竟然是 0.7+。你开始怀疑向量相似度是不是在骗人。

这篇文章用最直觉的方式解释:同义词为什么可能远(各向异性 + 维度塌缩)、非同义词为什么可能近(分布相似性)、以及完全不同的词余弦为什么也可能高——Hubness 和语义压缩。

前置理解:向量相似度到底在算什么?

先说清楚余弦相似度是怎么算的。两个向量 AB 的余弦相似度是:

1
cos(A, B) = (A · B) / (|A| × |B|)

分子是点积,分母是模长的乘积。翻译成人话:只看方向,不看长度。如果两个向量指向大致相同的方向,余弦就高(接近 1);指向相反方向,余弦就低(接近 -1);方向垂直,余弦就是 0。

这个”只看方向不看长度”的特性是理解一切异常的起点。

现象一:同义词语向量化后差距大

为什么会这样?

直觉上,”汽车”和”轿车”意思这么接近,向量应该紧紧挨在一起才对。但现实是它们的余弦相似度可能远低于你的预期。原因主要有三个:

1. 上下文分布差异(Context Distribution Mismatch)

嵌入模型(如 Word2Vec、BERT、text-embedding-3)是通过”一个词的上下文”来学习它的表示的。分布假设(Distributional Hypothesis)说:一个词的含义由它周围的词决定。JP 的经典表述是 “You shall know a word by the company it keeps.”

问题来了:”汽车”常常出现在”驾驶、加油、4S 店、高速、停车”这些上下文中;而”轿车”虽然语义上是一种汽车,但它的常见上下文偏向”商务、豪华、三厢、舒适性”。两者虽然高度相关,但上下文分布并不完全重合。模型学到的是它们各自的特征,而不是它们的语义等价关系。

这就像两个都叫”张三”的人,一个住在北京,一个住在纽约——名字一样,但邻居完全不同。

2. 各向异性(Anisotropy)

这是词向量空间中一个非常重要但常被忽视的特性。理想情况下,我们希望嵌入空间是各向同性的(Isotropic)——向量在各个方向上均匀分布。但实际训练出来的词向量空间几乎都是各向异性的(Anisotropic)——大多数向量挤在一个狭窄的锥形区域内,形成一个”语言学家”认为离谱、但模型觉得 OK 的形状。

在这种各向异性的空间中,向量之间的差异更多来自于模长而非方向。然而余弦相似度只看方向,所以两个同义词如果在方向上只有微小差异,它们的余弦相似度就会很低——不是因为它们不相似,而是因为整个空间的几何就是”扭曲”的。

类比:想象所有人被要求贴在一面墙上站着。要区分两个人,你只能看他们贴在哪面墙上(方向),但所有人都在同一面墙上——差别就变得很模糊。

3. 高频词与低频词的嵌入差异

高频词(如”的”、”是”、”在”)在训练中会经历更多的更新,它们的嵌入往往趋于”大模长 + 各向异性”;低频词则”小模长 + 不充分学习”。一个高频的同义词和一个低频的同义词,即使语义接近,它们的嵌入方向和模长可能差异巨大,最终余弦相似度惨不忍睹。

实际案例

词对 预期余弦 实际余弦(典型 BERT 表现)
汽车-轿车 0.9+ 0.50 ~ 0.65
开心-快乐 0.9+ 0.55 ~ 0.70
快速-迅速 0.9+ 0.60 ~ 0.75

原因很统一:上下文分布差异 + 各向异性 + 频率偏差让它们没有”看起来那么近”。

现象二:非同义词语向量化后差距小

这是另一个方向的反直觉:两个意思完全不同的词,余弦相似度却很高。

最典型的例子是反义词。”好”和”坏”、”大”和”小”、”成功”和”失败”——它们在嵌入空间中往往非常接近。原因很直观:反义词经常出现在完全相同的上下文中。

想想看:”今天天气真好”和”今天天气真坏”——只有”好”和”坏”这个词不同,周围的词一模一样。模型从上下文学习表示,看到的是”好”和”坏”被完全相同的邻居包围。如果只看上下文,模型会认为它们几乎是等价的。

在分布假设下,“意思相反”和”意思相同”都产生相似的上下文——模型无法区分”同义替换”和”反义替换”,它看到的是”替换后句子仍然成立”。

另一个常见来源是共现模式(Co-occurrence Patterns)。”苹果”和”香蕉”在嵌入空间中很近,不是因为它们形状相似,而是因为它们都频繁和”水果”、”吃”、”甜”、”超市”这些词共现。模型学到的是”它们出现在相似的语境中”,而不是”它们在语义上属于同一类”——后者是人类的概念归纳,前者是模型的统计规律。

词对 关系 为什么余弦高
高-矮 反义词 相同上下文(”他___了”)
苹果-香蕉 不同事物同类别 共享上下文(”吃___”、”___很甜”)
老师-学生 相关但不同角色 共享场景上下文(”___在教室上课”)
买-卖 反义动作 相同上下文(”我去___东西”)

现象三:完全不同的词余弦也很高——Hubness

如果说前两个现象还算是”有道理的反直觉”,那第三个现象就是真正让人困惑的了:“量子”和”披萨”、”哲学”和”篮球”——这些词如果在 768 维的嵌入空间里,余弦相似度可能高达 0.7 以上。 这明显不是语义相似性能解释的。这就是 Hubness(枢纽性) 现象。

Hubness 是什么?

Hubness 是”维度诅咒”(Curse of Dimensionality)的一个具体表现。在高维空间中,某些点会不自然地成为大量其他点的”最近邻居”——即使它们之间没有任何语义关联。这种现象被称为 Hubness,而那些被频繁选为邻居的点称为 Hub(枢纽点)

学术定义:Hubness 衡量的是一个点出现在其他点的 k-最近邻列表中的频率。在一个不存在 Hubness 的均匀分布中,每个点作为其他点最近邻的期望次数大致相等。但在高维空间中,某些点的”被邻居次数”会远远高于统计期望——高出几十倍甚至上百倍。

为什么高维空间会产生 Hubness?

核心原因在于高维空间的距离分布趋于均匀

在低维空间(2D、3D)中,点与点之间的距离差异很大——你可以轻松区分”近”和”远”。但在高维空间中,任意两点之间的距离都趋向于一个常数。用一个经典结论来表述:

对于高维空间中的独立同分布点,最远距离和最近距离的比值趋近于 1。换句话说,所有点和所有其他点的距离都差不多。

1
lim(d → ∞) (D_max - D_min) / D_min → 0

翻译成人话:维度越高,距离越没有意义。

当所有距离都差不多的时候,那些稍微”靠近中心”或”模长稍大”的点,就会意外地成为许多其他点的最近邻——不是因为它们在语义上更相似,而是因为在高维空间里,”谁是最近邻”几乎由随机波动决定

Hubness 在多模态模型中更严重

如果你用过 CLIP 这样的多模态模型(文本+图像共享嵌入空间),Hubness 现象会更加明显。原因在于多模态模型往往存在模态差异——文本的分布在空间中相对稀疏,图像的分布相对密集,所以图像向量更容易成为 Hub。

这意味着当你用文本搜索图像时,同一个图像可能出现在几乎所有文本查询的 top-k 结果中——不是因为它在语义上与所有查询都相关,而是因为它是嵌入空间中的一个 Hub。

一个真实案例:在某个生产级别的图文搜索系统中,大约 3% 的图片占据了 40% 以上的检索召回结果。这 3% 就是典型的 Hub——它们和任何查询的”距离”都差不多近。

现象四:语义压缩(Semantic Collapse)

语义压缩是 Hubness 的一个近亲,但描述的是不同的机制。如果说 Hubness 是高维空间的几何问题,那语义压缩就是训练过程的表征退化问题

什么是语义压缩?

语义压缩指的是:在模型训练过程中,不同语义的样本在嵌入空间中逐渐”坍缩”到相似的区域,导致嵌入空间的区分度下降。越训练,不同类的向量越挤在一起——这听起来反直觉,但实际上非常普遍。

为什么会发生语义压缩?

1. 对比损失的过度优化

在对比学习(Contrastive Learning)中,模型被训练来拉近相似样本、推远不相似样本。但当训练数据中的”负样本”不够多样化或难易度不匹配时,模型会找到一种”偷懒”的解法:把所有样本映射到一个小区域内,然后在这个区域内做微小的区分。这样既能完成对比任务(因为正负样本在小区域内仍有相对距离),又不需要模型学习真正有意义的特征。

这就是为什么很多人在微调嵌入模型时发现:在下游任务上指标提升了,但检索质量反而下降了——模型在”作弊”,用语义压缩换取表面指标的提升。

2. Transformer 的各向异性漂移

研究表明,Transformer 模型的各层输出存在明显的各向异性积累。模型越深,输出向量的分布越偏离均匀分布,越趋向于集中在某个狭窄的锥形区域内。这意味着:

  • 模型不同层的嵌入质量显著不同
  • 最后一层的嵌入往往”最压缩”——语义区分度最低
  • 取倒数第二层或做层间平均,有时能缓解语义压缩

3. 有限的数据多样性

当训练数据的语义多样性不足时,模型天然倾向于将”没见过太多区分模式”的样本压缩到一起。这不是模型的错误——在有限的监督信号下,把不确定的样本放在”安全区”是统计上的理性选择。

语义压缩 VS Hubness

Hubness 语义压缩
根源 高维空间的几何特性 训练过程的表征退化
表现 某些点成为通用最近邻 所有点的区分度下降
能否缓解 部分可以通过后处理缓解 可以通过改进训练策略缓解
与维度的关系 维度越高越严重 与维度关系不大
是否可以消除 不能完全消除 可以在很大程度上修复

怎么缓解这些问题?

理解了这些现象之后,工程上可以采取的缓解措施:

处理各向异性和语义压缩

1. 向量归一化与中心化(Normalization + Centering)

这是最简单有效的后处理。对所有嵌入向量做减去均值(中心化)然后除以标准差(白化),可以有效缓解各向异性。公式:

1
A' = (A - μ) / σ

其中 μ 是所有向量的均值,σ 是标准差。经过这一步,向量的分布从”锥形”变为”球形”,余弦相似度的可解释性显著提升。

2. 使用更长的上下文

对于同义词余弦低的问题,一个工程技巧是:不要只编码单个词,而是编码包含该词的完整句子或段落。上下文越丰富,嵌入的区分度越高。

缓解 Hubness

1. 查询-中心化变换(Query-side Centering)

在搜索前对查询向量做全局中心化(减去数据集的均值中心)。这能有效降低 Hub 向量的影响力。

2. 互惠排名融合(Reciprocal Rank Fusion, RRF)

不要只依赖一次向量检索。用多个不同的嵌入模型或不同的查询变体做多次检索,然后将结果排名用 RRF 融合:

1
score(d) = Σ 1 / (k + rank_i(d))

RRF 能有效降低单一 Hub 点对最终结果的扭曲影响。

3. 流形重排(Manifold Ranking)

不只考虑查询点到候选点的距离,还考虑候选点之间的流形距离。如果一个候选点是”几乎所有点的邻居”,它在流形重排中的得分会被其邻居”拉低”。

具体工程建议

问题 推荐做法 效果
同义词余弦低 用整句嵌入替代单词嵌入 大幅改善
非同义词余弦高 用中心化 + 白化后处理 明显改善
Hubness RRF 融合或多查询检索 有效缓解
语义压缩 取模型倒数第二层输出 可修复部分问题
通用最佳实践 先用中心化,再算余弦,再做 RRF 全面改善

总结

现象 一句话解释 根本原因
同义词向量远 上下文分布不完全重叠 + 空间各向异性 分布假设的局限 + 高维几何
非同义词向量近 反义词/同类词共享上下文 分布假设无法区分同义和反义
不同词余弦高 某些点成为通用最近邻 Hubness——维度诅咒
所有词分不开 嵌入空间塌缩,区分度丢失 语义压缩——训练表征退化

向量相似度不是语义相似度。 它只是一个几何度量,受制于高维空间的反直觉特性和训练过程的统计偏差。本文描述的四种现象不是”Bug”——它们是嵌入系统的固有属性。理解它们,你才能在实际的 RAG、搜索、推荐系统中做出正确的工程判断,知道什么时候该相信余弦相似度、什么时候该对其保留怀疑。

最后送一句话:在嵌入空间里,”近”不一定是同类,”远”不一定是异类——你看到的是几何的投影,不是语义的真相。