Embedding:从 Token 到向量表示

上一篇介绍了 Token。文本进入大模型后,通常会经历以下过程:
text
文本
↓
Tokenizer
↓
Token
↓
Token ID
例如:
text
"我喜欢猫"
↓
[我] [喜欢] [猫]
↓
[1024, 5832, 9217]
但 Token ID 只是词表中的索引,并不直接携带可解释的语义。假设:
text
猫 → 9217
狗 → 9218
汽车 → 9219
这些编号之间的大小关系,并不能说明"猫"和"狗"比"猫"和"汽车"更相似。
模型真正使用的是 Embedding。
Embedding 是将离散的 Token 映射为连续向量表示的过程。
例如:
text
猫 → [0.82, 0.31, -0.42, 0.71]
狗 → [0.76, 0.28, -0.35, 0.68]
汽车 → [-0.12, 0.91, 0.17, -0.63]
这些向量可以参与点积、矩阵乘法和相似度计算等操作,从而进入 Transformer 的后续计算。
Token ID 与 Embedding 的区别
Token ID 只是编号:
text
猫 → 1001
狗 → 1002
汽车 → 1003
Embedding 则是向量表示:
text
猫 → [0.82, 0.31, -0.42, ...]
狗 → [0.76, 0.28, -0.35, ...]
汽车 → [-0.12, 0.91, 0.17, ...]
可以这样理解:
Token ID 用于定位 Token,Embedding 用于表示 Token。
如果把 Token ID 看作数据库中的主键,那么 Embedding 就像该记录对应的特征向量。不过,Embedding 并不是人工定义的标签,而是模型在训练过程中学习得到的参数表示。
Embedding 的数学形式
假设词表大小为 (V),向量维度为 (d),Embedding 可以表示为一个矩阵:
E \in \mathbb{R}^{V \times d}\
这里的含义是:
- (E) 表示 Embedding 矩阵;
- (V) 表示词表中 Token 的数量;
- (d) 表示每个 Token 的向量维度;
- (\mathbb{R}^{V \times d}) 表示这是一个包含 (V) 行、每行 (d) 个实数的矩阵。
其中,每一行对应一个 Token 的向量:
text
Embedding Matrix
d 个维度
↓
┌──────────────────────┐
│ Token 1 x x x x x │
│ Token 2 x x x x x │
│ Token 3 x x x x x │
│ ... │
│ Token V x x x x x │
└──────────────────────┘
↑
V 个 Token
如果某个 Token 的 ID 是 9217,模型就会取出矩阵中的对应行:
\mathbf{e}\_{9217} = E9217\
这里的 (\mathbf{e}_{9217}) 表示 ID 为 9217 的 Token 对应的向量。这个操作本质上是根据 Token ID 从 Embedding 矩阵中查找对应行。
得到的结果可能是:
text
[0.82, 0.31, -0.42, 0.71, ...]
因此,Token ID 到 Embedding 的过程,本质上是一次矩阵查表操作。
真实模型中的向量维度通常较高,例如 768、1024 或更高:
text
Token
↓
Embedding
↓
[x₁, x₂, x₃, ..., xₙ]
这些维度通常没有明确的一一对应关系。不能简单地认为某一维代表"动物",另一维代表"可爱"。语义信息通常分布在整个向量空间中,由多个维度共同表达。
Embedding 是如何学习出来的?
Embedding 不是人工为每个词指定的,而是模型在训练过程中通过梯度下降学习得到的。
训练开始时,Embedding Matrix 通常会被随机初始化。模型在大量文本上进行预测:
text
输入:
我喜欢吃____
预测:
汽车
真实答案:
苹果
模型根据预测误差计算损失,并通过反向传播更新参数:
text
预测
↓
Loss
↓
Gradient
↓
Backpropagation
↓
更新参数
Embedding Matrix 也会随之更新。经过大量训练后,出现在相似上下文中的 Token,往往会形成更接近的向量表示。
例如,"猫"和"狗"经常出现在相似的语境中,模型可能会逐渐学到它们之间的某些相似性;而"汽车"通常出现在不同的语境中,其向量位置可能与前两者相距更远。
需要注意的是,这并不意味着 Embedding 直接存储了一个明确的词典定义。它更像是模型根据上下文统计和预测任务学习到的一种内部表示。
向量空间与语义关系
Embedding 将 Token 映射到了一个连续的高维空间。向量之间的距离或方向关系,可以反映一定的语义和使用关系。
例如,在简化的二维空间中:
text
猫 → (0.8, 0.7)
狗 → (0.7, 0.8)
汽车 → (0.1, 0.2)
飞机 → (0.2, 0.1)
"猫"和"狗"可能在空间中更接近,"汽车"和"飞机"也可能更接近。
需要注意的是,这种关系并不是由某个单独维度决定的,而是由整个向量空间中的几何关系共同体现。向量之间的接近程度也不是绝对的"词义相同",而是表示它们在特定模型和训练数据中具有相似的表示或使用模式。
相似度计算
常见的向量相似度指标包括欧氏距离、点积和余弦相似度。文本检索中经常使用余弦相似度:
\cos(\theta)=\frac{\mathbf{A}\cdot\mathbf{B}}{\lVert\mathbf{A}\rVert\lVert\mathbf{B}\rVert}\
这个公式可以分成三部分理解:
- (\mathbf{A}\cdot\mathbf{B}) 是两个向量的点积,用于衡量它们在各个维度上的共同方向;
- (\lVert\mathbf{A}\rVert) 和 (\lVert\mathbf{B}\rVert) 是两个向量的模长,也就是向量的长度;
- 分母用于消除向量长度的影响,使结果主要反映方向之间的接近程度。
其中,向量的点积可以展开为:
\sum_{i=1}^{d} A_iB_i\
这个公式表示:将两个向量对应位置的元素分别相乘,再把所有结果相加。 向量的模长可以表示为: \sqrt{\sum\_{i=1}^{d} A\_i^2}\
它表示向量的长度。余弦相似度的取值通常在 (-1,1) 之间:
- 越接近 (1),表示两个向量方向越接近;
- 接近 (0),表示两个向量方向差异较大;
- 越接近 (-1),表示两个向量方向相反。
不过,实际系统使用哪种相似度指标,还取决于模型训练方式、向量是否经过归一化,以及向量数据库的实现。余弦相似度只是常见选择之一,并不是所有场景下的唯一方案。
Embedding 与语义搜索
Embedding 是语义搜索的重要基础。
假设用户输入:
text
怎么学习 Java 并发?
系统首先将问题转换为查询向量:
text
Query
↓
Embedding Model
↓
Query Vector
知识库中的文档也会预先转换为向量:
text
文章 A → Vector A
文章 B → Vector B
文章 C → Vector C
然后计算查询向量与文档向量之间的相似度:
text
A → 0.42
B → 0.87
C → 0.31
系统可以优先返回相似度较高的文档。
与单纯依赖关键词的搜索相比,Embedding 更关注语义关系。例如:
text
"Java 程序内存越来越高怎么办?"
可能与:
text
"Java 内存泄漏"
具有较高的语义相似度,即使两者并不完全包含相同的关键词。
不过,Embedding 搜索并不能完全替代关键词搜索。对于错误码、产品型号、专有名词等内容,关键词匹配往往更加准确。因此,实际系统中经常会结合关键词检索和向量检索,形成混合搜索。
Embedding 与 RAG
RAG 通常依赖 Embedding 完成文档召回。
建立知识库时:
text
文档
↓
切分 Chunk
↓
Embedding
↓
Vector
↓
Vector Database
用户查询时:
text
用户问题
↓
Embedding
↓
Query Vector
↓
向量检索
↓
相关 Chunk
↓
加入上下文
↓
LLM 生成答案
因此,Embedding 负责将用户问题和知识库内容映射到同一个向量空间,向量数据库负责检索相近内容,LLM 则负责结合检索结果生成回答。
需要注意的是,Embedding 主要负责"召回相关内容",并不负责最终回答。即使向量检索效果很好,如果文档切分不合理、召回数量不合适,或者上下文组织方式存在问题,RAG 仍然可能生成不准确的结果。
Embedding 的其他应用
Embedding 不仅用于 RAG,还广泛应用于:
- 语义搜索
- 推荐系统
- 文本聚类
- 文本分类
- 意图识别
- 内容审核
- 代码检索
- 图片搜索
- 多模态匹配
例如,推荐系统可以分别生成用户和商品的向量:
text
用户 → User Embedding
商品 → Item Embedding
通过计算两者的相似度,可以估计用户对商品的兴趣。
代码搜索系统也可以将自然语言问题和代码片段转换为向量,从而检索语义相关的实现。
图片和文本同样可以被映射到共享向量空间,实现"以文搜图"等跨模态检索能力。
Token Embedding 与 Embedding Model
工程实践中,"Embedding"通常有两种语境。
第一种是模型内部的 Token Embedding:
text
Token ID
↓
Embedding Matrix
↓
Transformer
它是大模型输入层的一部分,用于将 Token ID 转换为模型内部的向量。
第二种是专门用于检索的 Embedding Model:
text
文本
↓
Embedding Model
↓
固定长度向量
↓
Vector Database
它通常用于语义搜索、RAG、推荐和聚类等任务。
两者的基本思想相同,都是将输入转换为向量,但用途、训练目标和模型结构可能不同。模型内部的 Token Embedding 主要服务于语言模型的后续计算,而检索模型生成的向量通常需要在不同文本之间保持较好的语义可比较性。
总结
Embedding 的核心作用可以概括为:
将离散的信息转换为连续向量,使计算机能够通过数学运算表示和比较它们之间的关系。
完整流程可以表示为:
text
文本
↓
Token
↓
Token ID
↓
Embedding
↓
向量空间
↓
相似度计算
↓
搜索 / 推荐 / RAG / 分类
Token 解决的是"文本如何切分和编号",Embedding 解决的是"这些 Token 如何以可计算的形式表示"。
不过,单个 Token 的向量还不足以表达完整句子的含义。多个 Token 的向量进入 Transformer 后,模型还需要进一步建模它们之间的关系。
例如在"我喜欢苹果"中,模型需要判断"喜欢"和"苹果"之间的关联,也需要根据上下文判断"苹果"指的是水果,还是 Apple 公司。
这就需要进入 Transformer 的核心机制:
text
Embedding
↓
Q、K、V
↓
Attention Score
↓
Softmax
↓
Attention Weight
↓
加权求和
↓
新的上下文表示