Bootstrap

ChatGPT为啥这么强:万字长文详解 by WolframAlpha之父

Wolfram语言之父Stephen Wolfram,又来给ChatGPT背书了。

上个月,他还专门写过一篇文章,力荐自家的计算知识搜索引擎WolframAlpha,希望能跟ChatGPT来个完美结合。

大概表达的意思就是,“你计算能力不达标,那可以把我的’超能力’注入进去嘛”。

而时隔一个多月,Stephen Wolfram围绕“ChatGPT是什么”和“为什么它能这么有效”两个问题,再次发表万字长文做了番深入浅出的详解。

(为了保证阅读体验,以下内容将以Stephen Wolfram的第一人称来叙述;文末有彩蛋!)

一次添加一个单词

ChatGPT 能够自动生成类似于人类撰写的文本,这一点非常引人注目,也是出乎意料的。那么,它是如何实现的?为什么它能够如此出色地生成有意义的文本呢?

在本文中,我将大致介绍 ChatGPT 内部运作的机制,并探讨它为什么能够成功地生成令人满意的文本。

需要说明的是,我将重点关注 ChatGPT 的整体机制,虽然会提到一些技术细节,但不会做深入的探讨。同时,还要强调的一点是,我所说的内容同样适用于当前其它的“大型语言模型”(LLM),而不仅仅限于 ChatGPT。

首先需要解释的一点是,ChatGPT 的核心任务始终是生成一个“合理的延续”,即根据已有的文本,生成一个符合人类书写习惯的下一个合理内容。所谓“合理”,是指根据数十亿个网页、数字化书籍等人类撰写内容的统计规律,推测接下来可能出现的内容。

例如,我们输入了文本“AI 最好的事情是它的能力”,ChatGPT 就会在数十亿页的人类文本中查找类似文本,然后统计下一个单词出现的概率。需要注意的是,ChatGPT 并不是直接对比文字本身,而是以某种意义上的“意思匹配”为依据。最终,ChatGPT 会生成一个可能的单词列表,并给出每个单词的概率排名:

值得注意的是,当ChatGPT完成像写文章这样的任务时,它实际上只是一遍又一遍地询问:“在已有的文本的基础上,下一个词应该是什么?”——并且每次都会添加一个词(更准确地说,如我所解释的,它添加一个“token”,这可能只是单词的一部分,这就是为什么它有时会“创造新词”的原因)。

在每一步中,它都会得到一个带有概率的单词列表。但是,它应该选择哪个单词来添加到它正在写作的文章(或任何其他东西)中呢?

有人可能认为应该选择“排名最高”的单词(即被分配最高“概率”的单词)。但这就是一些神秘的事情开始悄悄发生的地方。因为由于某种原因——也许有一天我们会有一种科学式的理解——如果我们总是选择排名最高的单词,我们通常会得到一篇非常“平淡”的文章,从不显示任何创造力(有时甚至逐字重复)。如果有时(随机地)我们选择较低排名的单词,可能会得到一篇“更有趣”的文章。

这里存在随机性意味着,如果我们多次使用相同的提示,很可能每次都会得到不同的文章。与voodoo理念一致,过程中会有一个特定的所谓“温度”(temperature)参数,它决定较低排名的单词会被使用的频率,对于文章生成,这个“温度”最好设置为0.8。值得强调的是,这里没有使用“理论”;这只是已被证明在实践中起作用的事实。例如,“温度”概念之所以存在,是因为指数分布(来自统计物理学的熟悉分布)恰好被使用,但至少就我们所知,它们之间没有“物理”联系。

在继续之前,我应该解释一下,为了表达的目的,我大多数时候不会使用ChatGPT中的完整系统;相反,我通常会使用一个更简单的GPT-2系统,它具有很好的特性,即它足够小,可以在标准台式计算机上运行。因此,我所展示的几乎所有内容都将包含明确的Wolfram语言代码,您可以立即在计算机上运行。

例如,下面这张图展示了如何获得上述概率表的。首先,我们必须检索底层的 “语言模型 “神经网络:

