彻底理解GPT tokenizers

发布于 2024-7-17 10:12
浏览
0收藏

你可能已经听说过GPT这个词,它是一种人工智能模型,可以生成各种各样的文本,比如小说、诗歌、对话、新闻等等。GPT的全称是Generative Pre-trained Transformer,意思是生成式预训练变换器。生成式表示它可以根据一些输入(比如一个单词或一句话)来创造新的内容,预训练表示它在使用之前已经在大量的文本数据上进行了学习,变换器表示它使用了一种叫做Transformer的神经网络结构。

要理解GPT的工作原理,我们需要先了解一个重要的概念:token。token是文本的最小单位,可以是一个字母、一个单词、一个标点符号或者一个符号。比如,这句话:

Hello, world!

可以被分成五个token:

Hello , world !

GPT模型在处理文本时,需要先把文本分割成token,然后把每个token转换成一个数字,这个数字就代表了这个token的含义。这个数字叫做token ID。比如,我们可以用下面的表格来表示每个token和它对应的token ID:

token

token ID

Hello

1

,

2

world

3

!

4

那么,这句话就可以被转换成一个数字序列:

1 2 3 4

GPT模型就是通过学习大量的这样的数字序列,来掌握文本的规律和语义。

然后,当我们给它一个输入(比如一个token ID或者一个数字序列),它就可以根据它学到的知识,来生成一个合理的输出(比如一个新的token ID或者一个新的数字序列)。

但是,如果我们只用单个字母或单词作为token,会有一些问题。首先,不同的语言有不同的词汇量,有些语言可能有几万个单词,有些语言可能有几十万甚至几百万个单词。如果我们要给每个单词分配一个唯一的token ID,那么我们需要很大的内存空间来存储这些ID。其次,有些单词可能很少出现在文本中,或者有些单词可能是新造出来的,比如一些专有名词、缩写、网络用语等等。如果我们要让GPT模型能够处理这些单词,那么我们需要不断地更新我们的token ID表格,并且重新训练模型。

为了解决这些问题,GPT模型使用了一种叫做BPE(Byte Pair Encoding)的方法来分割文本。BPE是一种数据压缩技术,它可以把一段文本分割成更小的子单元(subword),这些子单元可以是单个字母、字母组合、部分单词或完整单词。

BPE的原理是基于统计频率来合并最常见的字母对或子单元对。比如,如果我们有下面这四个单词:

lowlowernewestwidest

我们可以先把它们分割成单个字母:

l o wl o w e rn e w e s tw i d e s t

然后,我们可以统计每个字母对出现的次数,比如:

pair

count

l o

2

o w

2

w e

2

e r

1

n e

1

e w

1

w i

1

i d

1

d e

1

e s

1

s t

1

我们可以看到,l o,o w和w e都出现了两次,是最常见的字母对。我们可以把它们合并成一个新的子单元,比如:

lowlow ern e westw i dest

这样,我们就减少了一些token的数量。我们可以重复这个过程,直到达到我们想要的token的数量或者没有更多的可合并的字母对。比如,我们可以继续合并e r,n e,e w等等,得到:

lowlowernewestwidest

这样,我们就把四个单词分割成了六个子单元:

lowernewestwidest

这些子单元就是BPE的token。我们可以给它们分配token ID,比如:

token

token ID

low

5

er

6

new

7

est

8

wid

9

那么,这四个单词就可以被转换成下面的数字序列:

55 67 89 8

你可能会问,为什么要用BPE来分割文本呢?有什么好处呢?其实,BPE有以下几个优点:

  • 它可以减少token的数量,从而节省内存空间和计算资源。
  • 它可以处理未知或罕见的单词,只要把它们分割成已知的子单元就行了。比如,如果我们遇到一个新单词lowerest,我们可以把它分割成low er est,然后用对应的token ID表示它。
  • 它可以捕捉单词的形态变化,比如复数、时态、派生等等。比如,如果我们遇到一个单词lowering,我们可以把它分割成low er ing,然后用对应的token ID表示它。这样,GPT模型就可以学习到这个单词和其他形式的关系。

