什么是 GPT?通过图形化的方式来理解 Transformer 架构 [译]

什么是 GPT?通过图形化的方式来理解 Transformer 架构 [译]

在线字幕版

Predict, sample, repeat

GPT 是 Generative Pre-trained Transformer 的缩写。首个单词较为直接,它们是用来生成新文本的机器人。"Pre-trained" 指的是模型经历了从大量数据中学习的过程,这个词暗示了该模型还有进一步在特定任务中进行额外训练和微调的可能。然而,最后一个词,才是真正重要的部分。Transformer 是一种特定类型的神经网络,一个机器学习模型,它是现今 AI 高速发展的核心创新。我希望通过这个视频和接下来的章节,以一种便于理解的方式,阐述 Transformer 内部实际发生的过程。我们将逐步探索流经它的数据。

你可以使用 Transformer 构建许多不同类型的模型。有些模型接受音频输入并生成文字。这句话来自一个反向工作的模型,只需要文本输入就能生成人工语音。所有那些在 2022 年风靡全球的工具,如 DALL-E 和 MidJourney,能够将文本描述转化为图像,都是基于 Transformer 的。即使我无法让它完全理解 "π 生物"到底是什么,我仍对这样的事情有可能发生感到惊讶。最初的 Transformer 是 Google 在 2017 年推出的,主要用于将一种语言的文本翻译成另一种语言。但我们将关注的版本,也就是像 ChatGPT 这样的工具所依赖的类型,会是一个接受一段文本(可能伴随一些图像或声音)的模型,然后预测文章接下来的内容。这种预测呈现为概率分布形式涵盖了很多可能接下来出现的文字片段。

这个过程,就是通过重复的预测和选取来生成文本,正是你在使用 ChatGPT 或其他大型语言模型时所经历的,模型会逐字地生成文本。其实,我特别希望能有一种功能,即能看到它在选择每个新词时的底层概率分布。

乍一看,你可能觉得预测下一个词似乎与生成新的文字有着天壤之别。但当你有了像这样的预测模型后,你可以试着让它生成一段更长的文字,方法就是给它一个初始的片段,然后随机从刚生成的概率分布中选取一个样本,将这个样本追加到文字中,接着再进行一轮预测,这次的预测需要基于所有新生成的文字,包括刚刚添加的那部分。

我不知道你怎么看,但我真的觉得这个方法的效果可能并不理想。举个例子,在这个动画中,我在我的笔记本电脑上运行 GPT-2,并让它不断地预测与取样下一个文字块,尝试基于一段起始文本生成一个故事。结果呢,这个故事基本上没什么逻辑可言。但是,如果我换成 GPT-3 的 API 调用,这是同样的基本模型,只是规模更大,突然间就像变魔法一样,我们不仅得到了一个合乎逻辑的故事,这个故事甚至能暗示出一个 π 生物可能居住在一个充满数学和计算的世界里。

将这样的工具转化为聊天机器人的一个简单方法是,就是准备一段文本,设定出用户与一个有帮助的 AI 助手交互的场景,这就是所谓的系统提示。然后,你可以利用用户的初始问题或提示词作为对话的开头,接着让 AI 开始预测这个有用的 AI 助手会如何进行回应。为了使这个过程运行得更好,还需要额外的训练步骤,不过总的来说,这就是基本的思路。

Inside a transformer

我们先从宏观角度看看数据是如何在 Transformer 模型中流转的。接下来,我们会详细探讨、解释每一个步骤,并对其进行扩展。但是大体来说,当聊天机器人生成某个特定词汇时,下面就是它底层的运行机制。

首先,输入内容会被拆分成许多小片段。这些小片段被称为词元 (Tokens)。对于文本来说,这些 Token 通常是单词、单词的一小部分,或者其他常见的字符组合。如果是图像或声音,Token 则可能代表图像的一小块区域或声音的一段小片段。

