生成日期: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
2
tokens:    ["我", "喜欢", "猫"]
token ids: [1024, 5832, 941]

再查 embedding table:

1
2
3
1024 -> E[1024]
5832 -> E[5832]
941 -> E[941]

得到三个向量后,模型才能开始计算。

1
2
3
4
5
6
7
flowchart LR
A["文本"] --> B["Tokenizer"]
B --> C["Token IDs"]
C --> D["Embedding Table 查表"]
D --> E["Token Embeddings"]
E --> F["位置处理"]
F --> G["Transformer Blocks"]

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
2
3
4
5
6
7
输入文本: "Transformers are powerful"

tokens:
["Transform", "ers", " are", " powerful"]

token ids:
[41762, 388, 527, 8147]

不同 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 在词表里的编号。

注意:编号大小没有语义。10241025 是否语义接近,取决于它们对应 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
2
3
取第 1024 行
取第 5832 行
取第 941 行

结果是:

1
2
3
4
5
[
E[1024],
E[5832],
E[941]
]

如果每个 embedding 是 4096 维,那么输出形状是:

1
2
sequence length x d_model
= 3 x 4096

对 batch 输入:

1
2
input_ids shape:      [batch, seq_len]
embedding output: [batch, seq_len, d_model]

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import torch
import torch.nn as nn

vocab_size = 50000
d_model = 4096

embedding = nn.Embedding(vocab_size, d_model)

input_ids = torch.tensor([
[1024, 5832, 941],
[18, 927, 4501],
])

x = embedding(input_ids)

print(x.shape)
# torch.Size([2, 3, 4096])

这里:

张量 形状 含义
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
2
猫 追 狗
狗 追 猫

两句话 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
2
3
4
5
6
7
8
9
10
flowchart LR
A["原始文本"] --> B["Tokenizer"]
B --> C["Token IDs"]
C --> D["Token Embedding"]
D --> E["位置处理"]
E --> F["Transformer Blocks"]
F --> G["Hidden States"]
G --> H["Output Projection"]
H --> I["Logits"]
I --> J["Softmax 或采样"]

各阶段做什么:

阶段 输入 输出
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
2
3
<system> 你是一个助手
<user> 解释 softmax
<assistant>

模型并不是“天生知道”这些标记的意义。它通过训练学会这些特殊 token 的作用。


12. padding 和 attention mask

batch 训练时,不同样本长度不同,通常要 padding 到同一长度。

1
2
样本 1: [我, 喜欢, 猫]
样本 2: [你好, <pad>, <pad>]

<pad> 也有 embedding,但模型不应该把它当有效内容看。所以还需要 attention mask。

内容 是否有 embedding 是否应被 attention 看见
普通 token
<pad> token

所以 embedding lookup 和 attention mask 是两件事:

1
2
embedding lookup: 把所有 id 转成向量
attention mask: 告诉模型哪些位置不能看

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
2
文本如何切
每个 token 对应哪个 id

Embedding 决定:

1
每个 id 在模型内部对应哪个向量

如果换 tokenizer,词表和 token ids 就变了,原来的 embedding table 通常不能直接复用。


17. 新增 token 会发生什么

如果给模型增加新 token,比如:

1
<my_special_token>

需要做两件事:

  1. tokenizer 词表里加入这个 token,分配新 id。
  2. 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
2
3
4
5
6
7
8
9
10
文本
-> token ids
-> embeddings
-> Q/K/V
-> attention
-> hidden states
-> logits
-> softmax / sampling
-> 下一个 token id
-> 文本

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. 参考资料