本节由 AI 整理生成,仅供参考。
#Vocab / Tokenizer / Mask Token
##tokenizer
把文本切成整数编号。干三件事:
| 职责 | 例子 |
|---|---|
| 编码 | '人工智能' → [2225] |
| 解码 | [2225] → '人工智能' (byte-exact) |
| 持词表 | 记住全部 token 和合并规则 |
命名陷阱: 它不按「词」切。 它按字节切, 再看哪些字节常一起出现 (byte-level BPE)。真正的按词切是 jieba, 完全另一回事。
TEXT
'人工智能' → 1 token [2225]
'Transformer' → 3 tokens ['Trans', 'form', 'er']
'🧠' → 3 tokens [4544, 136, 290]模型从头到尾没见过一个汉字, 它只见过 [2225, ...]。
##vocab 是什么
vocab (词表) = tokenizer 的编号表。 vocab_size 是它的行数。
模型里有一块 embedding 矩阵, 形状 (vocab_size, hidden_size), 第 i 行
是 token i 的向量。lm_head 通常也是 (vocab_size, hidden_size);
当 tie_word_embeddings=True 时两者共享同一份权重。
###为什么 vocab 大小决定模型能不能训起来
| Qwen3-0.6B | minimind-3 | |
|---|---|---|
vocab_size |
151936 | 6400 |
hidden_size |
1024 | 768 |
| embedding 参数量 | 151936 × 1024 = 155M | 6400 × 768 = 4.9M |
| 占整个模型 | 23% | 7% |
| 标称 params | 680M | 68.8M |
| 真正干活的 transformer | 525M | 63.9M |
Qwen3-0.6B 宣称 680M 参数, 其中 155M 纯粹是查表用的 embedding table。
64M 的模型配 151936 的 vocab 是荒谬的 —— 大半参数是查表, 而 332M token 根本训不完 1.5 亿个 embedding。
换 vocab = 换 tokenizer = 权重全部作废。 vocab 是架构的一部分, 不是可以随便换的超参。
##怎么查任何模型的 config
python
from transformers import AutoConfig
cfg = AutoConfig.from_pretrained("Qwen/Qwen3-0.6B")
cfg.num_attention_heads # Q heads
cfg.num_key_value_heads # K/V heads (GQA)
cfg.head_dim # 可能不存在, 要自己算不用 transformers 也可以 —— 直接读模型仓库里的 config.json。
想知道 tokenizer 到底多少条, 直接读 tokenizer.json 的 model.vocab 长度,
或用独立的 tokenizers 库 (Tokenizer.from_file(...) → .get_vocab())。
##mask token (DLM 需要)
DLM 要在序列里插入 [MASK] 占位符, 需要一个 mask_token_id。
###方案 A: 复用空闲的 special token
很多 tokenizer 继承了一堆用不上的占位符 (Qwen 系列从 Llama 继承的
<|object_ref_start|>、<|vision_pad|>、<|buffer1|> 等)。
minimind 的 tokenizer 里 id 27 就是 <|buffer1|> —— minimind 讨论 618
的作者用的正是 mask_token_id: 27。
###方案 B: 用 vocab_size 里的空闲 slot (推荐)
config.vocab_size 常常故意大于 tokenizer 的实际 token 数, 留出空位
给 pad/special token。Qwen3-0.6B:
TEXT
config vocab_size : 151936
tokenizer 实际最大 : 151669 (151668 是最高的 added_token)
空闲 slot : 267 个 → 151669 .. 151935直接用 151669。不需要 resize_token_embeddings, 所有已有 token id 不变,
预训练权重 100% 兼容。 LLaMA 系列的经典做法。
验证方法:
python
cfg = AutoConfig.from_pretrained(model)
vocab = Tokenizer.from_file("tokenizer.json").get_vocab()
real = max(vocab.values()) + 1
free = cfg.vocab_size - real # 267
assert max(added_token_ids) < real # 确认 special token 没占这些 slot
###方案 C: add_special_tokens + resize
python
tokenizer.add_special_tokens({"additional_special_tokens": ["<|mask|>"]})
model.resize_token_embeddings(len(tokenizer))会改变 embedding 形状, 已有权重需要重新加载。能用, 但比 A/B 麻烦。