训练

训练分词器

字节对编码:数对、合并、重复

语料
本站术语表 15,307 个字节
合并规则
300 GPT-2 50,000
起点
256 个字节符号

全部步骤

  1. 从字节开始

    分词器在模型之前就从文本中学出来。这里的文本是本站的英文术语表:15,307 个字节,预切分成 3,216 个词。训练从每个字节一个符号开始:共 256 个,没有任何未知符号。

    15,307 个字节 · 词表 256

  2. 统计每一对相邻符号

    统计每一对相邻符号出现的次数,只在词内部统计,并按每个词出现的次数加权。这里最常见的一对是 Ġ + t,共 426 次。

    在词内部统计相邻对

  3. 合并最常见的一对,重复

    把这一对在所有地方替换成一个新符号,加入词表,然后重新计数。每次合并就是一条规则,按顺序保存。随着 300 条合并规则被学出,看示例词如何从字节合成更大的片段。

    300 次合并 · 词表 556

  4. 词表大小与序列长度

    合并越多,每个词的词元越少,同样的上下文就能装下更多文本;但每个新词元都需要在嵌入矩阵和输出层中各占一行。GPT-2 停在 50,000 次合并;LLaMA 3 大约有 128,000 个词元。

    每词更少的词元 vs 更大的词表

  5. GPT-2 的合并规则

    GPT-2 的前几条合并规则(来自它真实的 merges.txt,在 40 GB 网页文本上学出)开头和我们的很像:空格与常见字母相连,“h e”、“i n”。编码一个新词时就按这个顺序重放合并。

    GPT-2:50,000 次合并,50,257 个词元

代码

words = Counter(regex.findall(PAT, text))              # pre-split, counted
vocab = {w: tuple(w.encode()) for w in words}          # every word as bytes
merges = []
for _ in range(num_merges):
    pairs = Counter()
    for w, n in words.items():
        for a, b in zip(vocab[w], vocab[w][1:]): pairs[a, b] += n
    best = max(pairs, key=pairs.get)
    merges.append(best)                                # the rule, in order
    vocab = {w: merge(s, best) for w, s in vocab.items()}

延伸阅读