Do you know how the GPT model works?

Make a fortune with your little hand, give it a thumbs up!

Source[1]

Introduction

It was 2021 when I wrote my first few lines of code using the GPT model, and at that moment I realized that text generation had reached an inflection point. Before this, I wrote language models from scratch in graduate school, and I have experience with other text generation systems, so I know how difficult it can be to get them to produce useful results. As part of my announcement work on the release of GPT-3 in the Azure OpenAI service, I was lucky enough to get early access to GPT-3, and I tried it in preparation for its release. I let GPT-3 summarize a long document and tried a small number of hints. I could see the results being much more advanced than previous models, which got me excited about the technology and eager to see how it would be implemented. Now that the follow-on GPT-3.5, ChatGPT, and GPT-4 models are rapidly gaining widespread adoption, more people in the field are curious about how they work. While the details of their inner workings are proprietary and complex, all GPT models share some basic ideas that are not too difficult to understand. My goal with this post is to explain the core concepts of language models in general, and GPT models in particular, with an explanation aimed at data scientists and machine learning engineers.

How generative language models work

Let's start by exploring how generative language models work. The most basic idea is as follows: they take n tokens as input and produce one token as output.

alt

This seems like a fairly simple concept, but in order to really understand it, we need to know tokenwhat it is.

tokenis a piece of text. In the context of the OpenAI GPT model, common words and short words usually correspond to a single token, such as the word "we" in the image below. Long and uncommon words are usually broken down into several tokens. For example, the word "anthropomorphic" in the image below is broken down into three tokens. An abbreviation like "ChatGPT" can be represented by a single token or broken down into multiples, depending on how often the letters appear together. You can go to OpenAI's Tokenizer page, enter your text, and see how it's segmented into tokens. You can choose between "GPT-3" tokenization for text and "Codex" tokenization for code. We will keep the default "GPT-3" setting.

alt

You can also tokenize using Python code using OpenAI's open-source tiktoken library. OpenAI provides a few different tokenizers, each of which behaves slightly differently. In the code below, we use "davinci"'s tokenizer (a GPT-3 model) to match the behavior you see with the UI.

import tiktoken

# Get the encoding for the davinci GPT3 model, which is the "r50k_base" encoding.
encoding = tiktoken.encoding_for_model("davinci")

text = "We need to stop anthropomorphizing ChatGPT."
print(f"text: {text}")

token_integers = encoding.encode(text)
print(f"total number of tokens: {encoding.n_vocab}")

print(f"token integers: {token_integers}")
token_strings = [encoding.decode_single_token_bytes(token) for token in token_integers]
print(f"token strings: {token_strings}")
print(f"number of tokens in text: {len(token_integers)}")

encoded_decoded_text = encoding.decode(token_integers)
print(f"encoded-decoded text: {encoded_decoded_text}")
text: We need to stop anthropomorphizing ChatGPT.
total number of tokens: 50257
token integers: [1135, 761, 284, 2245, 17911, 25831, 2890, 24101, 38, 11571, 13]
token strings: [b'We', b' need', b' to', b' stop', b' anthrop', b'omorph', b'izing', b' Chat', b'G', b'PT', b'.']
number of tokens in text: 11
encoded-decoded text: We need to stop anthropomorphizing ChatGPT.

You can see in the code's output that this tokenizer contains 50,257 different tokens, and each token is internally mapped to an integer index. Given a string, we can split it into integer tokens, and then we can convert these integers to their corresponding character sequences. Encoding and decoding a string should always return the original string.

This gives you a good intuition of how OpenAI's tokenizer works, but you might wonder why they chose these token lengths. Let's consider some other tokenization options. Suppose we try the simplest implementation, where each letter is a token. This makes it easy to break up text into tokens and keeps the total number of distinct tokens small. However, we cannot encode as much information as OpenAI's approach. If we use letter-based tokens in the above example, 11 tokens can only encode "we need", while OpenAI's 11 tokens can encode the entire sentence. It turns out that current language models have a limit on the maximum number of tokens they can accept. Therefore, we want to pack as much information as possible in each token.