然后,每个 Token 会对应到一个向量上,也就是一串数字,这串数字的目的是以某种方式来表达该片段的含义。如果你把这些向量看作是在一个高维空间中的坐标,那么含义相似的词汇倾向于彼此接近的向量上。每当我说到"含义"这个词时,完全通过向量中的数字来表达。

这些向量序列接下来会经过一个称为"注意力块"的处理过程,使得向量能够相互"交流"并根据彼此信息更新自身的值。例如,"model"这个单词在"机器学习模型(model)"中的意思和在"时尚模特(model)"中的意思是不同的。注意力模块的作用就是要确定上下文中哪些词对更新其他词的意义有关,以及应该如何准确地更新这些含义。

之后,这些向量会经过另一种处理,这个过程根据资料的不同,可能被称作多层感知机或者前馈层。这个阶段,向量不再互相"交流",而是并行地经历同一处理。虽然这个步骤比较难以理解,但我们会在后面讨论,这个步骤有点像对每个向量提出一系列的问题,然后根据这些问题的答案来更新向量。

这两个处理阶段的操作本质上都是大量的矩阵乘法,我们要学习的主要是如何解读这些背后的矩阵。在讲解中,我省略了一些中间步骤的归一化细节,毕竟这只是宏观概览。

接下来,过程基本上是重复的。你需要在注意力模块和多层感知机(MLP)模块之间不断切换,直到最后,我们期望通过某种方式,文章的核心意义已经被完全融入到序列的最后一个向量中。然后对这最后一个向量进行特定操作,产生一个覆盖所有可能 Token 的概率分布,这些 Token 代表的是可能接下来出现的任何小段文本。就像我说的,一旦拥有了这样一个工具,它可以根据一小段文本预测下一步,你就可以给它输入一些初始文本,让它不断地进行预测下一步,从概率分布中抽样,添加到现有文本,然后不断重复这个过程。了解这一点的人可能还记得,早在 ChatGPT 出现之前,GPT-3 的早期演示就是这样的,根据一段起始文本自动补全故事和文章。

Chapter layout

在这一章节中,我们将深入讨论网络开始和结束时发生的事情,同时,我也会花大量的时间回顾一些重要的背景知识,这些知识对于熟悉 Transformer 的机器学习工程师来说,都是基础常识。如果你已经对背景知识比较熟悉,而且迫不及待想要了解更多,那么你可以选择直接跳到下一章节,这一章节将会关注 Transformer 的核心部分,即注意力模块。在这之后,我还会详细讨论多层感知机模块,训练过程,以及之前被省略的其他一些细节。

作为背景信息,这些视频是我们的深度学习系列课程的补充部分,你不一定非得按照顺序来看,但在深入研究 Transformer 之前,我认为有必要确保我们对深度学习的基本概念和架构有共同的理解。

The premise of Deep Learning

这里需要明确的是,机器学习是一种方法论,它涉及到使用数据来指导模型的行为模式。具体来说,你可能需要一个函数,输入一张图片,输出对应的标签描述,或者预测给定文本片段的下一个单词,或者其他需要直觉和模式识别的任务,虽然我们现在已经习以为常,机器学习的核心思想在于,我们不再尝试去编写固定的程序来完成这些任务,这是在 AI 的最早阶段人们会做的事情。

而是构建一个具有可调节参数的灵活结构,就像一系列的旋钮和调节器,然后通过大量实例输入和期望输出的学习,调整和微调参数的值,以此来模拟这种直觉行为。比如,可能最直观的机器学习入门模型就是线性回归了,这里你把输入和输出都视为单个数字,如房子的面积和价格,你要做的,就是找出一条最拟合这些数据的直线,以此来预测将来的房价。这条线由两个连续的参数,即斜率和 y 轴截距。线性回归的目标就是确定这些参数以尽可能匹配数据。

不用说,深度学习模型会更复杂。比如,GPT-3 就拥有 1750 亿个参数,而不仅仅是两个。但值得注意的是,并不是简单地构建一个参数众多的庞大模型就能有效工作,这样做可能会导致模型严重过拟合训练数据,或者训练起来极其困难。

