【新智元导读】「从头开始构建GPT分词器」笔墨版来了。

前段韶光,AI大神Karpathy上线的AI大课,已经收成了全网15万次播放量。

当时还有网友表示,这2小时课程的含金量,相称于大学4年。

就在这几天,Karpathy又萌生了一个新的想法:

干货满满大年夜神Karpathy两小时AI大年夜课工作流自动把视频转成文章

那便是,将2小时13分钟的「从头开始构建GPT分词器」的视频,转换为一本书的章节(或者博客文章)形式,专门谈论「分词」。

详细步骤如下:

- 为视频添加字幕或讲授笔墨。

- 将视频切割成多少带有配套图片和笔墨的段落。

- 利用大措辞模型的提示工程技能,逐段进行翻译。

- 将结果输出为网页形式,个中包含指向原始视频各部分的链接。

更广泛地说,这样的事情流程可以运用于任何视频输入,自动天生各种教程的「配套指南」,使其格式更加便于阅读、浏览和搜索。

这听起来是可行的,但也颇具寻衅。

他在GitHub项目minbpe下,写了一个例子来阐述自己的想象。

地址:https://github.com/karpathy/minbpe/blob/master/lecture.md

Karpathy表示,这是自己手动完成的任务,即不雅观看视频并将其翻译成markdown格式的文章。

「我只看了大约4分钟的视频(即完成了3%),而这已经用了大约30分钟来写,以是如果能自动完成这样的事情就太好了」。

接下来,便是上课韶光了!

「LLM分词」课程笔墨版

大家好,本日我们将磋商LLM中的「分词」问题。

遗憾的是,「分词」是目前最领先的大模型中,一个相对繁芜和棘手的组成部分,但我们有必要对其进行详细理解。

由于LLM的许多毛病可能归咎于神经网络,或其他看似神秘的成分,而这些毛病实际上都可以追溯到「分词」。

字符级分词

那么,什么是分词呢?

事实上,在之前的视频《让我们从零开始构建 GPT》中,我已经先容过分词,但那只是一个非常大略的字符级版本。

如果你去Google colab查看那个视频,你会创造我们从演习数据(莎士比亚)开始,它只是Python中的一个大字符串:

First Citizen: Before we proceed any further, hear me speak.All: Speak, speak.First Citizen: You are all resolved rather to die than to famish?All: Resolved. resolved.First Citizen: First, you know Caius Marcius is chief enemy to the people.All: We know't, we know't.

但是,我们如何将字符串输入LLM呢?

我们可以看到,我们首先要为全体演习集中的所有可能字符,构建一个词汇表:

# here are all the unique characters that occur in this textchars = sorted(list(set(text)))vocab_size = len(chars)print(''.join(chars))print(vocab_size)# !$&',-.3:;?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz# 65

然后根据上面的词汇表,创建用于在单个字符和整数之间进行转换的查找表。
此查找表只是一个Python字典:

stoi = { ch:i for i,ch in enumerate(chars) }itos = { i:ch for i,ch in enumerate(chars) }# encoder: take a string, output a list of integersencode = lambda s: [stoi[c] for c in s]# decoder: take a list of integers, output a stringdecode = lambda l: ''.join([itos[i] for i in l])print(encode("hii there"))print(decode(encode("hii there")))# [46, 47, 47, 1, 58, 46, 43, 56, 43]# hii there

一旦我们将一个字符串转换成一个整数序列,我们就会看到每个整数,都被用作可演习参数的二维嵌入的索引。

由于我们的词汇表大小为 vocab_size=65 ,以是该嵌入表也将有65行:

class BigramLanguageModel(nn.Module):def __init__(self, vocab_size): super().__init__() self.token_embedding_table = nn.Embedding(vocab_size, n_embd)def forward(self, idx, targets=None): tok_emb = self.token_embedding_table(idx) # (B,T,C)

在这里,整数从嵌入表中「提取」出一行,这一行便是代表该分词的向量。
然后,该向量将作为相应韶光步长的输入输入到Transformer。

利用BPE算法进行「字符块」分词

对付「字符级」措辞模型的天真设置来说,这统统都很好。

但在实践中,在最前辈的措辞模型中,人们利用更繁芜的方案来构建这些表征词汇。

详细地说,这些方案不是在字符级别上事情,而是在「字符块」级别上事情。
构建这些块词汇表的办法是利用字节对编码(BPE)等算法,我们将不才面详细先容该算法。

暂时回顾一下这种方法的历史发展,将字节级BPE算法用于措辞模型分词的论文,是2019年OpenAI揭橥的GPT-2论文Language Models are Unsupervised Multitask Learners。

