Appearance
分词器
在进入模型之前,文本必须先被切成模型认识的「token」。分词器(Tokenizer) 就是文本 ↔ token id 之间的翻译官,也是很多人踩坑的第一站。
1. 分词器做的三件事
原始文本 "I love NLP!"
│ ① 切分 Split : 切成子词 ["I", "Ġlove", "ĠN", "LP", "!"]
│ ② 映射 ID : 查词表 [40, 2697, 6865, 3137, 0]
│ ③ 后处理 : 加特殊符号/注意力掩码/截断填充
▼
input_ids = [40, 2697, 6865, 3137, 0] → 送进模型的就是这串整数反过来,模型输出 token id,还要靠分词器 decode 回人类可读文本。编码/解码必须用同一个分词器,否则会乱码。
2. 为什么是「子词」而不是「词」
词级的问题: "unbelievable" 没见过 → OOV(未知词) 直接抓瞎
子词级(BPE/WordPiece): unbelievable → un + believ + able 部件都认识!- BPE(GPT 系)、WordPiece(BERT 系)、SentencePiece/Unigram(LLaMA 等)思路略不同,目标一致:常用词整体成 token,生僻词拆成常见子词,兼顾词表大小与覆盖率。
- 中文常按字切(
模型),或字+子词混合。
3. 一行代码用起来的 AutoTokenizer
python
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("gpt2") # 自动匹配该模型的 BPE 分词器
enc = tok("I love NLP!", add_special_tokens=True) # GPT-2 基本不额外加特殊符
print("tokens :", tok.convert_ids_to_tokens(enc["input_ids"]))
print("ids :", enc["input_ids"])
print("decode :", tok.decode(enc["input_ids"])) # 还原成文本不同模型用各自的分词器,绝不能混用(拿 GPT-2 的分词器配 BERT 模型,结果全错)。
4. 批量、填充与截断
真实训练要一次处理多条长短不一的句子,需要 padding(补齐)和 truncation(截断):
python
batch = tok(
["I love NLP", "Transformers are great for many tasks"],
padding=True, # 短的用 <pad> 补到同长
truncation=True, # 长的截断到 model_max_length
return_tensors="pt", # 直接返回 PyTorch 张量
)
print(batch["input_ids"].shape) # [2, 最大长度]
print(batch["attention_mask"]) # 1=真实token, 0=padding(注意力要屏蔽它)attention_mask 至关重要:它告诉模型哪些是补出来的空位,注意力必须屏蔽,否则结果被污染。
5. 特殊 token 一览
[BOS]/<bos> 序列开始 [EOS]/<eos> 序列结束(生成时"写到这里就停")
[PAD]/<pad> 填充补齐 [CLS] BERT 句首聚合 [SEP] BERT 分隔
[MASK] BERT 完形填空要预测的位置 [UNK] 未知词兜底不同模型的特殊符不同(GPT-2 用 endoftext 作为 EOS,很多对话模型还有 im_start / im_end 之类的 ChatML 控制符)。微调时要确保这些 token 正确注册,否则模型学不到「何时停止」。
6. token 数 = 成本与长度上限
上下文长度按 token 计, 不是按字符/单词:
"internationalization" → 1~几个 token(子词) 中文一个字常 1~2 token
API 计费、显存占用、能否塞进 prompt, 都取决于 token 数想估算成本或判断会不会被截断,先 len(tok(text)["input_ids"]) 数一数。
7. 训练自己的分词器(选读)
python
from tokenizers import Tokenizer, models, trainers
tok = Tokenizer(models.BPE())
trainer = trainers.BpeTrainer(vocab_size=4000, special_tokens=["<unk>","<pad>","<eos>"])
tok.train_from_iterator(["我们的语料 每一行 ...", ...], trainer)小语料(如 NanoGPT 的字符级实验)时,我们甚至直接把每个字符当作一个 token,用最简单的词表——实战章节会这么干。
小结
- 分词器负责 文本 ↔ token id 双向翻译,编解码必须同一套。
- 子词(BPE/WordPiece)解决未知词与词表膨胀问题。
padding/truncation/attention_mask是批处理的三件套。- 特殊 token(尤其 EOS/PAD)关系生成能否正确停止。
- token 数决定长度上限与成本。
下一步
有了 token,看看怎么加载模型、一句话出结果 → 模型与推理。