深度学习涵盖了一系列在过去几十年里证明了具有出色扩展能力的模型类别。它们之所以能够成功,关键在于都采用了相同的训练算法:即反向传播,我们在前面的章节已经介绍过这一点。你需要理解的是,要让这种训练算法能在大规模应用中顺利进行,模型必须遵循一种特定的结构。如果你对这种结构有所了解,就能更好地理解 Transformer 处理语言的方式及其背后的逻辑,否则某些设计选择可能显得有些随意。

首先,不管你构建的是哪种模型,输入都必须是一个实数数组。这可能只是一个数字列表,也可能是一个二维数组,或者更常见的是更高维度的数组,这种通用的术语我们称之为张量。这些输入数据通常会被逐步转换成多个不同的层,每一层都构成了实数数组,直到最后一层,你可以将其视为输出层。例如,我们的文本处理模型的最终输出层是一个数字列表,这些数字代表了所有可能的下一词汇的概率分布。

在深度学习领域,这些模型的参数通常被称作权重。这样称呼的原因是,这些模型的一个核心特点是这些参数与正在处理的数据之间的唯一交互方式就是通过权重和。虽然模型中也会穿插一些非线性函数,但它们并不依赖于这些参数。通常来说,我们不会直接看到这些权重和的裸露形式,而是会发现它们被作为矩阵向量乘积的不同部分封装起来。这其实是在表达同一种概念。如果你回想一下矩阵向量乘法是如何运作的,输出中的每一部分都像是一个权重和。

更直观的方式是,将这些可调参数填充的矩阵想象成对处理中数据进行向量转换的工具。例如,GPT-3 中的那 1750 亿个权重就被组织在大约 28,000 个不同的矩阵中。这些矩阵又被分为八个不同的类别,你和我将要做的就是逐一理解这些类别,了解每种类型的功能。接下来的过程会非常有趣,我们将参考 GPT-3 的具体数据来统计这 1750 亿是如何分配的。即使现在有更大更好的模型,GPT-3 模型仍具有独特的魅力,作为第一个引发全球关注的大语言模型,影响力并未局限于机器学习社区。实际上,对于更现代的模型,公司往往对具体的数据保持更严格的保密。

在这里,我想说明的是,当你深入探索像 ChatGPT 这样的工具的内部机制时,你会发现几乎所有的计算过程都体现为矩阵和向量的乘积。在这海量的数字中,很容易迷失方向,但你需要在心中清楚地区分两个概念:模型的权重(我将用蓝色或红色表示)和正在处理的数据(我将用灰色表示)。权重就是模型的"大脑"。这些是在训练过程中学习到的,它们决定了模型的行为模式。正在处理的数据仅仅是编码了某次操作中模型接收的具体输入,比如一段文本示例。

理解了上述基础知识后,让我们探讨文本处理示例的第一步:将输入分割成小片段,并将这些片段转换成向量。我之前提到过,这些小片段被称为 Tokens,它们可能是单词的一部分或是标点符号,但在本章,特别是在下一章中,我倾向于简化理解,假设它们完整地对应于单词。因为我们人类用单词来思考,通过参考小例子和解释每一步可以使这个过程更加容易理解。

Word embeddings

模型拥有一个预设的词汇库,包含所有可能的单词,比如说有 50,000 个。我们将首先遇到的一个矩阵叫做嵌入矩阵,它为每个单词都分配了一个独立的列。这些列定义了第一步中每个单词转换成的向量。我们将其称为 we,就像我们看到的所有其他矩阵一样,它的初始值是随机的,但基于数据进行学习和调整。

在 Transformers 出现之前,机器学习中就已经普遍采用了将单词转换为向量的做法,虽然这对于初次接触的人来说可能有些奇怪,但它为接下来的一切建立了基础,因此,我们需要花一些时间来熟悉它。我们通常称这种转换为词嵌入,这种表述让你可以从几何的角度去理解这些向量,把它们想象成高维空间中的点。

