一、从文字到数字:为什么需要 Embedding?
在传统信息检索中,我们主要依赖关键词匹配。但这种方式存在明显缺陷:用户搜索“苹果”,系统可能返回水果相关文档,也可能返回苹果公司新闻,因为它无法理解语义。更进一步,用户搜索“好吃的手机”,传统方法可能束手无策。
Embedding(嵌入) 技术正是为了解决这个问题而生。它的核心思想是将离散的、高维的符号(如单词、句子、图片)映射到一个连续的、低维的向量空间中。在这个空间里,语义相近的物体,其向量表示也相近。“苹果(水果)”和“香蕉”的向量距离,会比“苹果(水果)”和“苹果公司”的向量距离更小。
这个转换过程就像把复杂的语义信息“压缩”编码成一组数字。一旦万物皆可向量化,我们就能用数学中的距离计算(如余弦相似度)来精准衡量它们之间的语义相似程度,这为智能检索、推荐系统等应用打开了大门。
二、向量空间与相似度计算
Embedding 生成的向量存在于一个多维的几何空间中。想象一个三维空间,每个点(向量)代表一个词或句子。向量之间的“距离”或“夹角”直接反映了它们在语义上的亲疏关系。
计算两个向量相似度最常用的方法是余弦相似度。它通过计算两个向量夹角的余弦值来衡量方向的一致性,取值范围在 -1 到 1 之间。值越接近 1,表示两个向量方向越一致,语义越相似。
提示:余弦相似度关注的是向量的方向而非大小。例如,“我喜欢猫”和“我非常喜欢猫”表达的情感方向一致,只是强度不同,它们的向量夹角很小,余弦相似度接近1,这非常符合我们的语义直觉。
除了余弦相似度,欧氏距离和点积也常用于相似度计算。欧氏距离衡量的是两点间的直线距离,值越小越相似;点积则综合考虑了方向和大小。在实际应用中,需要根据模型和场景选择合适的度量方式。
三、常见的 Embedding 模型
生成高质量的 Embedding 是关键。模型大致可分为静态和动态两大类。
- 静态词嵌入:如 Word2Vec、GloVe。它们为每个词生成一个固定的向量,不考虑上下文。优点是简单高效,但无法处理一词多义问题(例如“苹果”在不同语境下的向量是相同的)。
- 动态上下文嵌入:以 BERT、GPT 系列为代表的 Transformer 模型是主流。它们生成的词向量会根据上下文动态变化。“苹果”在“吃苹果”和“苹果发布”中的向量表示会截然不同。这极大地提升了语义表征的精确性。
对于句子和段落的 Embedding,我们通常是在词向量基础上进行池化(如取平均),或者直接使用专门训练的句子编码模型(如 sentence-transformers 库中的模型)。
四、构建语义检索系统的完整流程
一个典型的基于 Embedding 的语义检索系统,其工作流程可以分为三步:
- 离线索引:将知识库(所有文档)通过 Embedding 模型转换为向量,并存入专门的向量数据库(如 Faiss、Milvus)或索引结构中。
- 在线查询:当用户输入查询时,同样将其转换为向量。
- 检索与排序:在向量空间中,找到与查询向量最相似的 top-k 个文档向量,并返回对应的原始文档。
下面是一个用 Python 演示的简化流程代码,使用了 sentence-transformers 库和 faiss 库:
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# 1. 加载预训练的句子编码模型
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
# 2. 准备知识库文档
documents = [
"如何学习Python编程?",
"人工智能的基础是什么?",
"推荐几本深度学习书籍",
"今天天气真不错"
]
# 3. 将文档编码为向量(离线索引阶段)
doc_embeddings = model.encode(documents)
print(f"文档向量维度:{doc_embeddings.shape}") # (4, 384)
# 4. 构建 FAISS 索引
dimension = doc_embeddings.shape[1]
index = faiss.IndexFlatIP(dimension) # 使用内积(等价于余弦相似度,需归一化)
# 为了使用内积近似余弦相似度,需要对向量进行L2归一化
faiss.normalize_L2(doc_embeddings)
index.add(doc_embeddings.astype('float32'))
# 5. 处理用户查询
query = "深度学习入门指南"
query_embedding = model.encode([query])
faiss.normalize_L2(query_embedding)
# 6. 进行语义检索(在线查询阶段)
k = 2 # 返回最相似的前2个结果
distances, indices = index.search(query_embedding.astype('float32'), k)
print(f"\n查询:'{query}'")
print("最相关的文档:")
for i, idx in enumerate(indices[0]):
print(f" {i+1}. {documents[idx]} (相似度: {distances[0][i]:.4f})")
输出可能为:
查询:'深度学习入门指南'
最相关的文档:
1. 推荐几本深度学习书籍 (相似度: 0.7562)
2. 人工智能的基础是什么? (相似度: 0.5831)
可以看到,系统正确地识别出与“深度学习入门指南”语义最相关的是“推荐几本深度学习书籍”,而不是仅仅包含“学习”一词的“如何学习Python编程?”,这正是语义检索的魅力所在。
五、向量数据库与检索优化
当知识库达到百万、千万甚至上亿量级时,暴力计算查询向量与所有文档向量的相似度(如上例所示)会变得极其缓慢。这时就需要近似最近邻技术。
向量数据库的核心优化在于索引算法。常见的 ANN 索引包括:
- IVF(Inverted File Index):先对向量空间进行聚类,检索时只搜索查询向量所属簇及相邻簇。
- HNSW(Hierarchical Navigable Small World):构建多层图结构,通过导航快速定位近邻。
- PQ(Product Quantization):将向量分段量化压缩,大幅减少内存占用和计算量。
选择索引需要在召回率、查询速度和内存占用之间做权衡。在实际部署中,通常会对原始向量进行归一化处理,并选用支持分布式查询的向量数据库(如 Milvus)。
六、进阶思考与局限
虽然 Embedding 和语义检索强大,但也需了解其边界。首先,模型的效果严重依赖于训练数据和任务,可能存在偏见。其次,对于需要精确逻辑推理或高度结构化的查询(如“北京今天气温大于25度吗?”),纯粹的语义相似性检索可能不如知识图谱或传统数据库查询有效。
一个实用的策略是混合检索:结合关键词检索(BM25等算法)和向量语义检索。前者保证对精确术语的高召回,后者处理模糊、同义表达,两者的结果再进行融合排序,能产生更鲁棒的效果。
七、总结
Embedding 向量化技术将语义信息转化为可计算的数学对象,奠定了现代语义检索的基石。其核心路径是:文本 -> Embedding 模型 -> 向量 -> 相似度计算/ANN检索。从理解 Word2Vec 的“国王-男人+女人≈女王”的经典类比,到掌握 BERT 时代的上下文表征,再到利用向量数据库实现海量数据的快速检索,这条技术链路为构建智能应用提供了强大的底层支持。动手尝试文中代码,是你迈向实战的第一步。