论文地址:https://d4mucfpksywv.cloudfront.net/better-language-models/language_models_are_unsupervised_multitask_learners.pdf

向下翻到第2.2节「输入表示」,在那里他们描述并勉励这个算法。
在这一节的末端,你会看到他们说:

词汇量扩大到50257个。
我们还将高下文大小从512增加到1024个token,并利用512更大batchsize。

回忆一下,在Transformer的把稳力层中,每个token都与序列中之前的有限token列表干系联。

本文指出,GPT-2模型的高下文长度从GPT-1的512个token,增加到1024个token。

换句话说,token是 LLM 输入真个基本「原子」。

「分词」是将Python中的原始字符串,转换为token列表的过程,反之亦然。

还有一个盛行的例子可以证明这种抽象的普遍性,如果你也去Llama 2的论文中搜索「token」,你将得到63个匹配结果。

比如,该论文声称他们在2万亿个token上进行了演习,等等。

论文地址:https://arxiv.org/pdf/2307.09288.pdf

浅谈分词的繁芜性

在我们深入磋商实现的细节之前,让我们简要地解释一下,须要详细理解「分词」过程的必要性。

分词是LLM中许多许多怪异问题的核心,我建议你不要忽略它。

很多看似神经网络架构的问题,实际上都与分词有关。
这里只是几个例子:

- 为什么LLM不会拼写单词?——分词

- 为什么LLM不能实行超大略的字符串处理任务,比如反转字符串?——分词

- 为什么LLM在非英语措辞(比如日语)任务中更差?——分词

- 为什么LLM不善于大略的算术?——分词

- 为什么GPT-2在用Python编码时碰着了更多的问题?——分词

- 为什么我的LLM在看到字符串<|endoftext|>时溘然停滞?——分词

- 我收到的关于「trailing whitespace」的奇怪警告是什么?——分词

- 如果我问LLM关于「SolidGoldMagikarp」的问题,为什么它会崩溃?——分词

- 为什么我该当利用带有LLM的YAML而不是JSON?——分词

- 为什么LLM不是真正的端到端措辞建模?——分词

我们将在视频的末端,再回到这些问题上。

分词的可视化预览

接下来,让我们加载这个分词WebApp。

地址:https://tiktokenizer.vercel.app/

这个Web运用程序的优点是,分词在网络浏览器中实时运行,许可你轻松地在输入端输入一些文本字符串,并在右侧看到分词结果。

在顶部,你可以看到我们当前正在利用 gpt2 分词器,并且可以看到,这个示例中粘贴的字符串目前正在分词为 300个token。

在这里,它们用颜色明确显示出来:

比如,字符串「Tokenization」编码到token30642,其后是token是1634。

token「is」(把稳,这是三个字符,包括前面的空格,这很主要!
)是318。

把稳利用空格,由于它在字符串中是绝对存在的,必须与所有其他字符一起分词。
但为了清晰可见,在可视化时常日会省略。

你可以在运用程序底部打开和关闭它的可视化功能。
同样,token「at」是379,「the」是262,依此类推。

接下来,我们有一个大略的算术例子。

在这里,我们看到,分词器对数字的分解可能不一致。
比如,数字127是由3个字符组成的token,但数字677是由于有2个token:6(同样,请把稳前面的空格)和77。

我们依赖LLM来阐明这种任意性。

它必须在其参数内部和演习过程中,理解这两个token(6和77实际上组合成了数字677)。

同样,我们可以看到,如果LLM想要预测这个总和的结果是数字804,它必须在两个韶光步长内输出:

首先,它必须发出token「8」,然后是token「04」。

请把稳,所有这些拆分看起来都是完备任意的。
不才面的例子中,我们可以看到1275是「12」,然后「75」,6773实际上是三个token「6」、「77」、「3」,而8041是「8」、「041」。

(未完待续...)

(TODO:若想连续笔墨版的内容,除非我们想出如何从视频中自动天生)

网友在线,出谋划策

网友表示,太好了,实际上我更喜好阅读这些帖子,而不是看视频,更随意马虎把握自己的节奏。

还有网友为Karpathy出谋划策:

「觉得很棘手,但利用LangChain可能是可行的。
我在想是否可以利用whisper转录,产生有清晰章节的高等大纲,然后对这些章节块并行处理,在整体提要的高下文中,专注于各自章节块的详细内容(也为每个并行处理的章节天生配图)。
然后再通过LLM把所有天生的参考标记,汇编到文章末端」。

有人为此还写了一个pipeline,而且很快便会开源。