将三个数字看作是三维空间中的坐标点很简单,但词向量的维度远远超出这个范畴。在 GPT-3 中,它们的维度高达 12,288,如你所见,选择一个有很多不同方向的空间进行工作是很重要的。就像你可以在三维空间中选择一个二维切片,并将所有点投影到这个切片上一样,为了让简单模型输出的词向量能够被动态展示,我采取了相似的方法,选择了一个高维空间中的三维"切片",并将词向量映射到这个切片上来展示它们。

这里的关键思想是,模型在训练过程中调整和微调权重,以确定词具体如何被嵌入为向量,它会倾向于找到一组嵌入,使得这个空间中的方向含有特定的语义意义。对于我目前运行的这个简单的词向量模型来说,如果进行搜索,找到所有与"塔楼"最相似的词向量,你会发现这些词都有着类似的"塔楼感"。如果你想在家里用 Python 试一试,这就是我用来制作动画的模型。虽然它不是一个 Transformer 模型,但足以说明一个观点:空间中的方向能够传达特定的语义。

一个经典的例子是,如果你计算"女人"和"男人"向量之间的差值,你会发现这个差异可以被可视化为空间中的一个小向量,连接一个词的尖端和另一个词的尖端,这个差异与"国王"和"女王"之间的差值非常相似。所以假设你不知道表示"女性君主"的词,你可以通过向"国王"向量添加"女人减男人"的方向,并搜索最接近这个点的词向量来找到它。至少在理论上是这样。

虽然这是我正在使用的模型的一个经典例子,但实际上,真正的"女王"嵌入实际上比这种方法预想的要远一些,这可能是因为在训练数据中,"女王"并不仅仅是"国王"的女性版本。深入挖掘时,我发现通过家族关系来解释这一现象似乎更为恰当。关键在于,在训练过程中,模型发现采用这样的嵌入方式更为有利,即这个空间中的一个方向能够编码性别信息。

另一个例子是,如果你从"意大利"的向量表示中减去"德国"的向量表示,再加上"希特勒"的向量表示,结果非常接近于"墨索里尼"的向量表示。这就好像模型学会了将某些方向与"意大利"特性相关联,而将其他方向与二战轴心国的领导人相关联。

我个人最喜欢的一个例子是,在某些模型中,如果你计算"德国"和"日本"的向量差值,然后加上"寿司"的向量,你得到的结果会非常接近"德国香肠"。此外,在寻找最近邻居的过程中,我还惊喜地发现"猫"离"野兽"和"怪物"都很近。

有一个有用的数学概念,尤其对于接下来的章节非常重要,那就是两个向量的点积可以被视为一种衡量它们是否对齐的方法。从计算角度看,点积涉及到逐一乘以对应元素,然后进行求和,这很好,因为我们的很多计算看起来就像是权重求和。从几何角度来看,当两个向量指向相似方向时,点积为正;如果它们垂直,点积为零;当它们指向相反方向时,点积为负。

例如,假设你在测试这个模型,从"cats"(复数)的向量表示中减去"cat"(单数)的向量表示可能会在这个空间中找到表示复数概念的方向。为了验证这个观点,我将计算某个向量与一些特定的单数名词嵌入的点积,并将其与相应的复数名词的点积进行比较。如果你试一试,你会发现复数名词的点积值通常比单数的更高,这表明它们在某种方向上的对齐更为紧密。更有趣的是,如果你将这个点积操作应用到"一"、"二"、"三"等词汇的嵌入上,会发现得到的数值是逐渐增加的,就像我们能够量化地衡量模型认为一个词的"复数程度"。