现在让我们考虑每个单词都是一个标记的场景。与 OpenAI 的方法相比,我们只需要七个标记来表示同一个句子,这似乎更有效率。按词拆分也很容易实现。然而,语言模型需要有一个它们可能遇到的标记的完整列表,而这对于整个单词来说是不可行的——不仅因为字典中的单词太多,而且很难跟上领域的步伐——特定术语和发明的任何新词。

因此,OpenAI 选择介于这两个极端之间的解决方案也就不足为奇了。其他公司已经发布了遵循类似方法的分词器,例如 Google 的 Sentence Piece。

现在我们对令牌有了更好的理解,让我们回到我们原来的图表,看看我们是否能更好地理解它。生成模型接受 n 个标记,可以是几个词、几段或几页。他们输出一个标记,可以是一个短词或一个词的一部分。

alt

现在这更有意义了。

但是如果你玩过 OpenAI 的 ChatGPT,你就会知道它会产生很多令牌,而不仅仅是一个令牌。那是因为这个基本思想应用于扩展窗口模式。你给它 n 个令牌,它产生一个令牌输出,然后它将该输出令牌合并为下一次迭代输入的一部分,产生一个新的令牌输出,等等。此模式不断重复,直到达到停止条件,表明它已完成生成您需要的所有文本。

例如,如果我输入“We need to”作为模型的输入,算法可能会产生如下所示的结果:

alt

在玩 ChatGPT 时,您可能还注意到该模型不是确定性的:如果您两次问完全相同的问题,您可能会得到两个不同的答案。那是因为该模型实际上并没有产生单个预测标记;相反,它返回所有可能标记的概率分布。换句话说,它返回一个向量,其中每个条目都表示选择特定标记的概率。然后模型从该分布中采样以生成输出标记。

alt

该模型如何得出该概率分布?这就是训练阶段的目的。在训练期间,该模型会接触到大量文本,并且在给定输入标记序列的情况下调整其权重以预测良好的概率分布。 GPT 模型使用大部分互联网进行训练,因此他们的预测反映了他们所看到的信息的组合。

您现在对生成模型背后的想法有了很好的理解。请注意,虽然我只是解释了这个想法,但我还没有给你一个算法。事实证明,这个想法已经存在了几十年,并且多年来一直使用几种不同的算法来实现。接下来我们将看看其中的一些算法。

生成语言模型简史

隐马尔可夫模型 (HMM) 在 1970 年代开始流行。它们的内部表示对句子(名词、动词等)的语法结构进行编码,并在预测新词时使用这些知识。然而,因为它们是马尔可夫过程,所以它们在生成新令牌时只考虑最近的令牌。因此,他们实现了一个非常简单的“n 个标记输入,一个标记输出”想法,其中 n = 1。因此,它们不会生成非常复杂的输出。让我们考虑以下示例:

alt

如果我们将“The quick brown fox jumps over the”输入到语言模型,我们会期望它返回“lazy”。然而,HMM 只会看到最后一个标记“the”,并且在信息如此少的情况下,它不太可能给出我们期望的预测。随着人们对 HMM 进行试验,很明显语言模型需要支持多个输入标记才能生成良好的输出。

N-gram 在 1990 年代开始流行,因为它们通过将多个标记作为输入来修复 HMM 的主要限制。 n-gram 模型可能会很好地预测前面示例中的“懒惰”一词。

n-gram 的最简单实现是具有基于字符的标记的二元语法,给定单个字符,能够预测序列中的下一个字符。您只需几行代码就可以创建其中一个,我鼓励您尝试一下。首先,计算训练文本中不同字符的数量(我们称之为 n),并创建一个用零初始化的 n x n 二维矩阵。通过选择对应于第一个字符的行和对应于第二个字符的列,每对输入字符可用于定位该矩阵中的特定条目。在解析训练数据时,对于每一对字符,只需将一个字符添加到相应的矩阵单元格即可。例如,如果您的训练数据包含单词“car”,您可以向“c”行和“a”列中的单元格添加一个,然后向“a”行和“r”列中的单元格添加一个柱子。一旦您累积了所有训练数据的计数,将每一行转换为概率分布,方法是将每个单元格除以该行的总数。

