分词器是自然语言处理(NLP)管道的核心组件之一。它们的任务是将文本转换为模型可以处理的数据。由于模型只能处理数字,因此分词器需要将我们的文本输入转换为数值数据。本节将详细介绍分词管道中的过程。
在NLP任务中,通常处理的是原始文本数据。例如:
Jim Henson was a puppeteer
然而,模型只能处理数字,所以我们需要找到一种方法将文本转换为数字。这就是分词器的作用,有许多方法可以实现。目标是找到对模型最有意义的表示形式,如果可能的话,是最小的表示。
让我们看看一些分词算法的例子,并尝试回答你可能对分词的一些问题。
Word-based
首先想到的分词类型是“基于词”的。它通常设置和使用起来非常简单,只需要遵循一些规则,通常能取得不错的结果。在下面的示例中,目标是将原始文本分割成单词,并为每个单词找到一个数值表示:
有多种方法分割文本。例如,我们可以使用Python的split()
函数,利用空格将文本分割成单词:
tokenized_text = "Jim Henson was a puppeteer".split()
print(tokenized_text)
['Jim', 'Henson', 'was', 'a', 'puppeteer']
还有对标点符号有额外规则的词分词器。这种情况下,我们可能会得到一个较大的“词汇表”,其中词汇表由我们语料库中独立标记总数定义。
每个单词都会被分配一个ID,从0开始,直到词汇表的大小。模型使用这些ID来识别每个单词。
如果我们想完全用基于词的分词器覆盖一种语言,我们需要为该语言中的每个单词分配一个标识符,这将产生大量的标记。例如,英语中有超过500,000个单词,因此我们需要跟踪这么多的ID来构建从每个单词到输入ID的映射。此外,“dog”和“dogs”这样的单词会被分别表示,模型最初不会知道它们相似;同样,“run”和“running”这样的相似单词也会被模型视为不相关。
最后,我们还需要一个特殊的标记来表示不在词汇表中的单词,通常称为“未知”令牌,如”[UNK]”或””。如果分词器产生大量这样的令牌,通常是个坏信号,因为模型无法找到合理的单词表示,信息在过程中丢失了。构建词汇表时的目标是尽可能减少将单词转换为未知令牌的情况。
减少未知令牌的一个方法是深入一层,使用“基于字符的”分词器。
Character-based
基于字符的分词器将文本分割成字符,而不是单词。这有两个主要优点:
- 词汇表更小。
- 未知(out-of-vocabulary,OOV)令牌更少,因为每个单词都可以由字符组成。
然而,关于空格和标点符号的问题仍然存在:
这种方法也不是完美的。由于现在基于字符而不是单词的表示,有人可能会认为,直观上,这不太有意义:每个字符本身意义不大,而单词则不然。然而,这取决于语言;例如,在中文中,每个字符比拉丁语言中的字符携带更多信息。
另一个需要考虑的因素是,我们最终会得到大量需要由我们的模型处理的标记:而在基于单词的分词器中,一个词只会成为一个单独的标记,但当转换为字符时,它很容易变成10个或更多的标记。
为了兼顾效率和效果,我们可以采用第三种方法:<