再次说明,单词的嵌入方式是通过数据学习得到的。这种嵌入矩阵揭示了每个词汇的变化过程,它是我们模型中的第一批权重,根据 GPT-3 的数据,其词汇量具体为 50,257,但要注意,实际上它指的不是单词本身,而是 Tokens。嵌入的维度是 12,288。将这两者相乘,我们得到大约有 6.17 亿个权重。我们将这个数字加入到我们的累计计数中,最后,我们应该得到 1750 亿个权重。

Embeddings beyond words

在谈到 transformer 时,你会想到这些嵌入空间中的向量不仅仅代表着单个词汇。它们还携带了词汇位置的信息,这一点我们稍后会详细说明。但更关键的是,这些向量能够吸纳并反映语境。举个例子,一个最初代表"国王"的向量,在网络中的各个环节的作用下,可能会逐渐变化,因此最后,它指向的方向会更具体、更微妙,以某种方式编码了一位生活在苏格兰的国王,在杀死前任国王后取得其职位的国王,此人的描绘方式充满了莎士比亚式的语言。

想想你对某个词汇的理解通常是怎样形成的。那个词的意义很大程度上是由其所处的环境决定的,有时这甚至包括来自很远的上下文。因此,在构建一个能预测下一个词汇的模型时,关键目标就是让它能够高效地融合上下文信息。

明确一点,在第一步,当我们根据输入文本创建向量数组时,每个向量都是直接从嵌入矩阵中选取的。这意味着,起初,每个向量仅能代表一个单词的含义,而不涉及其周边环境的信息。但我们的主要目标是让这些向量通过网络传递,使每一个向量都能获得比单个词更丰富、更具体的含义。这个网络每次只能处理一定数量的向量,这就是所谓的上下文大小。对于 GPT-3,它的训练上下文大小为 2048,意味着数据在网络中流动时,总是看起来像一串 2048 列的数组,每一列都有 12000 个维度。

这个上下文大小限制了 Transformer 在预测下一个词的过程中可以纳入的文本量。这就解释了为什么如果和一些聊天机器人比如 ChatGPT 的早期版本进行长对话时,你可能会感觉到机器人似乎在对话中迷失了方向,尤其是当对话持续过长时。

我们会在适当的时候详细讨论注意力机制的细节,但先让我们简单了解一下最终阶段的处理过程。

Unembedding

请记住,最终的目标是产生一个概率分布,预测下一个可能出现的 Token。举例来说,如果最后一个词是"教授",上下文中包含了"哈利·波特"等词语,紧接着出现的是"最不喜欢的老师",如果允许我稍微发挥一下,假设 Tokens 就是完整的单词。那么,一个经过良好训练并对哈利·波特世界有所了解的网络,会很可能给"斯内普"这个词赋予一个较高的权重。

此过程涉及两个不同的步骤。首先,使用另一个矩阵,将上下文中的最后一个向量映射到一个包含 50,000 个值的列表,词汇表中的每个 token 都对应一个值。接着,通过一个函数,把这些值转换成概率分布。这个函数叫 softmax,我们稍后会详细讨论。

但在此之前,你可能会觉得,仅仅基于最后一个嵌入来做出预测似乎有些奇怪,毕竟在最后一层中还有成千上万的其他向量,每个向量都蕴含着丰富的上下文意义。这是因为在训练过程中,如果我们利用最终层的每一个向量来预测其后可能出现的内容,被证明是更高效的方法。关于训练的更多细节我们稍后还会提到,现在先简单指出这一点。

这个矩阵被称为 unembedding 矩阵,我们用标签 Wu 来标记它。就像我们见过的所有权重矩阵一样,这个矩阵的初始值是随机的,但在训练过程中,这些值会被更新。关于参数总数的统计,这个 unembedding 矩阵为词汇表中的每个单词都分配了一行,每一行包含与嵌入维度相同数量的元素。这与嵌入(embedding)矩阵非常相似,只不过是把顺序倒过来了,因此它为网络增加了另外 6.17 亿个参数。到目前为止,我们的参数总数已经超过了 10 亿,这只是我们最终要达到的 1750 亿的一小部分。

Softmax with temperature

