一文详解GPT tokenizer 的工作原理

人工智能

629人已加入

描述

来源 | OSCHINA 社区

作者 | OneFlow深度学习框架

在 GPT 模型中,tokenization(词元化)指的是将用户输入的文本分割成 token(词元)的过程,以让 GPT 能更好地理解输入文本的词义、句法和语义,以及生成更连贯的输出内容。这是非常重要的预处理操作,对模型的最终效果有重大影响。

而 tokenizer(词元生成器)是将文本切分成 token 的工具或组件。它将原始文本转换成模型可处理的数字形式,为 GPT 的生成与推理提供基础能力。

本文详细介绍了 GPT tokenizer 的工作原理。作者 Simon Willison 是开源 Web 应用框架 Django 的共同发起人,他也开源了用于探索和发布数据的工具 Datasette。

作者|Simon Willison

OneFlow 编译

翻译|贾川 语言大模型(如 GPT-3/4、LLaMA 和 PaLM)使用 token 作为基本单位进行工作。它们接受文本作为输入,将其转换为 token(整数),然后预测接下来应该出现哪些 token。 通过操作这些 token,可以更好地了解它们在语言模型内部的工作原理。 OpenAI 提供了一个 tokenizer,用以探索 token 的工作方式。我自己构建了一个更有意思的工具,是一个 Observable notebook( https://observablehq.com/@simonw/gpt-tokenizer )。在这个 Observable notebook 中,你可以将文本转换为 token,将 token 转换为文本,还可以搜索整个 token 表。 这个 Observable notebook 看起来是这样的:

GPT

我在这里切分的文本是:

The dog eats the apples El perro come las manzanas 片仮名

在给定示例中,总共生成了 21 个整数 token。5 个对应英文文本,8 个对应西班牙文本,6 个(每个字符两个)对应三个日文字符。两个换行符也分别被表示为整数 token。   Observable notebook 使用了 GPT-2 的 tokenizer(基于 EJ Fox 和 Ian Johnson 所创建的 优秀 notebook ),主要作为教育工具使用,不过 GPT-3 及更高版本的最新 tokenizer 与 GPT-2 的 tokenizer 存在些许差异。  

1
探索一些有趣的 token

通过与 tokenizer 进行交互可以发现各种有趣的模式。 大 多数常见的英语单词都分配一个 token,如上所示:

“The”: 464

“ dog”: 3290

“ eats”: 25365

“ the”: 262

“ apples”: 22514

需要注意的是:字母的大小写很重要。以单词 “the” 为例,大写字母 T 的 “The” 对应的 token 是 464,而以小写字母 t 开头且有一个前导空格的单词 “the” 对应的 token 却是 262。 许多单词的 token 里都包含了一个前导空格,这样就不再需要为每个空格字符使用一个额外的 token,从而能更有效地对整个句子进行编码, 相比英语,在对其他语言进行切分时,效率可能要低点。 西班牙语 “El perro come las manzanas” 这句话的编码如下:

“El”: 9527

“ per”: 583

“ro”: 305

“ come”: 1282

“ las”: 39990

“ man”: 582

“zan”: 15201

“as”: 292

此处就显示出了对英语的偏向。因为 “man” 是一个英语单词,所以它的 token ID 较低,为 582。而 “zan” 不是一个在英语中独立存在的单词,但也是一个常见的字符序列,因此仍然值得拥有自己的 token,所以它的 token ID 为 15201。 有些语言甚至会出现单个字符编码为多个 token 的情况,比如以下这些日语:

片: 31965 229

仮: 20015 106

名: 28938 235

2
故障 token

“故障 token”(glitch tokens)是一类令人着迷的 token 子集。其中一个有趣的例子是 token 23282,即 “davidjl”。 可以通过在 notebook 的搜索框中搜索 “david” 来找到该 token。

GPT

Scale AI 的 prompt 工程师 Riley Goodside 指出了与该 token 相关的一些奇怪行为。

GPT

为什么会发生这种情况?这是一个有趣的谜题。 token 23282 可能与 Reddit 上的用户 “davidjl123” 有关。该用户是 /r/counting 子论坛的一位热情用户,他经常在该论坛上发布递增数,并且已经发布了超过 163,000 次这样的帖子。 据推测,/r/counting 子论坛中的数据最终被用于训练 GPT-2 的 tokenizer。由于用户 davidjl123 在该子论坛中出现了数十万次,所以最终分配到了属于自己的 token。 为什么这种情况会导致类似问题呢?到目前为止,我看到最好的解释来自 Hacker News 上的用户 @londons_explore

这些故障 token 都位于 token 嵌入空间的中心附近。这意味着,模型在区分这些 token 和其他位于嵌入空间中心附近的 token 时存在困难,因此当被要求 “重复” 这些 token 时,模型会选择错误的 token。   这种情况发生的原因是,这些 token 在互联网上出现了很多次(例如,davidjl 用户在 Reddit 上有 163000 个帖子,仅仅是计算递增的数字),但是这些 token 本身并不难以预测(因此,在训练过程中,梯度变得几乎为零,并且嵌入向量会衰减到零,这是某些优化器在归一化权重时会进行的操作)。

在 “ SolidGoldMagikarp (plus, prompt generation) ” 这篇帖子下,LessWrong 对这种现象进行了详细说明。

3
用 tiktoken 进行 token 计数

OpenAI 的模型都有 token 限制。有时在将文本传递给 API 之前,需要计算字符串中的 token 数量,以确保不超过该限制。 其中,一个需要计算 token 数量的技术是 “检索增强生成(Retrieval Augmented Generation)”,通过对文档语料库运行搜索(或嵌入搜索)来回答用户的问题,提取最有可能的内容,并将其作为上下文涵盖在 prompt 中。 成功实现这种模式的关键是,在 token 限制内包含尽可能多的相关上下文,因此需要能够计算 token 数量。 OpenAI 提供了一个名为 tiktoken( https://github.com/openai/tiktoken )的 Python 库来实现这一功能。 如果你深入研究这个库,就会发现它目前包括五种不同的切分方案:r50k_base、p50k_base、p50k_edit、cl100k_base 和 gpt2。 其中,cl100k_base 是最相关的,它是 GPT-4 和当前 ChatGPT 使用的经济型 gpt-3.5-turbo 模型的 tokenizer。 text-davinci-003 使用的是 p50k_base 。在 tiktoken/model.py 的 MODEL_TO_ENCODING 词典中可以找到模型与 tokenizer 的完整映射。 以下是如何使用 tiktoken 的代码示例:

import tiktoken

encoding = tiktoken.encoding_for_model("gpt-4")
# or "gpt-3.5-turbo" or "text-davinci-003"
tokens = encoding.encode("Here is some text")
token_count = len(tokens)

现在token将是一个包含四个整数token ID的数组——在该例中是[8586, 374, 1063, 1495]。

使用.decode()方法将一个token ID数组转换回文本:

text = encoding.decode(tokens)
# 'Here is some text'
第一次调用 encoding_for_model () 时,编码数据将通过 HTTP 从 openaipublic.blob.core.windows.net Azure Blob 存储桶(storage bucket)获取(代码: https://github.com/openai/tiktoken/blob/0.4.0/tiktoken_ext/openai_public.py )。这些数据会被缓存在临时目录中,但如果机器重新启动,该目录将被清除。你可通过设置 TIKTOKEN_CACHE_DIR 环境变量来强制使用更持久的缓存目录。

4
ttok

几周前,我介绍了 tto k(https://github.com/simonw/ttok) ,这是 tiktoken 的一个命令行封装工具,具有两个关键功能:一是可以计算输入给它的文本中的 token 数量,二是可以将该文本截断为指定数量的 token。 它可以计算输入到其中的文本中的 token 数:

 

# Count tokens
echo -n "Count these tokens" | ttok
# Outputs: 3 (the newline is skipped thanks to echo -n)


# Truncation
curl 'https://simonwillison.net/' | strip-tags -m | ttok -t 6
# Outputs: Simon Willison’s Weblog


# View integer token IDs
echo"Show these tokens" | ttok --tokens
# Outputs: 7968 1521 11460 198
  使用 - m gpt2 或类似选项可选择使用适用于不同模型的编码。

 

 

5
token 生成过程

一旦你理解了 token,那么 GPT 工具生成文本的方式就会变得更加明了。 特别有趣的是,观察到 GPT-4 将其输出流式化为独立的 token(GPT-4 的速度略慢于 3.5 版本,可以更容易观察到其生成过程)。 以下是使用我的 llm CLI( https://github.com/simonw/llm )工具从 GPT-4 生成文本的结果,命令是 llm -s 'Five names for a pet pelican' -4:

GPT

如你所见,不在词典中的名字(如 “Pelly”)占据了多个 token,而 “Captain Gulliver” 作为一个整体输出了 token “Captain”。  

编辑:黄飞

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分