在NLP领域中有多种不同的输入层级,字符 character, 词 word, 和subword,这三种方法是最常用的输入方式,他们实际上可以表达同样的句子和语义,对人来说并无特殊含义与区别,但对机器来说,确实很不一样。正如我们在第一次分享中提到的,我们需要把输入元素转换成数值,把语义理解转换成数值计算。而不同的粒度输入对此很有影响。
我们首先需要复习一下Embedding这一概念,把一个离散的输入元素代换成一个(一组)数值,这就是embedding,他的名字来自于把一个离散点嵌入到连续空间中。Embedding背后的理论认为,任何输入元素之间的交互可以被基于对他们的连续表示的进一步运算所替代。而不同的输入粒度会导致不同的语义理解过程,比如在词级别,“你好”是一个整体,“你好”的含义与“你”和“好”无关,而在字级别,“你好”就等于“你”和“好”经过某种运算。同理,“麦克风”等于“麦”,“克”,“风”经过某种运算得到。
字典本质上还是一个静态的表格,它的内容是固定的,不能处理未知项,比如训练时只看过英文字母,那就无法处理中文。同样的,如果我们把字典定在词级别,那么它能处理的词就是固定数量的,无法应对新词,比如新出现的流行语或网络用语。这类问题通常被称为Out-of-vocabulary(OOV),是一个长期被关注的问题。
对于字级别还是词级别比较好这个问题,其实有过一些争论,从语义组成的复杂性来讲,词级别更好,表达得更准,但从拓展性来讲,显然字级别更好,覆盖的面更大。此外,还有一个重要因素就是用字或词表示序列,会让序列长度有很大变化,比如英文单词平均有5个多字母组成。
https://arxiv.org/pdf/1508.06615.pdf
字和词各有优劣,所以后来人们把目光投向了一个折中的方案,subword,即把一串字母作为一个单元。而如何构造它们则需要用到编码学的知识。目前主流构造subword的算法实际上是借用了压缩算法,即如何用尽量少的subword让语料库压缩的最多。不同于哈夫曼编码,我们认为每一个编码后的元素是等长的,并且压缩过程是一个替换过程,把原文中一部分连续的字符串替换成一个新的字符,以达到长度缩减的目的。在这种条件下,Byte Pair Encoding (BPE)便是一种比较合适的解法,简而言之,BPE是一个迭代,贪心的算法,每次迭代选取一个最高频的字符对(相邻的两个字符),把它替换成一个新的字符,如此反复,直到达到指定的合并次数。
https://en.wikipedia.org/wiki/Byte_pair_encoding
但需要注意的是,BPE在英文,或西方语言中是不跨空格合并的,也就是合并只在一个单词中进行,第二是BPE既包含character也包含word,很多时候覆盖了大部分常用词,所以和word level是等效的。
https://www.aclweb.org/anthology/P18-1007.pdf
ULM认为一句话,或者一个字符串的概率等于个元素概率的乘积,即假设各元素出现时独立的,所以有
\begin{align}
P(w_1,w_2,\cdots,w_N)=\prod_i^NP(w_i) \
P(w_1,w_2,\cdots,w_N)=\prod_i^M P(m_i)
\end{align}
实际求解中,预设出众多候选字符串
非常简单,以概率删掉一些BPE中的合并规则。