当然,BPE也有一些缺点,比如:

  • 它可能会破坏一些有意义的子单元,比如把一个完整的单词分割成两个或多个部分。比如,如果我们遇到一个单词tower,我们可能会把它分割成t ow er,而不是保留它作为一个整体。
  • 它可能会导致一些歧义或混淆,比如把两个不同的单词分割成相同的子单元序列。比如,如果我们遇到两个单词tow er和tower,我们可能会把它们都分割成t ow er,而不是区分它们。
  • 它可能会影响一些特殊的符号或标记的处理,比如HTML标签、URL、邮箱地址等等。比如,如果我们遇到一个URLhttps://www.bing.com/, 我们可能会把它分割成多个子单元,比如:

https : / / www . bing . com /

这样,可能会丢失一些原本的含义或格式。

所以,BPE并不是一种完美的方法,它只是一种权衡的方法,它在减少token数量和保留token含义之间寻找一个平衡点。不同的BPE方法可能会有不同的分割规则和结果,比如,我们可以设置一个最大的token数量,或者一个最小的合并频率,来影响BPE的过程和输出。

那么,GPT模型是如何使用BPE来分割文本的呢?实际上,GPT模型并不是直接使用BPE来分割文本,而是使用了一种叫做GPT-2 tokenizer的工具,这个工具是基于BPE的一种改进版本。GPT-2 tokenizer有以下几个特点:

  • 它使用了Unicode编码来表示每个字符,而不是ASCII编码。这样,它可以支持更多的语言和符号,比如中文、日文、阿拉伯文、表情符号等等。
  • 它使用了一个固定的token数量,即50257个。这个数字是根据GPT-2模型的输入层的大小来确定的,每个输入层可以容纳50257个不同的token ID。
  • 它使用了一个预先训练好的BPE模型来分割文本,这个BPE模型是在一个大规模的文本数据集上训练得到的,它包含了各种各样的文本类型和语言。

上手实践

如果你想使用GPT-2 tokenizer来分割文本,你可以参考以下的步骤:

  • 首先,你需要安装和导入transformers库,这是一个提供了各种预训练模型和工具的开源库¹²。
  • 然后,你需要从预训练的gpt2模型中加载tokenizer和model,你可以使用AutoTokenizer和GPT2DoubleHeadsModel类来实现这一功能¹²。
  • 接着,你需要给tokenizer添加一些特殊的token,比如[CLS]和[SEP],这些token可以帮助模型识别文本的开始和结束¹²。
  • 最后,你可以使用tokenizer的encode或encode_plus方法来把文本转换成token ID的序列,并且使用model的forward方法来得到模型的输出¹²³。

下面是一个简单的Python代码示例:

# 导入transformers库
from transformers import AutoTokenizer, GPT2DoubleHeadsModel
import torch

# 加载tokenizer和model
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = GPT2DoubleHeadsModel.from_pretrained("gpt2")

# 添加特殊的token
num_added_tokens = tokenizer.add_special_tokens({"cls_token": "[CLS]", "sep_token": "[SEP]"})

# 分割文本
text = "Hello, my dog is cute"
inputs = tokenizer.encode_plus(text, add_special_tokens=True, return_tensors="pt")

# 得到模型的输出
outputs = model(**inputs)
last_hidden_states = outputs.last_hidden_state

一旦您了解了令牌,GPT 工具生成文本的方式就会变得更加有意义。

特别是,观看 GPT-4 将其输出作为独立令牌流式传输回很有趣(GPT-4 比 3.5 略慢,因此更容易看到发生了什么)。


彻底理解GPT tokenizers-AI.x社区

这是我得到的 - 使用我的 llm CLI 工具从 GPT-4 生成文本:llm -s 'Five names for a pet pelican' -4。

字典中不存在的“Pelly” 占用了多个token,而字典中存在的“Captain Gulliver”则能一次性输出。

本文转载自 AI小智​,作者: AI小智

收藏
回复
举报
回复
相关推荐