稍后,我们将深入了解这个神经网络,并讨论它是如何工作的。但目前为止,我们可以将这个“网络模型”作为一个黑盒应用到我们的文本中,并根据模型认为应该遵循的概率,请求前5个单词:

获取结果后,会将其转换为显式格式化的“数据集”:

下面是重复 “应用模型 “的情况—在每一步中加入概率最高的词(在此代码中指定为模型中的 “决定”):

如果再继续下去会怎样?在这种(”零度”)情况下,很快就会出现相当混乱和重复的情况。

但如果不总是挑选 “顶级 “词,而是有时随机挑选 “非顶级 “词(”随机性 “对应 “温度 “为0.8)呢?我们就又可以续写文本了:

而每次这样做,都会有不同的随机选择,对应的文本也会不同。例如以下这5个例子:

值得指出的是,即使在第一步,根据已有的文本,也有很多可能的“下一个词”可供选择(在温度为0.8的情况下),尽管它们的概率很快就会下降(是的,在这个对数图上的直线对应于一个 n–1 的“幂律”衰减,这是语言的一般统计特征):

那么如果我们继续写下去会发生什么呢?这里有一个随机的例子。它比使用最高排名的单词(零度)的情况要好一些,但仍然是有点奇怪:

这是使用最简单的GPT-2模型(来自2019年)完成的。使用更新的更大的GPT-3模型结果更好。这里是使用相同的“提示”,但使用最大的GPT-3模型生成的使用最高排名单词(零度)的文本:

接下来是一个“温度为0.8”的随机例子:

这些概率是从何而来?

ChatGPT总是基于概率来选择下一个单词。但这些概率从何而来呢?

让我们先从一个更简单的问题开始。当我们考虑逐字母(而非逐词)生成英文文本,该如何确定每个字母的概率呢?

最简单的方法是取一份英文文本样本,然后计算其中不同字母的出现频率。例如,这是“猫”在维基百科文章中字母的计数情况(此处省略了计数结果):

这是“狗”的情况:

结果相似,但并不完全一样(毕竟,“o”在“dogs”文章中更常见,因为它本身就出现在“dog”这个单词中)。然而,如果我们取足够大的英文文本样本,最终可以期望得到至少相当一致的结果:

下面是我们只用这些概率生成字母序列的样本:

我们可以通过像是将空格视为带有一定概率的字母来将其分解为“单词”:

可以通过强制“单词长度”的分布与英文一致,来更好地分割“单词”:

这里我们没有生成任何“真实的单词”,但结果看起来稍微好了一些。然而,要进一步推进,我们需要比仅仅随机选择每个字母更多的工作。例如,我们知道如果出现了“q”,下一个字母基本上必须是“u”。

这是字母本身的概率图:

这是典型英文文本中字母对(“2-grams”)的概率图。横轴是可能的第一个字母,纵轴是第二个字母(此处省略了概率图):

在这里,我们可以看到,“q”列除了在“u”行上以外,其他地方都是空白(零概率)。那么,现在我们不再逐个字母地生成“单词”,而是使用这些“2-gram”概率,一次生成两个字母来生成它们。以下是结果的一个样本——恰好包括一些“实际单词”:

通过足够多的英语文本,我们不仅可以很好地估计单个字母或字母对(2-gram)的概率,还可以估计更长的字母组合的概率。如果我们使用逐渐变长的n-gram概率来生成“随机单词”,我们会发现它们逐渐变得“更加真实”。

但是现在让我们假设——与ChatGPT一样——我们处理的是整个单词,而不是字母。英语中大约有40,000个常用单词。通过查看大量的英语文本(例如几百亿个单词的几百万本书),我们可以估计每个单词的出现频率。使用这个估计,我们可以开始生成“句子”,其中每个单词都是独立地随机选择的,其概率与它在语料库中出现的概率相同。以下是我们得到的一个样本:

毫不意外,这是无意义的。那么我们该怎么做才能更好地生成句子?就像处理字母一样,我们可以开始考虑不仅单词的概率,还可以考虑单词对或更长的n-gram的概率。对于单词对,以下是5个例子,所有情况都是从单词“cat”开始:

看起来稍微“更有意义”了一点。如果我们能够使用足够长的n-grams,我们可能会想象基本上会“得到一个ChatGPT”——也就是说,我们会得到一些生成具有“正确的整体文章概率”的长篇文字序列的东西。但是问题在于:实际上没有足够多的英语文本被写出来,以便能够推断出这些概率。

在网络爬虫中可能有数百亿个单词;在数字化的书籍中可能还有另外数百亿个单词。但是,即使是 4 万个常用单词,可能的 2 元组数量已经达到 16 亿,而可能的 3 元组数量则高达 60 万亿。因此,我们无法通过现有的文本估计这些可能性的概率。当我们需要生成 20 个单词的“文章片段”时,可能性的数量已经超过了宇宙中的粒子数量,所以在某种意义上,它们无法全部被写下。

那么,我们该怎么办呢?关键的想法是建立一个模型,让我们能够估计序列应该出现的概率,即使我们从未在我们查看的文本语料库中明确看到过这些序列。而在ChatGPT的核心正是所谓的“大型语言模型”(LLM),它被构建出来可以很好地估计这些概率。

(由于篇幅原因,此处省略“什么是模型”、“神经网络”、“机器学习和神经网络的训练”、“神经网络训练的实践与知识”、“Embedding概念”等章节的编译,感兴趣读者可自行阅读原文)

ChatGPT的内部结构

毫无疑问,它最终是一个巨大的神经网络,目前版本是一个拥有 1750 亿个权重的 GPT-3 网络。在许多方面,这个神经网络与我们讨论过的其它神经网络非常相似,但它是一个专门用于处理语言的神经网络。最显著的特征是一个被称为“Transformer”的神经网络架构。

在我们上面讨论的第一类神经网络中,每个神经元在任何给定层都与前一层的每个神经元基本上相连(至少有一些权重)。但是,如果要处理具有特定已知结构的数据,这种完全连接的网络(大概)是overkill的。因此,在处理图像的早期阶段,通常会使用所谓的卷积神经网络(“convnets”),其中神经元实际上是布置在类似于图像像素的网格上,并且仅与网格附近的神经元相连。

Transformer的思路是对组成文本的token序列做出至少有点类似的事情。但是,Transformer不仅定义了一个固定区域,在该区域内可以建立连接,还引入了“注意力”的概念——“注意力”的概念更多地集中在序列的某些部分而不是其他部分。也许有一天,通过训练,直接启动通用神经网络并进行所有自定义都会有意义。但至少目前在实践中,模块化东西是至关重要的,就像Transformer一样,也可能是我们的大脑所做的一样。

那么 ChatGPT(或者更准确地说,它所基于的GPT-3网络)实际上是在做什么呢?请记住,它的总体目标是基于其从训练中看到的东西(其中包括查看了来自网络等数十亿个页面的文本),“合理地”续写文本。因此,在任何给定的时刻,它都有一定量的文本,并且其目标是为下一个token pick一个适当的选择。

ChatGPT的运作基于三个基本阶段。首先,它获取与目前文本对应的token序列,并找到代表它们的embedding(即一个数字数组)。然后,它以“标准神经网络方式”对此embedding进行操作,使值在网络中的连续层中“波动”,以产生一个新的embedding(即一个新的数字数组)。接着,它获取该数组的最后一部分并生成一个包含约50,000个值的数组,这些值将转化为不同且可能的下一个token的概率(是的,恰好有与英语常用词汇相同数量的token,尽管只有大约3000个token是完整单词,其余是片段。)

关键的一点是,这个pipeline的每个部分都由神经网络实现,其权重由网络的端到端训练决定。换句话说,实际上,除了整体架构之外,没有什么是“明确设计的”;一切都是从训练数据中“学到”的。

而,在架构建立的方式上有很多细节——反映了各种各样的经验和神经网络知识。虽然这绝对是一个细节问题,但我认为讨论其中一些细节很有用,至少可以了解构建ChatGPT所需的内容。

