NLP--BPE、WordPiece、ULM、SentencePiece子词分词器总结【原理】

2 篇文章 0 订阅
1 篇文章 0 订阅

序言

当我们在做英语文本任务时,机器无法理解文本。当我们将句子序列送入模型时,模型仅仅能看到一串字节,它无法知道一个词从哪里开始,到哪里结束,所以也不知道一个词是怎么组成的。所以,为了帮助机器理解文本,我们需要

  1. 将文本分成一个个小片段
  2. 然后将这些片段表示为一个向量作为模型的输入
  3. 同时,我们需要将一个个小片段(token) 表示为向量,作为词嵌入矩阵, 通过在语料库上训练来优化token的表示,使其蕴含更多有用的信息,用于之后的任务。

分词方法

分词的方法,一般分为3大类

  • 基于空格的分词方法(词级
    • 在训练语料中出现的token才能被训练器学习到,而那些没有出现的token将会被<UNK>等特殊标记代替,这样将影响模型的表现
    • 词典将非常庞大,产生很大的开销。
    • 出现次数很少的词,学习其token的向量表示也非常困难,遇到新词,会变成OOV
  • 基于字母的分词方法(字符级
    • 单个字符本身缺少语义,使得到的词向量缺乏含义
    • 输入序列变长,对于限制最大长度的模型,容易达到最大值
    • 计算复杂度提升
    • 字符级解决了 OOV 问题,但将输入表示为字符序列会增加序列长度,这使得学习字符之间的关系以形成有意义的单词变得具有挑战性。
  • 基于子词的分词方法(子词级
    • 结合了字符级与词级的优点,在<UNK>数目和词向量含义丰富性之间达到平衡
    • 通过一个有限的单词列表来解决所有单词的分词问题,同时将结果中token的数目降到最低

子词分词

子词背后的核心概念是,频繁出现的单词应该在词汇表中,而稀有单词应该被拆分为频繁出现的子词。例如。“refactoring”一词可以分为“re”“factor”“ing”,子词“re”“factor”“ing”“refactoring”更频繁地出现,其整体含义也保持不变。

BPE

Byte Pair Encoding (BPE) tokenisation

使用模型:GPT-2Roberta

  • BPE 的第一步是将所有字符串拆分为单词

  • 再分词后,假设我们有以下单词,其频率如下:

    [(“car”, 5), (“cable”, 3), (“tablet”, 1), (“watch”, 2), (“chair”, 5), (“mouse”, 1)]
    
    • 所需的词汇表大小(vocabulary size)是 BPE 的超参数。在示例中,假设我们想要词汇表中总共 17 (size = 17)个标记。单词中的所有唯一字符和符号都作为基本词汇表。在此,基本词汇表是
    [‘a’, ‘b’, ‘c’, ‘e’, ‘h’, ‘i’, ‘l’, ‘m’, ‘o’, ‘r’, ‘s’ ,’t’, ‘u’, ‘w’] size=14
    
    • 将所有单词拆分为基本词汇字符,如下:

      [(‘c’,’a’,’r’ , 5), (‘c’,’a’,’b’,’l’,’e’, 3),(‘t’,’a’,’b’,’l’,’e’,’t’, 1), (‘w’,’a’,’t’,’c’,’h’, 2), (‘c’,’h’,’a’,’i’,’r’, 5), (‘m’,’o’,’u’,’s’,’e’, 1)]
      
    • BPE 算法计算每个符号对的出现次数,并选择频率最高的符号对。在上面的例子中,“ca”对在car中出现 5 次,在cable中出现 3 次,总共出现 8 次,是所有对中出现的最高的。接下来是 7 次 ch(2 次来自watch,5 次来自chair)等等

      • 最常见的对“ca”被添加到词汇表中,并且所有出现的ca被合并。基本词汇现在变为

        [‘a’, ‘b’, ‘c’, ‘e’, ‘h’, ‘i’, ‘l’, ‘m’, ‘o’, ‘r’, ‘s’ ,’t’, ‘u’, ‘w’, ‘ca’] size=15
        

        token词汇变成了

        [(‘ca’,’r’ , 5), (‘ca’,’b’,’l’,’e’, 3), (‘t’,’a’,’b’,’l’,’e’,’t’, 1), (‘w’,’a’,’t’,’c’,’h’, 2), (‘c’,’h’,’a’,’i’,’r’, 5), (‘m’,’o’,’u’,’s’,’e’, 1)]
        
      • 第二出现次数多的是“ch”,它被添加到词汇表中,所有成对出现的ch 都合并在一起。

        [‘a’, ‘b’, ‘c’, ‘e’, ‘h’, ‘i’, ‘l’, ‘m’, ‘o’, ‘r’, ‘s’ ,’t’, ‘u’, ‘w’, ‘ca’, ‘ch’] size=16
        

        token词汇变成了

        [(‘ca’,’r’ , 5), (‘ca’,’b’,’l’,’e’, 3), (‘t’,’a’,’b’,’l’,’e’,’t’, 1), (‘w’,’a’,’t’,’ch’, 2), (‘ch’,’a’,’i’,’r’, 5), (‘m’,’o’,’u’,’s’,’e’, 1)]
        
      • 目标词汇size = 17BPE 将选择下一个最常见的对“ca”“r”,出现 5 次。它们将被合并,“car”将被添加到词汇表中,最终词汇

        [‘a’, ‘b’, ‘c’, ‘e’, ‘h’, ‘i’, ‘l’, ‘m’, ‘o’, ‘r’, ‘s’ ,’t’, ‘u’, ‘w’, ‘ca’, ‘ch’,’car’] size=17
        

        token词汇变成了

        [(‘car’ , 5), (‘ca’,’b’,’l’,’e’, 3), (‘t’,’a’,’b’,’l’,’e’,’t’, 1), (‘w’,’a’,’t’,’ch’, 2), (‘ch’,’a’,’i’,’r’, 5), (‘m’,’o’,’u’,’s’,’e’, 1)]
        
      • 由于达到词汇限制,因此不会进行进一步的合并。

    • 现在 BPE 已经过训练,相同的标记化合并将应用于新单词。比如说,我们得到一个新词“cab”,它将被标记化为[“ca”,“b”]。但是,如果新单词是“card”,它将被拆分为[“car”,“[UNK]”],因为字母d不在词汇表中。实际上,这永远不会发生,因为所有字符至少在语料库中出现一次。但是,如果标点符号或数字等符号未添加到词汇表中,而是新单词的一部分,则可能会遇到 <UNK>标记。

WordPiece

WordpieceBERTtoken分词器,WordPiece类似于BPE,它首先将所有字符和符号包含到其基本词汇表中。我们定义所需的词汇大小,并不断添加子词,直到达到限制。

BPEWordPiece之间的区别在于选择符号对以添加到词汇表的方式。

BPE选择频数最高的相邻子词合并,而WordPiece选择能够提升语言模型概率最大的相邻子词加入词表

WordPiece不依赖于对的频率,而是选择最大化训练数据可能性最大的一个。这意味着它从基本词汇开始训练语言模型,并选择可能性最高的对(pair=基本词汇字符 + 生成字符的最高概率)。该对被添加到词汇中,语言模型再次在新词汇上训练。重复这些步骤,直到达到所需的词汇量。

例如:"I just got a funky phone case!"
分词为:[“I”, “just”, “got”, “a”, “fun”, “##ky”, “phone”, “case”]
##将这个符号添加到子词前面
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
tokenizer.tokenize("I have a new GPU!")
 
# ["i", "have", "a", "new", "gp", "##u", "!"]
The tokenizer splits "gpu" into known subwords: ["gp" and "##u"]. 

Unigram Language Model (ULM)

ULMWordPiece一样,ULM同样使用语言模型来挑选子词。不同之处在于,BPEWordPiece算法的词表大小都是从小到大变化,属于增量法。而Unigram Language Model则是减量法,即先初始化一个大词表,根据评估准则不断丢弃词表,直到满足限定条件。ULM算法考虑了句子的不同分词可能,因而能够输出带概率的多个子词分段。

ULM在每一步都使用语言模型,并不断删除loss最高的pairx%pair的定义与Wordpiece的定义相同)。loss通常定义为该训练步骤中词汇表的对数似然函数。

Unigram 主要与 SentencePiece 结合使用

以上三种子词分词器的关系

img

SentencePiece

SentencePiece
上面讨论的所有分词器都假设空格分隔单词。除了中文、日语等少数语言外,情况确实如此。SentencePiece不将空格视为分隔符,而是将字符串作为其原始原始格式的输入,即与所有空格一起。它使用 BPE ULM 作为其分词器来构建词汇表。

使用SentencePiece的模型ALBERTXLNetMarianT5

例如:“I just got a funky phone case!”
 [“_I”, “_just”, “_got”, “_a”, “_fun”, “ky”, “_phone”, “_case”]
 token可以连接形成字符串,“_”可以替换为空格
from transformers import XLNetTokenizer
tokenizer = XLNetTokenizer.from_pretrained("xlnet-base-cased")
tokenizer.tokenize("Don't you love 🤗 Transformers? We sure do.")
 
# ["▁Don", "'", "t", "▁you", "▁love", "▁", "🤗", "▁", "Transform", "ers", "?", "▁We", "▁sure", "▁do", "."]

总结

子词解决了词汇量问题,并在很大程度上有助于减少模型参数的数量,子词有助于保持词汇更加平衡。以上主要是英文文本下的子词分词器,因为英文文本多空格间隔,而对于中文来说适用性不强。

以上是我个人在学习过程中的记录所学,希望对正在一起学习的小伙伴有所帮助!!!
如果对你有帮助,希望你能一键三连【关注、点赞、收藏】!!!

TODO

中文文本分词器

参考链接

https://blog.csdn.net/qq_27586341/article/details/113424560

https://paddlepedia.readthedocs.io/en/latest/tutorials/pretrain_model/subword.html

https://zhuanlan.zhihu.com/p/86965595

https://blog.csdn.net/muyao987/article/details/126288609

https://zhuanlan.zhihu.com/p/460678461

https://aitechtogether.com/article/26837.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

故事挺秃然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值