生成日期:2026-06-26 主题:token id 如何变成 embedding、embedding table 的内部机制、位置编码、训练更新,以及它在 LLM 整体流程中的作用 适合读者:知道 LLM 会“分词”,但想弄清楚数字 id 怎么进入神经网络的人
0. 先看结论
LLM 不能直接处理文字。它先把文本切成 token,再把每个 token 映射成一个整数 id,最后用这个 id 去 embedding table 里查一行向量。
1 | 文本 -> tokenizer -> token ids -> embedding lookup -> token embeddings -> Transformer |
比如:
1 | "我喜欢猫" |
可能被 tokenizer 变成:
1 | tokens: ["我", "喜欢", "猫"] |
再查 embedding table:
1 | 1024 -> E[1024] |
得到三个向量后,模型才能开始计算。
1 | flowchart LR |
1. 为什么需要 embedding
文字是离散符号,神经网络擅长处理连续数值。
| 表示方式 | 例子 | 问题 |
|---|---|---|
| 原始文字 | "猫" |
模型不能直接矩阵乘 |
| token id | 941 |
只是编号,没有语义距离 |
| embedding | [0.12, -0.38, ...] |
可参与神经网络计算 |
token id 本身没有语义。941 不比 940 更接近
猫,也不代表第 941 个 token 比第 940 个 token
“大”。它只是词表里的行号。
embedding 的作用是把这个行号变成可学习的向量。
2. 从文本到 token id
2.1 tokenizer 做什么
Tokenizer 的工作是把文本切成模型词表里的 token,并把 token 转成 id。
1 | 输入文本: "Transformers are powerful" |
不同 tokenizer 的切分方式不同。常见方法有:
| 方法 | 常见位置 | 特点 |
|---|---|---|
| BPE | GPT 系列常见 | 从字符/字节片段合并高频片段 |
| WordPiece | BERT 系列常见 | 子词切分,常用 ## 标记后缀 |
| SentencePiece | 多语言模型常见 | 把文本当原始字符流处理,不强依赖空格 |
| Byte-level BPE | GPT-2 之后常见 | 能覆盖任意字节,较少出现未知字符 |
Tokenizer 不是神经网络主体的一层。它通常是一个确定性预处理器:同一段文本、同一套 tokenizer,输出的 token ids 应该一致。
2.2 token id 是词表索引
模型有一个 vocabulary,也就是词表。词表可以看成:
| token id | token |
|---|---|
| 0 | <unk> |
| 1 | <bos> |
| 2 | <eos> |
| 941 | 猫 |
| 1024 | 我 |
| 5832 | 喜欢 |
token id 就是 token 在词表里的编号。
注意:编号大小没有语义。1024 和 1025
是否语义接近,取决于它们对应 token 的 embedding,而不是 id 数值。
3. Embedding table 是什么
Embedding table 是一个可训练矩阵:
\[ E\in \mathbb{R}^{V\times d_{\text{model}}} \]
其中:
| 符号 | 含义 |
|---|---|
| \(V\) | 词表大小,也就是 token 总数 |
| \(d_{\text{model}}\) | 模型隐藏维度 |
| \(E\) | embedding table |
如果词表大小 \(V=50,000\),模型维度 \(d_{\text{model}}=4096\),那么 embedding table 的形状就是:
1 | 50000 x 4096 |
第 i 行就是 token id 为 i 的向量:
\[ \mathrm{embedding}(i)=E_i \]
4. 查表机制:id 怎么变成向量
假设输入 token ids 是:
1 | [1024, 5832, 941] |
embedding lookup 做的是:
1 | 取第 1024 行 |
结果是:
1 | [ |
如果每个 embedding 是 4096 维,那么输出形状是:
1 | sequence length x d_model |
对 batch 输入:
1 | input_ids shape: [batch, seq_len] |
5. 查表等价于 one-hot 乘矩阵
token id 查表也可以写成矩阵乘法。
假设词表大小为 5,token id 是 2。它的 one-hot 向量是:
1 | [0, 0, 1, 0, 0] |
embedding table 是:
\[ E\in \mathbb{R}^{5\times d} \]
那么:
\[ [0,0,1,0,0]E=E_2 \]
也就是取出第 2 行。
实际工程不会真的构造巨大的 one-hot 矩阵,因为太浪费。框架会直接按 id 做索引。
| 写法 | 含义 | 工程实现 |
|---|---|---|
| one-hot 乘 embedding matrix | 数学上好理解 | 不常直接用 |
| embedding lookup | 直接取对应行 | 实际使用 |
6. PyTorch 里的写法
简化代码:
1 | import torch |
这里:
| 张量 | 形状 | 含义 |
|---|---|---|
input_ids |
[2, 3] |
batch size 为 2,每条 3 个 token |
embedding.weight |
[50000, 4096] |
embedding table |
x |
[2, 3, 4096] |
每个 token 的向量表示 |
7. embedding 是怎么训练出来的
Embedding table 是模型参数。训练开始时,它通常是随机初始化的。
训练过程中,模型预测下一个 token,并计算 loss:
1 | input ids -> embeddings -> Transformer -> logits -> loss |
反向传播会更新:
| 参数 | 是否更新 |
|---|---|
| embedding table | 更新 |
| attention 层参数 | 更新 |
| MLP 层参数 | 更新 |
| 输出层参数 | 更新 |
7.1 哪些 embedding 行会被更新
如果一个 batch 只出现了这些 token ids:
1 | [1024, 5832, 941] |
那么直接参与前向计算的是这几行:
1 | E[1024], E[5832], E[941] |
这些行会收到直接梯度。没出现的 token 行不会通过输入 embedding lookup 直接更新。
但如果输入 embedding 和输出 embedding 共享权重,输出层会让更多 token 的行参与 softmax 计算。这个问题见后面的权重共享部分。
7.2 高频 token 和低频 token
高频 token 出现次数多,embedding 被更新得更频繁。低频 token 更新少,学习更难。
这也是 tokenizer 设计很重要的原因:
| token 太细 | token 太粗 |
|---|---|
| 序列变长,训练和推理更贵 | 稀有词太多,很多 embedding 学不好 |
| 子词可复用,覆盖能力强 | 词表变大,embedding table 变大 |
好的 tokenizer 是覆盖率、序列长度、词表大小之间的折中。
8. embedding 和位置有什么关系
只做 token embedding 还不够。
如果输入是:
1 | 猫 追 狗 |
两句话 token 一样,但顺序不同,意思也不同。模型需要位置信息。
所以进入 Transformer 前,通常要加入或使用位置编码。
8.1 绝对位置 embedding
早期 Transformer 使用 sinusoidal positional encoding,也可以用可学习的 position embedding。
如果使用可学习位置 embedding:
\[ x_i = E_{\text{token}}[t_i] + E_{\text{pos}}[i] \]
| 项 | 含义 |
|---|---|
| \(E_{\text{token}}[t_i]\) | 第 \(i\) 个 token 的语义向量 |
| \(E_{\text{pos}}[i]\) | 第 \(i\) 个位置的位置向量 |
| \(x_i\) | 送入 Transformer 的输入向量 |
8.2 RoPE
很多现代 LLM 使用 RoPE,也就是 Rotary Position Embedding。
RoPE 不一定在最开始把 position embedding 加到 token embedding 上,而是在 attention 里旋转 Q/K,让点积带上相对位置信息。
| 方法 | 位置作用在哪里 |
|---|---|
| absolute position embedding | 输入层直接加到 token embedding |
| sinusoidal encoding | 输入层加位置编码 |
| RoPE | attention 里作用于 Q/K |
| ALiBi | attention score 上加位置偏置 |
所以“token id 到 embedding”通常只是第一步。真正进入 attention 时,还会通过位置机制补上顺序信息。
9. embedding 在 LLM 整体流程中的位置
完整流程可以这样看:
1 | flowchart LR |
各阶段做什么:
| 阶段 | 输入 | 输出 |
|---|---|---|
| tokenizer | 文本 | token ids |
| embedding lookup | token ids | token embeddings |
| 位置处理 | token embeddings | 带位置信息的表示 |
| Transformer blocks | hidden states | 更深的 hidden states |
| output projection | hidden states | vocab logits |
| softmax / sampling | logits | 下一个 token id |
生成时,模型输出的是下一个 token id。这个 id 再被 tokenizer decode 回文本。
10. 输入 embedding 和输出 embedding
LLM 不只在输入端用 embedding。输出端也有一个矩阵,把 hidden state 投影回词表 logits:
\[ z = hW_{\text{out}}^T \]
其中:
| 符号 | 形状 | 含义 |
|---|---|---|
| \(h\) | \(d_{\text{model}}\) | 当前 hidden state |
| \(W_{\text{out}}\) | \(V\times d_{\text{model}}\) | 输出词表矩阵 |
| \(z\) | \(V\) | 每个 token 的 logit |
很多语言模型会使用 weight tying:
\[ W_{\text{out}} = E_{\text{token}} \]
也就是输入 embedding table 和输出词表矩阵共享参数。
| 做法 | 优点 | 代价 |
|---|---|---|
| 不共享 | 输入和输出自由度更高 | 参数更多 |
| 共享 | 参数更少,输入输出语义空间一致 | 约束更强 |
直观上:一个 token 作为输入时的向量,和它作为输出候选时的向量,使用同一套语义空间。
11. 特殊 token 的 embedding
词表里通常有一些特殊 token。
| token | 作用 |
|---|---|
<bos> |
序列开始 |
<eos> |
序列结束 |
<pad> |
padding |
<unk> |
未知 token |
<mask> |
mask 语言模型使用 |
| chat template tokens | 标记 system/user/assistant 等角色 |
这些 token 也有自己的 token id,也会有对应 embedding。
例如 chat 模型的输入可能包含:
1 | <system> 你是一个助手 |
模型并不是“天生知道”这些标记的意义。它通过训练学会这些特殊 token 的作用。
12. padding 和 attention mask
batch 训练时,不同样本长度不同,通常要 padding 到同一长度。
1 | 样本 1: [我, 喜欢, 猫] |
<pad> 也有
embedding,但模型不应该把它当有效内容看。所以还需要 attention mask。
| 内容 | 是否有 embedding | 是否应被 attention 看见 |
|---|---|---|
| 普通 token | 是 | 是 |
<pad> token |
是 | 否 |
所以 embedding lookup 和 attention mask 是两件事:
1 | embedding lookup: 把所有 id 转成向量 |
13. embedding 和语义空间
训练后,embedding 不再是随机向量。语义、语法、格式、语言、代码结构等信息都会被压进向量空间。
常见现象:
| 现象 | 说明 |
|---|---|
| 语义相近 token embedding 可能更接近 | 比如动物、数字、标点等类别 |
| 高频 token embedding 学得更充分 | 训练数据里出现更多 |
| 特殊 token embedding 有控制作用 | chat 模板、分隔符会影响模型行为 |
| 多语言 token 会共享空间 | 跨语言模型里常见 |
这里要小心:embedding 空间不是人工设计的词典。它是训练目标和数据共同塑造出来的。
14. embedding 维度为什么很大
一个 token 需要携带很多信息:
| 信息类型 | 例子 |
|---|---|
| 语义 | 猫 是动物 |
| 语法 | 名词、动词、助词 |
| 语言 | 中文、英文、代码 |
| 格式 | 空格、换行、Markdown |
| 任务信号 | 指令、角色、分隔符 |
| 统计关系 | 常和哪些 token 一起出现 |
低维向量放不下足够多的可分离特征。高维 embedding 给模型更多空间来表达这些关系。
但维度越大,参数越多:
1 | embedding 参数量 = vocab_size * d_model |
例如:
| vocab size | d_model | 参数量 |
|---|---|---|
| 50,000 | 4,096 | 204,800,000 |
| 100,000 | 4,096 | 409,600,000 |
| 100,000 | 8,192 | 819,200,000 |
embedding table 本身就可能有几亿参数。
15. 训练和推理时 embedding 的差别
15.1 训练
训练时,输入是一批 token ids:
1 | input_ids -> embedding -> Transformer -> logits -> loss |
loss 反向传播后,embedding table 会被更新。
15.2 推理
推理时,embedding table 固定不变。每生成一个新 token:
1 | 新 token id -> embedding -> Transformer -> logits -> 采样下一个 id |
生成出的 token id 会追加到上下文里,再参与下一步。
16. 和 tokenizer 的边界
Tokenizer 和 embedding 经常被混在一起说,但它们不是一回事。
| 组件 | 输入 | 输出 | 是否神经网络参数 |
|---|---|---|---|
| tokenizer | 文本 | token ids | 通常不是 |
| embedding table | token ids | vectors | 是 |
Tokenizer 决定:
1 | 文本如何切 |
Embedding 决定:
1 | 每个 id 在模型内部对应哪个向量 |
如果换 tokenizer,词表和 token ids 就变了,原来的 embedding table 通常不能直接复用。
17. 新增 token 会发生什么
如果给模型增加新 token,比如:
1 | <my_special_token> |
需要做两件事:
- tokenizer 词表里加入这个 token,分配新 id。
- embedding table 增加一行新向量。
新 embedding 通常要初始化:
| 初始化方式 | 说明 |
|---|---|
| 随机初始化 | 简单,但需要训练 |
| 用相近 token 平均 | 让新 token 起点更合理 |
| 复制已有 token embedding | 常用于特殊标记 |
如果不继续训练或微调,新 token 的 embedding 没学过,模型很难正确使用它。
18. 常见误解
| 误解 | 更准确的说法 |
|---|---|
| token id 本身有语义 | id 只是词表行号,语义在 embedding 里 |
| embedding 是 tokenizer 生成的 | tokenizer 生成 id,embedding 是模型参数 |
| embedding 是固定词典 | embedding 会在训练中更新 |
| 相邻 id 的 token 语义接近 | id 相邻不代表 embedding 接近 |
<pad> 没有 embedding |
它也有 embedding,只是 attention mask 会屏蔽它 |
| 位置 embedding 和 token embedding 是一回事 | 一个表示 token 内容,一个表示位置 |
| 输出 token 直接来自 embedding | 输出来自 hidden state 经过输出投影得到的 logits |
19. 和已有几篇文档的关系
| 文档 | 关注点 |
|---|---|
| 本文 | token id 如何变成 embedding |
为什么LLM要使用QKV.md |
embedding 进入 attention 后如何变成 Q/K/V |
Scaled Dot-Product Attention详解.md |
Q/K/V 如何计算 attention |
softmax历史由来与LLM应用深度调研.md |
logits 如何变成概率 |
LLM 的主流程可以串起来:
1 | 文本 |
20. 小结
Token id 到 embedding 的转换,本质上是一次查表:
\[ \mathrm{embedding}(i)=E_i \]
这个查表看起来简单,但它是 LLM 进入连续向量世界的入口。
| 阶段 | 作用 |
|---|---|
| tokenizer | 把文本变成 token ids |
| embedding lookup | 把 ids 变成向量 |
| position handling | 补上顺序信息 |
| Transformer | 在向量空间里建模上下文 |
| output projection | 把 hidden state 映射回词表 |
embedding table 是模型参数,会被训练数据塑造。它连接了离散符号和神经网络计算,也是后续 Q/K/V、attention、MLP、logits 的起点。
21. 参考资料
- Word2Vec:Mikolov et al., Efficient Estimation of Word Representations in Vector Space
- GloVe:Pennington et al., GloVe: Global Vectors for Word Representation
- WordPiece:Schuster and Nakajima, Japanese and Korean Voice Search
- BPE for NMT:Sennrich et al., Neural Machine Translation of Rare Words with Subword Units
- SentencePiece:Kudo and Richardson, SentencePiece
- Transformer:Vaswani et al., Attention Is All You Need
- Weight tying:Press and Wolf, Using the Output Embedding to Improve Language Models
- RoPE:Su et al., RoFormer: Enhanced Transformer with Rotary Position Embedding
- ALiBi:Press et al., Train Short, Test Long