alt

然后要进行预测,您需要给它一个字符作为开头,例如“c”。您查找对应于“c”行的概率分布,并对该分布进行采样以生成下一个字符。然后你选择你制作的角色,重复这个过程,直到你达到停止条件。高阶 n-gram 遵循相同的基本思想,但它们能够通过使用 n 维张量来查看更长的输入标记序列。

N-grams 很容易实现。然而,由于矩阵的大小随着输入标记数量的增加呈指数增长,因此它们不能很好地扩展到更大数量的标记。而且只有几个输入令牌,它们无法产生好的结果。需要一种新技术来继续在该领域取得进展。

在 2000 年代,递归神经网络 (RNN) 变得非常流行,因为它们能够接受比以前的技术多得多的输入标记。特别是作为 RNN 类型的 LSTM 和 GRU,得到了广泛的应用,并被证明能够产生相当好的结果。

RNN 是一种神经网络,但与传统的前馈神经网络不同,它们的架构可以适应接受任意数量的输入并产生任意数量的输出。例如,如果我们给 RNN 输入标记“We”、“need”和“to”,并希望它生成更多标记直到达到一个完整点,RNN 可能具有以下结构:

alt

上面结构中的每个节点都具有相同的权重。您可以将其视为连接到自身并重复执行的单个节点(因此称为“循环”),或者您可以将其视为上图中显示的扩展形式。在基本 RNN 上添加到 LSTM 和 GRU 的一个关键功能是存在一个从一个节点传递到下一个节点的内部存储单元。这使后面的节点能够记住先前节点的某些方面,这对于做出良好的文本预测至关重要。

然而,RNN 在处理非常长的文本序列时存在不稳定问题。模型中的梯度趋向于呈指数增长(称为“爆炸梯度”)或减小为零(称为“消失梯度”),从而阻止模型继续从训练数据中学习。 LSTM 和 GRU 可以缓解梯度消失问题,但不能完全阻止它。因此,即使在理论上他们的架构允许任何长度的输入,但实际上对该长度有限制。再次,文本生成的质量受到算法支持的输入令牌数量的限制,需要新的突破。

2017 年,介绍 Transformers 的论文被谷歌发布,我们进入了文本生成的新时代。 Transformers 中使用的架构允许大幅增加输入令牌的数量,消除了 RNN 中出现的梯度不稳定问题,并且高度可并行化,这意味着它能够利用 GPU 的强大功能。 Transformers 在今天被广泛使用,它们是 OpenAI 为其最新的 GPT 文本生成模型选择的技术。

Transformer 基于“注意力机制”,它允许模型比其他输入更多地关注某些输入,而不管它们出现在输入序列中的什么位置。例如,让我们考虑以下句子:

alt

在这种情况下,当模型预测动词“bought”时,它需要匹配动词“went”的过去式。为了做到这一点,它必须非常关注“去了”的令牌。事实上,它可能更关注标记“went”而不是标记“and”,尽管事实上“went”在输入序列中出现得更早。

GPT 模型中的这种选择性注意行为是由 2017 年论文中的一个新颖想法实现的:使用“蒙面多头注意”层。让我们分解这个术语,并深入研究它的每个子术语:

  • 「Attention」:“注意”层包含一个权重矩阵,表示输入句子中所有标记位置对之间的关系强度。这些权重是在训练期间学习的。如果一对仓位对应的权重很大,那么这两个仓位中的token相互影响很大。这种机制使 Transfomer 能够比其他标记更多地关注某些标记,而不管它们出现在句子中的什么位置。

  • 「Masked」:如果矩阵仅限于每个标记位置与输入中较早位置之间的关系,则注意力层被“屏蔽”。这就是 GPT 模型用于文本生成的内容,因为输出标记只能依赖于它之前的标记。

  • 「Multi-head」:Transformer 使用蒙面的“多头”注意层,因为它包含多个并行操作的蒙面注意层。

