【知识扫盲】tokenizer.json中的vocab和merges是什么?
在自然语言处理里,tokenizer.json
文件一般是由 Hugging Face 的 Tokenizers 库生成的,它是分词器配置的核心文件。这里面的 vocab
和 merges
是子词分词算法(像 BPE 这种)的重要构成要素。下面为你详细解释它们的作用和工作原理:
1. vocab(词汇表)
- 功能:
vocab
是一个从 token(子词)到 ID 的映射表,其作用是把文本转换为模型能够处理的数字表示。 - 内容形式:
- 基础字符:涵盖了单个字符,例如
["a", "b", "c", ...]
。 - 常见子词:包含常见的前缀、后缀或者词片段,例如
["Ġthe", "Ġquick", "Ġbrown", ...]
(这里的Ġ
代表空格)。 - 特殊 token:有用于填充的
[PAD]
、句子开始的[CLS]
、分隔的[SEP]
、未知词的[UNK]
等。
- 基础字符:涵盖了单个字符,例如
- 示例:
{"vocab": {"Ġ": 0,"a": 1,"b": 2,"c": 3,"Ġthe": 4,"Ġquick": 5,"[PAD]": 100,"[CLS]": 101,"[SEP]": 102,"[UNK]": 103}
}
- 运作机制:
在分词时,文本会先被分解成基础字符,接着依据merges
规则合并成子词,最后通过vocab
将这些子词转换为对应的 ID。
2. merges(合并规则)
- 功能:
merges
是一系列的合并规则,其目的是把基础字符组合成子词。这体现了 BPE(字节对编码)算法的核心思想。 - 内容形式:
- 它是一个按照合并优先级排序的二元组列表,格式为
["ab", "Ġt", "he", ...]
。 - 排序越靠前的规则,应用的优先级越高。
- 它是一个按照合并优先级排序的二元组列表,格式为
- 示例:
{"merges": ["a b", // 先将 "a" 和 "b" 合并为 "ab""Ġ t", // 再将 "Ġ" 和 "t" 合并为 "Ġt""Ġt h", // 接着将 "Ġt" 和 "h" 合并为 "Ġth""Ġth e" // 最后将 "Ġth" 和 "e" 合并为 "Ġthe"]
}
-
运作机制:
- 初始状态:文本被拆分成单个字符,比如
"The dog"
会变成["Ġ", "T", "h", "e", "Ġ", "d", "o", "g"]
。 - 应用合并规则:按照
merges
中的顺序依次进行合并。- 首先合并
"Ġ"
和"T"
,得到["ĠT", "h", "e", "Ġ", "d", "o", "g"]
。 - 然后合并
"h"
和"e"
,得到["ĠT", "he", "Ġ", "d", "o", "g"]
。 - 继续合并
"d"
和"o"
,得到["ĠT", "he", "Ġ", "do", "g"]
。 - 最后合并
"do"
和"g"
,得到["ĠT", "he", "Ġ", "dog"]
。
- 首先合并
- 映射到 ID:利用
vocab
将这些子词转换为 ID,例如[103, 4, 0, 500]
(假设"ĠT"
是未知词,对应[UNK]
的 ID 为 103)。
这些id就是token id,可参考文章:大模型推理过程中的tokenazier,tokenid,词向量之间的关系
- 初始状态:文本被拆分成单个字符,比如
3. 二者的协同工作方式
- 训练流程:
- 从所有出现的字符构成初始词汇表。
- 统计训练数据中字符对的出现频率。
- 不断合并最常出现的字符对,每合并一次就更新一次词汇表。
- 重复上述合并过程,直到达到预设的词汇表大小或者合并次数。
- 分词流程:
- 把输入文本拆分成字符序列。
- 按照
merges
规则进行合并,直到无法再合并或者达到最大子词长度。 - 查找
vocab
,将子词转换为 ID。
4. 实际应用案例
假设 vocab
和 merges
已经训练好,对句子 "Hello world!"
进行分词:
- 初始字符:
["Ġ", "H", "e", "l", "l", "o", "Ġ", "w", "o", "r", "l", "d", "!"]
。 - 应用合并规则:
- 合并
"H"
和"e"
,得到["Ġ", "He", "l", "l", "o", "Ġ", "w", "o", "r", "l", "d", "!"]
。 - 合并
"l"
和"l"
,得到["Ġ", "He", "ll", "o", "Ġ", "w", "o", "r", "l", "d", "!"]
。 - 合并
"He"
和"ll"
,得到["Ġ", "Hell", "o", "Ġ", "w", "o", "r", "l", "d", "!"]
。 - 合并
"Hell"
和"o"
,得到["Ġ", "Hello", "Ġ", "w", "o", "r", "l", "d", "!"]
。 - 合并
"Ġ"
和"Hello"
,得到["ĠHello", "Ġ", "w", "o", "r", "l", "d", "!"]
。 - 合并
"w"
和"o"
,得到["ĠHello", "Ġ", "wo", "r", "l", "d", "!"]
。 - 合并
"wo"
和"r"
,得到["ĠHello", "Ġ", "wor", "l", "d", "!"]
。 - 合并
"wor"
和"l"
,得到["ĠHello", "Ġ", "worl", "d", "!"]
。 - 合并
"worl"
和"d"
,得到["ĠHello", "Ġ", "world", "!"]
。 - 合并
"Ġ"
和"world"
,得到["ĠHello", "Ġworld", "!"]
。
- 合并
- 转换为 ID:假设
vocab
中有对应的项,那么结果就是[1000, 1001, 1002]
。
总结
- vocab:是子词到 ID 的映射表,它能将文本转换为模型可以处理的数字形式。
- merges:是子词合并规则,它决定了如何从基础字符构建出子词。
- 相互关系:
merges
规则生成子词,而vocab
负责存储这些子词并为它们分配 ID。
通过这种方式,子词分词器能够在处理常见词时保持完整性,同时将罕见词拆分成有意义的片段,有效平衡了词汇表的大小和表达能力。