随机分词与tokenizer(BPE->BBPE(tiktoken)->Wordpiece->Unigram->sentencepiece->bytepiece)

0 tokenizer综述

  • 根据不同的切分粒度可以把tokenizer分为: 基于词的切分,基于字的切分和基于subword的切分。 基于subword的切分是目前的主流切分方式。
  • subword的切分包括: BPE(/BBPE), WordPiece 和 Unigram三种分词模型。其中WordPiece可以认为是一种特殊的BPE。
  • 完整的分词流程包括:文本归一化,预切分,基于分词模型的切分,后处理。
  • SentencePiece是一个分词工具,内置BEP等多种分词方法,基于Unicode编码并且将空格视为特殊的token。这是当前大模型的主流分词方案。
  • BPE:GPT, Baichuan, RoBERTa,BART,DeBERTa
  • BBPE:ChatGLM
  • BPE / BBPE: GPT-2, GPT-J, GPT-Neo, GPT-4O, GPT3, Qwen, Qwen2, Llama, Llama2, Llama3
  • WordPiece:BERT, DistilBERT,MobileBERT, MPNET,Funnel Transformers
  • Unigram:AlBERT, T5, mBART, XLNet

中文分词&新词发现
在这里插入图片描述

1 基于subword的切分

基于词和字的切分都会存在一定的问题,直接应用的效果比较差。
基于词的切分,会造成:

词表规模过大
一定会存在UNK,造成信息丢失
不能学习到词缀之间的关系,例如:dog与dogs,happy与unhappy

基于字的切分,会造成:

每个token的信息密度低
序列过长,解码效率很低

所以基于词和基于字的切分方式是两个极端,其优缺点也是互补的。而折中的subword就是一种相对平衡的方案。

基于subword的切分能很好平衡基于词切分和基于字切分的优缺点,也是目前主流最主流的切分方式。
subword的基本切分原则是:

高频词依旧切分成完整的整词
低频词被切分成有意义的子词,例如 dogs => [dog, ##s]

基于subword的切分可以实现:

词表规模适中,解码效率较高
不存在UNK,信息不丢失
能学习到词缀之间的关系

基于subword的切分包括:BPE,WordPiece 和 Unigram 三种分词模型。

1.1 处理流程概述

  • 归一化:最基础的文本清洗,包括删除多余的换行和空格,转小写,移除音调等。
    HuggingFace tokenizer的实现: https://huggingface.co/docs/tokenizers/api/normalizers
  • 预分词:把句子切分成更小的“词”单元。可以基于空格或者标点进行切分。 不同的tokenizer的实现细节不一样。例如:
    pre-tokenize:
    [BERT]: [(‘Hello’, (0, 5)), (‘,’, (5, 6)), (‘how’, (7, 10)), (‘are’, (11, 14)), (‘you’, (16, 19)), (‘?’, (19, 20))]
    [GPT2]: [(‘Hello’, (0, 5)), (‘,’, (5, 6)), (‘Ġhow’, (6, 10)), (‘Ġare’, (10, 14)), (‘Ġ’, (14, 15)), (‘Ġyou’, (15, 19)), (‘?’, (19, 20))]
    [t5]: [(‘▁Hello,’, (0, 6)), (‘▁how’, (7, 10)), (‘▁are’, (11, 14)), (‘▁you?’, (16, 20))]
    可以看到BERT的tokenizer就是直接基于空格和标点进行切分。
    GPT2也是基于空格和标签,但是空格会保留成特殊字符“Ġ”。
    T5则只基于空格进行切分,标点不会切分。并且空格会保留成特殊字符"▁",并且句子开头也会添加特殊字符"▁"。
    预分词的实现: https://huggingface.co/docs/tokenizers/api/pre-tokenizers
  • 基于分词模型的切分:不同分词模型具体的切分方式。分词模型包括:BPE,WordPiece 和 Unigram 三种分词模型。
    分词模型的实现: https://huggingface.co/docs/tokenizers/api/models
  • 后处理:后处理阶段会包括一些特殊的分词逻辑,例如添加sepcial token:[CLS],[SEP]等。
    后处理的实现: https://huggingface.co/docs/tok

1.2 BPE

Byte-Pair Encoding(BPE)是最广泛采用的subword分词器。

训练方法:从字符级的小词表出发,训练产生合并规则以及一个词表
编码方法:将文本切分成字符,再应用训练阶段获得的合并规则
经典模型:GPT, GPT-2, RoBERTa, BART, LLaMA等

因为BPE是从字符级别的小词表,逐步合并成大词表,所以需要先获得字符级别的小词表。
基于word2splits统计vocabs中相邻两个pair的词频pair2count
经过统计,当前频率最高的pair为: (‘Ġ’, ‘t’), 频率为7次。 将(‘Ġ’, ‘t’)合并成一个词并添加到词表中。同时在合并规则中添加(‘Ġ’, ‘t’)这条合并规则。
根据更新后的vocab重新对word2count进行切分。具体实现上,可以直接在旧的word2split上应用新的合并规则(‘Ġ’, ‘t’)
从而获得新的word2split
重复上述循环直到整个词表的大小达到预先设定的词表大小。

在推理阶段,给定一个句子,我们需要将其切分成一个token的序列。 具体实现上需要先对句子进行预分词并切分成字符级别的序列,然后根据合并规则进行合并。

BPE 的适用范围
BPE 一般适用在欧美语言拉丁语系中,因为欧美语言大多是字符形式,涉及前缀、后缀的单词比较多。而中文的汉字一般不用 BPE 进行编码,因为中文是字无法进行拆分。对中文的处理通常只有分词和分字两种。理论上分词效果更好,更好的区别语义。分字效率高、简洁,因为常用的字不过 3000 字,词表更加简短。

举例来说,我们要对下面的字符串编码,
aaabdaaabac
字节对 aa 出现的次数最多,所以我们将它替换成一个没在字符串中被用过的字符 Z ,
ZabdZabac
Z=aa
然后我们重复这个过程,用 Y 替换 ab ,
ZYdZYac
Y=ab
Z=aa
继续,用 X 替换 ZY ,
XdXac
X=ZY
Y=ab
Z=aa
这个过程重复进行,直到没有字节对出现超过一次。当需要解码时,就将上述替换过程反向进行。

下面是一段 BPE 算法原文中对 BPE 算法的实现:

import re
import collections


def get_stats(vocab):
    pairs = collections.defaultdict(int)
    for word, freq in vocab.items():
        symbols = word.split()
        for i in range(len(symbols)-1):
            pairs[symbols[i], symbols[i+1]] += freq  # 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值