趋近智
嵌入将文本意义有效地以数值形式表示。为了找到相关内容,你需要判断这些数值向量之间的‘接近程度’或‘相似度’。此项判定是通过向量相似度指标来完成的。
可以将每个嵌入看作高维空间中的一个点。在这个空间中,意义相似的文本彼此靠近,而意义不同的文本则相距较远。相似度指标是计算这些点之间距离或角度关系的数学函数。
相关术语在向量空间中紧密聚集,根据其语义形成不同的群组。
存在多种指标,但对于文本嵌入,有一个最为常用和有效:那就是余弦相似度。
余弦相似度计算两个向量夹角的余弦值。此指标特别适合文本嵌入,因为它注重向量的方向而非其大小。方向捕获语义内容,而大小有时并不那么关键,特别是考虑到大多数现代嵌入模型生成的是归一化向量(长度为1的向量)。
基本思路很简单:
两个向量 和 之间余弦相似度的公式是:
当向量归一化为长度 1 时,分母 变为 1,余弦相似度就简化为两个向量的点积 。
你可以使用 cosine_similarity 函数轻松计算此值。我们来比较相关词和不相关词之间的相似度。
from kerb.embedding import embed, cosine_similarity
# 生成两个相似词的嵌入
vec1 = embed("Hello")
vec2 = embed("Hi")
sim_related = cosine_similarity(vec1, vec2)
print(f"“Hello”和“Hi”之间的相似度:{sim_related:.4f}")
# 生成两个不相关词的嵌入
vec3 = embed("Car")
sim_unrelated = cosine_similarity(vec1, vec3)
print(f"“Hello”和“Car”之间的相似度:{sim_unrelated:.4f}")
如预期的那样,“Hello”和“Hi”的相似度得分较高,而“Hello”和“Car”的得分非常低,这反映了它们之间语义关联的缺乏。
虽然余弦相似度最为常用,但该工具包也提供在不同情况下有用的其他指标。与余弦相似度不同,这些是距离指标,其中较低的值表示更高的相似度。
欧几里得距离是向量空间中两点之间的直线距离。它兼顾向量的方向和大小。距离为 0 表示向量完全相同。
曼哈顿距离,也称为“城市街区”距离,是向量各分量绝对差值的总和。它通常比欧几里得距离对异常值不那么敏感。
点积衡量一个向量在另一个向量方向上的分量。对于归一化向量,它与余弦相似度相同。但是,对于非归一化向量,它对向量的大小敏感,这意味着较长的向量可能产生不成比例的较大影响。
我们来看看这些指标在同一组文本上的比较情况。
from kerb.embedding import embed, euclidean_distance, manhattan_distance, dot_product
vec_a = embed("Python programming language")
vec_b = embed("Python coding and development")
vec_c = embed("JavaScript web framework")
# 欧几里得距离(值越小越相似)
dist_ab = euclidean_distance(vec_a, vec_b)
dist_ac = euclidean_distance(vec_a, vec_c)
print(f"欧几里得距离(相似文本):{dist_ab:.4f}")
print(f"欧几里得距离(不同文本):{dist_ac:.4f}")
# 点积(值越大越相似)
dot_ab = dot_product(vec_a, vec_b)
dot_ac = dot_product(vec_a, vec_c)
print(f"\n点积(相似文本):{dot_ab:.4f}")
print(f"点积(不同文本):{dot_ac:.4f}")
你可以看到,对于相似的文本对,欧几里得距离更小,而点积更大,两者都正确指明了更紧密的关联。
对于大多数基于文本的语义搜索应用,余弦相似度是推荐的指标。由于现代嵌入模型生成归一化向量,它们的长度不带有太多信息,而关注角度(方向)能提供最可靠的语义关联判定。
batch_similarity 函数提供一种高效的方法,可以使用任何可用指标将单个查询向量与文档向量集合进行比较。这是语义搜索系统的基础。
from kerb.embedding import embed, embed_batch, batch_similarity
query_text = "cloud computing infrastructure"
documents = [
"Cloud services and platforms",
"Infrastructure as a service",
"Traditional on-premise servers",
"Mobile app development",
]
query_emb = embed(query_text)
doc_embeddings = embed_batch(documents)
# 比较不同指标的得分
cosine_scores = batch_similarity(query_emb, doc_embeddings, metric="cosine")
print("余弦相似度(值越大越好):")
for doc, score in zip(documents, cosine_scores):
print(f" [{score:.4f}] {doc}")
euclidean_scores = batch_similarity(query_emb, doc_embeddings, metric="euclidean")
print("\n欧几里得距离(值越小越好):")
for doc, score in zip(documents, euclidean_scores):
print(f" [{score:.4f}] {doc}")
请注意,两个指标都正确地将“Cloud services and platforms”和“Infrastructure as a service”识别为最相关的文档。然而,它们的评分范围和解读有所不同。余弦相似度提供了一个介于 -1 和 1 之间的归一化、易于理解的分数,从而更容易设定一致的相关性阈值。
在对嵌入及其比较方式有了扎实掌握后,你现在可以开始构建你的第一个语义搜索功能了。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造