LSTM 和 GRU 的记忆单元还使后来的标记能够记住早期标记的某些方面。但是,如果两个相关的标记相距很远,梯度问题可能会成为障碍。变形金刚没有这个问题,因为每个标记都直接连接到它之前的所有其他标记。

现在您了解了 GPT 模型中使用的 Transformer 架构的主要思想,让我们看一下当前可用的各种 GPT 模型之间的区别。

不同的 GPT 模型是如何实现的

在撰写本文时,OpenAI 最新发布的三种文本生成模型分别是 GPT-3.5、ChatGPT 和 GPT-4,它们均基于 Transformer 架构。事实上,“GPT”代表“Generative Pre-trained Transformer”。

GPT-3.5 是一个作为完成式模型训练的转换器,这意味着如果我们给它几个词作为输入,它能够生成更多可能在训练数据中跟随它们的词。

另一方面,ChatGPT 被训练为一种对话式模型,这意味着当我们与它交流时,它表现得最好,就像我们在进行对话一样。它基于与 GPT-3.5 相同的 transformer 基础模型,但它使用对话数据进行了微调。然后使用人类反馈强化学习 (RLHF) 对其进行进一步微调,这是 OpenAI 在其 2022 InstructGPT 论文中引入的一项技术。在这种技术中,我们给模型两次相同的输入,取回两个不同的输出,然后询问人类排序者它更喜欢哪个输出。然后使用该选择通过微调改进模型。这种技术使模型的输出与人类期望保持一致,这对 OpenAI 最新模型的成功至关重要。

另一方面,GPT-4 可用于完成和对话,并拥有自己全新的基础模型。该基础模型还使用 RLHF 进行了微调,以更好地符合人类期望。

编写使用 GPT 模型的代码

你有两种选择来编写使用 GPT 模型的代码:你可以直接使用 OpenAI API,或者你可以在 Azure 上使用 OpenAI API。无论哪种方式,您都使用相同的 API 调用编写代码,您可以在 OpenAI 的 API 参考页面中了解这些内容。

两者之间的主要区别在于 Azure 提供了以下附加功能:

  • 自动化负责任的 AI 过滤器,可减少 API 的不道德使用
  • Azure 的安全功能,例如专用网络
  • 区域可用性,以便在与 API 交互时获得最佳性能

如果您正在编写使用这些模型的代码,则需要选择要使用的特定版本。这是一个快速备忘单,其中包含 Azure OpenAI 服务中当前可用的版本:

  • GPT-3.5: text-davinci-002, text-davinci-003
  • ChatGPT: gpt-35-turbo
  • GPT-4: gpt-4, gpt-4–32k

两个 GPT-4 版本的区别主要在于它们支持的令牌数量:gpt-4 支持 8,000 个令牌,而 gpt-4–32k 支持 32,000 个。相比之下,GPT-3.5 模型仅支持 4,000 个令牌。

由于 GPT-4 目前是最昂贵的选择,因此最好从其他模型之一开始,并仅在需要时升级。有关这些模型的更多详细信息,请查看文档。

总结

在本文中,我们介绍了所有生成语言模型共有的基本原则,尤其是来自 OpenAI 的最新 GPT 模型的独特之处。

在此过程中,我们强调了语言模型的核心思想:“n 个标记输入,一个标记输出”。我们探讨了代币是如何分解的,以及为什么要以这种方式分解。我们追溯了语言模型从早期的隐马尔可夫模型到最近的基于 Transformer 的模型长达数十年的演变。最后,我们描述了来自 OpenAI 的三个最新的基于 Transformer 的 GPT 模型,每个模型是如何实现的,以及如何编写使用它们的代码。

到现在为止,您应该已经准备好就 GPT 模型进行有见地的对话,并开始在您自己的编码项目中使用它们。我计划写更多关于语言模型的解释,所以请关注我,让我知道你希望看到哪些主题!感谢您的阅读!

Reference

[1]

Source: "https://towardsdatascience.com/how-gpt-models-work-b5f4517d5b5"

This article is published by mdnice multi-platform

Guess you like

Origin blog.csdn.net/swindler_ice/article/details/131261002