在接触大语言模型(LLM)或自然语言处理(NLP)时,Tokenizer(分词器) 和 Embedding(嵌入) 是两个出现频率极高,却常被初学者混淆的概念。它们似乎都在做“把文字变成数字”的工作,但它们在模型中的角色、原理和目的却截然不同。
简单来说:Tokenizer 负责“认字”(将文本切分为离散的符号),而 Embedding 负责“理解”(将符号转化为包含语义的数学向量)。
Tokenizer(分词器):LLM 的“字典”
大模型无法直接阅读我们看到的文字(如中文汉字或英文字母),它只能处理数字。Tokenizer 的工作就是充当翻译前的“查字典”步骤。
核心任务
Tokenizer 的作用是将非结构化的 原始文本(Raw Text) 切分成模型能处理的最小单位——Token,并将这些 Token 映射为唯一的整数索引(Input IDs)。
工作流程
- 切分(Splitting): 依据特定的规则(如空格、标点、或更高级的算法如 BPE、WordPiece),将句子切开。
- 映射(Mapping): 在一个预先构建好的词表(Vocabulary)中查找每个片段对应的编号。
举个例子
假设我们的输入是:“我爱AI”
- Tokenizer 切分:
["我", "爱", "AI"] - 查表映射: 假设在词表中,“我”是 5,“爱”是 20,“AI”是 101。
- Tokenizer 输出:
[5, 20, 101]
关键特征
- 输出是离散的整数: 比如
101代表 “AI”,102可能就代表完全不相关的 “香蕉”。在 Tokenizer 的阶段,数字之间没有数学上的关联(101 和 102 仅仅是索引的先后,没有语义上的远近)。 - 它不包含语义: Tokenizer 不知道”我”和”你”是相似的代词,它只知道它们在词表中位于不同的位置。
工作流程可视化
graph LR
A[原始文本
'我爱AI'] --> B[预处理
Normalization]
B --> C[切分算法
BPE/WordPiece]
C --> D["Token序列
['我','爱','AI']"]
D --> E[词表查找
Vocabulary Lookup]
E --> F["Token IDs
[5, 20, 101]"]
style A fill:#e1f5ff
style F fill:#fff4e1
常见的Tokenizer算法
现代大语言模型主要使用以下几种分词算法:
| 算法 | 代表模型 | 特点 | 优势 |
|---|---|---|---|
| BPE (Byte Pair Encoding) | GPT系列 | 基于字节对频率合并 | 能有效处理未登录词,压缩率高 |
| WordPiece | BERT | 基于似然最大化 | 平衡了词汇量和表达能力 |
| SentencePiece | Llama、T5 | 直接处理原始文本 | 语言无关,支持多语言 |
| Unigram | mBART | 基于概率模型 | 可以生成多种分词方案 |
特殊Token说明
在词表中,除了普通词汇,还有一些特殊的Token用于控制模型行为:
[PAD]:填充符,用于对齐不同长度的序列[UNK]:未知词,处理词表外的词汇[CLS]:句子开始符(BERT)[SEP]:句子分隔符[MASK]:掩码符(用于MLM任务)<|endoftext|>:文本结束符(GPT)
Embedding(嵌入层):LLM 的“大脑连接”
如果说 Tokenizer 只是把文字变成了身份证号,那么 Embedding 就是把这些身份证号变成了包含丰富特征的个人档案。
核心任务
Embedding 是一个查找表(Lookup Table)或神经网络层,它将 Tokenizer 输出的整数 ID 转换为一个高维稠密向量(Dense Vector)。这个向量是一串浮点数,代表了该词在语义空间中的位置。
工作流程
- 接收输入: 拿到 Tokenizer 传来的 ID(例如
101)。 - 向量化: 在高维空间中找到
101对应的向量表示。
举个例子
继续上面的“我爱AI”,输入 ID 为 [5, 20, 101]。
- Embedding 转化:
5(“我”) →[0.12, -0.58, 0.99, ...]20(“爱”) →[0.77, 0.23, -0.11, ...]101(“AI”) →[-0.45, 0.88, 0.02, ...]
关键特征
- 输出是连续的浮点数向量: 比如 768 维或 4096 维的数组。
- 它包含语义(Semantic Meaning): 这是 Embedding 最神奇的地方。在训练过程中,模型学会了将含义相近的词放在向量空间中靠近的位置。
- 例如:在向量空间中,”猫”和”狗”的距离会非常近,而”猫”和”冰箱”的距离会很远。
- 经典的例子:King(国王) - Man(男人) + Woman(女人) ≈ Queen(女王)。这种数学运算只有在 Embedding 层之后才能实现,在 Tokenizer 阶段的整数 ID 上是做不到的。
语义空间可视化
graph TB
subgraph 动物语义空间
A1[猫
Cat]
A2[狗
Dog]
A3[老虎
Tiger]
end
subgraph AI技术语义空间
B1[机器学习
ML]
B2[深度学习
DL]
B3[神经网络
NN]
end
subgraph 日常用品语义空间
C1[冰箱
Fridge]
C2[桌子
Table]
C3[椅子
Chair]
end
A1 -.语义相近.-> A2
A2 -.语义相近.-> A3
B1 -.语义相近.-> B2
B2 -.语义相近.-> B3
C2 -.语义相近.-> C3
A1 ~~~|语义距离远| C1
style A1 fill:#ffd6d6
style A2 fill:#ffd6d6
style A3 fill:#ffd6d6
style B1 fill:#d6e5ff
style B2 fill:#d6e5ff
style B3 fill:#d6e5ff
style C1 fill:#e1ffe1
style C2 fill:#e1ffe1
style C3 fill:#e1ffe1
Embedding 维度的选择
不同模型使用不同的向量维度,这是性能与效率的权衡:
| 模型 | Embedding维度 | 参数量影响 |
|---|---|---|
| BERT-base | 768 | 较小,训练快 |
| BERT-large | 1024 | 中等 |
| GPT-3 | 12288 | 极大,表达能力强 |
| Llama-2-7B | 4096 | 平衡性能与效率 |
维度越大:
- ✅ 表达能力越强,能捕捉更细微的语义差异
- ✅ 模型容量更大,理解能力更强
- ❌ 计算成本更高,内存占用更大
- ❌ 更容易过拟合(在小数据集上)
Position Embedding
值得注意的是,除了词嵌入(Token Embedding),模型还会加入 位置嵌入(Position Embedding) 来告诉模型词的先后顺序:
1 | 最终输入 = Token Embedding + Position Embedding |
这是因为 Transformer 架构本身不具备序列顺序的概念,需要通过位置编码来补充位置信息。
核心区别对比表
为了更直观地理解,我们可以从以下几个维度对比:
| 维度 | Tokenizer (分词器) | Embedding (嵌入层) |
|---|---|---|
| 输入 | 原始文本字符串 (Text) | 整数索引 (Token IDs) |
| 输出 | 整数索引列表 (如 [101, 205]) |
高维浮点数向量 (如 [0.1, -0.9...]) |
| 数据性质 | 离散的 (Discrete):数字仅代表位置 | 连续的 (Continuous):数字代表特征 |
| 是否包含语义 | 不包含:只做硬性映射 | 包含:捕捉词义、词性、关联 |
| 可训练性 | 通常在预训练前固定 (如 BPE 算法统计得出) | 是模型参数的一部分,随模型训练不断优化 |
| 类比 | 字典索引:查到“苹果”在第 10 页 | 对苹果的理解:圆的、红的、水果、甜的 |
它们是如何协作的?(Pipeline)
在任何一个现代大语言模型(如 GPT-4, Llama 3, BERT)中,数据流向都是固定的串行关系:
- 用户输入:
What is tokenizer? - Tokenizer 层: 切分并映射为 ID →
[2054, 2003, 19204, 1029] - Embedding 层: 将 ID 转化为向量 →
[[0.1, ...], [0.5, ...], ...] - Transformer 层(Attention): 模型在向量基础上进行复杂的数学运算(注意力机制等),理解上下文。
完整数据流转过程
graph TD
A[用户输入文本
'What is tokenizer?'] --> B[Tokenizer 预处理]
B --> C[Token切分
What/is/token/izer/?]
C --> D["ID映射
[2054, 2003, 19204, 1029]"]
D --> E[Embedding层
查找表Lookup]
E --> F["Token向量矩阵
Shape: [4, 768]"]
F --> G[+ Position Embedding]
G --> H[最终输入向量]
H --> I[Transformer层
Self-Attention]
I --> J[前馈神经网络
FFN]
J --> K[Layer Normalization]
K --> L[...重复N层]
L --> M[输出层
Language Model Head]
M --> N[预测结果]
style A fill:#e1f5ff
style D fill:#fff4e1
style F fill:#ffe1f5
style H fill:#e1ffe1
style N fill:#ffe1e1
classDef tokenizer fill:#fff4e1,stroke:#ffa500
classDef embedding fill:#ffe1f5,stroke:#ff1493
classDef model fill:#e1ffe1,stroke:#00ff00
class B,C,D tokenizer
class E,F,G,H embedding
class I,J,K,L,M model
数据形状变化
让我们追踪一个具体的例子,看数据是如何逐步变化的:
| 阶段 | 数据内容 | 数据类型 | 数据形状 |
|---|---|---|---|
| 原始输入 | "What is tokenizer?" |
String(字符串) | - |
| Tokenizer输出 | [2054, 2003, 19204, 1029] |
List[int](整数列表) | [4] |
| Embedding输出 | [[0.12, -0.58, ...], [...], ...] |
Tensor(浮点张量) | [4, 768] |
| +Position Embedding | [[0.15, -0.50, ...], [...], ...] |
Tensor(浮点张量) | [4, 768] |
| 经过Transformer | [[0.88, 0.23, ...], [...], ...] |
Tensor(浮点张量) | [4, 768] |
| 输出层 | [[0.01, 0.85, 0.03, ...]] |
Tensor(概率分布) | [4, 50257] |
关键观察:
- Tokenizer → Embedding:从离散变为连续
- Embedding → Transformer:维度保持不变,但语义理解加深
- 最后输出:从隐藏表示转换为词表概率分布(用于预测下一个词)
常见误区与易混淆点
在学习过程中,很多初学者会产生以下误解:
❌ 误区1:认为 Tokenizer 的输出已经包含语义
错误理解: “既然 Token ID 101 代表 ‘AI’,那它不就已经有意义了吗?”
正确理解: Token ID 只是索引编号,就像身份证号一样。身份证号 330106 和 330107 相邻,但这不代表这两个人有任何关系。只有经过 Embedding 层,模型才能理解词与词之间的语义关联。
❌ 误区2:混淆 Token ID 和 Embedding 向量
错误理解: “Token ID [101, 102] 不就是二维向量吗?”
正确理解:
- Token ID
[101, 102]是两个整数,不是向量 - Embedding 后是 两个高维向量,如
[[0.1, 0.2, ..., 0.9], [0.5, 0.3, ..., 0.1]],每个向量有 768 或更多维度
❌ 误区3:认为 Embedding 是固定不变的
错误理解: “Embedding 就是个查找表,训练前就确定好了。”
正确理解: Embedding 层的权重矩阵是可训练的。在模型训练过程中,它会不断调整,使得语义相近的词在向量空间中越来越接近。这是模型”学习”语义的核心机制。
❌ 误区4:认为 Tokenizer 和 Embedding 可以互换
错误理解: “我可以用不同的 Tokenizer 配同一个模型吗?”
正确理解: 不可以! Tokenizer 的词表和 Embedding 层的权重矩阵必须严格对应:
- 词表中第 101 个位置是 “AI”
- Embedding 矩阵的第 101 行存储的就是 “AI” 的向量表示
- 如果 Tokenizer 改变,Embedding 矩阵也必须重新训练
✅ 正确的理解框架
graph LR
A[Tokenizer
文字→数字索引] --> B[Embedding
索引→语义向量]
B --> C[模型计算
向量→理解]
A -.不可分离.-> B
style A fill:#fff4e1
style B fill:#ffe1f5
style C fill:#e1ffe1
- Tokenizer 和模型的 Embedding 层是绑定的,不能分离
- Tokenizer 处理的是符号映射(Symbol Mapping)
- Embedding 处理的是语义表示(Semantic Representation)
- 两者配合完成从”文字”到”机器可理解的数学对象”的转换
总结
Tokenizer 和 Embedding 缺一不可,但分工明确:
- Tokenizer 解决了 “如何把无限的自然语言文本映射到有限的数字集合” 的问题。它是数据进入模型的入口。
- Embedding 解决了 “如何让计算机理解这些数字背后的含义和关系” 的问题。它是模型进行思考的基础。
实践:用代码看清两者
理论理解后,让我们用实际代码演示整个过程:
使用 Transformers 库演示:
1 | from transformers import AutoTokenizer, AutoModel |
关键观察
- Tokenizer 输出是列表:
[2054, 2003, ...]- 简单的整数 - Embedding 输出是张量:
torch.Size([1, 5, 768])- 高维浮点向量 - 语义相似性只在Embedding之后才有意义:cat和dog的向量相似度明显高于cat和car
直接访问Embedding层:
1 | # 直接获取模型的Embedding矩阵 |
这个矩阵就是Embedding层的本质:一个 [词表大小 × 向量维度] 的查找表,每一行对应词表中一个词的向量表示。
延伸阅读与资源
经典论文:
推荐工具:
- Hugging Face Transformers - 最流行的预训练模型库
- SentencePiece - Google的语言无关Tokenizer
- tiktoken - OpenAI的高效Tokenizer
可视化工具:
- Embedding Projector - 可视化词向量空间
- BertViz - 可视化注意力机制