在这一章的最后一个小课中,我想更详细地讨论一下 softmax 函数,因为它在我们探索注意力机制时会再次成为焦点。如果你想让一串数字成为概率分布,比如预测下一个可能出现的词的概率,那么这些数字每个都得在 0 到 1 之间,并且加起来总和为 1。

但是,如果你正在进行深度学习的实践,你所做的每一步操作都可能看起来像是矩阵和向量的乘法,那么你得到的结果可能并不符合这个条件。这些值可能是负的,也可能远大于 1,而且加起来的和几乎确定不会是 1。Softmax 就是一种标准方法,可以把任何一组数字转换成一个有效的分布,使得最大的数值非常接近 1,而较小的值将会非常接近 0。

了解这一点就足够了。但如果你感到好奇,具体的工作原理是:首先对每个数值进行 e 的指数运算,这样就得到了一组正数;然后取所有正数的和,然后用每个数除以这个总和,这样就把它们标准化为一个总和为 1 的列表。你会注意到,如果输入中的某个数值明显大于其他数值,那么在输出中,这个数值对应的项就会在分布中占主导地位,几乎确定你在采样时会选择这个最大的输入值。

但这种方法比直接挑选最大值更为细腻,因为当其他数值也接近最大值时,它们在整体分布中同样能获得重要的比重,而且随着你不断改变输入,一切都会连续地变化。在一些情况下,比如当 ChatGPT 利用这个分布生成下一个单词时,可以为这个函数增加一些趣味性,可以通过在指数的分母里添加一个常量 t 来实现。我们称之为"温度",因其在某种程度上与热力学方程中温度的作用相似。它的效果是,当 t 值较大时,会使较小的数值获得更多的权重,使得分布稍微均匀一些。而如果 t 值较小,则较大的数值则会更加明显地占据主导,极端情况下,如果把 t 设为 0,那么所有的权重都会集中在最大的值上。

例如,我将用 GPT-3 生成一个故事种子文本是"从前,有一个 A"但我会在每次测试中使用不同的温度。温度为 0 意味着它总是选择最可预测的词,而你所得到的结果就变成了一个陈词滥调的金发姑娘故事。较高的温度给它提供了选择不太可能出现的词的机会,但这也伴随着风险。在这个例子中,故事的开始部分较为原创,讲述的是韩国的一位年轻网页艺术家,但很快就变得毫无意义。

严格地说,API 实际上并不允许你选择大于 2 的温度。这个限制并没有数学上的根据,只是一个人为的限制,我猜,目的是为了防止他们的工具产生太过荒诞的结果。所以,如果你感到好奇,这个动画的工作原理是这样的:我选择了 GPT-3 生成的可能性最高的前 20 个 Token,这看起来是他们能给我的最多的数量。然后,我会根据 1/5 的指数来调整这些概率。

再给你介绍一个专业术语,在这个上下文中,我们通常把这个函数的输出成分称作概率,人们通常将输入称为 logits,有的人说 logits,有的人说 logits,我选择说 logits。举个例子,当你输入一段文本时,所有这些词向量就会通过网络流动,并与 unembedding 矩阵进行最终的乘法运算。机器学习专家会把这种原始、未标准化的输出成分称为下一个词预测的 logits。

Up next

这一章的主要目标是为理解注意力机制打下基础,就像电影《龙威小子》里的基本功训练"上蜡刮蜡"。你看,如果你对词嵌入、softmax 有深入的理解,点积如何衡量相似度,以及大部分计算看起来都像是填满可调参数的矩阵乘法有着深刻的理解,那么掌握注意力机制—— 现代 AI 浪潮中的关键技术,对你来说应该会比较容易。为此,欢迎在下一章中加入我。

发布这篇文章时,下一章的草稿已经可以供赞助者审阅。最终版应该在一两周内公开。这通常取决于我根据审阅结果做出的修改有多大。与此同时,如果你想深入研究注意力机制,如果你想帮助这个频道,那么它就在那里等你。