首先是embedding模块。这是GPT-2的一个示意图,用Wolfram语言表示:

这段文字介绍了一个名为“embedding module”的模块,它有三个主要步骤。第一步,将文本转化为token序列,每个token都用一个单层神经网络转化为长度为768(对于GPT-2)或12288(对于ChatGPT的GPT-3)的embedding向量。同时,模块中还有一个“辅助通路”(secondary pathway),用于将token的整数位置转化为embedding向量。最后,将token值和token位置的embedding向量加在一起,生成最终的embedding向量序列。

为什么要将token值和token位置的embedding向量相加呢?似乎并没有特别科学的解释。只是尝试了各种不同的方法,这种方法似乎能够奏效。而且神经网络的传统也认为,只要初始设置“大致正确”,通过足够的训练,通常可以自动调整细节,而不需要真正“理解神经网络是如何进行工程配置的”。

这个“embedding module”模块的作用是将文本转换为embedding向量序列。以字符串“hello hello hello hello hello hello hello hello hello hello bye bye bye bye bye bye bye bye bye bye”为例,它可以将其转化为一系列长度为768的embedding向量,其中包括从每个token的值和位置中提取的信息。

这里展示了每个tokenembedding向量的元素,横向显示了一系列“hello”embedding,其后是一系列“bye”的embedding。上面的第二个数组是位置embedding,其看似随机的结构只是因为“(在这种情况下在GPT-2中)恰好被学习到了”。

好的,embedding模块之后是Transformer的“主要部分”:一系列所谓的“注意力块”(GPT-2为12个,ChatGPT的GPT-3为96个)。这很复杂,让人想起典型的难以理解的大型工程系统,或者说生物系统。但是,这里是GPT-2的单个“注意力块”的示意图:

在每个注意力块中,都有一组“attention heads”(GPT-2有12个,ChatGPT的GPT-3有96个),每个attention head都独立地作用于embedding向量中不同值的块。(是的,我们不知道将embedding向量拆分成若干部分的好处,也不知道它们的不同部分的含义;这只是已被发现可行的技术之一。)

那么,attention head的作用是什么呢?基本上,它们是一种“回顾”token序列(即已经生成的文本),并以一种有用的形式“打包”历史信息以便于找到下一个token的方式。在上文中,我们提到过使用二元概率来基于它们的前一个token选择单词。Transformer中的“注意力”机制允许对更早的单词进行“注意力”,从而可能捕捉到例如动词引用在句子中出现在它们前面多个词的名词的方式。

具体而言,attention head的作用是重新组合与不同token相关的embedding向量的块,并赋予一定的权重。因此,例如,GPT-2中第一个注意块中的12个attention head对于上面的“hello,bye”字符串具有以下(“回顾token序列一直到开头”的)“重新组合权重”模式:

经过注意力机制的处理,得到了一个“重新加权的embedding向量”(对于GPT-2长度为768,对于ChatGPT的GPT-3长度为12,288),然后通过一个标准的“全连接”神经网络层。很难理解这一层在做什么。但是这里是它所使用的768×768权重矩阵的绘图(这里是GPT-2):

通过64×64的移动平均,一些(随机游走状的)结构开始出现:

是什么决定了这种结构呢?这可能是一些关于人类语言特征的“神经网络编码”。但是到目前为止,这些特征可能还是未知的。实际上,我们正在“打开ChatGPT的大脑”(或至少是GPT-2),并发现,是的,里面很复杂,我们并不理解,尽管最终它产生了可识别人类语言的能力。

好的,在经过一个注意力模块之后,我们得到了一个新的embedding向量,随后连续通过其他注意力模块(对于GPT-2总共有12个,对于GPT-3则有96个)。每个注意力模块都有其自己特定的“注意力”和“全连接”权重模式。这里是针对“hello, bye”输入的第一个attention head的注意力权重的序列(对于GPT-2):

以下是(移动平均后的)全连接层的“矩阵”:

