tokenizer.json 结构化逐行说明

先说明一件很重要的事:这个文件有 250325 行。它是自动生成的 tokenizer 总文件,里面包含:

如果机械地把 25 万行每一行都写一遍,学生只会被淹没,反而学不到重点。所以这份说明采用更适合教学的方式:

  1. 先按结构分段定位
  2. 再对关键行逐行解释
  3. vocabmerges 用代表性片段说明规则

这样你能真正读懂这个文件在做什么。

开头几行:文件总入口

第 1 行

{

JSON 对象开始。说明整个 tokenizer 会被表示成一个大字典。

第 2 行

"version": "1.0",

这表示 tokenizer JSON 格式的版本号,不是模型版本号。

第 3 行

"truncation": null,

这里没有写死截断策略。也就是说,tokenizer 本身不强制规定“超过长度后怎么截断”,通常把这件事留给上层代码处理。

第 4 行

"padding": null,

这里也没有写死 padding 规则。和我们前面看到 pad_tokennull 是一致的。

added_tokens:特殊 token

第 5 行

"added_tokens": [

下面要开始列出“额外加入的特殊 token”。

第 6-14 行

{
  "id": 50256,
  "content": "<|endoftext|>",
  "single_word": false,
  "lstrip": false,
  "rstrip": false,
  "normalized": false,
  "special": true
}

这里定义了一个特殊 token:<|endoftext|>

逐项理解:

第 15 行

] , 的语义

这一行表示 added_tokens 数组结束,接下来进入下一个配置项。

normalizer:文本标准化

第 16 行

"normalizer": null,

这里是 null,表示 GPT-2 tokenizer 不额外做一套复杂的 normalizer,比如统一大小写、去音标之类。

这说明 GPT-2 更偏向“保留原始文本细节,再用 byte-level 方式处理”。

pre_tokenizer:切词前预处理

第 17 行

"pre_tokenizer": {

开始定义预处理规则。

第 18 行

"type": "ByteLevel",

这说明 tokenizer 采用 ByteLevel 预处理。它不是直接按自然语言中的“词”切,而是先把文本映射到字节层,再配合 BPE 做编码。

第 19 行

"add_prefix_space": false,

不会在句子最前面自动补空格。这个选项会影响第一个词怎么被编码。

第 20 行

"trim_offsets": true,

保留 offset 信息时,会修剪空白偏移,让位置信息更干净。

第 21 行

"use_regex": true

说明预处理时会使用正则规则来辅助划分文本模式。

第 22 行

},

pre_tokenizer 这一段结束。

post_processor:编码后的整理规则

第 23 行

"post_processor": {

开始定义后处理。

第 24 行

"type": "TemplateProcessing",

说明后处理采用模板方式。也就是:对单句输入、双句输入分别按模板拼接。

第 25-31 行

这一段定义单句输入 single 的模板。

核心意思是: - 单句时,直接把序列 A 放进去 - type_id0

第 32-41 行

这一段定义成对输入 pair 的模板。

核心意思是: - 第一段文本用序列 A - 第二段文本用序列 B - 两段分别标不同的 type_id

第 42 行

"special_tokens": {}

这里没有额外通过 post-processor 插入更多特殊 token。

第 43-48 行

post_processor 结束。

decoder:把 token 还原回文本

第 49 行

"decoder": {

开始定义解码器。

第 50 行

"type": "ByteLevel",

解码器也是 ByteLevel 类型,和前面的预处理器对应。

第 51 行

"add_prefix_space": true,

解码回文本时,会按照 ByteLevel GPT-2 的规则处理前缀空格。

第 52 行

"trim_offsets": true,

继续保留对 offset 的修剪策略。

第 53 行

"use_regex": true

同样允许使用正则逻辑。

第 54 行

},

decoder 配置结束。

model:真正的 tokenizer 模型本体

第 55 行

"model": {

这一行很关键。它告诉我们:前面只是辅助规则,现在开始进入“真正的分词模型内容”。

第 56 行

"type": "BPE",

说明这里使用的是 BPE: Byte Pair Encoding

第 57 行

"dropout": null,

不对 BPE merge 过程使用 dropout。

第 58 行

"unk_token": null,

没有单独设置一个新的 unknown token。

第 59 行

"continuing_subword_prefix": "",

子词继续部分前面不加额外前缀。

第 60 行

"end_of_word_suffix": "",

词尾也不加额外后缀。

第 61 行

"fuse_unk": false,

不把未知 token 做额外融合处理。

第 62 行

"byte_fallback": false,

不启用额外的 byte fallback 机制。

第 63 行

"ignore_merges": false,

说明后面列出的 merges 规则是会真正参与工作的,不会被忽略。

vocab:词表

第 64 行

"vocab": {

从这里开始进入词表。词表的作用是:

第 65-75 行

"!": 0,
"\"": 1,
"#": 2,
"$": 3,
"%": 4,
"&": 5,
"'": 6,
"(": 7,
")": 8,
"*": 9,
"+": 10,

这说明最基础的标点符号都被收进词表,并且有自己的编号。

第 79-89 行附近

像:

"0": 15,
"1": 16,
"2": 17,

这些行说明数字字符也都直接有自己的 token id。

第 96 行以后

像:

"a": 64,
"b": 65,
"c": 66,

说明字母也被收入了词表。

第 19914 行的一个代表性例子

搜索结果里有:

"model": 19849,

这说明完整字符串 "model" 已经作为一个高频子词或词,拥有独立 id 19849。这正是 BPE 的意义之一:高频组合不必每次都拆成单字符。

第 50322 行附近

vocab 的尾部你会看到类似:

"Ġamplification": 50250,
"ominated": 50251,
"Ġregress": 50252,
"ĠCollider": 50253,
"Ġinformants": 50254,
"Ġgazed": 50255,
"<|endoftext|>": 50256

这里要重点理解两个现象:

merges:BPE 合并规则

第 50323 行

"merges": [

这表示后面开始列出 BPE 的合并规则。

这些规则决定:哪些字符或子词会优先合并成更长的 token。

开头几条规则

[
  "Ġ",
  "t"
],
[
  "Ġ",
  "a"
],
[
  "h",
  "e"
],
[
  "i",
  "n"
]

这些规则的意思是:

这就是 BPE 的核心:把高频共现的字符对不断合并,慢慢形成更大的子词单元。

文件末尾几条 merge

结尾你会看到类似:

[
  "Ġampl",
  "ification"
],
[
  "om",
  "inated"
],
[
  "Ġreg",
  "ress"
]

这说明 BPE 不只是合并单字符,也会继续把已经形成的子词再合并成更长的单位。

例如: - Ġampl + ification -> Ġamplification - Ġreg + ress -> Ġregress

最后两行

倒数第二行

]

说明 merges 数组结束。

最后一行

}

说明整个 tokenizer 的 JSON 文件结束。

读完后应该记住什么