本文介绍了各种类型的分词(tokenization)
,用于将单词拆分为一个或多个标记(token)
,因为单词和分词之间存在一对多的关系。
什么是预分词(Pre-tokenization)
预分词是在处理基于文本的语料库时需要执行的几项任务中的第一项,这些任务通常包括以下的某个子集:
-
预分词
-
分词任务
-
基于单词的分词
-
基于字符的分词
-
子词分词
在我们深入研究预分词之前,我们将讨论一些基础知识:单词的定义。
什么是单词?
一个单词本质上是一系列表示可以是具体物体也可以是抽象概念的符号(这是您一直以来对于单词的认知)。只包含字母字符的单词在不同的分词器中通常被一致地视为一个单词。然而,分词器可能会以不同的方式处理英语中的缩写,特别是那些在空格上进行分词的情况。
举例来说,单词“I’ve”是“I”和“have”的缩写,在那些以空格为标志进行分词的分词器中被视为一个单词,而在使用空格和标点符号进行分词的分词器中,则将“I’ve”视为两个单词。
以下是执行在标记(tokens)、字符和单词之间进行映射操作的四种方法:
-
word_to_chars()
-
token_to_chars()
-
char_to_word()
-
char_to_token()
Pre-tokenization与Tokenization
Hugging Face文档区分了预分词和分词,而许多在线文章只使用“分词”这个术语。预分词可以以各种方式实现,可以单独使用,也可以组合使用,这里介绍了三种技术:
-
空格分词(如RoBERTa和GPT-2)
-
空格和标点分词
-
基于规则的分词(如FlauBERT和XLM)
在预分词中将空格作为单词分隔符(或空格和标点符号),与对英语和大多数欧洲语言进行的“常规”分词相一致。 然而,一些欧洲语言(如法语和德语)使用重音符号,删除它们可能会改变一个单词的含义,这将在后面的部分中讨论。
未区分大小写的LLM是一个所有单词都是小写且所有重音符号已删除的LLM。重音符号出现在一些印欧语言中,例如法语、西班牙语、德语和斯堪的纳维亚语言,但在英语中并不存在。然而,区分大小写的LLM保留大写字母和重音符号(如果有的话)。
英语可能是预分词最容易的语言,因为具有以下特征:
-
没有重音符号
-
所有单词之间用空格分隔
-
没有冠词或形容词的屈折(相对于德语/斯拉夫语言)
-
每个单词在每个语法格(例如主格和宾格)中都有一个形式
此外,英语中的撇号可以表示所有权或涉及动词的缩写(可能是不规则的),如下所示:
-
Yes it’s certainly true.
-
I think that that’s its true nature.
-
Yes, it’s true that its price is high.
-
John’s car is a convertible, it’s new, and its top is red. Dave’s buying a new car.
-
Sara won’t eat shrimp.
-
Sara isn’t finished yet.
请注意,单词“its”表示所有权,即使它不包含撇号,这是关于所有权的唯一的例外。
在英语对话中,英语还可以将名词视为动词。当上下文清晰时,人们即使在第一次听到这样的构造时也能理解它们的含义,如下例所示:
“I need to book for an hour and then I can meet up you.”
上述句子中的单词“book”是一个名词,用作动词“study”的替代。在标准英语中,不定式形式的动词由前置于动词之前的介词“to”触发。然而,上述句子是非标准英语,因为它包含“to book”,但人们可以轻松推断出预期的含义。
什么是分词(Tokenization)?
简化来说,分词涉及将语料库的文本分割成可以映射到数字(例如word2vec)的单词,以便通过神经网络处理这些单词的数值对应物。
分词器执行不同类型的分词,其特性取决于用于实例化分词器的NLP模型。基于BERT的分词器保留了单词偏移的索引。此外,预分词在空格和标点上进行。然而,基于GPT2的分词器在空格和标点上进行分词,并用一个Ġ符号替换空格,可以通过该符号恢复文本字符串中的原始空格。该分词器与BERT分词器不同,因为它识别双空格。
另一种类型的分词器是基于SentencePiece算法的T5分词器,也类似于GPT2分词器。然而,这个分词器保留空格并用下划线(_)代替它们。此外,T5分词器仅在空格上分割,而不是标点,并且还添加了一个初始空格。在第4章中,您将看到涉及实例化特定于模型的分词器的基于Python的语言模型示例。
分词任务及其挑战
分词涉及在句子和文档中找到标记,其中标记可以是单词、字符或部分单词。在执行以下子任务时,分词还必须考虑可能出现的问题:
-
将文本转换为小写(或不转换)
-
处理分隔句子的标点符号
-
处理重音符号(如法语和德语)
-
处理缩写(如“won’t”与“will not”)
-
处理不常见(罕见)单词
如果您之前没有执行过分词,它可能看起来像是一个简单的任务,但分词有几个非常规的方面。以下是在执行语料库的分词时要考虑的一些要点(无特定顺序):
-
普通名词与专有名词的区别
-
选择性的单词分隔符
-
重音符号和单词含义
-
不同的子词分词技术
-
单数与复数名词的区别
-
单词拼写的变体
-
打字错误
-
翻译任务中的假朋友词
-
大小写的变体
-
动词的不规则形式
-
词汇表外分词问题
-
发音差异问题
其中一些示例可能看起来微不足道(甚至是琐碎的),但这些细节可以影响已经被翻译成与输入文本语言不同的语言的文本字符串的准确性和流畅性。
分词还必须处理其他问题,例如处理单词的拼写和大小写的不同方式(例如“favor”与“favour”、“tire”与“tyre”、“color”与“colour”),相同单词的不同含义(比如“to table”一个讨论),以及排版错误(例如“dependent”与错误的“dependant”)。
单词、字符和子词分词器
实质上,分词器将句子和文档转换为适合语言模型处理的格式。请记住,LLMs只处理数值,这意味着分词器必须将文本字符串转换为数值数据。总体而言,分词器的目标是双重的:找到最有意义的表示,并且(如果可能的话)找到最小的表示。
在NLP中,有几种类型的分词器:
-
预分词器(之前讨论过)
-
单词分词器
-
字符分词器
-
子词分词器
基于单词的分词器
总体而言,基于单词的分词器比较简单,因为它们涉及有限数量的规则,可以取得相当好的结果。通过Python中的split()
函数,可以以基于空格的方式对文本字符串进行编程化分词,如下所示:
tokenized_text = "I love Chicago pizza".split()
print(tokenized_text)
# ['I', 'love', 'Chicago', 'pizza']
一些单词分词器为标点指定了额外的规则,这可能导致大量的词汇表(即给定语料库中的标记数量)。此外,单词被分配一个ID,其范围从0到(N-1),其中N是词汇表中的标记数量。模型通过其分配的ID值识别给定的单词。
不幸的是,相近的单词被视为不同的单词,这意味着它们将被分配不同的ID值。例如,以下一组单词在意义上是相关的:
-
sing
-
sang
-
sung
-
singing
此外,模型将不同地对待名词的单数形式和复数形式。在具有阳性、阴性、中性和名词复数形式的语言中(如德语和斯拉夫语言),这个过程更加复杂,所有这些形式都被视为不同的名词。
例如,英语只有一个冠词“the”的形式,而下面是定冠词“der”的屈折形式:
-
der (阳性单数)
-
die (阴性单数)
-
das (中性单数)
-
die (名词复数)
单词分词器的局限性
模型仅识别其训练步骤中存在的单词标记,这意味着如果组合词在训练步骤中未出现,它们将不被识别。例如,如果“book”和“keeper”是训练步骤的一部分,但“bookkeeper”在训练步骤中不存在,那么“bookkeeper”将不会被识别,因此它将通过UNK标记表示。
另一个分词器的挑战涉及缩写。例如,英语单词“its”和“it’s”有完全不同的含义:“its”表示所有权,而“it’s”意味着“它是”。在名词的情况下,撇号也表示所有权(例如,John’s car)。因此,“It’s true that John’s pen is worth its weight in gold”这句话只能有一个解释。
正如之前看到的,中文和日文等语言中,单词之间的空格是可选的。此外,日语有三个字母表:平假名、片假名(仅用于外来词)和罗马字母(用于罗马化日语单词)。日语还有汉字,是一种基于图形的系统,用于表示单词。日语句子和街道标志可能包含平假名和汉字的组合,这对于非日语人来说更难理解。
字符分词器的权衡
字符分词器将语料库分割成字符而不是单独的单词,这有两个主要优点:
-
词汇表比基于单词的分词要小。
-
出现的词汇表外标记较少(每个单词都可以由字符构建)。
然而,字符分词器也有两个限制。首先,一组字符提供了有限的实质含义。单词是句子的基本构建块,因此它们携带意义(有时是多重含义)。虽然这对于基于字母表的语言(如印欧语言)是真实的,但一些东南亚语言是基于象形文字的,可以传达需要一句话来解释的复杂概念。
其次,字符分词将生成数量显着更多的标记,很容易比基于单词的标记集大五倍,导致训练模型所需的处理时间比基于单词的标记所需的处理时间多得多。
子词分词
子词分词通常基于算法、统计规则和一个重要的启发式原则:将不常见或不经常出现的单词分词成子词,而不拆分经常出现的单词。
对于带有后缀“ly”的英语副词,可以轻松地执行这种分词:用两个标记替换副词,其中第二个标记是组合“ly”。因此,“slowly”分割为“slow”和“ly”,“quickly”替换为“quick”和“ly”,依此类推。
同样,形容词“lonely”可以分割成“lone”和“ly”。在某些情况下,这种分解成两个标记的方式会产生第一个标记的实际单词,这就是前面示例的情况。
此外,子词分词还可以生成具有含义的标记,例如将单词“internationalization”分词为“international”和“ization”。
除了处理英语单词子集的前述类型的分词之外,还有其他一些分词算法,其中一些列举如下:
-
字节级BPE(在GPT-2中)
-
WordPiece(在BERT中)
-
SentencePiece或Unigram
子词分词算法
子词分词涉及将OOV(超出词汇表)的令牌分割成较小的片段。回顾前面的部分,其中简要描述了以下类型的分词器:
-
单词分词器
-
字符分词器
-
子词分词器
子词分词算法基于一种启发式方法,这意味着它们基于直观的推理,“有意义”的推理,并且可以产生正确的答案。具体而言,出现频率更高的单词被分配唯一的ID。然而,出现频率较低的单词被分割成保留低频单词含义的子词。以下是四种重要的子词分词算法:
-
BPE
-
SentencePiece
-
unigram语言模型
-
WordPiece
慢速与快速分词器(Slow Versus Fast Tokenizers)
慢速和快速分词器之间存在差异。慢速分词器是用Python编写的,位于Hugging Face Transformers库中。相比之下,快速版本位于Hugging Face Tokenizers中,是用Rust编程语言编写的。
此外,要注意慢速和快速分词器的以下一点:在并行处理大量文本时,分词速度差异最为明显。实际上,在处理少量文本时,慢速分词器可能比快速分词器更快。
快速分词器支持另外两个重要特性:并行化和偏移映射,指的是记录标记的索引位置。后者的功能支持将单词映射到它们生成的标记,以及将文本字符映射到它们嵌入的标记中。
技术提升
论文探讨、算法交流、求职内推、干货分享、解惑答疑,与2000+来自港大、北大、腾讯、科大讯飞、阿里等开发者互动学习。
项目源码、数据、技术交流提升,均可加交流群获取,群友已超过2000人,添加时最好的备注方式为:来源+兴趣方向,方便找到志同道合的朋友
方式①、添加微信号:mlc2060,备注:来自CSDN +研究方向
方式②、微信搜索公众号:机器学习社区,后台回复:加群
资料1
资料2