有趣的是,即使在不同的注意力块中,这些“权重矩阵”看起来非常相似,权重大小的分布也可能有所不同(并且并不总是高斯分布):

那么,经过所有这些注意力块后,Transformer的净效应是什么?本质上,它将token序列的原始embedding集合转换为最终集合。而ChatGPT的特定工作方式是选择该集合中的最后一个embedding,并对其进行“解码”,以产生下一个token的概率列表。

因此,这就是ChatGPT内部的概述。它可能看起来很复杂(其中许多选择都是不可避免的、有些任意的“工程选择”),但实际上,最终涉及的元素非常简单。因为最终我们处理的只是由“人造神经元”构成的神经网络,每个神经元都执行将一组数字输入与某些权重组合的简单操作。

ChatGPT的原始输入是数字数组(到目前为止token的embedding向量),当ChatGPT“运行”以生成新的token时,这些数字只是通过神经网络的层“传播”,每个神经元“做自己的事情”并将结果传递给下一层的神经元。没有循环或“回溯”。所有东西都只是通过网络“前馈”。

这与典型的计算系统(如图灵机)完全不同,后者通过相同的计算元素重复“重新处理”结果。在这里——至少在生成给定输出token方面——每个计算元素(即神经元)只使用一次。

但在ChatGPT中仍然存在某种意义上的“外部循环”,即使是在计算元素中也会重复使用。因为当ChatGPT要生成新token时,它总是“读取”(即将其作为输入)在它之前出现的整个token序列,包括ChatGPT自己先前“编写”的token。我们可以将这个设置视为意味着ChatGPT在其最外层至少涉及一个“反馈循环”,尽管每次迭代都明确可见为在其生成的文本中出现的token。

让我们回到ChatGPT的核心:用于生成每个token的神经网络。从某个层面上说,它非常简单:一个由相同人工神经元构成的集合。网络的一些部分仅由(“完全连接”)神经元层组成,在该层上的每个神经元都连接到前一层上的每个神经元(具有某些权重)。但特别是在其Transformer架构中,ChatGPT具有更多结构化的部分,其中仅特定层上的特定神经元相连。(当然,人们仍然可以说“所有神经元都连接”-但有些神经元的权重为零)。

此外,ChatGPT中的神经网络的一些方面并不是最自然的“同质”层。例如,在一个注意力块中,有一些地方会对传入的数据进行“多份拷贝”,然后每一份都经过不同的“处理路径”,可能涉及不同数量的层,直到后来才重新组合。虽然这可能是一种方便的表示方式,但至少在原则上,总是可以考虑“densely filling in”层,只是让一些权重为零。

如果你看一下ChatGPT的最长路径,大约有400层(核心层)——在某些方面并不是一个庞大的数字。但是有数百万个神经元,总共有1750亿个连接,因此有1750亿个权重。需要意识到的一件事是,每次ChatGPT生成一个新token时,它都必须进行涉及每个权重的计算。在实现上,这些计算可以被组织成高度并行的数组操作,可以方便地在GPU上完成。但是对于产生的每个token,仍然需要进行1750亿次计算(最后还要多一点)——所以,是的,用ChatGPT生成一长段文本需要一段时间也就不足为奇了。

但最终我们还需要值得注意的是,所有这些操作都能以某种方式共同完成如此“类似人类”的生成文本的工作。必须再次强调的是,(至少就我们所知)没有“终极理论原因”可以解释为什么像这样的任何东西应该起作用。实际上,正如我们将要讨论的那样,我认为我们必须将其视为一项-潜在令人惊讶的-科学发现:在像ChatGPT这样的神经网络中,有可能捕捉到人类大脑在生成语言方面所能够做到的本质。

(由于原文篇幅过长,感兴趣的小伙伴可以戳文末链接阅读全文)

One More Thing

或许在打开这篇文章的时候,有些小伙伴已经注意到了一些细微变化:

没错,这篇文章核心内容的编辑,正是ChatGPT!

以及,它自己谈了谈对Stephen Wolfram这篇文章的看法:

;