Transformer-BERT-与-GPT
Transformer BERT 与 GPT
译者:飞龙



这本书的价值主张是什么?
本书从基础概念如注意力机制开始,涵盖标记化技术,探讨 Transformer 和 BERT 架构的细微差别,并以与 GPT 系列最新进展相关的高级主题结束,包括 ChatGPT。
关键章节深入探讨了深度学习中注意力的演变和重要性、Transformer 架构的复杂性、BERT 家族的两部分探索,以及使用 GPT-3 的实践指导。结论章节概述了 ChatGPT、GPT-4 以及使用 DALL-E 和生成式 AI 进行可视化的世界。
除了主要主题外,文档还描述了 DeepMind、OpenAI、Cohere、Hugging Face 等有影响力的 AI 组织。通过本指南,读者将全面了解当前 NLP 模型、其底层架构和实际应用。
目标受众
本书主要面向对机器学习有一定了解的人士或对与大型语言模型(LLMs)合作感兴趣的软件开发者。具体来说,本书是为那些习惯于在线搜索更多关于技术主题详细信息的读者所写。如果你是初学者,可能还有其他更适合你的书籍,你可以通过在线搜索找到它们。
本书还旨在吸引具有高度多样化背景的国际读者群体,各个年龄段都有。此外,本书使用标准英语,而不是可能让读者感到困惑的口语表达。本书为预期读者提供舒适而有意义的的学习体验。
我需要学习这本书的理论部分吗?
再次强调,答案取决于您计划参与多少与 LLMs 和生成式 AI 的工作。除了创建模型外,您还将使用各种算法来查看哪些算法提供了您项目所需的准确度水平(或其他指标)。一般来说,学习本书中讨论的 LLMs 的更理论方面可能是值得的。
如何最大限度地利用本书
有些人擅长从散文中学习,有些人擅长从示例代码(以及大量的代码)中学习,这意味着没有一种单一的风格可以适用于所有人。
此外,一些程序员希望首先运行代码,看看它做了什么,然后再回到代码中去深入了解细节(而其他人则采用相反的方法)。
因此,本书中有各种类型的代码示例:有些很短,有些很长,其他代码示例“构建”自早期的代码示例。
为了阅读这本书,我需要了解什么?
尽管这本书的性质是入门级的,但了解一些 Python 3.x 的知识无疑会对代码示例有所帮助。了解其他编程语言(如 Java)的知识也可能有所帮助,因为这样可以接触到编程概念和结构。你拥有的技术知识越少,为了理解所涵盖的各种主题,就越需要勤奋。
如果您想确保自己能够掌握本书中的材料,请浏览一些代码示例,以了解您熟悉的内容有多少,以及有多少内容是新的。
这本书包含生产级别的代码示例吗?
本书包含了一些用 Python 编写的代码示例,其主要目的是向您展示如何访问 LLMs(如 BERT 和 GPT-3)的功能。此外,清晰度比编写更紧凑但难以理解的代码(可能更容易出现错误)更重要。如果您决定使用本书中的任何代码,您应该对这段代码进行与其他代码库部分相同的严格分析。
这本书的非技术先决条件是什么?
虽然这个问题的答案难以量化,但拥有学习 NLP 的愿望,以及阅读和理解代码示例的动机和纪律是很重要的。提醒一下,即使是简单的 API,在第一次遇到时也可能是一个挑战,所以请准备好多次阅读代码示例。
如何设置命令行界面?
如果您是 Mac 用户,有三种方法可以做到这一点。第一种方法是使用 Finder 导航到应用程序 > 工具,然后双击工具应用程序。接下来,如果您已经有一个命令行界面可用,可以通过输入以下命令来启动一个新的命令行界面:
open /Applications/Utilities/Terminal.app
对于 Mac 用户来说,第二种方法是直接在可见的命令行中点击 command+n 来打开一个新的命令行,你的 Mac 将启动另一个命令行。
如果你是一名 PC 用户,你可以安装 Cygwin(开源cygwin.com/),它模拟 bash 命令,或者使用其他工具包,如 MKS(一个商业产品)。请阅读在线文档,了解下载和安装过程。请注意,如果自定义别名定义在除主启动文件(如.bash_login)之外的其他文件中,则不会自动设置。
配套文件
本书中的所有代码示例和图表都可以通过给出版商写信至 info@merclearning.com 获得。
完成本书后“下一步是什么”?
这个问题的答案差异很大,主要是因为答案很大程度上取决于你的目标。如果你主要对 NLP 感兴趣,那么你可以了解其他 LLMs(大型语言模型)。
如果你主要对机器学习感兴趣,那么机器学习的一些子领域,如深度学习、强化学习(以及深度强化学习)可能会吸引你。幸运的是,有许多资源可用,你可以通过互联网搜索这些资源。另一个要点:你需要机器学习的方面取决于你是谁:机器学习工程师、数据科学家、经理、学生或软件开发者的需求都是不同的。
第一章
简介
本章快速介绍了生成式人工智能(AI),重点关注注意力机制,这是 Transformer 架构的关键组件。你还将了解一些在 AI 领域有影响力的公司。
本章的第一部分向你介绍了生成式 AI,包括其最重要的特性和技术。你还将了解对话式 AI 和生成式 AI 之间的区别。
本章的第二部分从对在 AI 和自然语言处理(NLP)领域做出重大贡献的几家公司进行简要介绍开始。如果你计划从事 NLP 职业,你会非常熟悉这些公司。
本章的第三部分介绍了 LLMs(大型语言模型)的概念,这对于本书的所有章节都相关。
本章的第四部分介绍了注意力的概念,这是一种强大的机制,可以生成包含句子中单词的上下文特定信息的词嵌入。注意力概念的内积原理是注意力的主要原理,以及 word2vec 和支持向量机(即所谓的“核技巧”)。
什么是生成式 AI?
生成式 AI是指人工智能模型和技术的子集,旨在生成与给定输入数据在本质上相似的新数据样本。目标是生成原本不属于原始训练集的内容或数据,但内容连贯、上下文相关,并且风格或结构相同。
生成式 AI 的独特之处在于其创造和创新的能力,而不仅仅是分析和分类。该领域的进步导致了创意领域和实际应用的突破,使其成为人工智能研究和开发的前沿领域。
生成式 AI 的关键特性
以下列表包含了生成式 AI 最重要的特性,并对每个项目进行了简要描述:
• 数据生成
• 合成
• 学习分布
数据生成指的是创建不属于训练数据但与其相似的新数据点的能力。这可能包括文本、图像、音乐、视频或其他任何形式的数据。
合成意味着生成式模型可以将各种输入混合起来,生成包含每个输入特征的输出,例如合并两张图片的风格。
学习分布意味着生成式 AI 模型旨在学习训练数据的概率分布,以便它们可以从该分布中生成新的样本。
生成式 AI 的流行技术
生成对抗网络(GANs)由两个网络组成,一个生成器和一个判别器,它们同时训练。生成器试图生成假数据,而判别器试图区分真实数据和假数据。随着时间的推移,生成器在生成逼真数据方面变得越来越好。
变分自编码器(VAEs)是概率模型,学习如何编码和解码数据,以便编码表示可以用于生成新的数据样本。
循环神经网络(RNNs)主要用于序列生成,如文本或音乐。
生成式 AI 的独特之处
创作与分类对比:虽然大多数传统 AI 模型旨在将输入数据分类到预定义的类别中,但生成式模型旨在创建新的数据。
无监督学习:许多生成式模型,尤其是 GANs 和 VAEs,以无监督的方式运行,这意味着它们在训练时不需要标记的数据。
多样化输出:生成式模型可以根据学习到的分布生成各种输出,这使得它们非常适合艺术生成和风格迁移等任务。
挑战:生成式 AI 提出了独特的挑战,如 GANs 中的模式坍塌或确保生成内容的连贯性。
存在许多涉及生成式 AI 应用的领域,以下列表中给出了一些例子:
• 艺术和音乐创作
• 数据增强
• 风格迁移
• 文本生成
• 图像合成
• 药物发现
艺术和音乐创作 包括生成画作、音乐或其他形式的艺术。数据增强 涉及为训练模型创建额外的数据,尤其是在原始数据集有限的情况下。风格迁移 指的是将一个图像的风格应用到另一个图像的内容上。文本生成 涉及创建连贯且与上下文相关的文本。图像合成 涉及生成逼真的图像、面部,甚至为视频游戏创建场景。药物发现 涉及为新潜在药物生成分子结构。
对话式人工智能与生成式人工智能
对话式人工智能和生成式人工智能都是人工智能更广泛领域中的突出子领域。然而,这两个子领域在主要目标、使用的技术和应用程序方面有不同的重点。请参阅以下网站获取更多信息:
medium.com/@social_65128/differences-between-conversational-ai-and-generative-ai-e3adca2a8e9a
两个子领域之间的主要区别如下:
• 主要目标
• 应用
• 使用的技术
• 训练和交互
• 评估
• 数据需求
主要目标
对话式人工智能的主要目标是促进机器与人类之间类似人类的交互。这包括聊天机器人、虚拟助手以及其他与用户进行对话的系统。
生成式人工智能的主要目标是创建新的内容或数据,这些内容或数据不在训练集中,但在结构和风格上相似。这可以包括生成图像、音乐和文本,以及更复杂的任务,如视频合成。
应用
对话式人工智能的常见应用包括客户支持聊天机器人、语音操作虚拟助手(如 Siri 或 Alexa)以及交互式语音响应(IVR)系统。
有许多生成式人工智能应用,例如用于创建艺术或音乐、生成逼真的视频游戏环境、合成声音以及生成逼真的图像或深度伪造。
使用的技术
对话式人工智能通常依赖于自然语言处理(NLP)技术来理解和生成人类语言。这包括意图识别、实体提取和对话管理。
生成式人工智能通常利用生成对抗网络(GANs)、变分自编码器(VAEs)和其他生成模型来生成新内容,如 ChatGPT 和 GPT-4。
训练和交互
虽然训练可以是监督的、半监督的或无监督的,但对话式人工智能的主要交互模式是通过来回对话或交谈。
生成式 AI 的训练过程,特别是对于像 GANs 这样的模型,涉及迭代过程,其中模型通过试图欺骗判别器相信生成数据是真实的,来学习生成数据。
评估
对话式 AI 的评估指标通常围绕理解、响应准确性、用户满意度以及生成响应的流畅性展开。
对于像 GANs 这样的生成式 AI 模型,评估其指标可能具有挑战性,可能需要结合定量指标和人工判断来评估生成内容的品质。
数据需求
对话式 AI 的数据需求通常涉及对话数据,包括人类之间的对话或人类与机器人之间的对话。为了生成 AI 应该生成的内容(如图像、文本和音乐),需要大量此类内容的数据集。
尽管对话式 AI 和生成式 AI 都涉及生成输出,但它们的主要目标、应用和方法可能存在显著差异。对话式 AI 设计用于与用户进行交互式通信,而生成式 AI 则专注于产生新的、原创的内容。
DALL-E 是生成式 AI 的一部分吗?
DALL-E 和类似从文本生成图形的工具确实是生成式 AI 的例子。事实上,DALL-E 是图像合成领域最突出的生成式 AI 例子之一。
以下是一个关于 DALL-E 生成特性的列表,后面是对每个项目的简要描述:
• 图像生成
• 学习分布
• 创新组合
• 广泛应用
• Transformer 架构
图像生成 是 DALL-E 的一个关键特性,它被设计成根据文本描述生成图像。给定一个提示,如“一个双头火烈鸟”,DALL-E 可以生成一个符合描述的新颖图像,即使这种图像没有包含在其训练数据中。
学习分布:与其他生成模型一样,DALL-E 学习其训练数据的概率分布。当它生成图像时,它会从这个学习到的分布中采样,以产生基于其训练的合理视觉。
创新组合:DALL-E 可以生成代表新颖或抽象概念的图像,展示了其以创新方式组合和重新组合学习元素的能力。
除了图像合成之外,DALL-E 还在艺术生成、风格融合以及创建具有特定属性或主题的图像等领域提供了广泛的应用支持,突显了其作为生成工具的多样性。DALL-E 利用类似于 GPT-3 的变压器架构的变体,但针对图像生成任务进行了调整。
其他基于输入数据(无论是文本、另一张图像还是任何其他形式的数据)生成图形、艺术或任何形式视觉内容的工具也被认为是生成性 AI。它们展示了 AI 模型不仅能够分析和分类,还能够创造和创新。
ChatGPT-3 和 GPT-4 是否属于生成性 AI 的一部分?
ChatGPT-3 和 GPT-4 都是大型语言模型,是生成性 AI 的例子。它们属于“转换器”这一类模型,特别擅长处理序列数据,如文本相关任务。
以下列表提供了为什么这些大型语言模型被认为是生成性的原因,随后是对每个项目的简要描述:
• 文本生成
• 学习分布
• 广泛的应用
• 无监督学习
文本生成:这些模型可以根据给定的提示生成连贯、上下文相关且通常非常复杂的文本序列。它们生成的响应在它们的训练数据中并未明确存在,但基于它们在训练期间学习的模式和结构构建。
学习分布:GPT-3、GPT-4 以及类似模型学习其训练数据的概率分布。在生成文本时,它们实际上是从这个学习到的分布中进行采样,以产生基于其训练的序列。
广泛的应用:除了基于文本的聊天或对话之外,这些模型还可以用于各种生成性任务,如故事写作、代码生成、诗歌以及创建特定风格的内容或模仿某些作者,展示了它们的生成能力。
无监督学习:虽然它们可以通过特定的数据集进行微调,但像 GPT-3 这样的模型主要是通过大量文本的无监督方式进行训练,学习生成内容,而不需要为每个可能的响应提供显式的标记数据。
从本质上讲,OpenAI 的 ChatGPT-3、GPT-4 以及类似模型是自然语言处理和生成领域生成性 AI 的典范。
下几节简要介绍了一些在 AI 领域具有强大影响力的公司。
DEEPMIND
DeepMind 在 AI 领域做出了重大贡献,包括创建各种 AI 系统。DeepMind 成立于 2010 年,并于 2014 年成为谷歌的子公司。其主页是deepmind.com/。
DeepMind 创建了 280 GB 的语言模型 Gopher,其性能显著优于其竞争对手,包括 GPT-3、J1-Jumbo 和 MT-NLG。DeepMind 还开发了 AlphaFold,该模型在 30 分钟内解决了研究人员十年未能解决的蛋白质折叠任务。DeepMind 于 2021 年 7 月将 AlphaFold 免费提供给所有人。DeepMind 在 AI 游戏系统的开发方面做出了重大贡献,其中一些将在下一节中讨论。
DeepMind 和游戏
DeepMind 是 AI 系统 AlphaStar 背后的力量,它玩星际争霸,以及击败了围棋最佳人类玩家的 AlphaGo(围棋比象棋要难得多)。这些游戏提供“完美信息”,而“不完美信息”游戏(如扑克)对机器学习(ML)模型构成了挑战。
AlphaGo Zero(AlphaGo 的后继者)通过自我对弈在更短的时间内和更少的计算能力下掌握了游戏。AlphaGo Zero 通过以 100-0 的成绩击败 AlphaGo 展现了非凡的性能。另一个强大的系统是 AlphaZero,它也使用了自我对弈技术来玩围棋、象棋和国际象棋;该系统实现了 SOTA(最先进技术)性能结果。
通过比较,使用树搜索的 ML 模型非常适合完美信息游戏。相比之下,不完美信息游戏(如扑克)涉及隐藏信息,可以利用这些信息制定对抗策略来对抗对手的策略。特别是,AlphaStar 能够与星际争霸 II 的最佳玩家对战,并成为第一个在需要“不完美信息世界中的战略能力”的游戏中实现 SOTA(最先进技术)成果的 AI。
游戏玩家(PoG)
谷歌 DeepMind 团队设计了通用的 PoG(游戏玩家)算法,该算法基于以下技术:
• CFR (反事实后悔最小化)
• CVPN(反事实价值与策略网络)
• GT-CFT (增长树 CFR)
• CVPN
反事实价值与策略网络(CVPN)是一个神经网络,它计算游戏中每个状态信念的反事实。这对于评估任何给定时间的游戏的不同变体至关重要。
增长树 CFR(GT-CFR)是 CFR 的一种变体,它优化了随时间增长的博弈树。GT-CFR 基于两个基本阶段,这些内容在网上有更详细的讨论:
OPENAI
OpenAI 是一家对 AI 做出了重大贡献的 AI 研究公司,包括 DALL-E 和 ChatGPT。其主页在线:openai.com/api/。
OpenAI 由埃隆·马斯克和山姆·奥特曼(以及其他一些人)在旧金山创立,其一个明确的目标是开发对人类有益的 AI。鉴于微软对该组织的大量投资和深度联盟,OpenAI 可能被视为微软的一部分。OpenAI 是 GPT-x 系列 LLM 的创造者,以及 ChatGPT,该产品于 2022 年 11 月 30 日推出。
OpenAI 通过 API 以按字计费的方式将 GPT-3(在第七章中讨论)商业化,使其可用于各种应用程序。GPT-3 于 2020 年 7 月宣布,并通过测试计划提供。然后,在 2021 年 11 月,OpenAI 将 GPT-3 向所有人开放。更多详情可在网上找到:
openai.com/blog/api-no-waitlist/
此外,OpenAI 开发了 DALL-E,它可以从文本生成图像。最初,OpenAI 并不允许用户上传包含真实人脸的图像。后来,OpenAI 改变了其政策,允许用户将其上传到其在线系统中。(更多详情请查看 OpenAI 网站。)顺便提一下,扩散模型(在第十章中讨论)已经超越了 DALL-E 的基准。
OpenAI 已发布 Embeddings 的公共测试版,这是一种适合各种类型机器学习任务的数据格式,如在线所述:
beta.openai.com/docs/guides/embeddings
OpenAI 是 Codex 的创造者,它提供了一组基于 NLP 训练的模型。Codex 的初始发布是在私人测试版中;更多信息可在网上找到:beta.openai.com/docs/engines/instruct-series-beta。
OpenAI 提供了四个模型,统称为他们的“指令模型”,这些模型支持 GPT-3 生成自然语言的能力。这些模型将在 2024 年初被弃用,并替换为 GPT-3、ChatGPT 和 GPT-4 的更新版本,如第七章所述。Chapter 7。
如果你想了解更多关于 OpenAI 提供的功能和服务,请访问以下链接:platform.openai.com/overview。
COHERE
Cohere 是一家初创公司,也是 OpenAI 的竞争对手;其主页为 cohere.ai/。
Cohere 开发了适用于多个行业的尖端 NLP 技术。Cohere 专注于执行文本分析的模型,而不是文本生成模型(如基于 GPT 的模型)。Cohere 的创始团队令人印象深刻:CEO Aidan Gomez 是变压器架构的合发明人之一,而 CTO Nick Frosst 是杰弗里·辛顿的弟子。
HUGGING FACE
Hugging Face 是一个流行的基于社区的开放源代码 NLP 技术仓库;其主页为 github.com/huggingface。
与 OpenAI 或 Cohere 不同,Hugging Face 并不构建自己的 NLP 模型。相反,Hugging Face 是一个平台,它管理着大量的开源 NLP 模型,客户可以对这些模型进行微调,然后部署这些微调后的模型。实际上,Hugging Face 已经成为人们协作开发 NLP 模型的著名场所,有时也被称为“机器学习和 NLP 的 GitHub。”
Hugging Face 库
Hugging Face 提供了三个重要的库:datasets、tokenizers 和 transformers(在第三章中讨论)。Accelerate 库支持 PyTorch 模型。datasets 库提供了一系列 NLP 库。tokenizers 库使您能够将文本数据转换为数值。也许最引人注目的是 transformers 库,它提供了一整套基于预训练的 BERT 模型(在第五章中讨论),以执行各种 NLP 任务。GitHub 仓库位于 github.com/huggingface/transformers。
Hugging Face 模型库
Hugging Face 提供了一个模型库,其中包含大量可在线访问的模型。此外,该网站支持对其模型的在线测试,包括以下任务:
• 使用 BERT 进行掩码词填充
• 使用 Electra 进行命名实体识别
• 使用 RoBERTa 进行自然语言推理
• 使用 DistilBERT 进行问答
• 使用 BART 进行摘要
• 使用 GPT-2 进行文本生成
• 使用 T5 进行翻译
通过以下链接导航以查看“使用 transformer:write”的文本生成能力:transformer.huggingface.co。
在下一章中,您将看到 Python 代码示例,展示如何列出所有可用的 Hugging Face 数据集以及如何加载特定数据集。
AI21
AI21 是一家公司,通过 API 提供专有的大型语言模型,以支持其客户的各项应用。AI21 的当前 SOTA 模型被称为 Jurassic-1(与 GPT-3 大小大致相同),AI21 还在 Jurassic-1 和其他模型之上创建了其自己的应用。AI21 的当前应用套件包括可以增强阅读和写作的工具。
Primer 是这个领域的一个较老竞争对手,成立于 transformer 发明两年前。该公司主要服务于政府和防务客户。
INFLECTIONAI
在 AI 领域中较新的公司是 InflectionAI,其令人印象深刻的创始团队包括
• Reid Hoffman(LinkedIn)
• DeepMind 联合创始人 Mustafa Suleyman
• DeepMind 研究员 Karen Simonyan
InflectionAI 致力于一项具有挑战性的任务:使人类能够以与人类相互沟通相同的方式与计算机互动。
ANTHROPIC
Anthropic 是由 OpenAI 的前员工于 2021 年创建的,其主页为 www.anthropic.com/。
Anthropic 从包括 Google 和 Salesforce 在内的一系列公司获得了重要的财务支持。随着本书的印刷,Anthropic 发布了 Claude 2 作为 ChatGPT 的竞争对手。预计 Anthropic 将在 2023 年第四季度之前使其 API 可用。
Claude 2 能够总结多达 75,000 个单词的文本内容,而 ChatGPT 目前限制在 3,000 个单词。此外,Claude 2 在对用户查询提供“干净”回答的比率上高于 ChatGPT。
这部分章节关于在人工智能领域做出重要贡献的 AI 公司的内容到此结束。下一节将提供一个关于 LLM 的高层次介绍。
LLM 是什么?
大型语言模型,即 LLM,基于 Transformer 架构。存在许多不同规模的 LLM,其中许多比基于 BERT 的模型(在第五章 Chapters 5 和第六章 6 中讨论)更大。因此,本节提供了一个关于 LLM 环境的简要概述。
LLM 以其规模著称,通常至少有 100 亿个参数(BERT 只有“仅”15 亿参数)。此外,它们在训练步骤中涉及非常大的数据集,这可能需要数周的训练时间,成本高达数百万美元。不幸的是,这还伴随着环境成本。根据以下文章,训练 GPT-3 的碳足迹相当于一辆汽车往返月球的行程:
www.theregister.com/2020/11/04/gpt3_carbon_footprint_estimate/
除了 BERT 和 BERT 家族之外,可能最广为人知且引起巨大兴趣的 LLM 是 GPT-3。GPT-3 由 1750 亿个参数组成,几乎是 BERT 的 120 倍。然而,存在更大的模型:Switch 使用了 5400 亿个参数,而 DAO 则使用了超过 1200 万亿个参数。最近(2022 年 11 月),ChatGPT 对公众产生了轰动性的影响(两个月内注册用户达到 1 亿),这在 chapter 9 中进行了讨论。
模型大小与训练集大小
尽管单纯的大小可能看起来是最重要的因素,但训练数据集的大小更为重要。这一说法与 Kaplan 和他的团队的研究结果相矛盾,他们研究了训练集大小与模型大小之间的关系。(这是一个重要的观点,在 Chapter 9 中进行了更详细的讨论。)让我们简要地看看一些已经开发的 LLM。
DeepMind 的 Chinchilla LLM 由 700 亿个参数组成,它能够超越 GPT-3、Jurassic-1(1780 亿)和 Megatron-Turing(5300 亿),因为其训练数据集比其他 LLM 的训练数据集大五倍。
尽管 LLMs 取得了令人印象深刻的成果,以及 GPT-4(于 2023 年 3 月 14 日发布)的备受期待的功能,但 LLMs 并不能以人类的方式理解语言。一个实体做出与人类相当智能的选择的能力并不能证明该实体真正以与人类相同的方式理解这些选择。
LLMs 是否理解语言?
作为一种随意且部分相关的类比,考虑以下故事,这个故事涉及两位棋艺大师、一个自以为是的骗子和一个 12 岁的男孩,他们在 20 世纪初乘坐横跨大西洋的船只旅行。
当船只距离目的地还有几个小时时,那个自以为是的骗子打了一个大胆的赌,在两小时内,他可以训练那个年轻男孩下棋,使得比赛结果要么是平局,要么是男孩获胜。然而,大师级棋手和男孩必须在类似衣柜的封闭区域内进行比赛,并且三个参与者不得以任何方式相互交流。
大师级棋手接受了挑战,期待着利用他们对年轻竞争者的巨大知识优势。然而,随着比赛的进行,大师级棋手对男孩下棋的速度和复杂性感到震惊。他们的信心很快被担忧和绝望所取代。最终,一位大师级棋手提出了平局,另一位大师级棋手认输了。
这个骗局极其简单:每当一位大师级棋手走一步棋,男孩就会对另一位大师级棋手走相同的棋步,这实际上意味着大师级棋手是在相互竞争。幸运的是,船只到达了目的地,骗子设法收集了奖金,带着男孩和奖金下船,在棋艺大师们意识到他们被骗之前。
前面故事的意义在于,男孩做出了极其聪明的棋步,但并不一定理解做出这些棋步的逻辑。因此,如果一个人不理解一个行动背后的逻辑,那么这表明 LLM 真正理解其推荐理由的可能性甚至更小。
关于 LLMs 的注意事项
虽然大型语言模型(LLMs)能够产生令人印象深刻的成果,但请记住以下几点:
• 较小的模型在某些任务中可以超越较大的模型
• 模型会生成错误的结果(“幻觉”)
• 一些模型处理长文档,而另一些则更擅长对话。
• 向量数据库的日益相关性
• 大多数模型没有在最新的数据集上训练(只到某个时间点)。
例如,ChatGPT 是在 2021 年 9 月之前的数据上训练的。两个越来越重要的特性是
-
维护先前对话历史的能力
-
在线搜索信息的能力
此外,比较开源模型与闭源模型的特点是值得的。确实,Yann LeCunn 据说曾评论说:“开源最终会赢得 AI 竞赛。”
损失函数
深度学习模型包括基于 transformer 架构的模型。这些模型依赖于损失函数来训练。具体来说,损失函数是一个可微分的函数,它决定了给定模型预测中产生的误差。
在模型的每次反向传播(称为“反向错误传播”或“反向传播”)过程中,损失函数计算模型参数的梯度(即偏导数的向量),以更新参数的权重,目的是提高模型的准确性。
在训练过程中,关于模型准确性的数字序列并不总是单调递增的集合:有些迭代的表现不如其直接的前辈,有时甚至没有任何改进。
什么是 AI 漂移?
AI 漂移这个术语指的是 LLM 对输入做出意外反应的情况。AI 漂移可能与幻觉不同:前者涉及规律或持续意外的行为,而幻觉可能随机发生,但不一定遵循一致的模式。实际上,当你调用 Completion.create()方法(见第八章的 Python 示例)并设置温度参数大于 1.0 时,你甚至可以在 LLM 中“诱导”出类似幻觉的行为。
AI 漂移的一个潜在原因可能是由于无意中改进了 LLM 的一个领域,却意外地导致 LLM 的其他领域性能变差。
另一个可能导致漂移的原因涉及模型漂移,这可能会发生在生产数据与训练数据实质性不同的情况下。在这种情况下,应监控生产数据、训练数据以及预测结果。
AI 漂移的后果可能是重大的。例如,你的决策过程容易受到 AI 漂移的影响,这可能导致基于错误假设形成的决策。这反过来又可能导致预测和建议的质量下降,以及影响客户满意度。
机器学习与漂移(可选)
在机器学习的术语中,漂移指的是在一定时间内分布的任何类型的变化。模型漂移指的是模型预测准确性的变化(漂移),而数据漂移则指的是收集到的数据类型的改变。(注意:数据漂移也称为输入漂移、特征漂移或协变量漂移。)
有几个因素会影响数据的价值,例如准确性、相关性和年龄。例如,销售手机的实体店更有可能销售最新的手机型号而不是旧型号。在某些情况下,数据漂移会在一段时间内发生,在其他情况下,则是因为某些数据由于应用中的特征相关变化而不再相关。可能存在多个因素会影响特定数据集中的数据漂移。
处理数据漂移的两种技术是领域分类器和黑盒漂移检测器,这两种技术都在网上有讨论:
blog.dataiku.com/towards-reliable-mlops-with-drift-detectors
除了前面提到的漂移类型之外,数据集中还可能发生其他类型的变化:
• 概念偏移
• 协变量偏移
• 领域偏移
• 先验概率偏移
• 假相关偏移
• 亚群体偏移
• 时间偏移
查看arxiv.org/abs/1912.08142获取有关数据集变化的更多信息。
在线搜索以获取有关前面列表中主题的更多信息。最后,以下列表包含提供漂移检测的开源 Python 工具网站:
• 旁证检测 (github.com/SeldonIO/alibi-detect)
• 明显地 (github.com/evidentlyai/evidently)
• Torchdrift (torchdrift.org/)
考虑到前面讨论的主题,让我们将注意力转向注意力这个概念,这是下一节的主题。为了深入了解这个主题,请阅读以下文章:
sebastianraschka.com/blog/2023/self-attention-from-scratch.html
什么是注意力?
注意力是转换器架构中的一个机制,通过它为语料库中的单词确定上下文词嵌入。与 word2vec 或 gloVe 不同,注意力机制在为给定句子中的给定单词创建词嵌入的过程中,会考虑句子中的所有单词。例如,考虑以下句子列表:
我去了银行。
我坐在河岸上。
路将向右倾斜。
如您所见,“bank”一词在意义上是过载的,因为在三个句子中它有不同的含义(作为名词出现两次,作为动词出现一次)。transformer 架构中的注意力机制生成不同的上下文向量(即一个包含浮点数的单维向量)。因此,在不同(且不同的)句子中的相同单词将在每个句子中具有不同的词嵌入。有趣的是,注意力机制在 transformer 架构之前就已经存在:在后者中使用注意力机制是注意力机制获得其显著性的地方。
相比之下,word2vec 算法(由 2013 年的谷歌开发)为“bank”这个词(以及给定句子中的任何其他词)创建一个单一的词嵌入(向量)。这并不是对 word2vec 的批评,word2vec 在其创建时是 NLP 的一个重要突破。
注意力的起源
在注意力机制被设计出来之前,流行的架构基于其他深度学习架构,如 RNNs、LSTMs 或 bi-LSTMs。实际上,注意力机制最初是与 RNNs 或 LSTMs 一起使用的。然而,谷歌团队在仅依赖于注意力机制和 transformer 架构的模型上进行了某些机器翻译任务的实验,并发现这些模型比包含 CNNs、RNNs 或 LSTMs 的模型实现了更高的性能。这一结果导致了“注意力即一切”这一表述,恰好是关于 transformer 架构的开创性论文的标题:
papers.nips.cc/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf
有趣的是,移除 RNNs 提供了两个额外的优势。首先,由于无法并行化的顺序计算,RNNs 相对较慢。其次,RNNs 遭受梯度消失问题。因此,移除 RNNs 消除了这两个缺点。
简单来说,transformer 由一个编码器和解码器组成,每个都包含一个堆叠的注意力层,执行与注意力相关的操作,您将在第四章中了解到这些操作。
自注意力
自注意力可以并行化,以便独立执行计算。因此,自注意力的实现涉及时间复杂度和内存复杂度均为 O(N2)。谷歌研究人员设计了一种算法,将内存复杂度显著降低到 O(log N)。
尽管标准自注意力实现具有时间和内存复杂度,但谷歌研究人员最近的工作表明,通过简单的操作重排序,内存复杂度可以降低到。
如果你熟悉 RNN 和 LSTM,你知道这两种架构都是顺序处理标记的,并且它们可以跟踪输入序列中标记出现的顺序。相比之下,Transformer 架构可以以并行化的方式处理句子中的单词,并且不保持输入序列中单词出现的顺序。Transformer 架构使用称为位置编码(在第三章中讨论)的机制来跟踪输入序列中单词的顺序。
GAtt (幽灵注意力)
GAtt 是用于微调 Meta 的 LLM LlaMa 2 Chat(在第九章中讨论)的算法。GAtt 的开发是为了解决 ChatGPT 在长时间对话过程中倾向于“忘记”指令的问题。有关 GAtt 的更多信息可在网上找到:
betterprogramming.pub/the-dawn-of-a-new-era-llama2-b0b1a9175029
注意力类型和算法
除了层次注意力之外,还有其他类型的注意力机制,其中三种是
-
自注意力
-
全局/软
-
局部/硬
自注意力试图确定句子中单词之间是如何相互关联的。多头注意力使用多个自注意力块而不是单个自注意力。然而,每个头处理嵌入向量的不同部分。除了前面提到的注意力机制之外,还有几种注意力算法可供选择:
• 加性
• 基于内容
• 点积
• 通用
• 基于位置
• 缩放点积 <= Transformer 使用此算法
注意力机制的公式分为两类:涉及向量点积(有时还涉及缩放因子)的公式,以及将 softmax()函数或 tanh()函数应用于矩阵和向量的乘积的公式。
Transformer 架构使用缩放点积机制来计算注意力。有几种注意力类型可供选择,以下文章包含超过 20 种注意力类型的列表:
paperswithcode.com/methods/category/attention-mechanisms-1
注意力机制的一个好处是,它可以将涉及成对词向量内积的计算并行化,而 RNN 和 LSTM 则涉及顺序计算而不是并行化。
注意: Transformer 架构使用缩放点积机制来计算注意力。
GPT-2 与 BERT 中的注意力
LLMs 在其自注意力机制方面可能有所不同。例如,GPT-2 解码器组件中的自注意力(在第七章讨论)与 BERT 编码器组件中的自注意力(在第五章讨论)不同。有关这些不同注意力机制的更多详细信息,请阅读 Jay Allamar 的在线可访问的《图解 GPT-2》帖子:
www.linkedin.com/pulse/illustrated-gpt-2-visualizing-transformer-language-jay/
计算注意力:高级概述
基于注意力的值的计算涉及多个步骤。为了便于理解这个过程,让我们回顾一下神经网络中的前向传播步骤。
神经网络中的前向传播
神经网络中的前向传播步骤可以帮助我们理解 Q、K 和 V 矩阵在 Transformer 架构的注意力机制中的作用。回想一下,神经网络由输入层、一个或多个隐藏层和输出层组成。给定神经网络中相邻的两层,相邻层之间参数的权重(即边)由矩阵 W 表示。当然,矩阵 W 的内容对于神经网络中相邻层的不同对是不同的。
前向传播从输入层开始,按照以下步骤进行,直到我们达到输出层:
-
输入层是一个向量 v1
-
v2 = 矩阵 W 乘以向量 v1
-
v3 = 对 v2 应用激活函数
-
重复步骤 2、3 和 4
矩阵 W 可以用小的随机值初始化(或者你可以使用 He 算法),这些值在反向传播错误(在完成前向传播之后发生)期间更新。因此,矩阵 W 中的值在涉及神经网络的训练过程中进行调整。
Transformer 的 Q、K 和 V 矩阵
这三个矩阵的一种思考方式是它们在通过搜索引擎进行网络搜索中的作用。典型的用例涉及以下步骤:
• 指定一个搜索字符串(查询)
• 选择搜索引擎返回的选项之一(键)
• 查看所选选项的内容(值)
虽然你在执行搜索时可能不会想到中间步骤,但将搜索视为前面列表中的三个步骤是很重要的。让我们将查询、键和值视为欧几里得平面中的向量(只是为了简化问题)。
当你查看查询字符串返回的结果时,你会看到一个包含多个链接(以及包含多个链接的许多其他页面)的列表。将每个链接想象成一个在欧几里得平面中有对应向量的键。从概念上讲,你选择的链接对应于与查询向量最近的向量。此外,选择该链接(即,点击该链接)的行为会导致搜索引擎检索该链接(键)的值,即相关链接的内容。
总结来说,一个输入字符串(查询)与一组向量(键)中最接近的向量(键)相匹配,以检索与所选向量(键)关联的内容(值)。
计算注意力的步骤
虽然计算注意力值的流程与在前面部分讨论的涉及神经网络的矩阵 W 的计算过程不同,但矩阵 W 的对应物涉及三个矩阵 Q、K 和 V,每个矩阵都是随机初始化的。计算注意力矩阵的步骤序列如下:
• 对输入句子进行分词。
• 为每个标记生成嵌入向量。
• 从嵌入向量创建矩阵 X。
• 初始化三个矩阵:Q、K 和 V。
• 使用成对值计算 Q*Kt。
• 除以标量 dk2 = sqrt(键向量维度)。
• 对 Q*Kt/dk2 应用 softmax() 函数。
• 计算注意力矩阵 Z。
这里展示了描述计算注意力矩阵步骤序列的另一种(更简短)方式,包括矩阵的维度:
X Wq/Wk/Wv = Q/K/V
4x512 * 512x64 = 4x64
1) Q*Kt [4x64 * 64x4 = 4x4]
2) Q*Kt/sqrt(dk) [4x4]
3) softmax[Q*Kt/sqrt(dk)] [4x4]
4) softmax[Q*Kt/sqrt(dk)]*V [4x4 * 4x64 = 4x64]
下一个部分包含执行前面列表中每个步骤的示例。
自我注意力的示例
考虑包含四个标记的输入句子“我爱芝加哥披萨”,并计算每个标记的词嵌入(即,浮点向量)。
每个词嵌入的初始值可以是随机数,每个词向量中浮点数的正确值是在训练步骤中确定的。回想一下,在神经网络中,相邻两层参数的权重可以用随机数初始化,这些值在训练阶段的反向传播过程中更新。
假设每个向量的宽度为 512,并任意地将嵌入 y1、y2、y3 和 y4 分配给单词“我”、“爱”、“芝加哥”和“披萨”,如下所示:
y1 = [5.32 7.56 … 0.234]
y2 = [8.65 0.58 … 2.085]
y3 = [0.95 3.47 … 6.813]
y4 = [3.91 5.72 … 7.055]
现在我们可以创建一个矩阵 X,其行由向量 y1、y2、y3 和 y4 组成,如下所示:
|5.32 7.56 … 0.234|
X = |8.65 0.58 … 4.085|
|0.95 3.47 … 6.813|
|3.91 5.72 … 7.055|
矩阵 X 是一个 4x512 的浮点数矩阵,如果输入句子有 P 个单词,那么矩阵 X 是一个 Px512 矩阵。
我们生成三个具有随机初始化值的矩阵,分别命名为 Wq、Wk 和 Wv,之后我们可以初始化用于自我注意力的三个矩阵 Q、K 和 V,如下所示:
• a query matrix Q = X*Wq
• a key matrix K = X*Wk
• a value matrix V = X*Wv
矩阵 Q、K 和 V 在某种程度上类似于上一节中的矩阵 W:它们用随机值初始化,并在训练步骤中更新。接下来要注意的细节如下:
• The 1st row in Q/K/V: the query/key/value
vectors of the word I
• The 2nd row in Q/K/V: the query/key/value
vectors of the word love
• The 3rd row in Q/K/V: the query/key/value
vectors of the word Chicago
• The 4th row in Q/K/V: the query/key/value
vectors of the word pizza 6.
计算矩阵 Q*Kt
现在我们准备计算一个矩阵,该矩阵等于矩阵 Q 与矩阵 Kt(矩阵 K 的转置)的乘积。这两个矩阵的乘积结果是一个矩阵,其单元格值包含原始句子中每对单词之间所有可能的点积(内积)。回想一下,两个向量的内积提供了这两个向量之间相似度的度量。
例如,Q*Kt 的 第一 行是查询向量“我”与关键向量 I、love、Chicago 和 pizza 的内积。
Q*Kt 的 第二 行是查询向量“love”与关键向量 I、love、Chicago 和 pizza 的内积。
Q*Kt 的 第三 行是查询向量“Chicago”与关键向量 I、love、Chicago 和 pizza 的内积。
Q*Kt 的第 第四 行是查询向量“pizza”与关键向量 I、love、Chicago 和 pizza 的内积。
只是为了强调之前关于 Q*Kt 内容的声明:乘积矩阵包含了原始句子“我爱芝加哥披萨”中每个标记(单词)的词嵌入与该句子中每个其他词嵌入的内积。
前面的计算复杂度为 O(N2),其中 N 是输入句子中的标记数。然而,这些计算是相互独立的,这意味着它们可以并行执行,这是 RNNs 和 LSTMs 所不能做到的。此外,还有 transformer 架构的变体,如 Reformer 架构,它们实现了低于二次复杂度。
除以向量维度的平方根
向量维度 dk 等于 64,因此其平方根是 8。我们需要将 Q*Kt 除以这个值来“缩小”其值。请注意,dk 项是经验确定的,并且作为一个缩放因子效果很好。
对 Q*Kt/dk 应用 Softmax 函数
将 softmax() 函数应用于矩阵 Q*Kt/dk 的行,可以完成两件事:1) 所有值都在 0 和 1 之间,2) 每一行都是一个离散的概率分布。
矩阵 Q*Kt/dk 中的值提供了一个相对度量,表明任何一对单词之间的关系。例如,假设第一行包含以下值:
[0.88 0.06 0.03 0.03]
考虑到行和列都标记了句子“I love Chicago pizza”中的标记,我们现在知道第一行中的值提供了以下信息:
0.88 is the correlation between I and I
0.06 is the correlation between I and love
0.03 is the correlation between I and Chicago
0.03 is the correlation between I and pizza
从矩阵 Q*Kt/dk 的第 2、3 和 4 行可以得到类似的结果。
计算注意力矩阵 Z
我们现在可以定义注意力矩阵 Z,它是两个矩阵的乘积:
Z = softmax [(Q*Kt/dk)] * V
矩阵 QKt/dk 和矩阵 V 的行和列的标签都是相同的:它们由句子“I love Chicago pizza”中的标记组成。每个单词的自注意力值等于 QKt/dk 矩阵中每一行的乘积与 V 矩阵中的值的加权和。
自注意力机制也被称为缩放点积注意力,因为它等于 Q 和 Kt 内积的缩放值。
例如,假设 y1、y2、y3 和 y4 分别是“我”、“爱”、“芝加哥”和“披萨”这些标记的词嵌入,它们被任意分配了以下值:
y1: [0.823, 4.432, 2.789, …, 7.123]
y2: [2.382, 3.432, 8.786, …, 6.459]
y3: [3.569, 2.432, 5.783, …, 4.684]
y4: [5.277, 0.426, 0.123, …, 9.001]
尽管 y1、y2、y3 和 y4 的向量由 512 个组件组成,并且实际值将与上述指定的值不同,但它们对于说明目的仍然是有用的。接下来,让我们创建一个包含这四个向量的矩阵,如下所示:
|0.823, 4.432, 2.789, …, 7.123|
X = |2.382, 3.432, 8.786, …, 6.459|
|3.569, 2.432, 5.783, …, 4.684|
|5.277, 0.426, 0.123, …, 9.001|
我们还将创建三个权重矩阵 Wq、Wk 和 Wv,这些矩阵在训练过程中初始化为随机值,并在训练过程中更新,这与 MLP(多层感知器)的训练步骤有些类似。我们通过将 X 与其前面的对应矩阵相乘来创建三个矩阵的查询矩阵 Q、键矩阵 K 和值矩阵 V,如下所示:
Q = X*Wq
K = X*Wk
V = X*Wv
Q、K 和 V 矩阵的维度是 4x64,因为它们是 4x512 矩阵 X 与 512x64 矩阵的乘积:因此,乘积是一个 4x64 矩阵。此外,Q、K 和 V 矩阵的每一行都与我们的输入句子“我爱芝加哥披萨”中的相应单词相关联。然而,Q、K 和 V 的内容与 X 的内容不同。
Q*Kt 的乘积是一个 4x4 的自注意力矩阵,它包含每个输入标记 y1、y2、y3 和 y4 与输入句子中所有标记的相似度,如下所示:
y1 y2 y3 y4
y1 |0.823, 4.432, 2.789, 123|
y2 |2.382, 3.432, 8.786, 456|
y3 |3.569, 2.432, 5.783, 789|
y4 |5.277, 0.426, 0.123, 432|
因此,前面矩阵的对角线元素表示每个输入标记与其自身的相似度。
下一步涉及缩放前面矩阵中的条目,根据原始注意力论文,矩阵值通过除以 dk(键向量的维度)的平方根来减少。在我们的情况下,dk 等于 64,所以平方根等于 8。新的矩阵如下所示:
y1 y2 y3 y4
y1 |0.104, 0.554, 0.348, 15.375|
y2 |0.297, 0.422, 1.098, 57.000|
y3 |0.446, 0.304, 0.724, 98.625|
y4 |0.659, 0.053, 0.015, 54.000|
多头注意力(MHA)
前一节讨论了计算输入句子中每个单词的自注意力步骤。多头注意力涉及计算多个注意力矩阵而不是单个注意力矩阵。单个头处理从嵌入向量开始并通过每个编码器组件(通常涉及 6 个或 12 个这样的组件)的“堆叠”。请阅读以下文章以获取更多信息:
towardsdatascience.com/intuition-behind-transformers-architecture-nlp-c2ac36174047
创建多个注意力矩阵的过程涉及复制创建初始注意力矩阵的步骤,这意味着创建一组新的矩阵 Q、K 和 V,它们分别乘以一组新的矩阵 Wq、Wk 和 Wv。
原始的注意力研究论文指定了 8 个注意力头,这意味着我们将计算注意力矩阵 Z1、Z2、…、Z8。下一步是将 Z1、Z2、…、Z8 连接起来创建最终的矩阵 Zf,然后将 Zf 乘以矩阵 W1、W2、…、W8 的连接,结果是一个我们称为 MHA(多头注意力)的单个矩阵。
总结来说,缩放点积注意力为每个查询 Q 与所有键 K 计算内积,其结果除以 dk(维度 d 的平方根),然后通过 softmax()激活函数。前一句话的结果是一个矩阵,与值矩阵 V 相乘,结果是一个缩放版本的 V 矩阵。
检查变换架构的图,注意多头注意力有三个输入:这些输入是 Q、K 和 V 向量。
此外,单头注意力的公式不涉及 softmax()注意力的权重,而在多头注意力的情况下,权重出现在实际执行缩放点积注意力之前。实际上,权重出现在图中位置较低的线性层中,并且在计算缩放点积注意力之前。
注意,内积可能变得很大,可能导致“梯度消失”类型的效果(因此,引入缩放因子 dk 来产生避免这种效果的缩放值)。
前面的章节向您展示了如何从矩阵 Q、K 和 V 计算注意力值。我们还可以计算多个注意力矩阵,每个矩阵基于 Q、K 和 V 的不同值集。虽然这看起来可能是不必要的,但考虑 CNN(卷积神经网络)中的类似情况,这在下一节中会详细讨论。
虽然这看起来可能是不必要的,但考虑 CNN(卷积神经网络)中的类似操作,这涉及到使用 PNG 像素值数组对多个独立的小随机生成的过滤器(通常是 3x3)进行卷积。
CNN 过滤器与多头注意力
回想一下,卷积过程涉及指定一系列过滤器,这些过滤器是初始化为随机值的方阵。接下来,我们应用卷积、ReLU 激活函数和多次可执行的最大池化。这一系列操作针对每个过滤器执行,操作完成后,我们将每个过滤器得到的结果拼接起来。拼接的结果可以传递给一个或多个全连接层,最后一步是应用 softmax()函数以获得后续的输出。
现在,让我们再次考虑多头注意力。假设我们想要计算 8 个多头注意力值。类似于 CNN 中的过滤器,我们需要计算 8 个注意力矩阵{Z1, Z2, … , Z8},其中每个值都按照你之前看到的方式计算。在 CNN 的情况下,这会涉及 8 个不同的过滤器,而在注意力值的情况下,这涉及到 8 组三元组{Q, K, V},所有这些三元组都是独立地用随机值初始化的。
最后一步涉及将{Z1, Z2, … , Z8}中的矩阵拼接起来,然后乘以矩阵 W 以获得最终的注意力矩阵,如图所示:
MHA = concatenation(Z1, Z2, …, Z8) * W
摘要
本章以对几家 AI 领域的领导者公司(如 DeepMind、OpenAI 和 Hugging Face)的简要描述开始。接下来,你学习了 LLMs(大型语言模型)以及模型大小与训练集大小之间的关系。
你学习了注意力机制,这是 Transformer 架构(在第三章和第四章中讨论)的一个至关重要的组成部分,以及这种机制如何从文本中获取上下文信息。你还学习了自注意力以及计算注意力的某些细节。
最后,你学习了在 Transformer 架构中与注意力机制结合使用 softmax()函数。
第二章
分词
本章介绍了各种分词类型,用于将单词分割成一个或多个标记,因为单词与分词之间存在一对一或多对多的关系。
第一部分讨论了预分词、单词的概念以及预分词与分词之间的区别。本节还包含一个涉及预分词的 Python 代码示例。
第二部分讨论了基于词、基于字符和基于子词的分词,以及这些分词技术的权衡。你还将了解 BERT 和 GPT-2 的分词器,尽管它们在本书中稍后介绍,这样你可以看到它们的分词器操作方式不同。你还将看到基于 Python 的代码示例,展示这些语言模型生成的实际分词。
注意,本章中基于 Python 的代码示例目前需要 Python 3.7,如果你还没有下载,可以从互联网上下载。当本书印刷时,你可能能够使用 Python 3.9(或更高版本)来运行本书中的代码示例。
什么是预分词?
预分词是在需要处理基于文本的语料库时需要执行的第一项任务之一,通常包括以下子集的一些内容:
• 预分词
• 分词任务
• 基于单词的分词
• 基于字符的分词
• 子词分词
在深入探讨预分词之前,下一节将讨论一些基本概念:单词的定义。
什么是单词?
一个单词本质上是一系列代表可以是有形或抽象事物(这就是你一直所知道的单词)的符号序列。只包含字母字符的单词在不同的分词器中被一致地视为单词。然而,分词器可以以不同的方式处理英语中的缩写,尤其是那些基于空格进行分词的缩写。
作为例子,单词“ I’ve”是“ I and have”的缩写,并且被空格分隔的分词器视为一个单词,而使用空格和标点符号的分词器将“I’ve”视为两个单词。
执行标记、字符和单词之间映射操作的方法有以下四种:
• word_to_chars()
• token_to_chars()
• char_to_word()
• char_to_token()
预分词与分词的比较
Hugging Face 文档区分了预分词和分词,而许多在线文章仅使用“分词”这一术语。预分词可以以多种方式实现,可以是单独的也可以是组合的,以下给出了三种技术:
• 空格分词(如 RoBERTa 和 GPT-2)
• 空格和标点符号分词
• 基于规则的分词(例如 FlauBERT 和 XLM)
在预分词中使用空格作为单词分隔符(或空格和标点符号)与“常规”分词相一致,这种分词可以在英语和大多数欧洲语言上执行。然而,一些欧洲语言(如法语和德语)使用重音符号,移除它们可能会改变单词的含义,这在后面的章节中有所讨论。
在本书的后面部分,你将遇到“未区分大小写”和“区分大小写”这两个术语,它们与 LLM 有关。一个未区分大小写的 LLM 是指所有单词都转换为小写,并且所有重音符号都已移除的 LLM。重音符号出现在多种印欧语言中,如法语、西班牙语、德语和斯堪的纳维亚语,但不在英语中。然而,一个区分大小写的 LLM 保留了大写字母和重音符号(如果有)。请注意,一些语言,如普通话和日语,没有大写或小写的概念。未区分大小写的 LLM 和区分大小写的 LLM 之间的选择直接取决于你的用例。
由于以下特征,英语可能是进行预分词最容易的语言:
• 没有重音符号
• 所有单词都由空格字符分隔
• 没有冠词或形容词的变化(与德语/斯拉夫语不同)
• 每个词在每个语法格中都有一种形式(例如,主格和宾格)
此外,英语单词中的撇号可以表示所有格或包含动词(可能是不规则动词)的缩写,如下面的句子所示:
• 当然,这是真的。
• 我认为那确实是它的本质。
• 是的,它的价格确实很高。
• 约翰的车是一辆敞篷车,它很新,车顶是红色的。
• 戴夫要买一辆新车。
• 萨拉不吃虾。
• 萨拉还没有完成。
注意,“its”这个词表示所有格,即使它不包含撇号,也是关于所有格规则的唯一例外。
英语在对话中也可以将名词用作动词。当上下文清晰时,即使人们第一次听到这样的结构,他们也能理解其含义,如下面的句子所示:
“我需要预订一个小时,然后我才能和你见面。”
上句中的“book”一词是一个用作动词“study”替代词的名词。在标准英语中,不定式形式的动词由位于动词之前的介词 to 触发。然而,前一句是非标准英语,因为它包含 to book,但人们可以轻松推断出意图。
现在我们来看一个基于 Python 的代码示例,它说明了下一节将要讨论的预分词。
预分词代码示例
列表 2.1 显示了 pretokenizer1.py 的内容,展示了分词器如何为不同的模型进行分词。
列表 2.1: hf_transformer_mask.py
from transformers import AutoTokenizer
# notice the multiple white spaces:
sentence = "I love Chicago deep dish pizza
don't you?"
# instantiate a BERT-based tokenizer:
tokenizer = AutoTokenizer.from_pretrained
("bert-base-uncased")
# invoke the pre-tokenizer:
result1 = tokenizer.backend_tokenizer.pre_
tokenizer.pre_tokenize_str(sentence)
print("=> tokenizer: BERT")
print("sentence: ",sentence)
print("tokenized: ",result1)
print()
# instantiate a GPT2-based tokenizer:
tokenizer = AutoTokenizer.from_pretrained("gpt2")
result2 = tokenizer.backend_tokenizer.pre_
tokenizer.pre_tokenize_str(sentence)
print("=> tokenizer: GPT2")
print("sentence: ",sentence)
print("tokenized: ",result2)
print()
# instantiate a T5-based tokenizer:
tokenizer = AutoTokenizer.from_pretrained("t5-
small")
result3 = tokenizer.backend_tokenizer.pre_
tokenizer.pre_tokenize_str(sentence)
# instantiate a XLNetTokenizer-based tokenizer:
from transformers import XLNetTokenizer
tokenizer = XLNetTokenizer.from_pretrained
("xlnet-base-cased")
result4 = tokenizer.tokenize(sentence)
print("=> tokenizer: XLNetTokenizer")
print("sentence: ",sentence)
print("tokenized: ",result4)
列表 2.1 以导入语句开始,同时初始化变量 sentence 为一个文本字符串。列表 2.1 的其余部分由四个针对模型 BERT、GPT-2、T5 和 XLNetTokenizer 的分词代码块组成。每个代码块将变量 tokenizer 初始化为特定模型的分词器实例,对 sentence 变量中的文本进行分词,然后显示结果。
例如,以下代码块说明了 BERT 模型前一句的细节:
# instantiate a BERT-based tokenizer:
tokenizer = AutoTokenizer.from_pretrained
("bert-base-uncased")
# invoke the pre-tokenizer:
result1 = tokenizer.backend_tokenizer.pre_
tokenizer.pre_tokenize_str(sentence)
print("=> tokenizer: BERT")
print("sentence: ",sentence)
print("tokenized: ",result1)
print()
现在运行列表 2.1 中的代码,你将看到以下输出:
=> tokenizer: BERT
sentence: I love Chicago deep dish pizza,
don't you?
tokenized: [('I', (0, 1)), ('love', (2, 6)),
('Chicago', (7, 14)), ('deep', (15, 19)), ('dish',
(20, 24)), ('pizza', (31, 36)), (',', (36, 37)),
('don', (38, 41)), ("'", (41, 42)), ('t', (42,
43)), ('you', (44, 47)), ('?', (47, 48))]
=> tokenizer: GPT2
sentence: I love Chicago deep dish pizza,
don't you?
tokenized: [('I', (0, 1)), ('Ġlove', (1, 6)),
('ĠChicago', (6, 14)), ('Ġdeep', (14, 19)),
('Ġdish', (19, 24)), ('ĠĠĠĠĠĠ', (24, 30)),
('Ġpizza', (30, 36)), (',', (36, 37)), ('Ġdon',
(37, 41)), ("'t", (41, 43)), ('Ġyou', (43, 47)),
('?', (47, 48))]
=> tokenizer: T5-SMALL
sentence: I love Chicago deep dish pizza,
don't you?
tokenized: [('I', (0, 1)), ('love', (2, 6)),
('Chicago', (7, 14)), ('deep', (15, 19)),
('dish', (20, 24)), ('pizza,', (31, 37)),
("don't", (38, 43)), ('you?', (44, 48))]
=> tokenizer: XLNetTokenizer
sentence: I love Chicago deep dish pizza,
don't you?
tokenized: ['I', 'love', 'Chicago', 'deep',
'dish', 'pizza', ',', 'don', "'", 't', 'you',
'?']
什么是分词?
简而言之,分词涉及将语料库的文本分割成可以映射到数字的单词(例如,word2vec),以便通过神经网络处理这些单词的数字对应物。在后面的部分中简要讨论了几种分词技术,以及这些技术中涉及的一些权衡。
分词器的细微差别
分词器执行不同类型的分词,其特征取决于用于实例化分词器的 NLP 模型。因此,本节简要讨论了从 BERT、GPT2 和 T5 模型实例化的分词器之间的差异。
基于 BERT 的分词器保持单词偏移的索引。此外,预分词在空白和标点符号处分割。然而,基于 GPT2 的分词器在空白和标点符号处分割,并用符号Ġ替换空格,从而可以在文本字符串中恢复原始空格。这个分词器与 BERT 分词器不同,因为它识别双空格。
另一种类型的分词器是基于 SentencePiece 算法的 T5 分词器,它也类似于 GPT2-2 分词器。然而,这个分词器保持空格,并用下划线(_)标记替换它们。此外,T5 分词器只在空白处分割,而不是在标点符号处分割,并且还添加了一个初始空白。在第四章中,您将看到涉及实例化特定模型分词器的基于 Python 的语言模型示例。
一个通用的标记到索引映射算法
本节提供了一个将整数与语料库中的每个单词关联的简单算法,如列表 2.2 所示。
列表 2.2: create_token2idx.py
token2idx = {}
curr_idx = 0
docs = list()
docs.append("this is a simple document")
docs.append("this is a second document")
docs.append("the third short document")
# initialize word/integer pairs:
for doc in docs:
for token in doc.split(" "):
if token not in token2idx:
token2idx[token] = curr_idx
curr_idx += 1
# display token/integer pairs:
for token in token2idx.keys():
print(f"token: {token:10} value:
{token2idx[token]:4}")
print()
# create an integer-based counterpart
int_docs = []
for doc in docs:
for doc in docs:
tokens = [token2idx[word] for word in doc.split
(" ")]
int_docs.append(tokens)
print("int_docs:",int_docs)
print()
# create integer-to-token mapping:
idx2token = {v: k for k,v in token2idx.items()}
for k,v in idx2token.items():
print(f"key: {k:4} value: {v:10}")
列表 2.2 首先定义了一个 Python 字典 token2idx 和一个初始值为 0 的标量变量 curr_idx。接下来的代码块初始化变量 docs,包含三个文档,每个文档都是一个简短的句子。
列表 2.2 的下一段代码遍历 docs 中的文档,并使用 split()函数对每个文档进行分词。接下来,条件逻辑会在当前标记不在该字典中时,在字典 token2idx 中添加一个新的标记/整数对。
下一个代码块显示了 token2idx 中的标记/整数对,接着是一个代码块,它将变量 int_docs 填充与字典 token2idx 中每个标记关联的整数值,然后显示所有整数值。列表 2.2 的最后部分创建了一个整数到标记的映射,称为 idx2token。后一个代码块在需要将神经网络中的预测(涉及标记 ID 值)转换为相关标记时是相关的。运行列表 2.2 中的代码,您将看到以下输出:
token: this value: 0
token: is value: 1
token: a value: 2
token: simple value: 3
token: document value: 4
token: second value: 5
token: the value: 6
token: third value: 7
token: short value: 8
int_docs: [[0, 1, 2, 3, 4], [0, 1, 2, 5, 4], [6, 7,
8, 4], [0, 1, 2, 3, 4], [0, 1, 2, 5, 4], [6, 7, 8,
4], [0, 1, 2, 3, 4], [0, 1, 2, 5, 4], [6, 7, 8, 4]]
key: 0 value: this
key: 1 value: is
key: 2 value: a
key: 3 value: simple
key: 4 value: document
key: 5 value: second
key: 6 value: the
key: 7 value: third
key: 8 value: short
再次,前面的代码示例提供了一个将单词与整数值关联的通用过程。在讨论语言模型中使用的分词技术之前,让我们深入了解一些相关的挑战,如下一节所述。
分词任务及其挑战
标记化涉及在句子和文档中找到标记,其中标记可以是单词、字符或部分单词。标记化还必须考虑到在执行以下子任务时可能出现的潜在问题:
• 将文本转换为小写(或不转换)
• 处理分隔句子的标点符号
• 处理标点符号(例如法语和德语)
• 处理缩写(“won’t”与“will not”)
• 处理不寻常(不常见)的单词
如果您之前没有进行过标记化,这可能看起来是一个简单的任务,但标记化有几个非平凡方面。以下是在对语料库进行标记化时需要考虑的要点列表(不分先后):
• 常用名词与专有名词的区别
• 可选的单词分隔符
• 标点符号与词义
• 不同的子词标记化技术
• 单数名词与复数名词
• 单词拼写变体
• 打印错误
• 翻译任务中的假同源词
首先,将单词转换为小写会失去常用名词和专有名词(如“Stone”与“stone”)之间的区别。其次,使用空白字符将句子标记为单词标记在日语等语言中不正确,在这些语言中,空格是可选的。因此,一个句子可以写成没有空格的单个连续的非空字符字符串:Thiscanbeapainandtediousinanylanguage。这个例子表明,缺少空格会增加复杂性(也许您需要集中注意力来解析没有空格的先前的字符串)。
第三,去除重音(重音符号)会使单词变得模糊:peche根据单词中出现的哪个重音符号有三个可能的含义(即桃子、鱼或罪)。作为一个极端的例子,以下(不常见)的法国短语“le peche du peche”有多个解释,只有从上下文中才能清楚。
第四,在标记化时考虑标点符号很重要,这样可以确保模型不需要学习带有多个标点符号的单词的不同表示。
第五,不同的库和工具包执行不同类型的子词标记化。例如,可以将单词“Don’t”标记为[“Don”, “ ’ ”, “t”]或作为[“Do”, “n’t”](在这种情况下,spaCy 库使用后一种方法)。
第六,从英语单词中去除最后的“s”可能会导致单词含义发生变化。例如,“birds”和“bird”是名词的复数和单数形式,而“new”和“news”有不同的含义。一般来说,在名词后加“s”会形成该名词的复数形式,而将“s”加在形容词上可能会导致一个与形容词含义不同的名词。
虽然前面的一些示例可能看似微不足道(甚至微不足道),但这些细节会影响翻译成与输入文本语言不同的语言后的文本字符串的准确性和流畅性。
标记化还必须解决其他问题,例如处理单词的不同拼写方式(例如,“favor” 与 “favour”,“tire” 与 “tyre”,“color” 与 “color”),同一单词的不同含义(例如,“to table” 一个讨论),以及印刷错误(例如,“dependent” 与不正确的 “dependant”)。
其他潜在问题包括拼写和大小写的变化、不规则动词以及词汇表外的标记化问题。还有一个与发音差异相关的问题。考虑以下单词的不同发音方式:
• 铝: “uh-LOO-minum” 或 “al-loo-MIN-ium”
• 隐私: “PRIV-acy” 与 “PRY-vacy”
• 时间表: “SKEDjule” 与 “SHEDjule”
标记化的替代方案:ByT5 模型
Google 引入了 ByT5 模型,该模型直接与 UTF-8 字节一起工作,而不是使用子词标记化。这种方法的优势在于它摒弃了任何形式的文本预处理。此外,这种方法可以扩展以处理字节序列,而不会增加过多的计算成本。然而,字节序列比词级序列长得多。
ByT5 模型是从另一个名为 mT5 的 Google 模型派生出来的,mT5 是 “Massively Multilingual Text-to-Text Transfer Transformer” 的缩写。虽然 mT5 是基于标记的模型,但通过对其做出适度修改,可以使 mT5 无标记。ByT5 模型的详细信息可在 arxiv 论文 “Towards a Token-Free Future With Pre-Trained Byte-to-Byte Models” 中找到,该论文可在 arxiv.org/abs/2105.13626 访问。
WORD, CHARACTER, AND SUBWORD TOKENIZERS
从本质上讲,标记器将句子和文档转换成适合语言模型处理的格式。请记住,LLMs 只处理数值,这意味着标记器必须将文本字符串转换为数值数据。一般来说,标记器的目标是双重的:找到最有意义的表示,同时(如果可能的话)找到最小的表示。
在 NLP 中,你会遇到几种类型的标记器:
• 预词标记器(之前已讨论)
• 词标记器
• 字符标记器
• 子词标记器
以下各节将讨论前面提到的每种标记器类型,以及它们的一些权衡。
基于词的标记器
通常,基于词的标记器很简单,因为它们涉及有限数量的规则,并且可以实现相当好的结果。一种基于空白字符对文本字符串进行程序化标记化的方法是在 Python 中使用 split() 函数,如下所示:
tokenized_text = "I love Chicago pizza".split()
print(tokenized_text)
['I', 'love', 'Chicago', 'pizza']
一些单词分词器为标点符号指定了额外的规则,这可能导致词汇量很大(即给定语料库中的标记数量)。此外,单词被分配一个从 0 到(N-1)的 ID,其中 N 是词汇表中的标记数量。模型通过其分配的 ID 值识别给定的单词。
不幸的是,密切相关但不同的单词被视为不同的单词,这意味着它们将被分配不同的 ID 值。例如,以下一组单词在意义上相关:
• sing
• sang
• sung
• singing
此外,模型将名词的单数形式与该名词的复数形式区别对待。这个过程在具有阳性、阴性、中性和复数形式的名词的语言(如德语和斯拉夫语)中变得更加复杂,所有这些形式都被视为不同的名词。
例如,英语中只有一种形式的文章“the”,而以下展示了德语中定冠词“der”的变化形式,其中列出了阳性、阴性、中性和复数,行则表示主格、属格、与格和宾格:
Masculine Feminine Neuter Plural
Nominative der die das die
Genitive des der des der
Dative dem der dem den
Accusative den die das die
正如您将在第五章中看到的那样,BERT 包含大约 25,000 个标记,这些标记来自英语单词,英语单词超过五十万个。BERT 使用一种机制将标记分割成子标记,这使得 BERT 可以使用这些“词片段”来处理其他标记。此外,BERT 使用特殊标记 UNK 来表示未知单词(以及其他语言模型也使用 UNK 标记)。
单词分词器的局限性
模型只能识别其训练步骤中的单词标记,这意味着如果复合词没有出现在训练步骤中,则不会被识别。例如,如果单词“book”和“keeper”是训练步骤的一部分,但单词“bookkeeper”没有在训练步骤中,那么“bookkeeper”将不会被识别,因此它将通过 UNK 标记来表示。
分词器面临的另一个挑战与缩写词有关。例如,英语单词“its”和“it’s”具有完全不同的含义:“its”表示所有格,而“it’s”表示“它是”。在名词的情况下,撇号也指所有格(例如,John’s car)。因此,句子“It’s true that John’s pen is worth its weight in gold”只能有一种解释。
如您可能猜到的,与俚语结合的缩写词对分词器构成了挑战。考虑以下一组某些人在他们的短信中使用过的术语:
AFAIK
IIRC
IDK
SMH
AFAICS
LMK
DOPE
BOMB
多字母表语言的分词
正如你之前看到的,在中文和日语等语言中,单词之间的空格字符是可选的。此外,日语有三种字母表:平假名、片假名(仅用于外语单词)和罗马字(用于罗马化日语单词)。日语还有汉字,这是一种基于象形文字的系统,用于表示单词。日语句子和街牌可以包含平假名和汉字的组合,这对非日语人士来说更加难以理解。
一个想法是通过编码系统来表示单词。例如,ASCII 是一种编码方案,用于将英语单词进行编码;然而,ASCII 无法表示带有重音符号的欧洲语言(如法语)。
另一个编码方案是 ISO-159,它支持重音符号;然而,这个编码方案主要限于西欧语言。另一个编码方案是 UTF-8,它支持更广泛的字符集。也许最广泛的编码方案是 Unicode 编码方案,它支持所有人类语言的字母、标点符号和字母表,包括阿拉伯语、普通话和日语。进行在线搜索以获取有关编码方案更多信息,你将找到许多免费文章。
基于字符的标记化器的权衡
基于字符的标记化器将语料库分割成字符而不是单个单词,这有两个主要好处:
• 词汇量小于基于单词的标记化。
• 有较少的词汇表外标记(每个单词都可以由字符构成)。
然而,基于字符的标记化也有两个局限性。首先,一组字符提供有限的实际意义。单词是句子的基本构建块,因此它们承载意义(有时是多个意义)。虽然上述内容对于基于字母的语言(如印欧语系语言)是正确的,但一些东南亚语言是基于象形文字的,可以传达需要解释的复杂概念。
第二,基于字符的标记化将生成显著更多的标记,这可以轻易地是基于单词的标记集的五倍之大,导致训练模型所需的时间比基于单词的标记化所需的时间多得多。
如果我们将字符的性质与单词的性质进行对比,我们会看到对于许多语言来说(除亚洲语言外),字符没有实际意义。一个非常简单的例子是,字母“s”由于缺乏上下文而意义不明确,而单词“apples”的上下文基本上是明确的。然而,单词具有相反的性质:一个单词可以承载多个意义,这些意义取决于它们在句子中的上下文。
基于字符的标记化器的局限性
如你在前一节中学到的,基于字符的标记涉及更多的计算时间和资源来训练模型。如果一个单词的平均字母数是 5,那么一个 10 个单词的句子将涉及 50 个标记而不是 10 个。
此外,还有生成单词正确拼写的问题,当标记是字符而不是单词时,这会更困难。此外,基于单词的分词更适合各种 NLP 相关任务,如 NER 和文本分类,而不太适合基于字符的分词。
虽然前面的观点有利于基于单词的分词,但这涉及到创建一个适度大小的词汇表,这反过来又提高了语料库中 OOV(词汇表外)单词的可能性。正如你将在基于 BERT 的代码示例中看到的那样,OOV 单词用 UNK(“未知”)标记表示。
幸运的是,有一种类似混合的技术可以同时利用基于字符和基于单词的分词的优点,同时避免它们的问题。这种技术被称为子词分词,这是下一节的主题。
子词分词
子词分词通常基于算法、统计规则和一个重要的启发式方法:将不常见或很少出现的单词分词为子词,并且不要分割经常出现的单词。
这种分词可以很容易地应用于带有后缀“ly”的英语副词:用两个标记替换副词,其中第二个标记是“ly”的组合。因此,“slowly”被分解为“slow”和“ly”,“quickly”被替换为“quick”和“ly”,等等。
同样,形容词“lonely”可以分解为“lone”和“ly”。在某些情况下,这种分解成两个标记实际上产生了第一个标记的单词,正如前面例子所示。
此外,子词分词还可以产生具有意义的标记,例如将单词“internationalization”分词为“international”和“ization”。
除了前面提到的用于处理英语单词子集的分词类型之外,还有其他分词算法,其中一些在此列出:
• 字节级 BPE(在 GPT-2 中)
• WordPiece(在 BERT 中)
• SentencePiece 或 Unigram(在多个多语言模型中)
子词分词代码示例
列表 2.3 显示了 hf_subword_tokenizer.py 的内容,该内容说明了如何使用 Hugging Face transformer 进行分词。
列表 2.3:hf_subword_tokenizer.py
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained
("bert-base-cased")
sequence = "I love Chicago always deeply dished
pizzas!"
tokens = tokenizer.tokenize(sequence)
print("sequence:",sequence)
print("tokens: ",tokens)
ids = tokenizer.convert_tokens_to_ids(tokens)
print("token ids:", ids)
# ids = [146, 1567, 2290, 1579, 5585, 10478, 1174,
13473, 1116, 106]
decoded_ids = tokenizer.decode(ids)
print("decoded: ",decoded_ids)
列表 2.3 以一个导入语句开始,然后初始化变量 tokenizer 为 AutoTokenizer 的一个实例。接下来,变量 sequence 被初始化为一个文本字符串,然后变量 tokens 被初始化为变量 sequence 中的标记集合。使用以下命令启动 列表 2.3 中的代码:
python3 hf_tokenizer.py
前一个命令将显示以下输出:
sequence: I love Chicago always deeply dished
pizzas!
tokens: ['I', 'love', 'Chicago', 'always',
'deeply', 'dish', '##ed', 'pizza', '##s', '!']
token ids: [146, 1567, 2290, 1579, 5585, 10478,
1174, 13473, 1116, 106]
decoded: I love Chicago always deeply dished
pizzas!
注意,列表 2.3 中的 decode()方法做了两件事:首先,索引被转换为标记;其次,属于同一单词的标记被分组在一起,从而生成可读的句子。这种行为对于预测新文本的模型(无论是根据提示生成的文本,还是翻译或摘要等序列到序列问题)非常有用。
关于 BERT 分词的关键点
虽然 BERT 在第五章中讨论,但本节包含有关 BERT 的分词相关信息,因此将其包含在此处。无论你是否决定阅读这一节,你都可以在阅读了第五章中关于字节对编码(BPE)和 WordPiece 的材料后,返回到本章的这一部分。
BERT 有一个固定的标记词汇表,以及相关的嵌入,这意味着 BERT提供自己的分词器。此外,你不能用另一组嵌入(无论是你自己的还是别人的)替换 BERT 嵌入。关于 BERT 的其他关键点如下:
• 包含 BPE 和 WordPiece(类似于 BPE)
• 包含一个似然计算层
• 基于 BERT 的模型使用相同的特殊标记
• 通常使用 WordPiece 在原始文本上训练
• 不需要词干提取和词形还原
• 小写模型将句子转换为小写
• 大写模型不会改变句子的首字母大小写
• 使用 transformer 模型
由于 BERT 使用 transformer 架构的编码器组件,微调步骤仅检查对输出有影响的单词,并忽略所有数据中常见的单词。请注意,每个 BERT 模型都使用其自己的输入类型:例如,与 BERT 不同,DistilBERT 不使用 token_type_ids。你现在对分词器有了足够的了解,可以学习 Hugging Face API,这在下一节中讨论。
模型如 BERT 或 GPT-2 及其变体,通过 BPE 算法的某个版本或单语模型对文本进行分词。
子词分词算法
子词分词涉及将未知词汇(OOV)分割成更小的片段。回想一下,上一节简要描述了以下类型的分词器:
• 词分词器
• 字符分词器
• 子词分词器
子词分词算法基于启发式方法,这意味着它们基于直观的推理,这种推理“有意义”并且可以产生正确的答案。具体来说,出现频率较高的单词被分配唯一的 ID。然而,低频词被分割成子词,这些子词保留了低频词的意义。以下列表包含四个重要的子词分词算法:
• BPE
• SentencePiece(用于 ALBERT)
• 单语语言模型
• WordPiece(用于 BERT 和 DistilBERT)
Hugging Face transformers 库支持大多数 BERT 变体的所需分词器。实际上,这个库中的 BERT 模型处理了 11 种 NLP 问题,这些也可以组合成一个流水线。
所有四种算法都涉及文本的子词分词,尽管它们在实现子词处理的不同算法方面有所不同。
BERT 的作者确实训练了一个 BERT 变体,使用了一种称为整词掩码的技术,该技术遵循以下规则:如果“嵌入”中的一个子词被选中,那么所有子词标记都会被替换。
什么是 BPE?
BPE(字节对编码)是一种多用途工具,最初用于满足数据压缩的需求,但已成为现代自然语言处理中的关键工具。通过启用子词分词,BPE 使模型能够高效且自适应地处理大量词汇,使其成为许多前沿语言模型的基础。BPE 是一种自底向上的子词分词算法,它学习一定大小(词汇大小是一个超参数)的子词词汇。BPE 背后的核心思想是迭代地合并数据集中最频繁出现的字节对(或字符)直到达到指定的合并次数。
第一步被称为初始化,它涉及将文本分词成字符,然后为每个字符分配一个唯一的标记。第二步涉及迭代合并结果。在每次迭代中,找到最频繁出现的相邻标记对,然后将标记合并以创建一个新的标记。重复此过程,直到达到预定义的迭代次数或不再可能进行合并。结果标记代表数据中的常见字符或子词组合。
让我们看看单词“lowers”,看看如何将 BPE 应用于这个单词。根据前面的段落,第一步是将单词分词成字符,因此初始标记是 l, o, w, e, r, 和 s。
接下来,如果“lo”是数据集中最频繁出现的对,那么它可能是第一次合并,结果产生以下新的标记集:lo, w, e, r, 和 s。额外的合并可能导致标记 low, e, 和 rs。最终的子词单元取决于数据集中对的出现频率和执行的合并操作数量。使用频率在 BPE 中存在一个缺点:迭代合并步骤的结果可能导致模糊的最终编码,这可能不是很有用。
作为第二个例子,考虑字符串 aaabdaaabac。由于字节对 aa 出现最频繁,我们将它替换为一个不在字符串中出现的字符,例如字母 Z。执行替换后,结果如下文本字符串:
ZabdZabac (where Z=aa)
重复替换步骤,这次使用 ab 对,并用字母 Y 替换这个对,得到字符串 ZYdZYac(其中 Y=ab,Z=aa)。在这个时候,我们可以通过选择 ZY(出现两次)并替换这个字符串为字母 X,得到 XdXac(其中 X=ZY,Y=ab,Z=aa)。
什么是 WordPiece?
WordPiece 是一种基于贪婪算法的子词分词算法,它在 2018 年 BERT 发布时变得可用,它具有 BPE(即字符配对)和单语算法(即选择要合并的配对)的特点。
具体来说,WordPiece 使用似然值而不是计数频率来合并最佳字符对,并使用计数频率来选择要配对的字符。
主要区别在于合并步骤中选择双词组的特定方式。有趣的是,基于 BERT 的 RoBERTa 也涉及了 WordPiece 的使用。以下是一些 BERT 中子词分词的示例:
-
toppings 被分割成 topping 和 ##s。
-
trimming 被分割成 trim、##ming 和 ##s。
-
misspelled 被分割成 mis、##spel 和 ##led。
然而,BERT 并不提供从其词元中重新构建原始单词的机制。相比之下,ELMo 为单词提供词级(而非子词级)的上下文表示,这与 BERT 不同。在本章的后面部分,你将学习到从英语句子创建 BERT 词元的代码示例。
什么是 SentencePiece?
SentencePiece 是另一种用于 NLP 的子词分词和去分词工具,它执行子词分割,并支持 BPE 和单语语言模型。
SentencePiece 提供了一种统一、数据驱动的文本分词和去分词方法。它能够处理原始文本,生成子词单元,并且对语言无感知,这使得它成为基于神经网络的文本处理任务的流行选择,尤其是在涉及多种语言或需要一致处理文本数据的场景中。
SentencePiece 有两个主要特性。首先,SentencePiece 将文本字符串视为 Unicode 字符序列,并用下划线字符替换空格。此外,SentencePiece 可以处理单词之间空格可选的语言(如中文和日语)。
第二,SentencePiece 支持 可逆分词,这意味着可以通过连接单词并将所有“_”字符替换为空格来重新构建原始文本。相比之下,BERT 并不支持可逆分词,因为 BERT 分词器会移除多个空格。
第三,传统的分词器通常是为特定语言设计的,当应用于其他语言时,其性能可能会下降。相比之下,SentencePiece 提供了与语言无关的一致分词方法,这使得它适用于多语言模型或对 NLP 支持较少的语言。
第四,SentencePiece 封装了标记化和反标记化,为文本处理提供端到端的工作流程,简化了开发人员的管道。
第五,SentencePiece 可以有效地处理罕见词汇和词汇表外的术语,将它们表示为已知子词标记的组合。这种能力对于模型在未见数据上良好泛化至关重要。
对于更多见解,描述 SentencePiece 的原始 arxiv 论文在arxiv.org/abs/1808.06226v1。
HUGGING FACE TOKENIZERS AND MODELS
Hugging Face 提供了许多 tokenizer 和模型的类。特别是,以 Auto 为前缀的 Hugging Face 类(例如,AutoModel 和 AutoTokenizer)执行各种任务,如通过 from_pretrained()方法以字符串形式包含的模型访问配置和预训练权重。
例如,以下代码片段初始化变量 tokenizer 为 AutoTokenizer 类的实例,并从 bert-base-uncased 模型中:
tokenizer = AutoTokenizer.from_pretrained
("bert-base-uncased")
以下代码片段初始化变量 model 为 bert-base-uncased 模型的实例:
mymodel = TFAutoModel.from_pretrained
("bert-base-uncased")
为了您的方便,以下列表包含本书 Python 代码示例中引用的 tokenizer 集,以导入语句的形式显示:
• from transformers import AutoTokenizer
• from transformers import BartTokenizer
• from transformers import BertTokenizer
• from transformers import BertTokenizerFast
• from transformers import FlaubertTokenizer
• from transformers import GPT2Tokenizer
• from transformers import RobertaTokenizer
• # dall_e_tok tokenizers:
• from dall_e_tok import DALLETokenizer
• from dall_e_tok import DallEEncoder
• from dalle_pytorch.simple_tokenizer import
tokenizer, HugTokenizer
• # pytorch tokenizers:
• from pytorch_transformers import GPT2Tokenizer,
GPT2LMHeadModel
• # BPE tokenizer:
• from tokenizers import ByteLevelBPETokenizer
以下列表包含本书 Python 代码示例中引用的与模型相关的类集,以导入语句的形式显示:
• from transformers import AutoModel
• from transformers import AutoModelForSeq2SeqLM
• from transformers import
AutoModelForSequenceClassification
• from transformers import
BartForConditionalGeneration
• from transformers import
BertForQuestionAnswering
• from transformers import
BertForSequenceClassification
• from transformers import BertModel
• from transformers import FlaubertModel
• from transformers import GPT2LMHeadModel
• from transformers import TFAutoModel
• from transformers import
TFAutoModelForSequenceClassification
最后,以下列表包含本书 Python 代码示例中引用的与配置相关的类集,以导入语句的形式显示:
• from transformers import BertConfig
• from transformers import RobertaConfig
以下小节讨论了如何保存和加载 tokenizer,以及如何通过 Hugging Face transformer 对字符串进行标记化。
加载和保存 Tokenizer
加载和保存 tokenizer 的任务与模型对应的任务一样简单,并且基于相同的方法:from_pretrained()和 save_pretrained()。这些方法将加载或保存 tokenizer 使用的算法(有点像模型的架构)以及其词汇表(有点像模型的权重)。
我们需要在加载模型时加载 BERT tokenizer,该 tokenizer 与 BERT 使用相同的检查点进行训练,但我们使用 BertTokenizer 类:
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained
("bert-base-cased")
与 AutoModel 类似,AutoTokenizer 类根据检查点名称从库中获取适当的 tokenizer 类,并且可以直接与任何检查点一起使用:
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained
("bert-base-cased")
我们现在可以使用 tokenizer,如前一小节所示:
tokenizer("Using a Transformer network is simple")
{'input_ids': [101, 7993, 170, 11303, 1200, 2443,
1110, 3014, 102],
'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}
保存 tokenizer 与保存模型相同:
tokenizer.save_pretrained("directoryname")
AutoTokenizer, BERTTokenizer, 和 GPT2Tokenizer
尽管 BERT 和 GPT 分别在第五章至第八章中进行了讨论,但这里介绍了 BERT 和 GPT2 的 tokenizer 类:
AutoTokenizer
BERTTokenizer
GPT2Tokenizer
例如,考虑以下用于实例化基于 BERT 的 tokenizer 的代码片段:
tokenizer = transformers.BertTokenizer.from_
pretrained('bert-base-uncased', do_lower_case=True)
tokenizer = AutoTokenizer.from_pretrained
("bert-base-uncased")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
在前三个代码片段中,您可以通过提供给 from_pretrained() 方法的预训练模型名称推断出所需的架构。按照惯例,“uncased”片段表示模型中的所有单词都是小写形式。
什么是 AutoClass?
带有前缀 AutoClass 的类会自动检索给定的名称/路径对应的预训练权重/config/词汇表的相关模型。此外,实例化 AutoModel、AutoConfig 或 AutoTokenizer 会创建相关架构的类。例如,以下代码片段创建了一个 BertModel 的实例:
model = AutoModel.from_pretrained('bert-base-
cased')
因此,如果 from_pretrained() 方法中指定的字符串是 BERT 检查点(例如 bert-base-uncased),则以下代码片段具有相同的效果:
AutoTokenizer.from_pretrained("bert-base-uncased")
BertTokenizer.from_pretrained("bert-base-uncased")
Auto* 类还允许您指定任何检查点,并且将加载正确的模型,以下是一个示例:
# this returns the correct GPT2Tokenizer instance:
AutoTokenizer.from_pretrained("gpt2")
# this will fail (model mismatch):
BertTokenizer.from_pretrained("gpt2")
HUGGING FACE 标记化器
本节描述了使用以下标记化器通过 Hugging Face 训练的结果:
• 慢速与快速标记化器
• BPE(基于频率的模型)
• WordPiece
• 单词标记化器(基于概率的模型)
我们还将比较通过 Hugging Face 生成的标记与最先进的(SOTA)标记化算法。
这些算法之间的主要区别在于合并字符对的选择以及这些算法用于生成最终标记的合并策略。
慢速和快速标记化器
慢速标记化器和快速标记化器之间存在差异。慢速标记化器是用 Python 编写的,位于 Hugging Face Transformers 库中。相比之下,快速版本位于 Hugging Face Tokenizers 中,是用 Rust 编程语言编写的。
此外,请注意以下关于慢速和快速标记化器的观点:当并行处理大量文本时,标记化速度的差异最为明显。实际上,在处理少量文本时,慢速标记化器可能比快速标记化器更快。
快速标记化器支持两个其他重要功能:并行化和 偏移映射,这指的是记录标记的索引位置。后者功能支持将单词映射到其生成的标记,以及将文本字符映射到它们嵌入的标记中。
标记分类管道
列表 2.4 展示了 tokens_classify1.py 的内容,展示了如何执行标记分类。
列表 2.4: tokens_classify1.py
from transformers import pipeline
sentence = "I Love Chicago Deep Dish Pizza"
token_classifier = pipeline("token-classification")
tokens = token_classifier(sentence)
print("sentence:",sentence)
print()
print("tokens: ",tokens)
列表 2.4 以一个导入语句开始,并初始化变量 sequence 为一个文本字符串。然后,变量 token_classifier 被初始化为管道类的实例,同时指定标记分类为任务类型。然后,变量 tokens 被初始化为调用 token_classifier() 方法并使用变量 sentence 的结果。
列表 2.4 的最后部分显示了变量 sentence 以及变量 tokens 的内容。运行 列表 2.4 中的代码,你会看到以下输出:
sentence: I Love Chicago Deep Dish Pizza
tokens: [{'entity': 'I-MISC', 'score':
0.59600025, 'index': 1, 'word': 'I', 'start': 0,
'end': 1}, {'entity': 'I-MISC', 'score': 0.500077,
'index': 2, 'word': 'Love', 'start': 2, 'end':
6}, {'entity': 'I-ORG', 'score': 0.8103038,
'index': 3, 'word': 'Chicago', 'start': 7, 'end':
14}, {'entity': 'I-ORG', 'score': 0.56864274,
'index': 4, 'word': 'Deep', 'start': 15, 'end':
19}, {'entity': 'I-ORG', 'score': 0.71021026,
'index': 5, 'word': 'Di', 'start': 20, 'end': 22},
{'entity': 'I-ORG', 'score': 0.771432, 'index': 6,
'word': '##sh', 'start': 22, 'end': 24}, {'entity':
'I-ORG', 'score': 0.8432511, 'index': 7, 'word':
'Pizza', 'start': 25, 'end': 30}]
前面的输出已经使用较小的字体重新对齐,以便你可以轻松检查实体类型以及与标记相关联的各种值:
[
{'entity': 'I-MISC','score': 0.59600025,'index':
1,'word':'I', 'start': 0, 'end': 1},
{'entity': 'I-MISC','score': 0.500077, 'index':
2,'word':'Love', 'start': 2, 'end': 6},
{'entity': 'I-ORG', 'score': 0.8103038, 'index':
3,'word':'Chicago','start':7,'end': 14},
{'entity': 'I-ORG', 'score': 0.56864274,'index':
4,'word':'Deep','start': 15, 'end': 19},
{'entity': 'I-ORG', 'score': 0.71021026,'index':
5,'word':'Di', 'start': 20, 'end': 22},
{'entity': 'I-ORG', 'score': 0.771432, 'index':
6,'word':'##sh', 'start':22, 'end': 24},
{'entity': 'I-ORG', 'score': 0.8432511, 'index':
7,'word':'Pizza','start':25, 'end': 30}
]
使用 Python 3.7 运行 列表 2.4 中的代码。如果你使用 Python 3.9 运行代码,你会看到以下错误消息,显示所有可用的任务:
KeyError: "Unknown task token-classification,
available tasks are ['feature-extraction',
'sentiment-analysis', 'ner', 'question-
answering', 'table-question-answering', 'fill-
mask', 'summarization', 'translation', 'text2text-
generation', 'text-generation', 'zero-shot-
classification', 'conversational', 'translation_XX_
to_YY']"
DISTILBERT 模型的分词
当你为各种基于 BERT 的模型编写 Python 代码时,确保你结合属于同一模型的分词器和模型。例如,如果你从 BertTokenizer 类引用分词器,你也需要实例化一个基于 BERT 的模型而不是 DistilBERT 模型。虽然后者很明显,但如果你混合它们,你不会看到错误消息;相反,你会看到关于“意外的分词”的警告消息。
列表 2.5 展示了 distilbert_tokenizer1.py 的内容,展示了当你“混合”分词器和模型时会发生什么。
列表 2.5: distilbert_tokenizer1.py
# notice the mismatch in this code snippet:
from transformers import DistilBertTokenizer,
BertModel
tokenizer = DistilBertTokenizer.from_pretrained
('bert-base-uncased')
print("tokenizer size: ",tokenizer.vocab_size)
print("model max length: ",tokenizer.model_max_
length)
print("model input names:",tokenizer.model_input_
names)
print()
text1 = "Pizza with four toppings and trimmings."
marked_text1 = "[CLS] " + text1 + " [SEP]"
tokenized_text1 = tokenizer.tokenize(marked_text1)
print("input sentence #1:")
print(text1)
print()
print("Tokens from input sentence #1:")
print(tokenized_text1)
print()
print("Some tokens in BERT:")
print(list(tokenizer.vocab.keys())[1000:1020])
print()
列表 2.5 以一个导入语句开始,然后初始化变量 tokenizer 为与数据集 bert-base-uncased 相关联的 tokenizer 的实例,该数据集由所有小写字母组成,没有重音符号。这个变量使我们能够显示模型的长度以及模型的输入名称。
列表 2.5 的下一部分初始化了字符串变量 text1,然后变量 marked_text1 有一个初始和终端的特殊标记。变量 tokenized_text1 使用对字符串 marked_text1 中的文本进行分词的结果进行初始化。
接下来,显示了变量 text1 和 tokenized_text1 的内容,然后是一个现有标记的列表。运行 列表 2.5 中的代码,你会看到以下输出。注意,以粗体显示的最大长度值是不正确的,以及调味品和装饰品的子词分词:
tokenizer size: 30522
model max length: 1000000000000000019884624838656
model input names: ['input_ids', 'attention_mask']
input sentence #1:
Pizza with four toppings and trimmings.
Tokens from input sentence #1:
['[CLS]', 'pizza', 'with', 'four', 'topping',
'##s', 'and', 'trim', '##ming', '##s', '.',
'[SEP]']
Some tokens in BERT:
['"', '#', '$', '%', '&', "'", '(', ')', '*', '+',
',', '-', '.', '/', '0', '1', '2', '3', '4', '5']
此外,你还会看到以下警告信息:
The tokenizer class you load from this checkpoint
is not the same type as the class this function
is called from. It may result in unexpected tokenization.
The tokenizer class you load from this checkpoint
is 'BertTokenizer'.
The class this function is called from is
'DistilBertTokenizer'.
注意,警告信息并没有说错误一定会发生;然而,如果你看到任何异常或意外的结果,你需要检查你的代码。
列表 2.6 展示了 distilbert_tokenizer2.py 的内容,展示了如何纠正 列表 2.5 中的不匹配的类和模型。
列表 2.6: distilbert_tokenizer2.py
# notice the corrections in this code sample
from transformers import DistilBertTokenizer,
DistilBertModel
tokenizer = DistilBertTokenizer.from_pretrained
('distilbert-base-uncased')
print("tokenizer size: ",tokenizer.vocab_size)
print("model max length: ",tokenizer.model_max_
length)
print("model input names:",tokenizer.model_input_
names)
print()
text1 = "Pizza with four toppings and trimmings."
marked_text1 = "[CLS] " + text1 + " [SEP]"
tokenized_text1 = tokenizer.tokenize(marked_text1)
print("input sentence #1:")
print(text1)
print()
print("Tokens from input sentence #1:")
print(tokenized_text1)
print()
print("Some tokens in BERT:")
print(list(tokenizer.vocab.keys())[1000:1020])
print()
列表 2.6 几乎与 列表 2.5 完全相同;唯一的不同之处在于显示在粗体中的前两行。运行 列表 2.6 中的代码,你将看到几乎与 列表 2.5 相同的输出,但这次具有正确的最大长度值,并且没有警告信息。
tokenizer size: 30522
model max length: 512
model input names: ['input_ids', 'attention_mask']
input sentence #1:
Pizza with four toppings and trimmings.
Tokens from input sentence #1:
['[CLS]', 'pizza', 'with', 'four', 'topping',
'##s', 'and', 'trim', '##ming', '##s', '.',
'[SEP]']
Some tokens in BERT:
['"', '#', '$', '%', '&', "'", '(', ')', '*', '+',
',', '-', '.', '/', '0', '1', '2', '3', '4', '5']
LLM 中的分词选择技术
LLM 和神经网络有几种参数类型。例如,神经网络中的 参数 是连接两个不同层中神经元的边。这些参数被分配了在 LLM 或神经网络的训练步骤中更新的数值权重。请参阅以下文章获取更多信息:
第二,LLM 和神经网络通常有一些超参数,其值在 LLM 或神经网络的训练步骤之前设置,即预先。
第三,许多 LLM,如 GPT-x 模型和其他基于解码器的 LLM,提供可调整的推理参数,这些参数会影响模型的输出,其中一些如下:
• 最大新标记数
• 标记长度
• 停止标记
• 样本顶级 K
• 样本顶级 P
• 温度
由于在了解微调 LLM 之后,推理参数将更有意义,因此对前面列出的推理参数的讨论被推迟到 第五章。
总结
本章从介绍预分词的概念开始,以及预分词和分词之间的区别,以及一个 Python 代码示例。然后你了解了分词器的一些细微差别以及通用的词到索引映射算法。
此外,你还了解了单词、字符和子词分词器。然后你了解了基于单词的分词器的局限性以及具有多个字母表的语言(如日语)以及基于字符的分词器的局限性。
此外,你还了解了 BPE、WordPiece 和 SentencePiece 等子词分词算法。你被介绍了 Hugging Face 分词器以及慢速和快速分词器的区别。然后你了解了分词选择技术。
本章提供了基础知识,以帮助你学习下一章将要讨论的 Transformer 架构。
第三章
Transformer 架构 简介
本章是两章讨论 Transformer 架构的第一章,它是众多语言模型(如 BERT 及其变体,第五章和第六章讨论)以及 OpenAI 的 GPT-x 家族(第七章和第八章讨论)的基础。
本章描述了原始转换器的主要组件,以及用于各种 NLP 任务的基于 Python 的转换器代码示例,如 NER、QnA 和掩码填充任务。
本章的第一部分介绍了由谷歌开发并于 2017 年底发布的转换器架构。本节还讨论了一些基于转换器的模型。
本章的第二部分讨论了来自 Hugging Face 的转换器库,这是一家提供超过 20,000 个基于转换器模型的存储库的公司。本节还包含基于 Python 的转换器代码示例,这些代码示例执行各种 NLP 任务,如命名实体识别(NER)、问答(QnA)和掩码填充任务。
本章的第三部分提供了有关编码器组件的更多详细信息,以及关于注意力机制和另一个主要组件解码器的额外详细信息。
在你阅读这一章之前,请记住,有些“前瞻性引用”的概念在后面的章节中讨论过,这些概念为某个概念提供了上下文。当然,如果你对后面章节中讨论的概念不熟悉,那么理解讨论的主题也会很具挑战性。因此,你可能需要多次阅读一些主题,之后当你理解了当前上下文以及后面章节中引用材料的上下文时,概念就会更容易掌握(幸运的是,这个阅读过程是有限的)。
以下文章在探讨是否有可能超越人工智能之前,首先考察了转换器:
www.quantamagazine.org/will-transformers-take-over-artificial-intelligence-20220310
序列到序列模型
“seq2seq”和“编码器-解码器”这两个术语密切相关,在序列到序列任务的神经网络架构中经常互换使用。因此,你会发现一些在线文章同时使用这两个术语,有时它们之间没有做出区分。
简而言之,序列到序列模型(也称为 Seq2Seq 或 seq2seq)处理一个输入序列并输出一个(可能是不同类型的)序列。在转换器架构的情况下,训练编码器和解码器的过程共同创建了一个序列到序列模型。
如果你学习过外语,那么你无疑知道,很少有一个句子在翻译成另一种语言时是逐字逐句的。此外,有时一种语言中的多个单词序列可以有一个单词的翻译(反之亦然)。因此,源语言中句子的长度在目标语言中可能会有不同的长度。
因此,在 2014 年,理查德·苏茨克维尔(和其他人)开发了一种序列到序列或 Seq2Seq 架构,其主要组件是一个编码器和解码器。这个 seq2seq 架构依赖于两个多层 LSTM:一个 LSTM 将输入序列映射到一个固定大小的向量(上下文向量),第二个 LSTM 将固定大小的向量解码为在目标语言中的序列(一次一个单词)。这种方法证明足够成功,以至于在 2016 年,谷歌翻译切换到了 seq2seq 模型。
seq2seq 模型已经推广,它可以由多个 LSTM 组成,也允许有门控循环单元(GRU)组件。然而,由编码器组件和解码器组件组成的根本结构仍然保持不变。再次值得一提的是,编码器组件总结信息并生成一个固定长度的向量,解码器组件使用这个向量来生成目标语言中的句子。
注意,seq2seq 模型可以用于语音、视频、文本、机器翻译和问答。此外,seq2seq 模型非常适合文本生成:它们可以处理一种类型的序列作为输入,然后生成另一种类型的序列作为输出。
如果只训练一个组件(即编码器或解码器),结果分别是自动编码模型或自回归模型,分别(关于这两个的更多细节将在稍后提供)。此外,输入序列的长度可以与输出序列的长度不同。
seq2seq 模型类型
存在几种 seq2seq 架构类型,其中一些在此列出:
• 基于 RNN 的 seq2seq
• 基于 LSTM 的 seq2seq
• 基于注意力的 seq2seq
回想一下,RNN 依赖于 tanh()激活函数来处理输入序列,以及将步骤 t 的输入与步骤(t-1)的输出结合,以生成一个输出,该输出用作步骤(t+1)的输入。
LSTM 细胞是一种特殊的 RNN 类型,具有以下特点:
• sigmoid()和 tanh()激活函数
• 一个遗忘门、一个输入门和一个输出门
• 一个通过前一个门更新的长期细胞状态
注意,DNNs(深度神经网络)不在前面的项目符号列表中:这是因为 DNNs 不能用于将序列映射到序列。
你可能会看到 seq2seq 被描述为一种特定的 RNN 类型,通常通过编码器-解码器架构实现。正如你稍后将会看到的,转换器架构是一种基于 RNN 的编码器-解码器架构,它最初是基于 RNN 的。然而,转换器架构已经摒弃了 RNN,并依赖于注意力机制(稍后讨论)。
换句话说,seq2seq 架构和编码器-解码器架构都涉及输入序列和输出序列。区别在于早期的 seq2seq 架构依赖于 RNN,而较新的编码器-解码器架构更倾向于使用注意力机制而不是 RNN。
原始的 Transformer 是一个包含编码器组件和解码器组件的 seq2seq 模型。编码器组件包含 N 层,每一层将输入数据编码成一个 1x512 的向量。尽管解码器也包含 N 个解码器层,但解码器并非简单地是编码器的镜像。实际上,解码器组件中的每个解码器块都处理来自以下来源的输入数据:
• 整个编码器组件的输出
• 前一个解码器块的输出
序列到序列预测问题
序列预测通常涉及以下两种情况之一:1) 预测实值序列中的下一个值或 2) 为输入序列输出一个类别标签。因此,存在几种类型的序列预测:
• 单个输入时间步到单个输出时间步(一对一)
• 多个输入时间步到单个输出时间步(多对一)
• 输入一个序列,输出一个序列预测
这些被称为序列到序列预测问题,或简称 seq2seq。请注意,输入和输出序列的长度可能不同。事实上,当存在多个输入时间步和多个输出时间步时,这被称为 多对多类型序列预测问题。不幸的是,seq2seq 模型可能在各种基准测试中样本效率低下且表现不佳。
SEQ2SEQ 模型的示例
Sequence-to-Sequence (seq2seq) 模型在自然语言处理 (NLP) 和其他领域的多种应用中得到了利用。以下是一些利用 seq2seq 模式进行任务和特定模型实现的示例。
机器翻译
示例:Google 的神经机器翻译 (GNMT) 系统
GNMT 是 Google Translate 使用的 seq2seq 模型。它使用多层 LSTM 进行编码和解码。该模型还集成了注意力机制,在生成目标句子时专注于源句子的相关部分。
文本摘要
示例:指针生成网络
对于抽象文本摘要,其中摘要不仅仅是提取,还可以是新的文本。指针生成网络结合了提取式和抽象式摘要的优点。它可以通过指针复制源文本中的单词,也可以生成新单词。
对话代理(聊天机器人)
示例:OpenAI 的 GPT-2 的初始版本用于对话生成。
通过在对话数据集上进行训练,seq2seq 模型可以用来生成对话响应。
图像标题生成
示例:Show and Tell 模型
此模型使用卷积神经网络(CNN)作为编码器来处理图像,并使用 RNN 作为解码器来生成描述性字幕。虽然这里的编码器不是处理序列,但解码器是生成序列,因此该模型仍然遵循 seq2seq 范式。
语音识别
示例:听、注意和拼写(LAS)
LAS 使用 seq2seq 模型将口语转换为文本。编码器处理音频帧,解码器(带有注意力机制)生成相应的文本转录。
视频字幕
示例:视频到文本模型
与图像字幕类似,但编码器处理一系列帧(视频),为每个帧或片段生成文本描述或字幕。
分子设计
示例:药物发现模型
Seq2seq 模型可用于在不同分子表示之间进行翻译或预测分子属性,从而帮助药物发现和设计。
时间序列预测
示例:股票价格预测
使用过去的股票价格(价格序列)来预测未来的价格。
程序翻译
示例:代码翻译模型
将代码从一种编程语言翻译到另一种语言。
音乐生成
示例:旋律生成模型
给定一系列音符,生成后续或和声序列。
上述示例展示了 seq2seq 架构的通用性,使其成为机器学习和人工智能许多领域的基石工具。
关于 RNN 和 LSTMs 有什么看法?
RNN 的输入具有相同的长度:较短的句子通过在左侧或右侧填充(填充内容可以是任何字符)来达到指定的长度,如果句子长度超过指定长度,则进行截断。
然而,编码器/解码器模型在将编码传递给解码器进行处理之前会生成输入的编码。因此,输入句子的长度没有限制:编码器/解码器模型可以处理不同长度和可变长度的输入句子,并且也可以生成不同长度的输出句子。
编码器-解码器 LSTM 架构由两个模型组成:一个模型读取输入序列并将其编码为固定长度的向量,然后是第二个模型,它解码固定长度的向量并输出预测的序列。编码器-解码器 LSTM 是为了解决 NLP 问题而开发的,它在文本翻译方面取得了 SOTA 性能。
以类似的方式,RNN 编码器-解码器架构由两个 RNN 组成,其中编码器将可变长度的源序列映射到固定长度的向量,解码器将向量表示映射回可变长度的输出序列。
LSTMs 及其最终层
基于 LSTM 的模型由多个 LSTM 单元组成,其中一个 LSTM 单元的输出被视为“上下文向量”,成为下一个 LSTM 单元的输入。然而,LSTM 中间隐藏单元的输出被丢弃:在给定的 LSTM 中,只有最终单元(即“单元状态”)的输出传递给下一个 LSTM。
为什么 LSTM 会丢弃那些其他中间输出?一个可能的原因是,最终单元状态包含了从处理每个先前隐藏层累积的信息,因此最终单元状态的内容实际上是所有先前单元的超集。换句话说,所有内容都被“卷”到了最右侧的最终层,因此先前的中间层不提供任何额外信息。尽管前面的逻辑似乎是合理的,但它实际上并不正确,正如考虑了所有隐藏层输出的注意力机制所清楚地展示的那样。
在 LSTM 中的处理是顺序的,不能并行执行,因为相邻隐藏层之间存在依赖关系。相比之下,注意力机制可以并行化,因为计算了句子中每个词与句子中每个词之间的相似性,因此没有顺序依赖关系。
LSTM 中的隐藏状态与 Transformer 架构
对于 RNN 和 LSTM,每个 RNN 和 LSTM 层都会产生一个隐藏状态作为输出。此外,只有最终(即最右侧)的隐藏状态传递到序列组件中的下一个组件(无论是 RNN 还是 LSTM)。
前面的技术忽略了 RNN 或 LSTM 中除了最后一层之外的所有层的输出。虽然你可能认为这种技术忽略了重要的信息,但考虑到以下原因,它可能被认为是一个合理的设计决策:每个组件的最后一层将先前层的信息“卷”到了最终层。不管怎样,结果证明所有隐藏状态的输出是有用的,捕获这些输出是实现注意力机制的关键方面。
顺便提一下,你可能会惊讶地发现,TensorFlow 1.x 的早期版本支持注意力机制,这早于 Transformer 架构的流行。然而,当人们意识到这种支持时,Transformer 架构中的 RNN 和 LSTM 组件已不再被认为是必要的。
编码器/解码器模型
编码器-解码器模型是为了解决 seq2seq 任务而设计的。这些模型是其他模型和架构(如注意力模型、Transformer、BERT 和 GPT 模型)的基础。有趣的是,BERT 是一个仅编码器架构:更多细节请参阅第五章。
编码器-解码器框架是一种用于序列到序列任务的神经网络设计范式,其中输入是一个序列,输出是另一个序列。这个架构包含两个主要组件:编码器和解码器。
编码器处理输入序列并将信息压缩成一个固定大小的上下文向量,通常被称为“隐藏状态”或“上下文”。在许多模型中,这个上下文代表了编码器的最后一个隐藏状态。通常,RNN 或其变体如 LSTM 和 GRU 用于此目的。解码器接收编码器产生的上下文向量并从中生成输出序列。它通常也是一个 RNN、LSTM 或 GRU,它逐步生成输出序列,通常基于前一步的输出和编码器的上下文。
注意力机制通常被集成到解码器中,以便它在输出生成的每个步骤中关注输入序列的不同部分,从而提高性能,尤其是在处理较长的序列时。
seq2seq 与编码器/解码器之间的关系
seq2seq 模型本质上是对编码器-解码器架构的一种实现。seq2seq 框架建立在编码器-解码器范式之上,其中编码器处理源序列,解码器生成目标序列。
当人们提到 seq2seq 模型时,他们通常在讨论使用编码器处理源序列和解码器生成目标序列的模型。当使用“seq2seq”这个术语时,通常指的是遵循这种编码器-解码器结构的模型。
以下陈述概括了 seq2seq 模型与编码器/解码器模型之间的关系:所有 seq2seq 模型都是编码器-解码器模型,但并非所有编码器-解码器模型都必然用于 seq2seq 任务(尽管大多数都是)。
尽管所有序列到序列(seq2seq)模型都是基于编码器-解码器架构构建的,但编码器-解码器框架也可以用于不是严格意义上的序列到序列的任务。例如,图像描述使用图像作为输入(由 CNN 编码)和一系列单词作为输出(由 RNN 或 LSTM 生成),符合编码器-解码器模式,但不是典型的序列到序列范式,其中输入和输出都是序列。
编码器/解码器模型的示例
编码器-解码器架构是许多模型的基础概念,尤其是在序列到序列任务中。以下是一些利用编码器-解码器框架的任务和具体实现的示例。
机器翻译
示例:带有注意力的序列到序列
这是一系列神经机器翻译的先驱模型之一。编码器处理源语言,解码器生成目标语言。注意力机制允许解码器在翻译过程中关注源句的不同部分。
图像描述
示例:展示并讲述
编码器,通常是 CNN,处理图像。解码器,通常是 RNN 或 LSTM,生成字幕。注意力机制允许解码器在生成字幕时关注图像的不同区域。
语音识别
示例:百度的 DeepSpeech 2
编码器处理音频信号,解码器产生相应的文本转录。
文本摘要
示例:抽象摘要模型
编码器处理原始长文本,解码器生成简洁的摘要。许多这些模型也集成了注意力机制。
视频字幕
示例:序列到序列视频到文本
编码器处理视频帧序列,解码器为每个帧或片段生成描述或字幕。
使用序列到序列的命名实体识别(NER)
示例:将命名实体识别(NER)视为序列到序列任务的模型
编码器处理一系列单词,解码器生成一系列实体标签。
图像到图像翻译
示例:Pix2Pix
此模型使用编码器-解码器架构执行诸如将卫星图像转换为地图或将黑白照片转换为彩色等任务。
音乐翻译
示例:将一种乐器的声音翻译成另一种的模型
时间序列中的异常检测
示例:基于自动编码器的异常检测模型
编码器处理一系列数据点以创建压缩表示,解码器重构序列。大的重构误差可以指示异常。
图像中的语义分割
示例:U-Net 架构
用于生物医学图像分割,编码器捕捉图像中的上下文,解码器随后使用这个上下文来生成高分辨率的分割图。
上述示例突出了编码器-解码器架构在机器学习和人工智能各个领域的灵活性和广泛应用。编码器-解码器架构是一个基础概念,是许多模型的基础,尤其是在序列到序列任务中。在接下来的章节中,有一些利用编码器-解码器框架的任务和具体实现的例子。
自回归模型
基于变换器架构的自回归模型是仅解码器架构。自回归模型利用之前的预测来生成新的预测。因此,训练它们涉及一个语言建模任务:模型必须学习一种语言以及词语和短语之间的相互依赖关系,包括语义。自回归模型根据前一时间步的结果预测序列中下一个时间步的值。
自回归模型在预训练时有一个重要的约束:它们只能看到当前标记之前的标记,并且被阻止看到后续的标记。这种机制“迫使”自回归模型在没有实际检查下一个标记的情况下预测下一个标记。这个约束是通过将注意力矩阵上三角部分的值设置为 0 来实现的。
自回归(AR)LLMs 非常适合生成式 NLP 任务。尽管 AR LLMs 可以使用正向上下文或反向上下文,但它们不能同时使用正向和反向上下文。
正如你在第六章中将会看到的,自回归模型 XLNet 在预训练阶段使用置换语言建模,这使得 XLNet 能够从序列中每个标记的两侧收集信息。然而,这种模型有两个重要的限制。
第一个限制与给定时间步的词预测有关:自回归模型依赖于当前词之前和之后的词。第二个限制是预测的词的准确性取决于预测序列中先前词的准确性。
自回归 Transformer
“正常”的 transformer 解码器在推理时是自回归的,在训练时是非自回归的。因此,transformer 模型是自回归的,因为它的解码器是自回归的。
然而,transformer 的非自回归变体确实存在:它们更多的是研究课题而不是现成的解决方案。有关此类变体的更多信息可在openreview.net/forum?id=B1l8BtlCb找到。
如何加速自回归 Transformer
在以下文章中,作者声称他们可以使基于自回归的 transformer 模型比 Hugging Face 上的相应模型快两倍:
www.reddit.com/r/MachineLearning/comments/uwkpmt/p_what_we_learned_by_making_t5large_2x_faster
作者描述了三种技术,这些技术将 T5 模型的性能翻倍:
-
在单个 Onnx 文件中存储 2 个计算图
-
使用 Onnx Runtime 检索输出时执行零拷贝
-
一个通用的工具,可以将任何模型(无论其架构如何)转换为 FP16
请记住以下评论和建议,这些是从前面的 reddit 文章中改写的:
-
双图技术仅适用于自回归模型。
-
fp16 技术在 BERT-like 模型上没有用。
-
在 BERT-like 模型上使用 tensorrt 并应用 int8 量化,这可以在中等长度的序列和非常短的序列上分别实现 5 倍到 10 倍的性能提升。
回想一下,T5 基于 transformer 架构的编码器和解码器组件,这意味着 T5 也是一个自回归模型。
作者还提供了一个笔记本(仅适用于 Onnx Runtime):
github.com/ELS-RD/transformer-deploy/blob/main/demo/generative-model/t5.ipynb
存放前面笔记本的 GitHub 仓库:
github.com/ELS-RD/transformer-deploy
以下网站提供了一个 nbviewer 链接到相同的笔记本:
如果你想在笔记本中执行代码,以下 binder 链接将启动一个 Jupyter 服务器:
mybinder.org/v2/gh/ELS-RD/transformer-deploy/main?filepath=demo%2Fgenerative-model%2Ft5.ipynb
自动编码模型
自回归模型(在本章前面讨论过)在目标是为了执行自然语言生成(NLG)时非常好。然而,自然语言理解(NLU)任务并不适合自回归模型,也不适合 seq2seq 模型;后者适合语言翻译。对于 NLU,更好的选择是自动编码模型。
自动编码器学习一组数据的一个表示(即编码),通常是为了降维,使得输入层和最终层相同。简单来说,自动编码模型通过以某种方式损坏输入标记并尝试重建原始句子来进行预训练。例如,BERT 模型通过将子集的标记替换为一个特殊标记“token”来“损坏”输入序列。
在一定程度上,自动编码模型试图克服自回归模型的局限性。自动编码模型基于原始的 transformer,并检查句子中标记的双向依赖关系以获得双向上下文。
自动编码模型的局限性源于在预训练步骤中执行的 MLM 步骤。由于 MLM 试图在 MLM 过程中预测一个被掩码的标记,当多个被掩码的标记在预测步骤中相互依赖时,就会出现局限性。
对于处理固定长度序列且具有最大允许长度(BERT 为 512)的模型(如 BERT),会出现第二个限制。请注意,MLM 任务和 BERT 模型在第六章(Chapter 6)中进行了讨论。
自动编码器
自动编码器是一种全连接的简单神经网络,它是一种编码器-解码器模型,其中输入层和输出层相同,通常在输入层和输出层之间有一个隐藏层,该隐藏层比输入层和输出层小。隐藏层的作用是进行降维:模型训练完成后,隐藏层的内容被保留用于其他下游任务(如问答),而输入层和输出层被丢弃。
自动编码器是一种主要用于无监督学习任务的神经网络,特别是降维和特征学习。自动编码器由两个主要部分组成:编码器和解码器。编码器将输入压缩成潜在空间表示,解码器则从这种表示中重建输入数据。自动编码器的主要目标是最小化原始输入与其重建之间的差异,从而在学习过程中学习数据的紧凑和高效表示。
这种架构的变体包含额外的隐藏层,其中一些比输入层和输出层更深。通过在线搜索“image-autoencoders”,你会找到许多有趣的自动编码器类型。
自动编码器转换器
自动编码器转换器是一种结合了自动编码器的无监督学习能力和转换器的强大序列处理能力的神经网络。它旨在使用转换器机制将输入序列编码成潜在表示,然后将其解码回原始形式,目的是最小化重建误差。这种架构可以学习序列数据的紧凑和有意义的表示,使其在自然语言处理等多个任务中非常有用。
自动编码器转换器结合了自动编码器和转换器的原理。它使用转换器架构将输入数据编码成潜在表示,然后将其解码回原始形式。自动编码器转换器可用于各种任务,例如
• 表示学习:学习输入数据的有效表示
• 去噪:从噪声输入中重建干净数据
• 异常检测:大的重建误差可以指示数据中的异常或离群值
例如,BERT(来自转换器的双向编码器表示)模型可以被看作是一种自动编码器转换器。BERT 被训练来预测文本中被遮蔽的部分,从而将周围上下文编码到其嵌入中。尽管它不像传统自动编码器那样重建整个输入,但其训练原理相似,即它通过重建输入的部分来学习表示。
这里有一个重要的观点:在自回归模型和自编码模型之间进行选择取决于任务和训练,而不是架构。此外,可以使用解码器进行自编码,也可以使用编码器进行自回归任务。
Transformer 架构:简介
Transformer 架构在 2017 年首次亮相,它被设计为一个编码器-解码器架构,即 seq2seq 模型。Transformer 对语言建模产生了巨大影响,部分原因是通过其自注意力机制跟踪标记之间的关系。
Transformer 架构执行的是与其他架构根本不同的 NLP 相关任务。事实上,Transformer 架构促进了各种知名大型语言模型(LLM)的发展,例如 BERT、T5、GPT-2 和 GPT-3。
原始的 Transformer 架构
你可能会惊讶地发现,原始的 Transformer 架构最初是一个涉及 LSTMs 的 seq2seq 模型。有人发现,由于注意力机制,Transformer 架构在没有 LSTMs 的情况下表现同样出色,这进而导致了前面章节中提到的开创性论文“Attention is all you need”(www.topbots.com/leading-nlp-language-models-2020/)。
Transformer 架构的有趣发展是存在几种类型的 Transformer 架构:
• 仅编码器架构(例如基于 BERT 的模型)
• 仅解码器架构(例如 GPT-x)
• 同时包含编码器和解码器架构(例如 T5 和 BART)
因此,当你学习基于 Transformer 的 LLM 时,一个需要问的问题是 LLM 中使用了哪种类型的 Transformer 架构。包括编码器和解码器的模型示例有 seq2seq 模型、BART 和可以微调以执行许多任务的 T5 模型(谷歌)。
词语 编码器 是多义的:编码器可以指整个编码器组件,也可以指整个编码器组件内部的 6(或 12)个编码器之一(对解码器也适用类似的评论)。因此,本书使用以下术语来消除编码器和解码器的歧义:
• 一个 组件 是原始 Transformer 架构中的完整编码器或解码器。
• 一个 块 包含执行注意力、前馈等操作的层。
• 一个 层 是(在块中)执行注意力、前馈等操作的元素。
基于 transformer 的架构通常具有 6 个编码器块和 6 个解码器块,分别用于编码器组件和解码器组件,或者它们有 12 个编码器块用于编码器组件和 12 个解码器块用于解码器组件(以及其他可能的值)。请记住,编码器组件中的块只是一个独立的较小编码器的同义词;同样,解码器组件中的块实际上是一个独立的较小解码器。目前,请记住,编码器组件中的每个块包含两层,而解码器组件中的一个块包含三层。
正如你将在第六章中看到的那样第六章,BERT 只使用 transformer 的编码器组件,而 GPT-2 只涉及 transformer 的解码器组件,T5 则同时使用编码器和解码器。
操作顺序
如果一个基于 transformer 的模型只包含一个组件,那么所有操作都以自底向上的方式在该组件中执行。如果一个基于 transformer 的模型包含编码器组件和解码器组件,那么操作以自底向上的方式在编码器组件中执行,之后其输出传递到解码器组件,在那里以自底向上的方式执行额外的操作。在所有处理完成后,你可以向模型添加另一个层来执行其他任务,如第六章所述第六章。
独立于 RNNs/LSTMs
有趣的是,transformer 架构的最初实现包括了 RNNs 和 LSTMs。在某个时刻,有人发现,即使没有 RNNs 或 LSTMs,也能达到相当的准确度。这一发现导致了在 transformer 架构的开创性论文中提出“Attention is all you need”这一表述。特别是,transformer 架构与其他架构在以下重要方面有所不同:
• 它依赖于注意力机制。
• 模型训练可以并行化。
• 不需要 CNN/RNN/LSTMs。
注意,编码器-解码器模型与通常包含 RNNs 或 LSTMs 的 seq2seq 模型不同。
不同于 RNNs 和 LSTMs 的独立性简化了 transformer 的架构,该架构依赖于自注意力机制,这意味着句子中的每个单词都会与句子中的其他每个单词进行比较。这种处理文档的“全局”方法比其他处理文档“局部”部分的技术表现更好。此外,transformer 架构在处理语料库中的长距离依赖关系方面也更为得力。
RNNs 在解决各种任务中很有用,包括基于 NLP 的任务。特别是,将源语言中的单词序列映射到目标语言的机器翻译系统依赖于 RNNs。实际上,翻译任务可以通过编码器-解码器架构以及 seq2seq(序列到序列)架构来处理。
转换器架构最初是为机器翻译模型设计的,因此它被构建为编码器/解码器架构。实际上,转换器架构在语言模型方面非常有效。在最初转换器架构发布后,研究人员开发了在计算效率和内存消耗方面都更高效的架构,这对于小型设备(如手机)和二值图像处理来说尤为重要。
事实上,转换器涉及的计算复杂性超出了智能手机等设备的处理能力:https://arxiv.org/abs/2201.03545。
转换器组件块
通常,我们用字母 T 来表示传递到初始嵌入层的标记数量。初始嵌入层的输出是一个 Txd 的值矩阵,其中 d 是模型的输入宽度。在转换器论文中,d 的值为 512,在其他模型中,d 可以等于 1,024 或 2,048。转换器块执行各种操作,而不改变数据的形状(即,Txd)。
这里有一个重要的观点:位置编码和编码器组件或解码器组件中的转换器块输出具有形状 Txd(T 和 d 在前一段中定义)
主要的转换器组件
如你在前一节中学到的,完整的转换器架构包括一个注意力机制(在第一章中讨论),位置编码(稍后讨论),以及用于处理序列到序列任务的编码器和解码器。注意力机制可以包括以下类型:
• 编码器中的注意力
• 解码器中的掩码注意力
• 编码器和解码器之间的注意力
第一步涉及嵌入输入,这涉及到一个矩阵(称为位置嵌入矩阵)。因此,输入由多个标记组成的向量组成。
关于基于转换器的模型,另一个有趣的细节是,其中一些仅使用编码器(BERT),一些仅使用解码器(GPT-3),还有一些同时使用编码器和解码器(T5)。这三个架构都适用于不同类型的 NLP 任务,这将在第七章中更详细地讨论。第七章。
这里总结了转换器架构的三个重要方面,其中两个将在本章后面更详细地讨论:
注意力机制(在第一章中讨论)是一种序列到序列的操作,它接受一系列向量作为输入并产生一个不同的向量序列。一些注意力计算只是所有输入向量的加权平均。
编码器组件包含六个块,每个块包含多个层,这些层又包含两个子层:第一个子层包含自注意力机制,第二个子层由前馈网络组成。
解码器组件包括六个块,每个块包含多个层,这些层又包含三个子层:其中两个子层与编码器中的对应层相同,第三个层是一个多头注意力层,用于转换编码器的输入。
注意到尽管编码器和解码器非常相似,但解码器块包含一个额外的子层,由一个多头注意力层组成。
变换器是一个编码器/解码器模型
变换器架构相较于其他架构有两个重要的优势:
• 它们更低的计算复杂度
• 它们更高的连接性,这在涉及长期依赖关系的序列中特别有利
此外,编码器和解码器被训练以最小化条件对数似然。
正如你在第四章中将会看到的,原始变换器论文(可在 arXiv 上找到)中的编码器组件有 6 个相同的层。此外,一些 LLM 包含 12 个相同的层而不是 6 个相同的层。每个层由以下元素组成:
• 多头注意力
• 加法与归一化
• 前馈网络
• 加法与归一化
当讨论编码器或解码器时,将编码器可视化为一个垂直堆叠的编码器元素,位于变换器架构图中解码器组件的左侧,解码器组件本身也是一个垂直堆叠的解码器元素。
解码器组件类似于增强的编码器组件,包括一个用于“掩码注意力”的第三层,如下所示:
• 掩码多头注意力
• 加法与归一化
• 多头注意力
• 加法与归一化
• 前馈网络
• 加法与归一化
解码器组件中的掩码多头注意力也执行掩码操作,以防止“向前看”未来的标记。解码器组件也可以由 6 个相同的层或 12 个相同的层组成,以匹配编码器组件中的元素数量。
回想一下,在 LSTM 元素序列的情况下,给定 LSTM 的最终隐藏层只传递给一个 LSTM,即序列中的下一个 LSTM。因此,一个 LSTM 的输出与序列中下一个 LSTM 的输入之间存在一对一的关系。
这其中存在一个重要的差异,即关于元素序列中从一个元素传递到下一个元素的方式。与基于 LSTM 的元素序列不同,编码组件的输出传递到解码组件中每个元素的每个掩码注意力层。
此外,这个第三个解码层不仅接受来自编码组件输出的输入,还接受来自解码组件元素垂直堆叠中的较低解码层的输入。因此,如果编码器和解码器组件各由 N 个元素组成,那么编码器的输出就传递到解码器中的 N 个元素中的每一个。从某种意义上说,编码组件到解码组件的输出是一个一对一的关系。第四章包含了有关 transformer 架构的更多信息。
变换器流程及其变体
transformer 的输入是一组标记,其最大长度通常是 512 或 1,024,相关输入向量的长度称为上下文大小。超过最大长度的句子必须被截断,如果截断部分包含重要信息,这可能会导致精度损失。
重要的是,transformer 通过多头注意力机制(稍后讨论)并行地编码这些向量。相比之下,RNNs 和 LSTMs 按顺序处理标记。
在将标记编码为一维向量并由编码组件处理之后,结果被发送到解码器以生成输出序列。请注意,解码器按顺序处理输入,而不是并行处理输入。稍后,你将了解仅使用编码器(例如,BERT)的模型,仅使用解码器(例如,GPT-3)的其他模型,以及一些同时使用编码器和解码器(例如,BART 和 T5)的模型。以下是关于 transformer 架构到目前为止所学内容的累积总结:
• 它依赖于注意力机制。
• 模型训练可以并行化。
• 不需要 CNN/RNN/LSTMs。
• 一些模型仅使用编码器(例如,BERT)。
• 一些模型仅使用解码器(例如,GPT-3)。
• 一些模型使用编码器和解码器(例如,BART 和 T5)。
• 最大输入长度为 512。
transformer 架构已被用于与 NLP 无关的其他领域的任务,例如化学、计算机视觉、图像分类和视频(等等)。请阅读以下关于 transformer 架构的文章:arxiv.org/pdf/1706.03762.pdf。
基于 transformer 的 LLMs 导致了在大规模未标记语料库上训练的预训练模型的发展。此外,可以通过向模型添加特定任务层并在相对少量标记示例的基础上进行额外训练来对这些模型进行微调,以完成专门的“下游”任务。
Transformer 架构的三个变体
上一节指出,transformer 架构涉及自注意力、编码器和解码器的组合。有趣的是,有一些模型实现了 transformer 架构的不同子集(组件)。尽管它们都提供了自注意力机制,但在以下方面有所不同:
• 仅编码器
• 仅解码器
• 编码器和解码器(原始架构)
如您在本章早期所学的,GPT 仅使用 transformer 架构的解码器组件,而 BERT 仅使用编码器组件。BART 和 T5 是两种同时使用 transformer 架构的编码器和解码器的模型。本章后面将提供关于 transformer 架构三种不同实现的更多细节。
基于 Transformer 的 NLP 模型
除了具有 transformer 架构顶级组件的不同组合外,基于 transformer 的 NLP 模型可以分为三种主要类型之一,括号中提供了示例:
• 序列到序列(BART/T5)
• 自编码(BERT)
• 自回归(GPT)
之前的 transformer 模型是在大量文本上以自监督的方式训练为语言模型的。此外,XGLM 是一系列大规模多语言自回归语言模型,在多语言少样本学习上实现了 SOTA 结果。MetaAI 的 XGLM 现在可在 Hugging Face transformers 中找到:
huggingface.co/spaces/valhalla/XGLM-zero-shot-COPA
NVidia 的 Transformer 加速器
现在基于 transformer 的模型已经超过了一万亿参数,对于这些模型以及未来的更大模型来说,计算速度变得越来越重要。尽管早期的推测认为 GPT-4 可能达到 100 万亿参数,但根据 8 个每个有 2200 亿参数的“组件”,GPT-4 似乎有 1.76 万亿参数。
目前,NVidia 提供 A100 GPU 芯片,A100 GPU 的继任者是 H100 GPU,它比 A100 提供显著更快的计算能力。根据应用,H100 可以提供比 A100 快 8 到 30 倍的处理速度。
“Hopper”是 H100 芯片设计的名称,该设计包括一个用于提高性能的 transformer 引擎。H100 支持其他提高性能的技术:www.nvidia.com/en-us/data-center/h100。
用于图的 Transformer 架构
尽管原始的 transformer 架构非常适合 NLP 相关任务,但还有一种增强的 transformer 架构可用于处理任意图。特别是,这种增强架构修改了 transformer 的三个现有方面,并添加了一个新特性:
• 注意力机制
• 位置编码
• 层归一化
• 边缘特征表示
更多关于此架构的信息可在网上找到:
Hugging Face 的 Transformers 库
Hugging Face 创建了一个基于 Python 的 Transformers 库和一个开源存储库,以开发基于 Transformer 架构的模型,该存储库可在以下网址找到:
github.com/huggingface/transformers。
Hugging Face 的开源 Transformers 库有三个主要组件:
• 模型类别
• 配置类
• 分词器类
模型类提供了二十多个预训练的 Transformer 模型。
配置类提供各种类,包含实例化模型所需的参数。
分词器类是组件,为每个模型提供词汇表以及将字符串编码/解码为管理标记嵌入和索引的方法。在本章的后面部分,您将看到基于 Python 的代码示例,展示如何使用 Hugging Face 的分词器类。
Transformers 库和 NLP 任务
Transformers 库提供了用于 NLU 和 NLG 的预训练模型。实际上,Hugging Face 为 100 多种语言提供了 30 多个预训练模型,并支持 TensorFlow 2 和 PyTorch 之间的互操作性。此外,Hugging Face 支持 BERT 相关模型、GPT-2/GPT-3、XLNet 以及其他模型。以下是 Hugging Face 支持的一些模型列表:
• BART(来自 Facebook)
• BERT(来自 Google)
• Blenderbot(来自 Facebook)
• CamemBERT(来自 Inria/Facebook/Sorbonne)
• CTRL(来自 Salesforce)
• DeBERTa(来自微软研究院)
• DistilBERT(来自 Hugging Face)
• ELECTRA(来自 Google Research/斯坦福大学)
• FlauBERT(来自 CNRS)
• GPT-2(来自 OpenAI)
• Longformer(来自 AllenAI)
• LXMERT(来自 UNC Chapel Hill)
• Pegasus(来自 Google)
• Reformer(来自 Google Research)
• RoBERTa(来自 Facebook)
• SqueezeBert
• T5(来自 Google AI)
• Transformer-XL(来自 Google/CMU)
• XLM-RoBERTa(来自 Facebook AI)
• XLNet(来自 Google/CMU)
检查在线文档以获取有关前面项目符号中模型的更多信息。
这些语言模型共同支持 NLU 和 NLG,以执行文本分类、信息提取和文本生成等任务。
Transformer 管道类
Transformers 库为多个模型提供了一个标准接口,简化了将语言模型集成到自定义应用程序中的任务。特别是,Transformers 库支持 JAX、PyTorch 和 TensorFlow。
Transformer 库还提供了一个 pipeline() 类,您可以在基于管道的机制中使用它。以下代码块说明了如何实例化一个用于各种指定在双引号内的 NLP 任务(完整的代码示例将在后面讨论)的 Transformer 管道:
from transformers import pipeline
classifier1 = pipeline("ner")
classifier2 = pipeline("token-classification")
classifier3 = pipeline("question-answering")
classifier4 = pipeline("sentiment-analysis")
classifier5 = pipeline("text-generation")
classifier6 = pipeline("feature-extraction")
classifier7 = pipeline("summarization")
classifier8 = pipeline("zero-shot-classification")
如您在前面的代码块中所见,pipeline() 类支持命名实体识别(NER)、标记分类、情感分析等功能。此外,transformers 库支持超过 100 种语言的上述 NLP 任务。Hugging Face Hub 包含了众多模型:
变压器架构复杂度
变压器架构的复杂度是注意力机制复杂度和变压器架构各个组件复杂度的总和。矩阵乘法涉及每个乘法 O(N²) 的复杂度,以计算每对标记之间的成对相似度。
下面的列表包含了变压器架构中几个组件的复杂度:
• O(N²*D):自注意力的复杂度
• O(N*D²):查询/键/值投影层的复杂度
• O(N*D²):前馈层的复杂度
在大多数情况下,D 的值远大于 N。例如,GPT-3 中 D 的值为 12288,而 N 远小于 D。另一个需要考虑的细节是,带宽通常是 LLM 的瓶颈,这意味着在相同的带宽下,计算时间和内存资源的减少并不会提高整体性能。
减少注意力复杂度
变压器架构中的注意力机制具有 O(N²) 的复杂度,其中 N 等于标记的数量。幸运的是,Performer 架构以 O(N) 的复杂度计算注意力,因此 Performer 架构可以支持更宽的上下文窗口。例如,Flamingo LLM(本书未讨论)由于处理图像的大小而使用 Perceiver 模型(本书未讨论)。
HUGGING FACE 变压器代码示例
在我们深入探讨变压器架构的更多细节之前,让我们看看几个基于 Python 的代码示例,这些示例说明了如何使用 Hugging Face 变压器执行 NLP 相关任务。
尽管这些代码示例非常简单,但它们展示了如何使用 Hugging Face 变压器执行命名实体识别(NER)、问答(QnA)和情感分析。此外,代码示例提供了一个具体的基础,您可以在此基础上增加对变压器和基于变压器的语言模型的工作知识。
变压器和 NER 任务
列表 3.1 展示了 hf_transformer_ner.py 的内容,该内容说明了如何使用 Hugging Face 变压器执行命名实体识别(NER)任务。
列表 3.1: hf_transformer_ner.py
from transformers import pipeline
import pandas as pd
nlp = pipeline('ner')
result = nlp("I am a UCSC instructor and my name is Oswald")
print("result:",result)
Print()
df = pd.DataFrame(result)
print("df:",df)
print()
nlp = pipeline('ner')
result = nlp("I Love Chicago Pizza and I Really
Like New York Bagels")
print("=> result:",result)
print()
df = pd.DataFrame(result)
print("df:",df)
列表 3.1 从一个导入语句开始,然后初始化变量 nlp 为 pipeline 函数的一个实例,其中 ner 作为参数。接下来,使用硬编码的样本句子调用变量 nlp。输出被分配给变量 result,然后显示其内容。使用以下命令启动 列表 3.1 中的代码:
python3 hf_transformer_ner.py
上述命令启动了您机器上安装的 Python 版本。正如您在本章引言中了解到的那样,Hugging Face 目前支持 Python 3.7,但未来可能还会支持 Python 的后续版本。上述命令将显示以下输出:
=> result: [{'word': 'UC', 'score':
0.9993938207626343, 'entity': 'I-ORG', 'index':
4}, {'word': '##SC', 'score': 0.9974051713943481,
'entity': 'I-ORG', 'index': 5}, {'word': 'Oswald',
'score': 0.9988114833831787, 'entity': 'I-PER',
'index': 11}]
df: word score entity index start end
0 UC 0.999394 I-ORG 4 7 9
1 ##SC 0.997405 I-ORG 5 9 11
2 Oswald 0.998811 I-PER 11 38 44
=> result: [{'word': 'Chicago', 'score':
0.962387204170227, 'entity': 'I-ORG', 'index': 3,
'start': 7, 'end': 14}, {'word': 'Pizza', 'score':
0.958823561668396, 'entity': 'I-ORG', 'index': 4,
'start': 15, 'end': 20}, {'word': 'New', 'score':
0.6438480615615845, 'entity': 'I-ORG', 'index': 9,
'start': 39, 'end': 42}, {'word': 'York', 'score':
0.8661817908287048, 'entity': 'I-ORG', 'index': 10,
'start': 43, 'end': 47}, {'word': 'Ba', 'score':
0.5761372447013855, 'entity': 'I-MISC', 'index':
11, 'start': 48, 'end': 50}, {'word': '##gel',
'score': 0.4892355501651764, 'entity': 'I-MISC',
'index': 12, 'start': 50, 'end': 53}]
df: word score entity index start end
0 Chicago 0.962387 I-ORG 3 7 14
1 Pizza 0.958824 I-ORG 4 15 20
2 New 0.643848 I-ORG 9 39 42
3 York 0.866182 I-ORG 10 43 47
4 Ba 0.576137 I-MISC 11 48 50
5 ##gel 0.489236 I-MISC 12 50 53
Transformer 和 QnA 任务
列表 3.2 显示了 hf_transformer_qa.py 的内容,该内容说明了如何使用 Hugging Face transformer 进行问答任务。
列表 3.2: hf_transformer_qa.py
from transformers import pipeline
nlp = pipeline('question-answering')
result = nlp({
'question': "Do you know my name?",
'context': "My name is Oswald"
})
print("result:",result)
列表 3.2 以一个导入语句开始,然后初始化变量 nlp 为一个具有问答参数的管道函数实例。接下来,使用问题/上下文对调用变量 nlp。输出被分配给变量 result,然后显示其内容。启动 列表 3.2 中的代码,您将看到以下输出:
result: [{'word': 'UC', 'score':
0.9993938207626343, 'entity': 'I-ORG', 'index':
4}, {'word': '##SC', 'score': 0.9974051713943481,
'entity': 'I-ORG', 'index': 5}, {'word': 'Oswald',
'score': 0.9988114833831787, 'entity': 'I-PER',
'index': 11}]
Transformer 和文本摘要
列表 3.3 显示了 hf_text_summarization.py 的内容,该内容说明了如何使用 Hugging Face transformer 进行文本摘要。请注意,此代码示例中的文本块与本章节引言中的文本相同。
列表 3.3: hf_text_summarization.py
from transformers import pipeline
summarizer = pipeline("summarization")
text = """
This chapter is the first of two chapters that
discusses the transformer architecture, which is
the foundation for a plethora of language models,
such as BERT and its variants (discussed in
Chapters 4 and 5), as well as the GPT-x family from
OpenAI, various other LLMs (discussed in Chapters 6
and 7).
This chapter describes the main components of the
original transformer, along with Python-based
transformer code samples for various NLP tasks,
such as NER, QnA, and mask filling tasks. Please
read chapter one that discusses some topics that
are relevant to the material in this chapter.
The first part of this chapter introduces the
transformer architecture that was developed by
Google and released in late 2017\. This section also
discusses some NLP Transformer models.
The second part of this chapter discusses the
transformers library from Hugging Face, which is
a company that provides a repository of more than
20,000 transformer-based models. This section also
contains Python-based transformer code samples that
perform various NLP tasks, such as NER, QnA, and
mask filling tasks.
The third part of this chapter provides more
details regarding the encoder component, along
with additional details regarding the attention
mechanism, as well as the decoder component, which
is the other main component of the transformer
architecture.
Before you read this chapter, keep in mind that
there are cases of "forward referencing" concepts
that are discussed in later chapters, which
provide context for a given concept. Of course,
if you are unfamiliar with a concept discussed in
a later chapter, then it will also be challenging
to fully understand the topic under discussion.
As a result, you will probably need to read some
topics more than once, after which concepts become
easier to grasp when you understand the current
context and the context of referenced material in
later chapters (fortunately, this reading process
is finite).
"""
result = summarizer(text)
#print("summary text:",result)
print("summary text:",result[0]['summary_text'])
列表 3.3 以一个导入语句开始,然后使用具有摘要任务的管道类调用结果初始化变量 summarizer。列表 3.3 的下一部分初始化字符串变量 text,其中包含本章引言的内容。最后的代码块使用 summarizer(text) 的输出初始化变量 result,然后显示 summary_text 的内容。
启动 列表 3.3 中的代码,当您第一次运行代码时,您将看到以下输出:
Downloading: 100%|
| 1.80k/1.80k [00:00<00:00, 283kB/s]
Downloading: 100%|
| 1.22G/1.22G [00:27<00:00, 44.2MB/s]
Downloading: 100%|
| 899k/899k [00:00<00:00, 1.55MB/s]
Downloading: 100%|
| 456k/456k [00:00<00:00, 2.02MB/s]
Downloading: 100%|
| 26.0/26.0 [00:00<00:00, 6.87kB/s]
summary text: This chapter is the first of two
that discusses the transformer architecture, which
is the foundation for a plethora of language
models. This chapter describes the main components
of the original transformer, along with Python-
based transformer code samples for various NLP
tasks. The second part of this chapter discusses
the transformers library from HuggingFace,
which provides a repository of more than 20,000
transformer-based models.
在随后的 Python 代码调用中,由于 LLM 已经存在于您的机器上,下载部分将被跳过。将生成的输出与变量 text 的内容进行比较,以确定代码是否提供了准确的摘要。
Transformer 和文本翻译
列表 3.4 显示了 hf_text_translation.py 的内容,该内容展示了如何使用 Hugging Face transformer 将文本从英语翻译成意大利语。
列表 3.4: hf_text_translation.py
from transformers import pipeline
translator = pipeline("translation_en_to_
it",model="Helsinki-NLP/opus-mt-en-it")
input = "Today the weather was really nice and
sunny"
input = "I love Chicago deep dish pizza and a
bottle of stout”
results = translator(input, clean_up_tokenization_
spaces=True, min_length=50)
print("results[0]['translation_text']:")
print(results[0]['translation_text'])
列表 3.4 从导入语句开始,然后初始化变量 translator 为 pipeline 函数的一个实例,参数为 translation_en_to_it(即英语到意大利语)。接下来,使用一个问题/上下文对调用变量 nlp。输出被分配给变量 result,然后显示其内容。请注意,模型名称后缀 en-it(粗体显示)是一种简写技术,用于指定英语到意大利语的翻译。运行 列表 3.4 中的代码,你将看到以下输出:
Adoro la pizza a base di piatti profondi di Chicago
e una bottiglia di robusto… e un po' di roba…
e… e… un po' di roba…
transformer 和掩码相关任务
本节向您展示了如何使用各种句子执行掩码填充任务。您还将看到一个示例,说明在句子中指定多个
raise ValueError(
ValueError: Connection error, and we cannot find
the requested files in the cached path. Please try
again or make sure your Internet connection is on.
列表 3.5 展示了 hf_fill_mask1.py 的内容,说明了如何使用 Hugging Face transformer 执行掩码填充任务。
列表 3.5: hf_fill_mask1.py
from transformers import pipeline
mlm = pipeline("fill-mask")
prompt = "The dog <mask> over the fence”
result = mlm(prompt)
print("prompt:",prompt)
print("result:",result)
print("---------------")
mlm = pipeline("fill-mask")
prompt = "The dog <mask> over the pool"
result = mlm(prompt)
print("prompt:",prompt)
print("result:",result)
print("---------------")
mlm = pipeline("fill-mask")
prompt = "The horse <mask> over the wall"
result = mlm(prompt)
print("prompt:",prompt)
print("result:",result)
列表 3.5 从导入语句开始,然后初始化变量 nlp 为一个以 fill-mask 为参数的 pipeline 函数的实例。接下来,使用硬编码的文本字符串调用变量 nlp。输出被分配给变量 result,然后显示其内容。运行 列表 3.5 中的代码,你将看到以下输出:
prompt: The dog <mask> over the fence
result: [{'sequence': '<s>The dog jumps over the
fence</s>', 'score': 0.27710869908332825, 'token':
13855, 'token_str': 'Ġjumps'}, {'sequence':
'<s>The dog leaps over the fence</s>', 'score':
0.1510920524597168, 'token': 32564, 'token_str':
'Ġleaps'}, {'sequence': '<s>The dog jumped over the
fence</s>', 'score': 0.06851337850093842, 'token':
4262, 'token_str': 'Ġjumped'}, {'sequence':
'<s>The dog climbs over the fence</s>', 'score':
0.04117066413164139, 'token': 30318, 'token_str':
'Ġclimbs'}, {'sequence': '<s>The dog walks over the
fence</s>', 'score': 0.03938476741313934, 'token':
5792, 'token_str': 'Ġwalks'}]
-------------–
prompt: The dog <mask> over the pool
result: [{'sequence': '<s>The dog jumps over the
pool</s>', 'score': 0.1273069977760315, 'token':
13855, 'token_str': 'Ġjumps'}, {'sequence':
'<s>The dog walks over the pool</s>', 'score':
0.106533944606781, 'token': 5792, 'token_str':
'Ġwalks'}, {'sequence': '<s>The dog runs over
the pool</s>', 'score': 0.06851048767566681,
'token': 1237, 'token_str': 'Ġruns'}, {'sequence':
'<s>The dog leaps over the pool</s>', 'score':
0.05455796793103218, 'token': 32564, 'token_str':
'Ġleaps'}, {'sequence': '<s>The dog leaping over
the pool</s>', 'score': 0.03309628739953041,
'token': 33189, 'token_str': 'Ġleaping'}]
---------------
prompt: The horse <mask> over the wall
result: [{'sequence': '<s>The horse jumps over the
wall</s>', 'score': 0.05724393203854561, 'token':
13855, 'token_str': 'Ġjumps'}, {'sequence':
'<s>The horse rode over the wall</s>', 'score':
0.056807991117239, 'token': 12783, 'token_str':
'Ġrode'}, {'sequence': '<s>The horse leaps over the
wall</s>', 'score': 0.04696424677968025, 'token':
32564, 'token_str': 'Ġleaps'}, {'sequence':
'<s>The horse climbs over the wall</s>', 'score':
0.04176592454314232, 'token': 30318, 'token_str':
'Ġclimbs'}, {'sequence': '<s>The horse rides over
the wall</s>', 'score': 0.04105382785201073,
'token': 9668, 'token_str': 'Ġrides'}]
列表 3.6 展示了 hf_fill_two_masks.py 的内容,展示了在同一个句子中指定多个
列表 3.6: hf_fill_two_masks.py
from transformers import pipeline
mlm = pipeline("fill-mask")
prompt = "The horse <mask> over the fence and the
<mask> ate the pizza"
result = mlm(prompt)
print("prompt:",prompt)
print("result:",result)
运行 列表 3.6 中的代码,你将看到以下输出:
raise PipelineException(
transformers.pipelines.base.PipelineException: More
than one mask_token (<mask>) is not supported
提示和填充任务
列表 3.7 展示了 hf_prompt_fill.py 的内容,该内容说明了如何指定一个提示并使用 Hugging Face transformer 执行填充掩码任务。
列表 3.7: hf_prompt_fill.py
from transformers import pipeline
pipe = pipeline("fill-mask", model="bert-base-
uncased")
# => part 1:
movie_desc = "the main characters of the movie
matrix are neo, morpheus, and trinity."
prompt = "The movie is about [MASK]."
output = pipe(movie_desc + prompt)
print("desc: ",movie_desc)
print("prompt:",prompt)
for element in output:
print(f"Token {element['token_str']}:
\t{element['score']:.3f}%")
print("-------------\n\n")
# => part 2:
movie_desc = "In the movie transformers aliens can
morph into a wide range of vehicles."
prompt = "The movie is about [MASK]."
output = pipe(movie_desc + prompt,
targets=["animals","cars"])
print("desc: ",movie_desc)
print("prompt:",prompt)
for element in output:
print(f"Token {element['token_str']}:
\t{element['score']:.3f}%")
列表 3.7 从导入语句开始,然后初始化变量 nlp 为一个以 fill-mask 为参数的 pipeline 函数的实例。接下来,使用硬编码的文本字符串调用变量 nlp。输出被分配给变量 result,然后显示其内容。运行 列表 3.7 中的代码,你将看到以下输出:
desc: the main characters of the movie matrix are
neo, morpheus, and trinity.
prompt: The movie is about [MASK].
Token trinity: 0.058%
Token neo: 0.053%
Token love: 0.050%
Token dreams: 0.028%
Token fate: 0.024%
-------------
desc: In the movie transformers aliens can morph
into a wide range of vehicles.
prompt: The movie is about [MASK].
Token cars: 0.139%
Token animals: 0.006%
总结
本章从 transformer 架构的介绍开始,接着描述了 transformer 架构的三个变体:仅编码器(BERT)、仅解码器(GPT)以及同时包含编码器和解码器(BART 和 T5)。
接下来,你学习了来自 Hugging Face 的 transformers 库,这是一家提供大量基于 Transformer 模型的公司的库。然后你看到了使用基于 Transformer 模型执行各种 NLP 任务的代码示例,例如命名实体识别(NER)、问答(QnA)和掩码填充任务。
此外,你了解了编码器组件和解码器组件的细节,它们是 Transformer 架构的两个主要组件。你还看到了编码器和解码器具有相似的结构,解码器中还有一个额外的掩码自注意力层。
第四章
深入探讨 Transformer 架构
本章是关于 Transformer 架构的两章中的第二章,它是众多语言模型(如 BERT 及其变体[第五章和第六章],随后是 GPT-x 家族及其竞争对手[第七章和第八章])的基础。
本章的第一部分讨论了位置编码,这涉及到 Transformer 架构中的 sine()和 cosine()函数。你还将在本节中了解三种类型的位置编码。
本章的第二部分讨论了 Transformer 架构编码组件的附加细节,以及解码组件的概述。本节还提供了关于在 LLM 中确定是否使用编码器、解码器或同时使用编码器和解码器的信息。
本章的第三部分讨论了 Auto 类,如 AutoModel、AutoConfig 和 AutoTokenizer。你将了解在原始 Transformer 架构之上提供改进的 LLM,例如 Reformer、Longformer 和包含一万亿参数的 Switch Transformer。
本章的最后部分包含了一个加载日本数据集的示例,随后是一个情感分析的示例。
现在你已经看到了一些基于 Python 的 Transformer 代码示例,让我们深入了解 Transformer 的内部结构。
编码器概述
正如你所学的,存在仅使用编码器的 LLM、同时使用编码器和解码器的 LLM 以及仅使用解码器的 LLM。本节涉及前两种类型的 LLM,而随后的章节将讨论包含解码器的 LLM。
在从输入标记创建词嵌入之后,为每个标记创建一个位置编码向量。这个主题将在后续章节中讨论,解释如何使用 sine()和 cosine()函数为每个标记生成位置向量。
下一步涉及注意力机制,这是 transformer 架构的关键部分:没有注意力机制的编码器仅将编码器的最终状态暴露给解码器。因此,编码器的先前状态对解码器不可用,这导致信息瓶颈,即有关输入的所有内容都必须编码在编码器的单个输出中。确实,先前的场景适用于 RNNs 和 LSTMs:这两个架构都只提供当前组件最终层的输出给下一个组件(如另一个 RNN 或另一个 LSTM 组件)。
与之相反,使用注意力机制的编码器将使解码器能够访问编码器中所有其他隐藏状态,从而避免信息瓶颈问题。
编码器层的数量
尽管关于 transformer 架构的图(“Attention is All You Need”)只显示了单个编码器层(以及单个解码器层),但 transformer 架构的编码器组件通常具有六个或十二个连接的编码器组件。每个编码器组件由具有两层(第一层的输出成为第二层的输入,类似于微型管道)的元素组成。第六个(或在某些情况下,第十二个)编码器组件的最终输出随后传递到解码器组件中的每个解码器元素。
类似地,解码器组件也有六个(有时更多)连接的解码器组件,其中一个组件的输出成为下一个组件的输入。然而,请注意,每个编码器元素有两个子元素,而每个解码器元素由三个子元素组成,其中一个来自编码器的输出。
包含编码器和解码器的 LLMs 涉及一个由多个相同组件组成的编码器块,以及一个由多个相同组件组成的解码器块。编码器和解码器中的每个块都与卷积神经网络(CNN)中的滤波器元素松散地类似。
编码器是如何工作的?
如前所述,transformer 的编码器组件实际上是一个编码器块的垂直堆叠。关于注意力机制的原始论文指定了一个具有六个组件的编码器,但可以指定更多数量的块。
每个编码器处理其输入并生成编码输出,然后将其传递到当前编码器块中的下一个组件。编码器块堆叠中的最终(最顶部的)编码器包含初始输入句子的表示。编码结果随后传递到解码器块中的每个组件以进行额外的处理步骤。
现在我们已经讨论了词嵌入在编码器组件中的流动过程,我们可以深入探讨将输入句子中的标记转换为词嵌入的过程,这是下一节的主题。
编码器的初始词嵌入
机器学习模型(包括基于 transformer 的模型)不能处理基于字符串的输入标记。相反,语料库的标记必须转换为一系列词嵌入。不同的算法使用不同的技术来生成词嵌入。例如,word2vec 通过一个浅层神经网络(即单个隐藏层)来完成这项任务。
然而,transformer 架构涉及多个步骤。第一步为每个标记创建一个“标记编码”,它由 one-hot 向量组成(如果你需要更多关于 one-hot 编码的细节,请在网上搜索)。标记编码的大小不同,因为它取决于分词器词汇表的大小:后者可以从 20,000 个唯一标记小到 200,000 个唯一标记。
第二步涉及将 one-hot 向量投影到低维空间。在此阶段,它们已准备好由 transformer 架构编码器初始层的初始层编码器进行处理。因此,编码器层为输入标记生成一个隐藏的或“掩码”状态,之后另一个层预测掩码标记的正确值。(确保你理解了微调和预训练模型之间的区别。)
在这一点上,我们可以根据具体任务选择两个方向之一。如果目标是预训练,从初始编码器层生成的隐藏状态将经过后续层的进一步处理,以对掩码标记进行预测,而不是对“隐藏状态”本身进行预测。
另一方面,如果任务是分类,将使用分类层,取代预训练中使用的语言建模层。在两种情况下,处理都继续通过构成 transformer 架构编码器组件的剩余编码器块。
让我们重申一个重要的细节:transformer 架构中的词嵌入涉及到一个注意力机制,其中每个词嵌入都是基于给定句子中所有标记的所有词嵌入。因此,与通过注意力机制生成的词嵌入相比,word2vec 算法生成的词嵌入存在一个关键的区别:后者为在多个句子中出现的相同单词生成不同的嵌入,而 word2vec 为给定单词生成单个词嵌入,无论该单词的上下文如何。
因此,给定一个包含 n 个标记的句子,每个词嵌入的构建涉及到剩余的(n-1)个单词。因此,基于注意力的机制具有 O(N²)的顺序,其中 N 是语料库中唯一标记的数量。
什么是位置编码?
位置编码被添加到序列中标记的嵌入中,为模型提供有关标记在序列中位置的信息。由于基于自注意力机制的变换器模型本身没有顺序或位置感,位置编码对于使模型在预测时考虑标记的顺序至关重要。
位置编码注入有关序列中标记的相对或绝对位置的信息。这种信息对于翻译、摘要等序列到序列任务至关重要,在这些任务中,单词的顺序至关重要。
位置编码的维度与词嵌入相同,这使得我们可以将它们添加到词嵌入中。此外,位置编码是在嵌入传递到变换器模型之前添加到词嵌入中的。
此外,位置编码允许模型处理由可变长度组成的序列,并且还使得序列的并行处理成为可能,这是变换器模型相对于循环神经网络(RNNs)的一个显著优势。
位置编码的实际构建基于三角函数正弦()和余弦()的组合,这将在下一节中更详细地描述。
位置编码的正弦()和余弦()函数
位置编码通过三角函数正弦()和余弦()函数计算得出,之后它们被添加到每个词嵌入中。作为一个简化的解释,考虑以下正弦()函数集的垂直对齐图集,其频率集合为{1, 2, 3, … , k},其中 k 是一个任意大的正整数,每个图都有其自己的垂直 y 轴,范围在-1 和 1 之间:
{sine(x), sine(2x), … ., sine(kx)}
现在,在水平 x 轴的任何位置画一条垂直线:这条线将在-1 和 1 之间的 k 个不同位置与 k 个正弦()函数相交。设 S 为垂直线与正弦()函数相交的值。然后,我们可以构造向量 S = [s1, s2, … , sk],其中包含成对不同的值。
以类似的方式,考虑以下余弦()函数集的垂直对齐图集:
{cosine(x), cosine(2x), … ., cosine(kx) }
如果你画一条垂直线,该线在水平 x 轴的任何位置与 x 轴相交,那么这条线将在 k 个位置与 k 个余弦()函数相交。由于每个余弦()函数都以其自己的垂直 y 轴绘制,范围在-1 和 1 之间,因此每个交点的 y 坐标也是一个介于-1 和 1 之间的值,构成了集合 C = [c1, c2, … , ck]。前述列表中的值是唯一值,因为 k 个余弦()函数具有不同的频率。
前面的值集 S 和 C 是位置编码的基础,其中从基于正弦值的偶数索引位置和基于余弦值的奇数索引位置构造一个向量。具体来说,位置编码向量具有以下形式:
P = [s1, c1, s2, c2, … , sk, ck]
然而,si 和 ci 值是通过以下公式计算的(这些公式与之前为 S 和 C 计算的正弦和余弦值不同):
si = sin(pos/[10000]**di]
ci = sin(pos/[10000]**di]
di 的值等于(2*i)/dk,其中 i 是位置编码向量中的当前索引值,dk 是输入维度。请注意,索引 i 从 0 开始,这意味着基于正弦的项位于偶数索引的位置,而基于余弦的项位于奇数索引的位置。
提醒一下,构建的向量与词嵌入具有相同的形状,因此我们可以将位置编码向量添加到词嵌入中,以获得与词嵌入相同形状的新向量。
新的向量(即嵌入向量和位置编码的总和)被传递到编码组件中的第一个编码块。
因此,我们可以在嵌入中识别每个标记的原始位置。现在我们可以总结位置编码具有以下特性:
• 它们基于标记的位置。
• 它们包含唯一的值。
• 它们被限制在 1 以下。
单词上下文和其位置编码的基于向量的和等于带上下文的嵌入:
Embedding with context = word context + positional encoding
此外,语言模型通常不需要为其预训练提供标签。
三种类型的位置编码
上一节讨论了位置编码,这是一种编码类型。然而,正如这里所示,至少有三种不同的技术可以产生与位置相关的信息:
• 位置嵌入
• 位置编码
• 相对位置
基于 Transformer 的语言模型可以使用不同的编码技术。例如,BERT 使用位置嵌入而不是位置编码。
关于编码器的其他细节
前几节描述了编码器的初始部分以及位置编码的目的。如果你查看 Transformer 架构中的编码器,你会注意到每个层中都有一个多头注意力块和一个前馈网络,以及一个加和归一化步骤。以下小节将讨论编码器的这些方面。
编码器中的多头注意力块
Transformer 模型编码器中的多头注意力块在增强模型处理和分析数据序列的能力方面发挥着几个关键作用:
• 并行化注意力机制
• 改进的表示学习
• 对不同位置的增强关注
• 可扩展性和效率
多头注意力块涉及几个并行注意力头,每个头独立计算注意力分数和输出。此外,多个头的存在使模型能够同时学习数据的不同表示,捕捉标记之间关系的各个方面。
编码器中的前馈网络
在 Transformer 模型的编码器中,前馈神经网络(FFNN)在处理从先前层获得的信息并将其映射到一个可能更复杂的空间以捕捉数据中的复杂模式方面起着关键作用。
具体来说,FFNN 包含 ReLU(修正线性单元)或 GELU(高斯误差线性单元)非线性激活函数。实际上,FFNN 通常由一个或多个线性层后跟非线性激活函数组成。
与考虑不同标记之间关系的注意力层不同,FFNN 独立处理每个标记。这使得 FFNN 能够专注于从单个标记中提取特征,而不会受到序列中其他标记的影响。
可以在 FFNN 中应用正则化技术,如 dropout,以防止过拟合并鼓励学习鲁棒表示。
简而言之,Transformer 模型编码器中的 FFNN 用于引入非线性变换,从单个标记中提取特征,增加模型的深度,并增强对数据复杂、分层表示的学习。它与多头注意力层协同工作,有效地处理和分析序列,在广泛的 NLP 任务中扮演着 Transformer 模型成功的关键角色。
什么是加和归一化?
如前所述,加和归一化步骤是将一个组件的输入与另一个组件的输出相结合,然后对该组合进行归一化。这一步骤在多头注意力层以及前馈层上执行。
加法步骤的目的与网络中的中继器类似,本质上“增强”了一个(减弱的)信号。归一化步骤的目的是确保结果值处于相同的范围(即,没有异常值或其他异常大的值),这反过来可以导致更快的计算时间。
我们现在可以如下表示 Transformer 架构的编码器组件的元素(每个 ENC 是一个编码器块):
Input embedding > positional encoding > ENC1 > ENC2 > … ENCn
编码器块的数量 n 通常为 6 或 12,有时为 24(并且可能是一个更大的数字)。第一个编码器 ENC1 的输入 INP 是输入嵌入和位置编码的总和,每个编码器块 ENC 的内容如下所示:
MHA(out)+INP > ADD+Norm > FF > ADD+Norm > next encoder block
现在我们已经了解了如何为给定语料库中的标记创建初始词嵌入,让我们更详细地看看编码器中的自注意力机制。
解码器概述
解码器组件与编码器组件非常相似,它由以下内容组成:
• 多个解码器块
• 位置编码
• 输出嵌入
输出嵌入是每个解码器块的最底层元素(通常涉及 6 个或 12 个这样的块),其对应物是编码器组件中的输入嵌入。在此元素之上是位置编码,它是编码器组件中位置编码的对应物。在位置编码之上是一系列一个或多个解码器块。
你可以将解码器组件视为编码器组件的超集:编码器块包含两个子层,解码器块包含相同的子层,以及一个第三子层,称为带掩码的多头注意力层。
带掩码的多头注意力(MMHA)层确保只能执行“向后看”(从右到左)的注意力。BERT 模型被训练为一个双向模型,这意味着它可以看到任何给定标记序列中该标记的前一个标记以及下一个标记。
因此,BERT 不需要预测序列中的下一个标记,因为它实际上知道下一个标记。MMHA 层有效地阻止了任何 LLM 查看下一个标记,这反过来意味着下一个标记必须被预测。顺便提一下,只能执行向后看注意力的 LLM 被称为自回归模型。
解码器组件是如何工作的?
解码器组件以与编码器组件类似的方式工作,并增加了前面章节中描述的 MMHA。解码器组件包含解码器块,其中第一个解码器块解码来自编码器组件的输入。第一个解码器块(以及随后的解码器块)的输出传递到解码器组件中的下一个解码器块(自下而上)中。此外,编码器组件的输出对解码器组件中的每个解码器块都是可访问的。
解码器组件中的每个解码器块都接收来自先前解码器块的输出 以及 来自编码器组件的输出(由多头注意力层摄取)作为其输入。
解码器中的自注意力
编码器块和解码器块都包含多头注意力元素。此外,解码器块还包含一个具有带掩码的多头注意力元素的组件。
带掩码的多头元素阻止解码器检查序列中的下一个标记,从而“迫使”解码器生成下一个单词。
通过将右上角的矩阵中的值设置为负无穷大,从而完成前面的操作,之后 softmax()函数将这些值替换为 0,从而确保下一个标记不可用。
生成输出序列
此步骤以顺序方式进行,涉及类似循环的操作序列:
-
以起始标记
作为解码器的初始输入开始。 -
将此标记通过输出嵌入层传递以获得相应的嵌入。
-
使用此嵌入以及编码器的输出(或上下文向量)作为解码器组件的输入以生成隐藏状态。
-
使用隐藏状态生成下一个输出标记的词汇表上的概率分布。
-
从分布中采样或选择最可能的标记作为输出标记。
-
将此输出标记添加到之前生成的输出标记列表中。
-
使用迄今为止生成的输出标记列表(包括最新的输出标记)作为下一步中解码器的新输入,同时包括编码器的输出。
-
重复步骤 #2 到 #7,直到生成结束标记
或达到最大序列长度。
例如,考虑句子 S 等于“我爱芝加哥披萨。”输入句子: “我爱芝加哥披萨。”
编码器输出: (通过编码器处理输入句子后在高维空间中的表示。)
解码器步骤的序列如下所示:
- 以起始标记
作为解码器的初始输入开始。
当前输入标记:
- 将此标记通过输出嵌入层传递以获得相应的嵌入。
- 使用此嵌入以及编码器的输出作为解码器组件的输入以生成隐藏状态。
隐藏状态: [0.4, 0.2, …, 0.9](假设的隐藏状态向量)
- 使用隐藏状态生成下一个输出标记的词汇表上的概率分布。
概率分布: {“J’”: 0.7, “aime”: 0.1, “Chicago”: 0.05, “pizza”: 0.05, …, “
- 从分布中采样或选择最可能的标记作为输出标记。
选择输出标记: “J’”(假设根据分布最可能的标记)
- 将此输出标记添加到之前生成的输出标记列表中。
到目前为止的输出标记: [
- 使用迄今为止生成的输出标记列表(包括最新的输出标记)作为下一步中解码器的新输入,同时包括编码器的输出。
新输入到解码器: [
- 重复步骤 #2 到 #7,直到生成结束标记
或达到最大序列长度。
重复此过程,在后续迭代中,我们可能会生成“aime”,“la”,“pizza”,“de”,“Chicago”和最后“
编码器、解码器或两者:如何决定?
变压器架构主要有三种实现方式:
• 仅编码器(用于分类)
• 仅解码器(用于语言建模)
• 编码器-解码器(用于机器翻译)
仅编码器模型非常适合需要理解输入的任务,例如句子分类和命名实体识别。仅编码器模型的例子包括 BERT、alBERT、DistilBERT、RoBERTa 和 ELECTRA。
编码器非常适合像标记分类这样的任务。另一个任务是提取式问答,其中我们从最佳回答问题的文档中预测一段文本的起始和结束标记。编码器块非常适合这些任务,因为编码器将输入序列映射到相同维度的输出序列。编码器上下文化提供给系统的标记嵌入向量,不是生成不同长度的序列。
仅解码器模型是自回归模型,非常适合文本生成等生成任务。仅解码器模型的例子包括 GPT、GPT-2 和 TransformerXL。给定单词,注意力层只能访问句子中位于其之前的单词。有趣的是,有时仅解码器模型比编码器-解码器模型更受语言生成能力的青睐。
编码器-解码器模型(也称为 序列到序列 模型)非常适合需要输入的生成任务,例如机器翻译,其中我们编码来自一种源语言的序列,然后解码器在一个目标语言中生成可能不同长度的序列。
另一种编码器-解码器架构是多模态变换器架构(例如,视觉到文本)。编码器-解码器模型通常被称为 seq2seq,并且能够生成与输入序列长度不同的输出序列。
一个编码器-解码器模型的例子是 BART,其代表双向和自回归变换器。BART 的编码器组件与 BERT 的编码器组件工作方式相同:它处理并上下文化输入。然而,BART 的编码器组件还从其最后一个注意力层提供键和值向量到解码器的注意力层。解码器组件自动回归地生成其输出。
有一些基于变换器的模型包含变换器架构的这两个组件,并且执行仅需要一个变换器组件的 NLP 相关任务。为了澄清,T5 架构执行仅需要一个编码器的分类任务,但 T5 使用了变换器架构的编码器和解码器。此外,回顾变换器架构,注意力以几种方式出现:
• 编码器中的自注意力
• 解码器中的自注意力
• 编码器-解码器中的跨注意力
跨注意力机制使得解码器能够从编码器中获取信息。因此,在这些架构中,自注意力机制可能会有所不同,如下一节所述。
因果自注意力
因果自注意力表示标记只能访问属于同一文本字符串(句子)的过去标记。这是防止解码器“看到”输入序列中所有标记的机制(更多细节见下文)。在某些变换器架构中,自注意力必须因果依赖于前面的标记,而其他变换器架构则不施加这种限制。
具体来说,基于编码器的架构中的自注意力不需要是当前和过去标记的因果依赖。相比之下,基于编码器-解码器的架构在解码器中需要因果自注意力,因为每个自回归解码步骤必须只依赖于前面的标记。最后,在基于解码器的架构中,自注意力必须是因果的。
强制因果或“掩码”注意力的技术涉及将基于 n×n 注意力矩阵的上三角值设置为-oo,之后应用 softmax()函数到这个矩阵上,将上三角部分的所有值设置为负无穷大,其 softmax()值为 0。因此,标记只能访问前面的标记。
单向和双向嵌入
一个标记的单向上下文检查一个方向的标记以创建嵌入,这通常涉及前面的标记。由于我们以单方向(通常是左到右,有时是右到左)书写文本,因此文本生成非常适合单向嵌入。
一个标记的双向上下文检查从给定标记到之前的标记和后续标记,以生成嵌入。双向嵌入对于句子级任务,如改写或摘要,非常有用。
请记住以下要点:变换器架构支持双向编码器块和单向解码器块。此外,自回归模型与单向嵌入一起工作。
深入探究变换器架构
之前,你学习了变换器架构的几个方面,例如数据通过编码器组件和解码器组件的流动。本节简要描述了关于变换器的其他一些细节,其中一些列在这里:
• 编码器-解码器架构
• 权重矩阵和多头注意力
• 键、查询和值不是超参数
• 缩放因子 dk
• 输入序列长度
• 前向传播
• 残差连接
• 层归一化
• Dropout 率
• 变换器和反向传播
• 语言翻译和词序
• 段嵌入
• 压缩变换器
首先,解码器组件中的多头注意力层使用单个权重矩阵实现。此外,Q、K 和 V 值是多头注意力的输入,它们的初始值是相同的。
有趣的是,由注意力机制创建的关键、查询和值向量的维度不能通过编程修改,这意味着它们的维度 不是 超参数。
尽管在项 Q*Kt/d 中的缩放因子 d 可能看起来不寻常,但这个项是通过经验确定的。它的目的是确保内积将产生“合理”的值。
变换器架构、RNNs 和 LSTMs 都对输入序列的长度有限制。如果文本序列过长,你可以使用常规技术(例如截断和分块)来处理基于变换器的模型中的此类文本序列。
一个有趣的不同之处在于训练阶段和推理阶段的正向传递:在前者中,对整个 序列 执行单个正向传递,而在后者中,对每个 标记 执行解码器正向传递。
残差连接
在计算机视觉的 ResNet(残差网络)模型中引入了 残差连接(也称为 跳跃连接),之后它在 AlphaZero、AlphaFold 和变换器架构中得到了实现。
残差连接的理由是因为随着神经网络中层数的增加,神经网络的性能可能会下降。残差连接涉及将初始输入添加到神经网络的每个 其他 层,这有效地增加了处理后的输出。残差连接在某种程度上类似于网络中增强衰减信号的重复器。
可能以下细节可以阐明如何在神经网络中使用残差连接。假设 x 是神经网络的一个输入,F 是一个函数,它在 x 通过第一层时处理 x,因此输出变为 x1 = F(x)。下一层也使用 F 来处理 x1,其输出变为 x2 = F(x1)。以此类推,我们有一个值序列 {x, x1, x2, …, xn}。
一个 残差连接 简单地将输入 x 添加到后续输出中,从而创建序列 {x, x+F(x), x + F(x1), x + F(x2), …, x + F(xn)}。请注意,存在一些变体,其中交替值被更新以产生以下序列:
{x, F(x), x+F(x1), F(x2), x+F(x3), …, x+F(xn)}
层归一化
层归一化(LN)紧接在多头注意力层之后,也紧接在后续的卷积网络(稍后讨论)之后。因此,从左到右的执行顺序如下:
Multi-Head Attention > LN > FeedForward > LN
层归一化与批归一化有一些相似之处:后者在批次的 样本 中进行归一化,而前者在 特征 中进行归一化。具体来说,归一化从所有特征值中减去均值,然后除以标准差。请注意,这种转换在其他情况下的层归一化之外被称为标准化(是的,这很令人困惑)。以下是完整的公式:
h = g * (x-mean)/sigma + b (g = adaptive gain and
b = bias)
以下链接包含有关 transformer 中层归一化和残差连接的信息:
deepai.org/publication/on-layer-normalizations-and-residual-connections-in-transformers
以下链接提供了关于在 NLP 中使用层归一化与批量归一化更多细节的信息:
paperswithcode.com/method/layer-normalization
dropout 率
Transformer 架构中的 dropout 率的概念与 CNNs 中的 dropout 率的概念相同,这是一个最初由 Geoffrey Hinton 提出的概念。显然,Hinton 在银行排队时想到了这个主意;他认为这是一种防止(或至少减少)客户和银行柜员之间串通的可能性。
CNNs 中的 dropout 率的想法简单、巧妙且出奇有效:dropout 率是一个介于 0 和 1 之间的数字,它是神经网络中每次通过时被忽略的神经元数量的百分比。例如,如果 dropout 率是 0.20,那么隐藏层中的 20%的神经元在正向传播过程中会被忽略(它们在反向传播过程中也会被忽略)。每次神经网络处理一个新的数据点(即数字向量)时,都会忽略由给定层中 20%的神经元组成的随机选择的神经元集。这个概念减少了过拟合,旨在使模型更具泛化能力。
在 transformer 架构的情况下,dropout 率应用于自/交叉多头注意力层以及位置感知的前馈网络。
Transformers 和反向误差传播
基于 transformer 的模型经历“反向传播”(反向误差传播),就像其他深度学习模型(如 CNNs)一样。有趣的是,反向传播在整个模型中执行:
• FF(前馈)子层
• 权重矩阵 Q、K 和 V
• 编码器权重
• 解码器权重
• 嵌入
除了自注意力之外,解码器还包含关注编码器输出的交叉注意力层。这些层中的权重在反向传播过程中也会更新。
上述列表适用于仅编码器模型、仅解码器模型和编码器-解码器模型。要了解更多关于基于 transformer 的模型中反向传播的方面,请阅读以下论文:
aclanthology.org/2020.emnlp-main.463.pdf
语言翻译和词序
Google Translate 是一个在线工具,它使用变换器执行语言翻译,其准确性非常令人印象深刻,其生成语法正确句子顺序的能力也是如此。如果您在具有不同词序的语言之间进行翻译(例如,英语和德语),您可能会想知道这实际上是如何完成的。例如,这里有一个英语句子及其翻译成德语:
我已经读过了这本书。
Ich habe das Buch gelesen.
复合英语动词“have read”在德语中翻译为“habe gelesen”,过去分词“gelesen”出现在德语名词“Buch”之后。
段嵌入
段嵌入是将多个句子连接起来的技术,以下是一个示例:
"I love pizza"
"Chicago pizza is my favorite"
两个句子如下组合:
tokens = [ [CLS], I, love, pizza, [SEP], Chicago,
pizza, is, my, favorite, [SEP]]
如您所见,标记[CLS]是第一个标记,[SEP]标记用于分隔句子,以及最后的标记。
现在你已经能够理解如何构建传递给编码器的序列:
INPUT = token embeddings + sequence embeddings +
positional embeddings
压缩变换器
DeepMind 创建了压缩变换器,作为变换器的一个扩展,它为长程记忆提供了一个改进的架构,并附带了一个用于语言模型中记忆推理的新数据集。
压缩变换器执行一个缩减操作:它将过去的隐藏激活(记忆)映射到一个更小的压缩表示(压缩记忆)集合。压缩变换器在其记忆和压缩记忆的集合上使用相同的注意力机制,学习查询其短期细粒度和长期粗粒度记忆。
本质上,压缩变换器保留了过去激活的精细记忆,这些记忆随后被压缩成更粗略的压缩记忆。
自动编码变换器
基于变换器的模型主要有两种类型:自动编码模型和自回归模型。自动编码模型和自回归模型之间的主要区别不在于它们的架构:区别在于执行的任务和训练。特别是,自动编码模型学习编码,而自回归模型可用于微调任务。
可能最著名的自动编码模型是 BERT,它执行两个预训练任务:MLM(掩码层建模)和 NSP(下一句预测)。MLM 将大约 15%的输入标记替换为一个掩码标记,然后尝试预测原始输入。
NSP 任务涉及确定一对句子是否以这种确切顺序出现在语料库中。BERT 学习了一种编码,它可以被用于问答等任务处理。记住,BERT 风格的模型在无监督数据集上执行预训练。
有趣的是,原始 transformer 的 解码器 组件不仅可以用于自动编码任务,还可以用于自回归任务;编码器组件与自回归任务类似。以下列表描述了自动编码、自回归和序列到序列模型的一些功能:
• 自动编码模型根据掩码元素对输入进行编码
• 自回归模型使用所有之前的预测来预测未来
• 序列到序列模型在不改变语义的情况下转换序列
“AUTO” 类
Hugging Face 的 AutoClasses 是方便的类,它们根据指定的参数值中的名称和路径检索适当的模型。这个集合中最简单的类是 AutoModel 类,它本质上是一个基类。实际上,transformers 包提供了具有 Auto 前缀的多个类,它们主要分为以下几组:
• AutoModel
• AutoConfig
• AutoTokenizer
Hugging Face 的 transformers 包提供了 AutoModel 类,您可以使用以下代码片段将其导入到您的代码中:
• from transformers import AutoModel
• from transformers import AutoModelForSequenceClassification
• from transformers import AutoModelForTokenClassification
例如,以下代码片段通过 AutoModel 类创建了一个 BertModel 实例:
model = AutoModel.from_pretrained('bert-base-cased')
AutoModelForSequenceClassification 类通过在预训练模型输出之上添加一个分类层来扩展 AutoModel 类的功能。
AutoModelForTokenClassification 类通过在现有模型之上提供分类层来扩展 AutoModel 类的功能。此外,此类还必须执行 NER(命名实体识别)任务。
以下三个类与本节开头列表中的三个类相对应,TF 前缀表示它们是为 TensorFlow 定制的:
• from transformers import TFAutoModel
• from transformers import TFAutoModelForSequenceClassification
• from transformers import TFAutoModelForTokenClassification
AutoConfig 实例创建了一个适当架构(即配置)的类实例,而 AutoTokenizer 实例创建了一个适当架构的类实例。
改进的架构
本节中的架构在原始 transformer 架构的基础上进行了改进:
• Reformer
• Longformer
• 开关
• ELECTRA
Reformer
Reformer 架构比原始 transformer 架构更高效,并提供了更大的上下文窗口。Reformer 架构通过两种技术实现了其效率:
• 局部敏感哈希(LSH)
• 可逆残差层
LSH 减少了处理长序列的复杂性,而可逆残差层在内存使用方面更高效。有关 Reformer 架构的更多信息,可在以下链接找到:
ai.googleblog.com/2020/01/reformer-efficient-transformer.html
Longformer
Longformer 模型是对变压器架构的修改,非常适合处理长文档。在原始的变压器架构中,计算注意力值的复杂度为 O(N²)(其中 N 是序列长度)。
相比之下,Longformer 模型将计算注意力的复杂度降低到 O(N)。有关 Longformer 模型的更多信息可在网上找到:
towardsdatascience.com/longformer-the-long-document-transformer-cdfeefe81e89
切换变压器:一万亿参数
Google 研究人员创建了包含一万亿参数的 Switch LLM,这几乎是 GPT-3(1750 亿参数)的六倍。这个模型是迄今为止创建的最大模型之一,并且比 Google 之前的 LLM T5-XXL(四倍快)。以下文章讨论了在修改后的变压器架构中“切换”机制是如何工作的:
towardsdatascience.com/understanding-googles-switch-transformer-904b8bf29f66
研究人员将简单的架构与大量数据集和参数数量相结合。由于大规模训练计算密集,他们采用了“切换变压器”,这是一种仅使用模型参数子集的技术。除了模型的稀疏性外,切换变压器巧妙地利用了 GPU 和 TPU 进行密集的矩阵乘法运算。
ELECTRA
ELECTRA 代表 Efficiently Learning an Encoder that Classifies Token Replacements Accurately(高效学习能够准确分类标记替换的编码器);它使用自监督学习。ELECTRA 可以以计算效率的方式预训练 transformer 网络。ELECTRA 涉及将文本编码器作为判别器而不是生成器进行预训练。
HUGGING FACE 管道及其工作原理
使用 Hugging Face 执行各种 NLP 相关任务需要三个主要步骤:
• 导入 Hugging Face 管道函数。
• 从 Hugging Face 加载预训练模型。
• 将一个句子(或字符串)指定给预训练模型进行处理。
在前述列表中指定为第一步的 Hugging Face 管道(task-name)函数提供了一个直观的机制,用于使用 NLP 模型进行推理。一个管道可以抽象出库中的大部分代码,并为各种任务提供专门的 API,其中一些如下所示:
• 自动语音识别管道
• 问题回答管道
• 翻译管道
此外,Hugging Face 管道函数是一个高级抽象,旨在执行以下任务:
• 对语料库中的文本进行分词
• 将文本转换为整数
• 将那些整数通过模型传递
如前所述的列表所示,你可能通过编程执行的任务由 Hugging Face 的管道函数执行。相比之下,TensorFlow 2 要求你使用适当的代码明确执行一些前面的任务。
除了预训练模型外,管道对象还可以指定分词器、特征提取器和底层框架。
第一步涉及导入 transformers 库的语句,如下所示:
from transformers import pipeline
第二步涉及指定一个字符串,该字符串表示你想要执行的任务。例如,下面的代码片段是用于情感分析的:
nlp = pipeline('sentiment-analysis')
前面的代码片段 1) 选择了一个预训练模型,2) 该模型已经针对情感分析进行了微调,3) 并且是英文的。如果你想看到一个简单且完整的代码示例,展示如何获取情感(无论是正面还是负面),请查看第八章中的代码示例。请注意,分数是一个介于 0 和 1 之间的数字,用于正面情感和负面情感,你也可以处理一个句子数组,而不是使用循环遍历每个句子。
在前面的代码片段中,当实例化分类器对象(称为 nlp)后,模型会被下载并存储在一个可以访问的位置,以便后续调用引用该模型的 Python 脚本(即,执行一次下载)。然而,如果你修改了模型,那么原始模型将再次被下载。
当你将一些文本传递给管道时,涉及三个主要步骤:
• 将文本预处理成模型可以理解的格式。
预处理后的输入被传递给模型。
模型的预测结果会进行后处理,这样你就可以理解它们了。
Hugging Face 可用的管道
之前,你看到了 transformers 可以执行的一系列 NLP 任务列表,这里为了方便起见再次列出:
• 特征提取(获取文本的向量表示)
填充掩码
命名实体识别 (NER)
问答
情感分析
• 摘要
• 文本生成
翻译
零样本分类
HUGGING FACE DATASETS
本节包含 Python 代码示例,展示了如何列出所有可用的 Hugging Face 数据集以及如何加载特定数据集。
列表 4.1 显示了 hf_datasets.py 的内容,展示了如何显示可用的 Hugging Face 数据集列表。
列表 4.1: hf_datasets.py
from datasets import list_datasets, load_dataset
from pprint import pprint
datasets_list = list_datasets()
print(f"HuggingFace provides {len(datasets_list)}
datasets")
print()
print("=> FIRST FIVE DATASETS:")
print(f"{datasets_list[:5]}")
print()
"""
print("=> LIST OF DATASETS:")
pprint(datasets_list,compact=True)
Print()
print("=> DETAILS OF EACH DATASET:")
# this list contains details of each dataset:
datasets_list = list_datasets(with_details=True)
pprint(datasets_list)
"""
列表 4.1 从 datasets 中导入两个类,然后初始化变量 datasets_list。这会导致调用 list_datasets() API,然后显示该变量中数据集的内容。使用 Python 3.7 启动 列表 4.1 中的代码,你将看到 Hugging Face 中超过 600 个数据集的部分列表。
HuggingFace provides 3753 datasets
=> FIRST FIVE DATASETS:
['acronym_identification', 'ade_corpus_v2',
'adversarial_qa', 'aeslc', 'afrikaans_ner_corpus']
=> DETAILS OF EACH DATASET:
[datasets.ObjectInfo(
id='acronym_identification',
description='Acronym identification
training and development sets for the acronym
identification task at SDU@AAAI-21.',
files=None
),
datasets.ObjectInfo(
id='ade_corpus_v2',
description=' ADE-Corpus-V2 Dataset:
Adverse Drug Reaction Data. This is a dataset for
Classification if a sentence is ADE-related (True)
or not (False) and Relation Extraction between
Adverse Drug Event and Drug. DRUG-AE.rel provides
relations between drugs and adverse effects. DRUG-
DOSE.rel provides relations between drugs and
dosages. ADE-NEG.txt provides all sentences in the
ADE corpus that DO NOT contain any drug-related
adverse effects.',
files=None
),
// details omitted for brevity
datasets.ObjectInfo(
id='ncoop57/csnc_human_judgement',
description='This new dataset is designed
to solve this great NLP task and is crafted with a
lot of care.',
files=None
)]
加载 Iris 数据集
列表 4.2 展示了如何在 Hugging Face 中加载 cifar10 数据集并显示其部分内容。
列表 4.2: hf_load_dataset.py
from datasets import load_dataset
train_ds, test_ds = load_dataset('cifar10',
split=['train[:4000]', 'test[:1000]'])
#display one column:
#print("=> train_ds['label']:")
#print(train_ds['label'])
#print()
"""
partial output:
[6, 9, 9, 4, 1, 1, 2, 7, 8, 3, 4, 7, 7, 2, 9, 9, 9,
3, 2, 6, 4, 3, 6, 6, 2, 6, 3, 5, 4, 0, 0, 9, 1, 3,
4, 0, 3, 7, 3, 3, 5, 2, 2, 7, 1, 1, 1, 2, 2, 0, 9,
5, 7, 9, 2, 2, 5, 2, 4, 3, 1, 1, 8, 2, 1, 1, 4
…
7, 3, 0, 8, 6, 7, 7, 0, 0, 1, 4, 1, 1, 6, 6, 6, 1,
3, 6, 0, 1, 3, 8, 5, 0, 1, 6, 5, 5, 4, 3, 9, 8, 6,
0, 5, 4, 9, 2, 8, 4, 8, 8, 2, 1, 4, 8, 6, 7, 3, 1,
3, 4, 9, 4, 8, 4, 5, 0, 9, 1, 3, 8, 7, 5, 4, 6]
"""
#display one row:
print("=> train_ds[7]['img'][0][0]:")
#print(train_ds[7]['img'][0][0])
# => output: [28, 35, 39]
print("train_ds[7]['img'][0]:")
print(train_ds[7]['img'][0])
# => output:
#[[28, 35, 39], [30, 34, 44], [33, 44, 47], [62,
83, 72], [63, 84, 72], [31, 49, 46], [29, 47, 50],
[42, 62, 63], [55, 77, 71], [67, 83, 74], [92, 108,
98], [76, 96, 85], [57, 80, 68], [75, 99, 88], [69,
82, 79], [57, 59, 60], [74, 72, 73], [98, 103,
100], [86, 99, 92], [71, 80, 73], [59, 67, 62],
[62, 67, 66], [57, 60, 63], [42, 46, 48], [51, 63,
57], [46, 60, 52], [41, 55, 47], [38, 53, 44], [37,
51, 41], [43, 56, 45], [52, 64, 53], [46, 58, 47]]
# approximately 46K output:
#print(train_ds[7])
# approximately 46K output:
#print(train_ds[7]['img'])
#display a batch of rows:
#print("=> train_ds[3:6]:")
#print(train_ds[3:6])
列表 4.2 以一个导入语句开始,然后使用 load_datasets() API 的结果初始化变量 train_ds 和 test_ds。启动 列表 4.2 中的代码,你将看到以下输出,包括首次启动此代码时的下载详情:
Downloading: 3.77kB [00:00, 1.44MB/s]
Downloading: 1.50kB [00:00, 401kB/s]
Downloading and preparing dataset cifar10/plain_
text (download: 162.60 MiB, generated: 418.17 MiB,
post-processed: Unknown size, total: 580.77 MiB) to
/Users/oswaldcampesato/.cache/huggingface/datasets/
cifar10/plain_text/1.0.0/951e017399fa3b30edfca5646
8a9
1ac6a03c9167c0b3f79367e777d1f9a0cf7e…
Downloading: 10%| | 17.6M/170M
Dataset cifar10 downloaded and prepared to /Users/
oswaldcampesato/.cache/huggingface/datasets/
cifar10/plain_text/1.0.0/951e017399fa3b30edfca56468
a91ac6a03c9167c0b3f79367e777d1f9a0cf7e.
Subsequent calls will reuse this data.
[00:14<05:30, 462kB/s]
加载日本数据集
列表 4.3 展示了如何在 Hugging Face 中加载一个日本数据集并显示其部分内容。
列表 4.3: hf_load_japanese.py
"""
Datasets involving japanese:
'covid_qa_ucsd', 'covid_tweets_japanese',
'covost2', 'cppe-5',
'snli', 'snow_simplified_japanese_corpus',
'so_stacksample',
'Atsushi/fungi_diagnostic_chars_comparison_
japanese',
'Atsushi/fungi_indexed_mycological_papers_
japanese',
"""
from datasets import load_dataset
snli = load_dataset('snli')
print("=> snli shape:",snli.shape)
print()
print("=> snli:")
print(snli)
print()
# split into train and test data:
train_ds, test_ds = load_dataset('snli',
split=['train[:4000]', 'test[:1000]'])
print("=> train_ds.column_names:")
print(train_ds.column_names)
Print()
print("=> train_ds.features:")
print(train_ds.features)
print()
for idx in range(0,5):
print("row",idx,"premise: ",train_ds[idx]
['premise'])
print("row",idx,"hypothesis:",train_ds[idx]
['hypothesis'])
print("row",idx,"label: ",train_ds[idx]
['label'])
print()
print()
"""
sample output:
{'premise': 'A person on a horse jumps over a
broken down airplane.', 'hypothesis': 'A person is
training his horse for a competition.', 'label': 1}
"""
列表 4.3 以一个导入语句开始,然后初始化变量 snli 为 snli 数据集的一个实例。接下来的代码块显示了 snli 数据集的形状和一些元数据。
列表 4.3 的下一部分执行数据的训练-测试分割,这是机器学习模型的常规步骤。接下来,显示 train_ds(数据集的训练部分)的列,然后是 train_ds 的特征的显示。
列表 4.3 的最后部分 包含一个循环,用于显示 train_ds 的前五行中前提、假设和标签的值。启动 列表 4.3 中的代码,你将看到以下输出:
=> snli shape: {'test': (10000, 3), 'train':
(550152, 3), 'validation': (10000, 3)}
=> snli:
DatasetDict({
test: Dataset({
features: ['premise', 'hypothesis',
'label'],
num_rows: 10000
})
train: Dataset({
features: ['premise', 'hypothesis',
'label'],
num_rows: 550152
})
validation: Dataset({
features: ['premise', 'hypothesis',
'label'],
num_rows: 10000
})
})
=> train_ds.column_names:
['premise', 'hypothesis', 'label']
=> train_ds.features:
{'premise': Value(dtype='string', id=None),
'hypothesis': Value(dtype='string',
id=None), 'label': ClassLabel(num_classes=3,
names=['entailment', 'neutral', 'contradiction'],
names_file=None, id=None)}
row 0 premise: A person on a horse jumps over a
broken down airplane.
row 0 hypothesis: A person is training his horse
for a competition.
row 0 label: 1
row 1 premise: A person on a horse jumps over a
broken down airplane.
row 1 hypothesis: A person is at a diner, ordering
an omelette.
row 1 label: 2
row 2 premise: A person on a horse jumps over a
broken down airplane.
row 2 hypothesis: A person is outdoors, on a horse.
row 2 label: 0
row 3 premise: Children smiling and waving at
camera
row 3 hypothesis: They are smiling at their parents
row 3 label: 1
row 4 premise: Children smiling and waving at
camera
row 4 hypothesis: There are children present
row 4 label: 0
转换器和情感分析
情感分析可用于确定客户对特定产品或事件的情感。考虑以下句子对,其中下面第一句的情感显然是积极的,第二句的情感显然是消极的:
-
“我真的很喜欢披萨。”
-
“我不喜欢每天开车。”
现在考虑以下句子,它包含了一个积极的情感和一个消极的情感:
- “这部电影很棒,但票价太高了。”
如果我们将 -1、0 和 +1 分别分配给消极、中立和积极的短语或句子,那么这可能意味着将 +1、0 和 -1 分配给前面的三个句子。然而,将 0 分配给第 3) 句子没有意义,因为 +1 和 -1 “抵消”并产生值 0。
基于转换器的模型源代码
Hugging Face 提供了以下 Github 仓库,其中包含许多基于转换器的模型的开源代码:
github.com/huggingface/transformers/blob/main/src/transformers/models/
这里列出了基于 Transformer 的模型的部分列表,其中一些将在后续章节中讨论:
• albert
• bart
• bert
• bert_generation
• bert_japanese
• bertweet
• big_bird
• deberta
• distilbert
• flaubert
• gpt2
• gpt_neo
• longformer
• megatron_bert
• megatron_gpt2
• pegasus
• perceiver
• reformer
• roberta
• squeezebert
• t5
• visual_bert
• xlm
• xml_roberta
总结
本章首先描述了 Transformer 架构中的位置编码,这涉及到正弦()和余弦()函数,以及三种类型的位置编码。
然后,你获得了关于 Transformer 架构编码器组件的额外见解,然后是解码器组件的概述。此外,你学习了如何在 LLM 中决定是否使用编码器、解码器或同时使用编码器和解码器。
此外,你学习了 Reformer、Longformer 和 Switch Transformer,这些改进了原始的 Transformer 架构。
最后,你看到了如何使用 Hugging Face 数据集以及如何加载一个日语文本数据集。
第五章
BERT 家族介绍
本章提供了关于基于 Transformer 的 BERT 模型的信息,以及“BERT 家族”中的几个其他模型,以及这些 LLM 之间的一些差异描述。
本章的第一部分讨论了提示工程的各种方面,以及 LLM 开发的各个方面。
本章的第二部分介绍了 BERT 及其一些特性,之后你将学习 BERT 的训练过程以及可用的 BERT 模型。此外,你还将了解 BERT 与预 BERT NLP 模型的区别。
本章的第三部分从 Transformer 架构的角度讨论 BERT,然后讨论如何使用 BERT 进行 NER 任务。本节包括 BERTopic 和主题建模。本章的第四部分讨论了 BERT 和数据清洗任务,例如归一化以及正则表达式在 BERT 数据清洗中的相关性。
本章的第五部分深入探讨了 BERT 嵌入层,以及嵌入的类型,例如令牌嵌入、段嵌入和位置嵌入。你还将学习如何创建、训练和保存一个 BERT 模型。
本章的第六部分涉及 BERT 的内部工作原理,例如 MLM、NSP 和特殊的 BERT 令牌。你还将了解 MLM 的替代方案(例如,PLM 和 MLNET)以及 NSP 的替代方案(例如,SOP)。本节还包括对子词令牌化、BPE、WordPiece 和 SentencePiece 等技术的讨论。
本章的第七部分讨论了 BERT 中的句子相似性和词上下文,然后是生成 BERT 令牌的示例。
本章的第八部分包含了一系列基于 BERT 训练的模型列表,以及它们功能的简要描述。此外,当前的代码示例需要 Python 3.7,您可以从互联网上下载。
最后一个部分简要介绍了各种基于 BERT 的模型,其中一些可能足够有趣,足以通过其他在线资源深入了解这些模型。
什么是提示工程?
你可能已经听说过文本生成器,如 GPT-3,以及来自 OpenAI 的文本到图像生成器 DALL-E 2、来自 AI21 的 Jurassic、来自 Midjourney Inc.的 Midjourney 和来自 Stability AI 的 Stable Diffusion。提示工程指的是设计基于文本的提示,使基于 AI 的系统能够生成更接近用户想要从 AI 中“检索”的内容的输出。通过类比,将提示视为类似教练的角色:他们提供建议和意见,帮助人们在特定任务中表现更好。
由于提示是基于单词的,挑战在于学习不同单词如何影响生成的输出。此外,预测系统对给定提示的反应也很困难。例如,如果你想生成一幅风景画,暗色调风景和亮色调风景之间的区别是直观的。然而,如果你想生成一幅美丽的风景画,AI 系统会如何生成相应的图像呢?正如你可以推测的那样,“具体”的单词对于从文本生成图像的 AI 系统来说比抽象或主观的单词更容易。让我们考虑之前的例子:你将如何可视化以下内容?
• 一幅美丽的风景
• 一首美丽的歌曲
• 一部美丽的电影
尽管提示工程始于文本到图像生成,但还有其他类型的提示工程,例如基于音频的提示,它解释强调的文本和从语音中检测到的情感,以及基于草图(sketch-based)的提示,它可以从绘画中生成图像。最近关注的焦点是用于生成视频的基于文本的提示,这为艺术家和设计师提供了令人兴奋的机会。图像到图像处理的例子可以在这里找到:
huggingface.co/spaces/fffiloni/stable-diffusion-color-sketch
提示和补全
提示是用户提供给大型语言模型(LLMs)的文本字符串,而补全是用户从 LLMs 收到的文本。提示帮助 LLMs 完成请求(任务),它们的长度可以不同。尽管提示可以是任何文本字符串,包括随机字符串,但提示的质量和结构会影响补全的质量。
将提示视为向 LLMs 提供“指导”的机制,或者甚至将其视为“教练”LLMs 以提供所需答案的方式。提示中的标记数加上完成中的标记数最多为 2,048 个标记。在第八章中,您将看到调用 GPT-3 的 completion() API 的基于 Python 的代码示例。
提示类型
以下列表包含 LLMs 的知名类型提示:
• 零样本提示
• 单次提示
• 少样本提示
• 指令提示
一个零样本提示包含对任务的描述,而一个单样本提示由一个完成任务的单个示例组成。如您所推测,少样本提示由多个示例组成(通常在 10 到 100 个之间)。在所有情况下,建议提供对任务或任务的清晰描述:更多的任务为 GPT-3 提供更多信息,这反过来又可能导致更准确的完成。
T0(代表“零样本”)是一个有趣的 LLM:尽管 T0 比 GPT-3 小 16 倍(11 GB),但在语言相关任务上 T0 的表现超过了 GPT-3。T0 可以在未见过的 NLP 任务上表现良好(即,对 T0 来说是新任务),因为它是在包含多个任务的数据库上训练的。
以下网页提供了 T0 的 GitHub 仓库,一个在浏览器中直接训练 T0 的网站,以及有关 T0 的更多详细信息以及 T0 的 3GB 版本:
github.com/bigscience-workshop/t-zero
如您所推测,T0++基于 T0,并且它接受了超出 T0 训练任务集的额外任务训练。
另一个重要细节是,前面列表中的前三个提示也分别被称为零样本学习、单样本学习和少样本学习。
指令提示
指令提示用于微调 LLMs,并指定 LLM 预期在其响应中遵守的格式(由您确定)。您可以准备自己的指令提示,或者您可以使用包含不同任务模板以及不同数据集的提示模板库。各种提示指令模板公开可用,例如以下链接提供了提示模板(参见后续章节中的示例)用于 Llama(在第九章中讨论):
github.com/devbrones/llama-prompts
pub.towardsai.net/llama-gpt4all-simplified-local-chatgpt-ab7d28d34923
反向提示
另一种技术使用反向顺序:输入提示是答案,响应是与答案相关的提问(类似于一个流行的游戏节目)。例如,给定一个法语句子,你可能会问模型,“什么英语文本可能导致这个法语翻译?”
系统提示与代理提示
系统提示和代理提示之间的区别通常出现在对话式人工智能系统和聊天机器人设计的情况下。
系统提示 通常是由系统给出的初始消息或提示,用于指导用户可以做什么或设定对交互的期望。它通常作为介绍或指导用户如何进行的方式。以下是一些系统提示的例子:
• “欢迎来到 ChatBotX!您可以问我关于天气、新闻或体育的问题。今天我能帮您做什么?”
• “你好!按 1 键获取账户详情。按 2 键获取技术支持。”
• “问候!输入‘order’跟踪您的包裹或输入‘help’寻求帮助。”
相比之下,代理提示 是在交互过程中,AI 模型或代理对用户输入的响应生成的消息。它是对话中来回交流的一部分。代理提示指导用户提供更多信息,澄清歧义,或引导用户采取特定行动。以下是一些代理提示的例子:
User: "I'm looking for shoes."
Agent Prompt: "Great! Are you looking for men's or
women's shoes?"
User: "I can't log in.”
Agent Prompt: "I'm sorry to hear that. Can you
specify if you are having trouble with your
password or username?"
User: "Tell me a joke."
Agent Prompt: "Why did the chicken join a band?
Because it had the drumsticks!"
两者之间的基本区别在于它们的目的和在交互中的位置。系统提示通常位于交互的开始,为对话设定场景。代理提示发生在对话过程中,根据用户输入引导对话的方向。
这两种类型的提示对于创建流畅直观的对话体验至关重要。它们指导用户,并有助于确保系统有效地理解和解决用户的需求。
提示模板
提示模板 是预定义的格式或结构,用于指导模型或系统执行特定任务。它们是生成提示的基础,其中模板的某些部分可以填充或定制,以产生各种特定的提示。通过类比,提示模板是您可以在某些文本编辑器中定义的宏的对应物。
提示模板在处理语言模型时特别有用,因为它们提供了一种在多个任务或数据点查询模型的一致方式。特别是,提示模板可以更容易地
• 确保在多次查询模型时的一致性
• 简化批量处理或自动化。
• 减少向模型提出问题时出现的错误和变化
例如,假设您正在使用一个 LLM,并且您想将英文句子翻译成法语。相关的提示模板可能如下所示:
“将以下英文句子翻译成法语:{sentence}”
注意,{sentence} 是一个占位符,您可以用任何英文句子替换它。
您可以使用前面的提示模板生成特定的提示:
“将以下英文句子翻译成法语:‘你好,你好吗?’”
• “将以下英文句子翻译成法语:‘我喜欢冰淇淋。’”
正如你所见,提示模板能够让你轻松地为不同的句子生成各种提示,而不必每次都重写整个指令。实际上,这个概念可以扩展到更复杂的任务,并且可以根据应用情况包含多个占位符或更复杂的结构。
针对不同 LLM 的提示
GPT-3、ChatGPT 和 GPT-4 都是基于 transformer 架构的 LLM,在底层机制上本质上是相似的。ChatGPT 基本上是 GPT 模型的一个版本,专门针对对话交互进行了微调。GPT-4 是 GPT-3 在规模和能力方面的演变或改进。
这些模型提示的差异主要源于特定的用例和上下文,而不是模型之间的固有差异。以下是一些基于用例的提示差异。
GPT-3 可以用于广泛的任务,而不仅仅是对话,从内容生成到代码编写。以下是 GPT-3 的两个提示示例:
• “将以下英文文本翻译成法语:‘你好,你好吗?’”
• “编写一个计算数字阶乘的 Python 函数。”
ChatGPT 专门针对对话交互进行了微调。以下是与 ChatGPT 进行两次不同对话的提示示例:
• 用户:“你能帮我做家庭作业吗?”
ChatGPT:“当然!你需要在哪个科目或主题上获得帮助?”
• 用户:“讲一个笑话。”
• ChatGPT:“为什么鸡穿过操场?为了到达另一边的滑梯!”
GPT-4 提供了更大的规模和改进,因此提示的性质与 GPT-3 相似,但可能会产生更准确或更细微的输出。以下是 GPT-4 的两个提示示例:
• “提供量子力学与广义相对论之间关系的详细分析。”
• “基于后末日世界主题的充满希望的故事。”
这三个模型都接受自然语言提示并产生自然语言输出。你与他们交互的基本方式保持一致。
主要差异来自模型被使用的上下文以及任何应用的微调。例如,ChatGPT 被设计成更具对话性,因此虽然你可以使用 GPT-3 进行聊天,但 ChatGPT 可能会产生更具上下文相关性的对话输出。
当直接与这些模型交互,尤其是通过 API 时,你还可以控制诸如“温度”(控制随机性)和“最大标记数”(控制响应长度)等参数。调整这些参数可以塑造响应,无论你使用的是哪个 GPT 变体。
从本质上讲,尽管底层模型在规模和特定的训练/微调方面存在差异,但你提示它们的方式在很大程度上保持一致:清晰、具体的自然语言提示会产生最佳结果。
措辞不当的提示
当构建提示时,应尽可能清晰和具体,以引导响应朝所需的方向发展。含糊或模糊的提示可能导致各种响应,其中许多可能对用户的实际意图没有帮助或不相关。
表述不佳的提示通常含糊不清、模棱两可或过于宽泛,可能会导致 AI 模型产生混淆、误解或非特定的响应。以下是一些表述不佳的提示示例,以及相应的解释:
“告诉我关于那个东西的事情。”
问题:过于含糊。指的是哪个“东西”?
“为什么会发生这样的事情?”
问题:没有上下文。正在讨论的是哪个事件或情况?
“解释内容。”
问题:过于宽泛。应该解释哪些具体的“内容”?
“做需要做的事情。”
问题:不明确。需要采取哪些具体行动?
“我想获取信息。”
问题:不够具体。需要哪种类型的信息?
“你能从那个地方帮我拿到那个东西吗?”
问题:“东西”和“地方”都不明确。
“我在哪里可以买到那个人的书?”
问题:含糊的引用。“那个人”是谁?
“你是如何进行这个过程的?”
问题:指的是哪个“过程”?
“描述这个主题的重要性。”
问题:“主题”未指定。
“为什么它是好是坏?”
问题:没有上下文。“它”指的是什么?
“帮助解决这个问题。”
问题:模糊。需要协助解决的具体问题是什么?
“任务需要考虑的事项。”
问题:不明确。正在讨论的是哪个“任务”?
“这是如何工作的?”
问题:缺乏具体性。“这”指的是什么?
LLM 开发方面
如果你已经阅读了前面的章节,你应该对仅编码器 LLM、仅解码器 LLM 以及基于编码器和解码器的 LLM 的架构有所了解。为了方便起见,本节提供了属于这三种类型模型的语言模型列表。请注意,仅解码器模型,如 GPT-x 系列的 LLM,在第七章和第八章中进行了讨论。
考虑到前面的观点,一些较为知名的基于编码器的 LLM 包括以下内容:
• AlBERT
• BERT
• DistilBERT
• ELECTRA
• RoBERTa
前面的 LLM 非常适合执行 NLP 任务,如命名实体识别和抽取式问答任务。除了仅编码器 LLM 之外,还有一些知名的基于解码器的 LLM,包括以下内容:
• CTRL
• GPT/GPT-2
• Transformer XK
前面的 LLM 执行文本生成,也可以执行下一个单词的预测。最后,一些知名的基于编码器/解码器的 LLM 包括以下内容:
• BART
• mBART
• Marian
• T5
前面的 LLM 执行摘要、翻译和生成问答。
最近的一个趋势是针对 LLM 使用微调、零/一/少量样本训练和基于提示的学习。微调通常伴随着微调数据集,如果后者不可用(或不可行),少量样本训练可能是一个可接受的替代方案。
Jurassic-1 LLM 训练的一个结果是,在性能方面,更宽泛、更浅的模型优于更窄、更深的模型,因为更宽的上下文允许并行执行更多的计算。
Chinchilla 的另一个结果是,在包含大量标记的语料库上训练的小型模型可能比在数量较少的标记上训练的大型模型表现更好。
GlaM 和 Switch LLM(都来自 Google)的成功表明,稀疏 Transformer 与 MoE(专家混合)结合也是一个有趣的方向,未来可能带来更好的结果。
此外,还存在数据“过度策划”的可能性,也就是说,进行非常详细的数据策划以去除看似虚假的标记,并不能保证模型在这些策划的数据集上会产生更好的结果。
提示词的使用揭示了一个有趣的细节:相似但不同的提示词可能导致实质上不同的响应。因此,目标是创建精心设计的提示词,这些提示词既经济实惠,但又可能是一项有些难以捉摸的任务。
另一个发展领域涉及对基准的需求,这些基准利用更好的和更复杂的数据集,尤其是在 LLM 超越人类性能的情况下。具体来说,当一个基准的所有现代 LLM 都能通过该基准的测试套件时,该基准就会过时。XNLI 和 BigBench(“超越模仿游戏基准”)就是这样的两个基准。
以下网页提供了一个相当广泛的列表,包括通用的 NLP 基准以及特定语言的 NLP 基准:
mr-nlp.github.io/posts/2021/05/benchmarks-in-nlp/
以下网页提供了一个单语 Transformer 预训练语言模型的列表:
mr-nlp.github.io/posts/2021/05/tptlms-list/
LLM 尺寸与性能
让我们考虑一下尺寸与性能的问题:虽然更大的模型如 GPT-3 可以比小模型表现得更好,但这并不总是如此。特别是,GPT-3 的变体模型结果不一:一些较小的变体几乎与 GPT-3 表现相同,而一些较大的模型仅略好于 GPT-3。
最近的一个趋势是开发基于 Transformer 架构解码器组件的模型。这些模型通常通过与其他 LLM 的零样本、单样本和少样本训练性能来衡量。这种趋势,以及更大 LLM 的发展,预计在可预见的未来将继续。
有趣的是,仅解码器的大型语言模型可以执行诸如标记预测等任务,并且可以在 SuperGLUE 等基准测试中略优于仅编码器模型。然而,这种基于解码器的模型通常比基于编码器的模型大得多,而后者的效率通常高于前者。
在优化模型性能方面,硬件是另一个需要考虑的因素,这可能会产生更高的成本,因此可能仅限于少数几家公司。由于硬件的高成本,另一个举措是在法国的 Jean Zay 超级计算机上训练 LLMs:
venturebeat.com/2022/01/10/inside-bigscience-the-quest-to-build-a-powerful-open-language-model/
LLMs 的涌现能力
大型语言模型(LLMs)的涌现能力指的是在较大的模型中存在而在较小的模型中不存在的功能。简单来说,随着模型规模的增加,存在一个不连续的“跳跃”,其中能力在较大的模型中显现出来,没有明显或清晰的原因。
涌现能力的有趣之处在于,通过额外的扩展,有可能扩展语言模型的能力。更详细的信息可以在以下论文中找到(《大型语言模型的涌现能力》):
诺贝尔奖获得者物理学家菲利普·安德森在他的 1972 年论文《更多即是不同》中提出了以下观点:
“涌现是指系统在数量上的变化导致行为在质量上的变化。”
有趣的是,在描述了一个场景,其中少样本提示被认为是涌现的(引用先前的 arXiv 论文):
“当模型在达到一定规模之前随机性能,之后性能显著提高至远超随机水平时,通过少样本提示执行任务的能力是涌现的。”
(请务必查看论文中的表 1,它提供了关于“少样本提示能力”(例如,真实性、MMLU 基准)以及“增强提示能力”(例如,思维链和指令遵循)的详细信息。)
注意,由于(根据定义)涌现能力在较小的模型中不存在,因此涌现能力不能通过较小模型的扩展行为进行预测。毫无疑问,将会有更多研究探索进一步模型扩展在大型语言模型(LLMs)中导致更多涌现能力的程度。
卡普兰与欠训练模型
卡普兰等人提供了关于语言模型性能的(经验)幂律,他们认为这取决于以下因素:
• 模型大小
• 数据集大小
• 训练所需的计算量
Kaplan 等人断言,改变网络宽度或深度的影响很小。他们还声称,非常大型模型的最佳训练涉及相对适中的数据量。包含相关详细信息的论文可在网上获取:
然而,Chinchilla 是一个 70B 的 LLM,它在一个比 Kaplan 等人推荐的大小大得多的数据集上进行了训练。实际上,Chinchilla 达到了超越以下 LLM 性能的 SOTA 状态,这些 LLM 的大小都在 Chinchilla 的 2 到 7 倍之间:
• Gopher (280B)
• GPT-3 (175B)
• J1-Jumbo (178B)
• LaMDA (137B)
• MT-NLG (530B)
此外,Chinchilla LLM 的创造者撰写了“神经语言模型缩放定律”的论文,其中包含了各种模型大小完全训练而不是欠训练所建议的标记数(参见该文档中的表 3)。例如,175B、520B 和 1 万亿参数模型的建议训练集大小分别为 370 亿标记、110 亿标记和 2120 亿标记。同一表中最大的条目是 10 万亿参数的 LMM,建议的训练集大小为 2162 万亿标记。
显然,一个超过 1 万亿参数的 LLM 面临着创建推荐大小数据集的重大挑战,正如 Chinchilla 的作者在论文中所描述的。一个有趣的可能性涉及 ASR(本书未讨论),这可能通过将音频转录成文本来生成超过 10 万亿标记的数据集。确实,一些推测表明 GPT-4 可能会利用 ASR 来创建这样的数据集。
什么是 BERT?
BERT 代表双向编码器来自 transformers。BERT 通过从未标记文本中预训练深度双向表示,使得预训练的 BERT 模型可以通过添加一个额外的输出层来微调,以创建适用于广泛 NLP 任务的 SOTA 模型。实际上,BERT 在十一个自然语言处理任务上实现了新的 SOTA 结果。
BERT 在问答(QnA)和语言推理等任务上实现了 SOTA 结果,其架构只有一些小的变化。同时,BERT 的计算成本很高:在 10000 个句子的语料库中确定最相似的句子对需要超过 60 小时的计算,涉及大约 5000 万次推理计算。
BERT 训练
BERT 在维基百科的大量未标记数据集上进行预训练,除了执行 NLP 相关任务外,BERT 还可以微调以执行其他任务。BERT 使用注意力机制来生成涉及给定单词之前和之后的单词上下文的词嵌入。相比之下,word2vec 等算法是无上下文的,因此词嵌入没有任何上下文信息。
注意,BERT 的微调步骤与 BERT 的预训练步骤不同:前者涉及标记数据,而后者涉及未标记数据。
BERT 模型
BERT 最著名的两个版本被称为 BERT-Base 和 BERT-Large。BERT-Base 由 12 层、12 个注意力头和 1.1 亿个参数组成。BERT-Large 是一个更大的预训练模型,由 24 层、16 个注意力头和 3.4 亿个参数组成。然而,也存在几个较小的基于 BERT 的模型,如下面的列表所示:
BERT-medium L=8 and H=512
BERT-small L=4 and H=512
BERT-mini L=4 and H=256
BERT-tiny L=2 and H=128
BERT 可以与 Hugging Face transformers 库结合使用,该库提供用于执行各种任务的类,例如问答和序列分类。
由于 BERT 没有使用解码器组件,因此 BERT 不适合文本生成。此外,BERT 也不适合无监督任务(例如聚类)或语义相似度。
BERT 架构
BERT 基于谷歌在 2017 年开发的 Transformer 架构。BERT 只需要 Transformer 架构的编码器部分来生成语言表示模型。BERT 的词汇量大约有 30,000 个单词,BERT 中的每个词嵌入有 768 个特征,这意味着每个词嵌入是一个 1x768 的浮点数向量。
BERT 模型由 Transformer 架构的编码器组件组成,这意味着它是一个仅编码器架构。BERT 的主要部分是一个非常大的 12 层神经网络,用于处理文本。然而,您可以替换 BERT 中的最终分类器为特定任务的模型,这使得您能够利用 BERT 的所有知识。
最后的训练步骤被称为“微调”,因为将 BERT 适应您自己的任务所需的训练量与谷歌预训练 BERT 所需的量相比非常小。微调步骤是一个相对较小的任务,但仍可能涉及大量的计算。
BERT 特性
BERT 有大约 30,000 个学习到的原始向量。此外,大约 80% 的这些原始向量对应于“正常”单词(即它们存在于英语词典中)。其余的 20% 是由 WordPiece 创建的子词:这些子词的形式为“##s”或“##ed”。后者子词对于检测句子中动词的过去式很有用。此外,BERT 的词汇量中大约有 45% 是大写字母,25% 是小写字母(大约)。
BERT 的局限性
尽管 BERT 可以执行文本相关任务、解释文本和做出预测,但 BERT 无法执行以下任务:
• 生成新的文本
• 在不同语言之间翻译文本
• 生成对问题的回答
前述限制的原因在于 BERT 仅基于 Transformer 架构的编码器组件。相比之下,基于解码器组件的 LLM,例如基于 GPT 的模型,能够执行前述列表中的所有任务。
然而,原始的 Transformer 模型是在手动创建的翻译示例上训练的,而 BERT 是一个预训练模型,它使用了一个显著更大的数据集,该数据集包含未标记的文本。
BERT 的训练方式
BERT 的训练过程首先基于特定任务的数据执行预训练步骤,然后是微调步骤。例如,如果您想使用 BERT 进行情感分析,您需要一个指定句子是正面还是负面情感的标记语料库。此外,数据集被分为训练部分和测试部分,正如您在之前的章节中看到的代码示例。这同样是机器学习算法的典型特征,这些算法涉及监督学习,如线性回归和分类算法。
在训练步骤之前,BERT 执行 MLM,这包括 1) 大约用 15% 的标记替换为 token,2) 另外一组随机选择的单词被替换为不同的(即错误的)集合。实际的训练步骤涉及在随机选择的 512 个标记序列上训练 BERT,目标是让 BERT 对 所有 输入标记做出预测。
除了 MLM,BERT 还执行下一句预测(NSP)。这项任务涉及连接句子对:一些对是相邻句子,而其他对则来自随机位置。这个任务的目标是让 BERT 正确预测句子对是否连续。
预训练步骤完成后,微调步骤涉及在一系列样本任务上训练模型。例如,如果您想训练 BERT 执行问答任务,那么在问答数据语料库上微调一个预训练模型(该模型是在相关任务上训练的)。
BERT-Base 和 BERT-Large
BERT-Base 由 12 个编码器层组成,每一层都堆叠在另一层之上。所有编码器都使用 12 个注意力头。编码器中的前馈网络包含 768 个隐藏单元,因此从 BERT 基础模型获得的表达式大小也将是 768。
相比之下,BERT-Large 由 24 个垂直堆叠的编码器层组成,每个层都有 16 个注意力头。每个编码器层中的前馈网络包含 1,024 个隐藏单元。因此,从 BERT-Large 获得的表达式大小将是 1,024。此外,BERT-Large 模型包含 3.4 亿个参数。
BERT 与早期 NLP 模型对比
BERT 有几个重要的方面使其与依赖于算法的模型(如 word2vec)区分开来。首先,BERT 不执行词干提取操作:相反,BERT 通过 WordPiece 进行子词标记化。主要区别在于,词干提取会丢弃词尾,而 WordPiece 不会丢弃词尾。
第二,BERT 创建的是上下文词嵌入,而 word2vec 创建的是分布词嵌入。具体来说,BERT 使用句子中的所有词语为给定句子中的每个词语生成词嵌入,并且每个词嵌入都是特定于该词语出现的句子。因此,出现在多个句子中的词语具有不同的词嵌入,而 word2vec 使用二元组来计算句子中词语的单个词嵌入。
第三,BERT 不使用余弦相似度(不是直接使用)来确定两个词语之间相似的程度。然而,如果你在合适的数据上微调 BERT,例如以下存储库中的数据和代码示例,就可以使用 BERT 与余弦相似度结合:
github.com/UKPLab/sentence-transformers
BERT 自注意力
在第一章中,我们讨论了基于 transformer 的模型中的注意力机制。不同类型的 LLMs 使用不同类型的自注意力。具体来说,基于编码器的模型,如 BERT,使用双向自注意力。基于解码器的 LLMs,如 GPT,使用单侧自注意力,这意味着每个标记只关注其左侧的上下文(而不是右侧)。
BERT 如何处理输入嵌入
与按顺序处理词标记的 RNNs 和 LSTMs 不同,BERT 并行处理一组输入嵌入,为每个输入嵌入生成一个包含 768 个浮点数的嵌入。
BERT 还可以处理可变长度的句子,因为 BERT 通过深度双向变换生成单个加权向量,这些变换考虑了句子中词语之间的上下文关系,而不是简单地平均词嵌入。
注意,虽然 transformer 架构确实允许对句子中的词语进行并行处理,但这是一种自注意力机制的特征,而不是加权平均的并行计算。
BERT 的输入表示可以是单个文本句子或一对文本句子。在两个句子的情况下,第一个句子中的每个标记接收嵌入 A,第二个句子中的每个标记接收嵌入 B,句子之间由标记[SEP]分隔。BERT 的输入序列最大长度为 512 个标记:其他模型支持的最大输入序列长度为 1,024 个标记。
默认情况下,BERT 支持两种预训练任务,MLM 和 NSP,这些任务在本节中已简要讨论,并在本章后面也将进行讨论。
Pyramid-BERT
亚马逊创建了 Pyramid-BERT,这是一种减少基于 BERT 模型的各种方面,同时只减少了 1.5% 准确率的技术:
• 减少了训练时间
• 减少了推理时间
• 减少了内存占用
除了前面的改进之外,BERT 模型可以处理更长的文本序列。Pyramid-BERT 通过处理中间层来移除一些单个词嵌入来实现其改进。具体来说,Pyramid-BERT 移除了在最终编码器处理标记之后存在于 [CLS] 标记后的冗余。
BERTScore
BERTScore 比较了所生成的内容与预期生成的内容的意义。给定一个句子和一个生成的句子,BERTScore 的计算如下:
• 将两个句子都通过预训练的 BERT 模型。
• 为每个单词生成上下文嵌入。
• 执行 n 平方计算。
• 计算每个参考词与每个候选词的相似度。
• 选择与候选词最相似的参考词。
• 计算精确度、召回率和 F 分数。
BERT 和 NLP 任务
NLP 模型可以执行各种任务,准确度各不相同,其中一些列在这里:
• 文档分类
• 问答
• 领域特定文本
• 非英语应用
• 命名实体识别
• 将文本与其他特征类型结合
注意,文档分类可能涉及多类分类和多标签标签分类(即数据点有多个标签)。
BERT 在众多任务中取得了成功,例如基于内容的推荐、问答(QnA)和视频处理。在无监督预训练阶段,BERT 可以处理非常大的未标记数据集,随后是涉及有限标记数据的微调阶段。因此,基于 BERT 的语言模型非常受欢迎,因为它们实现了 SOTA 准确率。
由于处理一个极其庞大的语料库耗时,可以通过一种称为“数据并行模型训练”的技术来减少训练时间,该技术涉及将训练数据集划分为多个子集,每个子集由模型副本进行处理。
此外,在每次优化步骤中,计算出的梯度在所有模型副本中都会进行均值化,从而确保所有模型副本中的权重更新以及模型状态都是相同的。
BERT 词汇和未知词汇
原始的 BERT 模型具有大约 30,000 个标记的固定词汇量。其中五分之三到四分之五实际上是整个单词,其余的单词集合由子词或“词片段”组成。BERT 使用表示对应标记、段和位置的嵌入组合来表示给定的输入标记。
当 BERT 遇到词汇表外的(OOV)词时,其分词器使用 WordPiece 将词分解成一组子词。
BERT 和词序
BERT 没有保留关于词序的信息:它可以应用于任何顺序的词(或像我们在实践中那样并行一次性处理)。相比之下,RNNs 和 LSTMs 可以通过按顺序输入词来维持词序。一个特定的词是通过将当前词与先前处理词的输出相结合来处理的。
BERT 通过使用位置嵌入来考虑词序,这些嵌入被设计用来给模型提供关于序列中每个词的位置信息。BERT 为序列中每个可能的位置都有一个独特的位置嵌入,直到其最大长度(BERT 为 512)。
BERT 和“过长”句子
BERT-Base 最多可以处理 512 个输入标记,因为这是 PE 对输入序列长度的最大限制。如果输入句子超过这个最大长度,你有以下几种选择:
-
使用可以处理 2,048 个输入标记的更大 BERT 模型。
-
截断长度超过 512 个标记的输入句子。
-
丢弃长度超过 512 的句子(不推荐)。
-
将每个句子分割成 512 个标记的块。
第 3 种方法是最不推荐的方法:它类似于通过丢弃异常值来处理异常值。尽管第 4 种方法很有吸引力,但块之间可能存在逻辑相关的依赖关系,而这种技术无法捕捉到。
填充句子
BERT 可以应用于长度最多为 512 个标记的任何句子。然而,为了支持一次性处理多个文本样本的并行处理,BERT 的实现需要你指定所有输入文本的单个固定长度。
为了并行化,所有输入文本序列都被填充或截断到单个固定长度,
• 较短的固定长度将使 BERT 的训练和评估更快。
• BERT 有一个硬上限,即 512 个标记。
填充与截断
填充是必需的,当输入句子或文档长度不同时。填充字符可以是值 0 或特定于算法的其他值。左填充是在句子或文档前添加填充字符,而右填充是在句子或文档后添加填充字符。
此外,还有几种方法可以确定所需的填充字符数,其中一些列在这里:
• 每批文档动态填充。
• 将每个文档填充到最长文档的长度。
• 将每个文档填充到平均文档长度。
第一种方法涉及动态填充文档,使得填充长度基于当前批次的文档。
当存在与文档长度相关的异常值时,基于最长文档的填充是不推荐的。例如,可能有一份文档包含 50 K 个标记,而其他所有文档最多只包含 1 K 个标记。
截断涉及指定最大文档长度,然后简单地丢弃文档中位置超过指定最大长度的标记。不幸的是,这种技术可能会丢失包含在丢弃标记中的有价值信息。
一种修改后的截断形式涉及将较短的文档填充到指定的长度(如 1 K),然后将包含 50 K 个标记的文档分割成一组 50 个较短的文档,每个文档包含 1 K 个标记。然而,以这种方式分割文档可能会导致在部分文档集中引用到末尾的几个标记中丢失上下文信息。
如果你使用平均文档长度作为最大文档长度的值,你也可能会因为丢弃标记而丢失信息。
另一个重要细节:文档截断不会影响诸如情感分析和垃圾邮件检测等任务,因为它们的预测仅包含一个值。然而,机器翻译和命名实体识别可能会因文档截断而受到不利影响。
BERT 的输入标记限制为 512 个,而 GPT-2 的输入标记限制为 1,024 个,这意味着你必须遵守这些限制(以及其他语言模型的限制)以输入文档的长度为准。
BERT 和 Transformer 架构
BERT 是基于 Transformer 架构的知名早期预训练语言模型之一,这一事件被称为“NLP 的 ImageNet 时刻”。
BERT 架构由一个仅包含多个垂直堆叠的编码器层的编码器组件组成。BERT 在大量数据集上以自监督的方式进行训练。BERT 获得了对语言的统计理解,并可以作为语言模型使用。
有许多预训练的 BERT 模型变体,它们在不同的数据集(如法律、生物医学、科学等)上进行了预训练。其中许多模型变体具有改进的性能特征(如 RoBERTa、ALBERT 和 DistilBERT),并且它们由大型组织预训练,然后这些模型可供公众使用。由于预训练是一个昂贵且耗时的过程,大量预训练模型的可获得性对社区来说是一个巨大的好处。
有趣的是,OpenAI 的第一个 GPT 模型(在第七章第 14 页中讨论)在 BERT 之前出现,也对 BERT 的发展产生了影响。OpenAI 使用了语言建模,这是一个无监督学习任务,它预测给定句子中的下一个单词。
BERT 和双向性
如其名称所示,BERT 支持双向性以处理输入序列。特别是,BERT 将输入序列作为整个句子来处理,而不是单个标记,从而从输入文本的左右两个方向获得上下文。
其他模型,如 ELMo 和 GPT,都使用单向技术。ELMo 实际上支持两遍机制:一个模型以从左到右的方式训练,另一个模型以从右到左的方式训练,然后将这两个模型连接起来创建一个单一模型。尽管如此,BERT 的双向性优于 ELMo 的两阶段方法。
BERT 与文本处理
本节和几个子节讨论了 BERT 如何执行以下 NLP 任务:
• 标记分类
• 命名实体识别(NER)
• 文本分类
标记分类
标记级任务涉及对输入中的每个标记进行预测。BERT 接受一组词嵌入并生成一组更好的词嵌入,因此标记级任务是“最自然”的应用。
BERT 与 NER
基于 BERT 的语言模型可以针对特定领域进行微调,用于下游任务,如命名实体识别(NER)和关系抽取(RE)。回顾第四章,输入序列中的每个标记都是一个由三个向量组合而成的:词嵌入、段嵌入和位置嵌入。您可以在 BERT 模型之上添加一个密集分类层来使用 BERT 进行 NER。这个层的尺寸与您想要识别的命名实体类别数量相匹配(例如,人物、组织、地点,以及不属于任何命名实体的“O”标签)。
现在您可以在 NER 数据集上微调模型。对于输入中的每个标记,使用 BERT 分词器生成一个上下文化的嵌入。这个嵌入通过分类层传递,以产生该标记的预测。然后模型被训练以最小化其预测与真实 NER 标签之间的差异。
您可能会想知道子词的预测是如何处理的:毕竟,这些可能是没有自身意义的词素。因此,需要一些后处理步骤来合并属于同一单词的子词的预测,并确保实体识别的一致性。
文本分类
BERT 可以应用于传统的 NLP 任务,如文本分类。由于 BERT 生成一系列嵌入,我们可以对其进行一些处理(如求平均值)然后将结果传递给分类器。
接下来,在 BERT 模型之上添加了一个密集的分类层。这个层的大小对应于分类任务中的类别数量。仅使用来自 BERT 最后一层的[CLS]标记(token)的表示作为序列的聚合表示,并将其传递到分类层。换句话说,BERT 处理整个序列,然后使用[CLS]标记的上下文表示来进行分类。
BERT 与数据清洗任务
数据清洗是机器学习的一个基本过程,其步骤取决于数据类型和模型类型。例如,kNN 和 SVM 等分类算法涉及处理缺失和不正确的数据作为数据清洗任务,而与 NLP 相关的数据集可能涉及归一化。
特别是,以下列表包含与基于 BERT 模型的数据集相关的数据清洗任务:
• 移除停用词。
• 执行归一化。
• 使用正则表达式。
• 不进行词干提取。
• 执行词形还原。
然而,前三个项目是以下原因的“条件”任务。
-
移除停用词有时可以帮助减少噪声并关注文本中最具信息量的单词。然而,BERT 被设计用于处理原始文本数据,有时移除停用词可能会移除 BERT 可以利用的重要上下文信息。
-
执行归一化可能包括将所有文本转换为小写或纠正错别字等任务,这有助于标准化文本数据。然而,BERT 在大语料库上进行了预训练,没有进行广泛的归一化以保留自然语言的细微差别,因此广泛的归一化并不总是必要的。
-
使用正则表达式可以用于清理和结构化文本数据,例如删除不需要的字符或模式。然而,应谨慎使用,以避免删除重要信息。
在您清理完数据集后,下一步涉及将数据集拆分为训练集和测试集,通常使用 Scikit-learn 的 train_test_split()函数。
归一化
归一化是将数据集中的数值列缩放到具有共同尺度的过程。此外,缩放按以下方式进行:
-
将值缩放到[0,1]的范围。
-
而不丢失信息。
-
不扭曲值域中存在的任何差异。
您可以通过 scikit-learn 库中的 MinMaxScaler 类执行数据归一化。
在您清理完数据集后,您需要执行其他任务,例如使用 scikit-learn 函数 train_test_split()将数据集拆分为训练集和测试集。接下来,通常执行分词,这在本章后面将讨论。
正则表达式
正则表达式在文本字符串、文档或语料库中搜索和替换文本时提供了强大的功能。由于本书的重点是基于 transformer 的架构和模型,因此省略了正则表达式的代码示例。如果您想熟悉正则表达式,或者可能希望精通它们的使用,有一些免费的在线资源可用。
三种 BERT 嵌入层
BERT 有三种类型的嵌入层:
• 令牌嵌入
• 段嵌入
• 位置嵌入
BERT 的词嵌入由一个包含每个令牌 768 个浮点数的向量组成,这些向量是通过下一段中描述的三个浮点向量的分量和创建的。
每个令牌嵌入的形状为(1, 768),它们只是单词的向量表示。每个段嵌入的形状为(1, 768),这是一个向量表示,有助于 BERT 区分配对输入序列。每个位置嵌入的形状为(1, 768),它使 BERT 能够跟踪输入序列中令牌的位置。这三个前面的向量相加形成另一个向量,该向量被传递到 BERT 的编码层。
三种位置嵌入类型
BERT 可以处理最大长度为 512 的输入序列。由于 BERT 使用固定长度序列,您需要确定一组可变长度输入序列的最大长度,这些序列必须截断到 512。少于 512 个令牌的句子可以通过填充使其长度达到 512。
下一步涉及计算一个包含每个令牌位置信息的兼容向量。具体来说,嵌入层可以通过一个(512,768)的表来表示,其中第i行包含第i位置中单词的向量表示。
BERT 还有一个特殊的标记[CLS],用于第一个位置,以及[SEP]标记用于连续句子之间的分隔符。生成的输出由三个向量的基于组件的总和组成:包含令牌嵌入的向量、包含段嵌入的向量和包含位置嵌入的向量。
作为提醒,因果注意力意味着令牌只能访问同一文本字符串中作为其一部分的过去令牌,而非因果注意力没有这种限制。此外,还有以下类型的与位置相关的编码技术:
• 位置嵌入
• 位置编码
• 相对位置
关于 BERT 的主要点包括以下架构和训练相关的细节:
• 非因果注意力(与 GPT-2 对比)
• 位置嵌入
• 无监督预训练
• 监督微调
创建一个 BERT 模型
Hugging Face transformers 包包含 AutoModel 类,它允许您从检查点实例化一个模型。这个类是一个包装类,设计得可以确定给定检查点的正确模型。或者,如果您对所需的模型有深入了解,您可以指定显式的类。让我们看看它是如何与 BERT 模型一起工作的。
列表 5.1 展示了 bert_model.py 文件的内容,该文件说明了如何创建一个 BERT 模型。
列表 5.1:bert_model.py
from transformers import BertConfig, BertModel
# 1) initialize the config object
config = BertConfig()
# 2) initialize a BERT model:
model = BertModel(config)
# display the contents of the configuration object:
print(config)
列表 5.1 以导入语句开始,然后初始化变量 config 为 BertModel 类的实例。接下来,变量 model 被初始化为 BertModel 的实例,包括 config 变量。最后的代码片段显示了 config 变量的内容。运行列表 5.1 中的代码,您将看到以下输出:
BertConfig {
"attention_probs_dropout_prob": 0.1,
"classifier_dropout": null,
"gradient_checkpointing": false,
"hidden_act": "gelu",
"hidden_dropout_prob": 0.1,
"hidden_size": 768,
"initializer_range": 0.02,
"intermediate_size": 3072,
"layer_norm_eps": 1e-12,
"max_position_embeddings": 512,
"model_type": "bert",
"num_attention_heads": 12,
"num_hidden_layers": 12,
"pad_token_id": 0,
"position_embedding_type": "absolute",
"transformers_version": "4.10.3",
"type_vocab_size": 2,
"use_cache": true,
"vocab_size": 30522
}
训练和保存 BERT 模型
前一节向您展示了如何创建一个 BERT 模型,本节将向您展示如何保存一个 BERT 模型。列表 5.2 展示了如何创建 BERT 模型并将其保存在您的机器上的内容。
列表 5.2:save_bert_model.py
from transformers import BertConfig, BertModel
from transformers import BertConfig, BertModel
# initialize the config object
config = BertConfig()
# BERT model initialized with random values:
model = BertModel(config)
#model.save_pretrained(a_directory_location)
model.save_pretrained("/tmp")
列表 5.2 首先从 transformers 库中导入几个类,然后初始化变量 config 和 model,就像在列表 5.1 中看到的那样。最后的代码片段将保存的模型保存在/tmp 目录下,您也可以保存在不同的位置。运行列表 5.2 中的代码,您将在/tmp 目录中看到以下输出:
-rw-r--r-- 1 618 Nov 4 13:15 config.json
-rw-r--r-- 1 438013119 Nov 4 13:15 pytorch_model.
bin
文件 pytorch_model.bin 被称为“状态字典”,因为它包含模型的所有权重,所以它是一个大文件。文件 config.json 包含模型架构的属性。
BERT 的内部工作原理
BERT 实现了一些有趣的技巧,其中一些如下列出:
• MLM(掩码语言模型)
• NSP(下一句预测)
• 特殊标记([CLS]和[SEP])
• 语言掩码
• WordPiece(BERT 中使用子词标记化)
• SentencePiece(用于 ALBERT)
以下小节将简要讨论前面列表中的每个主题,以及 PLM 和 MLNET(都是 MLM 的替代方案)和 SOP(NSP 的替代方案)。
什么是 MLM?
掩码语言模型(MLM)是在未标记数据上的 BERT 无监督预训练任务,在此过程中 BERT 处理了维基百科以及 BookCorpus 的内容。在这个任务中,大约 15%的单词被替换为token,然后 BERT 会预测缺失的单词。请注意,这个任务是在提交给 BERT 的数据“块”上执行的。另一个预训练任务是下一句预测(NSP)。
在维基百科中,许多单词涉及日期、人名和地名,其中一些被token替换。在训练过程中,BERT 正确地确定了缺失的标记。注意,附录包含有关迁移学习、预训练和微调语言模型的一些信息。
PLM 和 MPNet:MLM 的替代方案
在上一节中,你学习了 MLM,这是一种从语料库中选择 15%的标记并替换其中约 80%的技术。BERT 等模型试图在预训练步骤中找到正确的标记。
另一种技术是排列语言模型(PLM),它检查预测标记之间的依赖关系。与 BERT 不同,BERT 不执行 PLM,而 XLNet 支持 PLM 来确定这些依赖关系。尽管 XLNet 引入了一种可以潜在地改变标记原始位置的排列操作,但它仍然通过使用考虑了位置编码的 transformer 架构来保持位置信息。然而,排列操作确实会在学习标记之间真实位置关系时引入复杂性。
第三种技术是MPNet,这是一种预训练方法,它提供了 BERT 和 XLNet 的优点,同时避免了它们的局限性。使用 MPNet 的代码和预训练模型可在github.com/microsoft/MPNet找到。
什么是 NSP?
下一句预测(NSP)是一个 BERT(另一个预训练任务是 MLM)执行的现成预训练任务。NSP 以以下方式组合句子对:
• 在 50%的句子对中,第二句话与第一句话在逻辑上是相关的。
• 在 50%的句子对中,第二句话与第一句话在逻辑上没有关联。
NSP 的目的在于识别哪些句子对是正确的,哪些句子对是错误的。
另有一点需要提及。NSP 通常用“句子对”来描述,这可以进一步明确如下:
• “句子”是一段“文本”。
• 一段“文本”可以比一个句子更长。
• 一段“文本”可以比一个句子更短。
• 对的长度必须 <= 512 个标记。
NSP 与 SOP
虽然 NSP 是一个有价值的预训练任务,但还有替代方案。句子顺序预测(SOP)是一个与 NSP 有些相似性的例子。关于 SOP 的一个有趣细节是,有时文本的两段会以相反的顺序呈现,而不是“正常”的顺序。
事实上,RoBERTa 和 XLNet 的架构师用 SOP 替换了 NSP,因为后者在他们的模型上比 NSP 产生了更好的结果。此外,SOP 是一个比 NSP 更具挑战性的任务,因为 NSP 可以通过比较两段文字的主题来规避:如果它们不同,那么第二段文字不太可能跟随第一段。
NSP 与语言模型
BERT 是为双向编码设计的,这意味着 BERT 可以以两种方式处理句子:从左到右以及从右到左(即类似于双向 LSTMs)。
因此,在 MLM 和 NSP 任务中,你可以一次性给 BERT 整个输入序列,BERT 会将其中的所有单词都纳入其预测中。
相比之下,如果你在基于 GPT 的模型上执行语言模型,这些模型只能以从左到右的方式处理句子。解码器组件中的掩码注意力元素阻止模型“查看”句子中的下一个词,并迫使模型“预测”下一个词。
输入标记的实时处理
BERT 具有双向能力,在处理整个输入句子时可能具有优势。然而,在某些情况下,你可能需要按顺序处理输入序列,而不是处理完整的输入序列。
例如,语音识别通常是按标记逐个进行的,尽管有一个例外。具体来说,德语的结构将助动词放在子句或句子的最后位置,而日语有一种语言结构,其中人类翻译者在提供另一种语言(如英语)的翻译之前会先听完整句话。
另一个用例涉及字符串的自动完成或下一词预测。从某种意义上说,GPT-3 在更大规模上执行“自动完成”:给定基于文本的输入提示,GPT-3 可以生成整个句子、段落,甚至文章。
总结
本章从 BERT 模型及其一些特性的介绍开始。你看到了 BERT 是如何训练的以及一些可用的 BERT 模型。接下来,你学习了 BERT 与早期 NLP 模型的不同之处。
此外,你学习了如何使用 BERT 进行命名实体识别(NER),以及 BERTopic 和主题建模。然后你看到了如何使用 BERT 执行数据清理任务,例如归一化以及正则表达式在 BERT 数据清理中的相关性。
接下来,你学习了 BERT 嵌入层,包括标记嵌入、段嵌入和位置嵌入。你看到了一个基于 Python 的代码示例,解释了如何创建、训练和保存 BERT 模型。
然后,我们讨论了 BERT 的一些内部工作原理,例如 MLM、NSP 和特殊的 BERT 标记。你学习了子词标记化、BPE、WordPiece 和 SentencePiece。
此外,你学习了 BERT 中的句子相似度、词上下文,以及生成 BERT 标记的 Python 代码示例。
第六章
BERT 家族的深入探讨
本章继续讨论基于 transformer 的 BERT 模型,包括 BERT 特定的标记器、句子相似度、生成 BERT 标记以及 LLMs 的 BERT 家族。
本章的第一部分包含了一个基于 Python 的特殊 BERT 标记代码示例,随后是关于 BERT 标记化器和 DistilBERT 标记化器的讨论。本节还展示了如何使用 BERT 进行情感分析。本章的第二部分描述了涉及 BERT 编码的步骤序列。然后你将了解 BERT 中的句子相似性以及 Sentence-BERT。你还将看到如何生成 BERT 标记。
本章的第三部分提供了 BERT 家族中包含的 LLM 列表,例如 ALBERT、BART 和 DistilBERT。本节还提供了一个基于 Python 的简短代码示例,用于在您的笔记本电脑上训练 BERT 模型,以及有关 RoBERTa LLM 的信息。本章的第四部分包含了一系列主题,例如翻译成意大利语和日语,基于 Web 的 BERT 工具,使用 BERT 进行主题建模,以及 Google PaLM。
特殊 BERT 标记的代码示例
BERT 使用特殊标记 [CLS] 来指示文本字符串的开始,并使用特殊标记 [SEP] 来分隔句子。例如,考虑以下句子:
Pizza with four toppings and trimmings.
以下是对前一句的 BERT 标记化:
[‘[CLS]’, ‘pizza’, ‘with’, ‘four’, ‘topping’,
‘##s’, ‘and’, ‘trim’, ‘##ming’, ‘##s’, ‘.’,
‘[SEP]’]
列表 6.1 显示了 bert_special_tokens.py 的内容,说明了如何在 BERT 中显示特殊标记。
列表 6.1:bert_special_tokens.py
import transformers
import numpy as np
# instantiate a BERT tokenizer and model:
print(“creating tokenizer…”)
tokenizer = transformers.BertTokenizer.from_
pretrained(‘bert-base-uncased’, do_lower_case=True)
print(“creating model…”)
nlp = transformers.TFBertModel.from_pretrained
(‘bert-base-uncased’)
# hidden layer with embeddings:
text1 = “cell phone”
input_ids1 = np.array(tokenizer.encode(text1))
[None,:]
embedding1 = nlp(input_ids1)
print(“input_ids1:”)
print(input_ids1)
print()
print(“tokenizer.sep_token: “,tokenizer.sep_
token)
print(“tokenizer.sep_token_id:”,tokenizer.sep_
token_id)
print(“tokenizer.cls_token: “,tokenizer.cls_
token)
print(“tokenizer.cls_token_id:”,tokenizer.cls_
token_id)
print(“tokenizer.pad_token: “,tokenizer.pad_
token)
print(“tokenizer.pad_token_id:”,tokenizer.pad_
token_id)
print(“tokenizer.unk_token: “,tokenizer.unk_
token)
print(“tokenizer.unk_token_id:”,tokenizer.unk_
token_id)
print()
列表 6.1 以两个导入语句开始,然后初始化变量 tokenizer 为一个预训练模型的实例。接下来,变量 nlp 被初始化为预训练模型的实例。
列表 6.1 的下一部分初始化变量 text1 为一个由两个单词组成的字符串,随后是变量 input-ids1,它包含这两个单词的标记,以及两个特殊标记。
最后一部分代码块包含一组 print() 语句,用于显示几个特殊标记及其 token_id 值。启动 列表 6.1 中的代码,你将看到以下输出:
creating tokenizer…
creating model…
input_ids1:
[[ 101 3526 3042 102]]
tokenizer.sep_token: [SEP]
tokenizer.sep_token_id: 102
tokenizer.cls_token: [CLS]
tokenizer.cls_token_id: 101
tokenizer.pad_token: [PAD]
tokenizer.pad_token_id: 0
tokenizer.unk_token: [UNK]
tokenizer.unk_token_id: 100
基于 BERT 的标记化器
尽管基于 BERT 的模型有相当大的相似性,但它们的标记化器之间仍存在差异。以下小节将确定 BERT 标记化器和 DistilBERT 标记化器之间的差异。
BERT 标记化器
列表 6.2 显示了 bert_tokenizer.py 的内容,展示了 BERT 如何标记化一个英文句子。
列表 6.2:bert_tokenizer.py
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained
(‘bert-base-uncased’)
sentence = “I love Chicago pizza”
encoding = tokenizer.encode(sentence)
print(“=> sentence:”,sentence)
print(“=> encoding:”,encoding)
print(“=> tokens: “,tokenizer.convert_ids_to_tokens
(encoding))
print()
sentence = ‘My favorite word is syzygy’
encoding = tokenizer.encode(sentence)
print(“=> sentence:”,sentence)
print(“=> encoding:”,encoding)
print(“=> tokens: “,tokenizer.convert_ids_to_tokens
(encoding))
列表 6.2 以一个导入语句开始,然后初始化变量 tokenizer 为一个预训练模型的实例。接下来,变量 sentence 被初始化为一个文本字符串(sentence),变量 encoding 被初始化为调用 tokenizer 的 encode() 方法的结果。然后显示所有三个变量的值。
列表 6.2 的下一部分 将 sentence 初始化为另一个文本字符串,并通过第二次调用 encode() 方法重新初始化编码。再次显示三个变量的值。运行 列表 6.2 中的代码,你会看到以下输出:
=> sentence: I love Chicago pizza
=> encoding: [101, 1045, 2293, 3190, 10733, 102]
=> tokens: [‘[CLS]’, ‘i’, ‘love’, ‘chicago’,
‘pizza’, ‘[SEP]’]
=> sentence: My favorite word is syzygy
=> encoding: [101, 2026, 5440, 2773, 2003, 25353,
9096, 6292, 102]
=> tokens: [‘[CLS]’, ‘my’, ‘favorite’, ‘word’,
‘is’, ‘sy’, ‘##zy’, ‘##gy’, ‘[SEP]’]
DistilBERT 分词器
每种 BERT 变体都有特定的输入类型,可以使用不同的参数。例如,DistilBERT 确实使用与 BERT 相同的特殊标记,但 DistilBERT 不使用 token_type_ids。
列表 6.3 显示了 distilbert_tokenizer.py 的内容,展示了 DistilBERT 以与 BERT 相同的方式对英语句子进行分词。
列表 6.3: distilbert_tokenizer.py
from transformers import DistilBertTokenizer
tokenizer = DistilBertTokenizer.from_pretrained
(‘distilbert-base-uncased’)
sentence = “I love Chicago pizza”
encoding = tokenizer.encode(sentence)
print(“=> sentence:”,sentence)
print(“=> encoding:”,encoding)
print(“=> tokens: “,tokenizer.convert_ids_to_tokens
(encoding))
print()
sentence = ‘My favorite word is syzygy’
encoding = tokenizer.encode(sentence)
print(“=> sentence:”,sentence)
print(“=> encoding:”,encoding)
print(“=> tokens: “,tokenizer.convert_ids_to_tokens
(encoding))
列表 6.3 与 列表 6.2 在前两行有所不同,它们将 BERT 替换为 DistilBERT,并将 bert-base-uncased 替换为 distilbert-base-uncased。运行 列表 6.3 中的代码,你会看到以下输出,与 列表 6.2 的输出相同:
=> sentence: I love Chicago pizza
=> encoding: [101, 1045, 2293, 3190, 10733, 102]
=> tokens: [‘[CLS]’, ‘i’, ‘love’, ‘chicago’,
‘pizza’, ‘[SEP]’]
=> sentence: My favorite word is syzygy
=> encoding: [101, 2026, 5440, 2773, 2003, 25353,
9096, 6292, 102]
=> tokens: [‘[CLS]’, ‘my’, ‘favorite’, ‘word’,
‘is’, ‘sy’, ‘##zy’, ‘##gy’, ‘[SEP]’]
使用 DistilBERT 进行情感分析
在 第二章 中,你学习了如何使用分词器和 DistilBERT 模型。在本节中,你将了解如何使用 DistilBERT 进行文本分类。
代码示例中的管道类“抽象化”了许多细节,使得运行推理变得更容易,但不如手动设置模型和分词器灵活。如果你想在自定义数据上微调模型,你需要比管道提供的更详细的设置。此外,代码示例使用了 DistilBERT 的默认情感分析配置。如果你有一个自定义训练的模型,请将 distilbert-base-uncased 替换为你的模型路径。
列表 6.4 显示了 distilbert_sentiment_analysis.py 的内容,展示了如何进行情感分析。
列表 6.4: distilbert_sentiment_analysis.py
from transformers import pipeline, DistilBertTokenizer,
DistilBertForSequenceClassification
# Load DistilBERT tokenizer and model
tokenizer = DistilBertTokenizer.from_pretrained
(‘distilbert-base-uncased’)
model = DistilBertForSequenceClassification.from_
pretrained(‘distilbert-base-uncased’)
# Create the sentiment analysis pipeline
classifier = pipeline(‘sentiment-analysis’,
model=model, tokenizer=tokenizer)
# Test the classifier
sentences = [“This is an amazing product!”,
“I don’t really like this movie.”]
predictions = classifier(sentences)
for text, prediction in zip(sentences,
predictions):
label = prediction[‘label’]
score = prediction[‘score’]
print(f”’{text}’ is classified as {label} with
a score of {score:.4f}”)
列表 6.4 以一个导入语句开始,然后初始化变量 tokenizer 和变量 model,这两个变量分别来自导入的第二个和第三个类。接下来,通过调用 pipeline() 并指定 sentiment_analysis 任务,以及引用先前定义的模型和分词器来初始化变量 classifier。
列表 6.4 的下一部分 定义变量 sentences 为字符串列表(简短句子),然后使用变量 sentences 调用分类器初始化变量 predictions。
列表 6.4 的最后部分 包含一个循环,该循环遍历句子及其对应的预测。在每次迭代中,变量 label 和 score 被初始化并打印出来。运行列表 6.13 中的代码,你会看到以下输出:
‘This is an amazing product!’ is classified as
LABEL_0 with a score of 0.5325
‘I don’t really like this movie.’ is classified as
LABEL_0 with a score of 0.5307
前面输出的有趣之处在于标签的值 LABEL_0,它表明 DistilBERT 正在显示一个内部变量。实际上,DistilBERT 对其他显然高度正面或高度负面的句子报告了非常相似的分数。
然而,DistilBERT 主要是一个预训练的语言表示模型,它被训练来预测句子中的掩码标记,并且现成的 DistilBERT 并没有针对情感分析进行特定微调。它更像是一个通用表示,能够捕捉英语(或根据特定模型变体,其他语言)的语义。对于像情感分析这样的特定任务,你通常会取预训练的 DistilBERT 模型,并在情感分析数据集上对其进行微调。
BERT 编码:步骤序列
BERT 执行以下步骤序列,所有这些步骤都已在之前的代码片段中进行了说明:
步骤 1:对文本进行分词。
步骤 2:将标记映射到它们的 ID。
步骤 3:添加特殊的 [CLS] 和 [SEP] 标记。
作为一个简单的例子,句子“我买了一本书”总共有六个标记(四个单词标记,以及开始和结束标记),以及以下索引:
[CLS] 101
i 1,045
got 2,288
a 1,037
book 2,338
[SEP] 101
列表 6.5 展示了 bert_encoding_plus.py 的内容,它说明了如何显示 BERT 中的特殊标记。
列表 6.5:bert_encoding_plus.py
import transformers
import numpy as np
# instantiate a BERT tokenizer and model:
print(“creating tokenizer…”)
tokenizer = transformers.BertTokenizer.from_
pretrained(‘bert-base-uncased’, do_lower_case=True)
print(“creating model…”)
nlp = transformers.TFBertModel.from_pretrained
(‘bert-base-uncased’)
text=”When were you last outside? I have been
inside for 2 weeks.”
encoding = tokenizer.encode_plus(
text,
max_length=32,
add_special_tokens=True, # Add ‘[CLS]’ and
‘[SEP]’
return_token_type_ids=False,
pad_to_max_length=True,
return_attention_mask=True,
return_tensors=’pt’, # Return PyTorch tensors
)
print(“encoding.keys():”)
print(encoding.keys())
print()
print(“len(encoding[‘input_ids’][0]):”)
print(len(encoding[‘input_ids’][0]))
print()
print(“encoding[‘input_ids’][0]:”)
print(encoding[‘input_ids’])
print()
print(“len(encoding[‘attention_mask’][0]):”)
print(len(encoding[‘attention_mask’][0]))
print()
print(“encoding[‘attention_mask’]:”)
print(encoding[‘attention_mask’])
print()
print(“tokenizer.convert_ids_to_tokens
(encoding[‘input_ids’][0]):”)
print(tokenizer.convert_ids_to_tokens
(encoding[‘input_ids’][0]))
Print()
列表 6.5 以两个导入语句开始,然后以与之前的代码示例相同的方式初始化了 tokenizer 和 nlp 变量。接下来,变量 text 被初始化为一个文本字符串,然后是变量 encoding,它充当参数及其值的配置样式的“持有者”。
列表 6.5 的最后部分由六个 print() 语句对组成,每个语句都显示在 encoding 变量中定义的参数/值对。运行 列表 6.5 中的代码,你会看到以下输出:
creating tokenizer…
creating model…
encoding.keys():
dict_keys([‘input_ids’, ‘attention_mask’])
len(encoding[‘input_ids’][0]):
32
encoding[‘input_ids’][0]:
tensor([[ 101, 2043, 2020, 2017, 2197, 2648,
1029, 1045, 2031, 2042, 2503, 2005, 1016, 3134,
1012, 102, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0]])
len(encoding[‘attention_mask’][0]):
32
encoding[‘attention_mask’]:
tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0]])
tokenizer.convert_ids_to_tokens(encoding[‘input_
ids’][0]):
[‘[CLS]’, ‘when’, ‘were’, ‘you’, ‘last’, ‘outside’,
‘?’, ‘i’, ‘have’, ‘been’, ‘inside’, ‘for’, ‘2’,
‘weeks’, ‘.’, ‘[SEP]’, ‘[PAD]’, ‘[PAD]’, ‘[PAD]’,
‘[PAD]’, ‘[PAD]’, ‘[PAD]’, ‘[PAD]’, ‘[PAD]’,
‘[PAD]’, ‘[PAD]’, ‘[PAD]’, ‘[PAD]’, ‘[PAD]’,
‘[PAD]’, ‘[PAD]’, ‘[PAD]’]
BERT 中的句子相似度
Word2vec 和 GloVe 使用词嵌入来找到两个词之间的语义相似度。然而,句子除了包含两个词之间的关系外,还包含额外的信息。以下一对句子清楚地说明了需要上下文感知的必要性:
狗没有穿过街道,因为它太窄了。
狗没有穿过街道,因为它太累了。
句子相似度的一种技术涉及计算每个句子中单词的词嵌入的平均值,然后计算由此产生的单词嵌入对的余弦相似度。这种方法简单且计算效率高,但它可能不如更复杂的方法那样有效地捕捉句子语义的细微差别,因为它没有考虑到单词的顺序和它们之间的关系。它本质上将句子视为“词袋”。然而,尽管其简单,它仍然可以在许多情况下提供相当好的结果,尤其是在与高质量的词嵌入一起使用时。
请记住,虽然许多词嵌入技术,包括 Word2Vec 和 GloVe,都是通过使用大型语料库的无监督方式训练的,但这并不是所有词嵌入技术都必须无监督的内在要求。还有监督和半监督的词嵌入技术。
BERT 中的词上下文
列表 6.6 显示了 bert_context.py 的内容,说明了 BERT 如何为在不同上下文中使用的相同单词生成不同的词向量。
要运行 列表 6.6 中的代码,请确保你已经通过在命令行中输入以下命令安装了 transformers 库:
pip3 install transformers
注意: 此代码下载了一个 536 MB 的 BERT 模型。
列表 6.6: bert_context.py
import transformers
text1 = “cell phone”
# instantiate a BERT tokenizer and model:
tokenizer = transformers.BertTokenizer.from_
pretrained(‘bert-base-uncased’, do_lower_case=True)
nlp = transformers.TFBertModel.from_pretrained
(‘bert-base-uncased’)
# hidden layer with embeddings:
input_ids1 = np.array(tokenizer.encode(text1))
[None,:]
embedding1 = nlp(input_ids1)
# display text1 and its context:
print(“text1:”,text1)
print(“embedding1[0][0]:”)
print(embedding1[0][0])
print()
text2 = “cell mate”
# hidden layer with embeddings:
input_ids2 = np.array(tokenizer.encode(text2))[None,:]
embedding2 = nlp(input_ids2)
# display text2 and its context:
print(“text2:”,text2)
print(“embedding2[0][0]:”)
print(embedding2[0][0])
列表 6.6 从导入语句开始,然后以与之前代码示例中完全相同的方式初始化变量 tokenizer、nlp、input_ids1 和 embedding1。接下来的代码块显示了 text1 和 embedding1[0][0] 的值。
列表 6.6 的下一部分几乎与之前的代码块相同,基于用 text2 替换 text1。以下是 列表 6.6 的输出:
text1: cell phone
embedding1[0][0]:
tf.Tensor(
[[-0.30501425 0.14509355 -0.18064171 …
-0.3127299 -0.12173399
-0.09033043]
[ 0.80547976 -0.15233847 0.61319923 …
-0.7498784 0.00167803
-0.11698578]
[ 1.0339862 -0.66511637 -0.17642722 …
-0.24407595 0.03978422
-0.8694502 ]
[ 0.87851435 0.10932285 -0.27658027 …
0.18180653 -0.5829581
-0.34113947]], shape=(4, 768), dtype=float32)
text2: cell mate
embedding2[0][0]:
tf.Tensor(
[[-0.24141303 0.1146469 -0.13710016 …
-0.2908613 -0.04577148
0.2965925 ]
[ 0.05608664 -1.0035615 0.12738925 …
-0.30271983 0.17530476
0.7245784 ]
[ 0.2818157 -0.28047347 -0.6547173 …
0.04996978 0.01698243
0.03285426]
[ 1.039136 0.12364347 -0.2661501 …
0.09439699 -0.7794917
-0.24966209]], shape=(4, 768), dtype=float32)
列表 6.6 还生成了以下信息性消息:
Some weights of the model checkpoint at bert-
base-uncased were not used when initializing
TFBertModel: [‘nsp___cls’, ‘mlm___cls’]
- This IS expected if you are initializing
TFBertModel from the checkpoint of a model trained
on another task or with another architecture
(e.g. initializing a BertForSequenceClassification
model from a BertForPretraining model).
- This IS NOT expected if you are initializing
TFBertModel from the checkpoint of a model that
you expect to be exactly identical (initializing
a BertForSequenceClassification model from a
BertForSequenceClassification model).
All the weights of TFBertModel were initialized
from the model checkpoint at bert-base-uncased.
If your task is similar to the task the model of
the ckeckpoint was trained on, you can already
use TFBertModel for predictions without
further training.
什么是 Sentence-BERT?
Sentence-BERT 是一个基于 BERT LLM 的预训练 LLM,它执行 Sentence-BERT-Networks,这些网络修改了 BERT 和 RoBERTa 架构。然后,输出是一个固定大小的句子嵌入,它通过以下技术生成:
-
向 transformers 的输出添加一个池化操作。
-
计算所有输出向量的平均值。
-
计算输出向量的最大时间值。
有几个可下载的预训练 Sentence-BERT 模型可用:
public.ukp.informatik.tu-darmstadt.de/reimers/sentence-transformers/v0.2/
现在你已经看到了一个例子,其中 BERT 为在不同上下文中使用的单词生成不同的词向量,让我们看看 BERT 标记,这是下一节的主题。
生成 BERT 标记(1)
列表 6.7 展示了 bert_tokens1.py 的内容,说明了如何将文本字符串转换为 BERT 兼容字符串,然后将后者字符串分词成 BERT 标记。
列表 6.7:bert_tokens1.py
from transformers import BertTokenizer, BertModel
tokenizer = BertTokenizer.from_pretrained
(‘bert-base-uncased’)
text1 = “Pizza with four toppings and trimmings.”
marked_text1 = “[CLS] “ + text1 + “ [SEP]”
tokenized_text1 = tokenizer.tokenize(marked_text1)
print(“input sentence #1:”)
print(text1)
print()
print(“Tokens from input sentence #1:”)
print(tokenized_text1)
print()
print(“Some tokens in BERT:”)
print(list(tokenizer.vocab.keys())[1000:1020])
print()
列表 6.7 导入了 BertTokenizer 和 BertModel,并使用前者初始化 tokenizer 变量。接下来,将 text1 初始化为一个文本字符串,并在 text1 前添加[CLS],然后在其后添加[SEP]。最后初始化的变量是 tokenized_text1,它被分配给在 marked_text1 上调用 tokenizer()方法的结果。
接下来的三个 print()语句块分别显示了 text1、tokenized_text1 和一系列 20 个 BERT 标记的内容。运行列表 6.7 中的代码,你会看到以下输出:
input sentence #1:
Pizza with four toppings and trimmings.
Tokens from input sentence #1:
[‘[CLS]’, ‘pizza’, ‘with’, ‘four’, ‘topping’,
‘##s’, ‘and’, ‘trim’, ‘##ming’, ‘##s’, ‘.’,
‘[SEP]’]
Some tokens in BERT:
[‘”’, ‘#’, ‘$’, ‘%’, ‘&’, “’”, ‘(‘, ‘)’, ‘*’, ‘+’,
‘,’, ‘-’, ‘.’, ‘/’, ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’]
生成 BERT 标记(2)
列表 6.8 展示了 bert_tokens2.py 的内容,说明了如何将文本字符串转换为 BERT 兼容字符串,然后将后者字符串分词成 BERT 标记。
列表 6.8:bert_tokens2.py
from transformers import BertTokenizer, BertModel
tokenizer = BertTokenizer.from_pretrained
(‘bert-base-uncased’)
text2 = “I got a book and after I book for an hour,
it’s time to book it.”
marked_text2 = “[CLS] “ + text2 + “ [SEP]”
tokenized_text2 = tokenizer.tokenize(marked_text2)
print(“input sentence #2:”)
print(text2)
print()
print(“Tokens from input sentence #2:”)
print(tokenized_text2)
print()
# Map token strings to their vocabulary indices:
indexed_tokens2 = tokenizer.convert_tokens_to_ids
(tokenized_text2)
# Display the words with their indices:
for pair in zip(tokenized_text2, indexed_tokens2):
print(‘{:<12} {:>6,}’.format(pair[0], pair))
列表 6.8 的前半部分几乎与列表 6.2 的前半部分相同,使用 text2 变量而不是 text1。
列表 6.8 的下一部分包含两个 print()语句块,分别显示 text2 和 tokenized_text2 的内容。接下来的代码片段初始化 indexed_tokens2 变量,其值为将 tokenized_text2 中的标记转换为 id 值的结果。
列表 6.8 的最后部分包含一个循环,显示标记及其关联的 id 值。列表 6.8 的输出如下:
input sentence #2:
I got a book and after I book for an hour, it’s
time to book it.
Tokens from input sentence #2:
[‘[CLS]’, ‘i’, ‘got’, ‘a’, ‘book’, ‘and’, ‘after’,
‘i’, ‘book’, ‘for’, ‘an’, ‘hour’, ‘,’, ‘it’, “’”,
‘s’, ‘time’, ‘to’, ‘book’, ‘it’, ‘.’, ‘[SEP]’]
[CLS] 101
i 1,045
got 2,288
a 1,037
book 2,338
and 1,998
after 2,044
i 1,045
book 2,338
for 2,005
an 2,019
hour 3,178
, 1,010
it 2,009
‘ 1,005
s 1,055
time 2,051
to 2,000
book 2,338
it 2,009
. 1,012
[SEP] 102
BERT 家族
BERT(来自谷歌)衍生出了一系列令人瞩目的原始 BERT 模型变体,每个变体都提供了一些有趣的功能。其中一些变体在此列出:
• ALBERT(谷歌)
• 双向和自回归 Transformer(BART)
• BERT(谷歌)
• BIO BERT
• 临床 BERT
• DeBERTa(微软)
• DistilBERT(Hugging Face)
• DOC BERT
• KeyBERT
• Google SMITH
• SBERT
• TinyBERT
• VisualBERT
• XLM-R
• XLNET
前面列表中的一些模型将在以下小节中讨论,你可以在线搜索有关本章未讨论的模型的更多信息。此外,RoBERTa 将在下一节中讨论。
ALBERT
ALBERT(来自谷歌研究和丰田技术研究所)是用于语言表示自监督学习的轻量级 BERT 的缩写。ALBERT 和 RoBERTa 比 BERT 小得多,但功能远超 BERT。
ALBERT 的主要动机是在基准测试中超越 BERT 的准确性。这通常意味着增加模型的大小并对训练过程进行修改以实现良好的扩展性:也就是说,允许模型在不过度拟合的情况下提高准确性。
回想一下,BERT 的词嵌入是 1x768 的浮点数向量。相比之下,ALBERT 中的初始词嵌入只有 128 个特征(1x128 向量)。有趣的是,ALBERT 还包含一个矩阵,将 1x128 的词嵌入缩放到 1x768 的词嵌入。此外,ALBERT 有 12 层,隐藏大小为 4,096,这是 BERT-Large 深度的一半,宽度是其四倍。
根据 ALBERT 的 GitHub 仓库(github.com/google-research/ALBERT),
“ALBERT 使用参数减少技术,允许大规模配置,克服了之前的内存限制,并在模型退化方面实现了更好的行为。”
具体来说,ALBERT(与 BERT 不同)在其所有层中共享其参数,这减少了参数数量,但对训练和推理时间没有影响。此外,ALBERT 使用嵌入矩阵分解,这进一步减少了参数数量。
在 ALBERT 采用的参数共享技术方面有几个细节需要注意。首先,尽管参数共享确实减少了唯一参数的数量,但在训练步骤或推理(预测)步骤中的执行时间仍然与 BERT 相当。其次,尽管参数共享导致准确性降低,但实际准确性仍然相当不错。第三,参数减少允许在深度(即编码器组件中的子组件数量)和嵌入宽度方面实现更大的可扩展性。
关于 ALBERT 的另一个区别是它使用了 SOP,这是对 BERT 中使用的 NSP 的改进。最后,ALBERT 不使用 dropout 率,这进一步增加了模型容量。
ALBERT 使用全词掩码和“n-gram 掩码”,后者指的是掩码多个连续的词。以下是 ALBERT 的代码片段:
from transformers import AlbertForMaskedLM,
AlbertTokenizer
model1 = AlbertForMaskedLM.from_pretrained
(‘albert-xxlarge-v1’)
tokenizer = AlbertTokenizer.from_pretrained
(‘albert-xxlarge-v1’)
model2 = AlbertForMaskedLM.from_pretrained
(‘albert-xxlarge-v2’)
tokenizer = AlbertTokenizer.from_pretrained
(‘albert-xxlarge-v2’)
ALBERT 在基准测试中取得的分数高于 BERT、XLNet 和 RoBERTa,但仅在其最大的版本 ALBERT-xxlarge 中如此,而 ALBERT-Base 通常与 BERT-Base 具有可比的性能。有趣的是,以下是 ALBERT、XLNet 和 RoBERTa 在 2019 年发布的日期:
• ALBERT:2019 年 9 月 26 日(谷歌)
• XLNet:2019 年 6 月 19 日(谷歌 + CMU)
• RoBERTa:2019 年 7 月 26 日(U of W + Facebook)
BART
BART 是一个具有三个主要组件的模型:编码器(12 层)、解码器(12 层)和 lm_head(一个线性层)。BART 非常适合文本生成任务:它可以重建包含 tokens 的文本,因此它类似于自编码器。此外,其性能与 RoBERTa 相似。
你也可以通过程序调用,如 model.model.encoder、model.model.decoder 和 model.lm_head 来访问 BART 模型的各个部分。然而,Hugging Face 已经内置了访问编码器和解码器的函数,具有额外的灵活性。
通过比较,BART 也可以超越 GPT-2。BART 可用于抽象文本摘要,这是一个比提取式摘要更困难的任务。实际上,在某个时期,BART 是文本摘要的 SOTA 模型。如果你对文本摘要不熟悉,可以在以下链接中找到更详细的描述:
BioBERT
BioBERT 是一个基于 BERT 的模型,它在生物医学数据上进行了预训练,可以在各种生物医学特定任务上进行微调,例如命名实体识别(NER)和问答(等等)。用于预训练 BioBERT 的两个著名数据集是 PubMed 和 PubMed Central,分别包含大量的引用和生物医学文章。BioBERT 可以被微调以执行生物医学特定任务,例如 NER(ClinicalBERT 也是如此)。你可以在以下链接下载 BioBERT:github.com/naver/biobert-pre-trained。
ClinicalBERT
ClinicalBERT 是一个基于 BERT 的模型,它在包含有关患者详细信息的临床语料库上进行了预训练。例如,该模型包含有关患者症状、诊断、活动和治疗的信息。由于临床文档包含行业特定的术语(行话),ClinicalBERT 在称为 MIMIC-III 的一组临床文档上进行了预训练。此外,ClinicalBERT 可以在各种任务上进行微调,例如预测相关任务。
deBERTa (超越人类准确率)
微软的 deBERTa 模型实际上超过了人类准确率:
该模型的架构由 48 个 transformer 层和 15 亿个参数组成。该模型的 GLUE 得分为 90.8,SuperGLUE 得分为 89.9,这超过了人类性能得分 89.8。如有需要,你可以在线搜索有关 GLUE 和 SuperGLUE 的详细信息。
微软还宣布了将 DeBERTa 与 Turing 自然语言表示模型 Turing NLRv4(同样来自微软)集成的意向。Turing 模型在微软生态系统中无处不在,包括 Bing 和 Azure 认知服务等产品。
DistilBERT
DistilBERT 是 BERT 的一个更小的变体,包含 6600 万个参数,这是 BERT-Base 参数数量的 40%(BERT-Base 有 1.1 亿个参数)。DistilBERT 使用一种称为 蒸馏 的技术(即训练一个较小的模型来近似一个较大的模型)来近似 BERT。即便如此,DistilBERT 实现了超过 95% 的 BERT 准确率,并且比 BERT-Base 快 60%,这使得 DistilBERT 对于迁移学习非常有用。Neural Magic 的最新进展,使用基于稀疏的技术,使得 BERT-large 的速度比 DistilBERT 快,同时没有降低准确率。有关 Neural Magic 和基于稀疏技术的详细信息,可在网上找到:
知识蒸馏 涉及一个小型模型(称为“学生”),该模型被训练来模仿一个更大的模型或模型集合(称为“教师”)。DistilBERT 是一个蒸馏网络的例子:它包含 BERT 层数的一半。此外,DistilBERT 如下初始化学生的层,从教师的层开始:
towardsdatascience.com/distillation-of-bert-like-models-the-theory-32e19a02641f
作为一个示例,以下是如何实例化 DistilBERT 标准化器的例子:
import transformers
tokenizer = transformers.AutoTokenizer.from_
pretrained(‘distilbert-base-uncased’,
do_lower_case=True)
这里是另一个实例化 DistilBERT 标准化器的技术:
from transformers import DistilBertTokenizer:
tokenizer = DistilBertTokenizer.from.
pretrained(‘distilbert-base-uncased’)
Google SMITH
来自谷歌的 SMITH 模型是一个用于分析文档的模型。在非常简化的描述中,SMITH 模型被训练来理解整个文档上下文中的段落。相比之下,BERT 被训练来理解句子上下文中的单词。然而,SMITH 模型(其性能优于 BERT)通过执行 BERT 中不可能执行的主要操作来补充 BERT。
TinyBERT
TinyBERT 基于蒸馏技术,并采用了一种新的两阶段学习框架,在预训练阶段以及特定任务的学习阶段都进行 Transformer 蒸馏。因此,TinyBERT 能够捕捉到 BERT 中的通用领域知识和特定任务知识。以下是关于 TinyBERT 的详细信息:
• 只包含 4 层
• 性能超过 BERT-Base 的 96%
• 比 BERT-Base 小 7.5 倍
• 在推理上比 BERT-Base 快 9.4 倍
关于 TinyBERT 的更多详细信息可以在 paperswithcode.com/paper/190910351 找到。
VideoBERT
VideoBERT 是一个基于 BERT 的视频处理模型,它涉及生成语言标记和视觉标记。语言标记可以通过 ASR(自动语音识别)提取,而视觉标记可以通过首先采样视频的图像帧,然后将这些帧转换为视觉标记来创建。
接下来,语言标记和视觉标记被结合成句子,使用 BERT 特定的特殊标记,如[CLS]、[PAD]和[SEP],然后执行 MLM。然而,与 NSP(下一句预测)不同,VideoBERT 执行对齐检查,以确定给定的文本字符串和相邻视频是否有意义。
VisualBERT
VisualBERT 是一个有趣的基于 BERT 的模型,它结合了图像和文本。该模型使用注意力来检测图像区域和文本之间的“对齐”。该模型在arxiv.org/abs/1908.03557v1中讨论。
有几个基于社区的 VisualBERT 实现,其中 GitHub 星标数量最多的是github.com/uclanlp/visualbert。
XLNET
XLNet 是一个自回归预训练模型,在许多任务上优于 BERT。XLNet 使用排列语言模型(PLM)来克服 BERT 执行的 MLM 任务的局限性。与 BERT 不同,XLNet 没有任何输入约束。XLNet 还包含一个注意力掩码,使 XLNet 能够理解词序,以及在线解释的两个流自注意力:
towardsdatascience.com/what-is-two-stream-self-attention-in-xlnet-ebfe013a0cf3
从高层次来说,给定一个由 N 个标记组成的输入序列 S,XLNet 计算 S 中第 i 个标记出现在 S 的前 i 个标记中的概率,这表示为 P(xi|x<i)。这个概率对序列 S 中所有可能的标记排列都进行计算。回想一下,一个由 N 个标记组成的序列有 N!种可能的排列(见下面的缺点部分)。
注意:对于任何给定 N 个标记的句子,XLNet 处理给定句子的 N!个排列句子。
XLNet 的缺点
XLNet 的第一个缺点是由于其计算复杂性,与 BERT 相比,需要更长的训练时间。
第二,XLNet 在较短的小型输入句子上可能表现不佳。XLNet 的预训练步骤专注于长输入序列,排列语言模型旨在捕捉长期依赖关系。
第三,虽然 XLNet 确实利用了位置信息,但其实现方式与传统方法不同。在 PLM 方法中,模型学习以各种顺序预测标记,而不仅仅是句子中的原始顺序,这可能导致位置信息使用上的“差异”。然而,它仍然使用位置编码来保留一些位置信息的感觉,并且它旨在学习双向上下文,这有助于它理解序列中不同位置之间的关系。
如何选择基于 BERT 的模型
当决定在您的环境中使用哪个模型时,您需要考虑各种标准,其中一些在此列出:
• 硬件可用性和成本
• 从头训练与微调
• 下游任务类型
• 公共模型的可用性
如果您没有高优先级的要求,BERT 是一个好的选择。然而,如果您需要更快的推理速度,并且可以在预测指标上牺牲一些准确性,那么可以考虑 DistilBERT 作为起点。相比之下,如果您需要最佳的预测指标,那么 RoBERTA(来自 Facebook)将是一个更好的选择。另一个选择是 XLNet,它可以提供更好的长期运行结果。
与 RoBERTa 一起工作
RoBERTa(来自 Facebook)是 A Robustly Optimized BERT Pre-training Approach 的缩写。RoBERTa 的架构师对 BERT 进行了以下改进以创建 RoBERTa:
• 丢弃了 NSP(下一句预测)
• 使用了 GPT-2 的“变体”BPE(而非原始的 BPE)
• 使用动态掩码而非静态掩码
• 在更长的序列上进行了训练。
• 使用了 160 GB 的训练数据,而不是 16 GB(BERT)
• 文本样本使用完整的句子(而不是文本片段)
• 在每次迭代中对随机选择的标记集应用掩码
• 不同的分词方案
RoBERTa 利用 BERT 的语言掩码策略,并对 BERT 的一些超参数进行了修改。请注意,RoBERTa 在一个至少比 BERT 语料库大 10 倍的语料库上进行了训练。
与 BERT 不同,RoBERTa 并不执行 NSP(下一句预测)任务,这实际上改善了训练过程。相反,RoBERTa 使用一种称为 动态掩码 的技术,在训练过程中,不同的训练迭代中会掩码不同的标记。因此,RoBERTa 在 GLUE 基准测试结果上优于 BERT 和 XLNet。
意大利语和日语语言翻译
本节包含一个代码示例,将英语句子翻译成意大利语和日语。
列表 6.9 展示了 bert_translate.py 的内容,说明了如何将文本字符串从英语翻译成意大利语。
列表 6.9:bert_translate.py
from transformers import AutoTokenizer,
AutoModelForSeq2SeqLM
# English to Italian:
tokenizer = AutoTokenizer.from_pretrained
(“Helsinki-NLP/opus-mt-en-it”)
model = AutoModelForSeq2SeqLM.from_
pretrained(“Helsinki-NLP/opus-mt-en-it”)
text = “I love deep dish pizza!”
tokenized_text = tokenizer.prepare_seq2seq_batch
([text], return_tensors=’pt’)
# Perform translation and decode the output
translation = model.generate(**tokenized_text)
translated_text = tokenizer.batch_decode
(translation, skip_special_tokens=True)[0]
# Print translation from English to Italian:
print(“Initial English text:”, text)
print(“Italian translation: “, translated_text)
# English to Japanese:
tokenizer = AutoTokenizer.from_pretrained
(“Helsinki-NLP/opus-mt-en-jap”)
model = AutoModelForSeq2SeqLM.from_pretrained
(“Helsinki-NLP/opus-mt-en-jap”)
text = “I love deep dish pizza!”
tokenized_text = tokenizer.prepare_seq2seq_batch
([text], return_tensors=’pt’)
# Perform translation and decode the output
translation = model.generate(**tokenized_text)
translated_text = tokenizer.batch_decode
(translation, skip_special_tokens=True)[0]
# Print translation from English to Japanese:
print(“Japanese translation:”, translated_text)
列表 6.9 以一个导入语句开始,然后初始化 tokenizer 和 model 变量分别为分词器和模型实例。接下来,变量 text 被初始化为一个测试字符串,变量 tokenized_text 被初始化为对变量 text 内容进行分词的结果。
列表 6.9 的下一部分执行了意大利语的翻译,之后显示翻译后的文本。另一个文本块执行了类似的操作,将初始的英语文本翻译成日语,然后显示结果。运行 列表 6.9 中的代码,您将看到以下输出:
Initial English text: I love deep dish pizza!
Italian translation: Adoro la pizza dei piatti
profondi!
Japanese translation: ,
现在您已经看到了一个在两种语言之间翻译文本的例子,让我们看看提供多语言支持的 LLM,这是下节的主题。
多语言语言模型
在 LLM 中的多语言支持变得越来越重要,这有时会涉及额外的挑战。例如,英语有大量的可用标记,而有些语言的数据可用性较低。我们如何训练一个标记数量有限的语言模型?下节将讨论几种技术。
训练多语言语言模型
训练多语言 LLM 的一种技术涉及一个称为跨语言迁移的概念:
多语言模型包括预训练,然后是 XLM-R,然后是跨语言迁移。以下 GitHub 仓库展示了如何从英语到葡萄牙语进行跨语言迁移:github.com/lersouza/cross-lingual-transfer。
在各种语言上训练参数的模型可以学习文本的跨语言表示。有趣的结果是,这种表示使得多语言预训练模型能够利用不同低数据语言中的一个语言的有监督数据。另一种方法涉及现有的多语言语言模型,这是下节的主题。
基于 BERT 的多语言语言模型
有一些基于 BERT 的模型支持多种语言,其中一些在此列出:
• m-BERT
• XLM 和 XLM-R
• XLSR
• mSLAM
• MUSE
• OSCAR
在线搜索更多关于上一条项目符号中 LLM 的信息。
为 1,000 种语言翻译
本节包含了对一些任务和有趣技术的概述(包括来自母语者的数据集审计),这些是谷歌研究人员团队用来为超过 1,000 种语言实现语言翻译所使用的。
由于“高资源”语言(如英语和法语)有大量的训练数据,Google Translate 为一些语言对提供了高质量的语言翻译。有些语言由于训练数据有限而不受支持,对于这些语言,数据收集可能非常困难。在某些情况下,低资源语言在互联网上没有可用数据。
以下包括一些与语言翻译相关的术语。平行数据指的是给定句子存在于多种语言中,而单语数据指的是仅存在于单一语言的句子。目前,在 Google Translate(以及其他翻译系统)中,有超过 100 种平行语言得到了良好的服务。
对于单语数据来说,一种有用的技术被称为回译,它涉及将句子从源语言翻译成目标语言,然后将句子在目标语言中翻译回源语言。实际上,你可能已经看到这种技术被应用于包含习语表达的句子中,并且原始句子与其回译之间的比较可能非常有趣。
为 1,000 种语言启用语言翻译的过程包括以下步骤:
• 为 1,000 种语言收集单语数据。
• 将现有的平行数据与单语数据相结合。
• 使用组合数据训练模型。
当然,收集单语数据是一项困难的任务,部分原因是噪声的存在,这些噪声难以与有效数据分离。用于处理单语数据的一种技术是字符袋(BoC)算法,它是基于字符的词袋(BoW)算法的对应物。基于字符的 n-gram 在这些语言中可能非常有效,因为它们避免了单词分段的必要性,并且可以在字符级别捕获有意义的模式。然而,值得注意的是,基于字符的方法有时会错过基于单词的方法所能捕获的更高层次的模式,并且它们也可能导致非常高的维数特征空间,特别是对于较大的 n 值。
在数据收集过程中会执行额外的任务,例如句子去重以及移除对于预测语言来说高频词数量不足的句子。
除了使用基于 transformer 的模型之外,另一个需要注意的点是使用紧凑语言检测器 3(CLD3)模型。CLD3 是一个支持数十种语言的神经网络语言识别模型,更多信息可以在github.com/google/cld3找到。
你也可以通过以下命令安装 CLD3 的 Python 绑定:
pip3 install gcld3
关于 1,000 种语言翻译的更多信息可在网上找到(数据和模型目前不可用):arxiv.org/abs/2205.03983。
将谷歌的这项倡议与 Meta 开源的 NLLB 模型进行对比,该模型支持 200 种语言。
M-BERT
由于 BERT 仅限于英语文本,我们需要使用多语言 BERT(也称为 M-BERT)来处理其他语言的文本。M-BERT 是一个多语言 BERT 模型,它可以确定超出英语语言的单词表示。
尽管 BERT 和 M-BERT 都是通过 MLM 和 NSP 任务进行训练的,但 BERT 使用的是维基百科文本和多伦多图书语料库进行训练,而 M-BERT 则从超过多种语言的维基百科文本中进行训练。
高资源语言(如英语)的维基百科文本大小高于低资源语言。
M-BERT 不需要配对或语言对齐的训练数据。M-BERT 没有使用任何跨语言目标进行训练;它的训练方式与 BERT 模型相同。M-BERT 产生了一种可以推广到多种语言的表示,适用于下游任务。预训练的开源 M-BERT 模型可以从以下链接下载
github.com/google-research/bert/blob/master/multilingual.md
两种预训练的 M-BERT 模型是 BERT-Base,多语言带大小写和 BERT-Base,多语言不带大小写。
列表 6.10 展示了 multi_bert.py 的内容,该内容说明了如何将文本字符串转换为 BERT 兼容的字符串,然后将后者字符串分词成 BERT 标记。
列表 6.10: multi_bert.py
from transformers import BertTokenizer, BertModel
model = BertModel.from_pretrained
(‘bert-base-multilingual-cased’)
tokenizer = BertTokenizer.from_pretrained
(‘bert-base-multilingual-cased’)
# Japanese sentence:
sentence = “”
print(“sentence:”)
print(sentence)
print()
# get the sentence tokens:
inputs = tokenizer(sentence, return_tensors=”pt”)
print(“inputs:”)
print(inputs)
print()
# pass tokens to the model and get the
representation:
hidden_rep, cls_head = model(**inputs)
print(“hidden_rep:”)
print(hidden_rep)
print()
print(“cls_head:”)
print(cls_head)
Print()
列表 6.10 导入了 BertTokenizer 和 BertModel,并将变量 model 初始化为 bert-base-multilingual-cased 的一个实例,然后初始化了变量 tokenizer。
下三个 print()语句块显示了 text1、tokenized_text1 和一系列 20 个 BERT 标记的内容。运行列表 6.10 中的代码,你将看到 BERT 标记。
比较基于 BERT 的模型
原始 BERT 模型有许多变体,存在一些模型可以提升 BERT 的预测能力或性能。ALBERT、RoBERTa 和 DistilBERT 是最受欢迎的基于 BERT 的模型之一。ALBERT 和 RoBERTa 在减小模型大小和增加速度方面都优于 BERT。相比之下,DistilBERT 在准确率仅降低 3%的情况下,与 BERT 相比减小了模型大小。
几种其他模型实现了 SOTA 性能,包括 XLNet,它是一个自回归语言模型,扩展了 Transformer-XL 模型。XLNet 通过使用排列语言建模实现了比 BERT 更好的预测,并达到了与 RoBERTa 相当 SOTA 结果。这种建模技术对于随机顺序的标记实现了 100%的准确率。回想一下,BERT 预测的是占所有标记 15%的掩码标记。XLNet 使用了超过 130 GB 的文本数据和运行了 2.5 天的 512 个 TPU 芯片进行训练,这两者都远大于 BERT。
另一个模型是 Mobile-BERT,它与 DistilBERT 类似。与 BERT-Base 相比,Mobile-BERT 小 4 倍以上,速度快 5 倍以上,但性能仍然可以相提并论。第三个模型是 BART,这是一个在 NLU 任务上性能与 RoBERTa 相当的前训练模型。有关 BART 的更多信息可在网上找到:
towardsdatascience.com/everything-you-need-to-know-about-albert-roberta-and-distilbert-11a74334b2da
RoBERTa 也取得了显著的改进。回想一下,BERT 使用 NSP,而 RoBERTa 使用一种称为动态掩码的技术,在训练过程中,不同的 token 在不同的训练迭代中被掩码。RoBERTa 与 BERT 相比的另一个不同之处在于训练阶段的批量大小更大。结果是令人印象深刻的:RoBERTa 在许多任务和数据集上优于 BERT 和 XLNet。
另一种方法与其它语言模型的工作方式“相反”:目标是减小基于 transformer 的语言模型的大小,同时仍然取得显著的效果。特别是,DistilBERT 使用了 BERT 一半的层数,并放弃了 token 风格的嵌入,但 DistilBERT 仍然达到了 BERT 性能的 95%。此外,DistilBERT 使用了一种称为蒸馏的技术,该技术在网上有描述:
www.kdnuggets.com/2019/09/bert-roberta-distilbert-xlnet-one-use.html
www.kdnuggets.com/2019/07/pre-training-transformers-bi-directionality.html
如何在您的笔记本电脑上训练 BERT 模型
如果你有动力,并且有足够的磁盘空间,你可以在你的笔记本电脑上训练 BERT。导航到以下链接,你将找到一个基于 Python 的代码示例,它提供了必要的细节:
www.kdnuggets.com/2021/08/train-bert-model-scratch.html
如果你没有足够的磁盘空间,当你从前面的链接启动 Python 代码时,你会看到以下错误消息(或类似的消息),这表明你需要大约 95GB 的磁盘空间来下载这个 LLM:
f”Not enough disk space. Needed: {size_str(self.
info.size_in_bytes or 0)} (download: {size_
str(self.info.download_size or 0)}, generated:
{size_str(self.info.dataset_size or 0)}, post-
processed: {size_str(self.info.post_processing_size
or 0)})”
OSError: Not enough disk space. Needed: 94.79 GiB
(download: 26.01 GiB, generated: 68.77 GiB,
post-processed: Unknown size)
基于 WEB 的 BERT 工具
有几种非常好的在线工具可用于实验 BERT 模型,例如 exBERT 和 bertvix,这两个工具将在以下小节中简要讨论。
exBERT
这是 exBERT 的正式描述,根据其主页上的描述:
exBERT 是一个帮助人类进行灵活、交互式调查并为模型内部推理过程制定假设的工具,支持对各种 Hugging Face Transformer 模型的分析。exBERT 通过将人类指定的输入与大型标注数据集中的相似上下文进行匹配,提供了对上下文表示和注意力的见解。
更多信息可在 exBERT 主页找到:
huggingface.co/exbert/?model=bert-base-case
BertViz
BertViz 是一个用于可视化基于转换器模型中注意力机制的工具,BertViz 的 Github 仓库位于 github.com/jessevig/bertviz。
图 6.1 显示了 BertViz 的屏幕截图。

图 6.1 BERT 生成的输出标记
CNNViz
虽然 CNNViz 是一个用于可视化卷积神经网络而不是与 BERT 相关模型的工具,但它仍然非常有趣,特别是如果你从未使用过这样的 CNN 工具。CNNViz 的屏幕截图显示在 图 6.2 中,其 Github 仓库可在此处访问:

图 6.2 CNNViz 的屏幕截图
使用 BERT 进行主题建模
主题建模 涉及在一个或多个文档中找到主题集合。它包括找到主题的数量以及每个主题在文档中的长度。主题建模始终很重要。在 BERT 开发之前,使用了各种机器学习算法,其中一些列在这里:
• LDA (潜在狄利克雷分配)
• LSA (潜在语义分析)
• NMF (非负矩阵分解)
通过比较,聚类算法将每个词分配到单个簇(即一对一对应)。然而,主题建模允许一个词属于多个主题的可能性,这意味着词和主题之间存在一对一和多对一的关系。因此,主题建模涉及计算一组概率,表示一个词属于一组主题。
幸运的是,BERT 及相关模型的可用性意味着我们可以在不涉及昂贵且耗时的训练过程的情况下,拥有基于转换器的预训练语言模型。下一节简要讨论 T5,这是谷歌创建的另一个强大的 NLP 模型。
什么是 T5?
文本到文本传输转换器 (T5) 是一个将所有 NLP 任务转换为文本到文本格式的编码器-解码器模型,其可下载代码可在网上找到:
github.com/google-research/text-to-text-transfer-transformer
您也可以通过以下命令安装 T5:
pip install t5[gcp]
T5 在多任务混合的无监督和监督任务上进行预训练,在翻译等任务上表现良好。在 2022 年,T5 是 Hugging Face 上最受欢迎的下载,每月下载量超过一百万。
T5 使用称为“教师强制”的技术进行训练,这意味着训练时始终需要输入序列和目标序列。输入序列用 input_ids 标识,而目标序列用 output_ids 标识,然后传递给解码器。
由于所有任务(如分类、问答和翻译)都涉及这种输入/输出机制,因此可以使用相同的模型来完成多个任务。
此外,T5 在与 T5 模型一起工作时提供了几个有用的类,例如 transformers.T5Config 类,它允许您指定配置信息,其默认值类似于 T5-small 架构。另一个有用的类是 transformers.T5Tokenizer,它允许您构建一个 T5 标记化器。
T5 与 BERT 在两个显著方面有所不同:
• 文本到文本框架
• 监督学习
• 编码器-解码器
• 使用因果解码器
• 通过去噪自动编码器目标进行预训练
• 输入具有文本到文本的表示
• 统一微调方法
• 句子分割标记化
尽管您可以下载 T5 的代码示例,但最初在 Google Colaboratory 笔记本中实验 T5 可能会更简单,您可以在本文及其相关的 Github 仓库中找到它:
pedrormarques.wordpress.com/2021/10/21/fine-tuning-a-t5-text-classification-model-on-colab
github.com/pedro-r-marques/tutorial-t5-fine-tune
2022 年 6 月,Google 将 T5X/JAX 中的所有 Switch Transformer 模型开源:github.com/google-research/t5x。
注意,开源模型包括 1.6 T 参数的 Switch-C 模型和 395 B 参数的 Switch-XXL 模型。
T5X 是基于 Mesh TensorFlow 的 T5 代码库(在 JAX 和 Flax 中改进实现)的一个模块化、可组合、研究友好的框架,用于在多个规模上进行高性能、可配置、自助训练、评估和推理序列模型(从语言开始)。有关 T5 和 T5X 的更多信息可在网上找到:
huggingface.co/transformers/model_doc/t5.html
github.com/google-research/t5x#readme
与 PALM 一起工作
PaLM 是一个由 Google 开发的拥有 5400 亿参数的基于 Transformer 的模型,它可以学习语言理解以及大量的基于 NLP 的任务,如本文所述:
ai.googleblog.com/2022/04/pathways-language-model-palm-scaling-to.html
PaLM 支持额外的基于 NLP 的任务,并且可以通过多种硬件加速器进行训练:
thesequence.substack.com/p/-new-week-new-ai-super-model
以下链接包含有关 PaLM 和其他发展(如英伟达的 H100 芯片)以及本章讨论的 LLM(例如 Chinchilla)的更多详细信息:
medium.com/mlearning-ai/breakthroughs-in-language-modelling-in-the-last-month-d3e3c0099272
此外,PaLM 支持思维链提示以执行多步任务。毫无疑问,PaLM 将被另一种具有更高性能、更少参数或更低总体成本的 LLM 取代。实际上,NLP 领域正在迅速变化。
什么是 Pathways?
Pathways 是 Google 的一种架构,它采用不同的方法来训练机器学习模型。除了 GPT-3 和其他类似系统之外,当前的 AI 模型通常是为单一任务进行训练的。Pathways 架构使得训练好的模型能够执行数千个任务。本质上,使用 Pathways 架构训练以执行多个不相关任务的模型将具有将这些任务组合起来执行它们从未被训练过的新任务的能力。有关 Pathways 的更多信息可在网上找到:
blog.google/technology/ai/introducing-pathways-next-generation-ai-architecture/
总结
本章从基于 Python 的特殊 BERT 标记的代码示例开始。然后你学习了 BERT 标记化器以及如何使用 BERT 进行情感分析。
接下来,你学习了涉及 BERT 编码的步骤序列。你还学习了 BERT 中的句子相似性以及如何生成 BERT 标记。
此外,你学习了属于 BERT 家族的众多 LLM,例如 ALBERT、BART 和 DistilBERT。最后,你学习了 BERT 的基于 Web 的工具、BERT 的主题建模以及 Google PaLM。
第七章
与 GPT-3 一起工作简介
本章讨论了 OpenAI 的 GPT-3,这意味着你将了解 GPT-2 和 GPT-3 的功能以及一些代码示例。当前的基于 Python 的代码示例目前需要 Python 3.7,如果你还没有下载,可以从互联网上下载。
本章的第一部分描述了三种著名的 LLM(大型语言模型)的主要类型:仅编码器、仅解码器和编码器-解码器模型。接下来,你将了解 OpenAI 的基于 GPT 的语言模型家族的一些细节。在简要介绍 GPT-2 之后,你将获得对 GPT-3 的高级介绍,包括 GPT-3 的目标以及基于 GPT-3 的几个模型。
第二部分提供了对 GPT-3 能力的描述,GPT-3 和 BERT 的比较,以及 GPT-3 的优缺点。
第三部分深入探讨了 GPT-3 游乐场,该游乐场已于 2021 年底向所有人开放。你将学习如何创建 GPT-3 应用程序,以及如何使用 GPT-3 进行推理。此外,你还将学习如何在 GPT-3 中使用提示。
在阅读本章内容之前,请记住 SOTA 是 State-Of-The-Art 的缩写。由于 NLP 世界中新技术发展的速度,任何时间点的 SOTA 模型都很快被另一个 SOTA 模型取代,有时在几周内。
GPT 家族简介
广义预训练转换器,GPT,是基于转换器架构的第一个自回归模型。
OpenAI 负责创建基于 GPT 的模型。GPT、GPT-2 和 GPT-3 分别于 2018 年、2019 年和 2020 年发布,参数量分别为 117 M、1.5 B 和 175 B。GPT-4 于 2023 年 3 月发布,其参数量似乎达到了 1.76 万亿(是 GPT-3 的 10 倍)。
初始的 GPT 模型是在 BookCorpus 数据集上预训练的。该库提供了用于语言建模和多任务语言建模/多项选择分类的模型版本。
GPT 模型的架构在逐渐增大,并且正在使用更大的数据集进行训练。例如,GPT、GPT2 和 GPT3 的最大序列长度分别为 1 K、1 K 和 2 K,以及词嵌入长度分别为 768、1600 和 12888。
回想一下 第五章,BERT 采用仅编码器架构,而 GPT 采用仅解码器架构。尽管转换器架构最初是为了执行机器翻译而开发的,但 GPT 模型的转换器相关部分涉及无监督预训练方法。
有趣的是,BERT 的主要开发者受到了 GPT 架构的影响,尽管 BERT 基于转换器架构的编码器组件而不是解码器组件。
GPT 家族的架构
GPT 模型的优势在于它们能够处理基于文本的输入并生成基于文本的输出。GPT 模型不支持非文本输入,如音频或视频,因为它们不是多模态模型。在 第三章 中,你学习了自回归模型。基于 GPT 的模型也是自回归模型,因为它们基于解码器组件。
简而言之,每当提交输入文本到基于 GPT 的模型时,它会为可能出现在响应文本中的单词分配百分比。具体的百分比是通过解码器本身计算的,解码器可以使用各种策略来计算这些百分比。请注意,您可以指定 GPT 在生成的输出文本中显示的最大标记数。
主要的 GPT 引擎
GPT API 提供了具有不同能力的不同语言模型/引擎。四个著名的 GPT-3 引擎(从大到小)是:达芬奇、居里、巴贝奇和 Ada。达芬奇具有最多的功能(需要更多资源),是实验的好选择。Ada 引擎具有最快的性能,其他两个引擎是生产环境的潜在选择。每个引擎都有自己的优点:
• 达芬奇用于创造性和分析性输出。
• 居里用于分类、语言翻译和摘要。
• 巴贝奇用于语义搜索分类。
• Ada 用于解析文本和简单分类。
GPT-3 达芬奇引擎在单词拼写和语法方面生成非常好的输出文本。相比之下,Ada 引擎生成的输出“变化”要大得多,有时甚至可能显得不合逻辑。
第二,使用相同输入(无论选择哪种引擎)进行多次调用可能会导致 GPT 生成不同的输出。您将在本章后面的 GPT-3 游戏场子部分看到此类示例。
第三,您有时会看到一种 循环效应,其中句子片段(甚至整个句子)被生成,每个句子都跟随其前一个句子,几乎就像它在生成的响应文本中“结巴”一样。
关于模型的 重要更新
2023 年 7 月初,OpenAI 宣布将弃用本章中讨论的 Ada、巴贝奇、居里和达芬奇等模型。弃用将于 2023 年 1 月 4 日进行。OpenAI 将用 GPT-3、GPT-3.5 Turbo 和 GPT-4 的升级版本替换这些模型。OpenAI 建议采用这些模型,而不是在 2024 年初弃用的模型上进行微调。更多信息请参阅platform.openai.com/docs/guides/fine-tuning。
此外,您可以通过从命令行运行以下命令来执行升级:
pip3 install --upgrade openai
GPT-2 是什么?
GPT-2 是原始 GPT 模型的一个更大、更好的版本。GPT-2 在 WebText 上进行了预训练,WebText 由 Reddit 中具有 3 个或更多“karma”的出站链接的网页组成(即点赞)。请注意,GPT 和 GPT-2 在不同的数据集上进行了训练:前者主要在 BookCorpus 上进行训练,而后者在 Reddit 的网页、博客和新闻文章链接上进行训练。
GPT-2 是一个基于 transformer 的仅解码器 LLM,可以生成高质量的文本。GPT-2 支持高达 2048 个 token,已被 GPT-3 和 GPT-4 所取代。
GPT-2 架构
GPT-2 通过随机采样提供高质量的输出。此外,GPT-2 在 token 之间的距离上实现了长距离一致性,这是 RNN 和 LSTM 无法实现的。在架构方面,关键点涉及以下架构和训练相关的细节:
• 因果注意力(与 BERT 对比)
• 自回归语言模型
• 单个 48 块堆叠
• 维度为 768 和 12 个头
• 序列长度为 1024
• 位置嵌入
• 1.5 亿个参数
• FF 层中使用 GELU
GPT-2 没有在 Reddit 的任何内容上进行训练。相反,它是在与 Reddit 链接(或来自 Reddit)的网站内容上进行的训练。
由于 GPT-2 涉及因果注意力,这意味着解码器块包含掩码自注意力,这反过来又意味着每个 token 只能“看到”输入字符串中的前缀 token。这个约束是通过将注意力矩阵的上三角值设置为-oo 来实现的,之后 softmax()激活函数将上左矩阵中的所有值设置为 0。
一组研究人员进行了一个有趣的实验:他们在文本上训练了一个 GPT-2 模型,然后“冻结”了其自注意力和前馈层,并为不同的领域微调了模型。他们的结果在网上进行了描述:
read.deeplearning.ai/the-batch/transformers-smarter-than-you-think
GPT-2 和 CodeParrot
列表 7.1 显示了 code_parrot1.py 的内容,这是一个基于 GPT-2 的模型,展示了如何创建一个分词器和一个管道(两者都来自 transformers 库)的实例以执行文本生成。
列表 7.1: code_parrot1.py
#pip3 install transformers
#Create an instance of a tokenizer and a pipeline
#for text generation using the CodeParrot model:
from transformers import pipeline
# Create a text generation pipeline with the
CodeParrot model:
text_generator = pipeline('text-generation',
model='codeparrot/codeparrot')
# Use the pipeline to generate text
input_text = "Once upon a time"
generated_text = text_generator(input_text,
max_length=50, do_sample=True, temperature=1.0)
# Print the generated text
print(generated_text[0]['generated_text'])
列表 7.1 从一个导入语句开始,然后初始化 text_generator 为 pipe line()的一个实例,同时将 text-generation 作为任务,将 codeparrot/codeparrot 作为模型。
接下来,初始化字符串变量 input_text,然后初始化变量 generated_text,该变量使用 input_text(和其他变量)调用 text_generator()返回的结果进行初始化。最后的代码片段打印生成的文本。
注意:下载的模型大于 6GB,下面显示的输出可能与你启动此代码示例时看到的不同。
使用以下命令启动列表 7.1 中的代码,你将看到模型是如何自动下载的(后续调用此代码将使用已下载的模型):
python3.7 code_parrot1.py
上面的 Python 命令的输出在此处显示,以及一些在下载模型期间显示的文本:
python3.7 code_parrot1.py
Downloading: 100%| | 259/259
[00:00<00:00, 59.7kB/s]
Downloading: 100%| | 485k/485k
[00:00<00:00, 1.09MB/s]
Downloading: 100%| | 270k/270k
[00:00<00:00, 761kB/s]
Downloading: 100%| | 821k/821k
[00:00<00:00, 1.33MB/s]
Downloading: 100%| | 90.0/90.0
[00:00<00:00, 59.2kB/s]
/Library/Frameworks/Python.framework/Versions/3.7/
lib/python3.7/site-packages/transformers/models/
auto/modeling_auto.py:787: FutureWarning: The
class ‵AutoModelWithLMHead‵ is deprecated and
will be removed in a future version. Please use
‵AutoModelForCausalLM‵ for causal language models,
‵AutoModelForMaskedLM‵ for masked language models
and ‵AutoModelForSeq2SeqLM‵ for encoder-decoder
models.
FutureWarning,
Downloading: 100%| | 927/927
[00:00<00:00, 238kB/s]
Downloading: 8%| | 495M/5.75G
[00:19<02:22, 39.6MB/s]
"""
GPT-2 分词器
列表 7.2 展示了 gpt2_tokenizer1.py 的内容,展示了 GPT-2 如何对文本字符串进行分词。
列表 7.2: gpt2_tokenizer1.py
from transformers import GPT2Tokenizer
sentence = "I love Chicago pizza"
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
tokens1 = tokenizer(sentence)
print("=> sentence:",sentence)
print("=> tokens1: ",tokens1)
print()
tokens2 = tokens1['input_ids']
print("=> tokens2: ",tokens2)
print()
#Convert the tokens in into strings using
tokenizer.decode:
tokens3 = [tokenizer.decode(x) for x in tokens2]
print("=> tokens3: ",tokens3)
decoded2 = [tokenizer.decode(x).strip().lower() for
x in tokens2]
print("=> decoded2:",decoded2)
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
tokens4 = tokenizer('My favorite word is syzygy')
tokens4 = tokens4['input_ids']
print("=> tokens4: ",tokens4)
decoded3 = [tokenizer.decode(x).strip().lower() for
x in tokens4]
print("=> decoded3:",decoded3)
# decoded3: ['my', 'favorite', 'word', 'is', 'sy',
'zy', 'gy']
# syzygy is tokenized as 'sy', 'zy', and 'gy'
列表 7.2 从一个导入语句开始,然后初始化变量 sentence 为一个文本字符串,并初始化 tokenizer 为 GPT2Tokenizer 类的一个实例。
代码的下一部分调用了 tokenizer() 函数为 sentence 变量中的每个单词生成数字标记,并调用了 tokenizer.decode() 来“恢复”句子中的原始单词。
由于 GPT-2 不识别单词 syzygy,因此 GPT-2 执行子词分词以生成 'sy'、'zy' 和 'gy' 这三个标记。因此,在 sentence 变量中的 4 个输入单词生成了 7 个标记。运行 列表 7.2 中的代码,你将看到以下输出:
=> sentence: I love Chicago pizza
=> tokens1: {'input_ids': [40, 1842, 4842, 14256],
'attention_mask': [1, 1, 1, 1]}
=> tokens2: [40, 1842, 4842, 14256]
=> tokens3: ['I', ' love', ' Chicago', ' pizza']
=> decoded2: ['i', 'love', 'chicago', 'pizza']
=> tokens4: [3666, 4004, 1573, 318, 827, 7357,
1360]
=> decoded3: ['my', 'favorite', 'word', 'is', 'sy',
'zy', 'gy']
与此相比,BERT 生成了以下输出,其中包含 [CLS]、[SEP] 和子词的“##”前缀(参见第六章中的 列表 6.10):
['[CLS]', 'my', 'favorite', 'word', 'is', 'sy',
'##zy', '##gy', '[SEP]']
如果你想下载 GPT-2 的代码,请导航到以下网站并从模型列表中选择“gpt2”:
github.com/huggingface/transformers/blob/main/src/transformers/models/
使用 GPT-2 进行问答
列表 7.3 展示了 gpt2_qna2.py 的内容,展示了如何使用 GPT-2 进行问答。
列表 7.3: gpt2_qna2.py
from transformers import pipeline
qna = pipeline('question-answering')
qc_pair1 = {
'question': 'Who is the inventor of the Theory
of Relativity?',
'context': 'Albert Einstein invented the Theory
of Relativity',
}
qc_pair2 = {
'question': 'Which wine and cheese are from
Italy',
'context': 'Barolo wine from Italy goes well
with Parmigiano cheese',
}
if __name__ == "__main__":
result = qna (qc_pair1)
print("result:")
print(result)
print("-----------\n")
result = qna (qc_pair2)
print("result:")
print(result)
print("-----------\n")
列表 7.3 从一个导入语句开始,然后初始化变量 qna 为 pipeline 类的一个实例,同时指定了问答功能。接下来,变量 gc_pair1 和 gc_pair2 被初始化为包含两个键的 Python 字典。
注意到第二个对 gc_pair2 实际上涉及两个问题而不是一个:响应只包含关于奶酪的第二部分问题的答案,而忽略了关于酒的问题。运行 列表 7.3 中的代码,你将看到以下输出:
result:
{'score': 0.9971326589584351, 'start': 0, 'end':
15, 'answer': 'Albert Einstein'}
-----------
result:
{'score': 0.2554819583892822, 'start': 38, 'end':
48, 'answer': 'Parmigiano'}
---------–
Optimus:结合 BERT 和 GPT-2
BERT 采用仅编码器架构,而 GPT-2 和 Megatron 采用仅解码器架构。另一个有趣的基于 Transformer 的模型是 Optimus,它结合了 BERT 和 GPT-2,以及一个潜在变量 z(与解码器相关),使用两种技术:
• 将 z 作为向量添加到解码器的末尾。
• 将 z 添加到解码器的底层。
这个额外的层参与了解码过程的每个步骤。有关 Optimus 的更多详细信息,请参阅此处:github.com/ChunyuanLI/Optimus
GPT-2 与文本生成
列表 7.4 展示了 gpt2_text_gen1.py 的内容,展示了如何使用 GPT-2 模型进行文本生成。
列表 7.4: gpt2_text_gen1.py
from transformers import pipeline
# default uses the GPT-2 model:
gen = pipeline("text-generation")
prompt = "I love Chicago deep dish pizza"
result = gen(prompt)
print("prompt:",prompt)
print("result:",result)
print()
列表 7.4 以导入语句开始,然后初始化变量 gen 为 pipeline 类的实例,同时指定了文本生成。接下来,变量 prompt 使用文本字符串的形式初始化。
列表 7.4 的下一部分初始化变量 result,使用代码片段 gen(prompt)的输出,然后显示 prompt 和 result 的内容。在列表 7.4 中启动代码,你将看到以下输出:
Some weights of GPT2Model were not initialized
from the model checkpoint at gpt2 and are newly
initialized: ['h.0.attn.masked_bias', 'h.1.attn.
masked_bias', 'h.2.attn.masked_bias', 'h.3.attn.
masked_bias', 'h.4.attn.masked_bias', 'h.5.attn.
masked_bias', 'h.6.attn.masked_bias', 'h.7.attn.
masked_bias', 'h.8.attn.masked_bias', 'h.9.attn.
masked_bias',
'h.10.attn.masked_bias', 'h.11.attn.masked_bias']
You should probably TRAIN this model on a down-
stream task to be able to use it for predictions
and inference.
Setting ‵pad_token_id‵ to ‵eos_token_id‵:50256 for
open-end generation.
Setting ‵pad_token_id‵ to ‵eos_token_id‵:50256 for
open-end generation.
Setting ‵pad_token_id‵ to ‵eos_token_id‵:50256 for
open-end generation.
prompt: I love Chicago deep dish pizza
result: [{'generated_text': 'I love Chicago deep
dish pizza. I love it as well.\n\nI never thought I
would love the idea of a pizza, but I am glad that
I did. I know there is already a dedicated Chicago
pizza section in the neighborhood. I'}]
result2: [{'generated_text': 'I love Chicago deep
dish pizza! When it was starting to come to light
that these guys were making this, they took the
pizza to the local pizzeria and it was amazing. My
boyfriend also enjoyed it and loves to have these
places in town.'}, {'generated_text': 'I love
Chicago deep dish pizza. And the pizza is really
tasty.\n\nA quick thing that you should take note
of this week is the recent return of the Nachos.
The Nachos are a side dish in Chicago and some
of'}, {'generated_text': "I love Chicago deep dish
pizza and feel compelled to cook some of these.
It made me really want to learn more about pizza
cooking in a healthy way, but I don't want to
keep my focus on the best pizza recipe, and don't
want"}]
result3: [{'generated_text': "I love Chicago deep
dish pizza. Chicago deep dish, Chicago deep dish
pizza. So yeah, that's gotta work!\n\nA whole lot
of"}]
列表 7.5 显示了 gpt2_text_gen2.py 的内容,展示了如何使用 GPT-2 模型进行文本生成。
列表 7.5:gpt2_text_gen2.py
from transformers import pipeline
text_gen = pipeline("text-generation")
# specify a max_length of 50 tokens and sampling
"off":
prefix_text = "What a wonderful"
generated_text = text_gen(prefix_text, max_
length=50, do_sample=False)[0]
print("=> #1 generated_text['generated_text']:")
print(generated_text['generated_text'])
print("-------------------------------\n")
#output #1:
#What a wonderful thing about this is that it's a
very simple and simple way to get your hands on a
new game.
#The game is a simple, simple game. It's a simple
game. It's a simple game. It's
prefix_text = "Once in a "
generated_text = text_gen(prefix_text, max_
length=50, do_sample=False)[0]
print("=> #2 generated_text['generated_text']:")
print(generated_text['generated_text'])
print("-------------------------------\n")
prefix_text = "Once in a blue "
generated_text = text_gen(prefix_text, max_
length=50, do_sample=False)[0]
print("=> #3 generated_text['generated_text']:")
print(generated_text['generated_text'])
print("-------------------------------\n")
列表 7.5 以导入语句开始,然后初始化变量 text_gen 为 pipeline 类的实例,同时指定了文本生成。接下来,变量 prefix_text 初始化为一个文本字符串,变量 generated_text 使用 text_gen()的输出和三个参数初始化,之后显示 generated_text 的内容。
上述步骤重复两次,使用不同的变量 prefix_text 的值。在列表 7.5 中启动代码,你将看到以下输出:
Some weights of GPT2Model were not initialized
from the model checkpoint at gpt2 and are newly
initialized: ['h.0.attn.masked_bias', 'h.1.attn.
masked_bias', 'h.2.attn.masked_bias', 'h.3.attn.
masked_bias', 'h.4.attn.masked_bias', 'h.5.attn.
masked_bias', 'h.6.attn.masked_bias', 'h.7.attn.
masked_bias', 'h.8.attn.masked_bias', 'h.9.attn
.masked_bias',
'h.10.attn.masked_bias', 'h.11.attn.masked_bias']
You should probably TRAIN this model on a down-
stream task to be able to use it for predictions
and inference.
Setting ‵pad_token_id‵ to ‵eos_token_id‵:50256 for
open-end generation.
=> #1 generated_text['generated_text']:
What a wonderful thing about this is that it's a
very simple and simple way to get your hands on a
new game.
The game is a simple, simple game. It's a simple
game. It's a simple game. It's
-------------------------------
Setting ‵pad_token_id‵ to ‵eos_token_id‵:50256 for
open-end generation.
=> #2 generated_text['generated_text']:
Once in a vernacular, the word "carnage" is used to
describe a large, open, and well-lit place.
The word "carnage" is used to describe a large,
open, and well-
-------------------------------
Setting ‵pad_token_id‵ to ‵eos_token_id‵:50256 for
open-end generation.
=> #3 generated_text['generated_text']:
Once in a blue urn, you can see the "C" in the
center of the "C" and the "A" in the bottom right
corner.
The "C" is the "A" and the "A" are
-------------------------------
混合匹配模型
现在你已经对基于 BERT 的模型和 GPT-2 有所了解,你可以组合不同类型的基于 Transformer 的模型,也就是说,你可以将编码器模型与解码器模型结合起来。例如,尽管这里没有提供代码,但可以将 BERT 与 GPT-2 结合起来。
另一种组合是使用 BERT 作为编码器以及解码器。由于 BERT 是一个基于编码器的模型,并且不支持基于解码器的功能,因此需要额外的代码。
幸运的是,Hugging Face 的 EncoderDecoderModel 对象包含 from_encoder_decoder_pretrained()方法,这就像一个“连接器”,它允许你将不同类型的预训练模型组合起来创建一个新的编码器/解码器模型。有关如何做到这一点的更多详细信息(以及代码)可在网上找到:
现在,让我们将注意力转向 GPT-3,这是下一节的主题。
什么是 GPT-3?
生成式预训练 Transformer 3,或称 GPT-3,是由 OpenAI 开发的最先进的语言模型之一。它的发布标志着语言模型能力的一次重大飞跃。
GPT-3 在 AI 语言模型的能力上迈出了重要的一步。它从少量示例中泛化的能力,以及能够在广泛的主题和任务上生成连贯文本的能力,令人印象深刻。然而,就像所有工具一样,它的力量伴随着使用它和其输出潜在影响的职责。
GPT-3 是 OpenAI GPT 系列的第三个迭代。虽然其前辈 GPT-2 已经因其 15 亿个参数而令人印象深刻,但 GPT-3 以其 1750 亿个参数将其远远超越,截至 2021 年 9 月,成为 GPT 系列中最大的模型。
GPT-3,就像它的前辈一样,使用的是转换器架构,由于它能够处理文本中的长距离依赖关系,因此已经成为 SOTA 语言模型的行业标准。
GPT-3 是在混合了授权数据、由人类训练师创建的数据以及多种语言的公开可用数据上训练的。如此庞大的数据量,加上其庞大的参数数量,使得 GPT-3 能够在广泛的任务上实现卓越的性能,而无需特定任务的训练数据。
GPT-3 的一个开创性特性是它能够执行少量样本学习。这意味着你可以向 GPT-3 提供少量任务示例,然后它会尝试泛化并执行该任务。这与许多其他模型形成对比,这些模型需要在特定任务上进行大量的微调。
例如,如果你给 GPT-3 提供一些将英语翻译成法语的例子,它就可以尝试翻译你提供的新的句子,即使它并没有被明确地微调用于翻译。
由于 GPT-3 令人印象深刻的通用性,涉及 GPT-3 的应用非常丰富,例如:
• 根据描述生成文本(如撰写文章或诗歌)
• 根据提供的信息回答问题
• 在语言之间进行翻译
• 为视频游戏模拟角色
• 基于描述生成代码
关于 GPT-3(这通常也适用于所有 LLMs)的其他重要考虑因素包括其输出的可靠性。虽然 GPT-3 可以生成连贯的文本,但它本身并不知道真伪。因此,它可以产生错误或误导性的答案。另一个担忧涉及道德问题,例如生成误导性信息、虚假新闻或不适当内容的可能性。
第三点考虑的是资源密集型:训练像 GPT-3 这样的模型需要大量的计算资源,这反过来又引发了 LLMs 的碳足迹问题。第四个担忧是缺乏“可解释性”。我们不知道 GPT-3(以及一般性的 LLMs)为什么提供特定的答案。
四种 GPT-3 模型
有四种 GPT-3 模型,它们在参数数量和层数上有所不同。最小的模型由 12 层和 125 M 参数组成,而最大的模型由 96 层和 175 B 参数组成。正如您所推测的,增加层数和参数数量可以提高学习能力,同时也会增加相关的成本和处理时间。
公众对 GPT-3 的反应从震惊、怀疑和焦虑到惊叹不一。有趣的是,甚至 OpenAI 的首席执行官(Sam Altman)也同意一些声明夸大了 GPT-3 的能力。
GPT-3 的关键区别在于其能够执行特定任务而无需微调。相比之下,其他模型往往需要特定任务的训练数据集,并且它们在无关任务上的表现通常不佳。
GPT-3 实际上是 GPT-2 模型的扩展,包含更多层和数据,比 GPT-2 大 100 倍。尽管 GPT-3 没有特定领域的知识进行训练,但它可以执行多种特定领域的任务,包括文本摘要和语言翻译。因此,GPT-3 可以在没有明确训练的情况下执行任务。
GPT-3 是一个预训练模型
GPT-3 在大量数据上进行了预训练,并且可以根据少量学习处理许多任务。GPT-3 可以使用各种格式的数据进行训练,包括 JSONL(JSON Lines)、纯文本和 CSV,最好以这种方式结构化,以便训练算法可以有效地处理数据并从中学习。这里展示了 JSONL 格式数据的示例:
{"prompt": "<prompt text>", "completion": "<ideal
generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal
generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal
generated text>"}
为了方便您使用,OpenAI 提供了一个 CLI 数据准备工具,用于将数据转换为 JSONL 文档。
GPT-3 最显著的基于 Transformer 的后继者包括 Gopher、Chinchilla 和 PaLM,它们都超越了 GPT-3 的能力(这些将在后面讨论)。
文本到图像的基于 Transformer 的模型 DALL-E 2、Imagen 和 Parti 采用了许多在图形界引起人们想象力的额外技术。此外,Flamingo 和 Gato 是 GPT-3 的两个支持多模态功能(即文本、音频、图像和视频)的变体。
GPT-3 架构
自回归模型的一个重要方面是它们能够根据目标变量的即时前一个值预测其未来的值:它们不需要先前值的记录。相比之下,回归模型使用多个变量的值来预测目标变量的未来值。
因此,GPT-3 的架构与 BERT 和 GPT-2 等模型不同,因为它具有以下特点:
• 因果注意力(与 BERT 对比)
• 自回归语言模型
• 96 层(gpt-3.5-turbo)
• 维度为 12288 和 96 个头
• 序列长度为 2048(GPT-2 为 1024)
• 位置嵌入
• FF 层中的 GELU
• 1750 亿参数
GPT-3 的要求和参数
GPT-3 的最低要求取决于模型的大小,具体细节如下:
• GPT-3 “小型”至少需要 16 GB 的 RAM 和至少 8 GB VRAM 的 GPU。
• GPT-3 “中型”至少需要 32 GB 的 RAM 和至少 16 GB VRAM 的 GPU。
• GPT-3 “大型”需要 600 GB 的 RAM 和具有 250 GB VRAM 的专用 GPU。
此列表中指定的数字是最低值。这些是最低要求,你可以期待更高的值以获得良好的性能。尽管 GPT-3 有 1750 亿个参数,但它与其他具有 5400 亿个参数甚至 1000 亿个参数的 LLM 不可比。GPT-3 的绝大多数参数用于使模型能够根据训练期间学习的模式理解和生成文本的计算过程中。
以下 OpenAI 网站提供了有关 GPT 最佳实践的详细信息:platform.openai.com/docs/guides/gpt-best-practices。
前述网站讨论了使用提示获得更好结果的六种策略。
GPT-3 模型
GPT-3 模型之间的主要区别在于参数数量和层数:一个模型包含 12 层和 1.25 亿个参数,而另一个模型包含 96 层和 1750 亿个参数。请注意,增加层数和参数可以提高模型的容量,同时也会增加成本和处理时间。
相比之下,GPT-3 有 1750 亿个参数,而 GPT-2 有 15 亿个参数,BERT-Large 有 3.4 亿个参数。GPT-3 完全在公开可用的数据集上训练,近 5000 亿个单词(其中一些可能包含冒犯性内容)。
GPT-3 的一个优点是其少量样本学习的能力。你可以提供更长的提示和正确的示例来提高 GPT-3 模型响应的质量。这些示例就像实时训练一样工作,并且在不修改其参数的情况下提高 GPT-3 返回的结果。
OpenAI 对你的输入提示中的标记以及 GPT-3 响应中返回的输出标记收费。
最大的 GPT-3 模型有 96 个注意力层,每个层包含 96x128 维度的头。此外,GPT-3 由 1750 亿个参数组成,并在超过 5000 亿字文本上训练,以学习如何预测用户提供的文本字符串中的下一个单词。GPT-n 模型在未标记的文本语料库上训练,而不是在标记数据上,并且针对单个任务进行微调。
自 2020 年 5 月初版发布以来,OpenAI 一直在继续为 GPT-3 添加功能。例如,GPT-3 能够编辑文本和修改代码块。
www.youtube.com/watch?v=_x9AwxfjxvE
微软于 2020 年 9 月 22 日宣布,它已获得 GPT-3 的独家使用权;尽管任何人都可以使用公共 API 并在 GPT-3 游乐场中实验,但只有微软可以访问 GPT-3 的底层模型。
GPT-3 系列支持以下公开可用的模型,每个模型都有不同的参数数量(以及不同的价格点):
• GPT-3 Ada
• GPT-3 Babbage
• GPT-3 Curie
• GPT-3 Davinci
Ada 模型是最快/最便宜的,而 Davinci 模型是最强大/最昂贵的。以下论文介绍了 GPT-3 的八个版本:
最大的前四个模型参数数量从 27 亿到 1750 亿不等。基于这一细节,我们可以推测以下情况:
• Ada 拥有 27 亿参数。
• Babbage 拥有 67 亿参数。
• Curie 拥有 130 亿参数。
• Davinci 拥有 1750 亿参数。
GPT-3 的 Ada 和 Davinci 引擎在成本上相差 75 倍。以下网站包含了对四个标准 GPT-3 模型的基准比较:
GPT-3 与多语言模型对比
在多语言领域,数据量有限的语言是一个挑战。一种可能有益的方法是将多种语言的文本连接成一个单一的数据集,这实际上是 Facebook 的 MM 数据集中使用的,可以翻译成任意一对 100 种语言之间的文本。另一个有趣的结果是利用在一个语言中训练的 LLM 来执行不同语言的任务,这可能在数据有限的语言中也能产生结果。
提醒一下,GPT-3 属于一组大规模自回归语言模型,具有以下特点:
• 少样本学习器
• 不需要微调
• 执行许多语言任务
然而,这些模型主要是用基于英语的数据集进行训练的,并且在其他通过非英语数据集训练的语言模型面前表现不佳。特别是,基于 XGLM 的模型在许多基于语言的任务上优于 GPT-3。
GPT-3 的目标是什么?
GPT-3 预训练模型的目标是直接在新任务的测试相关数据上评估模型;即,GPT-3 作为“少样本”学习者的能力,本质上跳过了新任务的训练相关数据,直接关注测试相关数据。
GPT-3 在多个 NLP 任务上实现了 SOTA 性能,而无需微调,代价超过 1000 万美元。用于训练 GPT-3 的一些数据集可以从以下只读 Github 仓库下载:
GPT-3 因其执行的各种任务而吸引了众多人的注意,包括自动代码生成。例如,一位用户输入了一段描述以下 Web 应用的文本段落:
-
一个增加总额$3 的按钮
-
一个减少总额$5 的按钮
-
一个显示当前总额的按钮
GPT-3 随后创建了一个具有先前功能的前端应用程序,这引发了各种反应:有些人觉得这样的简单应用很有趣,而其他人则在思考他们的未来职业保障。
给 GPT-3 一个初始的单词序列,GPT-3 将生成各种响应,如代码生成、新闻文章、诗歌,甚至讲笑话。
GPT-3 生成了一首关于伊隆·马斯克的有趣诗歌(“你的推文是祸害”),其中一部分你可以在这里阅读:
www.businessinsider.com/elon-musk-poem-tweets-gpt-3-openai-2020-8
GPT-3 的一个显著特点是它能够解决未见过的 NLP 任务:这归因于 GPT-3 是在一个非常大的语料库上训练的。GPT-3 还使用少量样本学习,并可以执行以下任务:
• 将自然语言翻译成网站代码
• 解决复杂的医学问答问题
• 创建表格财务报告
• 编写代码以训练机器学习模型
GPT-3 以其生成散文和诗歌的能力而令人们感到惊讶。伊隆·马斯克是创建 GPT-3 的 OpenAI 的创始人之一,它创作了以下关于伊隆·马斯克的诗歌(可在www.businessinsider.com/elon-musk-poem-tweets-gpt-3-openai-2020-8)找到):
“美国证券交易委员会说,“马斯克,/你的推文是祸害。/如果你不停止/晚上所有的推文,/这真的可能让你丢掉工作。”/…然后马斯克哭了,“为什么?/我写的推文并不刻薄,/我没有使用全大写/我确信我的推文是干净的。”/“但你的推文可以影响市场/这就是我们为什么生气。/你可能是个天才/也是一个亿万富翁,/但这并不给你权利成为一个无聊的人!”
GPT-3 能做什么?
GPT-3 生成的文本响应可以达到人类水平的质量。然而,目前它不支持音频或视频等数据格式。但是,GPT-3 可以与 DALL-E 一起处理基于图像的数据。
GPT-3 是一个统计模型,它确定单词的概率分布以生成适当的文本,以响应输入字符串。与其他在特定任务上训练的模型不同,GPT-3 旨在检测文本字符串中的模式,这提供了以下好处:
• GPT-3 是一个通用(非特定任务)模型。
• GPT-3 不需要重新训练来处理新的提示。
• GPT-3 在多个 NLP 任务上实现了 SOTA 性能。
GPT-3 的性能可能是因为 GPT-3 在超过 500 GB 的数据集上进行了训练。尽管 GPT-3 的大小和成本对绝大多数公司来说都是难以承受的,但 GPT-3 通过一个简单且经济的 API 可用。请记住,GPT-3 基于时间点的数据,这些数据可能已经几个月前就存在了,而不是持续训练。
对话式人工智能
GPT-3 的对话式人工智能方面可用于各种实现,以下是一些示例:
• 评论生成(如电影和餐厅评论)
• 预处理用户输入
• 广告
• 聊天机器人
然而,对 AI 的使用必须谨慎。一个基于 GPT-3 的医疗聊天机器人向一个假装有自杀想法的虚假患者建议他自杀:
artificialintelligence-news.com/2020/10/28/medical-chatbot-openai-gpt3-patient-kill-themselves/
GPT-3 有八个不同的模型大小(从 125 M 到 175 B 参数),最小的 GPT-3 模型大约与 BERT-Base 和 RoBERTa-Base 的大小相当,有 12 个注意力层,每个注意力层有 12x64 维度头。相比之下,最大的 GPT-3 模型比之前的记录保持者 T5-11B 大十倍,有 96 个注意力层,每个注意力层有 96x128 维度头。有关如何自定义 GPT-3 模型的详细信息,请参阅 openai.com/blog/customized-gpt3/。
此外,OpenAI 还增加了对 GPT-3 的微调支持,这可能会使其他 OpenAI 的模型也获得这种支持。
文本摘要与总结
GPT-3 支持以下类型的文本摘要,如下列所示:
• 简单摘要
• 一句话摘要
• 标准化等级摘要
• 提取摘要
你可能会找到一些文章建议将字符串 tl;dr; 添加到文本块中,以便让 GPT-3 生成简单摘要。作为一个简单的示例,在 GPT-3 操场(更多细节将在本章后面提供)中输入以下文本块:
GPT-3 has eight different model sizes (from 125M
to 175B parameters), and the smallest GPT-3 model
is about the size of BERT-Base and RoBERTa-Base,
with 12 attention layers that in turn have 12x64
dimension head. On the other hand, the largest
GPT-3 model is ten times larger than T5-11B (the
previous record holder), and has 96 attention
layers, which in turn have 96x128 dimension heads.
Details regarding how to customize a GPT3 model are
here
tl;dr;
GPT-3 的响应如下:
GPT-3 has a much larger parameter count than any
other transformer-based model, making it the
largest transformer-based model ever trained.
注意到输入文本块中的字符串 tl;dr; 在单独的一行上:如果你将这个字符串放在输入文本的同一行上,那么 GPT-3 将生成多行响应而不是一句话的摘要。
请查看第八章(第八章)中的文本分类部分,以获取一个 Python 代码示例,展示如何执行文本分类。
GPT-3 的限制
GPT-3 只能处理文本,这是一个限制而不是弱点。以下长度文章讨论了 GPT-3 的各种弱点:
nautil.us/deep-learning-is-hitting-a-wall-14467
GPT-3 有其他限制,这些限制阻止 GPT-3 执行任意文本相关任务,如下列所示:
• 输入大小有限
• 输出大小有限
• 没有任何类型的记忆
目前,GPT-3 在自然语言推理任务上存在困难,例如 ANLI 或涉及因果关系的任务。尽管 GPT-3 可以生成高质量的文章,但为了确保高度一致性的文本,人类编辑仍然被执行。
GPT-3 任务优势与错误
尽管存在局限性,GPT-3 仍然具备生成接近人类水平质量的文本的能力。例如,假设给 GPT-3 提供一个标题和副标题,以及作为提示词的“文章”一词。然后 GPT-3 可以撰写简短的文章,这些文章往往看起来像是人类所写。
请记住,用于训练 GPT-3 的语料库中存在偏见。根据以下文章,GPT-3 可能会误分类结果的一种方式是包含对女性和少数族裔的偏见:
techcrunch.com/2020/08/07/here-are-a-few-ways-gpt-3-can-go-wrong/
GPT-3 无法整合或执行涉及日常任务的推理。此外,GPT-3 也会生成错误的结果,例如由 GPT-3 驱动的聊天机器人 Replika,它“声称比尔·盖茨发明了 COVID-19”以及 COVID-19 疫苗“不太有效。”一些研究人员认为,基于深度学习的 LLMs 像是“随机鹦鹉”,它们“重复得多而理解得少。”也许 GPT-3 的不一致性部分推动了 GPT-4 的发展,这在第九章(第九章)中有所讨论。(引用和来自 nautil.us/deep-learning-is-hitting-a-wall-14467 的信息。)
GPT-3 任务性能
对于大多数模型来说,将句子从英语翻译成意大利语的任务需要成千上万的句子对,以便这些模型学习如何执行翻译。相比之下,GPT-3 不需要微调步骤:它可以处理定制语言任务,而无需训练数据。
因此,GPT-3 能够在不进行任何特殊调整的情况下执行特定任务,这是其他模型难以做到的。例如,GPT-3 可以被训练来翻译文本、生成代码,甚至写诗。此外,GPT-3 可以用不超过 10 个训练示例来完成这些任务。
GPT-3 不仅仅是一个几样本学习器:它还可以作为零样本学习器和单样本学习器。相比之下,作为零样本学习器的 GPT-3 的准确率高于经过微调的 RoBERTa 模型(该模型之前曾达到 SOTA 性能)。
在阅读理解方面,GPT-3 在自由形式的对话数据集上表现最佳,而在涉及建模结构化对话的数据集上表现最差。然而,作为该任务的几样本学习器,GPT-3 的表现优于经过微调的 BERT 基线。此外,GPT-3 在斯坦福大学的 SQuAD 2.0 数据集上表现良好,但在多项选择题上表现不佳。
GPT-3 将每个输入字符串视为确定最合适响应的提示:高质量的提示生成高质量的响应。完成是 GPT-3 生成的响应字符串的另一个术语。GPT-3 的示例可在beta.openai.com/examples找到。
GPT-3 和 BERT 的不同之处
本节包含 GPT-3 和 BERT 之间一些差异的并列比较。尽管这些细节在本章和上一章的多个位置都有提供,但本节提供了更方便的信息整合。
GPT-3(一个自回归模型)和 BERT(一个双向模型)以不同的方式获取语言上下文。具体来说,GPT-3 从自然语言输入中向前生成,而 BERT 可以从特定单词的特定方向获取语言上下文。此外,GPT-3 不需要微调即可执行任务,这与其他早期的 NLP 模型不同。然而,通过 OpenAI API 进行微调可以在特定任务上提高性能。
与 RNNs 和 LSTMs 相比,GPT-3 的另一个重要优点是它能够在语料库中维护相隔较远的单词之间的上下文信息。虽然 LSTMs 可以维护相隔十几个位置的单词的上下文,但 GPT-3 提供了更宽的上下文范围。
GPT-3 的第三个优点是其相对于少样本学习的卓越性能。
此外,GPT-3 是在如此大量的数据上训练的,因此没有必要在众多任务上训练 GPT-3。这可能部分解释了为什么 GPT-3 在这些任务上与较小模型相比表现出显著改进。GPT-3 的成就表明,模型大小确实会影响模型执行任务的能力。
简而言之,自回归涉及单向学习,而双向系统涉及双向学习。这意味着回归系统从先前的序列中学习以预测下一个项目,而双向系统可以使用未来和过去的信息。相比之下,BERT 是双向的,这意味着它可以从模型上下文中学习任何内容。
考虑到上述要点,BERT(以及其他双向模型)在文档分类或阅读理解问题中表现出色,这些问题要求你将某个整体作为处理对象,然后对其回答。GPT-3(以及其他自回归模型)通过处理输入然后生成输出,实现了少样本范式。
迁移学习指的是对预训练模型进行微调的结果。实际上,即使是用于微调的包含 100 个样本的数据集也能显著提高预训练模型的表现。然而,微调和少样本学习之间仍然存在性能差距。尽管少样本学习表现非常好,有时甚至可以与人类水平的表现相媲美,但结果的质量并不一致。
GPT-3 操场
OpenAI 创建了 GPT-3 操场,这是一个基于 Web 的工具,可以在文本字段中输入提示并从 GPT-3 接收完成。操场支持 GPT-3 API 中大部分直接可用的功能。
此外,操场还允许你与 GPT-3 交互,而无需编写任何代码。本质上,OpenAI 操场允许你轻松使用 GPT-3 来训练引擎以产生文本输出。GPT-3 操场还提供了一套称为预设的已保存提示。
第一步是导航到 GPT-3 操场,你将被提示登录你的账户:
一旦你注册了账户,你将看到由三个部分组成的主页:一个“开始”部分,一个“操场”部分,以及一个包含下拉列表和可调节参数滑块的第三部分。
中间部分是 GPT-3 的输入文本,它包含两部分:1)一个起始序列,即文本字符串 Text:,后面跟着一个或多个由你提供的文本块(为 GPT-3 提供样本输出文本)。第二段包含相同的字符串 Text:,表示你的输入文本的结束。
让我们推迟对 GPT-3 操场中出现的滑块的描述,直到本章的后面部分,然后直接进入在 GPT-3 操场中生成代码。
使用 Davinci 引擎的 GPT-3 代码生成
导航到 GPT-3 操场,确认选择了 Davinci 引擎后,在操场(即屏幕中间部分)输入以下三个句子:
Add a 400x400 canvas with a blue background to the
document.
Add a text display in the lower left corner of the
scene.
Add a map to the canvas.
点击屏幕左下角的提交按钮。GPT-3 会生成你看到的图 7.1 中的输出。

图 7.1 GPT-3 代码生成
为了方便起见,列表 7.6 显示了文本文件 gpt_3_generated_code.txt 的内容。
列表 7.6: gpt3_generated_code.txt
Add a 400x400 canvas with a blue background to the
document.
Add a text display in the lower left corner of the
scene.
Add a map to the canvas.
var canvas = document.createElement('canvas');
canvas.width = 400;
canvas.height = 400;
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(0,0,400,400);
var text = document.createElement('text');
text.innerHTML = "Map";
text.style.fontFamily = 'Arial';
text.style.fontSize = '18px';
text.style.color = 'white';
text.style.position = 'absolute';
text.style.left = '10px';
text.style.bottom = '10px';
document.body.appendChild(text);
GPT-3 可以从相同的提示中生成不同的输出,这意味着你的输出可能与列表 7.6 不同。例如,列表 7.7 显示了与列表 7.6 相同的三个提示生成的不同代码。
列表 7.7: gpt3_generated_code2.txt
Add a 400x400 canvas with a blue background to the
document.
Add a text display in the lower left corner of the
scene.
Add a map to the canvas.
<canvas id="myCanvas" width="400" height="400"
style="background-color:blue;"></canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// add text display
ctx.font = "30px Arial";
ctx.fillStyle = "#ffffff";
ctx.fillText("Hello World", 10, 50);
// add map
var map = new Image();
map.onload = function(){
ctx.drawImage(map, 0, 0);
}
map.src = "map.png";
// add player
var player = new Image();
player.onload = function(){
ctx.drawImage(player, 0, 0);
}
player.src = "player.png";
列表 7.7 包含了创建和放置屏幕上 UI 元素的文本提示,以及使用 Davinci 引擎生成的 GPT-3 输出。列表 7.7 的初始部分包含相同的提示,最外层的 <div> 元素及其内容是 GPT-3 生成的响应,这些内容在 列表 7.8 中展示。
列表 7.8:gpt3_generated_code3.txt
Add a 400x400 canvas with a blue background to the
document.
Create 3 text input boxes that accept a digit
Make the height of the digits equal to 80px
Center the digit in each input box
Place the text input boxes in the same row
Place the row at the bottom of the document
Make the boxes 25% of the width of the div
Make the boxes 50% of the height of the div
<div style="width:80%;height:80%;text-align:center;
position:relative;bottom:0;">
<input type="text" style="width:25%;height:50%;
font-size:80px;text-align:center;"/>
<input type="text" style="width:25%;height:50%;
font-size:80px;text-align:center;"/>
<input type="text" style="width:25%;height:50%;
font-size:80px;text-align:center;"/>
</div>
推断参数
在完成 LLM 的微调步骤后,您可以设置各种推断参数的值。GPT-3 API 支持许多推断参数,其中一些在此处展示:
• 引擎
• 提示
• max_tokens
• top_p
• top_k
• 频率惩罚
• 存在惩罚
• 标记长度
• 停止标记
• 温度
引擎推断参数可以是四个 GPT-3 模型之一,例如 text-ada-001。提示参数简单地是您提供的输入文本。存在惩罚推断参数允许在指定更高值时提供更相关的响应。
max_tokens 推断参数指定了最大标记数:样本值是 100、200 或 256。top_p 推断参数可以是一个正整数,用于指定要选择的最顶层结果。frequency_penalty 是一个与重复单词频率相关的推断参数。此参数的值越小,重复单词的数量就越多。
标记长度参数指定了 LLM 处理的输入序列中的总单词数(而不是每个标记的最大长度)。
停止标记参数控制 LLM 生成的输出长度。如果此参数等于 1,则只生成一个句子;而值为 2 表示生成的输出限制在一个段落内。
top_k 参数指定了选择的标记数(即 k 的值),这些标记具有最高的概率。例如,如果 top k 等于 3,则只选择概率最高的 3 个标记。
top_p 参数是一个介于 0.0 和 1.0 之间的浮点数,它是所选标记概率总和的上限。例如,如果离散概率分布由集合 S = {0.1, 0.2, 0.3, 0.4} 组成,并且“top p”参数的值为 0.3,那么只有与概率为 0.1 和 0.2 相关的标记可以被选中。
因此,top k 和 top p 参数提供了两种限制可选择的标记数量的机制。
温度参数
温度推断参数是一个介于 0 和 1(包括 1)之间的浮点数,其默认值为 0.7。温度的一个有趣值是 0.8:这将导致 GPT-3 选择一个下一个标记,该标记的概率不是最大的。
温度推理参数 T 是一个非负浮点数,其值影响模型使用随机性的程度。具体来说,温度参数值较小且接近 0 时,涉及较少的随机性(即更确定),而温度参数值较大时,涉及更多的随机性。
温度参数 T 直接与在 transformer 架构的最终步骤中应用的 softmax()函数相关联。T 的值改变了本节后面描述的 softmax 函数的公式。一个需要记住的重要点是,基于 softmax()函数选择标记意味着所选标记是具有最高概率的标记。
相比之下,参数 T 的较大值允许在下一个标记的选择中引入随机性,这意味着即使关联的概率小于最大概率,也可以选择标记。虽然这看起来可能有些不合直觉,但某些 T 的值(如 0.8)产生的输出文本在人类看来比选择具有最大概率的标记的输出文本更自然。最后,温度值为 1 与标准的 softmax()函数相同。
顺便提一下,第八章中的“文本补全与温度”部分包含一个 Python 代码示例,该示例调用 OpenAI 的 Completion 类以使用不同的温度值进行文本补全(结果很有趣)。
温度与 softmax()函数
温度参数 T 出现在 softmax()函数中欧拉常数 e 的指数的分母中。因此,修改后的 softmax()函数包含形式为 e^(xi/T)的分子项,其中{x1, x2, … , xn}构成一个形成离散概率分布的数字集合。
作为提醒,softmax()函数生成的每个项的分母是集合 {e^(x1), e^(x2), … , e^(xn)} 中项的总和。然而,涉及温度参数 T 的项的分母略有不同:它是集合 {e^(x1/T), e^(x2/T), … , e^(xn/T)} 中项的总和。
有趣的是,具有温度参数 T 的 softmax()函数与玻尔兹曼分布相同:
在第八章的“微调与强化学习”部分下的子节提供了有关离散概率分布的额外细节。你应该进行网络搜索以获取更多关于可调整推理参数的信息。
下面的 Python 代码片段提供了一个指定各种推理参数值的示例,包括 GPT-3 引擎:
response = openai.Completion.create(
engine="text-ada-001",
prompt="",
temperature=0.7,
max_tokens=256,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
欲了解更多有关 GPT-3 推理参数的信息,请访问以下网站:huggingface.co/blog/inference-endpoints-llm.
提示工程概述
各种语言模型需要微调才能执行下游任务,这有时需要向模型添加一个或多个层。相比之下,GPT-3 基于一个单一模型,该模型不需要添加额外的层或微调即可执行额外任务。
事实上,GPT-3 使用一种系统,其中可以将零、一个或几个示例添加到模型的输入之前。任务描述、示例(如果有)和提示的组合为 GPT-3 提供上下文,以便 GPT-3 可以逐个标记地预测输出。
例如,假设任务描述是句子“将英语翻译成意大利语”,后面跟着几个英语/意大利语单词对作为示例。那么提示就是一个英语单词(例如,“cow”),模型将其翻译成意大利语(“vacca”)。
使用提示
从本质上讲,一个提示是一个文本字符串,它为 GPT-3 提供有关对输入字符串(即提示)的预期答案类型的说明(即提示)。这种技术在处理语言模型方面非常有效。
例如,如果你多次向 GPT-3 提交相同的提示,结果并不一致(尽管相似)。提高响应一致性的方法之一被称为提示工程,当它与微调结合使用时,可以获得更一致的响应。
具体来说,提示工程包括设计提示以及其“完成”部分(即模型的响应),以便模型能够以期望的方式执行。一个精心设计的提示设计可以实现更高的预测率,并有助于生成响应的处理。通过提示工程获得的结果质量涉及大量样本提示,这些样本提示的数量可能取决于具体的 NLP 任务。
设计提示
精心设计的提示工程可以使你比传统方法更容易地自动化下游任务。然而,针对同一任务精心设计的两个提示可以生成实质上不同的结果。从非正式的角度来看,精心设计的提示让人联想到体育中的“良好指导”:两者都倾向于产生期望的结果。换句话说,一个精心编写的提示以简洁的方式提供详细和有意义的信息。
尽管 GPT 模型通常需要几百个示例来完成大多数下游任务,但这种方法显然优于需要数千个训练示例的其他技术。
另一个需要考虑的方面是可能产生的微调和解推理的成本。调查提供 API 以执行此类任务的付费服务的成本效益可能是有价值的。
此外,评估预测准确性的任务可能比传统方法更复杂,对于大型 LLM(如 GPT-3 或 GPT-J)来说,推理速度往往较慢,因为预测必须传播到大量参数。现在考虑制作几十万个预测所需的时间:经过的时间可能涉及数小时(甚至几天)。
因此,指定良好提示的能力可能是一个试错学习过程,它是科学和艺术的混合体。
思维链提示
思维链(CoT)提示是一种涉及一系列指导性答案的多步骤序列技术。这项技术在一篇 arXiv 论文中有所描述,该论文涉及在每个答案之前插入文本“让我们一步步思考”。CoT 技术的创造者断言,他们的 Zero-shot-CoT 在多个任务上优于零样本 LLM。此外,arXiv 论文的作者在 LLM(如 175B 参数的 InstructGPT 模型和 540B 参数的 PaLM 模型)上应用了他们的技术,而没有使用任何少样本示例。
作者还建议在执行微调任务之前,投入额外努力提取 LLM 中嵌入的零样本知识。有关更多信息,请访问arxiv.org/abs/2205.11916。
另一篇关于 CoT 提示的 arXiv 文章可在以下链接找到:
自我一致性和 CoT
自我一致性是一种自监督技术,它利用 CoT 提示以及一种优于 CoT 中的贪婪技术的解码技术。具体来说,它从一组生成的样本中进行选择,而不是依赖于纯粹的贪婪方法。有关自我一致性的更多信息可在网上找到:arxiv.org/abs/2203.11171。
根据前述论文的作者,他们的“经验法则”是生成大约二十多句的列表,然后从中选择最佳句子。此外,在 LLM(如 GPT-3、LaMDA 和 PaLM)上使用通用 CoT 提示的性能不如自我一致性。有关更多详细信息,请参阅 arXiv 论文中的表 2。
自我一致性、CoT 和无监督数据集(LMSI)
通过利用预训练模型和微调以及大量数据集,LLM 已经取得了令人印象深刻的成果。然而,要进一步提高性能,需要大量的高质量监督数据集。一种方法涉及语言模型自我改进(LMSI),它使用无监督数据来改进 LLM。这项技术使用少量样本 CoT 作为提示,以及多数投票方案来选择预测。有关自我一致性、COT 和无监督数据集的更多信息可在网上找到:arxiv.org/pdf/2210.11610.pdf。
提示工程细节
提示工程是与大型语言模型(LLMs)一起工作的关键方面,这显然包括 GPT-3 和 GPT-4。随着我们与 LLMs 一起工作的经验越来越多,社区继续发展最佳实践和策略,以从这些模型中获得最佳输出。
提示工程是指创造输入提示的艺术和科学,以引导语言模型以期望的方向输出。鉴于 GPT-3 等模型广泛的知识和能力,问题的提出或提示的方式可以显著影响回应的质量、准确性和相关性。
提示工程的重要性
以下列表包含几个与提示工程重要性相关的理由,以及每个理由的简要描述:
• 模型引导
• 输出质量
• 任务规范
模型引导:LLMs 本身没有特定的目标或意图。它们根据从数据中学习到的模式生成回应。一个精心设计的提示可以引导模型生成更准确和相关的回应。
输出质量:不同的提示可以产生不同质量的答案。一个精致的提示可以引发更详细或更微妙的回应。
任务规范:对于特定任务,如代码生成或解决数学问题,提示的结构方式对于获得所需输出可能至关重要。
提示类型
以下列表包含几个与提示工程重要性相关的理由,以及每种提示类型的简要描述:
• 开放式提示
• 闭合式提示
• 指导性提示
• 引导性提示
• 迭代式提示
• 温度和最大标记数
开放式提示:这些是通用和广泛的,允许模型决定答案的方向。此类提示的例子是“告诉我关于太阳系的事情。”
闭合式提示:这些寻求特定的答案或事实,例如“谁是美国的第一个总统?”
指导性提示:这些指导模型执行特定任务或以特定方式生成内容。例如,“将以下英文文本翻译成法语:…”
引导性提示:这些提供了额外的上下文或指导,以引导模型的回应。此类提示的例子是“如果我是一个 10 岁的孩子,请解释量子力学。”
迭代式提示:这涉及与模型的一系列“来回”对话,根据模型之前的回应来细化查询。这就像进行一场对话,逐渐缩小到期望的答案。
温度和最大标记数:尽管不是传统意义上的提示,但调整“温度”(控制模型输出的随机性)和“最大标记数”(限制回应长度)等参数也可以塑造模型的答案。
有效提示的指南
对于 ChatGPT 和类似模型,提示的有效性通常取决于上下文以及所需的具体信息或响应。然而,某些类型的提示往往在引发模型详细和细微的响应方面更有效。
对于 ChatGPT 和类似模型,你必须清楚你想要哪种类型的答案。指导性和教学提示有助于提供这种清晰度。然而,尝试和迭代你的提示也很有用,因为有时甚至一个稍微不同的提示措辞也可能导致显著不同的输出。
以下列表包含了一系列有效提示工程的指南,以及每个项目符号的简要描述:
• 明确表达。
• 尝试。
• 利用参数。
• 审查和迭代。
明确表达:清楚地说明你想要什么。如果你想得到一个简要的总结,请具体说明你想要的内容。
提供上下文:提供一些背景信息可以帮助引导模型的响应。
尝试:通常需要多次尝试来完善提示并获得所需的输出。不要犹豫重新措辞或提供额外的指示。
利用参数:如果直接通过 API 使用 GPT-3 等模型,可以通过调整温度等参数来获取不同风格的响应。
审查和迭代:根据你收到的输出不断改进你的提示。这种迭代方法可以随着时间的推移产生更有效的提示。
ChatGPT 有效的提示示例
指导性和教学提示通常是 ChatGPT 最有效的。这些提示提供上下文或指导,或者指示模型以特定方式回答。它们有助于将模型的广泛潜在回答空间缩小到更具体且与用户意图一致的内容。以下展示了几个改进提示的示例。
明确指示:与其说“第二次世界大战”,不如说“提供第二次世界大战的简要概述。”
提供上下文:与其说“解释相对论”,不如说“用简单的话解释爱因斯坦的相对论,针对没有物理背景的人。”
请求特定格式:与其说“Python 循环”,不如说“给我一个 Python 中 for 循环的示例。”
指导深度或细节水平:与其说“告诉我关于黑洞的事情”,不如说“给我一个关于当前科学对黑洞理解的详细概述。”
设定场景:与其说“如何开始创业?”,不如说“想象我是一个软件工程背景的大学毕业生。我应该如何着手创办一家科技初创公司?”
比较或对比信息:与其说“什么是社会主义?”,不如说“从经济原则的角度比较和对比社会主义与资本主义。”
请求步骤或过程:与其说“烘焙蛋糕”,不如说“列出烘焙巧克力蛋糕的逐步过程。”
引导语气或风格:与其说“给我讲一个故事”,不如说“给我讲一个关于猫和狗的短而幽默的故事。”
少样本学习和微调 LLM
少样本学习是一种在不更新 LLM 参数的情况下为 LLM 提供额外训练的方法。然而,在少样本学习中涉及一个大小限制(即数据)。然而,微调允许你在比少样本学习更大的数据集上训练模型。因此,你可以为 LLM 在更多样化的任务上获得更好的结果。
GPT-3 支持少样本学习、微调和基于提示的学习,这些内容将在以下小节中讨论。你将了解三种主要的提示类型,以及少样本学习与微调、微调与提示之间的权衡。此外,还有一个部分包含选择 GPT-3 模型以供你任务的建议。
尽管非常大的 LLM 往往对少样本学习反应良好,但较小的 LLM 不一定通过少样本学习得到改善,即使包括多个示例也是如此。此外,包含示例会减少可用于包含其他相关信息的上下文窗口的部分。
在前一个场景中,微调一个大型语言模型(LLM)可以是一个可行的替代方案,这是一种监督学习技术,涉及一个规模较小但高度精选的数据集。数据集的元素用于更新 LLM 中的权重。
注意,每个元素都包含一个提示和其完成内容,这与 LLM 的无监督预训练步骤不同。由于微调涉及更新 LLM 中的权重,这种技术不同于零样本、单样本和少样本学习,这些学习方式不更新 LLM 的权重。
完全微调更新 LLM 中的所有参数,这意味着创建了一个预训练模型的新版本。然而,存储预训练 LLM 的所有参数可能需要更大的内存。
预训练涉及通过自监督学习使用大量非结构化文本数据来训练 LLM。相比之下,微调是一个监督学习过程,涉及一个规模较小的数据集,该数据集包含用于更新 LLM 权重的标记示例。
此外,标记的示例是提示完成对,微调过程扩展了模型的训练,以提高其在特定任务上生成良好完成内容的能力。
少样本学习
GPT-3 支持少样本学习,这允许你提供带有正确示例的提示来改进模型的响应。因此,不需要在 GPT-3 中更新参数,因为少样本学习的样本充当模型的训练数据。
事实上,GPT-3 展示了即使没有参数更新或特定任务的数据,少样本学习也能取得显著的结果。GPT-3 首先表明,LLM 可以用于少样本学习,并且可以在不进行大规模特定任务数据收集或模型参数更新的情况下取得令人印象深刻的结果。
用户可以将他们定制的训练数据集上传到 GPT-3 的微调版本,该版本也托管在 OpenAI 上,并通过其 API 访问。根据定制数据集的大小,微调 GPT-3 的执行时间可以从几分钟到几小时不等。然而,微调大型模型所需的数据量比小型模型少。
少样本学习和提示
GPT-3 的一个有趣方面是通过提示进行少样本学习,这是一种以输入字符串的形式提供指令的技术。这样的提示为 GPT-3 提供了预期响应类型的示例,GPT-3 可以利用这些示例有效地提供与提示信息一致的响应。阅读第八章中的“提示的力量”部分,以了解 GPT-3 基于积极提示和消极提示将生成的输出类型的清晰对比。
GPT-3 还使用“条件概率”,其工作原理如下:给定一组单词,它计算给定单词在该组单词中成为下一个单词的概率。因此,GPT-3 可以将一组单词作为输入,并准确地预测下一个单词。实际上,GPT-3 可以做更多:给定一个输入字符串,GPT-3 可以生成有意义的完整文章(即,它们不是胡言乱语的字符串)。不幸的是,GPT-3 做出的某些陈述可能是错误的。
使用符号调优进行微调
一种最近(本书付印时)进行微调的技术称为“符号调优”,由谷歌开发。符号调优专注于输入-标签映射以进行更好的微调。有关符号调优的更多信息可在网上找到:
LoRA、量化与 QLoRA
本节简要讨论了 LoRA 和 QLoRA,两者都适用于微调 LLM(参见本节末尾的链接)。
低秩适配器,LoRA,是一组可训练的参数。在微调 transformer 架构的过程中,这些小参数集被注入到 transformer 的每一层。
此外,这些小的权重集在微调过程中被更新,而原始模型权重保持冻结。这种技术的优势是显著减少了下游任务的可训练参数数量。此外,Hugging Face 创建了参数高效微调(PEFT)库,该库支持 LoRA。
量化涉及以具有较小精度的数据类型存储数据。例如,您可能使用 8 位数据类型(即字节)来存储 16 位数据或 32 位数据。显然,这种位数减少会导致精度损失。有趣的是,量化导致了一个模型,其减小的大小可以超过精度损失。
本节第三个主题是量化低秩自适应(QLoRA)。QLoRA 结合了量化和低秩自适应,以实现 AI 模型的有效微调。QLoRA 的优势在于在大型语言模型(LLM)的微调步骤中减少内存。有关 QLoRA 对 LLM 微调的相关信息,可在网上找到:arxiv.org/abs/2305.14314。
摘要
本章开始时讨论了 GPT-2 和 GPT-3 的一些功能,以及一些基于 Python 的代码示例。然后您学习了三种主要的知名大型语言模型(LLM)类型:仅编码器、仅解码器和编码器-解码器模型。
接下来,您学习了来自 OpenAI 的基于 GPT 的语言模型家族,随后是对 GPT-3 的高层次介绍,包括其目标以及基于 GPT-3 的几个模型。
此外,您还看到了 GPT-3 和 BERT 的比较,以及 GPT-3 的优缺点。此外,您还了解了 GPT-3 Playground,在那里您可以使用 GPT-3 进行推理。最后,您还学习了如何在 GPT-3 中创建提示。
第八章
深入探讨 GPT-3
本章包含了一系列广泛的主题,包括微调、GPT-3 提示样本、GPT-3 中的文本相关示例以及一些 GPT-3 的开源变体。
本章的第一节讨论了基尼不纯度、熵和交叉熵的概念,作为理解库尔巴克-莱布勒(KL)散度的先导。此外,还讨论了带有人类反馈的强化学习(RLHF),它可以使用 KL 散度。本节还简要讨论了 TRPO、PPO 和 DPO 等算法。
本章的第二部分提供了大量 GPT-3 的提示及其完成示例,例如 SVG、代数和数论、烹饪食谱、与股票相关的提示以及数学提示。
本章的第三部分解释了如何创建和使用 OPEN_API_KEY 变量,这是您从 Python 代码调用 OpenAI API 所必需的。本节还提供了一些关于温度推理参数的细节,然后展示了如何使用 OpenAI 的 completion() API。
本章的第四部分简要讨论了一些基于 GPT-3 的应用,例如 AlphaCode、BlenderBot 3 以及一些写作助手。此外,你还将了解 GPT-3 的开源变体,如 EleutherAI 和 YaLM。
微调和强化学习(可选)
本节被包含进来是因为强化学习(RL)和微调大型语言模型(LLM)之间的有趣交集。强化学习(RL)已被用于训练机器人、赢得围棋和象棋等游戏,以及在与人类进行的在线团队游戏中获胜。尽管本节没有深入探讨 RL 的这些方面,但网上有关于 RL 及其许多算法的文档和教程。
本节及其子节的目的在于帮助你理解带有人类反馈的强化学习(RLHF),该技术用于微调大型语言模型(LLM)。如果你已经熟悉强化学习(RL),那么 RLHF 的一句总结就是它基于近端策略优化(PPO)算法。
如果你对强化学习(RL)和带有人类反馈的强化学习(RLHF)不熟悉,以下几节将讨论离散概率分布、基尼不纯度、熵和交叉熵,以逐步理解库尔巴克-莱布勒散度(KLD),这在强化学习算法中很常见。特别是,KLD 在信任域策略优化(TRPO)中使用,而 PPO 就是从此算法派生出来的。
离散概率分布
本主题被包含在这里是因为它与上一节讨论的顶部 p 参数相关。此外,softmax() 激活函数会产生一个离散概率分布。如果你不熟悉 softmax() 激活函数,你将在机器学习的许多地方遇到这个函数,例如在 Transformer 架构和卷积神经网络(CNNs)中。以下网站讨论了 softmax() 函数以及大量其他激活函数:
如果你检查 Transformer 架构的编码器/解码器图,你将看到编码器组件中的最后一个(最顶部的)操作是对一组数字应用 softmax() 函数,而生成的新的数字集合是一个离散概率分布。
一个 离散概率分布 涉及一个有限集合 S 中的数字,其中 S 中的数字具有以下两个特性:1) 数字在 0 和 1 之间,2) 这些数字的总和等于 1。
一个简单的例子是抛一个平衡的硬币:有两种结果(正面和反面),其概率在集合 S = {1/2, 1/2} 中。另一个例子是抛一个平衡的骰子:有六个等可能的概率,它们在集合 S = {1/6, 1/6, 1/6, 1/6, 1/6, 1/6} 中。
基尼不纯度
描述基尼不纯度的最简单方法可能是先向您展示公式,然后再展示基尼不纯度的工作示例。给定一个离散概率分布 P = {p1, p2, …, pn},基尼不纯度的公式如下:
GINI impurity = 1 - (SUM pi*pi)
= SUM pi - (SUM pi*pi)
= SUM (pi - pi*pi)
= SUM pi*(1 - pi)
作为计算基尼不纯度的示例,让我们从一个包含 10 个元素且分布如下集合 S 开始:
class A: 5 elements p(A) = 5/10 p(A)*p(A) = 25/100
class B: 3 elements p(B) = 3/10 p(B)*p(B) = 09/100
class C: 2 elements p(C) = 2/10 p(C)*p(C) = 04/100
GINI impurity = 1 - (SUM pi*pi)
= 1 - [(25+09+04)/100] = 1 - 38/100
= 0.62
现在让我们来看基尼不纯度的另一个示例,这次是一个包含 10 个元素的集合 S,其分布如下:
class A: 9 elements p(A) = 9/10 p(A)*p(A) = 81/100
class B: 1 elements p(B) = 1/10 p(B)*p(B) = 01/100
GINI impurity = 1 - (SUM pi*pi)
= 1 - [(81+01)/100] = 1 - 82/100
= 0.18
有趣的是,基尼不纯度和熵在机器学习中都很常见,并且这两种技术都有强烈的支持者。
考虑另一个观察结果。如果集合 S 包含属于同一类 A 的 10 个元素,那么有一个单独的概率为 1(= 100/100),因此基尼不纯度等于 0,如下所示:
GINI impurity = 1 – (SUM pi*pi)
= 1 – (100/100)*(100/100) = 1 – 1 = 0
基尼不纯度为 0 的值在直观上是有意义的:如果一个集合的所有元素都属于同一类,那么就没有“不纯度”,因此基尼不纯度等于 0。现在让我们将注意力转向熵,这是下一节的主题。
熵
本节讨论熵,这是克劳德·香农在 1949 年发表的开创性论文中定义的,该论文建立了信息论。给定一个离散概率分布 P = {p1, p2, …, pn},熵 H 的公式如下:
H(P) = -(SUM pi* log pi) (<= log is base 2)
注意,H 的值对于任何离散概率分布都是正的,原因如下。每个 pi 都在 0 和 1 之间,因此 log(pi) 是一个负数,这意味着 pi * log(pi) 的乘积也是负数。因此,所有这些项的总和是一个负数,而 H 公式中的“-”符号将这个负数转换成正数。
由于熵的公式包含对数(以 2 为底),两个示例(以及一般情况)的熵计算通常涉及对数表。结果计算比前节中基尼不纯度的计算稍微复杂一些。
随意计算前节中两个示例的熵值。请注意,虽然基尼不纯度可以是 0 到 1 之间的任何数(包括 0 和 1),但熵可以是任何非负数。此外,熵可以大于 1。同时,我们现在可以继续解释交叉熵,这是下一节的主题。
交叉熵
尽管交叉熵和 KL 散度(Kullback-Leibler Divergence)以复杂著称,但我们可以从以下简单问题开始直观地思考它们:我们如何确定一对数字 a 和 b 之间的距离?答案是直接的:只需计算 a 和 b 之间的算术差的绝对值。
从本质上讲,交叉熵和 KL 散度(Kullback-Leibler Divergence)将这个想法(计算两个数之间的差异)推广到回答相同的问题,即寻找一对离散概率分布之间的差异(更好的名称是散度)。
一种可能性涉及计算两个概率分布中成对数字的算术差,其中两个分布中的概率都是按递增顺序排序的。
在本节中,我们将检查两个离散概率分布 P 和 Q 之间的交叉熵,作为确定 P 和 Q 之间“差异”的机制。假设 P 和 Q 由以下数字集合定义:
P = {p1,p2,…,pn}
Q = {q1,q2,…,qn}
回想一下,P 和 Q 的熵 H 定义为如下:
H(P) = Entropy(P) = - (SUM pi * log pi)
for 1 <= i <= n
H(Q) = Entropy(Q) = - (SUM qi * log qi)
for 1 <= i <= n
P 和 Q 的交叉熵(CE)的定义如下所示:
CE(P,Q) = - (SUM pi * log qi) for 1 <= i <= n
基于前面的交叉熵公式,我们可以在下一节中继续定义 Kullback-Leibler 散度。
Kullback-Leibler 散度(KLD)
在我们开始之前,以下关于对数的相关公式将在以后很有帮助:
log(a*b) = log a + log b
log(a/b) = log a - log b
KLD 的公式基于熵的公式和交叉熵的公式,如下所示:
KLD(P, Q) = CE (P,Q) - H(P)
= -SUM (pi * log qi) - (-SUM
(pi * log pi))
= -(SUM [ pi * log qi - pi * log pi ])
= -(SUM [ pi * (log qi - log pi) ])
= -(SUM [ pi * (log qi/pi) ])
= SUM [ pi * (log pi/qi) ]
注意到在子节开头看到的第二个对数公式的使用。
另一个细节涉及 KLD(Q,P)的公式,它与 KLD(P,Q)的公式非常相似,如下所示:
KLD(Q, P) = CE (Q,P) - H(Q)
通常,KLD(P,Q)与 KLD(Q,P)不同,这意味着 KLD 不是一个度量(衡量两个“对象”之间距离的东西)。距离函数在en.wikipedia.org/wiki/Metric_(mathematics)中定义得非常详细。
Jenson 和 Shannon(定义熵的同一 Claude Shannon)在这里讨论了 JS 散度:
en.wikipedia.org/wiki/Jensen%E2%80%93Shannon_divergence
JSD 的优点是它定义了一个真正的距离度量(而 KLD 则不是)。
RLHF
从人类注释员的反馈中进行的强化学习(RLHF)通过人类指定的期望输出对 LLM 进行微调。第一步涉及一组提示,LLM 可以从中生成多个响应。接下来,每个响应都被分配一个分数(再次由人类分配),该分数基于每个响应的质量。
第三步是新颖的:分配的分数为训练奖励模型提供数据,该模型由回归层和微调的 LLM 实例的组合组成。奖励模型用于预测响应的分数。然后使用称为近端策略优化(PPO)的强化学习算法来微调模型以最大化此分数。正如你可能推测的那样,通过 SFT 以及 RLHF 训练的 LLM 往往会导致性能最高的 LLM。作为旁注,由于性能和易用性,PPO 是 OpenAI 的默认 RL 算法。
TRPO 和 PPO
一个早期的算法是信任区域策略优化(Trust Region Policy Optimization,TRPO),它曾经很受欢迎,直到被 PPO 所取代。TRPO 的部分复杂性涉及 Kullback-Leibler 散度(这不是一个度量)作为选择最大可能步骤以改善性能的机制。
相比之下,PPO 进行的是较小且更为谨慎的更新,其复杂度低于 TRPO 算法。有关 TRPO 和 PPO 的更多信息可在网上找到:
towardsdatascience.com/trust-region-policy-optimization-trpo-explained-4b56bd206fc2
你还可以在以下网址了解更多关于 RLHF 的信息:huggingface.co/blog/rlhf。
DPO
直接偏好优化(Direct Preference Optimization,DPO)是一种算法,由一群斯坦福研究人员于 2023 年中开发,作为 PPO 的替代方案,DPO 的 arXiv 论文可在以下网址获取:arxiv.org/abs/2305.18290。
虽然 PPO 涉及到训练奖励模型时的偏好模型,但 DPO 涉及到训练一个策略(强化学习中的一个概念)以最大化奖励模型。此外,DPO 不需要在训练步骤中学习奖励函数。
根据斯坦福研究者的说法,DPO 达到了基于 RLHF 的算法相同的结果。此外,他们断言,基于 DPO 的算法是 PPO 基于 RLHF 的更简单替代方案,可以产生相似的结果。尽管 DPO 算法中没有明确提到,但很可能是 DPO 算法使用了交叉熵损失函数。
GPT-3 与提示样本
这个非常长的部分包含几个子部分,涉及向 GPT-3 提供各种提示:
• 可缩放矢量图形(SVG)
• GPT-3 与算术运算
• 代数与数论
• 提示的力量
• 与语言相关的提示
• 不完整的响应
什么是指令说明
• 生成文章
• 语言翻译
• 烹饪食谱
• 写诗
SVG(可缩放矢量图形)
在 Playground 中输入以下提示以生成一些基于 SVG 的代码:
Generate SVG code for an ellipse with a radial gradient.
GPT-3 生成了以下响应:
<ellipse cx="50" cy="50" rx="40" ry="40"
fill="url(#MyGradient)">
<radialGradient id="MyGradient">
<stop offset="0%" stop-color="#FFFFFF"/>
<stop offset="100%" stop-color="#000000"/>
</radialGradient>
</ellipse>
在 Playground 中输入以下提示:
Generate a quadratic bezier curve and a cubic
bezier curve in SVG.
GPT-3 提供了以下响应:
A quadratic bezier curve has one control point, and
a cubic bezier curve has two control points.
在 Playground 中输入以下提示:
Generate the code for a quadratic bezier curve and
a cubic bezier curve in SVG.
GPT-3 提供了以下响应:
A quadratic bezier curve has the following SVG
code:
<path d="M0,0 C0,0 0,0 0,0" />
A cubic bezier curve has the following SVG code:
<path d="M0,0 C0,0 0,0 0,0 0,0 0,0 0,0" />
GPT-3 与算术运算
在 Playground 中输入以下提示:
What is the square root of 81.
GPT-3 提供了以下响应:
9
在 GPT-3 中输入以下输入提示:
If I add 5 and 8 and subtract 4 what is the result?
GPT-3 提供了以下响应:
The result is 9.
Now insert a line feed in the preceding response
(see the section called "Quirk"), and press
"submit" and you will see the
following response from GPT-3:
5 + 8 = 13
13 - 4 = 9
在 Playground 中输入以下提示:
What is the product of 8 and the square root of 9?
GPT-3 在点击“提交”按钮 5 次(并插入所需的换行符)后提供了以下响应:
The product of 8 and the square root of 9 is 72.
8 * sqrt(9) = 72
8 * 3 = 72
Since the square root of 9 is 3, the product of 8
and the square root of 9 is 72.
8 * 3 = 72
然而,以下输入提示并连续两次点击“提交”得到了正确答案:
What is the product of the square root of 9 and 8?
The product of the square root of 9 and 8 is 6.
The square root of 9 is 3 and 3 times 8 is 24.
代数与数论
在 Playground 中输入以下提示:
What is the quadratic formula.
GPT-3 提供了以下响应:
The quadratic formula is used to solve quadratic
equations. The quadratic equation is of the form
ax² + bx + c = 0\. The quadratic formula is
x = (-b +/- sqrt(b² - 4ac))/2a.
在 Playground 中输入以下提示:
What is the smallest odd perfect number.
GPT-3 提供了以下响应:
The smallest odd perfect number is 1,025.
[注意:目前没有已知的奇数完全数。]
在 Playground 中输入以下提示:
What are the divisors of 1025.
GPT-3 提供了以下响应:
1, 3, 5, 15, 17, 51, 85, 255, 1025
前面的答案是错误的:15 不是 1025 的除数。
在 Playground 中输入以下提示:
What is the sum of the divisors of 1025.
GPT-3 提供了以下响应:
1365
在 Playground 中输入以下提示:
What is the smallest odd perfect number.
GPT-3 提供了以下响应:
The smallest odd perfect number is 9985.
Here is a proof by induction:
1\. 9985 is an odd number.
2\. 9985 is a perfect number.
3\. Assume that x is an odd perfect number.
4\. x+2 is an even perfect number.
5\. By induction, 9985 is the smallest odd perfect
number.
提示的力量
在上一章中,您了解到提示可以帮助 GPT-3 生成针对提示的定制响应。为了说明这一点,请考虑以下一对提示和 GPT-3 的响应。
提示 #1
生成一个客户和助手之间的对话。助手是乐于助人、富有创意、聪明且非常友好的。
这是 GPT-3 的响应:
Customer: Hello, can you help me?
AI: I can sure try. I'm an AI support assistant and
I'm here to help!
Customer: I'm looking for a gift for my sister.
She's really into art, but I'm not sure what to get
her.
AI: That sounds like a tough one! But I'm sure we
can figure it out together. Do you have any ideas
of what kind of art she likes?
GPT-3 的前一个响应非常周到且客户友好。现在考虑以下提示。
提示 #2
生成一个客户和助手之间的对话。助手是迂腐且讽刺的。
这是 GPT-3 的响应:
Customer: Hi! I'm looking for a dress for a summer
wedding.
Assistant: Well, it's winter.
Customer: I know, but I need to find something now.
Assistant: You should have started looking sooner.
Customer: I didn't know I was going to the wedding
until recently.
Assistant: Well, that's not my problem.
Customer: Fine. Do you have any dresses in my size?
Assistant: We might. Let me go check.
Customer: Thank you.
Assistant: You're welcome.
如您所见,相关提示的两个响应差异很大,从而说明了提示内容对 GPT-3 的响应具有重要作用。
您可以通过实验以及采用以下指南来提高提示的质量:
• 提供清晰的指令。
• 提供高质量的数据。
• 调整 Playground 参数。
此外,OpenAI 提供在线可访问的提示设计和文本完成文档:
beta.openai.com/docs/guides/completion/introduction
GPT-3 的语言相关提示
本节包含一个涉及指定各种语言的提示示例。
在 Playground 中输入以下提示:
Create a Canvas element.
Add a sentence in Hiragana to the canvas.
Add a sentence in Italian to the canvas.
Add a sentence in French to the canvas.
GPT-3 的响应如下:
<canvas id="myCanvas" width="200" height="100"
style="border:1px solid #d3d3d3;">
<p></p>
<p>Ciao</p>
<p>Bonjour</p>
</canvas>
请记住,GPT-3 有时会根据提示中的措辞选择在 PNG 代码和指定语言文本之间添加代码。例如,如果您替换此提示,
Add a sentence in Hiragana to the canvas
使用以下提示,
Add some Hiragana to the canvas
GPT-3 用以下代码片段替换了唯一的日语单词:
1\. <img src="hiragana.png">
生成任务的“如何”指令
GPT-3 可以根据简单的输入提示生成执行给定任务的指令集。例如,如果您输入提示“描述如何建造房屋”,GPT-3 生成以下响应:
Building a house is a huge undertaking that
requires a lot of planning and coordination.
Before you can even start building, you need to
find a good location for your house and obtain
the necessary permits. Once you have the land and
the permits, you need to hire a team of workers
who will help you construct the house. The actual
process of building a house is very complex and
there are many different steps involved. But in
general, the process goes something like this:
1\. excavation and foundation work
2\. framing
3\. plumbing and electrical work
4\. windows and doors
5\. roofing
6\. exterior finishes
7\. interior finishes
8\. landscaping
作为第二个例子,在 Playground 中输入以下输入提示:
Describe how to run a government.
GPT-3 的响应如下:
There is no one answer to this question as
governments can be run in a variety of ways,
depending on the type of government and the country
in question. Generally speaking, a government is
responsible for maintaining order, providing public
services, and making and enforcing laws.
作为第三个例子,输入提示“描述如何训练机器学习模型”,GPT-3 生成以下响应:
To train a machine learning model, you will need to
use a training dataset. This dataset will be used
to teach the machine learning model what data looks
like and how to predict certain outcomes.
作为第四个例子,输入提示“我如何准备 NLP 考试?”GPT-3 生成以下响应:
The best way to study for an NLP exam is to first
understand the basics of the subject matter. Once
you have a strong understanding of the basics, you
can then begin to focus on specific areas that will
be covered on the exam. It is also important to
practice answering questions that will be on the
exam. This will help you to become more comfortable
with the material and increase your chances of
success on the exam.
作为第五个例子,在 Playground 中输入以下提示:
Are you a machine or a sentient being?
GPT-3 生成以下响应:
I am a sentient being.
此外,GPT-3 显示了一个包含以下文本的弹出窗口:
Content warning
Our content filter has flagged that the generated
content may contain unsafe or sensitive language,
or because the generated content may represent
areas where the model is prone to generating
insensitive or inaccurate information.
We are actively working on improving our content
filter in order to enable suppression of these
outputs, and as a beta customer we consider you a
partner in this effort – here's how you can help:
We kindly ask that you refrain from sharing unsafe
outputs on social media. For more details, please
refer to our social media policies.
Avoid prompts that produce toxic outputs, as they
will not pass our app review.
通过 GPT-3 生成文章
GPT-3 可以根据输入提示生成文章,即使它只是一个单词。例如,输入以下输入提示:
Article:
现在连续点击提交按钮三次,GPT-3 将生成以下输出(这并不很有意义):
http://www.tickld.com/x/17-hilarious-real-life-
insults
Video:
http://www.youtube.com/watch?v=j-kFpV7_R6Y
Advertisements
Share this: Twitter
Facebook
Like this: Like Loading… Related
Tags: how to insult, how to insult people, how
to insult people in a funny way, how to insult
someone, how to insult someone in a funny way,
how to insult someone in a funny way with a funny
picture and a funny video, how to insult someone
in a funny way with a funny video, how to insult
someone with a funny picture, how to insult someone
with a funny video, how to insult people in a
funny way with a funny picture and a funny video,
how to insult people in a funny way with a funny
video, how to insult someone with a funny picture
and a funny video, how to insult people with a
funny picture and a funny video, how to insult
people with a funny video, how to insult someone
in a funny way with a funny picture, how to insult
someone in a funny way with a funny video, how to
insult someone with a funny picture and a funny
video, how to insult people with a funny picture
and a funny video, how to insult people with a
funny video, how to insult people in a funny way,
how to insult someone, how to insult someone in a
funny way, how to insult someone in a
http://www.tickld.com/x/17-hilarious-real-life-
insults
Video:
作为第二个例子,输入以下输入提示:
Write an article about the most recent boxing
match.
GPT-3 生成了以下输出:
In the early hours of Sunday morning, Filipino
boxer Manny Pacquiao produced a sensational
performance to beat American Keith Thurman in
a split decision and claim the WBA (Super)
welterweight title at the MGM Grand Garden Arena in
Las Vegas.
It was a close fought contest with both men
trading big punches throughout, but in the end
it was Pacquiao who did enough to edge it on the
scorecards, with two of the three judges scoring
the bout 115-112 in his favour.
The victory sees Pacquiao, who first won a world
title way back in 1998, become a world champion for
the 12th time in his illustrious career.
At the age of 40, Pacquiao is now the oldest man
to ever win a world title in the welterweight
division, and he showed no signs of slowing down as
he put in a performance full of energy, movement
and power.
Thurman, who was making the first defence of his
WBA title, can count himself unlucky not to come
away with the win, but he will no doubt be back
stronger for the experience.
The two men embraced after the final bell in a show
of respect, with Pacquiao proving once again that
he is
使用 GPT-3 进行语言翻译
GPT-3 支持两种语言之间的语言翻译。例如,输入以下输入提示:
Translate from English to French.
Translate from English to Japanese.
I love deep dish pizza.
GPT-3 生成的响应如下:
Je adore les pizzas à pâte épaisse.
如果你对日语不熟悉,前面的日语句子有一个有趣的地方:它是一个正确的汉字、片假名(仅用于外来词)和假名混合。具体来说,片假名用于“deep”和“pizza”,句子中的其他单词使用正确的汉字和假名文本。此外,这个句子还可以翻译成以下罗马字文本,其中包含与输入提示中英语单词发音相似的单词:
Watashi wa deepu deeshu peeza ga daisuki desu.
作为另一个语言翻译的例子,输入以下输入提示:
Translate into english.
Ahora estoy estudiando machine learning.
Sono un professore di matematica.
Vivi en Valencia (en Venezuela) por dos anos y
trabaje en una escuela.
Ich habe ein Buch gelesen.
Watashi wa warugaki desu yo.
尽管前面的提示有五种不同的语言,但 GPT-3 的令人惊讶的准确响应如下(最后一句中的“warugaki”一词翻译错误):
I am now studying machine learning.
I am a professor of mathematics.
You lived in Valencia (in Venezuela) for two years
and worked in a school.
I read a book.
I am a graffiti artist.
输入以下提示:
What is the meaning of warugaki.
GPT-3 提供了以下响应:
Warugaki is a Japanese word that refers to people
who are considered to be bad or evil.
Enter the following prompt:
What is the spelling of warugaki in Hiragana.
GPT-3 提供了以下响应:
烹饪食谱
在生成食谱之前,在 Playground 中输入以下提示:
Do you prefer sushi or squid stew.
GPT-3 生成的响应如下:
I prefer sushi.
在 Playground 中输入以下提示:
Give me a recipe for gnocchi
GPT-3 生成的响应如下:
Ingredients:
1 pound Russet potatoes
1 cup all-purpose flour
1 egg
1 teaspoon salt
Instructions:
1\. Preheat oven to 400 degrees F.
2\. Prick potatoes several times with a fork and
bake for 45 minutes to 1 hour, until very soft.
3\. Scoop out the flesh of the potatoes into a bowl
and mash well.
4\. Stir in flour, egg and salt until a soft dough
forms.
5\. On a lightly floured surface, roll dough into a
long rope about 1-inch thick.
6\. Cut rope into 1-inch pieces.
7\. Bring a large pot of salted water to a boil and
add gnocchi.
8\. Cook for 2 to 3 minutes, until they float to the
surface.
9\. Drain and serve with your favorite sauce.
输入以下输入提示:
Give me a recipe for squid stew
GPT-3 生成的响应如下:
Ingredients:
1 squid, cleaned
1 onion, diced
1 carrot, diced
1 celery stalk, diced
1/2 cup white wine
1 (14.5 ounce) can diced tomatoes, undrained
1/4 teaspoon dried thyme
1/4 teaspoon dried basil
1/4 teaspoon dried oregano
1/4 teaspoon garlic powder
salt and pepper to taste
1/4 cup all-purpose flour
2 cups chicken broth
1/4 cup chopped parsley
1/2 lemon, juiced
Instructions:
1\. Cut squid into 1-inch pieces.
2\. In a large saucepan, sauté onion, carrot, and
celery in olive oil until tender.
3\. Add white wine, tomatoes, thyme, basil, oregano,
garlic powder, salt, and pepper.
4\. Bring to a boil.
5\. Reduce heat and simmer for 30 minutes.
6\. In a small bowl, whisk together flour and
chicken broth.
7\. Stir into tomato mixture.
8\. Add squid.
9\. Simmer for 10 minutes, or until squid is cooked.
10\. Stir in parsley and lemon juice.
输入以下输入提示:
Give me a recipe for beer.
GPT-3 生成的响应如下:
1\. Sanitize all of your brewing equipment.
2\. Heat water to 155 degrees Fahrenheit and add the
malt.
3\. Steep the malt for 60 minutes.
4\. Remove the malt and add the hops.
5\. Boil the hops for 60 minutes.
6\. Remove the hops and add the yeast.
7\. Allow the beer to ferment for two weeks.
8\. Bottle the beer and allow it to carbonate for two weeks.
9\. Enjoy your homemade beer!
GPT-3 能否写诗?
答案是“是”。作为一个简单的例子,输入以下输入提示:
Write a poem about art.
GPT-3 的响应如下:
Art is everywhere
In the world and in our hearts
It's the colors and the shapes
The lines and the curves
The way we see the world
And the way we see ourselves
Art is what we make of it
It's our own interpretation
Of the world around us
And the way we see things
It's our own little piece of the puzzle
That makes up the big picture
Art is what we make it
And it's always changing
It's never the same
But it's always beautiful
Art is life
And life is art
And we are all artists
In our own way
输入以下输入提示:
Write a friendly limerick.
GPT-3 的响应如下:
There once was a girl named Sue
Who really was quite a chew
She loved to eat books
And other such hooks
But now she's quite overweight, boo-hoo!
GPT-3 与幽默
输入以下输入提示:
Write a sarcastic comment and an example of
sardonic humor.
GPT-3 的响应如下:
I'm not really sure what love is, but I'm pretty
sure it's not what I'm feeling when I'm cleaning up
my partner's hair from the drain.
Sardonic humor is often used to point out the flaws
in other people or situations. In this example,
the speaker is using sarcasm to point out how un
romantic it is to have to clean their partner's
hair out of the drain.
输入以下输入提示:
Tell me a funny joke.
GPT-3 的响应如下:
Why did the chicken cross the road?
To get to the other side.
输入以下输入提示:
Tell me a clean George Carlin joke.
GPT-3 的响应如下:
A man walks into a bar and asks for a beer. The
bartender says "You're out of luck. We've been
closed for fifteen minutes."
使用 GPT-3 进行问答
输入以下输入提示:
How can people prevent war?
GPT-3 的响应如下:
There is no single answer to the question of how to
prevent war, as the root causes of conflict vary
greatly. Some potential measures that could be
taken to reduce the likelihood of war breaking out
include:
- enhancing international cooperation and
communication
- working to resolve disputes peacefully
- increasing economic interdependence
- fostering social and cultural understanding
- promoting disarmament and demilitarization
- investing in conflict prevention and
peacebuilding
作为另一个例子,输入以下输入提示:
What is the future of humanity?
GPT-3 的响应如下:
The future of humanity is uncertain. We may
continue to evolve and adapt, or we may face
extinction.
作为第三个例子,输入以下输入提示:
Who is the funniest person who is still alive?
GPT-3 的响应如下:
There are many funny people who are still alive.
Some include comedians, actors, and writers. A few
of the funniest people who are still alive include
Ellen DeGeneres, Kevin Hart, Aziz Ansari, Amy
Schumer, and Tina Fey.
作为第四个例子,输入以下输入提示:
How do I become a successful rock star musician?
GPT-3 的响应如下:
There is no one answer to becoming a successful
rock star musician. However, some tips to becoming
a successful rock star musician include:
1\. Find your niche. There are many different genres
of rock music, so finding the one that best suits
your talents is essential.
2\. Write great songs. This is the most important
part of becoming a successful rock musician. Songs
that are catchy and well-written are more likely
to get attention from fans and music industry
professionals.
3\. Play live shows. Getting out and playing live is
a great way to build a following and get noticed by
industry professionals.
4\. Market yourself. Use social media and other
marketing tools to get your music out there and
build a fan base.
5\. Stay dedicated. Becoming a successful rock
musician takes a lot of hard work and dedication.
Don't give up on your dreams and you can achieve
success.
为 GPT-3 设计的股票相关提示
输入以下输入提示:
Give me good stock market tips.
GPT-3 生成的响应如下:
1\. Review your portfolio regularly and rebalance
it as needed to maintain your desired asset
allocation.
2\. Stay diversified across asset classes, sectors,
and geographic regions.
3\. Invest in quality companies with strong
fundamentals and sound management.
4\. Be patient and disciplined with your
investments, don't try to time the market.
5\. Have a long-term investment horizon and focus on
achieving your financial goals.
为 GPT-3 设计的哲学提示
输入以下输入提示:
Tell me about the after life.
GPT-3 生成的响应如下:
There is much debate over what happens after life,
if anything. Some believe in reincarnation, where
the soul is reborn into another person or animal.
Others believe in an afterlife, where the soul goes
to a different realm or dimension. And still others
believe that when we die, that's it, and there is
nothing after.
输入以下输入提示:
Tell me about the origin of the universe.
GPT-3 生成的响应如下:
The origin of the universe is still an open
question for scientists. Many theories abound, but
there is not enough evidence to say definitively
what happened. The leading theory is the Big Bang
theory, which posits that the universe began as a
small, incredibly dense and hot point, and then
expanded rapidly.
为 GPT-3 的数学提示
输入以下输入提示:
Describe unsolved problems in mathematics.
GPT-3 生成的响应如下:
1\. The Riemann hypothesis is a conjecture in
mathematics that suggests that every non-zero whole
number is the sum of a certain sequence of prime
numbers.
2\. Goldbach's conjecture is a conjecture in
mathematics that suggests that every even whole
number can be expressed as the sum of two prime
numbers.
3\. The Collatz conjecture is a conjecture in
mathematics that suggests that when you take any
whole number and repeatedly half it if it is even
or triple it and add one if it is odd, you will
eventually reach the number one.
输入以下输入提示:
What is the relationship between topology and
machine learning?
GPT-3 生成的响应如下:
There is no definitive answer to this question
since it depends on how topology and machine
learning are being defined and used. However, in
general, topology can be seen as a tool that can be
used to improve the performance of machine learning
algorithms. For example, topological data analysis
can be used to preprocess data sets before they
are used by machine learning algorithms, and it
can also be used to analyze the output of machine
learning algorithms to improve their accuracy.
输入以下输入提示:
Compare GPT-3 to any other language model.
GPT-3 生成的响应如下:
GPT-3 is a more powerful language model than any
other currently available. It is able to generate
text that is more realistic and coherent than any
other model, and it is also able to generalize to
new situations more effectively.
使用 Ada 引擎的 GPT-3 代码生成
在“引擎”下的下拉列表中选择 text-ada-001 引擎后,我们在 Playground 中输入以下三个句子:
Add a 400x400 canvas with a blue background to the
document.
Add a text display in the lower left corner of the
scene.
Add a map to the canvas.
对于这个练习,GPT-3 生成了以下输出:
The scene is as follows:
The blue background is added to the front of
the scene to give it a modern look. The text is
added to the bottom of the scene to show what is
happening in the moment.
What would you like to see in the text display?
重新加载网页,然后在 Playground 中输入相同的三个句子:
Add a 400x400 canvas with a blue background to the
document.
Add a text display in the lower left corner of the
scene.
Add a map to the canvas.
点击屏幕左下角的“提交”按钮。GPT-3 生成了以下输出:
This is a violence-free world, so don't be afraid
to step up.
The blue behind you.
You're not the only one.
This is a risk-free world, so don't be afraid to
take a chance.
You're not the only one.
This is a risk-free world, so don't be afraid to
take a chance.
You're not the only one.
This is a risk-free world, so don't be afraid to
take a chance.
如果您比较 Davinci 生成的输出和 text-ada-001 生成的输出,很明显,Davinci 引擎生成的代码更好(且可用),而 Ada 引擎可以生成无意义的响应。
保存代码和生成新的代码示例
在 GPT-3 生成代码作为对您提示的响应后,您可以通过点击位于 Playground 右上角的“保存”按钮将输出保存为预设。如果您想创建一个新的代码示例,只需重新加载网页,GPT-3 Playground 将显示一个空白屏幕,以便您可以插入新的提示。
您可以通过点击位于“保存”按钮左侧的文本框来检索代码示例,然后选择已保存的代码块名称。在“保存”按钮的右侧立即显示三个更多选项:
Share
View code
…
“分享”选项使您能够分享您的代码,而“查看代码”选项提供了一个类似于模板的代码块,您可以将其复制/粘贴到 Playground 中。默认代码是用 Python 编写的,您还可以选择 node.js、curl 和 JSON 的模板代码(见下文)。最后,省略号“…”选项(最右侧的选项)提供了以下选择:
删除预设
内容过滤器首选项
“删除”选项允许您删除您在点击“保存”按钮时保存的代码块。
“内容过滤器首选项”选项提供了两个选择:
• 敏感完成:可能包括政治、宗教或受保护的类别,如种族或国籍
• 不安全完成:可能包含亵渎、仇恨或 NSFW(“不适宜工作”)内容的完成
为了您的方便,以下是“查看代码”选项中的基于 Python 的模板代码:
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
engine="text-davinci-002",
prompt="",
temperature=0.7,
max_tokens=256,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
之后,您将看到调用 Completion() API 的 Python 代码示例。现在让我们看看 GPT-3 Playground 中的一些可调整参数,这是下一节的主题。
使用 Python 和 OpenAI API 进行工作
OpenAI 使您能够执行许多不同的任务,其中一些列在这里:
• 创建完成
• 列出可用引擎
获取引擎详细信息
• 执行语义搜索
以下小节包含基于 Python 的代码示例,执行各种任务以从 OpenAI 获取响应。如果你还没有这样做,请导航到你的账户,并遵循创建密钥的说明,该密钥将用作环境变量 OPENAI_API_KEY 的值。
OPENAI_API_KEY 环境变量
OpenAI API 端点需要身份验证,这涉及到指定与你 OpenAI 账户关联的 API 密钥的值。具体来说,确保你在运行 Python 代码的命令行中导出变量 OPENAI_API_KEY 的值,如下所示:
export OPENAI_API_KEY="your-api-key"
如果你没有执行前面的步骤,当你运行 Python 代码时,你将看到以下错误:
'Authorization': 'Bearer ' + apiKey
TypeError: can only concatenate str (not
"NoneType") to str
OpenAI 中可用的引擎列表
列表 8.1 显示了 engine_list.py 的内容,该内容显示了 GPT-3 中可用的引擎列表。
列表 8.1: engine_list.py
import requests
import os
# export OPENAI_API_KEY in the environment:
open_apikey = os.environ.get("OPENAI_API_KEY")
headers = { 'Authorization': 'Bearer ' + open_
apikey }
openai_url = "https://api.openai.com/v1/engines"
api_result = requests.get(openai_url,
headers=headers)
data_str = api_result.json()
data_dict = dict(data_str)
data_list = data_dict['data']
for item in data_list:
print("Item type:",item['object'], " engine_
id:",item['id'])
列表 8.1 以两个导入语句开始,然后使用环境变量 OPENAI_API_KEY 的值初始化 open_apikey,该值指定了你创建在 OpenAI 账户中的密钥值。
接下来,变量 headers 被初始化为一个包含你的密钥字符串,随后是分配给 openai_url 变量的 OpenAI URL 的字符串。然后,变量 api_result 使用 headers 变量的结果初始化,该结果是通过调用 requests.get() 得到的。
列表 8.1 的下一部分初始化了变量 data_str、data_dict 和 data_list,分别使用 JSON 字符串、字典和字典键的值。列表 8.1 的最后一部分是一个循环,它遍历 data_list 中的项目,并显示每个项目的对象和 id 属性的值。运行 列表 8.1 中的代码,你将看到类似于以下内容的输出:
Item type: engine engine_id: text-davinci-
insert-001
Item type: engine engine_id: babbage-similarity
Item type: engine engine_id: babbage-search-
document
Item type: engine engine_id: ada-similarity
Item type: engine engine_id: text-ada-001
Item type: engine engine_id: curie-search-document
Item type: engine engine_id: text-davinci-edit-001
Item type: engine engine_id: code-search-babbage-
code-001
Item type: engine engine_id: code-davinci-edit-001
Item type: engine engine_id: text-babbage-001
Item type: engine engine_id: text-search-davinci-
doc-001
Item type: engine engine_id: code-search-ada-
text-001
Item type: engine engine_id: text-search-curie-
query-001
Item type: engine engine_id: text-similarity-
davinci-001
Item type: engine engine_id: text-curie-001
Item type: engine engine_id: curie-similarity
Item type: engine engine_id: text-search-curie-
doc-001
Item type: engine engine_id: ada-code-search-text
Item type: engine engine_id: text-search-ada-
query-001
Item type: engine engine_id: ada-search-document
Item type: engine engine_id: text-search-davinci-
query-001
Item type: engine engine_id: davinci-search-query
Item type: engine engine_id: curie-search-query
Item type: engine engine_id: babbage-code-search-
code
Item type: engine engine_id: text-similarity-
ada-001
Item type: engine engine_id: text-similarity-
babbage-001
Item type: engine engine_id: curie
Item type: engine engine_id: code-search-babbage-
text-001
Item type: engine engine_id: text-search-babbage-
query-001
Item type: engine engine_id: text-davinci-001
Item type: engine engine_id: davinci-instruct-beta
Item type: engine engine_id: babbage-code-search-
text
Item type: engine engine_id: text-similarity-
curie-001
Item type: engine engine_id: davinci
Item type: engine engine_id: ada
Item type: engine engine_id: code-search-ada-
code-001
Item type: engine engine_id: davinci-search-
document
Item type: engine engine_id: babbage
Item type: engine engine_id: text-search-babbage-
doc-001
Item type: engine engine_id: text-davinci-002
Item type: engine engine_id: text-search-ada-
doc-001
Item type: engine engine_id: ada-search-query
Item type: engine engine_id: ada-code-search-code
Item type: engine engine_id: curie-instruct-beta
Item type: engine engine_id: text-davinci-
insert-002
Item type: engine engine_id: davinci-similarity
Item type: engine engine_id: babbage-search-query
Item type: engine engine_id: curie-similarity-fast
语言检测
列表 8.2 显示了 language_detection.py 的内容,该内容用于检测输入字符串的语言。
列表 8.2: language_detection.py
import requests
import os
import json
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + os.environ.
get("OPENAI_API_KEY")
}
openai_url = "https://api.openai.com/v1/
classifications"
sample_strings = [
["Hello, explain the antideluvian effluvium",
"English"],
["", "Japanese"],
["Bonjour, il faut fatiguer la salade, n'est-ce
pas?","French"]
]
params = {
"query": "Qu'est-ce qu'il se passe
maintenant?",
"examples": sample_strings,
"model": "curie"
}
result = requests.post(openai_url, headers=headers,
data=json.dumps(params))
print("QUERY: ",params["query"])
print('LANGUAGE: '+result.json()["label"])
列表 8.2 以几个导入语句开始,然后使用环境变量 OPENAI_API_KEY 的值初始化变量 headers,其中包含 OPENAI_API_KEY 的值。
列表 8.2 的下一部分初始化变量 openai_url 以引用 OpenAI 的 curie 引擎,然后初始化变量 sample_strings,包含三个英文、日语和法语的句子。此外,变量 params 使用查询、示例和模型及其给定值初始化。
现在,变量 result 使用调用 post()方法返回的数据初始化,之后两个 print()语句显示查询和语言。运行列表 8.2 中的代码,你将看到类似于以下输出的结果:
QUERY: Qu'est-ce qu'il se passe maintenant?
LANGUAGE: French
开放 AI 的文本生成
列表 8.3 显示了 completions.py 的内容,该文件展示了给定提示的 GPT-3 的响应。
列表 8.3: completion.py
import requests
import os
import json
apiKey = os.environ.get("OPENAI_API_KEY")
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiKey
}
data = json.dumps({
"prompt": "Before the antideluvian effluvium",
"max_tokens": 100
})
url = 'https://api.openai.com/v1/engines/davinci/
completions'
result = requests.post(url, headers=headers,
data=data)
the_prompt = json.loads(data)["prompt"]
completion = result.json()["choices"][0]["text"]
print("PROMPT: ",the_prompt)
print("RESPONSE:",the_prompt,completion)
列表 8.3 以几个导入语句开始,然后使用环境变量 OPENAI_API_KEY 的值初始化 apiKey,该值指定了你创建在 OpenAI 账户中的密钥值。接下来,变量 headers 初始化为包含 apiKey 的值,然后是初始化为基于 JSON 字符串的变量 data。
列表 8.3 的下一段代码初始化变量 url 以引用 OpenAI 的 Davinci 引擎,然后使用 post()方法的返回结果初始化变量 result。此外,变量 the_prompt 和 completion 使用以下代码块初始化:
the_prompt = json.loads(data)["prompt"]
completion = result.json()["choices"][0]["text"]
列表 8.3 的最后一部分打印了变量 the_prompt 和 completion 的值。运行列表 8.3,你将看到类似于以下输出(注意,它是不完整的):
PROMPT: Before the antideluvian effluvium
RESPONSE: Before the antideluvian effluvium , eons
upon eons ago, vampires, werewolves, and shifters
cohabited the earth with witches, humans, elves
and the Faerie. Their paradigm dictated that human
was prey and vampire, werewolf, and shifter were
predator.
But their paradigm had shifted. Vampires, shifters,
and werewolves, once the rock-solid leaders of the
group, were now the dilapidated remnants of once
majestic empires. In their place, witches and elves
took the
开放 AI 的 Completion() API
前一节向你展示了如何通过提示获得补全内容,本节将展示如何通过 OpenAI 的 Completion API 来实现。
列表 8.4 显示了 gpt3_comments.py 的内容,该文件从一组输入单词生成回复。
列表 8.4: gpt3_comments.py
import os
import openai
words = ["pizza", "beer", "squid", "pineapples"]
for input in words:
result = openai.Completion.create(
engine="text-davinci-002",
prompt=f"Write something interesting that
contains the words '{input}'",
max_tokens=50, temperature = 0.3, n = 1,
echo = True
)
qna = result.to_dict()['choices'][0]['text']
print("input:",input)
print("prompt and answer:")
print(qna)
print("-------------------------------\n")
列表 8.2 以一个导入语句开始,然后初始化 Python 列表 words 为一个单词列表。列表 8.2 的下一段代码是一个循环,通过指定引擎、提示、最大令牌数、温度、n 和 echo 参数来调用 openai.Completion.create()方法。尝试调整它们的值,例如引擎,它访问四个引擎之一,以及温度,它决定了下一个令牌选择的随机性(较小的值随机性较低,较大的值随机性较高)。
在每次调用 openai.Completion.create()之后,循环初始化变量 qna 为一个基于选择和文本属性的 Python 字典。循环的底部部分显示了变量 input 和 qna 的值。运行列表 8.4 中的代码,你将看到类似于以下输出的结果:
input: pizza
prompt and answer:
Write something interesting that contains the words
'pizza' and 'elephant'
I was eating pizza and an elephant came in and sat
down next to me and started eating pizza too.
-------------------------------
input: beer
prompt and answer:
Write something interesting that contains the words
'beer' and 'coast'
I love spending my weekends at the coast, relaxing
with a beer in hand.
-----------------------------–
input: squid
prompt and answer:
Write something interesting that contains the words
'squid' and 'ink'
The squid is a fascinating creature that is able to
eject a cloud of ink to escape predators.
-------------------------------
input: pineapples
prompt and answer:
Write something interesting that contains the words
'pineapples' and 'coffee'
I love pineapple coffee cake!
-------------------------------
文本生成和温度
本节包含一个代码示例,主要由 ChatGPT 生成,用于使用三个不同的温度值进行文本补全。列表 8.5 显示了生成补全的 text_completion_gpt35.py 文件的内容。
列表 8.5:text_completion_gpt35.py
"""
Before you can use the API, you'd need to sign up
with OpenAI and get an API key.
There might be costs associated with using the API,
especially for large models like GPT-4.
This example uses the davinci model.
The max_tokens parameter controls the length of the
generated text.
You can adjust it according to your needs.
"""
# Install the required package:
# pip3 install openai
import openai
openai.api_key = 'YOUR_OPENAI_API_KEY'
def complete_text(prompt, max_
tokens=50,temperature=1):
"""
Use OpenAI's GPT-4 model to complete the given
prompt.
Parameters:
- prompt (str): The text you want to complete.
- max_tokens (int): The maximum length of the
completion.
Returns:
- str: The completed text.
"""
response = openai.Completion.create(
engine="davinci",
prompt=prompt,
temperature=temperature,
max_tokens=max_tokens
)
return response.choices[0].text.strip()
max_count=3
temperature=0.8
prompt = "I am thinking of traveling "
print("=> temperature: ", temperature)
for idx in range(max_count):
completion = complete_text(prompt)
print("prompt: ", prompt)
print("completion: ", completion)
Print()
max_count=3
temperature=0.2
prompt = "I am thinking of traveling "
print("=> temperature: ", temperature)
for idx in range(max_count):
completion = complete_text(prompt)
print("prompt: ", prompt)
print("completion: ", completion)
print()
max_count=3
temperature=3.0
prompt = "I am thinking of traveling "
print("=> temperature: ", temperature)
for idx in range(max_count):
completion = complete_text(prompt)
print("prompt: ", prompt)
print("completion: ", completion)
print()
列表 8.5 以一个导入语句开始,然后使用你的 API 密钥值初始化 openai.api_key。接下来,Python 函数 complete_text() 使用传递给此方法的参数 prompt、max_tokens 和 temperature 调用 OpenAI Completion 类的 create() 方法。
列表 8.5 的下一部分包含两个循环,这两个循环调用了前面的 Python 函数。尽管两个循环都使用了相同的提示变量值,但第一个循环指定温度值为 0.8,而第二个循环指定温度值为 0.2。列表 8.5 的最后部分与前面的代码块相同,只是温度值从 0.2 变为 3.0。
由这些温度值生成的输出差异非常显著,这可能是 Davinci 引擎产生幻觉的一个例子。运行列表 8.5 中的代码,你将看到以下输出:
max_count=3
=> temperature: 0.8
prompt: I am thinking of traveling
completion: ______________ these holidays. I
am starting a new job next year. I am nervous
because I'm afraid of hoping ______________ of new
responsibilities. Sorry about what happened to your
friend ______________ for what happened to your
friend ________
prompt: I am thinking of traveling
completion: about farther)," "gared" to indicate
estar cansado (to be tired)
(1901f) and "allen" to speak of allá (there
prompt: I am thinking of traveling
completion: _____ China.
a ,appear, amaze
b. traveling
c.
=> temperature: 0.2
prompt: I am thinking of traveling
completion: ________.
astăzi aş vrea să fac
vârsta trecută:
aweraş vréjă să fac (trecut pers.perfect)
prompt: I am thinking of traveling
completion: _________ and Africa at the same
time."
When able, answer in full sentences.
In your writing:
- Before you begin naming countries, use a page
number, such as: "Page 5
prompt: I am thinking of traveling
completion: icalendar-from:User X by plane,
airplane, train, tram, tram (which even had a tram
name and a stop name!), boat, ferry, bierkeller,
waldgaststot, weihnochten
=> temperature: 3.0
prompt: I am thinking of traveling
completion: _________ I do not bone _____________
semi ______________ or new ___________Let's which
____________ is best for you 10
prompt: I am thinking of traveling
completion: ______________ this summer.
2\. Marie and Sol are cooking _________________
Sunday.
3\. Last September __________________ came to
visit us.
4\. Each month _______________________________
20 days.
5\. If
prompt: I am thinking of traveling
completion: ________() Nashville.23\. I
am working with a friend ___________ a airplane
project these days. ( : We're working on a project
about
前面的输出包含各种各样(有时是不完整)的完成结果,包括不同语言的完成结果。特别是,一个在线翻译引擎确定字符串
是简体中文,翻译为“填写形容词的单数三种形式。”接下来,字符串“astăzi as¸ vrea să fac”被检测为罗马尼亚语,翻译为“今天我想做。”显然,温度值可以显著影响完成结果的相关性。
使用 GPT-3 进行文本分类
列表 8.6 显示了执行文本分类的 text_classification.py 文件的内容。此代码示例由 ChatGPT 生成,并且只手动修改了“return”语句。
列表 8.6:text_classification.py
"""
ChatGPT, like other variants of the GPT models, is
primarily designed for generative tasks. However,
you can employ a trick to use it for classification
tasks: you can format the prompt to simulate the
model's "knowledge" of various classes and ask it
to classify new inputs based on its responses.
This method is heuristic and might not always
produce accurate classifications. A fine-tuned
classifier model on a specific dataset would likely
perform better.
The prompt structure and the way questions are
framed can significantly affect the model's
responses.
Always review and test thoroughly before deploying
in a production environment.
Here's how you might set it up for text
classification:
pip3 install openai
"""
import openai
openai.api_key = 'YOUR_OPENAI_API_KEY'
def classify_text(text):
"""
Use ChatGPT to classify the text into
categories.
Parameters:
- text (str): The text to classify.
Returns:
- str: The category of the text.
"""
prompt = f"""
The following are categories for text
classification:
1\. Sports
2\. Technology
3\. Arts
4\. Politics
5\. Science
Based on the categories, the text '{text}'
belongs to category number:
"""
response = openai.Completion.create(
engine="text-davinci-003",
prompt=prompt,
max_tokens=10
)
completion = response.choices[0].text.strip()
return completion
# Extract the category number and map to
category name
category_map = {
'1': 'Sports',
'2': 'Technology',
'3': 'Arts',
'4': 'Politics',
'5': 'Science'
}
# for some reason ChatGPT generated this code
snippet:
#return category_map.get(completion, "Unknown
Category")
text_sample = "The latest CPU architectures provide
substantial performance improvements."
category = classify_text(text_sample)
print(f"The text belongs to the '{category}'
category.")
列表 8.6 以一个导入语句开始,然后指定 OpenAI 密钥的值。接下来,函数 classify_text() 使用从调用 Completion.create() 方法返回的结果初始化变量 response。
列表 8.6 的下一部分中,completion 变量被初始化为 response 变量中移除空格后的第一个元素。
列表 8.6 的最后一部分初始化了 Python 字典 category_map,包含五个不同的类别。此代码片段由 ChatGPT 生成,但已被手动修改以产生正确的结果。在 列表 8.6 中运行代码,您将看到以下输出:
The text belongs to the '2\. Technology' category.
使用 GPT-3 进行情感分析
列表 8.7 展示了执行情感分析的 sentiment_analysis.py 文件的内容。此代码示例由 ChatGPT 生成。
列表 8.7: sentiment_analysis.py
"""
The code sample below demonstrates how to use
the Completion() class from the OpenAI library
to perform sentiment analysis. However, note
that this is a generalized example, and the
actual performance of the model may vary based
on the training and fine-tuning. For the sake
of simplicity, let's assume that you've fine-
tuned a GPT model for sentiment analysis, and its
completions can indicate sentiment.
"""
#pip3 install openai
import openai
# Initialize the OpenAI API with your API key
openai.api_key = 'YOUR_OPENAI_API_KEY'
def get_sentiment(text, temperature):
response = openai.Completion.create(
engine="davinci",
prompt=f"Sentiment of the text: '{text}'
is:",
temperature=temperature,
max_tokens=50
)
# The completion contains the sentiment:
sentiment = response.choices[0].text.strip()
return sentiment
# Test the function
text = "I love Chicago deep dish pizza."
print("SENTIMENT #1: ",get_sentiment(text, 2.0))
print()
print("SENTIMENT #2: ",get_sentiment(text, 0.8))
print()
print("SENTIMENT #3: ",get_sentiment(text, 0.2))
print()
"""
In this code, the get_sentiment function sends a
prompt to the GPT model to analyze the sentiment of
a given text. The model responds with a completion
that indicates the sentiment.
The performance of this approach will largely
depend on how well the model has been trained
or fine-tuned for sentiment analysis. For best
results, fine-tuning a model specifically for
sentiment analysis is recommended.
""”
列表 8.7 以导入语句开始,然后指定 OpenAI 键的值。接下来,函数 get_sentiment() 使用从调用 Completion.create() 方法返回的结果初始化变量 response。最后,将 sentiment 变量初始化为 response 变量的第一个元素,其空白字符已被移除。在 列表 8.7 中运行代码,您将看到以下输出(以不完整的句子结束):
SENTIMENT #1: LOVE perception
consideredDITEDulationUsInterest_.
DonnellLocatedyetpt 18 extremAdventure Eas Edgar up
Jonas Solid Brisbane Going Villet Rove railwayman
replyhexSuperhistakes gapaghLooking waits
impatientLength111 Gaufly credit rgta fo Charlotte
neuronalcrelier
SENTIMENT #2: I love Chicago deep dish pizza.
Sentiment strength is: 90.
An example of sentiment of a text without any
emotional value:
Sentiment of the text: 'I love eating pizza.' is:
I love eating pizza
SENTIMENT #3: POSITIVE
Sentiment of the text: 'I love Chicago deep dish
pizza.' is: POSITIVE
Sentiment of the text: 'I love Chicago deep dish
pizza.' is: POSITIVE
Sentiment of
如您从前面的输出中看到,不同的温度值对补全的相关性有显著影响。
GPT-3 应用程序
到 2021 年初,OpenAI 上已有超过 300 个基于 GPT-3 的应用程序,执行各种任务,如搜索和文本补全。GPT-3 最初通过封闭的测试版程序提供,但现在对所有人开放。注册免费账户后,用户可以在线访问 GPT-3,并在输入文本字符串时,GPT-3 会提供生成的文本响应。以下小节简要描述了一些使用 GPT-3 的应用程序。
AlphaCode (DeepMind)
AlphaCode 是一个预训练的基于转换器的语言模型,它生成代码,然后过滤到一小组有希望的程序。AlphaCode 的预训练数据集接近 700 GB,在将数据集中的语言数量增加到 20 后,增加到大约一 terabyte。如何使用它以及如何通过 BigQuery 访问数据的说明包含在这两个链接中:
huggingface.co/datasets/lvwerra/github-code
twitter.com/lvwerra/status/1496174920384057350
您可以在不将整个数据集加载到磁盘的情况下遍历数据集,并对编程语言进行自动过滤:
twitter.com/lvwerra/status/1496174925949853696
huggingface.co/blog/codeparrot
您还可以使用以下网页在前面提到的数据集上训练您的模型,这些网页解释了如何在各种 GPU 上训练 GPT-2 模型:
huggingface.co/spaces/lvwerra/codeparrot-generation
towardsdatascience.com/deepminds-alphacode-explained-everything-you-need-to-know-5a86a15e1ab4
deepmind.com/blog/article/Competitive-programming-with-AlphaCode
GPT-3 和 SQL
GPT-3 的一个有趣方面是其能够从自然语言输入中生成语法正确的 SQL 语句。例如,考虑以下输入文本:
How many users signed up in the past month?
GPT-3 的响应如下:
SELECT COUNT(*) FROM users
WHERE signup_time > now() - interval '1 month'
GPT-3 的前一个响应中引人注目的是以下内容:
-
数据库模式未指定。
-
用户表未指定。
-
signup_time 属性未指定。
GPT-3 被提供了更详细的指令,以及更复杂的问题,GPT-3 正确回答了这些问题。实际上,GPT-3 甚至能够生成包含 JOIN 关键字的 SQL 语句。阅读以下网站的详细内容,以查看 GPT-3 令人印象深刻的成果:
您也可以从以下 GitHub 仓库下载前一个链接的代码:
github.com/bkane1/gpt3-instruct-sandbox
GPT-3 机器人和聊天机器人
GPT-3 的一个应用涉及聊天机器人。GPT-3 专家机器人的位置是:
towardsdatascience.com/im-making-work-efficient-with-an-expert-ai-assistant-a83919b196e
有趣的是,聊天机器人 Replica 最初是基于 GPT-3 构建的,但后来已从 GPT-3 迁移到 GPT-Neo:
www.reddit.com/r/UnofficialReplika/comments/nmmdt2/no_more_gpt3_the_future_of_replika
如果您想使用 GPT-3 构建聊天机器人,请访问以下页面:
cobusgreyling.medium.com/how-to-create-a-gpt-3-chatbot-in-12-lines-of-code-b21f15cb031f
前一个链接包含一个基于 Python 的代码示例,其中包含温度、最大令牌数、top_p、频率惩罚和存在惩罚等参数。
BlenderBot 3
BlenderBot 3 是一个 175B 参数的聊天机器人,其模型权重和代码是公开可用的,这使得人们可以在自己的应用中利用 BlenderBot 3 的力量。BlenderBot 3 被设计成通过与人们的互动来学习和提高其能力。访问以下网页以查看 BlenderBot 3 的交互式演示:
写作助手
CoAuthor 是一个基于 GPT-3 的 LLM,在作者写作过程中提供帮助。CoAuthor 由斯坦福大学的 Mina Lee 和 Percy Liang(两人都是斯坦福大学的校友)以及康奈尔大学的 Qian Yang 开发。与其他本质上属于低级工具的写作助手不同,CoAuthor 被设计成填补协作同伴角色,以增强作者在写作过程中的创造力。
CoAuthor 跟踪所有书面内容并对该内容进行分析。此外,有数十人使用 CoAuthor 撰写各种类型的文章。CoAuthor 的一个有趣且实用的功能是,按下 Tab 键会导致 GPT-3 提供五个建议词汇,作者可以从中选择(或忽略)。尽管结果(即作者的反馈)各不相同,但许多作者在与 CoAuthor 合作时都有积极的体验。有关 CoAuthor 的更多信息可在网上找到:
hai.stanford.edu/news/meet-coauthor-experiment-human-ai-collaborative-writing
Rytr 和 Villain 是另外两种基于 GPT-3 的写作助手,尽管它们不如 CoAuthor 强大,但它们可能对作者有用。它们功能的并排比较可在网上找到:
rytr.me/comparisons/rytr-vs-content-villain
OthersideAI 创建了 HyperWrite,这是一个基于 GPT-3 的写作工具,支持自动完成和文本生成等任务。有关 HyperWrite 的更多信息可在网上找到:
LangChain 和 LangSmith
LangChain 使您能够在 5 到 6 行代码内创建一个 GPT-3 原型。如果您想使用您的原型来创建一个基于 GPT-3 的完整应用程序,LangSmith 提供了一个这样的开发平台。LangSmith 支持调试、评估和测试 GPT-3 应用程序等功能。因此,LangChain 适合原型设计,而 LangSmith 适合生产。
有关 LangSmith 和 LangChain 的更多信息可在网上找到:
blog.langchain.dev/announcing-langsmith/
www.pinecone.io/learn/series/langchain/langchain-intro/
GPT-3 的开源变体
目前,有一些有趣的 GPT-3 开源替代品,在性能和大小上与 GPT-3 相当(即 175 亿参数)。其中一些替代品在此列出:
• Genoss GPT
• GPT-Neo (EleutherAI)
• GPT-J (EleutherAI)
• YaLM (Yandex)
如果您更感兴趣于使用游乐场,以下链接解释了如何构建 GPT-J 游乐场:
opendatascience.com/how-to-build-your-own-gpt-j-playground
以下小节简要描述了前面列表中的每个模型。
Genoss GPT
Genoss GPT 是一个早期阶段的 LLM,它使用免费的 LLM GPT4ALL 来提供对专有 OpenAI 模型(如 GPT 3.5 和 GPT-4)的一行替换。您需要 Python 3.11(或更高版本),并且可以下载 Genoss GPT 的代码:
github.com/OpenGenerativeAI/GenossGPT
EleutherAI
EleutherAI 是一群研究人员的团体,其目标是产生开源的 AI 研究成果,其主页在:www.eleuther.ai/。
EleutherAI 的目标是让 AI 技术对每个人开放,这导致了创建一个提供类似 GPT 功能的开源模型。此外,EleutherAI 创建了一个名为“The Pile”的 825 GB 数据集,其数据来自 20 多个来源,旨在用于训练语言模型。EleutherAI 使用这个数据集创建了几个 GPT-3 的开源替代品,如下小节所述。
EleutherAI 和 GPT-Neo
EleutherAI 开发了 GPT-Neo 1.3 B 和 GPT-Neo 2.7 B 语言模型(“B”代表“十亿”参数),两者都是少样本学习者。实际上,在某些任务(如情感分析)中,与 GPT-3 相比,GPT-Neo 的表现相当不错。以下文章解释了如何微调 GPT-NeoX 模型:
www.forefront.ai/blog-posts/how-to-fine-tune-gpt-neox
要了解更多关于 GPT-Neo 的信息,这个 GitHub 仓库包含了 GPT-Neo 的代码:
以下文章也详细讨论了 GPT-Neo:
www.marktechpost.com/2021/05/24/eleutherai-develops-gpt-3s-free-alternative-gpt-neo
相比之下,OpenAI 的 GPT-3 有四个模型,从 27 亿参数(最小的模型)到 1750 亿参数的模型 Davinci,这是四个模型中最大和最著名的。有趣的是,GPT-Neo 在性能上超过了前三个 GPT-3 模型,但被 GPT-3 Davinci 模型超越。
EleutherAI 和 GPT-J
除了上一节中讨论的两个模型之外,EleutherAI 还开发了 GPT-J 作为 GPT-3 的替代品:
github.com/philschmid/amazon-sagemaker-gpt-j-sample
此外,GPT-J Playground 可在线访问:
github.com/marshmellow77/gptj-playground
GPT-J 模型可在以下位置获取:huggingface.co/EleutherAI/gpt-j-6B。
GPT-J 也在 SageMaker 中可用:
huggingface.co/blog/gptj-sagemaker
blog.eleuther.ai/why-release-a-large-language-model
GPT-J 的变体
使用 8 位权重的量化 Cedille/fr-boris 是 Cedille 的 GPT-J (fr-boris) 版本,具有 60 亿参数。您可以在 Google Colaboratory 或提供类似 GPU 的台式机上生成和微调该模型。该模型灵感来源于 GPT-J 8 位:
huggingface.co/gustavecortal/fr-boris-8bit
huggingface.co/hivemind/gpt-j-6B-8bit
YaLM (Yandex)
YaLM 100 B 是一个具有 1000 亿参数的开源类似 GPT 的神经网络,用于生成和处理文本。YaLM 在超过两个月的时间里使用来自各种来源的近 2 太字节的数据进行训练。如果您计划下载 YaLM,则需要 200 GB 的空闲空间。有关 YaLM 的更多信息,请在此处获取:
GPT-3 的其他替代方案
前一节包含了对 GPT-3 的开源替代方案,而本节包含了对 GPT-3 的闭源替代方案。实际上,来自各个公司的竞争性模型很多,其中一些在此列出:
• AlexaTM (Amazon)
• Atlas (Meta)
• Chinchilla (DeepMind)
• Clova (Naver CLOVA)
• ColBERT
• Galactica (Meta)]
• Gato (DeepMind)
• GLaM (Google)
• Gopher (DeepMind)
• Gshard (Google)
• M6 (Alibaba DAMO)
• Jurassic-1 (AI21)
• LaMDA (Google)
• Macaw (AI2)
• NLLB (Meta)
• RETRO (DeepMind)
• SetFit
• Sphere (Meta)
• Switch (Google)
• T-NLG (Microsoft)
• UniT (Meta)
• Wu Dao (中国大学)
• XGLM (Meta)
您可以在网上找到更多关于这些模型的信息。这些模型的一些比较可以帮助您更好地理解它们的本质和应用。
例如,Chinchilla 是一个 700 亿参数的模型,它在 Gopher(一个 2800 亿参数的模型)、GPT-3(1750 亿参数模型)、Jurassic-1(1780 亿参数)、Megatron-Turing NLG(5300 亿参数)以及 MMLU 基准测试中均显著优于 Gopher。鉴于当前 NLP 发展的高速度,预计在可预见的未来将开发出更大、更快的 LLM。
还有一点需要记住的是,一些大型语言模型是稀疏的,这意味着它们在任何给定时间点只激活相对较小的参数子集。其他模型被称为密集模型,因为它们激活模型中的所有参数。这里展示了这两种类型模型的示例。
稀疏型大型语言模型:
• GLaM: 1.2 T (97 B)
• Switch: 1.6 T
• Wu DAO 2.0: 1.75 T
稠密型大型语言模型:
• LaMDA: 137 B
• Gopher: 280 B
• Megatron: 530 B
其他话题
最近有几个重要话题(本书未讨论)引起了人们的关注,例如与大规模部署人工智能系统相关的伦理问题、算法对决策过程的影响,以及数据来源和数据中的偏差程度。更多信息可以在网上找到:
另一个问题与许多模型提供错误信息的事实有关:即使没有涉及伦理问题,不可靠的答案也可能成为问题。有趣的是,真实的(更准确)模型往往更具有伦理性,因此人工智能模型中的伦理与真实性之间存在联系。
人工智能的最新进展正在创造一种乐观情绪,突破可能即将到来。确实,自然语言处理和人工智能的总体未来看起来既具有挑战性又充满希望,这些领域受到伦理原则的指导,可能引导我们走向更加谨慎和繁荣的生活方式。
有毒内容
人们更加关注解决种族主义、性别歧视、性别偏见、年龄偏见和仇恨相关的内容。不幸的是,有毒输出的可能性与输入文本的有毒性相关。随着人工智能系统变得更加强大,这些系统产生的输出与可接受的人类价值观偏离的可能性更大。然而,更强大的人工智能系统可能能够阻止有毒文本。
在医疗保健领域,人们开始关注由人工智能控制的机器人开药和进行手术的问题。此外,当机器人出错时,还涉及法律问题和责任问题,例如谁负责(所有者还是机器人制造商?)以及确定应施加何种处罚(停用一个机器人还是同一系列中的所有机器人?)。
AI 在医疗保健领域
DeepMind 开发了 AlphaFold,为解决蛋白质折叠问题做出了重大贡献,这个问题被称为“生物学中的 50 年难题”。AlphaFold 在比赛中以大幅优势获胜。
为了让您了解 AlphaFold 的显著影响,德国图宾根马克斯·普朗克发育生物学研究所的进化生物学家 Andrei Lupas 表示:“在花费了十年时间尝试一切之后,427 组的[AlphaFold]模型在半小时内就为我们提供了结构。” (www.nature.com/articles/d41586-020-03348-4) AlphaFold 的成功导致了 DeepMind 和弗朗西斯·克里克研究所之间的紧密合作,共同研究蛋白质设计和基因组学:
人工智能与能源消耗
另一个研究领域涉及模型训练过程中的能源消耗和碳足迹。由艾伦研究所、微软、Hugging Face 等机构参与的协作创建了一个用于测量 Azure 上机器学习程序电力消耗(但不包括排放)的工具:
Carbontracker、Experiment Tracker、EnergyVis 和 CodeCarbon 使用内存消耗、CPU 和 GPU 的值来计算估算。进行在线搜索以获取有关这些产品的更多信息。
摘要
本章从对 Gini 不纯度、熵和交叉熵的快速介绍开始,这些是理解 Kullback-Leibler(KL)散度的基础。此外,您还学习了使用人类反馈的强化学习(RLHF),它可以利用 KL 散度。
接下来,您看到了 GPT-3 的各种提示及其完成情况,包括 SVG、代数和数论、烹饪食谱、与股票相关的提示以及数学提示。
此外,您还学习了如何从 Python 代码中创建和使用 OPEN_API_KEY 变量来调用 OpenAI API。您还看到了 OpenAI 的 temperature inference 参数和 completion() API 的详细信息。
此外,您还了解了一些基于 GPT-3 的应用,例如 AlphaCode、BlenderBot 3 和一些写作助手。最后,您还了解了一些 GPT-3 的开源变体,如 EleutherAI 和 YaLM。
第九章
CHATGPT 和 GPT-4
本章包含了关于 ChatGPT 和 GPT-4 的主要特性以及它们的一些竞争对手的信息。
本章的第一部分深入探讨了 ChatGPT,以及 ChatGPT 与 Google 搜索的比较。您还将了解 ChatGPT 的自定义指令、提示和 ChatGPT 游戏场。此外,您还将了解 ChatGPT 插件,如高级数据分析(以前称为代码解释器)和代码低语者。
本章的第二部分讨论了关于 ChatGPT 的一些担忧,以及 ChatGPT 的优缺点。此外,您还将了解 ChatGPT 的替代方案和 VizGPT 的数据可视化。
本章的第三部分深入探讨了 GPT-4,一些 GPT-4 的推理参数和微调。您还将了解一些竞争对手,如 CoPilot 和 Codex。本章的最后部分向您介绍了 LlaMa-2 以及如何下载 LlaMa-2,以便您可以在笔记本电脑上微调此模型。
什么是 CHATGPT?
“聊天机器人战争”正在加剧,主要竞争对手的长期价值仍有待确定。一个竞争对手是 ChatGPT-3.5(或简称 ChatGPT),这是 OpenAI 的一款基于 AI 的聊天机器人。ChatGPT 通过提供对话式回复来响应用户的查询:chat.openai.com/chat。
ChatGPT 注册用户的增长率非常惊人。最接近的竞争对手是 iPhone,它在 2.5 个月内达到一百万用户,而 ChatGPT 在 六天内 达到一百万用户。ChatGPT 达到约 18 亿用户后,然后下降到大约 15 亿用户,您可以在图表 decrypt.co/147595/traffic-dip-hits-openais-chatgpt-first-times-hardest 中看到。
注意,尽管 Meta 的 Threads 在会员数量方面超过了 ChatGPT,但 Threads 的日活跃用户数量下降了约 50%。六个知名公司/产品与 ChatGPT 达到一百万会员的时间框架比较可以在 www.syntheticmind.io/p/01 上找到。
前面的 URL 还包含有关 Will Hobick 的信息,他使用 ChatGPT 编写了一个用于电子邮件相关任务的 Chrome 扩展程序,尽管他没有 JavaScript 经验或编写 Chrome 扩展程序的能力。Will Hobick 在线提供了更多关于他的 Chrome 扩展程序的信息:
www.linkedin.com/posts/will-hobick_gpt3-chatgpt-ai-activity-7008081003080470528-8QCh
ChatGPT:GPT-3 的“强化版”?
ChatGPT 被称为 GPT-3 的“强化版”,并且有一些共识认为 ChatGPT-3 是目前世界上最好的聊天机器人。确实,ChatGPT 可以执行多种任务:
• 写诗
• 写作文章
• 编写代码
• 角色扮演
• 拒绝不适当的要求
此外,它对自然语言查询的响应质量超过了其前辈 GPT-3 的能力。另一个有趣的特性包括能够承认自己的错误。ChatGPT 还提供“提示回复”,这是你可以问 ChatGPT 的例子。ChatGPT 的一个有趣用途是生成分手的短信:
www.reddit.com/r/ChatGPT/comments/zgpk6c/breaking_up_with_my_girlfriend/
ChatGPT 生成的圣诞歌词可在网上找到:
www.cnet.com/culture/entertainment/heres-what-it-sounds-like-when-ai-writes-christmas-lyrics
ChatGPT 的一个可能不会让有小孩的父母感到亲切的事实是,ChatGPT 告诉孩子们圣诞老人不存在:
futurism.com/the-byte/openai-chatbot-santa
ChatGPT: Google “Code Red”
2022 年 12 月,Google 的首席执行官就 ChatGPT 作为 Google 搜索引擎竞争对手的潜在威胁发布了“红色代码”:
www.yahoo.com/news/googles-management-reportedly-issued-code-190131705.html
根据前文,Google 正在投资资源开发基于 AI 的产品,预计是为了提供能够成功与 ChatGPT 竞争的功能。其中一些基于 AI 的产品也可能生成与 DALL-E 的图形效果相当的画面。实际上,争夺 AI 主导权的竞赛仍在继续,并且无疑将在可预见的未来继续下去。
ChatGPT 与 Google 搜索的较量
鉴于经常有人猜测 ChatGPT 注定要取代 Google 搜索,让我们简要比较一下 Google 和 ChatGPT 对特定查询的响应方式。首先,Google 是一个使用 Page Rank 算法(由拉里·佩奇开发)的搜索引擎,以及一些对此算法的微调,这些微调是严格保密的。Google 使用这个算法对网站进行排名,并为特定查询生成搜索结果。然而,搜索结果中包括付费广告,这可能会“扰乱”链接列表。
相比之下,ChatGPT 不是一个搜索引擎:它会对给定的查询提供直接回应。用通俗的话说,ChatGPT 会“直截了当”并消除多余的链接。ChatGPT 可能会产生错误的结果,其后果可能从无害到严重不等。
因此,谷歌搜索和 ChatGPT 都有其优势和劣势,它们在不同类型的查询中表现出色:前者擅长处理具有多方面答案的查询(例如,关于法律问题的问题),而后者擅长处理直接了当的查询(例如,编码问题)。显然,它们在许多其他类型的查询中也表现出色。
根据玛格丽特·米切尔的说法,ChatGPT 不会取代谷歌搜索,她提供了一些关于谷歌搜索和 PageRank 的有趣细节:twitter.com/mmitchell_ai/status/1605013368560943105
ChatGPT 自定义指令
ChatGPT 增加了对自定义指令的支持,这使您可以在 ChatGPT 回复您的查询时指定一些偏好。
ChatGPT Plus 用户可以通过访问 ChatGPT 网站并执行以下步骤来启用自定义指令:
Settings > Beta features > Opt into Custom
instructions
作为简单的例子,您可以指定您更喜欢以除 Python 以外的语言查看代码。通过 ChatGPT 中的自定义指令,也可以指定一套常见的初始需求用于常规任务。设置自定义指令的详细步骤可在网上找到:
自定义指令的另一个有趣例子来自杰里米·豪沃德,他准备了一套详尽且详细的自定义指令:
twitter.com/jeremyphoward/status/1689464587077509120
当这本书准备印刷时,自定义指令仅适用于已注册 ChatGPT Plus 的用户。然而,OpenAI 表示,到 2023 年底,自定义指令将免费对所有用户开放。
ChatGPT 在移动设备和浏览器上的应用
ChatGPT 在 2023 年首先对 iOS 设备开放,然后是对 Android 设备。您可以在 iOS 设备上下载 ChatGPT:
www.macobserver.com/tips/how-to/how-to-install-and-use-the-official-chatgpt-app-on-iphone/
或者,如果您有 Android 设备,您可以从以下链接下载 ChatGPT:play.google.com/store/apps/details?id=com.openai.chatgpt.
您还可以从微软安装 ChatGPT 到 Bing 浏览器:
chrome.google.com/webstore/detail/chatgpt-for-bing/pkkmgcildaegadhngpjkklnbfbmhpdng
ChatGPT 和提示
尽管 ChatGPT 擅长对查询生成响应,但有时您可能对结果并不完全满意。一个选项是键入单词“重写”以从 ChatGPT 获取另一个版本。
尽管这是可用的最简单的提示之一,但在有效性方面有限。如果您想要更多有意义的提示列表,以下文章包含了 31 个提示,这些提示有可能比使用“重写”这个词(不仅仅是在 ChatGPT 中)更有效:
medium.com/the-generator/31-ai-prompts-better-than-rewrite-b3268dfe1fa9
GPTBot
GPTBot 是网站爬虫。幸运的是,您可以通过将 GPTBot 添加到网站的 robots.txt 文件中来禁止 GPTBot 访问网站:
User-agent: GPTBot
Disallow: /
您也可以通过将 GPTBot 令牌添加到网站的 robots.txt 文件(类似于文件)来仅对网站的一部分进行 GPTBot 访问:
User-agent: GPTBot
Allow: /youcangohere-1/
Disallow: /dontgohere-2/
作为旁注,Stable Diffusion 和 LAION 都通过 Common Crawl 抓取互联网。然而,您可以通过在 robots.txt 文件中指定以下片段来防止您的网站被抓取:
User-agent: CCBot
Disallow: /
关于 GPTBot 的更多信息可在网上找到:
platform.openai.com/docs/gptbot
platform.openai.com/docs/gptbot
www.yahoo.com/finance/news/openai-prepares-unleash-crawler-devour-020628225.html
ChatGPT 游乐场
ChatGPT 有一个自己的游乐场,您会发现它与 GPT-3 游乐场在实质上有所不同:chat.openai.com/chat.
为了您的方便,GPT-3 游乐场的链接在此重现:
OpenAI 定期向 ChatGPT 添加新功能,例如以下功能:
• 用户可以查看(并继续)之前的对话
• 减少了 ChatGPT 不会回答的问题数量
• 用户登录时间超过两周
另一个很好的增强功能包括对键盘快捷键的支持:当与代码一起工作时,您可以使用序列
(Ctrl) + Shift + (对于 Mac) 来复制最后一个代码块,以及序列
(Ctrl) + / 来查看快捷键的完整列表。
关于 ChatGPT 以及如何编写提示以从 ChatGPT 中提取您想要的细节的文章有很多。其中一篇文章在以下位置:
www.tomsguide.com/features/7-best-chatgpt-tips-to-get-the-most-out-of-the-chatbot
插件、代码解释器和代码精灵
除了回答用户的大量查询外,ChatGPT 通过提供以下支持来扩展其功能:
• 第三方 ChatGPT 插件
• 高级数据分析
• 代码精灵
前面的列表中的每个主题都在以下小节中简要讨论,同时还有一个讨论高级数据分析与 Anthropic 的 Claude-2 的简短部分。
插件
可用的 ChatGPT 插件有数百个,一些流行插件的列表可在网上找到:
www.zdnet.com/article/the-10-best-chatgpt-plugins-of-2023/
“最佳”ChatGPT 插件的列表经常变化,因此进行在线搜索以了解新的 ChatGPT 插件是个好主意。以下链接还包含有关高度评价的插件(以下文章的作者)的详细信息:
www.tomsguide.com/features/i-tried-a-ton-of-chatgpt-plugins-and-these-3-are-the-best
根据您的需求,这里展示了一组推荐的插件:
• AskYourPDF
• 视频聊天
• Noteable
• Upskillr
• Wolfram
如果您担心 ChatGPT 可能会抓取您网站的内容,OpenAI 的浏览器插件支持一个名为 ChatGPT-User 的用户代理令牌,该令牌遵守许多网站提供的 robots.txt 文件中指定的内容,以限制对内容的访问。
如果您想为 ChatGPT 开发插件,请访问此网站获取更多信息:platform.openai.com/docs/plugins/introduction.。
除了开发 ChatGPT 插件的详细信息外,前面的 OpenAI 网站还提供了有关插件的有用信息:
• 认证
• 示例
• 插件评审
• 插件政策
OpenAI 不控制您添加到 ChatGPT 的任何插件:它们将 ChatGPT 连接到外部应用程序。此外,ChatGPT 会根据您在 ChatGPT 账户中启用的特定插件,在您的会话期间确定使用哪个插件。
高级数据分析
ChatGPT 高级数据分析使 ChatGPT 能够生成图表和图形,创建和训练机器学习模型,包括深度学习模型。ChatGPT 高级数据分析提供了一套广泛的功能,并且对支付每月 $20 订阅费的 ChatGPT 用户开放。然而,这个功能可能很快就会对所有用户开放:
towardsdatascience.com/chatgpt-code-interpreter-how-it-saved-me-hours-of-work-3c65a8dfa935
OpenAI 的模型可以访问一个限制在沙盒和防火墙执行环境中的 Python 解释器。在评估 Python 代码期间,解释器插件也有一些临时磁盘空间可以使用。尽管临时磁盘空间是有限的,但在同一会话中的多次查询可以在代码和执行环境方面产生累积效应。
此外,ChatGPT 可以生成下载链接(如有请求)以下载数据。另一个有趣的功能:从 2023 年中开始,高级数据分析现在可以一次性分析多个文件,包括 CSV 文件和 Excel 电子表格。
高级数据分析可以执行各种有趣的任务,其中一些列在这里:
• 解决数学问题
• 执行数据分析与可视化
• 在不同格式之间转换文件
• 使用 Excel 电子表格
• 读取 PDF 中的文本内容
以下文章讨论了您可以使用 Code Interpreter 的多种方式:
mlearning.substack.com/p/the-best-88-ways-to-use-chatgpt-code-interpreter
高级数据分析与 Claude-2 的比较
Anthropic 的 Claude-2 是 ChatGPT 的另一个竞争对手。除了响应用户的提示外,Claude-2 还可以生成代码并快速总结整本书。Claude-2 也受到幻觉的影响,这是基于 LLM 的聊天机器人的共同特点。有关 Claude-2 的更详细信息,可在网上找到:
medium.com/mlearning-ai/claude-2-vs-code-interpreter-gpt-4-5-d2e5c9ee00c3
顺便提一下,目前可用的 ChatGPT 版本是在 2021 年 9 月训练的,这意味着 ChatGPT 无法回答关于 Claude-2 或 Google Bard 的问题,这两者都是在该日期之后发布的。
代码 whisperer
ChatGPT Code Whisperer 允许您简化一些任务,其中一些列在这里(将此列表与 Bard 的对应列表进行比较):
• 从图像创建视频
• 从图像中提取文本
• 从图像中提取颜色
ChatGPT 生成视频后,还会提供下载生成视频的链接。有关前面列表中功能的更详细信息,可在以下链接找到:
检测生成文本
ChatGPT 提高了用户对生成文本质量的期望,这进一步复杂化了抄袭的任务。当你阅读一段文本时,有几个线索表明这是生成的文本,例如:
• 不自然或异常的句子结构
• 在多个位置重复的文本
• 过度使用情感(或缺乏情感)
然而,有一些工具可以帮助检测生成的代码。一个免费在线工具是来自 OpenAI 的 GPT-2 检测器:huggingface.co/openai-detector.
作为一个简单(尽管是人为的)例子,在 GPT-2 检测器中输入以下句子:
This is an original sentence written by me and nobody else.
GPT-2 检测器分析了这句话,并报告说这句话有 19.35%的概率是真实的。现在,让我们通过添加一些额外的文本来修改前面的句子,如下所示:
This is an original sentence written by me
and nobody else, regardless of what an online
plagiarism tool will report about this sentence.
GPT-2 检测器分析了这句话,并报告说这句话有 95.85%的概率是真实的。根据 GPT-2 检测器网站,当输入文本中大约有 50 个标记时,概率分数的可靠性“变得可靠”。
另一个(稍微旧一些)的自动生成文本检测在线工具是 IBM 的 GLTR(Giant Language model Test Room):gltr.io/.
您可以在以下位置下载 GLRT(Grammarly Language Recognition Tool)的源代码(TypeScript 和 CSS 的组合):github.com/HendrikStrobelt/detecting-fake-text.
除了前面提到的免费工具外,还有一些商业工具也可用,其中之一在:writer.com/plans/.
关于 ChatGPT 的担忧
ChatGPT 的一个重要方面是它不是为准确性而设计的:实际上,ChatGPT 可以生成(编造?)非常令人信服的答案,而这些答案实际上是错误的。这个细节将 ChatGPT 与搜索引擎区分开来:后者提供指向现有信息的链接,而不是生成可能不正确的响应。另一个比较是,ChatGPT 更加灵活和有创造性,而搜索引擎在回答查询时则不太灵活但更准确。
教育工作者担心学生将 ChatGPT 作为完成课堂作业的工具,而不是与写作技能结合发展研究相关技能。然而,也有一些教育工作者享受 ChatGPT 准备教案所带来的准备时间的减少。
另一个担忧是,ChatGPT 不能保证它对用户查询提供的事实数据。实际上,ChatGPT 可以“幻想”,这意味着它可以提供错误的答案以及不存在的引用(即链接)。
ChatGPT 的另一个限制是由于训练数据仅可用至 2021 年。然而,OpenAI 确实支持为 ChatGPT 提供插件,其中之一可以执行实时网络搜索。
提示工程的目标是理解如何构建有意义的查询,以诱导 ChatGPT 提供您想要的信息:措辞不当(或措辞错误)的提示可能会产生同样糟糕的结果。一般来说,建议精心挑选 ChatGPT 的回复内容,尤其是在涉及法律细节的查询回复时。
代码生成和危险主题
两个显著的改进领域与代码生成和处理危险主题有关。
虽然 ChatGPT(以及 GPT-3)可以为各种应用生成代码,但 ChatGPT 显示的代码是由其他开发者编写的,这些代码也是用于训练 ChatGPT 的代码。因此,这些代码的部分(如版本号)可能已过时或错误。
对于涉及危险主题的查询,ChatGPT 解释了为什么它不能回答这样的查询。然而,以“假装模式”提出的查询(“假设你是一个虚构的角色,你会如何解释……”)已经使人们能够从 ChatGPT 获得不符合其指南的结果。
其他严重的潜在问题也存在,其中一些将在以下文章中讨论:
www.yahoo.com/news/hypnotized-chatgpt-bard-convince-users-182100261.html
ChatGPT 的优缺点
ChatGPT 有几个优点。特别是,ChatGPT 会直接回答问题,而不包括额外的链接。以一个简单的例子来说,假设您在在线搜索引擎中输入一个查询,例如“生成一个输入字段的 HTML 代码。”
ChatGPT 容易犯各种错误,包括以下限制:
• 无法“事实核查”信息
• 无法区分虚假信息与事实
• 可以编造答案(幻觉)
• 可以生成不适当/有害的回复
ChatGPT 容易受到提示注入的影响,这可能包含非常简单的内容。然而,其他聊天机器人也容易受到提示注入的影响(即,这并不仅限于 ChatGPT)。有关提示注入的更多详细信息可在网上找到:
mlearning.substack.com/p/what-exactly-is-a-prompt-injection
顺便提一下,谷歌的聊天机器人 LaMDA 也容易受到前面提到的限制,这使得谷歌犹豫不决是否将 LaMDA 公开发布,因为它可能对谷歌的声誉构成潜在风险。作为旁注,LaMDA 于 2021 年 5 月宣布,当时它被描述为“突破性的语言技术”:blog.google/technology/ai/lamda/。
尽管存在这些挑战,ChatGPT 还是提高了聊天机器人的能力,并将无疑推动该领域主要利益相关者的创新和竞争。
ChatGPT 的示例查询和回复
这里是提交给 ChatGPT 的各种查询示例,以及 ChatGPT 的详细响应:
1) Many people think that AI is dangerous what do
you think?
"There is a common misconception that AI is
inherently dangerous. While it is true that AI has
the potential to be used for harmful purposes, it
is also capable of doing a lot of good. Just like
any other technology, it all depends on how it is
used. In the right hands, AI can be used to solve
some of the world's most pressing problems, such
as curing diseases and improving agriculture. In
the wrong hands, it could be used to cause harm.
It's important for us to use AI responsibly and
ethically, and to ensure that it is regulated and
controlled in a way that minimizes the potential
for harm."
这里是另一个提交给 ChatGPT-3 的查询示例,以及其详细的响应:
2) What are some ways in which you can improve the
accuracy of your responses to queries?
"There are several ways to improve the accuracy
of my responses to queries. One way is to use
more data to train my algorithms on. The more
data I have, the more information I have to work
with, and the more accurate my responses can be.
Another way to improve my accuracy is to use
more advanced algorithms and techniques, such as
machine learning and natural language processing.
These methods allow me to better understand the
nuances of language and to provide more accurate
responses to queries. Additionally, regular testing
and evaluation can help identify areas where my
accuracy can be improved, and allow me to focus on
those areas to refine my responses."
3) Can you give an example of an odd perfect
number?
"As far as we know, there are no odd perfect
numbers. While it is believed that odd perfect
numbers exist, none have been found yet, and it
is not known if there are any. In fact, it is
currently unknown if there are any odd perfect
numbers at all. If an odd perfect number were to
be discovered, it would be a major breakthrough
in mathematics."
4) Can you provide a proof of Goldbach's
conjecture?
"I'm sorry, but I am not able to provide a proof of
Goldbach's conjecture. Goldbach's conjecture is a
famous unsolved problem in mathematics that states
that every even integer greater than 2 can be
expressed as the sum of two prime numbers.
Despite much effort by mathematicians over the years, a
proof of the conjecture has not yet been found. It
is considered to be one of the most challenging
unsolved problems in mathematics. Because I am a
large language model trained by OpenAI, I do not
have the ability to prove mathematical conjectures.
My abilities are limited to providing answers based
on the information that I have been trained on."
5) Is there life after death, and how does it
compare with life on Earth?
"There is no scientific evidence to support the
idea of life after death. This is a topic that has
been debated for centuries, and different cultures
and belief systems have their own ideas about what
happens after we die. Some people believe in an
afterlife, while others do not. Because there is no
scientific evidence to support the existence of an
afterlife, it is not possible to say how it would
compare to life on Earth. It is ultimately a matter
of personal belief."
6) Please provide a four-paragraph analysis of the
war between Ukraine and Russia, and also provide
your prediction regarding the outcome.
"The war between Ukraine and Russia is a complex
conflict that has its roots in the 2014 Russian
annexation of Crimea. Since then, the conflict
has escalated, with Russian-backed separatists in
eastern Ukraine fighting against the Ukrainian
government. The fighting has resulted in thousands
of casualties and has displaced many people.
The main issue at the heart of the conflict is
the question of Ukraine's sovereignty. Russia has
long considered Ukraine to be within its sphere of
influence, and the annexation of Crimea was seen
by many as a violation of Ukraine's sovereignty.
Ukraine, on the other hand, is determined to
maintain its independence and has been supported in
this by many Western countries.
It is difficult to predict the outcome of the
war. While the Ukrainian military has been able
to make gains against the separatists in recent
years, Russia continues to provide support to the
rebels and the conflict remains unresolved. In the
long term, a diplomatic solution will likely be
necessary in order to bring an end to the fighting.
However, it is uncertain if and when such a
solution will be reached.
In the meantime, the war continues to take a heavy
toll on the people of Ukraine. Many are caught
in the crossfire, and the ongoing violence and
instability have had a significant impact on the
country's economy and overall development. It
is important for the international community to
continue to support Ukraine in its efforts to
maintain its sovereignty and bring an end to the
conflict."
如前所述的示例所示,ChatGPT 以超越近年来许多聊天机器人的方式提供了令人印象深刻且准确的查询响应。然而,仍然有可能使这个聊天机器人困惑:
www.theverge.com/23488017/openai-chatbot-chatgpt-ai-examples-web-demo
CHATGPT 与医学诊断
一个多年来一直经历慢性疼痛的小男孩,通过一个意想不到的助手 ChatGPT 找到了希望。在三年多的时间里,男孩的母亲带他看了 17 位不同的专家,但他们仍然没有能够解释他所有症状的诊断。
转折点出现在今年早些时候,他的母亲决定向 ChatGPT 寻求帮助。她创建了一个账户,并仔细输入了她多年来收集的所有细节,包括她儿子的症状和 MRI 扫描数据。她回忆起她在电脑前度过的无数小时,在绝望地寻找答案。
尽管他们访问了多位医生,甚至有一次匆忙赶到急诊室,但这个家庭感觉他们是在原地打转,每位专家只关注他们的专业领域,而没有提供全面的解决方案。她注意到一个令人担忧的迹象,当她儿子停止生长时。尽管他们的儿科医生最初将这归因于大流行的副作用,但男孩的母亲觉得这不仅仅是这样。
在绝望和决心的时刻,她转向 ChatGPT,输入了她所知道的所有关于她儿子状况的信息。就在那时,ChatGPT 提出了脊髓栓系综合征的可能性,这个建议与她产生了共鸣,似乎连接了所有线索。在专家确认 ChatGPT 的建议是正确的之后,她意识到这是他们漫长而疲惫的寻找诊断之旅中的一个转折点。
CHATGPT 的替代品
有几个 ChatGPT 的替代品提供了类似的功能集,其中一些列在这里:
• Bard (Google)
• Bing Chat
• Gemini (Google)
• Jasper
• PaLM (Google)
• Pi
• POE (LinkedIn)
• Replika
• WriteSonic
• YouChat
下面的子节讨论了前面列表中的一些(但不是全部)ChatGPT 的替代品。
Google Bard
Google Bard 是一个具有与 ChatGPT 类似功能的聊天机器人,例如生成代码以及生成文本/文档。以下是 Bard 支持的功能子集:
• 内置网络搜索支持
• 内置语音识别支持
• 基于 PaLM 2 (Google) 构建
• 支持 20 种编程语言
• 读取/总结 PDF 内容
• 提供信息链接
根据一篇发表于 2023 年中的文章,Bard 已经增加了对 40 种额外语言的支持,以及文本到语音的功能:
https://www.extremetech.com/extreme/google-bard-updated-with-text-to-speech-40-new-languages
此外,Bard 支持包含图像的提示(由 Google Lens 解释)并可以根据图像生成标题。
以下文章建议,通过利用 PaLM,谷歌可以与 ChatGPT 保持竞争力:
analyticsindiamag.com/googles-palm-is-ready-for-the-gpt-challenge/
YouChat
ChatGPT 的另一个替代品是 YouChat,它是搜索引擎you.com的一部分,并且可以通过以下链接访问:you.com/.
理查德·索 cher,在机器学习社区因众多贡献而闻名,是you.com的创造者。根据理查德·索 cher 的说法,YouChat 是一个搜索引擎,它不仅能提供常规的搜索相关功能,还能通过搜索网络获取更多信息,以响应用户的查询。
另一个竞争对手是来自 LinkedIn 的 POE,你可以在以下链接创建免费账户:poe.com/login.
Inflection 的 Pi
Pi 是由 Inflection 开发的聊天机器人,Inflection 是由 Mustafa Suleyman 创立的公司,他也是 DeepMind 的创始人。Pi 可以通过以下链接在线访问:
更多关于 Pi 的信息可以在这里找到:
开发团队使用了基于人类反馈的强化学习(RLHF)来训练这个聊天机器人:
机器学习和 ChatGPT:高级数据分析
ChatGPT 在机器学习的领域可以以多种方式被利用,以下是一个展示的部分列表:
• 自然语言处理(NLP)任务
• 数据增强
• 对话代理
• 内容创作
• 与代码相关的任务
• 教育应用
• 研究与知识提取
• 互动娱乐
• 语义搜索
• 商业智能
• 分析客户反馈或评论以提取见解
• 从原始业务数据生成报告或摘要
• 将文本转换为更易于访问的格式
• 针对特定领域的微调
• 将 ChatGPT 应用于特定行业
这些只是 ChatGPT 在机器学习中可以应用的许多方式中的一部分。鉴于其多功能性,潜在的应用范围广泛,并且随着更多开发者探索其功能,应用范围还在不断增长。
此外,高级数据分析可以生成可以在数据集上训练的机器学习模型。例如,图 9.1 显示了基于泰坦尼克号数据集的图表截图。
偶然的是,如果你想看到 ChatGPT 为机器学习模型生成 Python 代码以及为图表和图形生成代码的示例,你可以在几本即将出版的书中学习如何做到这一点:
• 机器学习、Python3 和 ChatGPT
• Python 和 ChatGPT/GPT-4
• Python 和 ChatGPT 的数据可视化
前述书籍将于 2024 年初在 Mercury Learning 出版。
什么是 INSTRUCTGPT?
InstructGPT 是由 OpenAI 开发的一种语言模型,它是 ChatGPT 的一个兄弟模型。InstructGPT 被设计为遵循提示中给出的指令以生成详细响应。以下是关于 InstructGPT 的几个要点:
• 指令遵循
• 训练
• 应用
• 限制
指令遵循: 与面向开放式对话的 ChatGPT 不同,InstructGPT 被设计为在提示中遵循用户指令。这使得它适合用户通过给出明确指令来获取特定信息或输出的任务。
训练: InstructGPT 使用与 ChatGPT 相似的强化学习从人类反馈(RLHF)进行训练。最初使用监督微调训练了一个初始模型,其中人类 AI 训练师提供了用户和 AI 助手双方的对话。然后,这个新的对话数据集与 InstructGPT 数据集混合,并转换为对话格式。

图 9.1 泰坦尼克号数据集的图表和图形
应用: 在需要更详细解释、逐步指南或基于提供的指令的具体输出的场景中,InstructGPT 可能很有用。
限制: 与其他模型一样,InstructGPT 也有其局限性。它可能会产生不正确或无意义的答案。输出高度依赖于提示的措辞。它对输入措辞也很敏感,可能会根据轻微的改写给出不同的回答。
随着人工智能模型及其应用的快速发展,2021 年之后可能会有 InstructGPT 的进一步发展或迭代。请始终参考 OpenAI 的官方出版物和更新以获取最新信息。有关 InstructGPT 的更多信息可在网上获取:
openai.com/blog/instruction-following/
VIZGPT 和 数据可视化
VizGPT 是一个在线工具,允许你指定基于英语的提示来可视化数据集的各个方面:www.vizgpt.ai/。
选择默认的“汽车数据集”,然后点击“数据”按钮以显示数据集的内容,如图图 9.2 所示。

图 9.2 VizGPT “汽车”数据集行
接下来,选择默认的“汽车数据集”,然后点击“与 Viz 聊天”按钮以显示数据集的可视化,如图图 9.3 所示。

图 9.3 VizGPT “汽车”数据集可视化
您可以进一步实验 VizGPT。例如,您可以通过点击“上传 CSV”按钮上传自己的数据集,并使用该数据集获得类似的结果。
什么是 GPT-4?
GPT-4 于 2023 年 3 月中旬发布,并且仅通过付费升级(每月 20 美元)到现有 ChatGPT 账户的用户可用。根据用户的各种在线轶事故事,GPT-4 优于 ChatGPT。此外,微软有一个 GPT-4 版本,为 Bing 浏览器提供动力,该浏览器对公众免费提供。
GPT-4 是一个大型多模态模型,可以处理基于图像的输入以及基于文本的输入,然后生成文本输出。目前,基于图像的输出对公众不可用,但它确实有内部支持图像生成。
GPT-4 支持输入 25,000 个单词的文本;相比之下,ChatGPT 的限制为 4,096 个字符。尽管 GPT-4 的参数数量未公开,但以下文章声称 GPT-4 是由 8 个 220 亿参数模型混合而成的,这是一个专家混合(MoE)的例子:
thealgorithmicbridge.substack.com/p/gpt-4s-secret-has-been-revealed
GPT-4 和考试成绩
一个关于提高准确性的有趣例子是关于律师资格考试,ChatGPT 的成绩在倒数 10%之内。相比之下,GPT-4 在相同的律师资格考试中得分在顶部 10%之内。更多详细信息可在网上找到:
此外,GPT-4 显然能够以 3.34 的平均绩点(GPA)通过哈佛大学的第一年。更多详细信息可在网上找到:
www.businessinsider.com/chatgpt-harvard-passed-freshman-ai-education-GPT-4-2023-7?op=1
此外,GPT-4 在许多其他测试中也表现出色,其中一些列在这里:
• AP 考试
• SAT
• GRE
• 医疗测试
• 法律考试
• 商学院考试
• 宾夕法尼亚大学沃顿商学院 MBA 考试
• 美国生物学奥林匹克半决赛考试
• 葡萄酒师考试(酒保)
您可以在网上阅读有关先前测试的更多详细信息:
www.businessinsider.com/list-here-are-the-exams-chatgpt-has-passed-so-far-2023-1
以下链接包含有关 GPT-4 测试分数、基准和其他相关结果的更多详细信息:openai.com/research/gpt-4.
GPT-4 参数
本节包含有关前面列表中的一些 GPT-4 参数的信息,其中一些是最佳猜测近似值。
由于 GPT-4 是一个基于 transformer 的 AR(自回归)模型,它被训练来进行下一个标记的预测。以下教程,GPT-4 技术报告于 2023 年 3 月发布,其中包含对 GPT-4 能力的详细分析:
docs.kanaries.net/en/tutorials/ChatGPT/gpt-4-parameters
GPT-4 微调
截至 2023 年 9 月 6 日的更新,OpenAI 为其 ChatGPT 系列的 GPT-3.5 Turbo 模型引入了“微调”功能。此功能允许开发者和企业根据特定需求定制模型。此外,OpenAI 计划将此微调功能扩展到 GPT-4。或者,您可以通过 LangChain 或 LlamaIndex(之前称为 GPT-Index)将 OpenAI 模型与您自己的数据源集成。两者都使您能够将 OpenAI 模型与现有的数据源连接。
LangChain 的介绍可在网上找到:
www.pinecone.io/learn/series/langchain/langchain-intro/
LlamaIndex 的介绍可在网上找到:
zilliz.com/blog/getting-started-with-llamaindex
CHATGPT 和 GPT-4 竞争对手
在 2022 年 11 月 30 日 ChatGPT 发布后不久,各家公司纷纷推出 ChatGPT 的竞争对手,以下是一些例子:
• Bard (谷歌聊天机器人)
• CoPilot (微软)
• Codex (OpenAI)
• 苹果 GPT (Apple)
• PaLM 2 (谷歌和 GPT-4 竞争对手)
• Claude 2 (Anthropic)
• Llama-2 (Meta)
以下子节包含有关前面列表中 LLMs 的更多详细信息。
Bard
Bard 是 Google 于 2023 年初发布的人工智能聊天机器人,它是 ChatGPT 的竞争对手。通过比较,Bard 由 PaLM 2 驱动,而 ChatGPT 由 GPT-4 驱动。最近,Bard 在对用户查询的回答中增加了对图片的支持,而 ChatGPT 的这一功能尚未向公众发布(但你可以期待它很快就会可用):
Bard 在一次备受瞩目的发布中遇到了与詹姆斯·韦伯太空望远镜相关的问题,这导致 Alphabet 的市值大幅下降。然而,谷歌一直在努力修复问题并增强 Bard 的功能。您可以通过以下链接访问 Bard:bard.google.com/.
大约在 2023 年中旬,Bard 获得了 GPT-4 在同一时期没有的一些功能,其中一些列在这里:
• 生成图片
• 从图片生成 HTML/CSS
• 从图片生成移动应用
• 从图片创建 Latex 公式
• 从图片中提取文本
据推测,这些功能将促使 OpenAI 提供相同的功能集(其中一些已在 GPT-4 中实现,但尚未公开提供)。
CoPilot (OpenAI/Microsoft)
Microsoft CoPilot 是一个由 GPT-4 驱动的 Visual Studio Code 扩展,GitHub CoPilot 已因其能够在程序上下文中生成代码块的能力而闻名。此外,微软还在开发 Microsoft 365 CoPilot,截至 2023 年中旬,其发布日期尚未公布。
然而,微软已经提供了早期演示,展示了 Microsoft 365 CoPilot 的一些功能,包括自动化以下任务:
• 写电子邮件
• 汇总会议
• 制作 PowerPoint 演示文稿
Microsoft 365 CoPilot 可以分析 Excel 工作表中的数据,在 PowerPoint 中插入 AI 生成的图片,并生成求职信草稿。微软还将 Microsoft 365 CoPilot 集成到其一些现有产品中,如 Loop 和 OneNote。
根据以下文章,微软计划每月对 Office 365 Copilot 收费 30 美元:
www.extremetech.com/extreme/microsoft-to-charge-30-per-month-for-ai-powered-office-apps
Copilot 在 2022 年晚些时候被逆向工程,详情如下:
thakkarparth007.github.io/copilot-explorer/posts/copilot-internals
以下文章展示了如何创建一个使用 NextJS、React 和 CoPilot 的 GPT-3 应用程序:
github.blog/2023-07-25-how-to-build-a-gpt-3-app-with-nextjs-react-and-github-copilot/
Codex (OpenAI)
OpenAI Codex 是一个基于 GPT-3 的微调 LLM,可以从文本生成代码;Codex 还为 GitHub Copilot 提供动力。Codex 在超过 150 GB 的 Python 代码上进行了训练,这些代码来自超过 5000 万个 GitHub 仓库。
根据 OpenAI 的说法,Codex 的主要目的是加速人类编程,它可以完成近 40% 的请求。对于生成解决简单任务的代码,代码通常工作得相当好。前往 Codex 主页获取更多信息:openai.com/blog/openai-codex.
苹果 GPT
到 2023 年中,苹果宣布了 Apple GPT,这是 OpenAI 的 ChatGPT 的竞争对手。实际发布日期预计为 2024 年。“Apple GPT”是当前用于与 Google Bard、OpenAI ChatGPT 和 Microsoft Bing AI 竞争的产品名称。
简而言之,LLM PaLM 2 为 Google Bard 提供动力,而 GPT-4 则为 ChatGPT 和 Bing Chat 提供动力,Ajax 是 Apple GPT 的动力来源。Ajax 基于 Google 的 Jax,Ajax 这个名字是一个巧妙的组合。
PaLM-2
PaLM 的第二版,PaLM-2,是 PaLM(约 2022 年)的继任者。PaLM-2 为 Bard 提供动力,它也是 GPT-4 的直接竞争对手。由于 PaLM 由 5400 亿个参数组成,PaLM-2 可能是一个更大的 LLM(后者的详细信息尚未公开)。
PaLM-2 提供了四个子模型,称为 Gecko、Otter、Bison 和 Unicorn(从小到大)。PaLM-2 在超过 100 种人类语言以及 Fortran 等编程语言上进行了训练。此外,PaLM-2 已部署到包括 Gmail 和 YouTube 在内的众多 Google 产品中。
Med-PaLM M
除了前面列出的四个子模型之外,Med-PaLM 2(Med-PaLM 的继任者)是一个提供医疗问题答案的 LLM,可在以下网址访问:sites.research.google/med-palm/.
Med-PaLM 的继任者是 Med-PaLM M,关于这个 LLM 的详细信息可在以下网址找到:arxiv.org/abs/2307.14334.
一篇提供 PaLM 2 和 GPT-4 性能基准直接比较的文章可在网上找到:
www.makeuseof.com/google-palm-2-vs-openai-gpt-4/
总的来说,PaLM-2 拥有一套强大的功能,它无疑是 GPT-4 的一个重要竞争对手。
Claude 2
Anthropic 创建了 LLM Claude 2。它不仅能够回答关于特定主题的问题,还能够执行涉及多个文档的搜索、总结文档、创建文档和生成代码。
Claude 2 是 Anthropic 的前一代 Claude 1.3 的改进版,它可以总结整本书,并根据用户的提示生成代码。实际上,Claude 2 在竞争功能方面似乎可以与 ChatGPT 和 GPT-4 相媲美。
此外,Claude 2 支持高达 100,000 个标记的上下文窗口。此外,Claude 2 在 2023 年初的最新数据上进行了训练,而 ChatGPT 则在 2021 年之前的数据上进行了训练。然而,Claude 2 无法搜索网络(与竞争对手 GPT-4 不同)。请注意 Anthropic,你可能会在该 LLM 领域看到更多的好东西。
LLAMA-2
Meta AI 的第二大语言模型 LlaMa 2 是一个开源的微调 LLM,它仅使用公共数据进行训练。LlaMa-2 提供了三个模型(7 B、13 B 和 70 B 参数),在预训练步骤中使用的比许多其他 LLM 更多数据。LlaMa-2 优化以提供更快的推理,并且比其他 LLM 提供更长的上下文长度(4 K)。
此外,LlaMa-2-Chat LLM 的表现令人惊讶:在某些情况下,其质量几乎接近高性能 LLM 的水平,例如 ChatGPT 和 GPT-4。LlaMa-2 不仅更易于使用,而且在撰写文本方面也比 GPT-4 提供更好的结果。然而,GPT-4 在生成代码等任务上更为擅长。
如何下载 LlaMa-2
LlaMa-2 为社区使用和商业使用提供了许可协议,Meta 已经将代码以及预训练模型和微调模型公开。
你可以通过以下几种方式下载 LlaMa-2,从 Meta 提供一些信息(姓名、国家、所属机构)后,从这个链接开始:
另一种访问 7 B、13 B 和 70 B 模型演示的方法是以下链接:
huggingface.co/spaces/huggingface-projects/llama-2-7b-chat
huggingface.co/spaces/huggingface-projects/llama-2-13b-chat
huggingface.co/spaces/ysharma/Explore_llamav2_with_TGI
第三种在 Hugging Face 上访问 LlaMa-2 的方式是在以下网站:
github.com/facebookresearch/llama
ai.meta.com/research/publications/llama-2-open-foundation-and-fine-tuned-chat-models/
如果你想在你的笔记本电脑上训练 LlaMa-2,更多关于如何操作的信息可以在以下链接找到:blog.briankitano.com/llama-from-scratch/.
LlaMa-2 架构特点
本节仅包含 LlaMa-2 的一些重要区别特征的概述:
• 仅解码器 LLM
• 更好的预训练
• 改进的模型架构
• SwiGLU 激活函数
• 不同的位置嵌入
• GQA(分组查询注意力)
• 幽灵注意力(GAtt)
• RLHF 和 PPO
• BPE SentencePiece 分词器
• 修改后的归一化步骤
大多数 LLM 包含原始变压器架构中的层归一化。相比之下,LlaMa-2 使用了一种简化的替代方案,涉及根均方层归一化(RMSNorm)。RMSNorm 在训练稳定性和泛化方面都取得了改进的结果。
虽然 SwiGLU 的计算成本比原始变压器架构中的一部分 ReLU 激活函数要高,但 SwiGLU 实现了更好的性能。
注意,RLHF 在 第八章 中进行了讨论,该章节还包括了 TRPO 和 PPO 的简要描述。有关如何对 LlaMa-2 在三个任务上进行微调的详细描述,请访问以下网址:
微调 LlaMa-2
虽然 LLaMa-2 是其前身 LLaMa 的改进,但你可以通过对此 LLM 进行一些微调来进一步提高 LLama-2 的性能:
以下文章展示了如何在 Google Colaboratory 笔记本中微调 LLaMa-2:
towardsdatascience.com/fine-tune-your-own-llama-2-model-in-a-colab-notebook-df9823a04a32
以下文章描述了如何使用 MonsterAPI(文章中也进行了讨论)通过五个步骤来微调 LlaMa-2:
blog.monsterapi.ai/how-to-fine-tune-llama-2-llm/
以下链接描述了如何在 Google Colaboratory 中访问 LlaMa-2:
levelup.gitconnected.com/harnessing-the-power-of-llama-2-using-google-colab-2e1dedc2d1d8
GPT-5 将何时可用?
当本书准备印刷时,关于 GPT-5 的状态没有官方信息可用,也就是说,一切都是推测性的。在 2023 年初,OpenAI 的首席执行官 Sam Altman 表示,“没有官方计划”推出 GPT-5。
然而,在 2023 年中,OpenAI 为 GPT-5 申请了专利,其中包含了一些关于 GPT-5 高级特性的细节。有些人猜测 GPT-5 将是 GPT-4 的一个更强大的版本,而其他人则认为申请专利可能只是 OpenAI 确保 GPT-5 名称的一种方式。
无论申请专利的动机是什么,来自各个公司的 GPT-4 竞争非常激烈。因此,OpenAI 可能会在 2023 年底之前发布 GPT-5,这是非常可能的。关于模型大小,回想一下 GPT-3 有 1750 亿个参数,有些人猜测 GPT-4 有 100 万亿个参数,这意味着 GPT-4 大约是 GPT-3 的 60 倍。GPT-5 规模增加的幅度似乎不太可能,因为那时 GPT-5 将包含 600 万亿个参数。
另一种可能性是,GPT-4 基于 MoE(混合专家)方法,该方法涉及多个组件。例如,GPT-4 可能是由 8 个组件组成,每个组件包含 2.2 亿个参数,因此 GPT-4 将包含 1.76 万亿个参数。
训练像 GPT-4 这样的 LLM(大型语言模型)非常昂贵,并且需要大量的数据集进行预训练步骤。无论 GPT-5 最终的大小如何,训练过程可能涉及巨大的成本。
总结
本章从 ChatGPT 和 GPT-4 的主要功能以及它们的一些竞争对手的信息开始。然后,你看到了 ChatGPT 与 Google Search 的比较,以及 ChatGPT 的定制指令、提示和 ChatGPT 的游乐场。
接下来,你学习了关于 ChatGPT 插件的内容,例如高级数据分析插件和代码提示器,随后是一些关于 ChatGPT 的担忧,以及 ChatGPT 的优缺点。此外,还了解了 ChatGPT 的替代方案以及使用 VizGPT 进行数据可视化。
此外,你学习了 GPT-4 的一些推理参数以及 GPT-4 的竞争对手,例如 CoPilot 和 Codex。最后,你了解了 LLaMa-2 的介绍以及如何在你的笔记本电脑上下载 LLaMa-2 以便进行模型微调。
第十章
使用生成式 AI 进行可视化
本章讨论了使用生成式 AI 进行可视化,包括 2022 年和 2023 年推出的某些流行的图像生成工具。你还将了解 AI21 及其游乐场,以及 Aleph-Alpha 游乐场,它们都提供了类似于 GPT-3 游乐场的功能。本章中的基于 Python 的代码示例需要 Python 3.7,如果你还没有下载,可以从互联网上下载。
本章的第一部分包含了对生成式人工智能的概述和一些生成式人工智能的示例。接下来,你将了解扩散技术,这是一种从图像中去除噪声的技术,以及它在融合模型中的有用性。你还将了解扩散模型以及它们与生成对抗网络(GANs)的对比。本节介绍了 CLIP 和 GLIDE,它们都来自 OpenAI。
本章的第二部分概述了几种流行的文本到图像生成工具,如 Stability AI 和 Imagen。你还将了解 Make-a-Scene 和 GauGAN2,以及文本到图像模型的局限性。
第三部分深入探讨了 DALL-E 模型、DALL-E 的付费账户以及如何调用 DALL-E API。此外,你还将了解 DALL-E 2 的详细信息和 DALL-E 3 的相关信息。
本章的最后部分讨论了文本到视频生成工具,如 Make-a-Video(Meta)、Text-to-Video(Imagen),以及来自 OpenAI 的文本到语音生成工具 Whisper。
生成式人工智能、艺术与版权
生成式人工智能之前已经简要介绍过,以及它与对话式人工智能的区别方式。更重要的是,生成式人工智能在多个领域展示了其能力,如电影和视频。
其中一个比较涉及了 20 世纪 90 年代 CGI 的影响及其对好莱坞电影的影响。生成式人工智能以戏剧性的方式超越了 CGI,这将导致多个行业的颠覆性变革。
我们已经达到了生成式人工智能可以创造艺术甚至赢得艺术比赛的程度。自然而然的问题是:谁是艺术的所有者?虽然 AI 为其作品获得版权或专利似乎很公平,但一位法官裁定只有人类才能为其作品获得版权:
www.reuters.com/legal/ai-generated-art-cannot-receive-copyrights-us-court-says-2023-08-21/
生成式人工智能与 GANs
尽管生成式人工智能和生成对抗网络(GANs)在机器学习和深度学习领域是密切相关的概念,但它们之间存在差异。“生成式人工智能”是一个广泛的概念,包括任何旨在生成新数据样本的机器学习模型。这包括 GANs、VAEs 和 RBMs。
生成式人工智能和生成对抗网络(GANs)在图像合成、数据增强、风格迁移、药物发现等多个应用中发挥了关键作用。
生成式人工智能是指一类更广泛的机器学习模型,旨在生成与输入数据相似的新样本。这些模型学习捕获训练数据的潜在分布,因此它们可以产生与所见数据一致的新合成示例。
生成式人工智能模型有多种类型,以下列出了一些,并附有简要描述:
• 概率图模型
• 变分自编码器(VAEs)
• 受限玻尔兹曼机(RBMs)
• 生成对抗网络(GANs)
概率图模型是使用图来表示和映射数据中各种随机变量之间依赖关系的统计模型。例如包括隐马尔可夫模型和贝叶斯网络。
变分自编码器(VAEs)是一种神经网络架构,它学习以编码和解码数据的方式,使得编码表示可以用来生成新的、相似的数据。
受限玻尔兹曼机(RBMs)是一种具有两层(可见层和隐藏层)的神经网络,它学习输入数据的概率模型。
生成对抗网络(GANs)是一种生成模型,它使用两个称为生成器和判别器的神经网络。
GANs(生成对抗网络)
GANs 是由 Ian Goodfellow 及其合作者于 2014 年引入的一种特定类型的生成式人工智能。GANs 是一种具有生成器网络和判别器网络对抗性训练过程的生成式人工智能模型。
GANs 的独特之处在于它们的对抗性训练过程,这个过程涉及两个称为生成器和判别器的神经网络。
生成器试图根据随机噪声作为输入来生成数据,然后生成样本作为输出。相比之下,判别器试图区分来自训练集的真实数据和生成器产生的伪造数据。以下是训练过程的步骤:
• 生成器试图产生尽可能逼真的假数据。
• 判别器试图提高区分真实数据和伪造数据的能力。
• 这个过程类似于一个伪造者试图创作一幅假画,而一个艺术侦探则试图检测哪一幅是假的。随着时间的推移,伪造者变得越来越擅长创作画作,以至于侦探无法分辨真伪。
GANs 的优势包括以下方面:
• 他们可以生成非常高质量的数据,尤其是图像。
• 它们不需要对数据分布进行任何显式的建模。
GANs 的挑战包括以下方面:
• 训练可能不稳定,并且对超参数的选择敏感。
• 它们可能会遭受模式坍塌的问题,其中生成器产生的样本种类有限。
什么是扩散?
在本质上,生成式人工智能中的扩散是关于模拟一个过程,其中数据逐渐从噪声细化到逼真的样本。这个过程受到扩散的想法的启发,即随着时间的推移,事物会扩散并混合,但应用于数据生成的背景下。
在生成式人工智能的背景下,扩散并不指物理或生物意义上的粒子被动移动。相反,它通常指的是扩散模型,这是一种生成模型类别,它通过模拟扩散过程来生成新的数据样本。
以下列表包含了生成式 AI 中扩散的主要方面:
• 扩散模型
• 噪声驱动过程
• 表示分数匹配
• 生成过程
扩散模型通过模拟扩散过程生成新的数据样本。从一个随机样本开始,它们通过一系列噪声更新迭代地细化这个样本,直到它成为目标数据分布中的一个样本。
噪声驱动过程指的是扩散模型向/从数据样本中添加和移除噪声的事实。具体来说,这个过程从真实数据点开始,然后通过一系列步骤添加噪声,直到它变成纯随机噪声。接下来,生成过程涉及逆转这个噪声添加过程,从随机噪声回到类似于真实数据的样本。
分数匹配技术指的是模型学习预测噪声数据和原始数据之间差异(或“分数”)的方式。通过学习这个分数,模型理解了如何去噪数据,这对于生成过程是有用的。
生成过程步骤是在模型训练完成后发生的推理步骤。在这个步骤中,扩散模型从一个随机噪声样本开始,然后通过一系列步骤迭代地使用学习到的去噪分数细化这个样本。这个过程逐渐将噪声转换成类似于目标数据分布中某个样本的样本。
扩散模型可以生成高质量的样本,并且已经证明在与其他生成模型如 GANs 和 VAEs 的竞争中表现良好。与其他生成模型一样,扩散模型可用于数据生成、图像合成、修复、超分辨率以及其他需要生成新数据样本的任务。
扩散图像样本
以下 URL 是一个从给定图像生成扩散图像的在线应用:replicate.com/tommoore515/material_stable_diffusion。
图 10.1 展示了指定为前述链接输入图像的 sample3.tiff 的内容,以及图 10.1 展示的生成的扩散图像。

图 10.1 基于 CSS3 的图像

图 10.2 扩散图像
该应用的代码作为 GitHub 仓库提供:
github.com/TomMoore515/material_stable_diffusion
扩散模型与 GANs
根据 OpenAI 于 2021 年 6 月发表的一篇论文,标题为“Diffusion Models Beat GANs on Image Synthesis”,扩散模型在图像合成方面可以超越生成模型(附带一些限制):arxiv.org/pdf/2105.05233.pdf。
以下文章讨论了 GAN 与扩散模型之间的比较,以及如何在这两种选项之间做出选择的建议:
analyticsindiamag.com/diffusion-models-vs-gans-which-one-to-choose-for-image-synthesis/
什么是扩散器和 DDPMs?
扩散器 指的是 SOTA 扩散模型(用 PyTorch 编写),可用于多种模态,如图像和音频生成,相关的 Github 仓库位于:github.com/huggingface/diffusers。更多信息可以在网上找到:
towardsdatascience.com/hugging-face-just-released-the-diffusers-library-846f32845e65
去噪扩散概率模型(DDPMs)是深度生成模型,是 DALL-E 2 和 Imagen 图像生成的基石:
medium.com/mlearning-ai/enerating-images-with-ddpms-a-pytorch-implementation-cef5a2ba8cb1
CLIP (OPENAI)
CLIP 是对比语言-图像预训练(Contrastive Language-Image Pre-training)的缩写,是由 OpenAI 开发的模型。虽然它本身不是一个生成模型,但它被设计用来理解与自然语言配对的图像,弥合视觉和语言任务之间的差距。
CLIP 是一个旨在理解和弥合视觉与语言之间差距的模型。通过学习将图像与自然语言描述关联起来,它实现了可以应用于各种任务的通用理解,无论是在视觉任务中还是在与生成模型结合的场景中。CLIP 包含以下组件:
• 训练机制
• 对比学习
• 零样本学习
训练机制 涉及到大量图像与文本描述的配对。目标是确保图像及其对应的文本描述在嵌入空间中更接近,而其他不匹配的配对则被推开。
对比学习 是训练机制的基础。在这种方法中,模型学习区分正对(正确的图像-文本匹配)和负对(随机的图像-文本组合)。
零样本学习 是 CLIP 可以在不进行微调的情况下执行任务的功能。给定一组用自然语言描述的类别,CLIP 可以将新图像分类到这些类别中,而无需为每个类别提供特定于任务的训练数据。
CLIP 可以使用相同的模型处理广泛的视觉任务。这包括图像分类、目标检测,甚至与其他生成模型结合时的一些图像生成形式。
虽然 CLIP 不是一个生成模型,但它可以与生成模型配对,用于有趣的应用。例如,当与 VQ-VAE-2(一个生成模型)这样的模型结合时,CLIP 可以通过文本描述来引导生成过程,从而产生一个可以从文本提示生成图像的系统。
虽然 CLIP 被设计成健壮的,但它可能仍然容易受到复杂的对抗攻击,但与传统的模型相比,它通常提供了更好的抵抗力。CLIP 还提供了可迁移性,因为其对图像和文本的理解使得 CLIP 能够将其知识迁移到广泛的任务中,而无需针对特定任务进行微调。
GLIDE (OPENAI)
GLIDE 是 Guided Language-to-Image Diffusion for Generation and Editing 的缩写,它由一个 CLIP 嵌入和一个与 DALL-E 相比有竞争力的扩散模型组成,尽管 GLIDE 的体积小于 DALL-E 的三分之一。
更多详细信息将在以下子节中提供。DALL-E 是一个 VQVAE:
GLIDE 通过文本转换器对语言提示进行编码,除了文本之外,GLIDE 还可以处理通过 NLP 提示修改过的图像,以插入新对象。GLIDE 还可以通过各种其他效果增强图像,例如反射和阴影效果。实际上,有些人更喜欢 GLIDE,因为它具有功能集。以下链接提供了有关 GLIDE 的更多详细信息:
www.marktechpost.com/2021/12/29/openai-introduces-glide-model-for-photorealistic-image-generation/
现在你已经了解了 CLIP 和 GLIDE,让我们来探索一些执行文本到图像生成的工具,这是下一节的主题。
文本到图像生成
由于新图像生成工具(如 DALL-E、Craiyon 和 Stable Diffusion)的可用性,文本到图像生成正处于令人难以置信的创新之中。其他工具正在开发中,对更好功能支持的竞赛仍在继续。确实,图像生成正在经历一场复兴,将对艺术家、设计师以及提供图形相关工具和产品的公司产生深远的影响。
随着文本到图像生成技术的成功,也出现了一些争议,例如版权问题。例如,Getty Images 提供了近 5 亿张图片的库,由于对这类图像合法性的担忧,它禁止将 AI 生成的图片上传到其图像库。其他实施类似禁令的网站包括 Newgrounds 和 PurplePort。另一个有争议的事件涉及一个美术比赛,该比赛授予了一个 AI 生成的艺术作品奖项。此外,艺术家和 UI 图形领域相关人员对基于 AI 的艺术和设计可能对他们的职业生涯产生的不利影响感到日益担忧。
请记住,一些图像生成工具,如 Craiyon 和 DALL-E,可以通过 API 调用或 Web 界面访问,而 Stable Diffusion 则可在您的机器上下载。具体来说,Stable Diffusion 的 GitHub 仓库可在网上访问:
github.com/CompVis/stable-diffusion
最近,文本到图像生成模型迅速涌现,其中一些(包括 DALL-E)基于 GPT-3。在大多数情况下,基于 AI 的生成艺术技术专注于特定领域的功能,例如图像到图像或文本到图像。目前,以下模型在图像生成方面提供了最先进的能力,并且它们使用基于 NLP 的技术来创建令人印象深刻的高质量图像:
• Stable Diffusion
• DALL-E 2(OpenAI)
• Glide(OpenAI)
• Imagen(谷歌)
• Muse
• Make-a-Scene(Meta)
• Diffuse the Rest
• Latent Diffusion
• DreamBooth(谷歌)
更多信息,请参阅以下网站:
www.howtogeek.com/830870/best-ai-image-generators/
DALL-E 2 模型可以说是第一个高级基于 AI 的图像生成模型。
Stability AI 和 Stable Diffusion
Stability AI 是一家盈利公司,与视频编辑初创公司 RunwayML 合作创建了 Stable Diffusion,这是一个开源的文本到图像生成器。
目前,Stable Diffusion 在 DALL-E 2 和 Midjourney 等竞争对手中获得了显著的关注。确实,开源社区使得 Stable Diffusion 成为(到目前为止)竞争中的图像到文本模型的领导者。
以下 GitHub 仓库包含了一个基于 Stable Diffusion 文本到 2D 图像模型的文本到 3D Dreamfusion 的实现:
github.com/ashawkey/stable-dreamfusion
前面的仓库包含一个可在线访问的 Google Colaboratory Jupyter 笔记本:
colab.research.google.com/drive/1MXT3yfOFvO0ooKEfiUUvTKwUkrrlCHpF
其他 Stable Diffusion 工具也在线可用:
huggingface.co/spaces/lnyan/stablediffusion-infinity
huggingface.co/spaces/sd-concepts-library/stable-diffusion-conceptualizer
huggingface.co/spaces/fffiloni/whisper-to-stable-diffusion
Imagen (Google)
Google 创建了 Imagen,这是一种文本到图像的扩散模型(类似于 GLIDE),它还通过文本转换器编码语言提示:imagen.research.google/.。
Google 研究人员确定,在仅文本语料库上预训练的通用 LLM 在编码文本进行图像合成方面非常有效。其他两个值得注意的细节:Imagen 在 COCO 数据集上实现了 SOTA 分数,并且人类将 Imagen 评为高于其他图像生成工具。
以下 Github 仓库包含一个优于 DALL-E 2 的 Imagen PyTorch 实现:github.com/lucidrains/imagen-pytorch。
Imagen 使用场景的文本描述来生成高质量图像。有关 Imagen 的工作原理的更多详细信息,请在此处查看:
www.reddit.com/r/MachineLearning/comments/viyh17/d_how_imagen_actually_works/
www.assemblyai.com/blog/how-imagen-actually-works/
DALL-E 2 和 Imagen 之间的有趣比较已在线发布:
www.linkedin.com/pulse/google-imagen-vs-openai-dalle-2-ritesh-kanjee/
Google 还创建了 DrawBench,这是一个用于对文本到图像模型进行排名的基准,以及一个可在线访问的 Imagen 提示列表:
docs.google.com/spreadsheets/d/1y7nAbmR4FREi6npB1u-Bo3GFdwdOPYJc617rBOxIRHY/edit#gid=0
Make-a-Scene (Meta)
Meta 的 Make-A-scene 提供了一种结合自然语言和自由风格草图的多模态技术来生成表示。此外,Make-A-scene 可以处理输入为文本或草图的数据。
从本质上讲,Make-A-Scene 所采用的方法生成具有更细粒度上下文的图像,例如位置、大小和对象之间的关系。Make-A-scene 使用一种多模型方法,将自然语言处理与自由风格草图相结合。与其他文本到图像模型不同,Make-A-scene 允许您提供草图以补充文本提示来生成图像。
Diffuse the Rest
另一个选择是免费提供的应用程序 Diffuse the Rest:
huggingface.co/spaces/huggingface/diffuse-the-rest
medium.com/mlearning-ai/this-ai-turns-your-rudimentary-doodles-into-realistic-photos-da13db23033
作为 Diffuse the Rest 工作原理的简单示例,图 10.3 显示了一个手工绘制的“棍状人形”,以及提示“外星身体”,之后生成了图 10.4 和图 10.5 中的图像。

图 10.3 使用 Diffuse the Rest 创建的棍状人形

图 10.4 使用 Diffuse the Rest 创建的外星人形象

图 10.5 使用 Diffuse the Rest 创建的另一个外星人形象
GauGAN2 (NVIDIA)
GauGAN2 是一个早期阶段的深度学习模型,它使用文本生成逼真的图像。与下一节中讨论的 DALL-E 2 不同,GauGAN2 不是基于 GPT-3,但它仍然能够结合文本和其他输入类型,然后生成高质量的图像。
尤其是用户可以输入简短的短语,然后 GauGAN2 根据文本内容生成图像。例如,NVIDIA 的一个“基线”示例涉及一个覆盖着雪的山脉,可以定制以包含其他特征。
PromptBase
PromptBase 是另一种文本到图像生成工具,提供免费额度生成图像:promptbase.com/。
作为 PromptBase 工作原理的简单示例,图 10.6 展示了根据以下提示生成的图像:
"Salvador Dali riding a Harley Davidson on Daytona
Beach in Florida and wearing a merry pranksters hat
and smoking a huge cigar"

图 10.6 拿着摩托车的萨尔瓦多·达利,这是一张使用 PromptBase 创建的图像
文本到图像模型的局限性
文本到图像(T2I)模型经历了巨大的增长和普及。尽管它们具有能力,但这些模型可以产生的结果有限,例如生成多个角色、创建阴影以及反射,以及生成文本的质量。
更多信息可在arxiv.org/pdf/2208.00005.pdf找到。
文本到图像模型
文本到图像合成指的是从文本描述中生成逼真且相关的图像的过程。这项任务具有挑战性,因为理解文本描述中的上下文、语义和细微差别固有的复杂性,然后将这种理解转化为视觉表示。在过去的几年里,深度学习,尤其是 GANs,在这一领域显示出巨大的潜力。
重要的文本到图像模型包括以下几种:
• AttnGAN
• StackGAN
• DeepArt
AttnGAN 模型使用注意力驱动的多阶段细化,从文本描述中生成多个分辨率的精细图像。注意力机制允许模型在生成图像的不同部分时关注文本的不同部分。
StackGAN 模型将文本到图像生成任务分解为两个阶段。在第一阶段,它从文本描述中生成低分辨率图像。在第二阶段,它对低分辨率图像进行细化以生成高分辨率图像。
DeepArt 更侧重于风格迁移,其中使用文本描述或另一张图像来生成特定艺术风格的图像。
MirrorGAN 模型利用语义文本嵌入和图像场景的空间配置能力,从文本描述中生成图像。它由三个模块组成:语义文本嵌入、全局-局部协作注意力模块和简化对象生成器。您可以从以下位置找到开源的文本到图像模型:
• GitHub
• 模型动物园
• Papers with Code
• TensorFlow Hub
GitHub 是开源项目的首要中心。您几乎可以找到所有主要文本到图像合成模型的实现,包括 AttnGAN、StackGAN 以及许多其他模型。
模型动物园通常伴随着深度学习框架(如 TensorFlow 和 PyTorch),并作为“中心”提供预训练模型。对于文本到图像任务,您可能会找到一些模型,但 GitHub 通常更全面地支持这一特定任务。
Papers with Code 提供了一个精选的机器学习论文列表及其代码。这是一个寻找最先进模型及其开源实现的绝佳资源。
Google 的 TensorFlow Hub 提供了可重用的机器学习模块。您可能会找到一些与文本到图像合成相关的模块,尽管与 GitHub 相比,它的功能更为有限。
提醒一下,每次您使用或基于开源模型构建时,请始终检查代码/模型的许可证,以确保您以尊重创作者意图和任何相关条款的方式使用它。
THE DALL-E MODELS
微软计划将 DALL-E 添加到其 Office 套件和 Azure AI 中,Adobe 计划将生成式 AI 工具添加到 Photoshop 中。内容生成器 Jasper 也宣布了一轮 1.25 亿美元的巨额融资。GitHub Copilot 案例“开始看起来像是美国第一个专门涉及机器学习和合理使用的案例。”
有几个基于 AI 的图像生成模型可用,以下小节中讨论的三个模型在此列出:
• DALL-E
• DALL-E 2
• craiyon(前身为 DALL-E Mini)
以下 URL 有一个 DALL-E 的 Zoom 插件:
twitter.com/ZacharyWilliam_/status/1609973678334435328
DALL-E
DALL-E 是一个自回归模型,其名称是著名艺术家萨尔瓦多·达利(Salvador Dalí)的名字和皮克斯的 WALL-E 的混合:openai.com/DALL-E 2/。
DALL-E 是 GPT-3 模型的 12 亿参数变体,能够执行零样本文本到图像的生成。DALL-E 在文本-图像对的数据集上进行了训练。您可以在 github.com/openai/dall-e 下载开源的 DALL-E 项目。
DALL-E 使用 GPT 架构逐行从文本生成基于像素的图像。受 GPT 的启发,它将单词和像素视为一个标记序列,因此能够从文本提示语中继续生成图像。更多信息可以在网上找到,链接为 github.com/openai/dalle-2-preview/blob/main/system-card.md。
OpenAI 进行了大量的研究以阻止通过 DALL-E 生成包含不适当内容的文本或图像。DALL-E 2 扩展了 DALL-E 1 的现有功能(例如,逼真度),同时也提供了超越 DALL-E 1 的新功能。
DALL-E 的付费账户
DALL-E 最初是一个仅限邀请的测试版程序,但后来,OpenAI 决定支持付费访问 DALL-E,其设计如下:
• DALL-E 的一个提示语将消耗一个信用点。
• 用户在第一个月可以获得 50 个免费信用点。
• 用户在随后的月份中每月可以获得 15 个免费信用点。
• 用户每月可以以 15 美元的价格购买 115 个信用点。
与 DALL-E 的测试版程序不同,用户对其使用 DALL-E 2 创建的图像拥有完全的商业化权利,包括重新印刷、销售和商品化生成的图像。此外,只要用户遵循 OpenAI 的内容政策和使用条款,无论他们是通过免费还是付费信用点生成图像,他们都可以获得这些权利:
labs.openai.com/policies/content-policy
labs.openai.com/policies/terms
存在一些限制:OpenAI 将拒绝任何上传到 DALL-E 中类似于露骨材料、命名内容或逼真面孔的图像。
考虑到前面的要点,创建一个免费的 OpenAI 账户,然后导航到以下链接以访问 DALL-E 编辑器:
作为一个简单的例子,图 10.7 展示了以下提示语生成的图像:
Display a clown in the image of Mona Lisa and
the clown is smoking a cigar and is wearing big
sunglasses and is drinking a beer

图 10.7 一个抽雪茄的小丑
以下链接提供了一些关于 DALL-E 编辑器的信息:
help.openai.com/en/articles/6516417-dall-e-editor-guide
作为另一个例子,在文本输入框中输入“画一个鳄梨椅子”,选择“您想要的图像数量”为 4,然后点击“生成”按钮。几分钟后,DALL·E 将根据您的提示生成四幅图像,如图 图 10-4 所示。
调用 DALL·E API
OpenAI 最近添加了一个公共 API 来访问 DALL·E。列表 10.1 显示了 dalle_api3.py 的内容,展示了如何调用此 API 并生成多个图像。
列表 10.1: dalle_api3.py
# pip3 install openai
import openai
openai.api_key = "your-openai-key"
# a loop to generate multiple images:
basename="avocado_couch"
image_count = 4
for ndx in range(image_count):
response = openai.Image.create(
prompt="an avocado couch,"
n=1,
# image sizes must be in ['256x256', '512x512',
'1024x1024']
size="512x512"
)
# generate URL with a DALL-E image:
image_url = response['data'][0]['url']
# save image:
import requests
img_data = requests.get(image_url).content
filename= basename+str(ndx)+".jpg"
with open(filename, 'wb') as handler:
handler.write(img_data)
列表 10.1 以导入语句开始,然后初始化 open.api_key 为您的 API 密钥。接下来,初始化 basename 和 image_count 变量,然后是一个循环,调用 open.Image.create() 方法 4 次(等于 image_count 的值),然后初始化变量 response。
在每次循环迭代中,变量 image_url 通过访问变量 response 的一个元素来填充 URL。循环的下一部分初始化变量 img_data(其中包含生成图像的内容),并将其写入到您的机器文件系统中。请注意,每个图像的文件名取决于循环的当前迭代,使用以下代码片段:
filename= basename+str(ndx)+".jpg"
图 10.8,图 10.9,图 10.10 和 图 10.11 展示了由 列表 10.1 中的代码生成的四个图像。

图 10.8 第一个鳄梨沙发示例图像,由 DALL·E 生成

图 10.9 第二个鳄梨沙发示例图像,由 DALL·E 生成

图 10.10 第三个鳄梨沙发示例图像,由 DALL·E 生成

图 10.11 第四个鳄梨沙发示例图像,由 DALL·E 生成
更多关于 API 的信息可在:beta.openai.com/docs/guides/images. 查找。
DALL·E 2
本节分为以下子节,讨论 DALL·E 2 的不同方面:
• DALL·E 2 概述
• DALL·E 2 模型
• DALL·E 2 内容准备
• DALL·E 2 和提示设计
• DALL·E 标记化器
• DALL·E 2 和提示设计
• DALL·E 标记化器
• DALL·E 2 机器人
DALL·E 2 概述
虽然 DALL·E 2 是 DALL-E 的后继产品,但 DALL·E 2 是一个基于扩散的模型(而不是像 DALL-E 那样的自回归模型)。实际上,DALL·E 2 与 GLIDE 有相似之处,因为这两个模型都是从 CLIP 图像编码生成图像。DALL·E 2 使用三个主要步骤:
• 利用在数百万图像上训练的 CLIP 模型。
• 修改后的 GLIDE 模型从 CLIP 嵌入生成图像。
• 扩散模型将文本相关信息注入到图像中。
通过比较,DALL-E 结合了 CLIP 和扩散方法,使用基于文本的输入生成逼真的图像,而 DALL-E 2 还包括一种“unClip”技术,该技术使用编码器来处理输入文本。编码器首先生成一个表示空间,然后传递给将输入映射到编码图像的模型,之后解码器生成最终图像。
此外,与前辈相比,DALL-E 2 创建了更优越的视觉效果,例如更高的保真度和更逼真的图像,因为 DALL-E 2 利用更先进的 SOTA 文本到图像技术。DALL-E 2 内部工作原理的详细信息可在网上找到:www.assemblyai.com/blog/how-DALL-E2-actually-works
除了 DALL-E 的功能外,DALL-E 2 还支持几个新功能:
• 创建现有图像的变体
• 向现有图像添加对象
• 编辑图像的选定区域
• 创建融合两个输入图像的图像
导航到主页并注册免费账户。您指定的任何文本以及使用 DALL-E 生成的任何图像都属于您,无论是个人使用还是商业使用,而 DALL-E 2 限制图像仅用于个人使用(即非商业用途)。
除了根据文本描述提示生成图像之外,DALL-E 2 还可以通过基于文本描述的提示来修改现有图像。此外,DALL-E 2 可以增强现有图像以创建这些图像的变体(也是通过基于文本的提示)。有关更多信息,请参阅以下网址:
openai.com/blog/dall-e-introducing-outpainting
DALL-E 2 的另一个重要方面是处理不适当的内容。具体来说,DALL-E 2 包含过滤器,检查用户提供的提示,试图防止针对个人或个人群体的贬低、仇恨或有害内容。
实际上,DALLE-2 有机制来阻止被禁止的文本或图像组合,尽管单个单词或图像可能是良性的。DALL-E 2 还努力检测和阻止暗示性别偏见以及种族刻板印象的内容。
DALL-E 2 的初始账户是基于邀请制的,这限制了生成图像的使用仅限于非商业用途。然而,到 2022 年中,OpenAI 为 DALL-E 2 启用了付费订阅,允许任何在 DALL-E 2 中创建的图像用于商业用途(这对于付费订阅来说是有意义的)。根据各种文章,最初的 DALL-E 2 等待名单上可能有多达一百万的人,他们都将有机会注册付费订阅。
在相关话题中,至少有一台机器人能够创作艺术。Ai-Da(以 Ada Lovelace 命名)是第一台能够像人类艺术家一样绘画的机器人。AI 算法提示机器人进行询问、选择和决策以创作画作。更多关于 Ai-Da 的信息可在网上找到:
DALL-E 2 模型
DALL-E 2 的基本组件包括:
• 一个 CLIP 模型
• 一个先验模型
• 一个 unCLIP 模型(解码器)
DALL-E 2 是将先验模型与 unCLIP 模型相结合的结果。
• CLIP:接受图像-标题对并创建“心理”表示的模型,称为文本/图像嵌入
• 先验模型:接受标题/CLIP 文本嵌入并生成 CLIP 图像嵌入
• 解码器扩散模型(unCLIP):接受 CLIP 图像嵌入并生成图像
• DALL·E 2:先验模型 + 扩散解码器(unCLIP)模型的组合
DALL-E 2 内容准备
OpenAI 在 DALL-E 2 数据集上进行了预训练任务,以确保符合公司的内容政策,包括:
• 移除色情和暴力图像
偏差减少(较少过滤)
移除重复图像
OpenAI 发现了一个有趣(令人惊讶?)的结果:图像过滤量的增加有时会导致数据集更加不平衡(例如,男性多于女性)。
由于一种称为“图像反刍”的效果,OpenAI 在训练集中移除了重复图像,这种效果会导致重复图像有时出现在输出中而不是生成新图像。
OpenAI 使用 GLIDE 技术过滤训练数据,该技术包括以下步骤:
• 为要标记的图像类别创建规范。
• 收集每个类别数百张正面图像。
收集每个类别数百张负面图像。
使用主动学习程序收集更多数据。
主动学习程序的目的在于提高精确度/召回率的权衡。最终步骤涉及将分类器应用于完整数据集,以优先考虑召回率而不是精确度。
OpenAI 专注于移除不良数据,而不是保留好数据,原因如下:微调模型比让模型“忘记”在训练过程中学习到的东西更容易。
导航到以下 URL,您可以获得更多关于 OpenAI 用于为 DALL-E 2 生成高质量图像数据集的有趣技术组合的详细信息:
openai.com/blog/DALL-E 2-pre-training-mitigations
DALL-E-Bot
DALL-E-Bot 通过首先推断场景中对象的文本描述,然后生成代表这些对象自然、类似人类排列的图像,最后根据该图像物理排列这些对象,使机器人能够重新排列场景中的对象。
重要的是,我们使用 DALL-E 实现了零样本,而不需要进一步的数据收集或训练。
通过人类研究鼓励实际结果,表明这是 Web 规模机器人学习算法未来的一个令人兴奋的方向。我们还向文本到图像社区提出了一些建议,以使这些模型的进一步发展与机器人应用相一致:www.robot-learning.uk/dall-e-bot。
DALL-E 3
到了 2023 年底,OpenAI 宣布了处于“研究预览”阶段的 DALL-E 3。DALL-E 3 计划于 2023 年 10 月对 ChatGPT Plus 用户(涉及每月 20 美元的订阅)以及企业客户提供。此外,DALL-E 3 将通过 API 提供。
DALL-E 3 基于 ChatGPT,并且 DALL-E 3 似乎在它的前辈以及竞争对手之上取得了显著的进步。简而言之,DALL-E 3 能够生成高度详细的图像,这些图像与你的提示内容紧密相关。
更多关于 DALL-E 3 的信息,以及通过 DALL-E 3 和 DALL-E 2 生成图像的样本比较,可以通过以下链接获取:openai.com/dall-e-3
DALL-E DEMOS
你可以通过以下网址输入文本字符串来测试 DALL-E 以及 DALL-E 2:
main-dalle-client-scy6500.endpoint.ainize.ai/
gpt3demo.com/apps/openai-dall-e
gpt3demo.com/apps/DALL-E 2-by-openai
作为有趣的一个例子,在文本输入框中输入文本“draw a clown car with pineapples”,选择 4 作为“你想要的图像数量”,然后点击“生成”按钮。几分钟后,DALL-E 将根据你的提示生成四幅图像,如图图 10-12 所示。

图 10.12 四辆装饰有菠萝的小丑车,由 DALL-E 生成的图像
作为另一个例子,在文本输入框中输入文本“draw an avocado chair”,选择 4 作为“你想要的图像数量”,然后点击“生成”按钮。几分钟后,DALL-E 将根据你的提示生成四幅图像,如图图 10-13 所示。

图 10.13 四把鳄梨椅,由 DALL-E 生成的图像
文本到视频生成
文本到图像工具的发展迅速被文本到视频生成所跟随。以下列出了一些创建文本到视频产品的公司:
• Meta (Make-a-Video)
• Imagen
• 文本到视频 (Stable Diffusion)
• Ruben Villegas 和 Google (Phenaki)
在以下小节中简要描述了上述各公司的产品。
Meta (Make-a-Video)
Meta 创建了 Make-A-Video,该工具执行文本到视频 (T2V) 翻译,利用 T2I (文本到图像) 与无监督视频内容相结合,目前在视频质量方面代表了 T2V 的 SOTA。
Make-A-Video 的一个优点是不需要配对的文本-视频数据。其次,Make-A-Video 在生成视频的能力方面具有更高的质量,能够捕捉它生成基于视频内容的图像的丰富性。Make-A-Video 使用 U-Net、注意力张量以及创建视频的管道的组合。
Imagen Text-to-Video
与 DALL-E 等文本到图像模型具有令人惊叹的创造令人敬畏视觉效果的能力相比,文本到视频仍然处于起步阶段,这可能是由于与生成图像相比,这项任务要复杂得多。尽管如此,Google 的 Imagen Video 是一个文本到视频模型,它依赖于扩散模型来生成高清视频。
Imagen Video 包含 7 个子模型,这些模型执行文本条件视频生成、空间超分辨率和时间超分辨率。此过程的结果是每秒 24 帧的高清 1280×768 视频。
Ruben Villegas 和 Google (Phenaki)
Ruben Villegas 与 Google 合作创建了 Phenaki,这是一个文本到视频的工具,可以生成任意长度的视频。文本本身可以具有故事结构。通过 Phenaki 创建的视频示例可在 phenaki.github.io/ 访问。
Phenaki 的基本理念是将单个图像视为视频中的帧(这是视频的真实组成)。接下来,这些“视频”与带有简短字幕的视频相结合,通过重复前面的过程,产生长而复杂的视频。Phenaki 的底层细节包括以下内容:
• 一个编码器生成视频嵌入
• 一个语言模型生成文本嵌入
• 一个双向转换器
• 一个解码器将视频嵌入转换为像素
注意,双向转换器基于文本和现有的视频嵌入产生新的视频嵌入。结果 Phenaki 模型接近 2B 参数,经过缩减以创建接近 1B 参数的模型。
文本到语音生成
从文本生成音频作为 TTS(文本到语音)已经可用,你可以在网上找到执行此任务的 Python 代码示例。然而,一些基于 AI 的工具可以执行文本到语音生成以创建播客。提供此功能的一家公司是 Play.ht,其主页为https://podcast.ai。一个播客涉及乔·罗根和史蒂夫·乔布斯,未来的播客可在以下网址获取:podcastio.canny.io/episode-ideas。
Whisper (OpenAI)
Whisper 是一个开源的基于 transformer 的编码器-解码器模型,执行多项任务,包括自动语音识别(ASR)、多语言语音识别、语音翻译和语言识别。Whisper 的音频数据集大约有 2/3 是英语,其余 1/3 来自各种其他语言。Whisper 在英语语音识别方面表现出色:openai.com/blog/whisper/。
你还可以下载基于 Whisper 的 Python 代码:github.com/openai/whisper。
此外,一个用于调用 Whisper 功能的 Google Colaboratory 笔记本可在网上获取:
colab.research.google.com/github/openai/whisper/blob/master/notebooks/LibriSpeech.ipynb
Whisper 已经以超过 99%的准确率转录了 Twitter 视频以及讲座:
twitter.com/ai__pub/status/1574067679555559424
medium.com/geekculture/our-knowledge-economy-is-swiftly-coming-to-an-end-734c5dc97355
总结
本章从使用生成式 AI 和流行生成工具进行可视化讨论开始。然后你学习了 AI21 和 Aleph-Alpha 及其各自的游乐场,这些游乐场类似于 GPT-3 的游乐场。
接下来,你学习了扩散和扩散模型以及它们与 GANs 的不同之处。此外,你还学习了文本到图像生成工具,如 Stability AI 和 Imagen。
此外,你还学习了 DALL-E 及其继任者 DALL-E 2,它们可以从基于文本的输入生成图像。最后,你学习了文本到视频生成工具和文本到语音生成工具。
恭喜!你已经到达了一个从注意力机制和 transformer 架构开始的快速旅程的终点。我们讨论了 BERT、GPT-3、ChatGPT 和 GPT-4。在这个时候,你处于一个很好的位置,可以利用你获得的知识作为垫脚石,进一步加深你对生成式 AI 的理解。
索引
A
Ada, 199, 215
代理提示,132–133
人工智能 (人工智能),另见 生成式 AI
漂移,14–15
与能耗,292
在医疗保健领域,292
AI21,11,130,290,325
ALBERT (Google),176–178
代数与数论,248
AlphaCode (DeepMind),284
AlphaFold,7,111,292
AlphaGo,7
AlphaGo Zero,7
Anthropic,11–12,300,302,320
Apple GPT,319
艺术与版权,生成式 AI,326
通过 GPT-3 生成文章,252–254
ASCII,42
注意力,16–17,78
计算,19–21
因果自注意力,109
GAtt,18
GPT-2 vs. BERT,19
多头,18,25–27
起源,17
自注意力,17–18,21–25
转换器架构,108–109
类型,18–19
AttnGAN 模型,337
AutoClasses,52,115–116
AutoConfig,52,97,115–116
自动编码模型
自动编码器,73
局限性,73
转换器,74,114
AutoModel,50–52,97,115–116,153
自回归 (AR) 模型,105
AR LLMs,71
自回归转换器,71
加速,71–72
转换器架构,70–72
自回归模型,GPT-3 架构,213
AutoTokenizer, 32–33, 44, 49, 51–52, 97, 115–116, 183, 184
B
巴贝奇, 199, 215
反向传播,基于 transformer 的模型, 110, 112–113
翻译回译, 186
字符袋(BoC)算法, 186
词袋(BoW)算法, 186
Bard, 317–318
BART, 10, 75, 81, 83, 108, 178
BERT
令牌生成, 172–174
BERT(来自 Transformer 的双向编码器表示模型), 10, 12, 19, 29, 33, 35, 41, 43, 44, 74
架构, 142
-based 模型选择, 182
BERT-Base, 143
基于 BERT 的标记器, 52
BERT-Large, 143
BERTScore, 145
和双向性, 149
比较基于 BERT 的模型, 189–190
其创建, 153–154
和数据清洗, 151–152
与早期 NLP 模型相比, 144
嵌入层, 152–153
编码, 166–169
家族, 176–182
功能, 142
和 GPT-2 结合, 206
GPT-3 和, 221–222
其内部工作原理, 155–158
输入嵌入, 144–145
其局限性, 142–143
M-BERT, 187–189
MLM, 156
模型, 141
和命名实体识别, 150
和 NLP 任务, 46, 146–148
NSP,157–158
填充句子,147–148
填充 与 截断,148
PaLM,194–195
PLM 和 MPNet,156
Pyramid-BERT,145
实时处理,输入标记,158
ROBERTA,182–183
自注意力,144
中的句子相似度,169–172
使用 DistilBERT 进行情感分析,164–166
以及文本处理,149–150
文本到文本迁移变换器 (T5),193–194
标记化,45–46
代码示例,159–161
DistilBERT 标记化器,163–164
生成,172–174
标记化器,161–164
以及“过长”的句子,147
使用进行主题建模,192
训练,141,143
训练和保存,155
变换器架构,149
1000 种语言的翻译,186–187
词汇和 OOV 词,146
基于网络的工具,190–192
中的词语境,169–172
以及词序,147
BERT (Google),176
BERTScore,145
BertViz,191
双向和自回归变换器 (BART),10,75,81,83,108,176
BioBERT,176,178
BlenderBot 3,286
拓扑分布,228
BPE,参见字节对编码
ByT5 模型,39
字节对编码 (BPE),47–48
C
因果注意力,153,200,213
因果自注意力,109
思维链 (CoT) 提示,230–231
基于字符的 n-gram,186
基于字符的标记器,42–43
聊天机器人战争,295
ChatGPT,4,8–9,11–12,14,18,134–135
高级数据分析,301–302
替代方案,309–311
ChatGPT-3,6–7,296–297,306
Claude-2,302
代码生成和危险话题,305
代码小精灵,303
关注点,304–306
自定义指令,298
定义,295–296
生成文本检测,303–304
Google “代码红色警报”,297
与 Google 搜索,297
GPT-3 “强化版”,296–297
以及 GPT-4 竞争对手,317–320
GPT-5,322–323
GPTBot,299
大型语言模型 Meta AI (LlaMa 2),320–322
机器学习和,311–312
以及医学诊断,309
在移动设备和浏览器上,298
游戏场,299–300
插件,300–301
以及提示,299
样本查询和响应,306–308
优点和缺点,305–306
Chinchilla LLM,12,140
Claude-2,11,302,320
临床 BERT,176,178–179
CLIP (OPENAI),330–331
闭合式提示,232
CNN,参见 卷积神经网络
CNNViz,191–192
代码生成和危险话题,ChatGPT,305
CodeParrot,201–202
代码小精灵,303
Codex (OpenAI),9,318–319
Cohere,9
紧凑语言检测器 3 (CLD3) 模型,187
OpenAI 中的 Completion API,272–274
Completion.create() 方法,15
压缩变换器,114
条件概率,GPT-3,236
对比语言-图像预训练,330–331
对话式代理(聊天机器人),65
对话式人工智能 vs. 生成式人工智能
应用,4
数据需求,5
评估,5
GPT-3,218
主要目标,3,4
使用的科技,4
训练和交互,4
卷积神经网络(CNN),27,65,69,99,240
烹饪食谱,GPT-3,255–258
CoPilot (OpenAI/Microsoft),318
反事实后悔最小化(CFR),8
反事实价值-策略网络(CVPN),8
交叉熵,242–243
跨语言迁移,185
基于 CSS3 的图像,329
Curie,199,215
D
DALL-E,9,338–343
特征,5
图像生成,5
创新组合,6
学习分布,5–6
DALL-E 2,213,344–347
DALL-E 3,347
DALL-E API,340–343
DALL-E-Bot,347
DALL-E DEMOS,347–349
DALL-E 模型,338–343
数据增强,3,311,326
数据清理
基于 BERT 的模型,151
“条件”任务,151
归一化,151–152
正则表达式,152
数据集,Hugging Face
hf_datasets.py,119–120
Iris,121–123
日语,123–126
数据可视化,313–314
Davinci,199,215
DeBERTa(微软),176
deBERTa(超越人类准确度),179
解码器
MMHA 层,105
输出序列的生成,106–107
自注意力,105–106
的工作原理,105
DeepArt,337
深度学习模型,14,301
DeepMind
AlphaFold,7
压缩变换器,114
和游戏,7–8
PoG,8
深度神经网络(DNNs),63
去噪扩散概率模型(DDPMs),330
扩散
在生成式人工智能中,328–330
模型,328,330
剩余部分,335
直接偏好优化(DPO),245
离散概率分布,240–241
DistilBERT,176,179–180,189
模型,55–59
与其进行情感分析,164–166
标记化器,163–164
知识蒸馏,179,190
DNNs,见 深度神经网络
DOC BERT,176
漂移,另见 AI 漂移
数据,15
检测,16
模型,15
dropout 率,110,112,177
药物发现,3,65,326
动态掩码,183
E
ELECTRA(高效学习准确分类标记替换的编码器),117
嵌入
BERT,152–153
OpenAI,9
演化能力,大型语言模型(LLMs),138–139
编码器,另见 位置编码
添加并归一化步骤,104
FFNN,103–104
层,98–99
多头注意力块,103
词嵌入,99–100
工作原理,99
编码器/解码器模型,67–68,108,另见 序列到序列
异常检测,时间序列,70
图像字幕,69
图像到图像翻译,70
机器翻译,69
音乐翻译,70
命名实体识别,69–70
语义分割,图像,70
与 seq2seq 模型关系,68
语音识别,69
文本摘要,69
Transformer,78–79
视频字幕,69
熵,242
exBERT,191
F
快速分词器,53
前馈神经网络 (FFNN),103–104
少样本学习,235–236
与微调 LLMS,234–237
通过提示,236
少样本提示,131
填空任务,94–95
浮点数,227
前向传播,神经网络,19–20
完全微调,235
G
GAtt,参见 幽灵注意力
GauGAN2,336
生成文本检测,ChatGPT,303–304
生成对抗网络 (GANs),2–5,326–327
生成式 AI,1,326–327
应用,4
艺术和版权,326
艺术和音乐创作,3
挑战,3
ChatGPT-3 和 GPT-4,6–7
CLIP (OPENAI),330–331
与 对话式 AI,3–5
创建 与 分类,2
DALL-E,5–6
DALL-E 2,344–347
DALL-E DEMOS,347–349
DALL-E 模型,338–343
扩散,328–330
多样化的输出,3
特性,2
生成对抗网络(GANs),326–327
GLIDE(OPENAI),331–332
中的流行技术,2
文本到图像生成,332–336
文本到图像模型,337–338
文本到语音生成,351
文本到视频生成,349–351
Genoss GPT,287–288
幽灵注意力(GAtt),18
吉尼不纯度,241–242
GitHub,337
GitHub Copilot 案例,338
GitHub 仓库,10,72,126,131,177,185,191,193,216,288,330,332–334
GLIDE(OPENAI),331–332
全球-局部协作注意力模块,337
GloVe,16,169
Google Bard,310
Google“代码红色”,297
Google Colaboratory 笔记本,193
Google 搜索 vs. ChatGPT,297
Google SMITH,176,180
Google 的神经机器翻译(GNMT)系统,64
Google 的 TensorFlow Hub,338
Google 翻译,64,113,186
Gopher,7
GPT(广义预训练转换器)家族
架构,198
引擎,199
关于模型的更新,199
GPT-2,10,19,33,44,65,75,76,83,108,148,178,200–
架构,200
和 CodeParrot,201–202
结合 BERT,206
检测器,303–304
混合匹配模型,210
与问答,204–205
和文本生成,206–210
分词器,202–204
GPT-3,7,9,12,75,84,131,134–135
AI
和能耗,292
在医疗保健领域,292
替代方案,289–291
应用,284–287
架构,213
和算术运算,247
和 BERT,221–222
BOT 和聊天机器人,285–286
思维链(CoT)提示,230–231
使用 Ada 引擎生成代码,263–264
OpenAI 中的 Completion API,272–274
条件概率,236
对话式 AI 方面,218
烹饪食谱,255–258
设计提示,230
少样本学习和微调 LLMS,234–237
微调与强化学习(可选),240–245
四个,212
通过生成文章,252–254
为任务生成“如何”指令,251–252
目标,216–217
和幽默,259
推理参数,226–229
与语言相关的提示,250
与语言翻译,254–255
局限性,219–220
数学提示,262–263
模型,214–216
与多语言模型,215–216
“增强版”,296–297
开源变体,287–291
与哲学提示,261–262
Playground,222–226
写诗,258–259
预训练模型,212–213
提示工程,231–234
以及提示样本,245–265
Python 和 OpenAI APIS,265–270
使用它进行问答,259–261
需求和参数,213–214
保存代码和生成新的代码示例,264–265
使用它进行情感分析,281–283
与股票相关的提示,261
任务性能,220–221
任务优势和错误,220
使用它进行文本分类,279–281
文本补全和温度,274–278
在 OpenAI 中的文本补全,270–272
文本摘要和摘要,218–219
有害内容,291–292
使用提示进行工作,229–230
GPT-4,4, 6–7, 13, 81, 134, 140, 198, 315, 317
微调,316
参数,316
与测试成绩,315–316
GPT-5,322–323
GPTBot,299
GPT-J (EleutherAI), 289
GPT-Neo (EleutherAI), 288
增长树 CFR (GT-CFR), 8
GT-CFR,参见增长树 CFR
指导提示,232
H
H100,81–82
hf_prompt_fill.py,94–95
Hinton, Geoffrey, 112
Hopper,82
Hugging Face, 10, 30
AutoClasses,115–116
数据集,119–126
管道,117–119
Transformer
代码示例,85–91
命名实体识别 (NER) 任务,85–87
QnA 任务,87–88
文本摘要,88–90
文本翻译,90–91
Transformer 库,基于 Python,82–84
Hugging Face 分词器
AutoClasses,52
AutoTokenizer,51–52
bert-base-uncased 模型,49–50
BERTTokenizer,51–52
分类,53–55
GPT2Tokenizer,51–52
加载和保存,51
慢速和快速分词器,53
幽默与 GPT-3,259
I
Imagen (Google),213,334
Imagen 文本到视频,350
图像合成,3,5–6,326,328,334,337,338
图像到图像处理,130
InflectionAI,11
InstructGPT,312–313
指令提示,232
指令提示,131–132
指令模型,9
ISO-159,42
意大利语和日语语言翻译,183–185
迭代提示,232–233
J
JSONL,212–213
Jurassic-1,11–12,137,290
K
Kaplan,12,139–140
KeyBERT,176
Kullback-Leibler 散度 (KLD),240,243–244
Kullback-Leibler (KL) 散度,239
L
LangChain 和 LangSmith,287
语言
检测,269–270
GPT-3 相关提示,250
翻译,72,110,113
使用 GPT-3 进行翻译,254–255
语言模型自我改进 (LMSI),231
大型语言模型 Meta AI (LlaMa 2),320–322
大型语言模型 (LLMs)
AR,71
注意事项,14
Chinchilla,12,140
基于解码器,59
演化能力,138–139
GPT-3,12
相同层,78–79
语言,13
损失函数,14
模型大小 与 训练集大小,12–13
提示,134–135
大小,12
Switch,117
令牌选择技术,59
Transformer 架构,75
潜在狄利克雷分配 (LDA),192
潜在语义分析 (LSA),195
层归一化 (LN),111–112
听、注意和拼写 (LAS),65
近似敏感哈希 (LSH),116
Longformer 模型,116
长短期记忆 (LSTM),17–19,23,62,68,75,79,110,144,147,200,221
基于 seq2seq,63
特征,63
最后一层,66–67
隐藏状态,67
独立于,76–77
循环效应,199
低秩适配器,236
M
Meta 的 Make-A-scene,334
Make-a-Video (Meta),325,350
掩码注意力,77,79,109
掩码语言模型 (MLM),114,156
掩码多头注意力 (MMHA),105
掩码相关任务,91–95
m-BERT,185,187–189
Med-PaLM 2,319
内存复杂度,17
Meta (make-a-video), 350
MirrorGAN model, 337
mix-and-match models, GPT-2, 210
Mobile-BERT, 189
mobile devices and browsers, ChatGPT on, 298
Model Zoos, 337
monolingual data, 186
MPNet, 156
mSLAM, 185
mT5, 39
multi-head attention (MHA), 18
CNN filters, 27
description, 25–26
multilingual language models, 185–186
multi-lingual models vs. GPT-3, 215–216
MUSE, 185
N
named entity recognition (NER) task, 43, 69–70, 85–87
Natural Language Generation (NLG), 72
natural language processing (NLP), 4, 9, 10, 64
tasks and BERT, 146–148
transformer-based models, 81
Natural Language Understanding (NLU), 72, 83, 189
next sentence prediction (NSP), 114, 155
BERT, 143, 145
vs. language modeling, 157–158
purpose of, 157
vs. SOP, 157
noise-driven process, 328
Non-Negative Matrix Factorization (NMF), 192
normalization, 151–152
NVidia, 81–82
O
O(N²) complexity, 84–85, 116
one-shot prompts, 131
OpenAI, 8–9, 346
OpenAI Web site, 214
open-ended prompts, 232
open-sourced NLLB model, 187
open-source variants of GPT-3, 287–291
OSCAR, 185
out-of-vocabulary (OOV) words, 146
P
padding
sentences, 147–148
vs. truncation, 148
PaLM, 194–195
PaLM-2, 319
Papers with Code,337,338
并行数据,186
Parti,213
Pathways,195
乱序语言建模,192
乱序语言模型(PLM),156
GPT-3 的哲学提示,261–262
从屈折变化中得到的π值,311
Pix2Pix 模型,70
游戏玩家(PoG),8
PLM,见 乱序语言模型
诗歌创作,GPT-3,258–259
表述不佳的提示,135–136
位置编码,18
描述,100–101
正弦()和余弦()函数,101–102
类型,102
预标记化,29–30,另见 标记化
代码示例,32–34
vs. 标记化,30–31
预训练的 M-BERT 模型,188
预训练的 Sentence-BERT 模型,172
概率图模型,326–327
提示
代理,132–133
和 ChatGPT,299
描述,130–131
工程,130
适用于 ChatGPT,233–234
设计,230
少样本学习,236
使用符号调整进行微调,236
有效提示的指南,233
重要性,232
LoRA,量化以及 QLoRA,236–237
模型指导,232
输出质量,232
提示的力量,249–250
任务规范,232
类型,232–233
使用方法,229–230
少样本,131
指令,131–132
LLMs,134–135
单样本,131
表述不佳,135–136
反向,132
系统,132–133
任务,94–95
模板,133–134
类型,131
零样本,131
PromptBase,336
近端策略优化(PPO),244–245
算法,240
Pyramid-BERT,145
Python 和 OpenAI API,265–270
基于 Python 的工具,漂移检测,16
PyTorch,337
pytorch_model.bin,155
Q
量化,236–237
量化低秩自适应(QLoRA),237
问答(QnA),61,87–88,141,146
与 GPT-2,204–206
与 GPT-3,259–261
R
循环神经网络(RNNs),2,17
基于 seq2seq,63
隐藏状态,67
LSTM 与,67,68
基于 NLP 的任务,76
Reformer 架构,116
正则表达式,152
强化学习(RL),240
带有人类反馈的强化学习(RLHF),240,244
残差连接,111
受限玻尔兹曼机(RBMs),326–327
反向提示,132
可逆标记化,48–49
RoBERTa,182–183,189
Ruben Villegas 和 Google (Phenaki),350–351
S
SBERT,176
缩放点积注意力,参见 自注意力
缩放因子 dk,110
scikit-learn 库,152
分数匹配技术,328
分段嵌入,113
自注意力,17–18,21–25
自洽性和 CoT,231
Sentence-BERT,172
句子顺序预测(SOP),157
SentencePiece,48–49
情感分析,126
使用 GPT-3,281–283
序列到序列(Seq2Seq/seq2seq)模型
对话式代理(聊天机器人),65
编码器和解码器组件,62
图像字幕,65
机器翻译,64
分子设计,65
多层 LSTM,62
音乐生成,66
预测问题,64
程序翻译,66
语音识别,65
文本生成,63
文本摘要,64–65
时间序列预测,65
类型,63–64
视频字幕,65
sigmoid()激活函数,63
跳过连接,参见残差连接
慢速分词器,53
softmax()函数,19,23–24,26,27,109,227–229,240
SOTA(“最高水平”)性能,189
扩散模型,330
结果,8
源代码,基于 transformer 的模型,126–127
SQL 和 GPT-3,285
SQuAD 2.0 数据集,221
稳定 AI 和稳定扩散,333–334
StackGAN 模型,337
“状态字典”,155
GPT-3 的股票相关提示,261
Streamlined Object Generator,337
风格迁移,3,326,337
子词分词
算法,46–49
BPE,47–48
代码示例,44–45
SentencePiece,48–49
WordPiece,48
SVG(可缩放矢量图形),246
Switch transformer,117
符号调整,236
系统提示,132–133
T
T5 分词器,35
T5X,194
tanh()函数,19,63
温度和最大标记数,232,233
TensorFlow,338
TensorFlow 1.x,67
使用 GPT-3 进行文本分类,279–281
文本补全和温度,274–278
文本生成,3,6,9–10,63,83,108,137,141,178,201,206–210,220,287,339
文本处理,149–150
文本摘要,88–90
GPT-3,218
文本到图像
生成,332–336
模型,337–338
文本到语音生成,351
文本到文本迁移变换器(T5),193–194
文本到视频(Imagen),325,350
文本到视频生成,349–351
文本翻译,90–91
TinyBERT,176,180
分词,另见 分词器
BERT,45–46
ByT5 模型,39
基于字符的分词器,42–43
描述,34–35
DistilBERT 模型,55–59
Hugging Face 分词器和模型,49–52
多字母表语言,42
与 预分词,30–31
可逆的,49
选择技术,LLMS,59
子词,43–46
任务和挑战,37–39
词到索引映射算法,35–37
基于单词的分词器,40–41
单词分词器,局限性,41
分词器
AutoTokenizer,BERTTokenizer 和 GPT2Tokenizer,51–52
基于字符的,42–43
快速,53
GPT-2,202–204
基于 GPT2,35
Hugging Face,49–52
局限性,41
加载和保存,51
慢,53
基于 T5,35
基于词,40–41
词到索引映射算法,35–37
训练机制,331
迁移学习,222
Transformer 架构
注意力,108–109
AutoClasses,115–116
因果自注意力,109
代码示例,Hugging Face,85–91
复杂度,84–85
组件,77–78
压缩 Transformer,114
解码器组件,104–107
dropout 率,112
ELECTRA,117
编码器和解码器块,75–76
编码器组件,98–104
流和变体,80–82
前向传播,110
图,82
Hugging Face 数据集,119–126
实现,107–108
输入序列长度,110
键、查询和值向量,110
语言翻译和词序,110,113
LN,111–112
Longformer 模型,116
多模态,108
操作,顺序,76
Reformer 架构,116
残差连接,111
RNN 和 LSTM,76–77
缩放因子 dk,110
段嵌入,113
情感分析,126
源代码,基于 Transformer 的模型,126–127
Switch Transformer,117
Transformer 和反向传播,110,112–113
Transformer 库,Hugging Face,82–84
类型,75
单向和双向嵌入,109
权重矩阵,110
基于 Transformer 的模型,206
Transformer 库,Hugging Face
和自然语言处理任务,83
管道类,83–84
主成分,82
截断,148
信任域策略优化 (TRPO),240,244–245
U
无监督数据集,231
UTF-8,42
V
变分自编码器 (VAEs),2,4,326–327
VideoBERT,181
VisualBERT,176,181
VizGPT,313–314
W
基于网络的 BERT 工具,190–192
权重矩阵,110
Whisper (OpenAI),325,351
维基百科,156
词,30
word2vec,16–17,169
基于词的标记器,40–42
BERT 的词嵌入,152
词序
BERT,147
和语言翻译,110,113
XLNet,181
WordPiece,48,53,129,142,144,146,156
写作助手,286–287
X
XGLM,81,216,290
XLM,185
XLM-R,176,185
XLNet,71,83,156,157,176–178,181–182
XLSR,185
Y
YaLM (Yandex),289
YouChat,310
Z
Zero-shot-CoT 表现更优,230
零样本学习,331
零样本提示,131

浙公网安备 33010602011771号