Transformers-自然语言处理-全-

Transformers 自然语言处理(全)

原文:zh.annas-archive.org/md5/a1e65552fc41f3b5a667f63d9bed854c

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Transformers对于自然语言理解(NLU)的重要性不言而喻,NLU 是自然语言处理(NLP)的一个子集,在全球数字经济中已经成为人工智能的支柱之一。

Transformers模型标志着人工智能的新时代的开始。语言理解已成为语言建模、聊天机器人、个人助手、问答、文本摘要、语音转文本、情感分析、机器翻译等领域的支柱。我们正在见证社交网络与面对面的社交相比的扩张,电子商务与实体购物的竞争,数字新闻与传统媒体的竞争,流媒体与实体剧院的竞争,远程医生咨询与实体就诊的竞争,远程工作与现场任务的竞争以及数百个领域中类似的趋势。如果没有 AI 语言理解,社会将难以使用网络浏览器、流媒体服务以及任何涉及语言的数字活动。我们社会从物理信息到大规模数字信息的范式转变迫使人工智能进入了一个新时代。人工智能已经演化到了亿级参数模型来应对万亿字数据集的挑战。

Transformers架构既具有革命性又具有颠覆性。它打破了过去,摆脱了 RNN 和 CNN 的主导地位。 BERT 和 GPT 模型放弃了循环网络层,并用自注意力替换它们。Transformers模型胜过了 RNN 和 CNN。 2020 年代正在经历人工智能的重大变革。

Transformers编码器和解码器包含可以单独训练的注意力头,可以并行化最先进的硬件。注意力头可以在单独的 GPU 上运行,为亿级参数模型和即将推出的万亿级参数模型敞开大门。OpenAI 在拥有 10000 个 GPU 和 285000 个 CPU 核心的超级计算机上训练了一个有 1750 亿参数的 GPT-3 Transformers模型。

数据量的增加要求以规模训练 AI 模型。因此,Transformers为参数驱动 AI 开辟了新的时代。学会理解数亿个单词在句子中如何组合需要大量参数。

谷歌 BERT 和 OpenAI GPT-3 等Transformers模型已经将新兴技术推上了新的高度。Transformers可以执行它们未经过训练的数百种 NLP 任务。

Transformers还可以通过将图像嵌入为单词序列来学习图像分类和重建。本书将向您介绍最前沿的计算机视觉Transformers,如视觉Transformers(ViT),CLIP 和 DALL-E。

基础模型是完全训练的Transformers模型,可以在不进行微调的情况下执行数百种任务。在这个大规模信息时代,基础模型提供了我们所需要的工具。

想想需要多少人来控制每天在社交网络上发布的数十亿条消息的内容,以在提取其中的信息之前判断它们是否合法和道德。

想想需要多少人来翻译每天在网络上发布的数百万页。或者想象一下手动控制每分钟生成的数百万条消息需要多少人!

最后,想想需要多少人来记录每天在网络上发布的大量流媒体的转录。最后,想想替代 AI 图像字幕对那些持续出现在网上的数十亿张图片所需的人力资源。

这本书将带你从代码开发到提示设计,掌握控制 Transformer 模型行为的新 "编程" 技能。每一章都将带你从 Python、PyTorch 和 TensorFlow 的零基础开始,了解语言理解的关键方面。

你将学习到原始 Transformer、Google BERT、OpenAI GPT-3、T5 以及其他几个模型的架构。你将微调 transformer,从头开始训练模型,并学会使用强大的 API。Facebook、Google、Microsoft 和其他大型科技公司分享了大量数据集供我们探索。

你将与市场及其对语言理解的需求保持紧密联系,例如媒体、社交媒体和研究论文等领域。在数百个 AI 任务中,我们需要总结大量的研究数据,为经济的各个领域翻译文件,并为伦理和法律原因扫描所有的社交媒体帖子。

在整本书中,你将尝试使用 Python、PyTorch 和 TensorFlow 进行实践。你将了解关键的 AI 语言理解神经网络模型。然后,你将学习如何探索和实现 transformer。

在这个颠覆性的 AI 时代,你将学到成为工业 4.0 AI 专家所需的新技能。本书旨在为读者提供 Python 深度学习方面的知识和工具,以有效开发语言理解的核心内容。

本书适合谁阅读

本书不是 Python 编程或机器学习概念的入门。相反,它专注于机器翻译、语音转文字、文字转语音、语言建模、问答等多个 NLP 领域的深度学习。

最能从本书受益的读者有:

  • 熟悉 Python 编程的深度学习和 NLP 从业者。

  • 数据分析师和数据科学家想要对 AI 语言理解有个初步了解,以处理越来越多的以语言为驱动的功能。

本书涵盖的内容

第一部分:Transformer 架构简介

第一章,什么是 Transformer?,在高层次上解释了 Transformer 是什么。我们将看看 Transformer 生态系统以及基础模型的特性。本章突出了许多可用的平台以及工业 4.0 AI 专家的演变。

第二章,了解 Transformer 模型的架构初步,通过 NLP 的背景来理解 RNN、LSTM 和 CNN 深度学习架构是如何演变成打开新时代的 Transformer 架构的。我们将通过 Google Research 和 Google Brain 的作者们提出的独特 注意力就是一切 方法来详细了解 Transformer 的架构。我们将描述Transformers的理论。我们将用 Python 亲自动手来看看多头注意力子层是如何工作的。在本章结束时,你将了解到 Transformer 的原始架构。你将准备好在接下来的章节里探索 Transformer 的多种变体和用法。

第三章,微调 BERT 模型,在原始 Transformer 的架构基础上构建。来自Transformers的双向编码表示(BERT)向我们展示了一个感知 NLP 世界的新方式。BERT 不是分析过去的序列以预测未来的序列,而是关注整个序列!我们将首先了解 BERT 架构的关键创新,然后通过在 Google Colaboratory 笔记本中逐步微调 BERT 模型。像人类一样,BERT 可以学习任务,并且执行其他新任务而无需从头学习话题。

第四章,从头开始预训练 RoBERTa 模型,使用 Hugging Face PyTorch 模块从头构建一个 RoBERTa Transformers模型。 这个Transformers模型将类似于 BERT 和 DistilBERT。首先,我们将在一个定制的数据集上从头开始训练一个分词器。然后,训练好的Transformers模型将在一个下游掩码语言建模任务中运行。

第 II 部分:将 Transformer 应用于自然语言理解和生成

第五章,使用 Transformer 进行下游 NLP 任务,展示了使用下游 NLP 任务的魔力。一个预训练的Transformers模型可以被微调以解决一系列 NLP 任务,如 BoolQ、CB、MultiRC、RTE、WiC 等,在 GLUE 和 SuperGLUE 排行榜上占据主导地位。我们将介绍Transformers的评估过程、任务、数据集和指标。然后我们将使用 Hugging Face 的Transformers管道运行一些下游任务。

第六章,使用 Transformer 进行机器翻译,定义机器翻译以了解如何从人类标准到机器传导方法。然后,我们将预处理来自欧洲议会的 WMT 法英数据集。机器翻译需要精确的评估方法,在本章中,我们将探讨 BLEU 评分方法。最后,我们将使用 Trax 实现一个 Transformer 机器翻译模型。

第七章,超人类 Transformers 的崛起与 GPT-3 引擎,探讨了 OpenAI 的 GPT-2 和 GPT-3 transformers 的许多方面。我们将首先检查 OpenAI 的 GPT 模型的架构,然后解释不同的 GPT-3 引擎。接着我们将运行一个 GPT-2 345M 参数模型,并与其交互生成文本。接下来,我们将看到 GPT-3 游乐场的运作方式,然后编写一个用于 NLP 任务的 GPT-3 模型,并将结果与 GPT-2 进行比较。

第八章,将 Transformer 应用于法律和金融文件以进行 AI 文本摘要,介绍了 T5 Transformer 模型的概念和架构。我们将使用 Hugging Face 的 T5 模型来进行文档摘要。我们将让 T5 模型摘要各种文档,包括 权利法案 中的样本,探讨将迁移学习方法应用于 Transformers 的成功和局限性。最后,我们将使用 GPT-3 将一些公司法文本摘要成二年级水平的语言。

第九章,匹配 Tokenizers 和数据集,分析了分词器的限制,并研究了一些用于改进数据编码过程质量的方法。我们将首先构建一个 Python 程序来研究为什么一些单词会被 word2vector 分词器省略或误解。在此之后,我们将使用一个与分词器无关的方法来找出预训练分词器的限制。

我们将通过应用一些显示仍有很大改进空间的想法来改进 T5 摘要方法论。最后,我们将测试 GPT-3 的语言理解能力的限制。

第十章,使用基于 BERT 的 Transformers 进行语义角色标注,探讨了 Transformers 如何学习理解文本内容。语义角色标注(SRL)对人类来说是一个具有挑战性的练习。Transformers 可以产生令人惊讶的结果。我们将在 Google Colab 笔记本中实现由 AI 艾伦研究所设计的基于 BERT 的 Transformer 模型。我们还将使用他们的在线资源来可视化 SRL 输出。最后,我们将质疑 SRL 的范围,并理解其局限性背后的原因。

第三部分:高级语言理解技术

第十一章,让你的数据说话:故事、问题和答案,展示了 Transformer 如何学会推理。Transformer 必须能够理解文本、故事,并展现出推理技能。我们将看到如何通过添加 NER 和 SRL 来增强问答过程。我们将为一个问题生成器建立蓝图,该生成器可以用于训练 Transformers 或作为独立解决方案。

第十二章,检测客户情绪以进行预测,展示了Transformers如何改进情感分析。我们将使用斯坦福情感树库分析复杂句子,挑战几种Transformers模型,以理解一个序列的结构和逻辑形式。我们将看到如何使用Transformers进行预测,根据情感分析输出触发不同的动作。该章节最后通过使用 GPT-3 来解决一些边缘案例。

第十三章,使用Transformers分析假新闻,深入探讨了假新闻的热门话题以及Transformers如何帮助我们理解我们每天看到的在线内容的不同视角。每天,在线社交媒体、网站以及各种实时通讯方式发布数十亿条消息、帖子和文章。使用前几章的几种技术,我们将分析气候变化和枪支管制的辩论,以及一位前总统的推文。我们将讨论在合理怀疑的基础上确定什么可以被认为是假新闻,以及哪些新闻是主观的道德和伦理问题。

第十四章,解释黑匣子Transformers模型,通过可视化它们的活动揭开了Transformers模型的黑匣子。我们将使用 BertViz 来可视化注意力头,使用语言可解释性工具(LIT)来进行主成分分析(PCA)。最后,我们将使用 LIME 通过字典学习来可视化Transformers。

第十五章,从自然语言处理到任务无关的Transformers模型,深入研究了先进模型 Reformer 和 DeBERTa,运用 Hugging Face 运行示例。Transformers可以将图像处理为单词序列。我们还将看到不同的视觉Transformers,如 ViT、CLIP 和 DALL-E。我们将对它们进行计算机视觉任务的测试,包括生成计算机图像。

第十六章,Transformers驱动联合驾驶员的出现,探讨了工业 4.0 的成熟度。本章从使用非正式/随意英语的提示工程示例开始。接下来,我们将使用 GitHub Copilot 和 OpenAI Codex 从几行指令中创建代码。我们将看到视觉Transformers如何帮助自然语言处理Transformers可视化周围的世界。我们将创建一个基于Transformers的推荐系统,该系统可以由数字人类在您可能会进入的任何元宇宙中使用!

附录 I,Transformers模型术语,检查了一个Transformers的高层结构,从堆栈和子层到注意力头。

附录 II,Transformers模型的硬件约束,着眼于运行Transformers的 CPU 和 GPU 性能。我们将看到为什么Transformers和 GPU 以及Transformers是完美的匹配,最后进行一个测试,使用 Google Colab CPU、Google Colab 免费 GPU 和 Google Colab Pro GPU。

附录 III,使用 GPT-2 进行通用文本完成,详细解释了使用 GPT-2 进行通用文本完成的内容,从第七章,GPT-3 引擎的超人类转变。

附录 IV,使用 GPT-2 进行自定义文本完成,通过构建和训练 GPT-2 模型并使其与自定义文本交互,补充了第七章,GPT-3 引擎的超人类转变。

附录 V,问题答案,提供了每章末尾问题的答案。

充分利用本书

本书中的大多数程序都是 Colaboratory 笔记本。您只需要一个免费的 Google Gmail 帐户,就可以在 Google Colaboratory 的免费虚拟机上运行这些笔记本。

您需要在计算机上安装 Python 才能运行一些教育性程序。

花费必要的时间阅读第二章,开始理解Transformers模型的架构 和 附录 I,Transformers模型术语。第二章 包含了原始Transformers的描述,该描述是由 附录 I,Transformers模型术语 中解释的构建块构成的,这些构建块将在本书中实现。如果您觉得困难,可以从章节中提取一般的直观想法。当您在几章后对Transformers感到更加舒适时,您可以再回到这些章节。

阅读完每章后,考虑您如何为您的客户实施Transformers或使用它们提出新颖的想法来提升您的职业生涯。

请注意,我们在书的后面使用 OpenAI Codex,目前有等待名单。现在注册以避免长时间等待,请访问openai.com/blog/openai-codex/。

下载示例代码文件

本书的代码包托管在 GitHub 上,地址为github.com/Denis2054/Transformers-for-NLP-2nd-Edition。我们还提供了来自我们丰富书目和视频目录的其他代码包,请查看github.com/PacktPublishing/。

下载彩色图像

我们还提供了一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图像。您可以在此处下载:static.packt-cdn.com/downloads/9781803247335_ColorImages.pdf。

使用约定

本书中使用了几种文本约定。

CodeInText:指示在书中运行的句子和单词,文本中的代码单词,数据库表名,文件夹名,文件名,文件扩展名,路径名,虚拟 URL,用户输入和 Twitter 句柄。例如,“但是,如果您想要探索代码,您可以在本章的 GitHub 代码库中找到 Google Colaboratory 的 positional_encoding.ipynb 笔记本和 text.txt 文件。”

代码块设置如下:

import numpy as np
from scipy.special import softmax 

当我们希望引起您对代码块的特定部分的注意时,相关行或项会以粗体显示:

The **black** cat sat on the couch and the **brown** dog slept on the rug. 

任何命令行输入或输出都按如下方式编写:

vector similarity
[[0.9627094]] final positional encoding similarity 

粗体:表示新术语、重要词语或在屏幕上看到的文字,例如在菜单或对话框中,也会在文本中以此形式出现。例如:“在我们的情况下,我们正在寻找t5-large,一个我们可以在 Google Colaboratory 中顺利运行的 t5-large 模型。”

警告或重要提示以这种方式出现。

提示和技巧以这种方式出现。

第一章:什么是Transformers?

Transformers是工业化、同质化的后深度学习模型,设计用于超级计算机上的并行计算。通过同质化,一个Transformers模型可以在不经过微调的情况下执行各种任务。Transformers可以对数十亿条原始未标记数据进行自监督学习,其参数达到数十亿个。

这些特殊的后深度学习架构被称为基础模型。基础模型Transformers代表了 2015 年开始的第四次工业革命的顶峰,即机器对机器自动化将一切连接到一切。人工智能总体上,特别是自然语言处理(NLP)对工业 4.0(I4.0)的发展已经远远超越了过去的软件实践。

在不到五年的时间里,人工智能已经成为一个具有无缝 API 的有效云服务。以前的下载库和开发范式在许多情况下已经成为一种教育练习。

工业 4.0 项目经理可以进入 OpenAI 的云平台,注册,获取 API 密钥,并在几分钟内开始工作。用户然后可以输入文本,指定 NLP 任务,并获得由 GPT-3 Transformers引擎发送的响应。最后,用户可以转到 GPT-3 Codex,并创建没有编程知识的应用程序。提示工程是从这些模型中出现的新技能。

但是,有时候 GPT-3 模型可能不适合特定的任务。例如,项目经理、顾问或开发人员可能希望使用由谷歌 AI、亚马逊网络服务(AWS)、艾伦人工智能研究所或 Hugging Face 提供的另一个系统。

项目经理应该选择在本地工作吗?还是应该直接在谷歌云、微软 Azure 或 AWS 上实施?开发团队应该选择 Hugging Face、Google Trax、OpenAI 还是 AllenNLP?人工智能专家或数据科学家是否应该使用几乎没有 AI 开发的 API?

答案是以上全部。您不知道未来的雇主、客户或用户可能想要或指定什么。因此,您必须准备好适应任何可能出现的需求。本书并未描述市场上存在的所有提供。但是,本书为读者提供了足够的解决方案,以适应工业 4.0 AI 驱动的 NLP 挑战。

本章首先从高层次解释了Transformers是什么。然后,本章解释了获取对实现Transformers的所有类型方法的灵活理解的重要性。平台、框架、库和语言的定义在市场上提供的 API 和自动化的数量下变得模糊。

最后,本章介绍了在嵌入式Transformers方面的工业 4.0 人工智能专家的角色。

在开始我们探索本书中描述的各种Transformers模型实现之前,我们需要解决这些关键概念。

本章涵盖以下主题:

  • 第四次工业革命,工业 4.0 的出现

  • 基础模型的范式变革

  • 引入提示工程,一门新的技能

  • Transformers的背景

  • 实施Transformers的挑战

  • 颠覆性的Transformers模型 API

  • 选择Transformers库的难度

  • 选择Transformers模型的困难

  • 工业 4.0 人工智能专家的新角色

  • 嵌入式Transformers

我们的第一步将是探索Transformers的生态系统。

Transformers的生态系统

Transformers模型代表了一种范式变革,需要一个新名称来描述它们:基础模型。因此,斯坦福大学创建了基础模型研究中心(CRFM)。2021 年 8 月,CRFM 发表了一份 200 页长的论文(见参考文献部分),由一百多位科学家和专业人士所写:《关于基础模型的机遇和风险》。

基础模型并不是由学术界而是由大型科技行业所创建。例如,谷歌发明了Transformers模型,从而导致了 Google BERT。微软与 OpenAI 合作生产了 GPT-3。

大型科技公司不得不找到一个更好的模型来应对其数据中心中流动的百万吉字节数据的指数增长。因此,Transformers由此诞生。

让我们首先考虑工业 4.0,以了解需要具有工业化人工智能模型的需求。

工业 4.0

农业革命引发了第一次工业革命,引入了机械。第二次工业革命诞生了电力、电话和飞机。第三次工业革命是数字化的。

第四次工业革命,或工业 4.0,产生了无限的机器之间的连接:机器人、机器人、连接设备、自动驾驶汽车、智能手机、从社交媒体存储库搜集数据的机器人等。

反过来,这些数百万台机器和机器人每天生成数十亿的数据记录:图像、声音、文字和事件,如图 1.1所示:

一个包含文本描述的图像

图 1.1:工业 4.0 的范围

工业 4.0 需要进行大规模的数据处理和决策的智能算法,以应对人类历史上前所未有的数据量而无需人为干预。

大型科技公司需要找到一个能够执行以往需要多个独立算法的各种任务的单一 AI 模型。

基础模型

Transformers具有两个显著特点:高度同质化和令人震惊的新兴特性。 同质化 使得可以使用一个模型执行各种任务。这些能力 通过 在超级计算机上训练千亿参数模型而得到。

这种范式变化使得基础模型成为深度学习后生态系统,如图 1.2 所示:

图 1.2:I4.0 人工智能专家的范围

基础模型,虽然设计了创新的架构,但是建立在人工智能的历史基础之上。因此,人工智能专家的技能范围正在拓展!

目前Transformers模型的生态系统与人工智能领域的任何其他演进都不同,并且可以总结为四个特性:

  • 模型架构

    该模型是工业化的。模型的层是相同的,它们专门设计用于并行处理。我们将在第二章 Transformers模型架构入门中详细介绍Transformers的架构。

  • 数据

    大型科技公司拥有人类历史上最庞大的数据来源,首先由第三次工业革命(数字化)产生,并由工业 4.0 推动至不可想象的规模。

  • 计算能力

    大型科技公司拥有前所未见规模的计算能力。例如,GPT-3 的训练速度约为 50 PetaFLOPS/秒,谷歌现在拥有领域特定的超级计算机,超过了 80 PetaFLOPS/秒。

  • 提示工程

    经过高度训练的Transformers可以通过提示来执行任务。提示以自然语言输入。然而,所使用的单词需要一定的结构,这使得提示成为一种元语言。

因此,基础模型是在亿万条数据和亿级参数的超级计算机上进行训练的Transformers模型。该模型然后可以执行各种任务,而无需进一步的微调。因此,基础模型的规模是独一无二的。这些完全训练的模型通常被称为引擎。只有 GPT-3、Google BERT 和少数几个Transformers引擎可以被视为基础模型。

我在本书中只会在提及 OpenAI 的 GPT-3 或 Google 的 BERT 模型时提及基础模型。这是因为 GPT-3 和 Google BERT 是在超级计算机上进行完全训练的。尽管其他模型对于有限的用途来说很有趣且有效,但由于缺乏资源,其他模型并未达到基础模型的同质化水平。

现在让我们探究一个基础模型是如何工作的,并且如何改变了我们开发程序的方式。

编程现在是否成为 NLP 的一个子领域?

Chen等人(2021 年)于 2021 年 8 月发表了一篇爆炸性的论文,介绍了 Codex,这是一个能将自然语言转换为源代码的 GPT-3 模型。Codex 是在 5400 万个公共 GitHub 软件仓库上进行训练的。Codex 可以生成有趣的自然语言到源代码,我们将在第十六章 Transformers驱动共同合作者的出现 中看到。

现在,编程是一种从自然语言到源代码语言的翻译任务吗?

编程是否正在成为 GPT-3 引擎的一项 NLP 任务?

在回答那个问题之前,让我们看一个例子。

请记住,Codex 是一种随机算法,所以元语言很棘手。如果您不小心正确地设计提示,可能不会生成您期望的结果。

当我试验 Codex 时,我创建了一些提示。这个例子只是为了让您了解 Codex 的工作原理,纯粹是为了教育目的。

我的提示是:

  • 在 Python 中“生成 200 个介于 1 到 100 之间的随机整数的随机分布”

  • “使用 matplotlib 绘制数据”

  • “创建具有 3 个质心的 k 均值聚类模型并拟合模型”

  • “打印聚类标签”

  • “绘制聚类”

  • “绘制带有质心的聚类”

Codex 自动将我的自然元语言提示翻译成 Python!

Codex 是一种随机模型,因此如果您再次尝试,可能不会完全再现相同的代码。您将不得不通过实验来学习元语言,直到能像驾驶赛车一样驾驭它!

Python 程序将自动生成,并可复制和测试:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets.samples_generator import make_blobs
# generate random data
np.random.seed(0)
X, y = make_blobs(n_samples=200, centers=3, n_features=2, cluster_std=2, random_state=0)
# plot the data
plt.scatter(X[:, 0], X[:, 1], s=50)
plt.show()
# create the k-means model
kmeans = KMeans(n_clusters=3, random_state=0)
# fit the model to the data
kmeans.fit(X)
# print the cluster labels
print(kmeans.labels_)
#plot the clusters
plt.scatter(X[:, 0], X[:, 1], c=kmeans.labels_, cmap='rainbow')
plt.show()
# plot the clusters with centroids
plt.scatter(X[:, 0], X[:, 1], c=kmeans.labels_, cmap='rainbow')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], c='black', s=100, alpha=0.5)
plt.show() 

你可以复制粘贴这个程序。它有效。你也可以尝试 JavaScript,等等其他实验。

GitHub Copilot 现已与一些微软开发工具一起提供,我们将在第十六章《基于 Transformer 的协作工具的出现》中看到。如果您学会了提示工程元语言,您将在未来几年内缩短开发时间。

终端用户如果掌握了元语言,就能创建原型或小任务。未来,编码协助工具将会扩展。

我们将在第十六章中看到 Codex 在人工智能未来中的地位。

此时,让我们一睹人工智能专家美好未来的一瞥。

人工智能专家的未来

基础模型的社会影响不容小觑。提示工程已成为人工智能专家所需的一项技能。然而,人工智能专家的未来不能仅限于Transformers。人工智能和数据科学在 I4.0 中重叠。

AI 专家将参与使用经典人工智能、物联网、边缘计算等机器之间算法。AI 专家还将使用经典算法设计和开发有趣的机器人、服务器和各种连接设备之间的连接。

因此,这本书不仅限于提示工程,还涵盖了成为“工业 4.0 人工智能专家”或“I4.0 人工智能专家”所需的广泛设计技能。

提示工程是 AI 专家将必须开发的设计技能的子集。在这本书中,我将将未来的 AI 专家称为“工业 4.0 人工智能专家”。

现在让我们对Transformers如何优化 NLP 模型有一个总体了解。

使用Transformers优化 NLP 模型

循环神经网络(RNNs),包括 LSTMs,几十年来一直将神经网络应用于自然语言处理的序列模型。然而,当面对长序列和大量参数时,使用递归功能达到了极限。因此,现在最先进的转换器模型占据了主导地位。

本节将简要介绍导致Transformers的自然语言处理背景,我们将在第二章中更详细地描述这一点,开始使用Transformers模型的架构。然而,首先,让我们直观地看一下Transformers的注意头,它取代了自然语言处理神经网络的 RNN 层。

Transformers的核心概念可以粗略地总结为“混合标记”。自然语言处理模型首先将单词序列转换为标记。循环神经网络在递归函数中分析标记。Transformers不会按顺序分析标记,而是将每个标记与序列中的其他标记相关联,如图 1.3所示:

图 1.3:Transformers层的一个注意头

我们将在第二章详细讨论一个注意力头的细节。目前,图 1.3的要点是序列的每个单词(标记)都与序列的所有其他单词相关。这个模型为工业 4.0 的自然语言处理打开了大门。

让我们简要地了解一下Transformers的背景。

Transformers的背景

在过去的 100 多年里,许多伟大的思想家都致力于序列模式和语言建模。因此,机器逐渐学会了预测可能的单词序列。要列出所有使这一切发生的巨人,需要一整本书。

在本节中,我将与您分享一些我喜欢的研究人员,为Transformers的到来奠定基础。

在 20 世纪初,安德烈·马尔可夫介绍了随机值的概念,并创建了随机过程的理论。我们在人工智能中称之为马尔可夫决策过程(MDP)、马尔可夫链和马尔可夫过程。在 20 世纪初,马尔可夫证明了我们可以仅使用链的最后几个元素来预测链、序列的下一个元素。他将自己的方法应用到一个包含数千封信的数据集中,使用过去的序列来预测句子的后续字母。请记住,他没有计算机,但证明了一种至今在人工智能中仍在使用的理论。

1948 年,克劳德·香农出版了通信的数学理论。克劳德·香农奠定了基于源编码器、传输器和接收器或语义解码器的通信模型的基础。他创造了今天我们所知的信息论。

1950 年,艾伦·图灵发表了他的里程碑文章:计算机与智能。艾伦·图灵将这篇文章基于在二战期间解密德国消息的成功图灵机的机器智能。这些消息由一系列单词和数字组成。

1954 年,乔治城-IBM 实验使用计算机利用规则系统将俄语句子翻译成英语。 规则系统是一个运行规则列表的程序,该列表将分析语言结构。 规则系统仍然存在,并且无处不在。 但是,在某些情况下,机器智能可以通过自动学习模式来替代数十亿种语言组合的规则列表。

1956 年,约翰·麦卡锡首次使用了“人工智能”这个表达,当时确立了机器可以学习的事实。

1982 年,约翰·霍普菲尔德引入了一种称为霍普菲尔德网络或“联想”神经网络的循环神经网络(RNN)。 约翰·霍普菲尔德受到 W.A. Little 的启发,后者在 1974 年撰写了大脑中持久状态的存在,为学习过程奠定了几十年的理论基础。 RNN 不断发展,以及我们今天所知的 LSTM 也随之出现。

RNN 高效地记忆了序列的持久状态,如图 1.4所示:

图 1.4:RNN 过程

每个状态 Sₙ 捕获 S[n-1] 的信息。 当网络的末端到达时,函数 F 将执行一个动作:转换、建模或任何其他类型的基于序列的任务。

在 1980 年代,Yann LeCun 设计了多功能的卷积神经网络(CNN)。 他将 CNN 应用于文本序列,它们还适用于序列转换和建模。 它们还基于 W.A. Little 的持久状态,该状态逐层处理信息。 在 1990 年代,总结了几年的工作后,Yann LeCun 制作了 LeNet-5,导致了我们今天所知道的许多 CNN 模型。 但是,在处理冗长且复杂序列中的长期依赖关系时,CNN 的有效架构面临问题。

我们可以提到许多其他的名字、论文和模型,这些都会让任何 AI 专家感到自愧不如。 AI 领域的每个人似乎都走在正确的轨道上。 马尔可夫场、RNN 和 CNN 发展成了多种其他模型。 注意力的概念出现了:窥视序列中的其他令牌,而不仅仅是最后一个。 它被添加到了 RNN 和 CNN 模型中。

之后,如果 AI 模型需要分析需要增加计算机功率的更长序列,AI 开发人员使用了更强大的机器,并找到了优化梯度的方法。

对于序列到序列模型进行了一些研究,但并未达到预期。

看起来似乎没有其他方法可以取得更多进展。 这样过了三十年。 然后,从 2017 年末开始,工业化的最先进的 Transformer 带来了它的注意力头子层等等。 RNN 不再被视为序列建模的先决条件。

在深入研究原始 Transformer 的架构之前,我们将在 第二章,开始使用 Transformer 模型的架构 中进行。让我们从高层次上审视一下学习和实现 transformer 模型应该使用的软件资源的范式变化。

我们应该使用什么资源?

工业 4.0 AI 已经模糊了云平台、框架、库、语言和模型之间的界限。Transformer 是新的,生态系统的范围和数量令人惊叹。Google Cloud 提供了可直接使用的 transformer 模型。

OpenAI 部署了一个几乎不需要编程的“Transformer” API。Hugging Face 提供了一个云库服务,列表是无穷无尽的。

本章将对我们将在本书中实施的一些 transformer 生态系统进行高层次的分析。

你选择的资源来实现 NLP 的 transformer 是至关重要的。这是一个在项目中生存的问题。想象一下现实生活中的面试或演示。想象一下你正在与你的未来雇主、你的雇主、你的团队或一个客户交谈。

你以一个出色的 PowerPoint 开始你的演示,比如说使用 Hugging Face。例如。 你可能会从一个经理那里得到一个负面的反应,他可能会说:“对不起,但是我们在这种类型的项目中使用的是 Google Trax,而不是 Hugging Face。你能实现 Google Trax 吗?” 如果你不这样做,那么游戏结束了。

专门从事 Google Trax 可能会出现同样的问题。但是,相反,你可能会得到一个希望使用 OpenAI 的 GPT-3 引擎和 API 而不进行开发的经理的反应。如果你专门使用 OpenAI 的 GPT-3 引擎和 API 而不进行开发,你可能会面临一个希望使用 Hugging Face 的 AutoML API 的项目经理或客户。最糟糕的事情是,一个经理接受了你的解决方案,但最终它根本不适用于该项目的 NLP 任务。

要牢记的关键概念是,如果你只关注你喜欢的解决方案,你很可能最终会随着船沉没。

关注你需要的系统,而不是你喜欢的那个。

这本书并不是为了解释市场上存在的每一个 transformer 解决方案。相反,这本书旨在为您解释足够的 transformer 生态系统,以便您能够灵活地适应您在 NLP 项目中面临的任何情况。

在本节中,我们将介绍您将面临的一些挑战。但首先,让我们从 API 开始。

Transformer 4.0 无缝 API 的崛起

我们现在已经深入到人工智能的工业化时代。微软、谷歌、亚马逊网络服务(AWS)和 IBM 等公司提供的 AI 服务,没有任何开发人员或开发团队能够超越。科技巨头拥有百万美元的超级计算机,用于训练 transformer 模型和 AI 模型的大数据集。

大型科技巨头拥有广泛的企业客户群体,已经使用他们的云服务。因此,将Transformers API 添加到现有的云架构中所需的工作量比任何其他解决方案都要少。

一个小公司甚至一个个人都可以通过 API 访问最强大的Transformers模型,几乎不需要投资于开发。一名实习生可以在几天内实现 API。对于这样简单的实现,不需要成为工程师或拥有博士学位。

例如,OpenAI 平台现在为市场上一些最有效的Transformers模型提供 SaaS (软件即服务) API。

OpenAI Transformers模型如此有效且人性化,以至于目前的政策要求潜在用户填写请求表格。一旦请求被接受,用户就可以访问自然语言处理的宇宙!

OpenAI 的 API 的简单性令用户感到惊讶:

  1. 一键获取 API 密钥

  2. 在笔记本中导入 OpenAI 只需一行

  3. 在 提示 中输入您希望的任何 NLP 任务

  4. 您将以一定数量的 令牌(长度)作为 完成 收到响应

就是这样!欢迎来到第四次工业革命和 AI 4.0!

专注于仅代码解决方案的工业 3.0 开发者将进化为具有跨学科思维的工业 4.0 开发者。

4.0 开发者将学习如何设计一种方式来 展示 Transformers模型期望的内容,而不是像 3.0 开发者那样直观地 告诉 它要做什么。我们将通过 第七章,GPT-3 引擎崛起的超人类Transformers 来探讨这种新方法。

AllenNLP 提供免费使用在线教育界面的Transformers。AllenNLP 还提供一个可以安装在笔记本中的库。例如,假设我们被要求实现共指消解。我们可以从在线运行示例开始。

共指消解任务涉及找到一个词所指的实体,就像在 图 1.5 中所示的句子中那样。

图 1.5:在线运行 NLP 任务

“它” 这个词可能指的是网站或Transformers模型。在这种情况下,类似 BERT 的模型决定将 “it” 链接到Transformers模型。AllenNLP 提供了格式化的输出,如 图 1.6 所示:

图 1.6:AllenNLP Transformers模型的输出

此示例可以在 demo.allennlp.org/coreference-resolution 上运行。Transformers模型不断更新,因此您可能会获得不同的结果。

虽然 API 可能满足许多需求,但它们也有限制。一个多用途的 API 可能在所有任务中都相当不错,但对于特定的 NLP 任务来说并不够好。使用Transformers进行翻译并不是一件容易的事情。在这种情况下,4.0 开发者、顾问或项目经理将不得不证明仅靠 API 无法解决所需的特定 NLP 任务。我们需要寻找一个可靠的库。

选择现成的 API 驱动库

在本书中,我们将探索几个库。例如,Google 在世界上拥有一些最先进的人工智能实验室。Google Trax 可以在 Google Colab 中只需几行代码进行安装。你可以选择免费或付费服务。我们可以获得源代码,调整模型,甚至在我们自己的服务器或谷歌云上进行训练。例如,从使用现成的 API 到为翻译任务定制转换器模型是一个逐步进行的过程。

但是,在某些情况下,这可能既具有教育意义,又彰显效果。我们将探索 Google 在翻译方面的最新发展,并在第六章《使用 Transformer 进行机器翻译》中实施 Google Trax。

我们已经看到像 OpenAI 这样的 API 需要有限的开发者技能,而像 Google Trax 这样的库则更深入地涉及代码。这两种方法表明,AI 4.0 API 将需要更多的开发,但在实施转换器时需要更少的工作。

其中应用了转换器的最著名的线上应用之一,除其他算法之外,就是 Google 翻译。Google 翻译可以在线使用,也可以通过 API 使用。

让我们尝试使用 Google 翻译将一个需要指代消解的句子从英语翻译成法语:

图 1.7:利用 Google 翻译进行指代消解的翻译

Google 翻译似乎已经解决了指代消解的问题,但是法语中的 transformateur 这个词是指电器设备。transformer 这个词是法语中的一个新词。在某些项目中可能需要人工智能专家具有语言和语言学技能。这种情况下并不需要进行重大开发。但是,在请求翻译之前,项目可能需要澄清输入。

这个例子表明,你可能需要与语言学家合作或者获取语言学技能来处理输入上下文。此外,可能需要进行大量开发来为上下文增加一个界面。

因此,我们可能仍然需要费一些力气才能使用 Google 翻译添加脚本。或者我们可能需要为特定的翻译需求找到一个转换器模型,比如 BERT、T5 或我们在本书中将要探索的其他模型。

随着解决方案范围的不断增加,选择一个模型并不是一件容易的事情。

选择一个转换器模型

大型科技公司主导着自然语言处理(NLP)市场。仅有谷歌、Facebook 和微软每天运行数十亿次 NLP 例程,增强了它们的人工智能模型无与伦比的力量。这些巨头现在提供了各种转换器模型,并拥有顶尖的基础模型。

然而,更小的公司看到庞大的自然语言处理市场后也加入了竞争。Hugging Face 现在也有免费或付费的服务方式。Hugging Face 要达到通过投入数十亿美元进入 Google 研究实验室和微软资助 OpenAI 而获得的效率水平将是一个挑战。基础模型的入口是在超级计算机上完全训练的Transformers,如 GPT-3 或 Google BERT。

Hugging Face 采取了不同的方法,为任务提供了广泛的Transformers模型选择,这是一种有趣的哲学。Hugging Face 提供灵活的模型。此外,Hugging Face 还提供高级 API 和开发者可控的 API。我们将在本书的几个章节中探讨 Hugging Face 作为一个教育工具和可能的特定任务解决方案。

然而,OpenAI 已经专注于全球最强大的少数几个Transformers引擎,并且可以以人类水平执行许多自然语言处理任务。我们将展示 OpenAI 的 GPT-3 引擎的威力在 第七章,GPT-3 引擎崛起 中。

这些相反而经常冲突的策略给我们留下了一系列可能的实现方案。因此,我们必须定义工业 4.0 人工智能专家的角色。

工业 4.0 人工智能专家的角色

工业 4.0 正将所有事物与所有事物连接起来,无处不在。机器直接与其他机器通信。由人工智能驱动的物联网信号触发自动决策,无需人类干预。自然语言处理算法发送自动报告、摘要、电子邮件、广告等。

人工智能专家将不得不适应这个新时代日益自动化的任务,包括Transformers模型的实现。人工智能专家将有新的功能。如果我们按照一个人工智能专家将要执行的Transformers自然语言处理任务列出来,从头到尾,似乎一些高级任务不需要人工智能专家做任何开发。一个人工智能专家可以成为一个人工智能大师,提供设计思路、解释和实现。

Transformers对于人工智能专家的实际定义将随着生态系统的变化而变化。

让我们通过一些例子来说明:

  • API:OpenAI API 不需要一个 AI 开发者。一个网页设计师可以创建一个表单,一个语言学家或者专业领域专家(SME)可以准备提示输入文本。一个 AI 专家的主要角色将需要语言学技能来向 GPT-3 引擎展示如何完成任务,而不仅仅是告诉它们。例如,展示涉及处理输入的上下文。这个新任务被称为 提示工程。提示工程师 在人工智能领域有着很好的发展前景!

  • Library:Google Trax 库需要一定量的开发工作才能开始使用预先训练好的模型。一个精通语言学和自然语言处理任务的 AI 专家可以处理数据集和输出。

  • 训练和调优:一些 Hugging Face 功能需要有限的开发量,提供 API 和库。然而,在某些情况下,我们仍然需要细致入微。在这种情况下,训练、调优模型和找到正确的超参数将需要人工智能专家的专业知识。

  • 开发级技能:在一些项目中,分词器和数据集不匹配,正如第九章中所解释的那样,匹配分词器和数据集。在这种情况下,与语言学家一起工作的人工智能开发人员可以发挥关键作用。因此,在这个层面上,计算语言学培训非常有用。

最近 NLP AI 的演进可以称为“嵌入式转换器”,正在扰乱 AI 开发生态系统:

  • GPT-3 转换器目前嵌入在几个 Microsoft Azure 应用程序中,例如 GitHub Copilot。正如本章节基础模型部分中所介绍的那样,Codex 是我们将在第十六章中探讨的另一个例子,基于转换器的合作者的出现。

  • 嵌入式转换器不能直接访问,但提供自动开发支持,如自动代码生成。

  • 嵌入式转换器的使用对于最终用户来说是无缝的,辅助文本自动完成。

要直接访问 GPT-3 引擎,您必须首先创建一个 OpenAI 账户。然后您可以使用 API 或直接在 OpenAI 用户界面中运行示例。

我们将在第十六章中探索这个迷人的嵌入式转换器的新世界。但要充分利用该章节,您首先应该掌握前几章的概念、示例和程序。

工业 4.0 AI 专家的技能需要灵活性、跨学科知识,尤其是灵活性。本书将为人工智能专家提供各种转换器生态系统,以适应市场的新模式。

在潜入原始 Transformer 的迷人架构之前,现在是总结本章思想的时候了。

摘要

第四次工业革命,或工业 4.0,迫使人工智能发生深刻的演变。第三次工业革命是数字化的。工业 4.0 建立在数字革命的基础上,将一切与一切、无处不在的连接起来。自动化流程正在取代人类在重要领域的决策,包括 NLP。

RNN 存在限制,这些限制减缓了在快速移动世界中所需的自动化 NLP 任务的进展。转换器填补了这一空白。一个公司需要摘要、翻译和各种 NLP 工具来应对工业 4.0 的挑战。

因此,工业 4.0(I4.0)推动了人工智能产业化的时代。平台、框架、语言和模型概念的演进对工业 4.0 开发者构成了挑战。基础模型通过提供可以在没有进一步训练或微调的情况下执行各种任务的同质模型,弥合了第三次工业革命和 I4.0 之间的差距。

例如,AllenNLP 等网站提供了不需要安装的教育性 NLP 任务,但它也提供了在定制程序中实现转换器模型的资源。OpenAI 提供了一个 API,只需几行代码就可以运行强大的 GPT-3 引擎之一。Google Trax 提供了一个端到端库,Hugging Face 提供了各种转换器模型和实现。我们将在本书中探索这些生态系统。

工业 4.0 是与以前的人工智能的根本偏差,具有更广泛的技能集。例如,项目经理可以决定通过询问网页设计师创建一个接口来实现转换器的项目,通过提示工程来实现 OpenAI 的 API。或者,在必要时,项目经理可以要求人工智能专家下载 Google Trax 或 Hugging Face 来开发一个完整的项目,并使用定制的转换器模型。

工业 4.0 对开发者来说是一个改变游戏规则的因素,他们的角色将会扩展,并且需要更多的设计而不是编程。此外,嵌入式转换器将提供辅助代码开发和使用。这些新的技能集是一个挑战,但也打开了新的激动人心的视野。

在第二章中,开始使用 Transformer 模型的架构,我们将开始使用原始 Transformer 的架构。

问题

  1. 我们仍处于第三次工业革命中。(True/False)

  2. 第四次工业革命正在将一切连接到一切。(True/False)

  3. 工业 4.0 开发者有时不需要进行 AI 开发。(True/False)

  4. 工业 4.0 开发者可能需要从零开始实现转换器。(True/False)

  5. 没有必要学习超过一个转换器生态系统,例如 Hugging Face。(True/False)

  6. 一个即用型的转换器 API 可以满足所有需求。(True/False)

  7. 公司将接受开发者最擅长的转换器生态系统。(True/False)

  8. 云转换器已经成为主流。(True/False)

  9. 一个转换器项目可以在笔记本电脑上运行。(True/False)

  10. 工业 4.0 人工智能专家将不得不更加灵活(True/False)

参考资料

加入我们书籍的 Discord 空间

参加书籍的 Discord 工作区,与作者进行每月的问我任何(Ask me Anything)的交流活动:

www.packt.link/Transformers

第二章:起步使用 Transformer 模型的架构

语言是人类交流的本质。如果没有形成语言的词序列,文明将永远不会诞生。现在,我们大多生活在语言的数字表示世界中。我们的日常生活依赖于 NLP 数字化语言功能:网络搜索引擎、电子邮件、社交网络、帖子、推文、智能手机短信、翻译、网页、流媒体网站上的语音转文字、热线服务上的文字转语音以及许多其他日常功能。

第一章,什么是 Transformer?,解释了 RNN 的局限性以及云 AI 转换器的诞生,占据了设计和开发的一部分份额。工业 4.0 开发者的角色是理解原始 Transformer 的架构以及随之而来的多个 transformer 生态系统。

2017 年 12 月,Google Brain 和 Google Research 发表了具有开创性意义的瓦斯瓦尼等人的Attention is All You Need论文。Transformer 诞生了。Transformer 超越了现有的最先进的 NLP 模型。Transformer 比以前的架构训练速度更快,并获得了更高的评估结果。因此,transformer 已成为 NLP 的关键组成部分。

Transformer 的注意头的思想是消除循环神经网络特征。在本章中,我们将揭开瓦斯瓦尼等人(2017)描述的 Transformer 模型的面纱,检查其架构的主要组件。我们将探索引人入胜的关注世界,并说明 Transformer 的关键组件。

本章涵盖以下主题:

  • Transformer 的架构

  • Transformer 的自注意力模型

  • 编码和解码堆栈

  • 输入和输出嵌入

  • 位置嵌入

  • 自注意力

  • 多头注意力

  • 掩模多头注意力

  • 残差连接

  • 规范化

  • 前馈网络

  • 输出概率

让我们直接深入原始 Transformer 架构的结构。

Transformer 的崛起:Attention is All You Need

2017 年 12 月,瓦斯瓦尼等人(2017)发表了他们具有开创性意义的论文Attention is All You Need。他们在 Google Research 和 Google Brain 进行了这项工作。在本章和本书中,我将称Attention is All You Need中描述的模型为“原始 Transformer 模型”。

附录 I,Transformer 模型术语,可以帮助从深度学习词汇的经典用法过渡到 Transformer 词汇。附录 I总结了经典人工智能神经网络模型的一些变化。

在本节中,我们将看一下他们构建的 Transformer 模型的结构。在接下来的章节中,我们将探讨模型的每个组件内部的内容。

原始的 Transformer 模型是一个包含 6 个层叠的堆栈。第l层的输出是第l+1 层的输入,直到达到最终预测。左侧有一个 6 层编码器堆栈,右侧有一个 6 层解码器堆栈:

图 2.1:Transformer 的架构

在左侧,输入通过一个注意力子层和一个前馈子层进入 Transformer 的编码器侧。在右侧,目标输出通过两个注意力子层和一个前馈网络子层进入 Transformer 的解码器侧。我们立即注意到这个架构中没有 RNN、LSTM 或 CNN。在这种架构中已经放弃了循环。

注意力已经取代了需要随着两个单词之间距离增加而增加的循环函数。注意力机制是一种“单词对单词”的操作。实际上它是一个标记到标记的操作,但为了保持解释简单,我们将其保持在单词级别上。注意力机制将找到每个单词与序列中所有其他单词的关系,包括正在分析的单词本身。让我们来看一下以下序列:

The cat sat on the mat. 

注意力将在单词向量之间运行点积,并确定一个单词与所有其他单词(包括自己)的最强关系(“猫”和“猫”):

图 2.2:关注所有单词

注意机制将提供单词之间更深的关系并产生更好的结果。

对于每个注意子层,原始的 Transformer 模型不是运行一个而是运行八个并行的注意机制以加快计算速度。我们将在下一节“编码器堆栈”中探讨这种架构。这个过程被称为“多头注意力”,提供:

  • 对序列的更广泛的深入分析

  • 排除了减少计算操作的循环先验

  • 并行化的实现,可以减少训练时间

  • 每个注意机制学习相同输入序列的不同视角

注意力取代了循环。然而,Transformer 还有其他几个创造性方面,它们和注意力机制一样关键,当我们深入研究架构时,你将会看到。

我们刚刚从外部看了 Transformer 的结构。现在让我们深入了解 Transformer 的每个组件。我们将从编码器开始。

编码器堆栈

原始 Transformer 模型的编码器和解码器的层都是层叠的层。编码器堆栈的每一层都有以下结构:

图 2.3:Transformer 编码器堆栈的一层

原始编码器层结构对于 Transformer 模型的所有N=6 层保持不变。每一层包含两个主要的子层:一个多头注意力机制和一个完全连接的位置逐层前馈网络。

请注意,在 Transformer 模型中,每个主要子层子层(x)周围都有一个残差连接。这些连接将子层的未处理输入x传输到层标准化函数。这样,我们可以确定诸如位置编码之类的关键信息在传输过程中不会丢失。因此,每层的标准化输出如下:

层标准化 (x + 子层(x))

尽管编码器的N=6 层的结构是相同的,但每层的内容并不严格与上一层相同。

例如,嵌入子层仅出现在堆栈的底层。其他五层不包含嵌入层,这保证了经过所有层的编码输入是稳定的。

此外,多头注意力机制从第 1 层到第 6 层执行相同的功能。但它们并不执行相同的任务。每一层都从前一层学习,并探索关联序列中标记的不同方式。它寻找单词的不同关联,就像我们在解决填字游戏时寻找字母和单词的不同关联一样。

Transformer 的设计者引入了一个非常高效的约束。模型的每个子层的输出都具有恒定的维度,包括嵌入层和残差连接。该维度为d[model],可以根据您的目标设置为另一个值。在原始的 Transformer 架构中,d[model] = 512。

d[model]具有强大的影响。几乎所有关键操作都是点积。因此,维度保持稳定,这减少了计算操作的数量,减少了机器的消耗,并使跟踪信息在模型中流动变得更容易。

编码器的这个全局视图展示了 Transformer 的高度优化的架构。在接下来的几节中,我们将深入研究每个子层和机制。

我们将从嵌入子层开始。

输入嵌入

输入嵌入子层使用原始 Transformer 模型中学习的嵌入将输入标记转换为维度为d[model] = 512 的向量。输入嵌入的结构是经典的:

图 2.4:Transformer 的输入嵌入子层

嵌入子层的工作方式类似于其他标准的转换模型。标记器将一个句子转换为标记。每个标记器都有其方法,如 BPE、单词片段和句子片段方法。Transformer 最初使用了 BPE,但其他模型使用其他方法。

目标是相似的,选择取决于选择的策略。例如,应用于序列 Transformer is an innovative NLP model!的标记器将在一种模型中产生以下标记:

['the', 'transform', 'er', 'is', 'an', 'innovative', 'n', 'l', 'p', 'model', '!'] 

您会注意到这个分词器将字符串标准化为小写字母并将其截断为子部分。分词器通常会提供一个用于嵌入过程的整数表示。例如:

text = "The cat slept on the couch.It was too tired to get up."
tokenized text= [1996, 4937, 7771, 2006, 1996, 6411, 1012, 2009, 2001, 2205, 5458, 2000, 2131, 2039, 1012] 

此时,标记化文本中没有足够的信息进行更深入的分析。标记化文本必须被嵌入。

Transformer 包含了一个学习到的嵌入子层。许多嵌入方法可以应用到标记化的输入中。

我选择了word2vec嵌入方法中谷歌在 2013 年发布的 skip-gram 架构来说明 Transformer 的嵌入子层。skip-gram 会关注窗口中的中心词,并预测上下文词。例如,如果 word(i)是一个两步窗口中的中心词,skip-gram 模型会分析 word(i-2),word(i-1),word(i+1),和 word(i+2)。然后窗口会滑动并重复这个过程。skip-gram 模型通常包含输入层,权重,隐藏层,以及包含标记化输入词的词嵌入的输出。

假设我们需要为以下句子进行嵌入:

The black cat sat on the couch and the brown dog slept on the rug. 

我们将专注于两个词,black和brown。这两个词的词嵌入向量应该是相似的。

由于我们必须为每个词生成一个大小为d[model] = 512 的向量,我们将为每个词获得大小为512的向量嵌入:

black=[[-0.01206071  0.11632373  0.06206119  0.01403395  0.09541149  0.10695464 0.02560172  0.00185677 -0.04284821  0.06146432  0.09466285  0.04642421 0.08680347  0.05684567 -0.00717266 -0.03163519  0.03292002 -0.11397766 0.01304929  0.01964396  0.01902409  0.02831945  0.05870414  0.03390711 -0.06204525  0.06173197 -0.08613958 -0.04654748  0.02728105 -0.07830904
    …
0.04340003 -0.13192849 -0.00945092 -0.00835463 -0.06487109  0.05862355 -0.03407936 -0.00059001 -0.01640179  0.04123065 
-0.04756588  0.08812257 0.00200338 -0.0931043  -0.03507337  0.02153351 -0.02621627 -0.02492662 -0.05771535 -0.01164199 
-0.03879078 -0.05506947  0.01693138 -0.04124579 -0.03779858 
-0.01950983 -0.05398201  0.07582296  0.00038318 -0.04639162 
-0.06819214  0.01366171  0.01411388  0.00853774  0.02183574 
-0.03016279 -0.03184025 -0.04273562]] 

单词black现在用512维度表示。其他嵌入方法可以被使用,d[model]可以有更多维度。

brown的词嵌入也用512维度表示:

brown=[[ 1.35794589e-02 -2.18823571e-02  1.34526128e-02  6.74355254e-02
   1.04376070e-01  1.09921647e-02 -5.46298288e-02 -1.18385479e-02
   4.41223830e-02 -1.84863899e-02 -6.84073642e-02  3.21860164e-02
   4.09143828e-02 -2.74433400e-02 -2.47369967e-02  7.74542615e-02
   9.80964210e-03  2.94299088e-02  2.93895267e-02 -3.29437815e-02
…
  7.20389187e-02  1.57317147e-02 -3.10291946e-02 -5.51304631e-02
  -7.03861639e-02  7.40829483e-02  1.04319192e-02 -2.01565702e-03
   2.43322570e-02  1.92969330e-02  2.57341694e-02 -1.13280728e-01
   8.45847875e-02  4.90090018e-03  5.33546880e-02 -2.31553353e-02
   3.87288055e-05  3.31782512e-02 -4.00604047e-02 -1.02028981e-01
   3.49597558e-02 -1.71501152e-02  3.55573371e-02 -1.77437533e-02
  -5.94457164e-02  2.21221056e-02  9.73121971e-02 -4.90022525e-02]] 

为了验证这两个词产生的词嵌入,我们可以使用余弦相似度来查看单词black和brown的词嵌入是否相似。

余弦相似度使用欧几里得(L2)范数在一个单位球中创建向量。我们比较的向量的点积是这两个向量之间的余弦。更多关于余弦相似度理论的内容,您可以查阅 scikit-learn 的文档,以及其他很多来源:scikit-learn.org/stable/modules/metrics.html#cosine-similarity。

在示例的嵌入中,大小为d[model] = 512 的黑色向量与大小为d[model] = 512 的棕色向量之间的余弦相似度是:

cosine_similarity(black, brown)= [[0.9998901]] 

skip-gram 产生了两个彼此接近的向量。它检测到 black 和 brown 形成了一个颜色子集的词典。

Transformer 的后续层并不是空手起步。它们已经学会了词嵌入,这些词嵌入已经提供了有关如何关联这些词的信息。

然而,由于没有额外的向量或信息指示序列中单词的位置,很多信息都缺失了。

Transformer 的设计者提出了另一个创新特性:位置编码。

让我们看看位置编码是如何工作的。

位置编码

我们进入 Transformer 的这个位置编码函数时并不知道词在序列中的位置:

图 2.5:位置编码

我们不能创建独立的位置向量,这将对 Transformer 的训练速度产生较高的成本,并使注意力子层过于复杂。这个想法是向输入嵌入中添加一个位置编码值,而不是添加额外的向量来描述序列中一个标记的位置。

工业 4.0 是实用的,且不受模型限制。原始 Transformer 模型只有一个包含词嵌入和位置编码的向量。我们将在 第十五章,从自然语言处理到任务不可知的 Transformer 模型 中探索使用一个独立的矩阵来进行位置编码的分离注意力。

Transformer 期望输出的每个向量都具有固定大小 d[model] = 512(或模型的其他常量值)。

如果我们回到我们在词嵌入子层中使用的句子,我们可以看到黑色和棕色可能在语义上相似,但在句子中相距甚远:

The `black` cat sat on the couch and the `brown` dog slept on the rug. 

单词 black 处于位置 2,pos=2,而单词 brown 处于位置 10,pos=10。

我们的问题是找到一种方法,向每个单词的词嵌入中添加一个值,以便它具有该信息。但是,我们需要向 d[model] = 512 维度添加一个值!对于每个单词嵌入向量,我们需要找到一种方法,为 black 和 brown 的词嵌入向量的 range(0,512) 维度中的 i 提供信息。

有许多方法可以实现位置编码。本节将重点介绍设计者巧妙地使用单位球来表示位置编码,使用正弦和余弦值,因此保持小但有用。

Vaswani 等人(2017 年)提供了正弦和余弦函数,以便我们可以为每个位置和 d[model] = 512 的词嵌入向量的每个维度 i 生成不同的频率来生成位置编码 (PE):

如果我们从词嵌入向量的开头开始,我们将从一个常数开始 (512),i=0,并以 i=511 结束。这意味着正弦函数将应用于偶数,余弦函数将应用于奇数。一些实现方式可能不同。在这种情况下,正弦函数的定义域可能是i ∈ [0,255],余弦函数的定义域可能是i ∈ [256,512]。这将产生类似的结果。

在本节中,我们将使用 Vaswani 等人(2017 年)描述的函数方式。将其直译为 Python 伪代码产生了以下代码,用于表示位置向量 pe[0][i] 的位置 pos:

def positional_encoding(pos,pe):
for i in range(0, 512,2):
         pe[0][i] = math.sin(pos / (10000 ** ((2 * i)/d_model)))
         pe[0][i+1] = math.cos(pos / (10000 ** ((2 * i)/d_model)))
return pe 

Google Brain Trax 和 Hugging Face 等公司提供了用于单词嵌入部分和现在位置编码部分的即用型库。因此,你不需要运行我在本节中分享的代码。但是,如果你想探索代码,你可以在 Google Colaboratory 的 positional_encoding.ipynb 笔记本和本章的 GitHub 仓库中的 text.txt 文件中找到它。

在继续之前,你可能想看一下正弦函数的图表,例如 pos=2。

例如,你可以谷歌以下图表:

plot y=sin(2/10000^(2*x/512)) 

只需输入绘图请求:

图 2.6:使用 Google 绘图

你将获得以下图表:

图 2.7:图

如果我们回到这一部分正在解析的句子,我们可以看到 black 位于位置 pos=2,而 brown 位于位置 pos=10:

The black cat sat on the couch and the brown dog slept on the rug. 

如果我们将正弦和余弦函数直接应用于 pos=2,我们将获得大小为512的位置编码向量:

PE(2)= 
[[ 9.09297407e-01 -4.16146845e-01  9.58144367e-01 -2.86285430e-01
   9.87046242e-01 -1.60435960e-01  9.99164224e-01 -4.08766568e-02
   9.97479975e-01  7.09482506e-02  9.84703004e-01  1.74241230e-01
   9.63226616e-01  2.68690288e-01  9.35118318e-01  3.54335666e-01
   9.02130723e-01  4.31462824e-01  8.65725577e-01  5.00518918e-01
   8.27103794e-01  5.62049210e-01  7.87237823e-01  6.16649508e-01
   7.46903539e-01  6.64932430e-01  7.06710517e-01  7.07502782e-01
…
   5.47683925e-08  1.00000000e+00  5.09659337e-08  1.00000000e+00
   4.74274735e-08  1.00000000e+00  4.41346799e-08  1.00000000e+00
   4.10704999e-08  1.00000000e+00  3.82190599e-08  1.00000000e+00
   3.55655878e-08  1.00000000e+00  3.30963417e-08  1.00000000e+00
   3.07985317e-08  1.00000000e+00  2.86602511e-08  1.00000000e+00
   2.66704294e-08  1.00000000e+00  2.48187551e-08  1.00000000e+00
   2.30956392e-08  1.00000000e+00  2.14921574e-08  1.00000000e+00]] 

我们还为位置 10 获得了大小为512的位置编码向量,pos=10:

PE(10)= 
[[-5.44021130e-01 -8.39071512e-01  1.18776485e-01 -9.92920995e-01
   6.92634165e-01 -7.21289039e-01  9.79174793e-01 -2.03019097e-01
   9.37632740e-01  3.47627431e-01  6.40478015e-01  7.67976522e-01
   2.09077001e-01  9.77899194e-01 -2.37917677e-01  9.71285343e-01
  -6.12936735e-01  7.90131986e-01 -8.67519796e-01  4.97402608e-01
  -9.87655997e-01  1.56638563e-01 -9.83699203e-01 -1.79821849e-01
…
  2.73841977e-07  1.00000000e+00  2.54829672e-07  1.00000000e+00
   2.37137371e-07  1.00000000e+00  2.20673414e-07  1.00000000e+00
   2.05352507e-07  1.00000000e+00  1.91095296e-07  1.00000000e+00
   1.77827943e-07  1.00000000e+00  1.65481708e-07  1.00000000e+00
   1.53992659e-07  1.00000000e+00  1.43301250e-07  1.00000000e+00
   1.33352145e-07  1.00000000e+00  1.24093773e-07  1.00000000e+00
   1.15478201e-07  1.00000000e+00  1.07460785e-07  1.00000000e+00]] 

当我们直观地将 Vaswani 等人(2017 年)的函数翻译成 Python 并查看结果时,我们希望检查结果是否有意义。

用于单词嵌入的余弦相似度函数对于更好地可视化位置的接近度非常方便:

cosine_similarity(pos(2), pos(10))= [[0.8600013]] 

单词 black 和 brown 的位置之间的相似度以及词汇领域(一起使用的单词组)的相似度是不同的:

cosine_similarity(black, brown)= [[0.9998901]] 

位置的编码显示出比单词嵌入相似度更低的相似度值。

位置编码已经将这些词分开。请记住,单词嵌入会随用于训练它们的语料库而变化。现在的问题是如何将位置编码添加到单词嵌入向量中。

将位置编码添加到嵌入向量中

Transformer 的作者们发现了一种简单的方法,只需将位置编码向量简单地添加到单词嵌入向量中:

图 2.8:位置编码

如果我们回过头来,例如,提取 black 的单词嵌入,然后将其命名为 y[1] = black,我们就可以将其添加到通过位置编码函数获得的位置向量 pe(2)中。我们将获得输入单词 black 的位置编码 pc(black):

pc(black) = y[1] + pe(2)

解决方案很简单。然而,如果我们按照所示应用它,我们可能会丢失单词嵌入的信息,这将被位置编码向量最小化。

有许多可能性来增加 y[1] 的价值,以确保单词嵌入层的信息可以在后续层中有效使用。

许多可能性之一是向 y[1],即 black 的单词嵌入添加一个任意值:

y[1] * math.sqrt(d_model)

现在我们可以将单词black的位置向量加到其嵌入向量中,它们都是相同的大小(512):

for i in range(0, 512,2):
          pe[0][i] = math.sin(pos / (10000 ** ((2 * i)/d_model)))
          pc[0][i] = (y[0][i]*math.sqrt(d_model))+ pe[0][i]

          pe[0][i+1] = math.cos(pos / (10000 ** ((2 * i)/d_model)))
          pc[0][i+1] = (y[0][i+1]*math.sqrt(d_model))+ pe[0][i+1] 

得到的结果是维度为d[model] = 512*的最终位置编码向量:

pc(black)=
[[ 9.09297407e-01 -4.16146845e-01  9.58144367e-01 -2.86285430e-01
   9.87046242e-01 -1.60435960e-01  9.99164224e-01 -4.08766568e-02
   …
  4.74274735e-08  1.00000000e+00  4.41346799e-08  1.00000000e+00
   4.10704999e-08  1.00000000e+00  3.82190599e-08  1.00000000e+00
   2.66704294e-08  1.00000000e+00  2.48187551e-08  1.00000000e+00
   2.30956392e-08  1.00000000e+00  2.14921574e-08  1.00000000e+00]] 

对单词brown和序列中的所有其他单词应用相同的操作。

我们可以将余弦相似性函数应用于black和brown的位置编码向量:

cosine_similarity(pc(black), pc(brown))= [[0.9627094]] 

现在,通过我们应用的三个表示单词black和brown的余弦相似性函数,我们对位置编码过程有了清晰的认识:

[[0.99987495]] word similarity
[[0.8600013]] positional encoding vector similarity
[[0.9627094]] final positional encoding similarity 

我们看到初始单词嵌入的相似性较高,值为0.99。然后我们看到位置编码向量的位置 2 和 10 使这两个单词的相似性值降低为0.86。

最后,我们将每个单词的单词嵌入向量添加到其相应的位置编码向量中。我们发现,这使得两个单词的余弦相似度为0.96。

每个单词的位置编码现在包含初始单词嵌入信息和位置编码值。

位置编码的输出导致了多头注意力子层。

子层 1:多头注意力

多头注意力子层包含八个头,并带有后层规范化,将在子层输出中添加残差连接并对其进行规范化:

图 2.9:多头注意力子层

本节开始讲解注意力层的架构。接着,以 Python 中的一个小模块实现了多头注意力的示例。最后,描述了后层规范化。

让我们从多头注意力的架构开始。

多头注意力的架构

编码器堆叠的第一层的多头注意力子层的输入是包含每个单词的嵌入和位置编码的向量。堆叠的下一层不会重新开始这些操作。

输入序列每个单词xₙ的向量维度是 d[model] = 512:

pe(xₙ)=[d₁=9.09297407e^-01, d₂=-4.16146845e^-01, .., d[512]=1.00000000e+00]

每个单词xₙ的表示现在已经变成了512维的向量 d[model] = 512。

每个单词都映射到所有其他单词,以确定它在序列中的位置。

在下面的句子中,我们可以看到它可能与序列中的cat和rug相关:

Sequence =The cat sat on the rug and it was dry-cleaned. 

模型将训练以确定it是与cat还是rug相关联。我们可以通过使用当前的512维度训练该模型进行大量的计算。

但是,通过分析一个d[model]块的序列,我们只能得到一个观点。此外,使用现在的512维度将需要相当长的计算时间来找到其他观点。

一个更好的方法是将每个单词xₙ的512维度划分为8个64维度。

然后我们可以并行运行 8 个“头”来加速训练,并获得每个单词如何与另一个相关的 8 个不同表示子空间:

图 2.10:多头表示

现在可以看到有8个并行运行的头。其中一个头可能认为it和cat很合适,另一个认为it和rug很合适,另一个认为rug和dry-cleaned很合适。

每个头的输出是形状为x * d[k]的矩阵Zᵢ。多头注意力输出Z定义为:

Z = (Z₀, Z₁, Z₂, Z₃, Z₄, Z₅, Z₆, Z₇)

然而,Z必须被连接,这样多头子层的输出不是尺寸的序列,而是xm * d[model]矩阵的一行。

在退出多头注意力子层之前,Z的元素被连接:

MultiHead(output) = Concat(Z₀, Z₁, Z₂, Z₃, Z₄, Z₅, Z₆, Z₇) = x,d[model]

请注意,每个头都被连接成一个具有维度d[model] = 512 的z。多头层的输出遵循原始 Transformer 模型的约束。

在注意机制的每个头hₙ内,“单词”矩阵有三种表示:

  • 一个查询矩阵(Q)的维度为d[q] = 64,它寻求所有“单词”矩阵的键-值对。

  • 一个键矩阵(K)的维度为d[k] = 64,它将被训练以提供一个注意力值。

  • 一个值矩阵(V)的维度为d[v] = 64,它将被训练以提供另一个注意力值。

注意力被定义为“缩放点积注意力”,它在下面的方程中表示,我们将Q、K和V代入其中:

所有矩阵都具有相同的维度,这样可以相对简单地使用缩放点积来获得每个头的注意力值,然后连接 8 个头的输出Z。

要获得Q、K和V,我们必须使用它们的权重矩阵Q[w]、K[w]和V[w]训练模型,它们具有d[k] = 64 列和d[model] = 512 行。例如,Q是通过x和Q[w]的点积获得的。Q将具有d[k] = 64 的维度。

您可以修改所有参数,例如层数、头部、d[model]、d[k]和 Transformer 的其他变量,以适应您的模型。本章描述了由Vaswani等人(2017 年)提出的原始 Transformer 参数。在修改或探索其他人设计的原始模型变体之前,了解原始架构是至关重要的。

Google Brain Trax、OpenAI 和 Hugging Face 等提供了可供我们在本书中使用的即用型库。

然而,让我们打开 Transformer 模型的机制,并在 Python 中动手实现来说明我们刚刚探索的架构,以便可视化该模型的代码并用中间图形表示出来。

我们将使用基本的 Python 代码,只用numpy和一个softmax函数在 10 个步骤中运行注意力机制的关键方面。

请记住,工业 4.0 开发者将面临同一算法的多种架构挑战。

现在让我们开始构建我们模型的Step 1以表示输入。

步骤 1:表示输入

将Multi_Head_Attention_Sub_Layer.ipynb保存到你的 Google Drive(确保你有一个 Gmail 帐户),然后在 Google Colaboratory 中打开它。笔记本在本章的 GitHub 存储库中。

我们将从仅使用最小的 Python 函数开始,以低层次理解 Transformer 的工作原理。我们将使用基本代码探索多头注意力子层的内部工作:

import numpy as np
from scipy.special import softmax 

我们正在构建的注意力机制的输入被缩小到d[模型]==4,而不是d[模型]=512。这将输入x的向量维度缩小到d[模型]=4,更容易可视化。

x包含每个具有 4 个维度的3个输入,而不是512个:

print("Step 1: Input : 3 inputs, d_model=4")
x =np.array([[1.0, 0.0, 1.0, 0.0],   # Input 1
             [0.0, 2.0, 0.0, 2.0],   # Input 2
             [1.0, 1.0, 1.0, 1.0]])  # Input 3
print(x) 

输出显示我们有 3 个d[模型]=4 的向量:

Step 1: Input : 3 inputs, d_model=4
[[1\. 0\. 1\. 0.]
 [0\. 2\. 0\. 2.]
 [1\. 1\. 1\. 1.]] 

我们模型的第一步准备好了:

图 2.11:多头注意力子层的输入

现在我们将权重矩阵添加到我们的模型中。

步骤 2:初始化权重矩阵

每个输入都有 3 个权重矩阵:

  • Q[w]用来训练查询

  • K[w]用来训练键

  • V[w]用来训练值

这三个权重矩阵将应用于模型中的所有输入。

Vaswani等人(2017)描述的权重矩阵是d[K]64 维。但是,让我们将矩阵缩小到d[K]3。维度被缩小到3*4权重矩阵以更容易可视化中间结果并与输入x执行点积。

这个教育笔记本中矩阵的大小和形状是任意的。目标是通过注意力机制的整个过程。

三个权重矩阵是从查询权重矩阵开始初始化的:

print("Step 2: weights 3 dimensions x d_model=4")
print("w_query")
w_query =np.array([[1, 0, 1],
                   [1, 0, 0],
                   [0, 0, 1],
                   [0, 1, 1]])
print(w_query) 

输出是w_query权重矩阵:

w_query
[[1 0 1]
 [1 0 0]
 [0 0 1]
 [0 1 1]] 

现在我们将初始化关键权重矩阵:

print("w_key")
w_key =np.array([[0, 0, 1],
                 [1, 1, 0],
                 [0, 1, 0],
                 [1, 1, 0]])
print(w_key) 

输出是关键权重矩阵:

w_key
[[0 0 1]
 [1 1 0]
 [0 1 0]
 [1 1 0]] 

最后,我们初始化值权重矩阵:

print("w_value")
w_value = np.array([[0, 2, 0],
                    [0, 3, 0],
                    [1, 0, 3],
                    [1, 1, 0]])
print(w_value) 

输出是值权重矩阵:

w_value
[[0 2 0]
 [0 3 0]
 [1 0 3]
 [1 1 0]] 

我们模型的第二步准备好了:

图 2.12:添加到模型中的权重矩阵

现在我们将通过输入向量乘以权重矩阵来获得Q、K和V。

步骤 3:矩阵乘法以获得 Q、K 和 V

我们现在将输入向量乘以权重矩阵,以获得每个输入的查询、键和值向量。

在这个模型中,我们假设所有输入都有一个w_query、w_key和w_value权重矩阵。其他方法也是可能的。

让我们首先将输入向量乘以w_query权重矩阵:

print("Step 3: Matrix multiplication to obtain Q,K,V")
print("Query: x * w_query")
Q=np.matmul(x,w_query)
print(Q) 

输出是Q₁==64 的向量=[1, 0, 2],Q₂=[2,2, 2],Q₃=[2,1, 3]:

Step 3: Matrix multiplication to obtain Q,K,V
Query: x * w_query
[[1\. 0\. 2.]
 [2\. 2\. 2.]
 [2\. 1\. 3.]] 

现在我们将输入向量乘以w_key权重矩阵:

print("Key: x * w_key")
K=np.matmul(x,w_key)
print(K) 

我们得到K₁= [0, 1, 1],K₂= [4, 4, 0],以及K₃= [2 ,3, 1]的向量:

Key: x * w_key
[[0\. 1\. 1.]
 [4\. 4\. 0.]
 [2\. 3\. 1.]] 

最后,我们将输入向量乘以w_value权重矩阵:

print("Value: x * w_value")
V=np.matmul(x,w_value)
print(V) 

我们得到V₁= [1, 2, 3],V₂= [2, 8, 0],以及V₃= [2 ,6, 3]的向量:

Value: x * w_value
[[1\. 2\. 3.]
 [2\. 8\. 0.]
 [2\. 6\. 3.]] 

我们模型的第三步准备好了:

图 2.13:生成了Q、K和V

我们有了需要计算注意力分数的Q、K和V值。

步骤 4:缩放注意力分数

注意力头现在实现了原始的 Transformer 方程:

步骤 4 关注Q和K:

对于这个模型,我们将四舍五入√d[k] =√3 = 1.75为 1,并将值代入方程的Q和K部分:

print("Step 4: Scaled Attention Scores")
k_d=1   #square root of k_d=3 rounded down to 1 for this example
attention_scores = (Q @ K.transpose())/k_d
print(attention_scores) 

中间结果显示为:

Step 4: Scaled Attention Scores
[[ 2\.  4\.  4.]
 [ 4\. 16\. 12.]
 [ 4\. 12\. 10.]] 

步骤 4 现在已完成。例如,x₁的分数为[2,4,4]跨越了K向量的头部显示为:

图 2.14:输入#1 的缩放注意力分数

现在注意力方程将为每个向量的中间分数应用 softmax。

步骤 5:每个向量的缩放 softmax 注意力分数

现在我们对每个中间注意力分数应用 softmax 函数。与进行矩阵乘法不同,让我们放大到每个单独的向量:

print("Step 5: Scaled softmax attention_scores for each vector")
attention_scores[0]=softmax(attention_scores[0])
attention_scores[1]=softmax(attention_scores[1])
attention_scores[2]=softmax(attention_scores[2])
print(attention_scores[0])
print(attention_scores[1])
print(attention_scores[2]) 

我们为每个向量得到了缩放的 softmax 注意力分数:

Step 5: Scaled softmax attention_scores for each vector
[0.06337894 0.46831053 0.46831053]
[6.03366485e-06 9.82007865e-01 1.79861014e-02]
[2.95387223e-04 8.80536902e-01 1.19167711e-01] 

步骤 5 现在已完成。例如,所有键的x₁的分数的 softmax 是:

图 2.15:所有键的输入#1 的 softmax 分数

现在我们可以用完整的方程计算最终的注意力值。

步骤 6:最终的注意力表示

现在我们可以通过将V代入来完成注意力方程:

我们首先计算输入x₁对步骤 6 和 7 的注意力分数。我们为一个词向量计算一个注意力值。当我们到达步骤 8 时,我们将将注意力计算推广到另外两个输入向量。

为了获得x₁的 Attention(Q,K,V),我们将中间注意力分数逐个与 3 个值向量相乘,以放大方程的内部工作:

print("Step 6: attention value obtained by score1/k_d * V")
print(V[0])
print(V[1])
print(V[2])
print("Attention 1")
attention1=attention_scores[0].reshape(-1,1)
attention1=attention_scores[0][0]*V[0]
print(attention1)
print("Attention 2")
attention2=attention_scores[0][1]*V[1]
print(attention2)
print("Attention 3")
attention3=attention_scores[0][2]*V[2]
print(attention3)
Step 6: attention value obtained by score1/k_d * V
[1\. 2\. 3.]
[2\. 8\. 0.]
[2\. 6\. 3.]
Attention 1
[0.06337894 0.12675788 0.19013681]
Attention 2
[0.93662106 3.74648425 0\.        ]
Attention 3
[0.93662106 2.80986319 1.40493159] 

步骤 6 完成。例如,已计算了每个输入的x₁的 3 个注意力值:

图 2.16:注意力表示

现在需要将注意力值相加。

步骤 7:将结果求和

输入#1 的 3 个注意力值现在将被求和以获得输出矩阵的第一行:

print("Step 7: summed the results to create the first line of the output matrix")
attention_input1=attention1+attention2+attention3
print(attention_input1) 

输出是输入#1 的输出矩阵的第一行:

Step 7: summed the results to create the first line of the output matrix
[1.93662106 6.68310531 1.59506841]] 

第二行将是下一个输入,例如输入#2 的输出。

我们可以在图 2.17中看到x₁的求和注意力值:

图 2.17:一个输入的求和结果

我们已完成了输入#1 的步骤。现在我们需要将所有输入的结果添加到模型中。

步骤 8:所有输入的步骤 1 至步骤 7

现在,Transformers可以使用与步骤 1 到步骤 7 描述的相同方法产生输入#2 和输入#3 的注意力值,用于一个注意力头。

从这一步开始,我们假设有 3 个学习权重的注意力值,d[model] = 64。现在我们想看到这些原始维度在达到子层输出时是什么样子的。

我们已经详细了解了小模型中的注意力表示过程。让我们直接看结果,假设我们已经生成了 3 个d[model]=64 维的注意力表示:

print("Step 8: Step 1 to 7 for inputs 1 to 3")
#We assume we have 3 results with learned weights (they were not trained in this example)
#We assume we are implementing the original Transformer paper.We will have 3 results of 64 dimensions each
attention_head1=np.random.random((3, 64))
print(attention_head1) 

以下输出显示了z₀的模拟,它代表了头 1 的d[model]=64 维的 3 个输出向量:

Step 8: Step 1 to 7 for inputs 1 to 3
[[0.31982626 0.99175996…(61 squeezed values)…0.16233212]
 [0.99584327 0.55528662…(61 squeezed values)…0.70160307]
 [0.14811583 0.50875291…(61 squeezed values)…0.83141355]] 

运行笔记本时,由于向量生成的随机性质,结果将有所不同。

现在,Transformers有一个头的输入的输出向量。下一步是生成 8 个头的输出,以创建注意力子层的最终输出。

步骤 9:注意力子层的头部输出

我们假设我们已经训练了注意力子层的 8 个头。现在,Transformers有 3 个输出向量(3 个输入向量,即单词或词片段)每个d[model] = 64 维:

print("Step 9: We assume we have trained the 8 heads of the attention sublayer")
z0h1=np.random.random((3, 64))
z1h2=np.random.random((3, 64))
z2h3=np.random.random((3, 64))
z3h4=np.random.random((3, 64))
z4h5=np.random.random((3, 64))
z5h6=np.random.random((3, 64))
z6h7=np.random.random((3, 64))
z7h8=np.random.random((3, 64))
print("shape of one head",z0h1.shape,"dimension of 8 heads",64*8) 

输出显示了一个头的形状:

Step 9: We assume we have trained the 8 heads of the attention sublayer
shape of one head (3, 64) dimension of 8 heads 512 

这 8 个头现在产生了Z:

Z = (Z₀, Z₁, Z₂, Z₃, Z₄, Z₅, Z₆, Z₇)

Transformers将现在连接Z的 8 个元素以产生多头注意力子层的最终输出。

步骤 10:连接头部的输出

Transformers连接了Z的 8 个元素:

MultiHead(Output) = Concat (Z₀, Z₁, Z₂, Z₃, Z₄, Z₅, Z₆, Z₇) W⁰ = x,d[model]

请注意,Z被乘以W⁰,它是一个被训练的权重矩阵。在这个模型中,我们将假设W⁰是被训练并集成到连接函数中的。

Z₀到Z₇被连接在一起:

print("Step 10: Concantenation of heads 1 to 8 to obtain the original 8x64=512 ouput dimension of the model")
output_attention=np.hstack((z0h1,z1h2,z2h3,z3h4,z4h5,z5h6,z6h7,z7h8))
print(output_attention) 

输出是Z的连接:

Step 10: Concatenation of heads 1 to 8 to obtain the original 8x64=512 output dimension of the model
[[0.65218495 0.11961095 0.9555153  ... 0.48399266 0.80186221 0.16486792]
 [0.95510952 0.29918492 0.7010377  ... 0.20682832 0.4123836  0.90879359]
 [0.20211378 0.86541746 0.01557758 ... 0.69449636 0.02458972 0.889699  ]] 

连接可以可视化为将Z的元素并排堆叠:

图 2.18:注意力子层输出

连接产生了一个标准的d[model]=512 维的输出:

图 2.19:连接 8 个头的输出

现在,层归一化将处理注意力子层。

后层归一化

每个Transformers的注意力子层和每个前馈子层之后都跟随后层归一化(Post-LN):

图 2.20:后层归一化

后层归一化包含加法函数和层归一化过程。加法函数处理来自子层输入的残余连接。残余连接的目标是确保关键信息不会丢失。后层归一化或层归一化可以描述如下:

LayerNormalization (x + Sublayer(x))

Sublayer(x) 是子层本身。x 是 Sublayer(x) 输入步骤的可用信息。

LayerNormalization 的输入是由 x + Sublayer(x) 产生的向量 v。Transformer 的每个输入和输出都为 d[model] = 512,这标准化了所有过程。

存在许多层归一化方法,且从一个模型到另一个模型存在变化。v = x + Sublayer(x) 的基本概念可以由 LayerNormalization (v) 定义:

变量是:

  • 是维度 d 的 v 的均值。因此:

  • 是维度 d 的标准差 v。因此:

  • 是一个缩放参数。

  • 是一个偏置向量。

这个版本的 LayerNormalization (v) 展示了许多可能的后归一化方法的基本思想。下一个子层现在可以处理后归一化或 LayerNormalization (v) 的输出。在这种情况下,子层是一个前馈网络。

子层 2:前馈网络

前馈网络 (FFN) 的输入是前一个子层的后归一化输出 d[model] = 512:

图 2.21:前馈子层

FFN 子层可以描述如下:

  • 编码器和解码器中的 FFN 是全连接的。

  • FFN 是一种逐位置的网络。每个位置都是分别且相同方式处理的。

  • FFN 包含两个层,并应用 ReLU 激活函数。

  • FFN 层的输入和输出为 d[model] = 512,但内部层更大,为 d[ff] =2048。

  • FFN 可以被视为使用大小为 1 的卷积执行两次。

考虑到这个描述,我们可以描述优化和标准化的 FFN 如下:

FFN(x) = max (0, xW[1] + b₁) W₂+b₂

FFN 的输出经过了后归一化,如前一节所述。然后输出被发送到编码器堆栈的下一层和解码器堆栈的多头注意力层。

现在让我们来探索解码器堆栈。

解码器堆栈

Transformer 模型的解码器层是与编码器层类似的层堆栈。每个解码器堆栈层具有以下结构:

图 2.22:Transformer 解码器堆栈的一层

对于 Transformer 模型的所有 N=6 层,解码器层的结构与编码器相同。每一层包含三个子层:多头掩码注意力机制,多头注意力机制和全连接的逐位置前馈网络。

解码器有一个第三个主要子层,即遮罩式多头注意力机制。在此子层的输出中,在给定位置,随后的单词被掩盖,以便 Transformer 在不看到序列的其余部分的情况下基于其推断。因此,在这个模型中,它无法看到序列的未来部分。

每个 Transformer 模型中的三个主要子层都被一个残差连接,Sublayer(x),像编码器堆栈中一样:

层归一化 (x + Sublayer(x))

嵌入层子层只存在于堆栈的底层,就像编码器堆栈一样。解码器堆栈的每个子层的输出都具有恒定的维度,d[model],就像编码器堆栈一样,包括嵌入层和残差连接的输出。

我们可以看到,设计者们努力创建了对称的编码器和解码器堆栈。

每个子层的结构和解码器功能与编码器类似。在本节中,当我们需要时,我们可以参考编码器来获得相同的功能。我们只关注解码器和编码器之间的差异。

输出嵌入和位置编码

解码器子层的结构与编码器子层的大部分相同。输出嵌入层和位置编码函数与编码器堆栈中的相同。

在我们通过 Vaswani 等人 (2017) 提出的模型中探索 Transformer 的用法时,输出是我们需要学习的翻译。我选择使用法语翻译:

Output=Le chat noir était assis sur le canapé et le chien marron dormait sur le tapis 

这个输出是英文输入句子的法语翻译:

Input=The black cat sat on the couch and the brown dog slept on the rug. 

输出的词经过词嵌入层,然后是位置编码函数,就像编码器堆栈的第一层一样。

让我们看一下解码器堆栈的多头注意力层的具体属性。

注意力层

Transformer 是一个自回归模型。它使用先前的输出序列作为额外的输入。解码器的多头注意力层使用与编码器相同的过程。

然而,遮罩式多头注意力子层 1 只允许注意力应用到当前位置及其之前的位置。未来的词对 Transformer 是隐藏的,这迫使它学会预测。

在遮罩式多头注意力子层 1 之后,像在编码器中一样,遵循一个后层归一化过程。

多头注意力子层 2 也只关注到 Transformer 正在预测的当前位置之前的位置,以避免看到它必须预测的序列。

多头注意力子层 2 从编码器中汲取信息,在点积注意力操作期间考虑编码器 (K, V)。该子层还从掩码的多头注意力子层 1(掩码关注)中汲取信息,在点积注意力操作期间还考虑子层 1(Q)。因此,解码器使用编码器的训练信息。我们可以将解码器的自注意力多头子层的输入定义为:

输入 _ 注意力 = (输出 _ 解码器 _ 子层 – 1(Q), 输出 _ 编码器 _ 层(K, V))

在编码器后,会跟随一个后层标准化过程。

然后 Transformer 会进入 FFN 子层,然后是一个后层标准化和线性层。

FFN 子层,后层标准化和线性层

FFN 子层的结构与编码器堆栈的 FFN 相同。FFN 的后层标准化像编码器堆栈的层标准化一样工作。

Transformer 仅每次产生一个元素的输出序列:

输出序列 = (y₁, y₂, … yₙ)

线性层产生一个输出序列,其线性函数因模型而异,但依赖于标准方法:

y =w * x + b

w和b是学习参数。

线性层因此会产生序列的下一个可能元素,softmax 函数将其转换为概率元素。

解码器层,如编码器层,将从层l到l+1,一直到6层 Transformer 堆叠的顶层。

现在让我们看一下 Transformer 是如何训练的以及其性能如何。

训练和性能

最初的 Transformer 是在一个 450 万句对的英德数据集和一个 3600 万句对的英法数据集上进行训练的。

这些数据集来自机器翻译研讨会 (WMT),如果你希望探索 WMT 数据集,可以在以下链接找到:www.statmt.org/wmt14/

最初的 Transformer 基础模型在装有 8 个 NVIDIA P100 GPU 的计算机上进行了 100,000 步的训练,用时 12 个小时。大型模型则用了 3.5 天进行了 300,000 步的训练。

最初的 Transformer 在 WMT 英法数据集上取得了 41.8 的 BLEU 分数,优于所有以前的机器翻译模型。

BLEU 代表双语评估助手。它是一个评估机器翻译结果质量的算法。

Google 研究和 Google Brain 团队应用了优化策略来提高 Transformer 的性能。例如,使用了 Adam 优化器,但学习率通过首先经历线性增长的预热阶段,然后在之后降低。

应用了不同类型的正则化技术,如残差丢失和丢失,到嵌入之和上。此外,Transformer 应用了标签平滑,避免了通过过于自信的单热输出过拟合。它引入了更不准确的评估,并迫使模型更多、更好地训练。

几种其他 Transformer 模型变体导致了其他模型和用法,我们将在随后的章节中探讨。

在结束本章之前,让我们感受一下 Hugging Face 中可立即使用的变换器模型的简单性,例如。

Hugging Face 中的变换器模型

这一章中所见的一切都可以压缩成一个可立即使用的 Hugging Face 变换器模型。

通过 Hugging Face,你可以用三行代码实现机器翻译!

在 Google Colaboratory 中打开 Multi_Head_Attention_Sub_Layer.ipynb。将笔记本保存到您的 Google Drive 中(确保您有一个 Gmail 帐户)。转到最后两个单元格。

我们首先确保安装了 Hugging Face transformers:

!pip -q install transformers 

第一个单元导入了包含几个变换器用法的 Hugging Face 管道:

#@title Retrieve pipeline of modules and choose English to French translation
from transformers import pipeline 

然后我们实现 Hugging Face 管道,其中包含了可立即使用的功能。在我们的案例中,为了说明本章的 Transformer 模型,我们激活了翻译模型并输入一句要从英语翻译成法语的句子:

translator = pipeline("translation_en_to_fr")
#One line of code!
print(translator("It is easy to translate languages with transformers", max_length=40)) 

voilà!翻译显示出来了:

[{'translation_text': 'Il est facile de traduire des langues à l'aide de transformateurs.'}] 

Hugging Face 展示了变换器架构如何在可立即使用的模型中使用。

摘要

在本章中,我们首先通过研究变换器架构可以揭示的令人震惊的远距离依赖关系入门。变换器可以执行从书面和口头序列到有意义表示的转换,这在自然语言理解(NLU)的历史上前所未有。

这两个维度,转换的扩展和实现的简化,将人工智能推向了前所未有的水平。

我们探索了从转换问题和序列建模中移除 RNN、LSTM 和 CNN 的大胆方法,以构建 Transformer 架构。编码器和解码器的标准化维度的对称设计使得从一个子层到另一个子层的流程几乎无缝连接。

我们看到,除了移除循环网络模型外,变换器还引入了并行化层,减少了训练时间。我们还发现了其他创新,例如位置编码和掩码多头注意力。

灵活的、原始的 Transformer 架构为许多其他创新变体提供了基础,为更强大的转换问题和语言建模打开了道路。

在接下来的章节中,当描述原始模型的许多变体时,我们将更深入地了解 Transformer 架构的一些方面。

Transformer 的到来标志着一个新一代即用型人工智能模型的开始。例如,Hugging Face 和 Google Brain 使人工智能易于使用,只需几行代码即可实现。

在下一章节,Fine-Tuning BERT Models,我们将探讨原始 Transformer 模型的强大进化。

问题

  1. NLP 转换可以编码和解码文本表示。(真/假)

  2. 自然语言理解(NLU)是自然语言处理(NLP)的子集。(真/假)

  3. 语言建模算法根据输入序列生成可能的单词序列。(真/假)

  4. 一个 Transformer 是一个定制的 LSTM,带有一个 CNN 层。(真/假)

  5. 一个 Transformer 不包含 LSTM 或 CNN 层。(真/假)

  6. 注意力机制检查序列中的所有标记,而不仅仅是最后一个。(真/假)

  7. 一个 Transformer 使用位置向量,而不是位置编码。(真/假)

  8. 一个 Transformer 包含一个前馈网络。(真/假)

  9. Transformer 解码器的掩码多头注意力组件防止算法解析给定位置的序列其余部分正在处理的部分。(真/假)

  10. Transformers 能够比 LSTM 更好地分析长距离依赖关系。(真/假)

参考文献

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作区,与作者进行每月的问我任何事会话:

www.packt.link/Transformers

第三章:微调 BERT 模型

在第二章,开始使用Transformers模型的架构中,我们定义了原始 Transformer 架构的构建块。 将原始 Transformer 想象成用乐高^® 砖块构建的模型。 构建套件包含编码器、解码器、嵌入层、位置编码方法、多头注意力层、掩码多头注意力层、后层规范化、前馈子层和线性输出层等砖块。

砖块有各种大小和形状。你可以花几个小时使用相同的建筑套件构建各种模型!一些构建只需要一些砖块。其他构建将添加一个新的部件,就像我们使用乐高^® 组件构建模型时获得额外的砖块一样。

BERT 向 Transformer 构建套件添加了一个新部件:双向多头注意力子层。 当我们人类在理解一个句子时遇到问题时,我们不仅仅查看过去的单词。 BERT 像我们一样,同时查看同一句子中的所有单词。

本章将首先探讨来自Transformers的双向编码表示(BERT)的架构。 BERT 以一种新颖的方式仅使用Transformers的编码器块,并且不使用解码器堆栈。

然后,我们将对预训练的 BERT 模型进行微调。 我们将对将进行微调的 BERT 模型进行预训练,该模型由第三方训练并上传到 Hugging Face。 Transformers可以进行预训练。 然后,例如,可以在几个 NLP 任务上对预训练的 BERT 进行微调。 我们将通过使用 Hugging Face 模块进行下游 Transformer 使用的这种迷人经历。

本章涵盖以下主题:

  • 来自Transformers的双向编码表示(BERT)

  • BERT 的架构

  • 两步 BERT 框架

  • 准备预训练环境

  • 定义预训练编码器层

  • 定义微调

  • 下游多任务处理

  • 构建微调的 BERT 模型

  • 加载可接受性判断数据集

  • 创建注意力掩码

  • BERT 模型配置

  • 衡量微调模型的性能

我们的第一步将是探索 BERT 模型的背景。

BERT 的架构

BERT 将双向注意引入了Transformers模型。 双向注意需要对原始 Transformer 模型进行许多其他更改。

我们将不会讨论第二章,开始使用Transformers模型的架构中描述的Transformers构建块。 您可以随时查阅第二章,以查看有关Transformers构建块的某个方面的评论。 在本节中,我们将重点关注 BERT 模型的特定方面。

我们将重点关注Devlin等人(2018)设计的演进,描述了编码器堆栈。 我们将首先通过编码器堆栈,然后通过预训练输入环境的准备来描述 BERT 的两步框架:预训练和微调。

让我们首先探索编码器堆栈。

编码器堆栈

我们将从原始变换器模型中采用的第一个构建块是编码器层。正如在第二章 变换器模型架构入门 中描述的那样,编码器层显示在图 3.1中:

图 3.1:编码器层

BERT 模型不使用解码器层。BERT 模型具有编码器堆栈,但没有解码器堆栈。掩码的标记(隐藏要预测的标记)位于编码器的注意力层中,我们将在后续部分中放大 BERT 编码器层时看到。

原始变换器包含一个N=6 层的堆栈。原始变换器的维度数为d[model] = 512。原始变换器的注意力头数为A=8。原始变换器的头部维度是:

BERT 编码器层比原始变换器模型更大。

两个 BERT 模型可以使用编码器层构建:

  • BERT[BASE],其中包含N=12 编码器层。d[model] = 768,也可以表示为H=768,就像 BERT 论文中所述。多头注意力子层包含A=12 个头。每个头的维度z[A]与原始变换器模型中保持为 64:

  • 在连接之前,每个多头注意力子层的输出将是 12 个头的输出:

output_multi-head_attention={z[0], z₁, z₂,…, z[11]}

  • BERT[LARGE],其中包含N=24 编码器层。d[model] = 1024。多头注意力子层包含A=16 个头。每个头的维度z[A]与原始变换器模型中保持为 64:

  • 在连接之前,每个多头注意力子层的输出将是 16 个头的输出:

output_multi-head_attention={z[0], z₁, z₂,…, z[15]}

模型的大小可以总结如下:

图 3.2:变换器模型

BERT 模型不仅限于这三种配置。这三种配置说明了 BERT 模型的主要方面。有许多变种是可能的。

尺寸和维度在 BERT 风格的预训练中起着至关重要的作用。BERT 模型就像人类一样。BERT 模型随着更多的工作内存(维度)和更多的知识(数据)产生更好的结果。学习大量数据的大型变换器模型将为下游自然语言处理任务更好地进行预训练。

让我们进入第一个子层,看看 BERT 模型中输入嵌入和位置编码的基本方面。

准备预训练输入环境

BERT 模型没有解码器层的堆栈。因此,它没有一个掩码的多头注意力子层。BERT 设计者指出,掩码了其余序列的掩码的多头注意力层妨碍了注意力过程。

掩码的多头注意力层掩盖了超出当前位置的所有标记。 例如,采用以下句子:

The cat sat on it because it was a nice rug. 

如果我们刚到达单词it,编码器的输入可以是:

The cat sat on it<masked sequence> 

这种方法的动机是防止模型看到它应该预测的输出。 这种从左到右的方法可以产生相当好的结果。

然而,模型不能通过这种方式学到很多。 要知道it指的是什么,我们需要看整个句子,达到rug这个词,并弄清楚it指的是地毯。

BERT 的作者想到了一个主意。为什么不预训练模型使用不同的方法来进行预测?

BERT 的作者提出了双向注意力,让一个注意力头同时从左到右和从右到左关注所有单词。 换句话说,编码器的自注意力屏蔽可以在不受解码器的掩码多头注意力子层的阻碍的情况下完成任务。

该模型经过了两项任务的训练。 第一种方法是掩码语言建模(MLM)。 第二种方法是下一句预测(NSP)。

让我们从掩码语言建模开始。

掩码语言建模

掩码语言建模不需要训练模型,即可预测由可见单词序列后跟掩码序列。

BERT 引入了对句子的双向分析,其中对句子的一个单词进行随机掩盖。

需要注意的是,BERT 应用了WordPiece,一种子词分词的方法,以及学习的位置编码,而不是正弦-余弦方法。

一个潜在的输入序列可能是:

The cat sat on it because it was a nice rug. 

当模型到达单词it后,解码器将掩码注意力序列:

The cat sat on it <masked sequence>. 

但是 BERT 编码器会将一个随机标记进行掩码以进行预测:

The cat sat on it [MASK] it was a nice rug. 

多重注意力子层现在可以看到整个序列,运行自注意力过程,并预测被掩码的标记。

输入标记以一种棘手的方式进行了掩码,以便让模型训练时间更长,但产生更好的结果,采用三种方法:

  • 在数据集的 10%中,出其不意地不掩盖一个标记; 例如:

    The cat sat on it [because] it was a nice rug. 
    
  • 在数据集的 10%中,用随机标记替换标记来出其不意; 例如:

    The cat sat on it [often] it was a nice rug. 
    
  • 在 80%的数据集中,将一个标记替换为[MASK]标记; 例如:

    The cat sat on it [MASK] it was a nice rug. 
    

作者们大胆的方法避免了过拟合,并迫使模型高效训练。

BERT 还经过训练用于执行下一句预测。

下一句预测

第二种训练 BERT 的方法是下一句预测(NSP)。输入包含两个句子。 在 50%的情况下,第二个句子是文档的实际第二句。 在 50%的情况下,第二个句子是随机选择的,与第一个句子无关。

添加了两个新标记:

  • [CLS]是一个二元分类标记,添加到第一个序列的开头,以预测第二个序列是否跟随第一个序列。正样本通常是从数据集中取出的连续句子对。负样本是使用来自不同文档的序列创建的。

  • [SEP]是一个分隔标记,表示序列的结束。

例如,从一本书中摘录的输入句子可能是:

The cat slept on the rug. It likes sleeping all day. 

这两个句子将成为一个完整的输入序列:

[CLS] the cat slept on the rug [SEP] it likes sleep ##ing all day[SEP] 

这种方法需要额外的编码信息来区分序列 A 和序列 B。

如果我们将整个嵌入过程放在一起,我们得到:

图 3.3:输入嵌入

输入嵌入由标记嵌入、段(句子、短语、单词)嵌入和位置编码嵌入求和得到。

BERT 模型的输入嵌入和位置编码子层可以总结如下:

  • 一系列单词被分解成WordPiece标记。

  • 一个[MASK]标记将随机替换初始的单词标记,用于掩码语言建模训练。

  • 为了分类目的,在序列的开头插入一个[CLS]分类标记。

  • 一个[SEP]标记分隔两个句子(段落、短语)用于 NSP 训练。

  • 将句子嵌入添加到标记嵌入中,使句子 A 的句子嵌入值与句子 B 不同。

  • 学习位置编码。原始 Transformer 的正弦-余弦位置编码方法没有被应用。

还有一些额外的关键特性:

  • BERT 在其多头注意力子层中使用双向注意力,打开了广阔的学习视野,并理解标记之间的关系。

  • BERT 引入了无监督嵌入的场景,使用未标记的文本预训练模型。无监督场景迫使模型在多头注意力学习过程中更加努力思考。这使得 BERT 学习语言的构建方式,并将这些知识应用到下游任务中,而不必每次都进行预训练。

  • BERT 也使用监督学习,在预训练过程中涵盖了所有基础知识。

BERT 改进了 Transformer 的训练环境。现在让我们看看预训练的动机以及它如何帮助微调过程。

预训练和微调 BERT 模型

BERT 是一个两步框架。第一步是预训练,第二步是微调,如图 3.4所示:

图 3.4:BERT 框架

训练一个 Transformer 模型可能需要几个小时,甚至几天。设计架构和参数以及选择适当的数据集来训练 Transformer 模型需要相当长的时间。

预训练是 BERT 框架的第一步,可以分解为两个子步骤:

  • 定义模型的架构:层数、头数、维度和模型的其他构建模块

  • 在MLM和NSP任务上训练模型

BERT 框架的第二步是微调,也可以分解为两个子步骤:

  • 用预训练的 BERT 模型的训练参数初始化所选的下游模型

  • 针对特定下游任务(如文本蕴涵识别(RTE),问答(SQuAD v1.1,SQuAD v2.0)和带有对抗生成的情境(SWAG))微调参数

在本节中,我们介绍了微调 BERT 模型所需的信息。在接下来的章节中,我们将更深入地探讨本节提出的主题:

  • 在第四章,从头开始预训练 RoBERTa 模型中,我们将从头开始预训练一个类似 BERT 的模型的 15 个步骤。我们甚至会编译我们的数据,训练一个分词器,然后训练模型。这一章旨在首先讨论 BERT 的特定构建模块,然后微调现有模型。

  • 在第五章,变形金刚进行下游自然语言处理任务中,我们将遍历许多下游任务,探索GLUE,SQuAD v1.1,SQuAD,SWAG和其他几个自然语言处理评估数据集。我们将运行几个下游变形金刚模型来说明关键任务。本章的目标是微调一个下游模型。

  • 在第七章,GPT-3 引擎的超人变形金刚的崛起中,将探讨 OpenAI GPT-2和GPT-3变形金刚的架构和使用方法。BERT[BASE]被配置得接近于 OpenAI GPT,以展示它产生了更好的性能。然而,OpenAI 变形金刚也在不断进化!我们将看到它们如何达到了超人类的自然语言处理水平。

在本章中,我们将对语言可接受性语料库(CoLA)上进行微调的 BERT 模型进行训练。下游任务基于Alex Warstadt,Amanpreet Singh和Samuel R. Bowman的神经网络可接受性判断。

我们将微调一个 BERT 模型,该模型将确定一个句子的语法可接受性。微调后的模型将获得一定水平的语言能力。

我们已经讨论了 BERT 的架构及其预训练和微调框架。现在让我们来微调一个 BERT 模型。

微调 BERT

本节将微调一个 BERT 模型,以预测可接受性判断的下游任务,并使用马修斯相关系数(MCC)来衡量预测,这将在本章的使用马修斯相关系数进行评估部分进行解释。

在 Google Colab 中打开BERT_Fine_Tuning_Sentence_Classification_GPU.ipynb(确保你有一个电子邮箱账户)。笔记本在本书的 GitHub 存储库的Chapter03中。

笔记本中每个单元格的标题也与本章的每个小节的标题相同或非常接近。

我们将首先探讨为什么变形金刚模型必须考虑硬件约束。

硬件约束

Transformer 模型需要多处理硬件。在 Google Colab 的运行时菜单中,选择更改运行时类型,并在硬件加速器下拉列表中选择GPU。

Transformer 模型是硬件驱动的。我建议在继续本章之前阅读附录 II,Transformer 模型的硬件约束。

程序将使用 Hugging Face 模块,接下来我们将安装它们。

安装 Hugging Face PyTorch 接口的 BERT

Hugging Face 提供了一个预训练的 BERT 模型。Hugging Face 开发了一个名为PreTrainedModel的基类。通过安装这个类,我们可以从预训练模型配置中加载模型。

Hugging Face 提供了 TensorFlow 和 PyTorch 模块。我建议开发者对两种环境都要熟悉。出色的人工智能研究团队会使用其中一种或两种环境。

在本章中,我们将按照以下方式安装所需的模块:

#@title Installing the Hugging Face PyTorch Interface for Bert
!pip install -q transformers 

安装将运行,或者满足要求的消息将被显示。

现在我们可以导入程序所需的模块。

导入模块

我们将导入所需的预训练模块,如预训练的BERT tokenizer和 BERT 模型的配置。导入了BERTAdam优化器以及序列分类模块:

#@title Importing the modules
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader, RandomSampler, SequentialSampler
from keras.preprocessing.sequence import pad_sequences
from sklearn.model_selection import train_test_split
from transformers import BertTokenizer, BertConfig
from transformers import AdamW, BertForSequenceClassification, get_linear_schedule_with_warmup 

从tqdm导入一个漂亮的进度条模块:

from tqdm import tqdm, trange 

现在我们可以导入广泛使用的标准 Python 模块:

import pandas as pd
import io
import numpy as np
import matplotlib.pyplot as plt
% matplotlib inline 

如果一切顺利,不会显示任何消息,需要记住 Google Colab 已经在我们使用的虚拟机上预先安装了这些模块。

指定 CUDA 作为 torch 的设备

现在我们将指定 torch 使用计算统一设备架构(CUDA)来利用 NVIDIA 卡的并行计算能力,为我们的多头注意力模型工作:

#@title Harware verification and device attribution
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
!nvidia-smi 

输出可能会随 Google Colab 的配置而变化。请参阅附录 II:Transformer 模型的硬件约束,了解解释和截图。

现在我们将加载数据集。

加载数据集

现在我们将基于 Warstadt等人(2018 年)的论文加载 CoLA。

通用语言理解评估(GLUE)将语言可接受性视为首要的自然语言处理任务。在第五章,使用 Transformer 的下游自然语言处理任务中,我们将探讨 Transformer 必须执行的关键任务,以证明其效率。

笔记本中的以下单元格会自动下载必要的文件:

import os
!curl -L https://raw.githubusercontent.com/Denis2054/Transformers-for-NLP-2nd-Edition/master/Chapter03/in_domain_train.tsv --output "in_domain_train.tsv"
!curl -L https://raw.githubusercontent.com/Denis2054/Transformers-for-NLP-2nd-Edition/master/Chapter03/out_of_domain_dev.tsv --output "out_of_domain_dev.tsv" 

你应该看到它们出现在文件管理器中:

图 3.5:上传数据集

现在程序将加载数据集:

#@title Loading the Dataset
#source of dataset : https://nyu-mll.github.io/CoLA/
df = pd.read_csv("in_domain_train.tsv", delimiter='\t', header=None, names=['sentence_source', 'label', 'label_notes', 'sentence'])
df.shape 

输出显示了我们导入的数据集的形状:

(8551, 4) 

显示了 10 行样本以可视化可接受性判断任务,并查看序列是否合理:

df.sample(10) 

输出显示了 10行标记数据集,每次运行后可能会更改:

sentence_source label label_notes sentence

|

1742 

|

r-67 

|

1 

|

NaN 

|

they said that tom would n't pay up , but pay… 

|

|

937 

|

bc01 

|

1 

|

NaN 

|

although he likes cabbage too , fred likes egg… 

|

|

5655 

|

c_13 

|

1 

|

NaN 

|

wendy 's mother country is iceland . 

|

|

500 

|

bc01 

|

0 

|

* 

|

john is wanted to win . 

|

|

4596 

|

ks08 

|

1 

|

NaN 

|

i did n't find any bugs in my bed . 

|

|

7412 

|

sks13 

|

1 

|

NaN 

|

the girl he met at the departmental party will... 

|

|

8456 

|

ad03 

|

0 

|

* 

|

peter is the old pigs . 

|

|

744 

|

bc01 

|

0 

|

* 

|

frank promised the men all to leave . 

|

|

5420 

|

b_73 

|

0 

|

* 

|

i 've seen as much of a coward as frank . 

|

|

5749 

|

c_13 

|

1 

|

NaN 

|

we drove all the way to buenos aires . 

|

.tsv文件中每个样本包含四个以制表符分隔的列:

  • 第一列:句子的来源(代码)

  • 第二列:标签(0=不可接受,1=可接受)

  • 第三列:作者注释的标签

  • 第四列:待分类的句子

你可以在本地打开.tsv文件,阅读数据集的一些样本。程序现在将处理数据用于 BERT 模型。

创建句子,标签列表,并添加 BERT 标记

程序现在会按照本章准备预训练输入环境部分的描述创建句子:

#@ Creating sentence, label lists and adding Bert tokens
sentences = df.sentence.values
# Adding CLS and SEP tokens at the beginning and end of each sentence for BERT
sentences = ["[CLS] " + sentence + " [SEP]" for sentence in sentences]
labels = df.label.values 

[CLS]和[SEP]现在已经添加。

程序现在激活了分词器。

激活 BERT 分词器

在本节中,我们将初始化一个预训练的 BERT 分词器。这将节省从头开始训练它所需的时间。

程序选择了一个小写分词器,激活它,并显示了第一个标记化的句子:

#@title Activating the BERT Tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)
tokenized_texts = [tokenizer.tokenize(sent) for sent in sentences]
print ("Tokenize the first sentence:")
print (tokenized_texts[0]) 

输出包含分类令牌和序列分割令牌:

Tokenize the first sentence:
['[CLS]', 'our', 'friends', 'wo', 'n', "'", 't', 'buy', 'this', 'analysis', ',', 'let', 'alone', 'the', 'next', 'one', 'we', 'propose', '.', '[SEP]'] 

程序现在将处理数据。

处理数据

我们需要确定一个固定的最大长度并为模型处理数据。数据集中的句子很短。但为了确保这一点,程序将序列的最大长度设置为128,然后进行填充:

#@title Processing the data
# Set the maximum sequence length. The longest sequence in our training set is 47, but we'll leave room on the end anyway. 
# In the original paper, the authors used a length of 512.
MAX_LEN = 128
# Use the BERT tokenizer to convert the tokens to their index numbers in the BERT vocabulary
input_ids = [tokenizer.convert_tokens_to_ids(x) for x in tokenized_texts]
# Pad our input tokens
input_ids = pad_sequences(input_ids, maxlen=MAX_LEN, dtype="long", truncating="post", padding="post") 

序列已经被处理,现在程序创建了注意力掩码。

创建注意力掩码

现在就是过程中的一个棘手部分了。在前一个单元格中,我们添加了填充的序列。但我们想阻止模型对这些填充的标记执行注意力!

想法是为每个标记应用一个值为1的掩码,0 将用于填充:

#@title Create attention masks
attention_masks = []
# Create a mask of 1s for each token followed by 0s for padding
for seq in input_ids:
  seq_mask = [float(i>0) for i in seq]
  attention_masks.append(seq_mask) 

程序现在将分割数据。

将数据分割成训练集和验证集

程序现在执行标准的数据分割过程,将数据分成训练集和验证集:

#@title Splitting data into train and validation sets
# Use train_test_split to split our data into train and validation sets for training
train_inputs, validation_inputs, train_labels, validation_labels = train_test_split(input_ids, labels, random_state=2018, test_size=0.1)
train_masks, validation_masks, _, _ = train_test_split(attention_masks, input_ids,random_state=2018, test_size=0.1) 

数据已经准备好训练,但仍需调整为 torch。

将所有数据转换为 torch 张量

微调模型使用 torch 张量。程序必须将数据转换为 torch 张量:

#@title Converting all the data into torch tensors
# Torch tensors are the required datatype for our model
train_inputs = torch.tensor(train_inputs)
validation_inputs = torch.tensor(validation_inputs)
train_labels = torch.tensor(train_labels)
validation_labels = torch.tensor(validation_labels)
train_masks = torch.tensor(train_masks)
validation_masks = torch.tensor(validation_masks) 

转换结束了。现在我们需要创建一个迭代器。

选择批处理大小并创建迭代器

在这个单元格中,程序会选择批处理大小并创建一个迭代器。这个迭代器是避免加载所有数据到内存中并且配合 torch 的DataLoader巧妙的方式,可以批量训练大型数据集而不会使机器内存崩溃。

在这个模型中,批处理大小是32:

#@title Selecting a Batch Size and Creating and Iterator
# Select a batch size for training. For fine-tuning BERT on a specific task, the authors recommend a batch size of 16 or 32
batch_size = 32
# Create an iterator of our data with torch DataLoader. This helps save on memory during training because, unlike a for loop, 
# with an iterator the entire dataset does not need to be loaded into memory
train_data = TensorDataset(train_inputs, train_masks, train_labels)
train_sampler = RandomSampler(train_data)
train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=batch_size)
validation_data = TensorDataset(validation_inputs, validation_masks, validation_labels)
validation_sampler = SequentialSampler(validation_data)
validation_dataloader = DataLoader(validation_data, sampler=validation_sampler, batch_size=batch_size) 

数据已经被处理并且准备就绪。程序现在可以加载并配置 BERT 模型。

BERT 模型配置

程序现在初始化了一个 BERT 小写配置:

#@title BERT Model Configuration
# Initializing a BERT bert-base-uncased style configuration
#@title Transformer Installation
try:
  import transformers
except:
  print("Installing transformers")
  !pip -qq install transformers

from transformers import BertModel, BertConfig
configuration = BertConfig()
# Initializing a model from the bert-base-uncased style configuration
model = BertModel(configuration)
# Accessing the model configuration
configuration = model.config
print(configuration) 

输出包含主要的 Hugging Face 参数,类似于以下内容(该库经常更新):

BertConfig {
  "attention_probs_dropout_prob": 0.1,
  "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,
  "type_vocab_size": 2,
  "vocab_size": 30522
} 

来看看这些主要参数:

  • attention_probs_dropout_prob:0.1将0.1的丢失率应用于注意力概率。

  • hidden_act: "gelu" 是编码器中的非线性激活函数。这是一个高斯误差线性单元的激活函数。输入按其大小加权,这使其非线性。

  • hidden_dropout_prob: 0.1 是应用于全连接层的 dropout 概率。在嵌入、编码器和池层中都可以找到全连接。输出并不总是对序列内容的良好反映。池化隐藏状态序列有助于改善输出序列。

  • hidden_size: 768 是编码层和池层的维度。

  • initializer_range: 0.02 是初始化权重矩阵的标准差值。

  • intermediate_size: 3072 是编码器的前馈层的维度。

  • layer_norm_eps: 1e-12 是层归一化层的 epsilon 值。

  • max_position_embeddings: 512 是模型使用的最大长度。

  • model_type: "bert" 是模型的名称。

  • num_attention_heads: 12 是头的数量。

  • num_hidden_layers: 12 是层数的数量。

  • pad_token_id: 0 是填充标记的 ID,以避免训练填充标记。

  • type_vocab_size: 2 是token_type_ids的大小,它标识序列。例如,“the dog[SEP] The cat.[SEP]"可以用 token IDs [0,0,0, 1,1,1]表示。

  • vocab_size: 30522 是模型用于表示input_ids的不同标记的数量。

有了这些参数,我们现在可以加载预训练模型。

加载 Hugging Face BERT uncased 基础模型

程序现在加载了预训练的 BERT 模型:

#@title Loading the Hugging Face Bert uncased base model 
model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)
model = nn.DataParallel(model)
model.to(device) 

我们已经定义了模型,定义了并行处理,并且将模型发送到设备。更多解释,请参见附录 II,Transformer 模型的硬件限制。

如果需要,该预训练模型可以进一步训练。通过详细探索架构,可以可视化每个子层的参数,就像下面的摘录所示:

BertForSequenceClassification(
  (bert): BertModel(
    (embeddings): BertEmbeddings(
      (word_embeddings): Embedding(30522, 768, padding_idx=0)
      (position_embeddings): Embedding(512, 768)
      (token_type_embeddings): Embedding(2, 768)
      (LayerNorm): BertLayerNorm()
      (dropout): Dropout(p=0.1, inplace=False)
    )
    (encoder): BertEncoder(
      (layer): ModuleList(
        (0): BertLayer(
          (attention): BertAttention(
            (self): BertSelfAttention(
              (query): Linear(in_features=768, out_features=768, bias=True)
              (key): Linear(in_features=768, out_features=768, bias=True)
              (value): Linear(in_features=768, out_features=768, bias=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
            (output): BertSelfOutput(
              (dense): Linear(in_features=768, out_features=768, bias=True)
              (LayerNorm): BertLayerNorm()
              (dropout): Dropout(p=0.1, inplace=False)
            )
          )
          (intermediate): BertIntermediate(
            (dense): Linear(in_features=768, out_features=3072, bias=True)
          )
          (output): BertOutput(
            (dense): Linear(in_features=3072, out_features=768, bias=True)
            (LayerNorm): BertLayerNorm()
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
        (1): BertLayer(
          (attention): BertAttention(
            (self): BertSelfAttention(
              (query): Linear(in_features=768, out_features=768, bias=True)
              (key): Linear(in_features=768, out_features=768, bias=True)
              (value): Linear(in_features=768, out_features=768, bias=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
            (output): BertSelfOutput(
              (dense): Linear(in_features=768, out_features=768, bias=True)
              (LayerNorm): BertLayerNorm()
              (dropout): Dropout(p=0.1, inplace=False)
            )
          )
          (intermediate): BertIntermediate(
            (dense): Linear(in_features=768, out_features=3072, bias=True)
          )
          (output): BertOutput(
            (dense): Linear(in_features=3072, out_features=768, bias=True)
            (LayerNorm): BertLayerNorm()
            (dropout): Dropout(p=0.1, inplace=False)
          )
        ) 

现在让我们来看一下优化器的主要参数。

优化器分组参数

程序现在将初始化模型参数的优化器。微调模型的起始点是初始化预训练模型的参数值(而不是它们的名称)。

优化器的参数包括权重衰减率以避免过拟合,还有一些参数被筛选了出来。

目标是为了为训练循环准备模型的参数:

##@title Optimizer Grouped Parameters
#This code is taken from:
# https://github.com/huggingface/transformers/blob/5bfcd0485ece086ebcbed2d008813037968a9e58/examples/run_glue.py#L102
# Don't apply weight decay to any parameters whose names include these tokens.
# (Here, the BERT doesn't have 'gamma' or 'beta' parameters, only 'bias' terms)
param_optimizer = list(model.named_parameters())
no_decay = ['bias', 'LayerNorm.weight']
# Separate the 'weight' parameters from the 'bias' parameters. 
# - For the 'weight' parameters, this specifies a 'weight_decay_rate' of 0.01\. 
# - For the 'bias' parameters, the 'weight_decay_rate' is 0.0\. 
optimizer_grouped_parameters = [
    # Filter for all parameters which *don't* include 'bias', 'gamma', 'beta'.
    {'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)],
     'weight_decay_rate': 0.1},

    # Filter for parameters which *do* include those.
    {'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)],
     'weight_decay_rate': 0.0}
]
# Note - 'optimizer_grouped_parameters' only includes the parameter values, not the names. 

参数已经被准备并清理干净。它们已经为训练循环做好了准备。

训练循环的超参数

尽管似乎无害,但训练循环的超参数至关重要。例如,Adam 会激活权重衰减,并且还会经历一个温和的阶段。

学习率(lr)和温和率(warmup)在优化阶段的早期应该设为一个很小的值,并且在一定数量的迭代后逐渐增加。这可以避免大梯度和超出优化目标。

一些研究人员认为,在层归一化之前的子层输出水平上的梯度不需要预热率。解决这个问题需要进行多次实验运行。

优化器是一种称为BertAdam的 BERT 版本的 Adam:

#@title The Hyperparameters for the Training Loop 
optimizer = BertAdam(optimizer_grouped_parameters,
                     lr=2e-5,
                     warmup=.1) 

程序添加了一个精度测量函数来比较预测和标签:

#Creating the Accuracy Measurement Function
# Function to calculate the accuracy of our predictions vs labels
def flat_accuracy(preds, labels):
    pred_flat = np.argmax(preds, axis=1).flatten()
    labels_flat = labels.flatten()
    return np.sum(pred_flat == labels_flat) / len(labels_flat) 

数据准备就绪。参数准备就绪。现在是激活训练循环的时候了!

训练循环

训练循环遵循标准学习过程。epochs 数设置为4,并且损失和准确率的测量将被绘制。训练循环使用dataloader加载和训练批次。训练过程进行了测量和评估。

代码从初始化train_loss_set开始,它将存储将绘制的损失和准确率。它开始训练其 epochs 并运行标准训练循环,如下所示的摘录:

#@title The Training Loop
t = [] 
# Store our loss and accuracy for plotting
train_loss_set = []
# Number of training epochs (authors recommend between 2 and 4)
epochs = 4
# trange is a tqdm wrapper around the normal python range
for _ in trange(epochs, desc="Epoch"):
…./…
    tmp_eval_accuracy = flat_accuracy(logits, label_ids)

    eval_accuracy += tmp_eval_accuracy
    nb_eval_steps += 1
  print("Validation Accuracy: {}".format(eval_accuracy/nb_eval_steps)) 

输出使用trange包装器为每个epoch显示信息,for _ in trange(epochs, desc="Epoch"):

***output***
Epoch:   0%|          | 0/4 [00:00<?, ?it/s]
Train loss: 0.5381132976395461
Epoch:  25%|██▌       | 1/4 [07:54<23:43, 474.47s/it]
Validation Accuracy: 0.788966049382716
Train loss: 0.315329696132929
Epoch:  50%|█████     | 2/4 [15:49<15:49, 474.55s/it]
Validation Accuracy: 0.836033950617284
Train loss: 0.1474070605354314
Epoch:  75%|███████▌  | 3/4 [23:43<07:54, 474.53s/it]
Validation Accuracy: 0.814429012345679
Train loss: 0.07655430570461196
Epoch: 100%|██████████| 4/4 [31:38<00:00, 474.58s/it]
Validation Accuracy: 0.810570987654321 

Transformer 模型发展非常迅速,可能会出现废弃消息甚至错误。Hugging Face 也不例外,当发生这种情况时,我们必须相应地更新我们的代码。

模型已经训练。我们现在可以显示训练评估。

训练评估

损失和准确率数值存储在train_loss_set中,这在训练循环开始时定义。

程序现在绘制测量结果:

#@title Training Evaluation
plt.figure(figsize=(15,8))
plt.title("Training loss")
plt.xlabel("Batch")
plt.ylabel("Loss")
plt.plot(train_loss_set)
plt.show() 

输出是一张图表,显示训练过程进行得很顺利和高效:

图 3.6:每批次训练损失

模型已经微调。我们现在可以进行预测。

使用留存数据集进行预测和评估

BERT 下游模型是使用in_domain_train.tsv数据集训练的。程序现在将使用out_of_domain_dev.tsv文件中的留存(测试)数据集进行预测。目标是预测句子是否语法正确。

以下代码摘录显示了应用于训练数据的数据准备过程在留存数据集部分的代码中被重复使用:

#@title Predicting and Evaluating Using the Holdout Dataset 
df = pd.read_csv("out_of_domain_dev.tsv", delimiter='\t', header=None, names=['sentence_source', 'label', 'label_notes', 'sentence'])
# Create sentence and label lists
sentences = df.sentence.values
# We need to add special tokens at the beginning and end of each sentence for BERT to work properly
sentences = ["[CLS] " + sentence + " [SEP]" for sentence in sentences]
labels = df.label.values
tokenized_texts = [tokenizer.tokenize(sent) for sent in sentences]
.../... 

程序然后使用dataloader运行批次预测:

# Predict 
for batch in prediction_dataloader:
  # Add batch to GPU
  batch = tuple(t.to(device) for t in batch)
  # Unpack the inputs from our dataloader
  b_input_ids, b_input_mask, b_labels = batch
  # Telling the model not to compute or store gradients, saving memory and speeding up prediction
  with torch.no_grad():
    # Forward pass, calculate logit predictions
    logits = model(b_input_ids, token_type_ids=None, attention_mask=b_input_mask) 

预测的 logits 和标签被移动到 CPU 上:

 # Move logits and labels to CPU
  logits =  logits['logits'].detach().cpu().numpy()
  label_ids = b_labels.to('cpu').numpy() 

预测和它们的真实标签已存储:

 # Store predictions and true labels
  predictions.append(logits)
  true_labels.append(label_ids) 

程序现在可以评估预测了。

使用马修斯相关系数进行评估

马修斯相关系数(MCC)最初是设计用来衡量二元分类的质量,并且可以修改为多类相关系数。每个预测可以使用四个概率进行二元分类:

  • TP = 真阳性

  • TN = 真阴性

  • FP = 假阳性

  • FN = 假阴性

布莱恩·W·马修斯,一位生物化学家,于 1975 年设计了它,受他的前辈的phi函数的启发。从那时起,它已经发展成为各种格式,如以下格式之一:

MCC 产生的值在-1和+1之间。 +1是预测的最大正值。 -1是反向预测。 0是平均随机预测。

GLUE 用 MCC 评估语言可接受性。

MCC 是导入自sklearn.metrics的:

#@title Evaluating Using Matthew's Correlation Coefficient
# Import and evaluate each test batch using Matthew's correlation coefficient
from sklearn.metrics import matthews_corrcoef 

创建了一组预测:

matthews_set = [] 

MCC 值被计算并存储在matthews_set中:

for i in range(len(true_labels)):
  matthews = matthews_corrcoef(true_labels[i],
                 np.argmax(predictions[i], axis=1).flatten())
  matthews_set.append(matthews) 

由于库和模块版本更改,您可能会看到一些消息。 最终得分将基于整个测试集,但让我们看看各个批次的得分,以了解批次之间指标的变化。

各个批次的得分

让我们来看看各个批次的得分:

#@title Score of Individual Batches
matthews_set 

输出产生了预期的-1和+1之间的 MCC 值:

[0.049286405809014416,
 -0.2548235957188128,
 0.4732058754737091,
 0.30508307783296046,
 0.3567530340063379,
 0.8050112948805689,
 0.23329882422520506,
 0.47519096331149147,
 0.4364357804719848,
 0.4700159919404217,
 0.7679476477883045,
 0.8320502943378436,
 0.5807564950208268,
 0.5897435897435898,
 0.38461538461538464,
 0.5716350506349809,
 0.0] 

几乎所有的 MCC 值都是正值,这是个好消息。 让我们看看整个数据集的评估如何。

对整个数据集进行 Matthews 评估

MCC 是评估分类模型的一种实用方法。

该程序现在将为整个数据集聚合真实值:

#@title Matthew's Evaluation on the Whole Dataset
# Flatten the predictions and true values for aggregate Matthew's evaluation on the whole dataset
flat_predictions = [item for sublist in predictions for item in sublist]
flat_predictions = np.argmax(flat_predictions, axis=1).flatten()
flat_true_labels = [item for sublist in true_labels for item in sublist]
matthews_corrcoef(flat_true_labels, flat_predictions) 

MCC 产生-1和+1之间的相关值。 0是平均预测,-1是反向预测,1是完美预测。 在这种情况下,输出证实 MCC 是正值,表明模型和数据集之间存在关联:

0.45439842471680725 

在 BERT 模型的微调最终积极评估中,我们对 BERT 训练框架有了整体的认识。

摘要

BERT 为 transformers 引入了双向关注。 从左到右预测序列并屏蔽未来的标记以训练模型具有严格限制。 如果屏蔽的序列包含我们正在寻找的意义,模型将产生错误。 BERT 同时关注序列的所有标记。

我们探索了 BERT 的架构,它只使用 transformers 的编码器堆栈。 BERT 被设计为一个两步框架。 框架的第一步是预训练一个模型。 第二步是微调模型。 我们为可接受性判断下游任务构建了一个微调的 BERT 模型。 微调过程经历了所有阶段的过程。 首先,我们加载了数据集和加载了模型的必要预训练模块。 然后训练模型,并测量其性能。

对一个预训练模型进行微调所需的机器资源比从头开始训练下游任务要少。 细调模型可以执行各种任务。 BERT 证明我们只需对模型进行两项训练预处理就能实现这一点,这本身就是了不起的。但是基于 BERT 预训练模型的训练参数产生多任务微调模型是异常的。

第七章,具有 GPT-3 引擎的超人变形金刚的兴起,表明 OpenAI 已经达到了零调校水平。

在本章中,我们对 BERT 模型进行了微调。在下一章,第四章,从头开始预训练 RoBERTa 模型,我们将深入研究 BERT 框架,并从头构建一个预训练的类 BERT 模型。

问题

  1. BERT 代表双向编码器来自Transformers。 (True/False)

  2. BERT 是一个两步框架。 步骤 1 是预训练。 步骤 2 是微调。 (True/False)

  3. 对 BERT 模型进行微调意味着从头开始训练参数。 (True/False)

  4. BERT 仅通过所有下游任务进行预训练。 (True/False)

  5. BERT 预训练采用掩码语言建模 (MLM)。 (True/False)

  6. BERT 预训练采用下一句预测 (NSP)。 (True/False)

  7. BERT 预训练数学函数。 (True/False)

  8. 问答任务是一个下游任务。 (True/False)

  9. BERT 预训练模型不需要标记化。 (True/False)

  10. 对 BERT 模型进行微调所需时间比预训练少。 (True/False)

参考资料

加入我们书的 Discord 空间

加入书籍的 Discord 工作空间,与作者进行每月的 向我提问 会话:

www.packt.link/Transformers

第四章:从头开始预训练 RoBERTa 模型

在本章中,我们将从头开始构建一个 RoBERTa 模型。该模型将使用我们在 BERT 模型中所需的Transformers构造工具的模块。此外,不会使用预训练的分词器或模型。RoBERTa 模型将按照本章描述的十五步过程构建。

我们将利用在之前章节中获得的Transformers知识,逐步构建一个可以对遮蔽标记执行语言建模的模型。在第二章,开始使用Transformers模型的体系结构中,我们研究了原始Transformers的构建模块。在第三章,对 BERT 模型进行微调中,我们微调了一个预训练的 BERT 模型。

本章将重点介绍如何使用基于 Hugging Face 无缝模块的 Jupyter 笔记本从头开始构建一个预训练的Transformers模型。该模型被命名为 KantaiBERT。

KantaiBERT 首先加载了专门为本章创建的伊曼纽尔·康德的书籍的合集。您将看到数据是如何获取的。您还将看到如何为此笔记本创建自己的数据集。

KantaiBERT 从头训练自己的分词器。它将构建自己的合并和词汇文件,在预训练过程中使用。

然后 KantaiBERT 处理数据集,初始化一个训练师,并训练模型。

最后,KantaiBERT 使用训练好的模型执行一个实验性的下游语言建模任务,并使用伊曼纽尔·康德的逻辑填充掩码。

到本章结束时,您将了解如何从头开始构建一个Transformers模型。您将拥有足够的Transformers知识,以应对使用强大的预训练Transformers(如 GPT-3 引擎)的第四次工业革命挑战,这需要不仅有开发技能,还需要实施能够实现它们的技能。本章为第七章,GPT-3 引擎崛起的超人类Transformers做好了准备。

本章涵盖以下主题:

  • 类似 RoBERTa 和 DistilBERT 的模型

  • 如何从头训练一个分词器

  • 字节级字节对编码

  • 将训练好的分词器保存到文件中

  • 重新创建用于预训练过程的分词器

  • 从头初始化 RoBERTa 模型

  • 探索模型的配置

  • 探索模型的 8000 万参数

  • 为训练师构建数据集

  • 初始化训练师

  • 预训练模型

  • 保存模型

  • 将模型应用于遮蔽语言建模(MLM)的下游任务

我们的第一步将是描述我们将要构建的Transformers模型。

训练分词器并预训练Transformers

在本章中,我们将使用 Hugging Face 提供的用于类似 BERT 模型的构建模块来训练一个名为 KantaiBERT 的Transformers模型。我们在第三章,对 BERT 模型进行微调中介绍了我们将使用的模型构建模块的理论。

我们将在之前章节中获得的知识基础上描述 KantaiBERT。

KantaiBERT 是一种基于 BERT 架构的鲁棒优化 BERT 预训练方法(RoBERTa)-风格的模型。

最初的 BERT 模型为初始的Transformers模型带来了创新特性,正如我们在第三章中看到的那样。RoBERTa 通过改进预训练过程的机制来提高Transformers对下游任务的性能。

例如,它不使用WordPiece分词,而是下降到字节级别的字节对编码(BPE)。这种方法为各种 BERT 和类似 BERT 的模型铺平了道路。

在本章中,与 BERT 一样,KantaiBERT 将使用掩码语言建模(MLM)进行培训。MLM 是一种语言建模技术,它会在序列中掩盖一个单词。Transformers模型必须训练以预测被掩盖的单词。

KantaiBERT 将作为一个小型模型进行培训,包括 6 层、12 个头和 84,095,008 个参数。也许 8400 万个参数看起来很多。然而,这些参数分布在 12 个头上,使其成为一个相对较小的模型。一个小模型将使预训练体验得以顺畅进行,以便每一步都可以实时查看,而不必等待数小时才能看到结果。

KantaiBERT 是一种类似 DistilBERT 的模型,因为它具有相同的 6 层和 12 个头的架构。DistilBERT 是 BERT 的精简版本。如其名所示,DistilBERT 比 RoBERTa 模型包含更少的参数。因此,它运行速度更快,但与 RoBERTa 模型相比,结果略微不够准确。

我们知道,大型模型能够取得出色的性能。但是,如果你想在智能手机上运行一个模型会怎样呢?微型化一直是技术发展的关键。在实施过程中,Transformers有时必须遵循相同的路径。Hugging Face 提出使用 BERT 的精简版本是迈出的一大步。因此,通过使用更少的参数或其他类似方法进行精炼,是将预训练的最佳内容变得有效用于许多下游任务的巧妙方式。

显示所有可能的架构很重要,包括在智能手机上运行一个小型模型。然而,Transformers的未来也将是准备好的可用 API,正如我们将在第七章的超人类Transformers与 GPT-3 引擎的崛起中所看到的那样。

KantaiBERT 将实现一种类似 GPT-2 所使用的字节级字节对编码分词器。特殊的分词将使用 RoBERTa 所使用的分词。BERT 模型通常使用 WordPiece 分词器。

没有标记类型 ID 来指示标记属于哪个片段的哪个部分。片段将用分隔标记</s>来分隔。

KantaiBERT 将使用自定义数据集,训练分词器,训练Transformers模型,保存它,并在 MLM 示例中运行它。

让我们开始从头构建一个Transformers。

从头构建 KantaiBERT

我们将从头构建 KantaiBERT,并在 MLM 示例中运行它的 15 个步骤。

打开 Google Colaboratory(你需要一个 Gmail 帐号)。然后上传KantaiBERT.ipynb,它在本章的 GitHub 目录中。

本节的 15 个步骤的标题与笔记本单元格的标题类似,这使得它们易于跟踪。

让我们从加载数据集开始。

步骤 1:加载数据集

预先准备好的数据集提供了一个客观的方法来训练和比较 transformers。在第五章,使用 Transformers 进行下游 NLP 任务中,我们将探讨几个数据集。然而,本章旨在理解一个 transformer 的训练过程,使用可以实时运行的笔记本单元格,而不需要等待数小时才能获得结果。

我选择使用伊曼纽尔·康德(1724-1804)的作品,他是德国哲学家,是启蒙时代的典范。这个想法是为下游推理任务引入类似于人类的逻辑和预训练推理。

Project Gutenberg,www.gutenberg.org,提供了大量免费的可以以文本格式下载的电子书。如果你想基于书籍创建自定义数据集,可以使用其他书籍。

我将以下三本伊曼纽尔·康德的书编译成名为kant.txt的文本文件:

  • 纯粹理性批判

  • 实践理性批判

  • 道德形而上学基本原理

kant.txt为本章的 transformer 模型提供了一个小的训练数据集。所得到的结果仍然是试验性的。对于一个真实的项目,我会添加伊曼纽尔·康德、勒内·笛卡尔、帕斯卡尔和莱布尼茨等人的全部作品,例如。

文本文件包含书籍的原始文本:

`…For it is in reality vain to profess _indifference_ in regard to such`
`inquiries, the object of which cannot be indifferent to humanity.` 

数据集将在KantaiBERT.ipynb笔记本的第一个单元格中自动从 GitHub 下载。

你也可以使用 Colab 的文件管理器加载kant.txt,它位于本章在 GitHub 上的目录中。在这种情况下,使用 curl 从 GitHub 检索它:

#@title Step 1: Loading the Dataset
#1.Load kant.txt using the Colab file manager
#2.Downloading the file from GitHub
!curl -L https://raw.githubusercontent.com/Denis2054/Transformers-for-NLP-2nd-Edition/master/Chapter04/kant.txt --output "kant.txt" 

一旦加载或下载,你可以在 Colab 文件管理器窗格中看到它出现:

图 4.1:Colab 文件管理器

请注意,当您重新启动 VM 时,Google Colab 将删除文件。

数据集被定义并加载。

不要在没有kant.txt的情况下运行后续单元格。训练数据是先决条件。

现在,程序将安装 Hugging Face transformers。

步骤 2:安装 Hugging Face transformers

我们需要安装 Hugging Face transformers 和分词器,但在这个 Google Colab VM 实例中我们不需要 TensorFlow:

#@title Step 2:Installing Hugging Face Transformers
# We won't need TensorFlow here
!pip uninstall -y tensorflow
# Install 'transformers' from master
!pip install git+https://github.com/huggingface/transformers
!pip list | grep -E 'transformers|tokenizers'
# transformers version at notebook update --- 2.9.1
# tokenizers version at notebook update --- 0.7.0 

输出显示已安装的版本:

Successfully built transformers
tokenizers               0.7.0          
transformers             2.10.0 

Transformer 版本发展得非常迅速。你运行的版本可能会有所不同,并且显示方式也可能不同。

程序现在将通过训练一个分词器来开始。

步骤 3:训练分词器

在本节中,程序不使用预训练的分词器。例如,可以使用预训练的 GPT-2 分词器。但是,本章的训练过程包括从头开始训练一个分词器。

使用 Hugging Face 的 ByteLevelBPETokenizer() 将使用 kant.txt 进行训练。 BPE 标记器将字符串或单词分解为子字符串或子词。这有两个主要优点,其中之一是:

  • 标记器可以将单词分解为最小组件。然后它将这些小组件合并成统计学上有趣的组件。例如,“smaller" and smallest" 可以变成“small,”,“er,” 和“est。” 标记器可以进一步操作。例如,我们可以得到“sm" 和“all。” 无论如何,单词都被分解成子词标记和子词部分的更小单位,例如“sm" 和“all",而不仅仅是“small。”

  • 使用 WordPiece 级别编码,将被分类为未知的字符串块 unk_token,实际上会消失。

在此模型中,我们将使用以下参数训练标记器:

  • files=paths 是数据集的路径

  • vocab_size=52_000 是我们标记器模型长度的大小

  • min_frequency=2 是最小频率阈值

  • special_tokens=[] 是特殊标记的列表

在这种情况下,特殊标记列表是:

  • <s>:一个开始标记

  • <pad>:一个填充标记

  • </s>:一个结束符号

  • <unk>:一个未知标记

  • <mask>:语言建模的掩码标记

标记器将被训练以生成合并的子字符串标记并分析它们的频率。

在句子中间拿这两个词来说:

...the tokenizer... 

第一步是将字符串标记化:

'Ġthe', 'Ġtoken',   'izer', 

字符串现在被标记为带有 Ġ(空格)信息的标记。

下一步是用它们的索引替换它们:

‘Ġthe’ ‘Ġtoken’ ‘izer’
150 5430 4712

表 4.1:三个标记的索引

程序如预期般运行标记器:

#@title Step 3: Training a Tokenizer
%%time
from pathlib import Path
from tokenizers import ByteLevelBPETokenizer
paths = [str(x) for x in Path(".").glob("**/*.txt")]
# Initialize a tokenizer
tokenizer = ByteLevelBPETokenizer()
# Customize training
tokenizer.train(files=paths, vocab_size=52_000, min_frequency=2, special_tokens=[
    "<s>",
    "<pad>",
    "</s>",
    "<unk>",
    "<mask>",
]) 

标记器输出训练时间:

CPU times: user 14.8 s, sys: 14.2 s, total: 29 s
Wall time: 7.72 s 

标记器已经训练完成并准备保存。

第 4 步:将文件保存到磁盘中

当训练完成时,标记器将生成两个文件:

  • merges.txt,其中包含合并的标记化子字符串

  • vocab.json,其中包含标记化子字符串的索引

程序首先创建 KantaiBERT 目录,然后保存两个文件:

#@title Step 4: Saving the files to disk
import os
token_dir = '/content/KantaiBERT'
if not os.path.exists(token_dir):
  os.makedirs(token_dir)
tokenizer.save_model('KantaiBERT') 

程序输出显示两个文件已保存:

['KantaiBERT/vocab.json', 'KantaiBERT/merges.txt'] 

这两个文件应该出现在文件管理器窗格中:

图 4.2:Colab 文件管理器

此示例中的文件很小。您可以双击它们以查看其内容。merges.txt 包含按计划标记化的子字符串:

#version: 0.2 - Trained by 'huggingface/tokenizers'
Ġ t
h e
Ġ a
o n
i n
Ġ o
Ġt he
r e
i t
Ġo f 

vocab.json 包含以下索引:

[…,"Ġthink":955,"preme":956,"ĠE":957,"Ġout":958,"Ġdut":959,"aly":960,"Ġexp":961,…] 

训练好的标记化数据集文件已准备好进行处理。

第 5 步:加载训练好的标记器文件

我们本可以加载预训练的标记器文件。 但是,我们训练了自己的标记器,现在准备加载文件:

#@title Step 5 Loading the Trained Tokenizer Files 
from tokenizers.implementations import ByteLevelBPETokenizer
from tokenizers.processors import BertProcessing
tokenizer = ByteLevelBPETokenizer(
    "./KantaiBERT/vocab.json",
    "./KantaiBERT/merges.txt",
) 

标记器可以对序列进行编码:

tokenizer.encode("The Critique of Pure Reason.").tokens 

“The Critique of Pure Reason” 将变成:

['The', 'ĠCritique', 'Ġof', 'ĠPure', 'ĠReason', '.'] 

我们还可以要求看到此序列中的标记数:

tokenizer.encode("The Critique of Pure Reason.") 

输出将显示序列中有 6 个标记:

Encoding(num_tokens=6, attributes=[ids, type_ids, tokens, offsets, attention_mask, special_tokens_mask, overflowing]) 

分词器现在处理这些标记以适应本笔记本中使用的 BERT 模型变体。后处理器将添加一个开始和结束标记;例如:

tokenizer._tokenizer.post_processor = BertProcessing(
    ("</s>", tokenizer.token_to_id("</s>")),
    ("<s>", tokenizer.token_to_id("<s>")),
)
tokenizer.enable_truncation(max_length=512) 

让我们对一个后处理序列进行编码:

tokenizer.encode("The Critique of Pure Reason.") 

输出显示我们现在有 8 个标记:

Encoding(num_tokens=8, attributes=[ids, type_ids, tokens, offsets, attention_mask, special_tokens_mask, overflowing]) 

如果我们想看看添加了什么,我们可以要求分词器对后处理序列进行编码,运行以下单元格:

tokenizer.encode("The Critique of Pure Reason.").tokens 

输出显示已添加了开始和结束标记,这将标记数增加到了 8,包括开始和结束标记:

['<s>', 'The', 'ĠCritique', 'Ġof', 'ĠPure', 'ĠReason', '.', '</s>'] 

用于训练模型的数据现在已经准备好了。我们现在将检查运行笔记本的机器的系统信息。

步骤 6:检查资源限制:GPU 和 CUDA

KantaiBERT 在 图形处理单元(GPU)上以最佳速度运行。

我们首先运行一个命令来查看 NVIDIA GPU 卡是否存在:

#@title Step 6: Checking Resource Constraints: GPU and NVIDIA 
!nvidia-smi 

输出显示了卡的信息和版本:

图 4.3:NVIDIA 卡信息

输出可能随着每个 Google Colab VM 配置而变化。

我们现在将检查 PyTorch 是否看到 CUDA:

#@title Checking that PyTorch Sees CUDA
import torch
torch.cuda.is_available() 

结果应该是 True:

True 

CUDA(计算统一设备体系结构)是由 NVIDIA 开发的,用于利用其 GPU 的并行计算能力。

对于更多关于 NVIDIA GPU 和 CUDA 的信息,请参阅 附录 II,Transformer 模型的硬件限制。

我们现在准备定义模型的配置。

步骤 7:定义模型的配置

我们将使用与 DistilBERT Transformers相同数量的层和头部来预训练 RoBERTa 类型的Transformers模型。模型的词汇量设置为 52,000,具有 12 个注意力头和 6 个层:

#@title Step 7: Defining the configuration of the Model
from transformers import RobertaConfig
config = RobertaConfig(
    vocab_size=52_000,
    max_position_embeddings=514,
    num_attention_heads=12,
    num_hidden_layers=6,
    type_vocab_size=1,
) 

我们将更详细地探讨配置,见 步骤 9:从零开始初始化模型。

让我们首先在我们的模型中重新创建分词器。

步骤 8:在 transformers 中重新加载分词器

我们现在准备加载我们训练过的分词器,这是我们预训练的分词器 RobertaTokenizer.from_pretained():

#@title Step 8: Re-creating the Tokenizer in Transformers
from transformers import RobertaTokenizer
tokenizer = RobertaTokenizer.from_pretrained("./KantaiBERT", max_length=512) 

现在我们加载了我们的训练过的分词器,让我们从零开始初始化一个 RoBERTa 模型。

步骤 9:从零开始初始化模型

在本节中,我们将从零开始初始化一个模型,并检查模型的大小。

程序首先导入一个 RoBERTa 掩码模型进行语言建模:

#@title Step 9: Initializing a Model From Scratch
from transformers import RobertaForMaskedLM 

该模型使用 步骤 7 中定义的配置进行初始化:

model = RobertaForMaskedLM(config=config) 

如果我们打印模型,我们可以看到它是一个具有 6 层和 12 个头的 BERT 模型:

print(model) 

原始 Transformer 模型的编码器的构建模块以不同的尺寸存在,如输出摘录所示:

RobertaForMaskedLM(
  (roberta): RobertaModel(
    (embeddings): RobertaEmbeddings(
      (word_embeddings): Embedding(52000, 768, padding_idx=1)
      (position_embeddings): Embedding(514, 768, padding_idx=1)
      (token_type_embeddings): Embedding(1, 768)
      (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      (dropout): Dropout(p=0.1, inplace=False)
    )
    (encoder): BertEncoder(
      (layer): ModuleList(
        (0): BertLayer(
          (attention): BertAttention(
            (self): BertSelfAttention(
              (query): Linear(in_features=768, out_features=768, bias=True)
              (key): Linear(in_features=768, out_features=768, bias=True)
              (value): Linear(in_features=768, out_features=768, bias=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
            (output): BertSelfOutput(
              (dense): Linear(in_features=768, out_features=768, bias=True)
              (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
          )
          (intermediate): BertIntermediate(
            (dense): Linear(in_features=768, out_features=3072, bias=True)
          )
          (output): BertOutput(
            (dense): Linear(in_features=3072, out_features=768, bias=True)
            (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
…/… 

在继续之前,请花一些时间仔细阅读配置的输出详情。您将从内部了解模型。

Transformers的 LEGO^® 类型构建模块使得分析变得有趣。例如,您将注意到在子层中存在辍学正则化。

现在,让我们探索参数。

探索参数

该模型小巧,含有 84,095,008 个参数。

我们可以检查其大小:

print(model.num_parameters()) 

输出显示大约的参数数量,这可能因Transformers版本而异:

84095008 

现在让我们查看参数。我们首先将参数存储在LP中,并计算参数列表的长度:

#@title Exploring the Parameters
LP=list(model.parameters())
lp=len(LP)
print(lp) 

输出显示大约有108个矩阵和向量,这可能因Transformers模型而异:

108 

现在,让我们显示张量中的108个矩阵和向量:

for p in range(0,lp):
  print(LP[p]) 

输出显示所有参数,如下所示:

Parameter containing:
tensor([[-0.0175, -0.0210, -0.0334,  ...,  0.0054, -0.0113,  0.0183],
        [ 0.0020, -0.0354, -0.0221,  ...,  0.0220, -0.0060, -0.0032],
        [ 0.0001, -0.0002,  0.0036,  ..., -0.0265, -0.0057, -0.0352],
        ...,
        [-0.0125, -0.0418,  0.0190,  ..., -0.0069,  0.0175, -0.0308],
        [ 0.0072, -0.0131,  0.0069,  ...,  0.0002, -0.0234,  0.0042],
        [ 0.0008,  0.0281,  0.0168,  ..., -0.0113, -0.0075,  0.0014]],
       requires_grad=True) 

花几分钟时间来观察参数,以了解Transformers是如何构建的。

参数数量是通过取模型中的所有参数并相加来计算的;例如:

  • 词汇表 (52,000) x 维度 (768)

  • 向量的大小为1 x 768

  • 发现许多其他维度

你会注意到* d [model] = 768。模型中有 12 个头。因此,每个头的 d *[k]维度将是d[k] = d[model] / 12 = 64。

再次展示了Transformers优化的 LEGO^®概念,其构建快速。

现在我们将看一下模型的参数数量是如何计算,以及如何得到图中的 84,095,008。

如果我们在笔记本中悬停在LP上,我们将看到 torch 张量的一些形状:

图 4.4:LP

请注意,数字可能会根据您使用的 transformers 模块的版本而变化。

我们将进一步计算每个张量的参数数量。首先,程序初始化了一个名为np(参数数量)的参数计数器,并遍历了参数列表lp(108)中的元素:

#@title Counting the parameters
np=0
for p in range(0,lp):#number of tensors 

参数是不同大小的矩阵和向量;例如:

  • 768 x 768

  • 768 x 1

  • 768

我们可以看到一些参数是二维的,而一些是一维的。

查看列表中的参数LP[p]是否有两个维度的简便方法是:

 PL2=True
  try:
    L2=len(LP[p][0]) #check if 2D
  except:
    L2=1             #not 2D but 1D
    PL2=False 

如果参数有两个维度,那么它的第二个维度将是L2>0且PL2=True (2 dimensions=True)。如果参数只有一个维度,那么它的第二个维度将是L2=1且PL2=False (2 dimensions=False)。

L1是参数的第一个维度大小。L3是由下列定义的参数大小:

L1=len(LP[p])      
L3=L1*L2 

现在我们可以在循环的每一步中添加参数:

np+=L3             # number of parameters per tensor 

我们将获得参数的总和,但我们也想看到Transformers模型的参数数量是如何计算的:

 if PL2==True:
    print(p,L1,L2,L3)  # displaying the sizes of the parameters
  if PL2==False:
    print(p,L1,L3)  # displaying the sizes of the parameters
print(np)              # total number of parameters 

请注意,如果参数只有一个维度,那么PL2=False,那么我们只显示第一个维度。

输出是所有张量中参数数量的列表,如下所示:

0 52000 768 39936000
1 514 768 394752
2 1 768 768
3 768 768
4 768 768
5 768 768 589824
6 768 768
7 768 768 589824
8 768 768
9 768 768 589824
10 768 768 

RoBERTa 模型的总参数数量显示在列表的末尾:

84,095,008 

参数数量可能会随所使用的库版本而变化。

现在我们精确地知道转换模型中参数的数量代表什么。花几分钟回头看看配置的输出,参数的内容以及参数的大小。在这一点上,你将对模型的构建块有一个精确的心理表征。

程序现在构建数据集。

第 10 步:构建数据集

程序现在将逐行加载数据集以生成用于批量训练的样本,使用block_size=128限制一个示例的长度:

#@title Step 10: Building the Dataset
%%time
from transformers import LineByLineTextDataset
dataset = LineByLineTextDataset(
    tokenizer=tokenizer,
    file_path="./kant.txt",
    block_size=128,
) 

输出显示 Hugging Face 已经投入了大量资源来优化处理数据所需的时间:

CPU times: user 8.48 s, sys: 234 ms, total: 8.71 s
Wall time: 3.88 s 

墙时间,处理器实际活动的时间,已经被优化。

程序现在将定义一个数据收集器来创建一个反向传播的对象。

第 11 步:定义数据收集器

在初始化训练器之前,我们需要运行一个数据收集器。数据收集器将从数据集中取样并将其汇集成批次。结果类似于字典对象。

我们通过设置mlm=True为 MLM 准备了一个批处理样本过程。

我们还将训练的蒙版标记数目设置为mlm_probability=0.15。这将决定在预训练过程中屏蔽的标记的百分比。

现在我们使用我们的分词器初始化data_collator,MLM 被激活,并且蒙版标记的比例设置为0.15:

#@title Step 11: Defining a Data Collator
from transformers import DataCollatorForLanguageModeling
data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer, mlm=True, mlm_probability=0.15
) 

现在我们准备好初始化训练器了。

第 12 步:初始化训练器

前面的步骤已经准备好初始化训练器所需的信息。数据集已经被分词化和加载。我们的模型已经构建完成。数据收集器已经被创建。

程序现在可以初始化训练器了。出于教育目的,程序快速训练模型。训练的轮次数被限制为一个。GPU 非常方便,因为我们可以共享批次并多进程处理训练任务:

#@title Step 12: Initializing the Trainer
from transformers import Trainer, TrainingArguments
training_args = TrainingArguments(
    output_dir="./KantaiBERT",
    overwrite_output_dir=True,
    num_train_epochs=1,
    per_device_train_batch_size=64,
    save_steps=10_000,
    save_total_limit=2,
)
trainer = Trainer(
    model=model,
    args=training_args,
    data_collator=data_collator,
    train_dataset=dataset,
) 

现在模型已经准备好进行训练。

第 13 步:预训练模型

一切准备就绪。通过一行代码启动训练器:

#@title Step 13: Pre-training the Model
%%time
trainer.train() 

输出显示了实时的训练过程,显示了loss、learning rate、epoch和步骤:

Epoch: 100%
1/1 [17:59<00:00, 1079.91s/it]
Iteration: 100%
2672/2672 [17:59<00:00, 2.47it/s]
{"loss": 5.6455852394104005, "learning_rate": 4.06437125748503e-05, "epoch": 0.18712574850299402, "step": 500}
{"loss": 4.940259679794312, "learning_rate": 3.12874251497006e-05, "epoch": 0.37425149700598803, "step": 1000}
{"loss": 4.639936000347137, "learning_rate": 2.1931137724550898e-05, "epoch": 0.561377245508982, "step": 1500}
{"loss": 4.361462069988251, "learning_rate": 1.2574850299401197e-05, "epoch": 0.7485029940119761, "step": 2000}
{"loss": 4.228510192394257, "learning_rate": 3.218562874251497e-06, "epoch": 0.9356287425149701, "step": 2500}
CPU times: user 11min 36s, sys: 6min 25s, total: 18min 2s
Wall time: 17min 59s
TrainOutput(global_step=2672, training_loss=4.7226536670130885) 

模型已经训练完毕。现在是保存我们工作成果的时候了。

第 14 步:将最终模型(+分词器+配置)保存到磁盘上

现在我们将保存模型和配置:

#@title Step 14: Saving the Final Model(+tokenizer + config) to disk
trainer.save_model("./KantaiBERT") 

点击文件管理器中的刷新,文件应该会出现:

图 4.5:Colab 文件管理器

config.json、pytorh_model.bin和training_args.bin现在应该出现在文件管理器中。

merges.txt和vocab.json包含数据集的预训练标记化。

我们从零开始构建了一个模型。让我们导入管道来执行一个语言建模任务,使用我们预训练的模型和分词器。

第 15 步:使用 FillMaskPipeline 进行语言建模

现在我们将导入一个语言建模的fill-mask任务。我们将使用我们训练过的模型和训练过的分词器来执行 MLM:

#@title Step 15: Language Modeling with the FillMaskPipeline
from transformers import pipeline
fill_mask = pipeline(
    "fill-mask",
    model="./KantaiBERT",
    tokenizer="./KantaiBERT"
) 

现在我们可以让我们的模型像康德一样思考:

fill_mask("Human thinking involves human <mask>.") 

输出可能会在每个运行中发生变化,因为我们正在从有限的数据量中从头预训练模型。然而,在这次运行中获得的输出很有趣,因为它引入了概念语言建模:

[{'score': 0.022831793874502182,
  'sequence': '<s> Human thinking involves human reason.</s>',
  'token': 393},
 {'score': 0.011635891161859035,
  'sequence': '<s> Human thinking involves human object.</s>',
  'token': 394},
 {'score': 0.010641072876751423,
  'sequence': '<s> Human thinking involves human priori.</s>',
  'token': 575},
 {'score': 0.009517930448055267,
  'sequence': '<s> Human thinking involves human conception.</s>',
  'token': 418},
 {'score': 0.00923212617635727,
  'sequence': '<s> Human thinking involves human experience.</s>',
  'token': 531}] 

预测可能在每次运行和每次 Hugging Face 更新其模型时都会有所变化。

然而,经常会得到以下输出:

Human thinking involves human reason 

这里的目标是看如何训练一个转换器模型。我们可以看到有趣的类人预测是可能的。

这些结果是实验性的,在训练过程中可能会有变化。每次重新训练模型时,它们都会改变。

这个模型需要来自其他启蒙时代思想家的更多数据。

然而,这个模型的目标是展示我们可以创建数据集来训练一个特定类型的复杂语言建模任务的转换器。

由于转换器,我们只是处于人工智能新时代的开端!

下一步

你已经从零开始训练了一个转换器模型。花些时间想象一下你可以在个人或公司环境中做些什么。你可以为特定任务创建一个数据集,并从头开始训练。利用你感兴趣的领域或公司项目来探索转换器构建工具的迷人世界!

一旦你有了喜欢的模型,就可以与 Hugging Face 社区分享。你的模型将出现在 Hugging Face 模型页面上:huggingface.co/models

你可以按照本页描述的说明,用几个步骤上传你的模型:huggingface.co/transformers/model_sharing.html

你也可以下载 Hugging Face 社区共享的模型,以获取个人和专业项目的新思路。

摘要

在这一章中,我们使用了 Hugging Face 提供的构建块从零开始构建了 KantaiBERT,一个类似 RoBERTa 的模型转换器。

我们首先开始加载一个关于伊曼纽尔·康德作品相关主题的定制数据集。根据你的目标,你可以加载现有数据集或创建自己的数据集。我们发现使用定制数据集可以帮助我们了解转换器模型的思维方式。然而,这种实验方法是有局限性的。要训练一个超越教育目的的模型,需要更大规模的数据集。

KantaiBERT 项目被用来在kant.txt数据集上训练一个分词器。训练好的merges.txt和vocab.json文件被保存。用我们预训练的文件重新创建了一个分词器。KantaiBERT 建立了定制数据集,并定义了一个数据收集器来处理反向传播的训练批次。训练器被初始化,我们详细探索了 RoBERTa 模型的参数。模型被训练并保存。

最后,保存的模型被加载,用于一个下游语言建模任务。目标是用伊曼纽尔·康德的逻辑来填补空白。

现在大门已经敞开,你可以尝试现有或定制的数据集来看看你得到了什么结果。你可以与 Hugging Face 社区分享你的模型。Transformers是数据驱动的。你可以利用这一点来发现使用Transformers的新方法。

现在,你已经准备好了解如何运行无需预训练或微调的 API 的现成Transformers引擎。 第七章, 超人Transformers与 GPT-3 引擎的崛起,将带领你走进人工智能的未来。通过学习这一章和之前的章节,你将做好准备!

在下一章,用Transformers进行下游 NLP 任务,我们将继续准备实施Transformers。

问题

  1. RoBERTa 使用字节级字对编码分词���。(True/False)

  2. 经过训练的 Hugging Face 分词器会生成 merges.txt 和 vocab.json。 (True/False)

  3. RoBERTa 不使用 token-type ID。(True/False)

  4. DistilBERT 有 6 层和 12 个头。(True/False)

  5. 一个拥有 8000 万参数的Transformers模型是庞大的。(True/False)

  6. 我们无法训练分词器。(True/False)

  7. BERT-风格的模型有 6 个解码器层。(True/False)

  8. 掩盖语言建模 (MLM) 预测句子中掩盖的标记中包含的单词。(True/False)

  9. BERT-风格的模型没有自注意力子层。(True/False)

  10. 数据收集器对反向传播很有帮助。(True/False)

参考

加入我们书的 Discord 空间

加入该书的 Discord 工作空间,每月与作者进行问我任何事会话:

www.packt.link/Transformers

第五章:使用转换器的下游 NLP 任务

当我们释放预训练模型并观察它们在下游自然语言理解(NLU)任务中表现时,转换器展现出其全部潜力。对一个庞大的参数转换器模型进行预训练和微调需要大量时间和精力,但当我们看到一个模型在一系列 NLU 任务中发挥作用时,这些努力是值得的。

我们将从超越人类基线的探索开始这一章。人类基线代表人类在 NLU 任务上的表现。人类在幼年时学会了转导,并迅速发展出归纳思维。我们人类通过感官直接感知世界。机器智能完全依赖我们的感知被转录为文字来理解我们的语言。

我们随后将看到如何衡量转换器的性能。衡量自然语言处理(NLP)任务仍然是一种直观的方法,涉及基于真假结果的各种形式的准确性得分。这些结果是通过基准任务和数据集获得的。例如,SuperGLUE 是一个很好的例子,展示了谷歌 DeepMind、Facebook AI、纽约大学、华盛顿大学等共同努力设定了用于衡量 NLP 性能的高标准。

最后,我们将探索几个下游任务,如标准情感树库(SST-2)、语言可接受性和温格拉德模式。

转换器正在通过在设计良好的基准任务上胜过其他模型来迅速将 NLP 推向下一级。替代的转换器体系结构将继续出现和演化。

本章涵盖以下主题:

  • 机器与人类智能的转导和归纳比较

  • 自然语言处理的转导和归纳过程

  • 衡量转换器性能与人类基线

  • 测量方法(准确性、F1 分数和 MCC)

  • 基准任务和数据集

  • SuperGLUE 下游任务

  • 使用 CoLA 进行语言可接受性评估

  • 使用 SST-2 进行情感分析

  • 温格拉德模式

让我们首先了解人类和机器如何表示语言。

转导和Transformers的归纳继承

自动机器学习(AutoML)的出现,意味着自动化云 AI 平台中的 API,已经深刻改变了每个 AI 专家的工作描述。例如,Google Vertex 宣称实现 ML 所需的开发量减少了 80%。这表明任何人都可以使用现成的系统实现 ML。这是否意味着开发人员的工作减少了 80%?我认为不是。我认为工业 4.0 AI 专家会组装具有附加价值的 AI 项目。

工业 4.0。NLP AI 专家更多地投资于知识而不是源代码,以成为团队中的 AI 专家。

Transformers拥有独特的能力,可以将它们的知识应用于它们没有学习过的任务。例如,BERT Transformers通过序列到序列和掩码语言建模获得语言。然后可以对 BERT Transformers进行微调,以执行它从头开始没有学习的下游任务。

在本节中,我们将进行一次心灵实验。我们将使用Transformers的图表来表示人类和机器如何使用语言理解信息。机器以与人类不同的方式理解信息,但达到了非常高效的结果。

图 5.1,一个使用Transformers架构层和子层设计的心灵实验,显示了人类和机器之间的欺骗性相似性。让我们研究Transformers模型的学习过程,以了解下游任务:

图 5.1: 人类和 ML 方法

对于我们的例子,N=2。这个概念性表示有两层。这两层显示了人类从一代到下一代积累的知识。机器只处理我们给它们的东西。机器将我们的输出用作输入。

人类智能栈

在 图 5.1 的左侧,我们可以看到人类的输入是层 0 的原始事件的感知,输出是语言。我们首先作为孩子用感官感知事件。逐渐地,输出变成了潺潺的语言,然后是结构化的语言。

对于人类来说,转导 经历了一个反复试错的过程。转导意味着我们将我们感知到的结构并用模式来表示它们,例如。我们制作了我们应用于归纳思维的世界的表示。我们的归纳思维依赖于我们转导的质量。

例如,作为孩子,我们经常被迫在下午早些时候午睡。著名的儿童心理学家皮亚杰发现,这可能导致一些孩子说,例如,“我没有午睡,所以现在还不是下午。”孩子看到两个事件,用转导之间创建了链接,然后进行推理概括和归纳。

起初,人类通过转导注意到这些模式,并通过 归纳 将它们概括。我们通过反复试错来训练,以理解许多事件是相关的:

已训练的相关事件 = {日出 – 光,日落 – 黑暗,乌云 – 雨,蓝天 – 跑步,食物 – 好,火 – 温暖,雪 – 寒冷}

随着时间的推移,我们被训练去理解数百万相关事件。新一代人类不必从头开始。他们只是由上一代对许多任务进行了 微调。例如,他们被教导“火会烧伤你”。从那时起,一个孩子就知道这个知识可以被微调为任何形式的“火”:蜡烛、森林火灾、火山和每一种“火”的实例。

最后,人类将他们所知道、想象到的或预测到的一切都记录到书面 语言 中。第 0 层的输出诞生了。

对于人类来说,下一层(第 1 层)的输入是大量经过训练和微调的知识。此外,人类感知大量事件,然后通过转导、归纳、训练和微调子层以及先前的转录知识。

这些事件很多源自气味、情绪、情境、经历,以及构成人类独特性的一切。机器无法获取这种个体身份。人类对单词有一种个人的感知方式,对每个人来说都是特定的。

机器接收我们通过大量异质未经过滤的非个人数据给予它的内容。机器的目标是执行非个人的高效任务。人类的目标是个人的福祉。

我们的无限方法循环从第 0 层到第 1 层,然后回到第 0 层,带着更多的原始和处理后的信息。

结果令人着迷!我们不需要从头学习(训练)我们的母语就能获得摘要能力。我们利用预先训练的知识来调整(微调)以适应摘要任务。

Transformers通过不同的方式经历相同的过程。

机器智能栈

机器学习基本任务,就像本章描述的任务一样,然后使用它们学习如何预测的序列来执行数百个任务。

在图 5.1的右侧,我们可以看到机器的输入是语言形式的二手信息。我们的输出是机器分析语言的唯一输入。

在人类和机器历史的这一阶段,计算机视觉识别图像,但没有包含语言的语法结构。语音识别将声音转换成单词,这将我们带回书面语言。音乐模式识别不能导致用单词表达的客观概念。

机器起步有点吃力。我们对它们施加了人为的劣势。机器必须依赖我们的随机质量语言输出来:

  • 执行连接语言序列中所有一起出现的令牌(子词)的转导

  • 从这些转导中建立归纳

  • 基于令牌训练这些归纳,以产生令牌的模式

让我们在这一点上停下来,窥探一下注意子层的过程,它努力产生有效的归纳:

  • Transformers模型排除了以前基于循环的学习操作,并使用自注意力来提高模型的视野

  • 注意子层在这一点上比人类有优势:它们可以处理数百万个示例来进行归纳思维操作

  • 像我们一样,它们通过转导和归纳在序列中找到模式

  • 它们使用存储在模型中的参数来记忆这些模式。

通过利用其能力:大量数据、优秀的 NLP Transformers算法和计算能力,它们已经获得了语言理解。由于它们对语言的深刻理解,它们已经准备好运行数百个它们未经过训练的任务。

像人类一样,Transformers通过有限数量的任务来获得语言理解。像我们一样,它们通过转导检测到连接,然后通过归纳操作对其进行概括。

当Transformers模型达到机器智能的微调子层时,它的反应就像我们一样。它不是从头开始训练以执行新任务。像我们一样,它认为这只是一个只需要微调的下游任务。如果它需要学习如何回答问题,它不会从头开始学习一种语言。Transformers模型只是像我们一样微调其参数。

在本节中,我们看到Transformers模型在学习方式上存在困难。一旦它们依赖于我们用语言转录的感知,它们就从一开始就处于劣势。然而,它们可以利用无限多的数据和大量的计算能力。

现在让我们看看如何衡量Transformers性能与人类基线。

Transformers性能与人类基线

像人类一样,Transformers可以通过继承预训练模型的属性来进行微调,以执行下游任务。预训练模型通过其参数提供其架构和语言表示。

预训练模型在关键任务上训练,以获得对语言的一般知识。微调模型在下游任务上训练。并非每个Transformers模型都使用相同的任务进行预训练。潜在地,所有任务都可以预先训练或微调。

每个 NLP 模型都需要使用标准方法进行评估。

本节首先将介绍一些关键的测量方法。然后,我们将介绍一些主要的基准任务和数据集。

让我们从一些关键的度量方法开始。

使用度量标准评估模型

没有使用度量标准的通用测量系统,不可能将一个Transformers模型与另一个Transformers模型(或任何其他 NLP 模型)进行比较。

在本节中,我们将分析 GLUE 和 SuperGLUE 使用的三种测量评分方法。

准确度得分

无论您使用的是哪种变体,准确度得分都是一个实用的评估标准。得分函数为给定子集的每个结果计算一个简单的真值或假值。要么模型的输出,y_hat,与给定样本集的正确预测,y,匹配,要么不匹配。基本函数为:

如果子集的结果是正确的,则我们将获得1,如果是错误的,则为0。

现在让我们来看看更灵活的 F1 分数。

F1 分数

F1 分数引入了一种更灵活的方法,可以在面对包含不均匀类分布的数据集时提供帮助。

F1 分数使用精确率和召回率的加权值。它是精确率和召回率值的加权平均值:

F1score= 2* (precision * recall)/(precision + recall)

在这个方程中,真正例(p)、假正例(p)和假负例(n)被放入精确率(P)和召回率(R)的方程中:

因此,F1 分数可以视为精确率(P)和召回率(R)的调和平均值(算术平均值的倒数):

现在让我们回顾一下 MCC 方法。

Matthews 相关系数(MCC)

MCC 在 Fine-Tuning BERT Models 章节的 Evaluating using Matthews Correlation Coefficient 部分进行了描述和实现。MCC 计算出一个值,其中包括真正例(T[P])、真负例(Tₙ)、假正例(F[P])和假负例(Fₙ)。

MCC 可以用以下方程总结:

MCC 为二元分类模型提供了一个出色的度量标准,即使类别的大小不同也可以。

现在我们已经很好地了解了如何衡量给定 transformer 模型的结果,并将其与其他 transformer 模型或 NLP 模型进行比较。

有了测量评分方法的考虑,现在让我们来看看基准任务和数据集。

基准任务和数据集

有三个前提条件需要证明Transformers已经达到了最先进的性能水平:

  • 一个模型

  • 一个以数据集驱动的任务

  • 在本章的 Evaluating models with metrics 部分描述的度量标准

我们将从探索 SuperGLUE 基准开始,以说明一个 transformer 模型的评估过程。

从 GLUE 到 SuperGLUE

SuperGLUE 基准是由 Wang 等人(2019 年)设计并公开的。Wang 等人(2019 年)首次设计了 General Language Understanding Evaluation (GLUE) 基准。

GLUE 基准的动机是要表明,为了有用,NLU 必须适用于广泛的任务。相对较小的 GLUE 数据集旨在鼓励 NLU 模型解决一系列任务。

然而,随着Transformers的到来,NLU 模型的性能开始超越平均人类水平,正如我们可以在 GLUE 排行榜(2021 年 12 月)中看到的。GLUE 排行榜可在 gluebenchmark.com/leaderboard 查看,展示了 NLU 天才的显著表现,保留了一些以前的 RNN/CNN 思想,同时主要关注突破性的Transformers模型。

排行榜的下面摘录显示了顶尖领导者和 GLUE 人类基线的位置:

图 5.2:GLUE 排行榜 - 2021 年 12 月

新模型和人类基线的排名将不断变化。这些排名只是给出了经典 NLP 和Transformers带领我们走向何方的一个概念!

我们首先注意到 GLUE 人类基线并不处于顶级位置,这表明自然语言理解模型已经在 GLUE 任务上超越了非专业人类。人类基线代表了我们人类能够达到的水平。人工智能现在能够胜过人类。到了 2021 年 12 月,人类基线仅排在第 17 位。这是一个问题。如果没有一个要超越的标准,就很难盲目地寻找基准数据集来改进我们的模型。

我们还注意到 transformer 模型已经领先。

我喜欢将 GLUE 和 SuperGLUE 看作是语言理解从混乱到有序的转折点。对我来说,理解是让词语彼此契合并形成一种语言的粘合剂。

随着自然语言理解的进步,GLUE 排行榜将不断发展。然而,Wang 等人(2019)引入 SuperGLUE 是为了为人类基线设立更高的标准。

引入更高的人类基线标准

Wang 等人(2019)认识到了 GLUE 的局限性。他们为更困难的自然语言理解任务设计了 SuperGLUE。

SuperGLUE 立即将人类基线重新确定为第一名(2020 年 12 月),如下面排行榜摘录所示,super.gluebenchmark.com/leaderboard:

图 5.3:SuperGLUE 排行榜 2.0 – 2020 年 12 月

然而,随着我们生产出更好的自然语言理解(NLU)模型,SuperGLUE 排行榜也在发展。在 2021 年,transformers 已经超过了人类基线。到了 2021 年 12 月,人类基线已经下降到第 5 位,如 图 5.4 所示:

图 5.4:SuperGLUE 排行榜 2.0 – 2021 年 12 月

随着新的创新模型的到来,人工智能算法排名将不断变化。这些排名只是给出了自然语言处理至高无上的战斗有多么艰难的一个概念!

现在让我们看看评估过程是如何工作的。

SuperGLUE 评估过程

Wang 等人(2019)为他们的 SuperGLUE 基准选择了八个任务。这些任务的选择标准比 GLUE 更严格。例如,这些任务不仅要理解文本,还要进行推理。推理的水平不是顶级专家的水平。然而,性能水平已足以替代许多人类任务。

这八个 SuperGLUE 任务被呈现在一个现成的列表中:

图 5.5:SuperGLUE 任务

任务列表是交互式的:super.gluebenchmark.com/tasks。

每个任务都包含执行该任务所需信息的链接:

  • 名称 是一个微调、预训练模型的下游任务的名称

  • 标识符 是名称的缩写或简称

  • 下载 是数据集的下载链接

  • 更多信息 通过链接到设计数据集驱动任务的团队的论文或网站提供更多细节

  • 度量 是用于评估模型的测量分数

SuperGLUE 提供任务说明、软件、数据集以及描述要解决问题的论文或网站。一旦团队运行基准任务并达到排行榜,结果将显示如下:

图 5.6:SuperGLUE 任务分数

SuperGLUE 显示了整体评分以及每个任务的评分。

例如,让我们看看王等人(2019 年)在他们的论文的表 6中为选择合理答案(COPA)任务提供的说明。

第一步是阅读由Roemmele等人(2011 年)撰写的杰出论文。简言之,目标是让 NLU 模型展示它的机器思考能力(当然不是人类思考)。在我们的案例中,transformer 必须选择最合理的答案来回答问题。数据集提供前提,transformer 模型必须找出最合理的答案。

例如:

前提:我敲了敲邻居的门。

结果是什么?

另一种选择:我的邻居邀请我进去了。

另一种选择:我的邻居离开了他的房子。

这个问题需要人类花上一两秒钟来回答,这表明它需要一些常识机器思考。COPA.zip是一个可以直接从 SuperGLUE 任务页面下载的现成数据集,所提供的度量使得这个过程对于所有参与基准竞赛的人员都是公平和可靠的。

这些例子可能看起来很困难。然而,如果我们考虑所有的任务,transformers 接近了 COPA 人类基准线(图 5.7),它只排在第 5 名:

图 5.7:COPA 的 SuperGLUE 结果

看上去难以置信,transformers 在很短的时间内就攀登到了排行榜**上!而且这只是一个开始。新的想法几乎每个月都在出现!

我们已经介绍了 COPA。让我们定义另外七个 SuperGLUE 基准任务。

定义 SuperGLUE 基准任务

一个任务可以是一个用于生成训练模型的预训练任务。同一个任务可以是另一个模型的下游任务,该模型将对其进行微调。然而,SuperGLUE 的目标是展示给定的 NLU 模型可以执行多个下游任务并进行微调。多任务模型证明了 transformers 的思考能力。

任何 transformer 的力量都在于它能够使用预训练模型执行多个任务,然后将其应用于微调的下游任务。原始 Transformer 模型及其变体现在所有 GLUE 和 SuperGLUE 任务中处于领先地位。我们将继续关注 SuperGLUE 下游任务,而人类基准线很难击败。

在上一部分,我们介绍了 COPA。在本节中,我们将介绍王等人(2019 年)在其论文的表 2中定义的其他七个任务。

让我们继续进行一个布尔问题任务。

BoolQ

BoolQ 是一个布尔型的是或否回答任务。如在 SuperGLUE 中所定义的,数据集包含 15,942 个自然发生的例子。train.jsonl 数据集的第 3 行原始样本包含一段文章、一个问题和答案(true):

{`"question"`: "is windows movie maker part of windows essentials"
`"passage"`: "Windows Movie Maker -- Windows Movie Maker (formerly known as Windows Live Movie Maker in Windows 7) is a discontinued video editing software by Microsoft. It is a part of Windows Essentials software suite and offers the ability to create and edit videos as well as to publish them on OneDrive, Facebook, Vimeo, YouTube, and Flickr.", "idx": 2, "label": true} 

提供的数据集可能会随时间改变,但概念保持不变。

现在,让我们来看看 CB,这是一个需要人类和机器共同关注的任务。

Commitment Bank(CB)

承诺银行(CB)是一个困难的蕴含任务。我们要求Transformers模型阅读一个前提,然后检验基于前提构建的一个假设。例如,假设会确认前提或与之矛盾。然后Transformers模型必须将假设标记为中性、蕴含或矛盾,例如。

数据集包含自然语篇。

以下示例中的 #77,取自 train.jsonl 训练数据集,展示了 CB 任务的难度:

{`"premise"`: "The Susweca. It means ''dragonfly'' in Sioux, you know. Did I ever tell you that's where Paul and I met?"
`"hypothesis"`: "Susweca is where she and Paul met,"
`"label"`: `"entailment"`, "idx": 77} 

我们现在来看看多句问题。

多句阅读理解(MultiRC)

多句阅读理解(MultiRC)要求模型阅读一段文本,并从几个可能的选择中作出选择。这个任务对人类和机器来说都很困难。模型需要面对一个文本,多个问题,以及每个问题可能对应的答案,并带有 0(错误)或 1(正确)的标签。

让我们来看 train.jsonl 中的第二个样本:

"Text": "text": "The rally took place on October 17, the shooting on February 29\. Again, standard filmmaking techniques are interpreted as smooth distortion: \"Moore works by depriving you of context and guiding your mind to fill the vacuum -- with completely false ideas. It is brilliantly, if unethically, done.\" As noted above, the \"from my cold dead hands\" part is simply Moore's way to introduce Heston. Did anyone but Moore's critics view it as anything else? He certainly does not \"attribute it to a speech where it was not uttered\" and, as noted above, doing so twice would make no sense whatsoever if Moore was the mastermind deceiver that his critics claim he is. Concerning the Georgetown Hoya interview where Heston was asked about Rolland, you write: \"There is no indication that [Heston] recognized Kayla Rolland's case.\" This is naive to the extreme -- Heston would not be president of the NRA if he was not kept up to date on the most prominent cases of gun violence. Even if he did not respond to that part of the interview, he certainly knew about the case at that point. Regarding the NRA website excerpt about the case and the highlighting of the phrase \"48 hours after Kayla Rolland is pronounced dead\": This is one valid criticism, but far from the deliberate distortion you make it out to be; rather, it is an example for how the facts can sometimes be easy to miss with Moore's fast pace editing. The reason the sentence is highlighted is not to deceive the viewer into believing that Heston hurried to Flint to immediately hold a rally there (as will become quite obvious), but simply to highlight the first mention of the name \"Kayla Rolland\" in the text, which is in this paragraph. " 

样本包含四个问题。为了说明这个任务,我们只研究其中两个。模型必须预测正确的标签。请注意,模型被要求获取的信息分布在整个文本中:

`"question"`: "When was Kayla Rolland shot?"
`"answers"`:
[{"text": "February 17", "idx": 168, "label": 0}, 
`{"text": "February 29", "idx": 169, "label": 1},` 
{"text": "October 29", "idx": 170, "label": 0},
{"text": "October 17", "idx": 171, "label": 0},
{"text": "February 17", "idx": 172, "label": 0}], "idx": 26},
`{"question"`: "Who was president of the NRA on February 29?", 
`"answers": [{"text": "Charleton Heston", "idx": 173, "label": 1}`,
{"text": "Moore", "idx": 174, "label": 0},
{"text": "George Hoya", "idx": 175, "label": 0},
{"text": "Rolland", "idx": 176, "label": 0},
{"text": "Hoya", "idx": 177, "label": 0}, {"text": "Kayla", "idx": 178, "label": 0}], "idx": 27}, 

在这一点上,人们只能欣赏一个优秀的、经过精确调校的预训练模型在这些困难的下游任务上的表现。

现在,让我们来看看阅读理解任务。

Reading Comprehension with Commonsense Reasoning Dataset(ReCoRD)

通用常识推理数据集(ReCoRD)代表着另一个具有挑战性的任务。该数据集包含来自超过 70,000 篇新闻文章的 120,000 多个查询。Transformers必须运用常识推理来解决这个问题。

让我们来查看 train.jsonl 中的一个样本:

`"source"`: "Daily mail"
A passage contains the text and indications as to where the entities are located.
A passage begins with the text:
`"passage"`: {
    `"text"`: "A Peruvian tribe once revered by the Inca's for their fierce hunting skills and formidable warriors are clinging on to their traditional existence in the coca growing valleys of South America, sharing their land with drug traffickers, rebels and illegal loggers. Ashaninka Indians are the largest group of indigenous people in the mountainous nation's Amazon region, but their settlements are so sparse that they now make up less than one per cent of Peru's 30 million population. Ever since they battled rival tribes for territory and food during native rule in the rainforests of South America, the Ashaninka have rarely known peace.\n@highlight\nThe Ashaninka tribe once shared the Amazon with the like of the Incas hundreds of years ago\n@highlight\nThey have been forced to share their land after years of conflict forced rebels and drug dealers into the forest\n@highlight\n. Despite settling in valleys rich with valuable coca, they live a poor pre-industrial existence", 

实体如下摘录所示:

 `"entities": [{"start": 2,"end": 9}, …,"start": 711,"end": 715}]` 

最后,模型必须通过找到适当的值来回答一个查询,填写占位符:

{`"``query"`: "Innocence of youth: Many of the `@placeholder's` younger generations have turned their backs on tribal life and moved to the cities where living conditions are better", 
`"answers"`:[{"start":263,"end":271,"text":"Ashaninka"},{"start":601,"end":609,"text":"Ashaninka"},{"start":651,"end":659,"text":"Ashaninka"}],"idx":9}],"idx":3} 

一旦Transformers模型经历了这个问题,它现在必须面对一个包含的任务。

文本蕴含识别(RTE)

对于文本蕴涵识别(RTE),Transformers模型必须阅读前提,检查一个假设,并预测蕴含假设状态的标签。

让我们来看看 train.jsonl 数据集的样本 #19:

{`"premise"`: "U.S. crude settled $1.32 lower at $42.83 a barrel.", 
`"hypothesis"`: "Crude the light American lowered to the closing 1.32 dollars, to 42.83 dollars the barrel.", "label": `"not_entailment"`, >"idx": 19} 

RTE 需要理解和逻辑推理。现在让我们来看 Words in Context 任务。

Words in Context(WiC)

上下文中的词语(WiC)和以下的 Winograd 任务测试模型处理模棱两可的词语的能力。在 WiC 中,多任务 transformer 必须分析两个句子,并确定目标词在两个句子中是否具有相同的含义。

让我们检查train.jsonl数据集的第一个样本。

首先指定目标词:

 "word": `"place"` 

模型必须读取包含目标词的两个句子:

 "sentence1": "Do you want to come over to my place later?",
  "sentence2": "A political system with no `place` for the less prominent groups." 

train.jsonl指定了样本索引、标签的值以及sentence1(start1, end1)和sentence2(start2, end2)中目标词的位置:

 "idx": 0,
  "label": false,
  "start1": 31,
  "start2": 27,
  "end1": 36,
  "end2": 32, 

在完成这个艰巨的任务后,transformer 模型将面临 Winograd 任务。

Winograd 模式挑战(WSC)

Winograd 模式任务以 Terry Winograd 命名。如果一个 transformer 经过良好训练,它应该能够解决消歧问题。

该数据集包含针对代词性别细微差异的句子。

这构成了一个共指解析问题,这是执行的最具挑战性的任务之一。然而,允许自注意的 transformer 架构对于这个任务来说是理想的。

每个句子包含一个职业、一个参与者和一个代词。要解决的问题是找出代词是否与职业或参与者共指。

让我们看看从train.jsonl中取出的样本。

首先,样本要求模型阅读一段文本:

{`"text"`: >"I poured water from the bottle into the cup until it was full.",
The WSC ask the model to find the target pronoun token number 10 starting at 0: 
`"target"`: {`"span2_index"`: 10, 
Then it asks the model to determine if "it" refers to "the cup" or not: 
`"span1_index"`: 7,
`"span1_text"`: "the cup", 
`"span2_text"`: "it"}, 
For sample index #4, the label is true:
"idx": 4, `"label"`: true} 

我们已经了解了一些主要的 SuperGLUE 任务。还有许多其他任务。

然而,一旦你了解 transformer 的架构和基准任务的机制,你将迅速适应任何模型和基准。

现在让我们运行一些下游任务。

运行下游任务

在本节中,我们将随便选几辆 transformer 车,开一下看看它们是如何运行的。有许多模型和任务。我们将在本节运行其中几个。一旦你了解了运行几个任务的过程,你会很快理解所有任务。毕竟,所有这些任务的人类基线就是我们自己!

下游任务是从预训练 transformer 模型继承模型和参数的微调 transformer 任务。

因此,下游任务是一个从预训练模型运行微调任务的视角。这意味着,根据模型的不同,如果任务没有用于完全预训练该模型,则该任务是下游任务。在本节中,我们将考虑所有任务都是下游任务,因为我们没有预训练它们。

模型将会发展,数据库也会发展,基准方法、准确性测量方法和排行榜标准也会发展。但是反映在本章的下游任务中的人类思维结构将会保持不变。

让我们从 CoLA 开始。

语言接受性语料库(CoLA)

语言接受性语料库 (CoLA),一个 GLUE 任务,gluebenchmark.com/tasks,包含了标记为语法接受性的英语句子的成千上万个样本。

Alex Warstadt等人(2019)的目标是评估 NLP 模型对句子的语言能力,以判断句子的语言可接受性。NLP 模型应该按照预期对句子进行分类。

句子被标记为语法正确或不符合语法规范。如果句子不符合语法规范,则标记为 0。如果句子在语法上是正确的,则标记为 1。例如:

分类 = 1 代表 ‘我们喊得嘶哑了.’

分类 = 0 代表 ‘我们在喊.’

你可以在 第三章,Fine-Tuning BERT Models 中查看我们在 CoLA 数据集上对 BERT 模型进行微调的内容,打开 BERT_Fine_Tuning_Sentence_Classification_GPU.ipynb。我们使用了 CoLA 数据:

#@title Loading the Dataset
#source of dataset : https://nyu-mll.github.io/CoLA/
df = pd.read_csv("in_domain_train.tsv", delimiter='\t', header=None, names=['sentence_source', 'label', 'label_notes', 'sentence'])
df.shape 

我们还加载了一个预训练的 BERT 模型:

#@title Loading the Hugging Face Bert Uncased Base Model 
model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2) 

最后,我们使用的度量方法是 MCC,在 第三章,Fine-Tuning BERT Models 的 使用 Matthews 相关系数进行评估 部分和本章中有详细描述。

如果需要,您可以参考该部分以获取 MCC 的数学描述,并有必要时重新运行源代码。

一句话在语法上可能不可接受,但仍然传达情绪。情感分析可以为机器增加某种程度的同理心。

斯坦福情感树库(SST-2)

斯坦福情感树库(SST-2)包含电影评论。在这一部分,我们将描述 SST-2(二元分类)任务。然而,数据集远不止如此,可以将情感分类为 0(负面)到 n(正面)。

Socher等人(2013)将情感分析发展到了超越二元积极-消极 NLP 分类的程度。我们将在 第十二章,检测客户情绪以做出预测 中使用 Transformer 模型探索 SST-2 多标签情感分类。

在这一部分,我们将在 Hugging Face transformer pipeline 模型上运行从 SST 中取出的样本以说明二元分类。

打开Transformer_tasks.ipynb并运行以下单元格,其中包含从SST获取的正面和负面电影评论:

#@title SST-2 Binary Classification
from transformers import pipeline
nlp = pipeline("sentiment-analysis")
print(nlp("If you sometimes like to go to the movies to have fun , Wasabi is a good place to start."),"If you sometimes like to go to the movies to have fun , Wasabi is a good place to start.")
print(nlp("Effective but too-tepid biopic."),"Effective but too-tepid biopic.") 

输出是准确的:

[{'label': 'POSITIVE', 'score': 0.999825656414032}] If you sometimes like to go to the movies to have fun , Wasabi is a good place to start .
[{'label': 'NEGATIVE', 'score': 0.9974064230918884}] Effective but too-tepid biopic. 

SST-2 任务使用准确度指标进行评估。

我们对一个序列的情感进行分类。现在让我们看看一个序列中的两个句子是否是释义。

微软研究释义语料库(MRPC)

微软研究释义语料库(MRPC),一个 GLUE 任务,包含从网上新闻来源中提取的句子对。每对句子都经过人工标注,标明句子是否基于两个密切相关属性等价:

  • 解释等价

  • 语义等价

让我们使用 Hugging Face BERT 模型运行一个样本。打开Transformer_tasks.ipynb并前往以下单元格,然后运行从 MRPC 中提取的样本:

#@title Sequence Classification : paraphrase classification
from transformers import AutoTokenizer, TFAutoModelForSequenceClassification
import tensorflow as tf
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased-finetuned-mrpc")
model = TFAutoModelForSequenceClassification.from_pretrained("bert-base-cased-finetuned-mrpc")
classes = ["not paraphrase", "is paraphrase"]
sequence_A = "The DVD-CCA then appealed to the state Supreme Court."
sequence_B = "The DVD CCA appealed that decision to the U.S. Supreme Court."
paraphrase = tokenizer.encode_plus(sequence_A, sequence_B, return_tensors="tf")
paraphrase_classification_logits = model(paraphrase)[0]
paraphrase_results = tf.nn.softmax(paraphrase_classification_logits, axis=1).numpy()[0]
print(sequence_B, "should be a paraphrase")
for i in range(len(classes)):
    print(f"{classes[i]}: {round(paraphrase_results[i] * 100)}%") 

输出是准确的,尽管可能会收到警告消息,表明模型需要更多的下游训练:

The DVD CCA appealed that decision to the U.S. Supreme Court. should be a paraphrase
not paraphrase: 8.0%
is paraphrase: 92.0% 

MRPC 任务使用 F1/准确率分数方法进行度量。

现在让我们运行一个Winograd schema。

Winograd 模式

我们在本章的The Winograd schema challenge (WSC)部分描述了 Winograd 模式。训练集是英文的。

但是,如果我们要求Transformers模型解决英法翻译中的代词性别问题会发生什么?法语对具有语法性别(阴性、阳性)的名词有不同的拼写。

以下句子包含代词it,可以指代car或garage。Transformers能消除这个代词的歧义吗?

打开Transformer_tasks.ipynb,转到#Winograd单元格,并运行我们的示例:

#@title Winograd
from transformers import pipeline
translator = pipeline("translation_en_to_fr")
print(translator("The car could not go in the garage because it was too big.", max_length=40)) 

翻译是完美的:

[{'translation_text': "La voiture ne pouvait pas aller dans le garage parce qu'elle était trop grosse."}] 

Transformers检测到单词it指的是单词car,这是女性形式。女性形式适用于it和形容词big:

elle在法语中意味着she,这是it的翻译。阳性形式将是il,意思是he。

grosse是单词big的翻译的女性形式。否则,阳性形式将是gros。

我们给Transformers一个困难的 Winograd 模式来解决,它给出了正确的答案。

还有许多基于数据集的 NLU 任务可用。我们将在本书中探索其中一些,以将更多构建块添加到我们的 transformer 工具箱中。

概要

本章分析了人类语言表征过程与机器智能执行传导的方式之间的差异。我们看到,Transformers必须依赖于我们在书面语言中表达的极其复杂的思维过程的输出。语言仍然是表达大量信息的最精确的方式。机器没有感觉,必须将语音转换为文本,以从原始数据集中提取含义。

然后,我们探讨了如何衡量多任务Transformers的性能。Transformers在下游任务中获得顶级结果的能力在 NLP 历史上是独一无二的。我们经历了许多艰难的 SuperGLUE 任务,这些任务将Transformers带到了 GLUE 和 SuperGLUE 排行榜的前列。

BoolQ、CB、WiC 等我们涵盖的许多任务,甚至对人类来说都不容易处理。我们通过几个下游任务的示例展示了Transformers模型在证明其效率时面临的困难。

Transformers已经通过胜过以前的 NLU 架构证明了其价值。为了说明实施下游微调任务是多么简单,我们在 Google Colaboratory 笔记本中使用 Hugging Face 的 transformers 管道运行了几个任务。

在Winograd 模式中,我们给Transformers一个困难的任务,即解决英法翻译中的 Winograd 消歧问题。

在下一章,第六章,使用Transformers进行机器翻译,我们将进一步开展翻译任务,并使用 Trax 构建翻译模型。

问题

  1. 机器智能使用与人类相同的数据进行预测。(是/否)

  2. 对于 NLP 模型来说,SuperGLUE 比 GLUE 更难。(是/否)

  3. BoolQ 期望一个二进制答案。(True/False)

  4. WiC 代表上下文中的单词。(True/False)

  5. 文本蕴含识别(RTE)检测一个序列是否蕴含另一个序列。(True/False)

  6. Winograd 模式预测动词是否拼写正确。(True/False)

  7. Transformer 模型现在占据了 GLUE 和 SuperGLUE 的前几名。(True/False)

  8. 人类基准标准并非一劳永逸。它们被 SuperGLUE 制定得更难达到。(True/False)

  9. Transformer 模型永远不会达到 SuperGLUE 人类基准标准。(True/False)

  10. 变种的 Transformer 模型已经超过了 RNN 和 CNN 模型。(True/False)

参考资料

  • Alex Wang、Yada Pruksachatkun、Nikita Nangia、Amanpreet Singh、Julian Michael、Felix Hill、Omer Levy、Samuel R. Bowman,2019 年,《SuperGLUE:通用语言理解系统的更棘手的基准》:w4ngatang.github.io/static/papers/superglue.pdf

  • Alex Wang, Yada Pruksachatkun, Nikita Nangia, Amanpreet Singh, Julian Michael, Felix Hill, Omer Levy, Samuel R. Bowman, 2019, GLUE:用于自然语言理解的多任务基准和分析平台

  • Yu Sun、Shuohuan Wang、Yukun Li、Shikun Feng、Hao Tian、Hua Wu、Haifeng Wang,2019 年,《ERNIE 2.0:语言理解的持续预训练框架》:arxiv.org/pdf/1907.12412.pdf

  • Melissa Roemmele、Cosmin Adrian Bejan和Andrew S. Gordon,2011 年,《可选择的合理替代方案:常识因果推理评估》:people.ict.usc.edu/~gordon/publications/AAAI-SPRING11A.PDF

  • Richard Socher、Alex Perelygin、Jean Y. Wu、Jason Chuang、Christopher D. Manning、Andrew Y. Ng和Christopher Potts,2013 年,《递归深度模型用于情感树库的语义组合》:nlp.stanford.edu/~socherr/EMNLP2013_RNTN.pdf

  • Thomas Wolf、Lysandre Debut、Victor Sanh、Julien Chaumond、Clement Delangue、Anthony Moi、Pierric Cistac、Tim Rault、Rémi Louf、Morgan Funtowicz和Jamie Brew,2019 年,《HuggingFace 的 Transformer:最先进的自然语言处理》:arxiv.org/abs/1910.03771

  • Hugging Face Transformer 用法: huggingface.co/transformers/usage.html

加入我们书籍的 Discord 空间

加入该书的 Discord 工作区,与作者进行每月的问我任何事会话:

www.packt.link/Transformers

第六章:使用 Transformer 进行机器翻译

人类精通序列转换,将表示转移到另一个对象上。我们可以轻松想象一个序列的心理表示。如果有人说我的花园里的花很漂亮,我们可以轻松地想象出一个有花的花园。我们看到花园的图像,尽管我们可能从未见过那个花园。我们甚至可能想象出鸟鸣和花香。

机器必须从头开始学习用数字表示进行转换。循环或卷积方法产生了有趣的结果,但还没有达到显著的 BLEU 翻译评估分数。翻译需要将语言 A 的表示转换成语言 B。

Transformers模型的自注意创新提高了机器智能的分析能力。在尝试将语言 A 的序列翻译成语言 B 之前,必须对其进行充分的表示。自注意带来了机器获得更好 BLEU 分数所需的智能水平。

注意力全靠你 Transformers在 2017 年的英语-德语和英语-法语翻译中取得了最佳结果。从那以后,其他Transformers的得分已经有所提高。

在本书的这一部分,我们已经涵盖了Transformers的基本方面:Transformer 的 架构,从头开始 训练 一个 RoBERTa 模型,微调 一个 BERT,评估 一个经过微调的 BERT,并探索一些Transformers示例中的 下游任务。

在本章中,我们将通过三个额外的主题来介绍机器翻译。我们首先会定义什么是机器翻译。然后,我们将预处理一个机器翻译研讨会(WMT)数据集。最后,我们将看到如何实现机器翻译。

本章涵盖以下主题:

  • 定义机器翻译

  • 人类转换和翻译

  • 机器转换和翻译

  • 预处理 WMT 数据集

  • 使用 BLEU 评估机器翻译

  • 几何评估

  • Chencherry 平滑

  • 介绍 Google 翻译的 API

  • 使用 Trax 初始化英语-德语问题

我们的第一步将是定义机器翻译。

定义机器翻译

Vaswani 等人(2017 年)在设计 Transformer 时解决了 NLP 中最困难的问题之一。机器翻译的人类基线似乎对我们这些人类-机器智能设计者来说是遥不可及的。这并没有阻止 Vaswani 等人(2017 年)发布 Transformer 的架构并取得最先进的 BLEU 结果。

在本节中,我们将定义机器翻译。机器翻译是通过机器转换和输出来复制人类翻译的过程:

图 6.1:机器翻译过程

图 6.1 中的一般思想是让机器在几个步骤中执行以下操作:

  • 选择要翻译的句子

  • 学习单词如何相互关联以及数以亿计的参数

  • 学习单词之间相互指代的多种方式

  • 使用机器传导将学习的参数传递给新的序列

  • 为单词或序列选择候选翻译

这个过程总是以从源语言A翻译的句子开始。过程以包含语言B中翻译的句子的输出结束。中间计算涉及传导。

人类传导和翻译

例如,欧洲议会的人类口译员不会逐字逐句地翻译句子。逐字翻译通常毫无意义,因为它们缺乏适当的语法结构,并且无法产生正确的翻译,因为忽略了每个词的上下文。

人类传导将语言A中的一句话构建成一种认知表征这句话的含义。欧洲议会的口译员(口头翻译)或翻译员(书面翻译)只有在此之后才会将该传导转化为语言B中对该句话的解释。

我们将口译员或翻译员在语言B中完成的翻译称为参考句子。

在图 6.1中描述的机器翻译过程中,您会注意到几个参考资料。

人类翻译员在现实生活中不会将句子A翻译为句子B多次,而只会翻译一次。然而,在现实生活中可能会有不止一个翻译员翻译句子A。例如,你可以找到蒙田的《论文》的多个法语到英语的翻译。如果你从原始法语版本中取出句子A,你会发现被标注为引用1到n的句子B的几个版本。

如果有一天你去欧洲议会,你可能会注意到口译员只会在有限的时间内翻译两个小时,例如。然后另一个口译员接替。没有两个口译员有相同的风格,就像作家有不同的风格一样。源语言中的句子A可能由同一个人在一天中重复几次,但会被翻译成几个参考句子B版本:

参考 = {参考 1, 参考 2,…参考 n}

机器必须找到一种以与人类翻译员相同的方式思考的方法。

机器传导和翻译

原始 Transformer 架构的传导过程使用编码器堆栈、解码器堆栈和所有模型参数来表示一个参考序列。我们将称之为参考的输出序列。

为什么不直接说“输出预测”?问题在于没有单一的输出预测。Transformer,就像人类一样,将产生一个我们可以参考的结果,但如果我们对其进行不同的训练或使用不同的 Transformer 模型,结果可能会改变!

我们立即意识到人类语言序列转换的基线是一个相当大的挑战。然而,已经取得了很大的进步。

机器翻译的评估证明了自然语言处理的进步。为了确定一个解决方案是否比另一个更好,每个自然语言处理挑战者、实验室或组织必须参考相同的数据集,以便比较是有效的。

现在让我们探索一个 WMT 数据集。

预处理一个 WMT 数据集

Vaswani 等人(2017)展示了 Transformer 在 WMT 2014 英译德和 WMT 2014 英译法任务上的成就。Transformer 实现了最先进的 BLEU 分数。BLEU 将在本章的使用 BLEU 评估机器翻译部分进行描述。

2014 年的 WMT 包含了几个欧洲语言数据集。其中一个数据集包含了从欧洲议会语料库第 7 版中获取的数据。我们将使用来自欧洲议会会议平行语料库1996-2011 年的法语-英语数据集(www.statmt.org/europarl/v7/fr-en.tgz)。

一旦你下载了文件并解压缩它们,我们将预处理这两个平行文件:

  • europarl-v7.fr-en.en

  • europarl-v7.fr-en.fr

我们将加载、清理并缩小语料库的大小。

让我们开始预处理。

预处理原始数据

在本节中,我们将预处理europarl-v7.fr-en.en和europarl-v7.fr-en.fr。

打开本章的 GitHub 目录中的read.py。确保两个 europarl 文件与read.py在同一目录中。

程序开始使用标准的 Python 函数和pickle来转储序列化输出文件:

import pickle
from pickle import dump 

然后我们定义将文件加载到内存中的函数:

# load doc into memory
def load_doc(filename):
        # open the file as read only
        file = open(filename, mode='rt', encoding='utf-8')
        # read all text
        text = file.read()
        # close the file
        file.close()
        return text 

文档加载后被分割成句子:

# split a loaded document into sentences
def to_sentences(doc):
        return doc.strip().split('\n') 

检索到最短和最长的长度:

# shortest and longest sentence lengths
def sentence_lengths(sentences):
        lengths = [len(s.split()) for s in sentences]
        return min(lengths), max(lengths) 

导入的句子行必须经过清理以避免训练无用和嘈杂的标记。行被规范化,以空格分词,并转换为小写。从每个标记中删除标点符号,删除不可打印的字符,并排除包含数字的标记。清理后的行被存储为字符串。

程序运行清理函数并返回干净的附加字符串:

# clean lines
import re
import string
import unicodedata
def clean_lines(lines):
        cleaned = list()
        # prepare regex for char filtering
        re_print = re.compile('[^%s]' % re.escape(string.printable))
        # prepare translation table for removing punctuation
        table = str.maketrans('', '', string.punctuation)
        for line in lines:
                # normalize unicode characters
                line = unicodedata.normalize('NFD', line).encode('ascii', 'ignore')
                line = line.decode('UTF-8')
                # tokenize on white space
                line = line.split()
                # convert to lower case
                line = [word.lower() for word in line]
                # remove punctuation from each token
                line = [word.translate(table) for word in line]
                # remove non-printable chars form each token
                line = [re_print.sub('', w) for w in line]
                # remove tokens with numbers in them
                line = [word for word in line if word.isalpha()]
                # store as string
                cleaned.append(' '.join(line))
        return cleaned 

我们已经定义了将调用来准备数据集的关键函数。首先加载并清理英文数据:

# load English data
filename = 'europarl-v7.fr-en.en'
doc = load_doc(filename)
sentences = to_sentences(doc)
minlen, maxlen = sentence_lengths(sentences)
print('English data: sentences=%d, min=%d, max=%d' % (len(sentences), minlen, maxlen))
cleanf=clean_lines(sentences) 

数据集现在已经干净,pickle将其转储到名为English.pkl的序列化文件中:

filename = 'English.pkl'
outfile = open(filename,'wb')
pickle.dump(cleanf,outfile)
outfile.close()
print(filename," saved") 

输出显示关键统计信息,并确认English.pkl已保存:

English data: sentences=2007723, min=0, max=668
English.pkl  saved 

现在我们用相同的过程处理法语数据,并将其转储到名为French.pkl的序列化文件中:

# load French data
filename = 'europarl-v7.fr-en.fr'
doc = load_doc(filename)
sentences = to_sentences(doc)
minlen, maxlen = sentence_lengths(sentences)
print('French data: sentences=%d, min=%d, max=%d' % (len(sentences), minlen, maxlen))
cleanf=clean_lines(sentences)
filename = 'French.pkl'
outfile = open(filename,'wb')
pickle.dump(cleanf,outfile)
outfile.close()
print(filename," saved") 

输出显示法语数据集的关键统计信息,并确认French.pkl已保存。

French data: sentences=2007723, min=0, max=693
French.pkl saved 

主要的预处理已经完成。但我们仍需要确保数据集不包含嘈杂和混乱的标记。

完成数据集的预处理

现在,在与read.py相同目录中打开read_clean.py。我们的流程现在定义了一个函数,该函数将加载前一部分清理过的数据集,然后在预处理完成后保存它们:

from pickle import load
from pickle import dump
from collections import Counter

# load a clean dataset
def load_clean_sentences(filename):
        return load(open(filename, 'rb'))

# save a list of clean sentences to file
def save_clean_sentences(sentences, filename):
        dump(sentences, open(filename, 'wb'))
        print('Saved: %s' % filename) 

我们现在定义一个函数,该函数将创建一个词汇计数器。知道我们将解析的序列中每个单词的使用次数非常重要。例如,如果一个词在包含两百万行的数据集中只使用一次,我们将浪费我们的能量使用宝贵的 GPU 资源来学习它。让我们定义计数器:

# create a frequency table for all words
def to_vocab(lines):
        vocab = Counter()
        for line in lines:
                tokens = line.split()
                vocab.update(tokens)
        return vocab 

词汇计数器将检测频率低于min_occurrence的单词:

# remove all words with a frequency below a threshold
def trim_vocab(vocab, min_occurrence):
        tokens = [k for k,c in vocab.items() if c >= min_occurrence]
        return set(tokens) 

在这种情况下,min_occurrence=5,低于或等于此阈值的单词已被移除,以避免浪费训练模型分析它们的时间。

现在我们必须处理Out-Of-Vocabulary(OOV)单词。 OOV 词可以是拼写错误的单词,缩写词或任何不符合标准词汇表示的单词。我们可以使用自动拼写,但它不会解决所有问题。在本例中,我们将简单地用unk(未知)标记替换 OOV 词:

# mark all OOV with "unk" for all lines
def update_dataset(lines, vocab):
        new_lines = list()
        for line in lines:
                new_tokens = list()
                for token in line.split():
                        if token in vocab:
                                new_tokens.append(token)
                        else:
                                new_tokens.append('unk')
                new_line = ' '.join(new_tokens)
                new_lines.append(new_line)
        return new_lines 

现在我们将运行针对英语数据集的函数,保存输出,然后显示20行:

# load English dataset
filename = 'English.pkl'
lines = load_clean_sentences(filename)
# calculate vocabulary
vocab = to_vocab(lines)
print('English Vocabulary: %d' % len(vocab))
# reduce vocabulary
vocab = trim_vocab(vocab, 5)
print('New English Vocabulary: %d' % len(vocab))
# mark out of vocabulary words
lines = update_dataset(lines, vocab)
# save updated dataset
filename = 'english_vocab.pkl'
save_clean_sentences(lines, filename)
# spot check
for i in range(20):
        print("line",i,":",lines[i]) 

输出函数首先显示了获得的词汇压缩:

English Vocabulary: 105357
New English Vocabulary: 41746
Saved: english_vocab.pkl 

预处理的数据集已保存。输出函数然后显示20行,如下摘录所示:

line 0 : resumption of the session
line 1 : i declare resumed the session of the european parliament adjourned on friday december and i would like once again to wish you a happy new year in the hope that you enjoyed a pleasant festive period
line 2 : although, as you will have seen, the dreaded millennium bug failed to materialise still the people in a number of countries suffered a series of natural disasters that truly were dreadful
line 3 : you have requested a debate on this subject in the course of the next few days during this partsession 

现在让我们运行针对法语数据集的函数,保存输出,然后显示20行:

# load French dataset
filename = 'French.pkl'
lines = load_clean_sentences(filename)
# calculate vocabulary
vocab = to_vocab(lines)
print('French Vocabulary: %d' % len(vocab))
# reduce vocabulary
vocab = trim_vocab(vocab, 5)
print('New French Vocabulary: %d' % len(vocab))
# mark out of vocabulary words
lines = update_dataset(lines, vocab)
# save updated dataset
filename = 'french_vocab.pkl'
save_clean_sentences(lines, filename)
# spot check
for i in range(20):
        print("line",i,":",lines[i]) 

输出函数首先显示了获得的词汇压缩:

French Vocabulary: 141642
New French Vocabulary: 58800
Saved: french_vocab.pkl 

预处理的数据集已保存。输出函数然后显示20行,如下摘录所示:

line 0 : reprise de la session
line 1 : je declare reprise la session du parlement europeen qui avait ete interrompue le vendredi decembre dernier et je vous renouvelle tous mes vux en esperant que vous avez passe de bonnes vacances
line 2 : comme vous avez pu le constater le grand bogue de lan ne sest pas produit en revanche les citoyens dun certain nombre de nos pays ont ete victimes de catastrophes naturelles qui ont vraiment ete terribles
line 3 : vous avez souhaite un debat a ce sujet dans les prochains jours au cours de cette periode de session 

此部分显示了在训练之前必须处理原始数据的方法。数据集现在已准备好插入Transformers进行训练。

法语数据集的每一行都是要翻译的句子。 英语数据集的每一行都是机器翻译模型的参考。 机器翻译模型必须产生一个与参考匹配的英文候选翻译。

BLEU 提供了一种评估机器翻译模型生成的候选翻译的方法。

使用 BLEU 评估机器翻译

Papineni等人(2002 年)提出了一种评估人类翻译的高效方法。定义人类基线很困难。但是,他们意识到,如果我们逐字比较人类翻译和机器翻译,我们可以获得有效的结果。

Papineni等人(2002 年)将他们的方法命名为双语评估助手分数(BLEU)。

在本节中,我们将使用自然语言工具包(NLTK)实现 BLEU:

www.nltk.org/api/nltk.translate.html#nltk.translate.bleu_score.sentence_bleu

我们将从几何评估开始。

几何评估

BLEU 方法将候选句子的部分与参考句子或多个参考句子进行比较。

打开这本书的 GitHub 存储库的章节目录中的BLEU.py。

程序导入了nltk模块:

from nltk.translate.bleu_score import sentence_bleu
from nltk.translate.bleu_score import SmoothingFunction 

然后,它模拟了机器翻译模型生成的候选翻译与数据集中实际翻译参考之间的比较。 请记住,一句话可能已经多次重复,并且以不同的方式被不同的译者翻译,这使得找到有效的评估策略变得具有挑战性。

该程序可以评估一个或多个参考:

#Example 1
reference = [['the', 'cat', 'likes', 'milk'], ['cat', 'likes' 'milk']]
candidate = ['the', 'cat', 'likes', 'milk']
score = sentence_bleu(reference, candidate)
print('Example 1', score)
#Example 2
reference = [['the', 'cat', 'likes', 'milk']]
candidate = ['the', 'cat', 'likes', 'milk']
score = sentence_bleu(reference, candidate)
print('Example 2', score) 

这两个例子的得分都是1:

Example 1 1.0
Example 2 1.0 

候选C、参考R以及在C(N)中找到的正确令牌数量的简单评估P可以表示为几何函数:

如果您正在寻找 3 克重叠,例如:

#Example 3
reference = [['the', 'cat', 'likes', 'milk']]
candidate = ['the', 'cat', 'enjoys','milk']
score = sentence_bleu(reference, candidate)
print('Example 3', score) 

如果您正在寻找 3 克重叠,则输出会很严重:

Warning (from warnings module):
  File
"C:\Users\Denis\AppData\Local\Programs\Python\Python37\lib\site-packages\nltk\translate\bleu_score.py", line 490
    warnings.warn(_msg)
UserWarning: 
Corpus/Sentence contains 0 counts of 3-gram overlaps.
BLEU scores might be undesirable; use SmoothingFunction().
Example 3 0.7071067811865475 

一个人可以看出得分应该是1而不是0.7。 超参数可以更改,但方法仍然保持不变。

上面代码中的警告是一个很好的警告,它预告了下一节的内容。

每个程序版本和每次运行的消息可能会有所不同,因为这是一个随机过程。

Papineni等人(2002 年)提出了一种修改过的一元方法。 思路是统计参考句子中的词出现次数,并确保在候选句子中不会过度评估该词。

考虑由Papineni等人(2002 年)解释的以下示例:

参考 1:地板上有一只猫。

参考 2:垫子上有一只猫。

现在考虑以下候选序列:

候选:the the the the the the the

现在我们来找出候选句子中的单词数(相同单词“the”的7次出现)在参考 1句子中(单词“the”的2次出现)的情况。

标准的一元精确度将是7/7。

修改后的一元精确度为2/7。

请注意,BLEU 函数的输出警告表示同意并建议使用平滑。

让我们将平滑技术添加到 BLEU 工具包中。

应用平滑技术

Chen和Cherry(2014 年)引入了一种平滑技术,可以改进标准 BLEU 技术的几何评估方法。

标签平滑是一种非常有效的方法,可以在训练阶段改进Transformers模型的性能。 这对困惑度产生了负面影响。 然而,它迫使模型更加不确定。 这反过来对准确性产生积极影响。

例如,假设我们必须预测以下序列中的掩码单词是什么:

猫[mask]了牛奶。

想象一下输出以 softmax 向量的形式出现:

candidate_words=[drinks, likes, enjoys, appreciates]
candidate_softmax=[0.7, 0.1, 0.1,0.1]
candidate_one_hot=[1,0,0,0] 

这将是一个残酷的方法。 标签平滑可以通过引入epsilon使系统更开放。

candidate_softmax的元素数量为k=4。

对于标签平滑,我们可以将epsilon 设置为 0.25,例如。

标签平滑的几种方法之一可以是一个直观的函数。

首先,将 candidate_one_hot 的值减小1 - epsilon。

通过 0 值增加0 + epsilon / (k - 1)。

如果我们应用这种方法,我们将得到以下结果:

candidate_smoothed=[0.75,0.083,0.083,0.083],使输出对未来的变换和更改开放。

变换器使用标签平滑的变体。

BLEU 的一个变体是 chencherry 平滑。

Chencherry 平滑

Chen 和 Cherry(2014)介绍了一种通过将epsilon 添加到否则为 0 的值来平滑候选评估的有趣方法。有几种 chencherry(Boxing Chen + Colin Cherry)方法:www.nltk.org/api/nltk.translate.html。

让我们首先评估一个带有平滑的法语 - 英语示例:

#Example 4
reference = [['je','vous','invite', 'a', 'vous', 'lever','pour', 'cette', 'minute', 'de', 'silence']]
candidate = ['levez','vous','svp','pour', 'cette', 'minute', 'de', 'silence']
score = sentence_bleu(reference, candidate)
print("without soothing score", score) 

尽管人类可以接受候选者,但输出分数较低:

without smoothing score 0.37188004246466494 

现在,让我们对评估添加一些开放的平滑:

chencherry = SmoothingFunction()
r1=list('je vous invite a vous lever pour cette minute de silence')
candidate=list('levez vous svp pour cette minute de silence')

#sentence_bleu([reference1, reference2, reference3], hypothesis2,smoothing_function=chencherry.method1)
print("with smoothing score",sentence_bleu([r1], candidate,smoothing_function=chencherry.method1)) 

分数未达到人类可接受程度:

with smoothing score 0.6194291765462159 

我们现在已经看到了数据集是如何预处理的以及 BLEU 如何评估机器翻译。

使用谷歌翻译进行翻译

谷歌翻译,translate.google.com/,提供了一个用于翻译的即用界面。谷歌正在逐步将变换器编码器引入其翻译算法中。在接下来的部分中,我们将使用谷歌 Trax 实现一个翻译任务的变换器模型。

但是,可能根本不需要 AI 专家。

如果我们在谷歌翻译中输入前一节中分析的句子,Levez-vous svp pour cette minute de silence,我们将实时获得英文翻译:

图 6.2:谷歌翻译

翻译是正确的。

工业 4.0 是否仍需要 AI 专家进行翻译任务,或者只需要一个网络界面开发人员?

谷歌在其谷歌翻译平台上提供了翻译所需的每项服务:cloud.google.com/translate:

  • 一个翻译 API:一个网络开发人员可以为客户创建一个接口

  • 可以翻译流媒体内容的媒体翻译 API

  • 一个 AutoML 翻译服务,将为特定领域训练一个定制模型

一个谷歌翻译项目需要一个网络开发人员来处理界面,一个专业主题专家(SME),也许还需要一个语言学家。但是,AI 专家不是必需的。

工业 4.0 正朝着 AI 作为一种服务的方向发展。那么为什么要费心学习具有变换器的 AI 开发呢?成为工业 4.0 AI 专家有两个重要的原因:

  • 在现实生活中,AI 项目经常遇到意想不到的问题。例如,谷歌翻译可能无论投入多少善意都无法满足特定需求。在这种情况下,谷歌 Trax 将会派上用场!

  • 要使用谷歌 Trax 进行 AI,您需要是一个 AI 开发者!

你永远不知道!第四次工业革命正在将一切与一切连接起来。一些 AI 项目可能会顺利运行,而一些则需要 AI 专业知识来解决复杂问题。例如,在第十四章中,解释黑匣子Transformers模型,我们将展示有时需要 AI 开发来实现 Google 翻译。

现在我们已经准备好使用 Trax 进行翻译。

使用 Trax 进行翻译

谷歌大脑开发了Tensor2Tensor(T2T)来使深度学习开发更容易。T2T 是 TensorFlow 的一个扩展,包含了一个深度学习模型库,其中包含许多Transformers示例。

虽然 T2T 是一个很好的开始,但谷歌大脑随后推出了 Trax,一个端到端的深度学习库。Trax 包含一个可以应用于翻译的Transformers模型。谷歌大脑团队目前负责维护 Trax。

这一部分将重点介绍初始化由瓦斯瓦尼等人(2017 年)描述的英德问题所需的最小功能,以说明Transformers的性能。

我们将使用预处理的英语和德语数据集来表明Transformers架构是语言无关的。

打开Trax_Translation.ipynb。

我们将开始安装我们需要的模块。

安装 Trax

谷歌大脑已经使 Trax 易于安装和运行。我们将导入基础知识和 Trax,可以在一行中安装:

#@title Installing Trax
import os
import numpy as np
!pip install -q -U trax
import trax 

是的,就是这么简单!

现在,让我们创建我们的Transformers模型。

创建原始的Transformers模型

我们将创建原始的Transformers模型,就像第二章,开始使用Transformers模型架构中描述的那样。

我们的 Trax 函数将在几行代码中检索预训练模型配置:

#@title Creating a Transformer model.
# Pre-trained model config in gs://trax-ml/models/translation/ende_wmt32k.gin
model = trax.models.Transformer(
    input_vocab_size=33300,
    d_model=512, d_ff=2048,
    n_heads=8, n_encoder_layers=6, n_decoder_layers=6,
    max_len=2048, mode='predict') 

模型是一个具有编码器和解码器堆栈的Transformers。每个堆栈包含6层和8个头。d_model=512,与原始Transformers的架构相同。

Transformers需要预训练的权重才能运行。

使用预训练权重初始化模型

预训练权重包含Transformers的智能。权重构成了Transformers对语言的表示。权重可以表示为将产生某种形式的机器智能 IQ的参数数量。

让我们通过初始化权重来给模型赋予生命:

#@title Initializing the model using pre-trained weights
model.init_from_file('gs://trax-ml/models/translation/ende_wmt32k.pkl.gz',
                     weights_only=True) 

机器配置及其智能现已准备就绪。让我们对一个句子进行分词。

对句子进行分词

我们的机器翻译器已准备好对句子进行分词。笔记本使用由Trax预处理的词汇表。预处理方法类似于本章中描述的预处理 WMT 数据集部分。

现在,这个句子将被分词:

#@title Tokenizing a sentence.
sentence = 'I am only a machine but I have machine intelligence.'
tokenized = list(trax.data.tokenize(iter([sentence]), # Operates on streams.
                                   vocab_dir='gs://trax-ml/vocabs/',
                                   vocab_file='ende_32k.subword'))[0] 

程序现在将解码句子并产生一个翻译。

从Transformers解码

Transformers将句子编码为英语,然后将其解码为德语。模型及其权重构成了其能力集。

Trax已经使解码函数变得直观易用:

#@title Decoding from the Transformer
tokenized = tokenized[None, :]  # Add batch dimension.
tokenized_translation = trax.supervised.decoding.autoregressive_sample(
    model, tokenized, temperature=0.0)  # Higher temperature: more diverse results. 

请注意,较高的温度会产生多样化的结果,就像人类翻译者一样,在本章的定义机器翻译部分有详细解释。

最终,程序将解密并显示翻译。

解密并显示翻译

Google Brain 用Trax开发了一个主流、颠覆性和直观的 Transformer 实现。

程序现在将解密并显示翻译的结果:

#@title De-tokenizing and Displaying the Translation
tokenized_translation = tokenized_translation[0][:-1]  # Remove batch and EOS.
translation = trax.data.detokenize(tokenized_translation,
                                   vocab_dir='gs://trax-ml/vocabs/',
                                   vocab_file='ende_32k.subword')
print("The sentence:",sentence)
print("The translation:",translation) 

输出相当令人印象深刻:

The sentence: I am only a machine but I have machine intelligence.
The translation: Ich bin nur eine Maschine, aber ich habe Maschinenübersicht. 

转换器将machine intelligence翻译为Maschinenübersicht。

如果我们将Maschinenübersicht拆分为Maschin(机器)+ übersicht(智能),我们可以看到:

  • über的字面意思是“over”

  • sicht的意思是“视野”或“视图”

转换器告诉我们,尽管它是一台机器,它能够有视觉。机器智能通过 Transformer 不断增长,但它不是人类智能。机器用自身的智能学习语言。

这结束了我们对 Google Trax 的实验。

总结

在本章中,我们探讨了原始 Transformer 的三个重要方面。

我们首先定义了机器翻译。人工翻译为机器设立了一个极高的基准。我们看到,英语-法语和英语-德语翻译意味着需要解决大量问题。Transformer 解决了这些问题,并创造了最先进的 BLEU 记录。

然后,我们对来自欧洲议会的 WMT 法语-英语数据集进行了预处理,并进行了数据清理。我们必须将数据集转换成行并清理数据。做完这些之后,我们通过消除低于频率阈值的单词来减小数据集的大小。

机器翻译 NLP 模型需要相同的评估方法。在 WMT 数据集上训练模型需要进行 BLEU 评估。我们看到了几何评估是打分翻译的一个很好的基础,但即使是修改后的 BLEU 也有其局限性。因此,我们添加了一种平滑技术来增强 BLEU。

我们看到,Google 翻译提供了标准的翻译 API、媒体流 API 和自定义的自动机器学习模型训练服务。如果项目顺利进行,实施 Google 翻译 API 可能不需要进行 AI 开发。如果不顺利,我们将不得不像从前一样动手做!

我们使用了 Trax,Google Brain 的端到端深度学习库,实现了英语到德语的翻译转换器。

现在我们已经介绍了构建转换器的主要构件:架构、预训练、训练、数据预处理和评估方法。

在下一章,GPT-3 引擎崛起的超人类 Transformer中,我们将探索使用我们在前几章中探讨的构件实现 Transformer 的令人惊叹的方式。

问题

  1. 机器翻译现在已经超过了人类基准。(是/否)

  2. 机器翻译需要大规模的数据集。(是/否)

  3. 没有必要使用相同的数据集比较Transformers模型。(True/False)

  4. BLEU 是法语单词蓝色的缩写,也是 NLP 度量的首字母缩写。(True/False)

  5. 平滑技术增强了 BERT。(True/False)

  6. 德英与英德的机器翻译相同。(True/False)

  7. 原始的 Transformer 多头注意力子层有 2 个头。(True/False)

  8. 原始的 Transformer 编码器有 6 层。(True/False)

  9. 原始的 Transformer 编码器有 6 层,但只有 2 层解码器。(True/False)

  10. 你可以训练没有解码器的转换器。(True/False)

参考资料

加入我们书籍的 Discord 空间

加入该书的 Discord 工作区,与作者进行每月的Ask me Anything会话:

www.packt.link/Transformers

第七章:超人类Transformers与 GPT-3 引擎的崛起

在 2020 年,Brown 等人(2020)描述了一个包含 1750 亿个参数的 OpenAI GPT-3 模型的训练,该模型使用了诸如从 Common Crawl 数据中提取的 4000 亿个字节对编码的令牌等庞大的数据集进行了学习。OpenAI 在一个拥有 285,000 个 CPU 和 10,000 个 GPU 的 Microsoft Azure 超级计算机上进行了训练。

OpenAI 的 GPT-3 引擎的机器智能和超级计算机使 Brown 等人(2020)进行了零次实验。这个想法是使用一个训练好的模型进行下游任务,而不需要进一步训练参数。目标是让一个训练好的模型直接进入多任务生产,使用甚至可以执行它没有经过训练的任务的 API。

超人类云 AI 引擎的时代已经到来。OpenAI 的 API 不需要高级软件技能或 AI 知识。你可能想知道为什么我使用了“超人类”这个词。你会发现,在许多情况下,GPT-3 引擎可以执行许多任务,就像人类一样。目前,理解 GPT 模型是如何构建和运行的是至关重要的。

本章将首先研究Transformers模型的架构和规模的演变。我们将探讨使用经过训练的Transformers模型进行零次调优的挑战,对模型的参数进行几乎没有或没有任何调优的下游任务。我们将探讨 GPT Transformers模型的创新架构。OpenAI 提供了他们模型的特别训练版本,称为引擎。

我们将使用 OpenAI 仓库中的 TensorFlow 中的 345M 参数的 GPT-2 Transformers。我们必须亲自动手去理解 GPT 模型。我们将与模型进行交互,以生成通用调节句子的文本补全。

我们将继续使用一个 117M 参数的定制 GPT-2 模型。我们将对我们在第四章,从零开始预训练 RoBERTa 模型中使用的高级概念 Kant 数据集进行标记化。

该章节将探讨使用一个不需要数据科学家、人工专家甚至是经验丰富的开发人员就可以开始使用的 GPT-3 引擎。然而,这并不意味着在今后不会需要数据科学家或人工智能专家。

我们将看到 GPT-3 引擎有时确实需要微调。我们将运行一个 Google Colab 笔记本来微调一个 GPT-3 Ada 引擎。

该章节将以工业 4.0 AI 专家的新思维方式和技能集结束。

在本章结束时,你将了解到一个 GPT 模型是如何构建的,以及如何使用无缝的 GPT-3 API。你将理解到在 2020 年代,一个工业 4.0 的 AI 专家可以完成令人满意的任务!

本章涵盖以下主题:

  • 开始使用 GPT-3 模型

  • OpenAI GPT 模型的架构

  • 定义零次训练的Transformers模型

  • 从少次到一次的路径

  • 构建一个接近人类的 GPT-2 文本补全模型

  • 实现一个 345M 参数的模型并运行它

  • 与一个标准模型交互使用 GPT-2

  • 训练一个具有 117M 参数模型的语言建模 GPT-2

  • 导入一个定制的特定数据集

  • 对一个定制数据集进行编码

  • 对模型进行条件调节

  • 条件转换一个 GPT-2 模型以执行特定的文本完成任务

  • 对一个 GPT-3 模型进行微调

  • 工业 4.0 人工智能专家的角色

让我们通过探索 GPT-3 转换器模型开始我们的旅程。

使用 GPT-3 转换器模型进行超人类 NLP

GPT-3 建立在 GPT-2 架构之上。然而,一个完全训练的 GPT-3 转换器是一个基础模型。基础模型可以执行许多它没有训练过的任务。GPT-3 完成应用于所有 NLP 任务甚至编程任务。

GPT-3 是少数几个符合基础模型资格的完全训练的转换器模型之一。GPT-3 毫无疑问将产生更强大的 OpenAI 模型。Google 将为其在超级计算机上训练的 Google BERT 版本之外的基础模型提供更多。基础模型代表了对人工智能的一种新思考方式。

公司很快就会意识到,他们不需要数据科学家或人工智能专家才能开始一个具有像 OpenAI 提供的 API 那样的 NLP 项目。

为什么还要麻烦使用任何其他工具?拥有访问世界上最强大的超级计算机之一上训练过的最有效的转换器模型之一的 OpenAI API。

如果存在只有深腰包和世界上最好的研究团队才能设计的 API,比如 Google 或 OpenAI,为什么要开发工具、下载库或使用任何其他工具?

对于这些问题的答案非常简单。启动 GPT-3 引擎就像启动一辆一级方程式赛车或印第 500 赛车一样简单。没问题。但是,要驾驶这样的车几乎是不可能的,如果没有几个月的培训!GPT-3 引擎是强大的人工智能赛车。你可以通过几次点击让它们运行。然而,要掌握它们令人难以置信的动力需要你从本书的开始到现在所学到的知识,以及你将在接下来的章节中发现的东西!

我们首先需要了解 GPT 模型的架构,以了解开发者、人工智能专家和数据科学家在超人类 NLP 模型时代的定位。

OpenAI GPT 转换器模型的架构

在 2017 年底至 2020 年初的不到三年时间里,转换器模型从训练、微调,最终到零冲击模型。零冲击 GPT-3 转换器模型不需要微调。训练的模型参数不会为下游多任务更新,这为 NLP/NLU 任务开启了一个新时代。

在本部分中,我们将首先了解设计 GPT 模型的 OpenAI 团队的动机。我们将从零冲击模型的微调开始。然后我们将看到如何使一个转换器模型调节以生成令人惊叹的文本完成。最后,我们将探索 GPT 模型的架构。

我们首先将了解 OpenAI 团队的创建过程。

十亿参数Transformers模型的崛起

Transformers从用于自然语言处理任务的小型模型迅速发展到几乎不需要微调的模型的速度令人震惊。

瓦斯瓦尼等人(2017 年)介绍了Transformers,它在 BLEU 任务中超越了 CNN 和 RNN。 拉德福德等人(2018 年)引入了生成式预训练(GPT)模型,可以通过微调执行下游任务。 德夫林等人(2019 年)通过 BERT 模型完善了微调。 拉德福德等人(2019 年)进一步推出了 GPT-2 模型。

布朗等人(2020 年)定义了一个 GPT-3 零-shot 方法来处理Transformers,不需要微调!

同时,王等人(2019 年)创建了 GLUE 来评估自然语言处理模型。但是Transformers模型发展如此迅速,以至于超过了人类基线!

王等人(2019 年,2020 年)迅速创建了 SuperGLUE,将人类基线设定得更高,并使得 NLU/NLP 任务更具挑战性。Transformers发展迅速,一些模型在写作时已经超越了 SuperGLUE 排行榜上的人类基线。

这是如何如此迅速地发生的?

我们将研究一个方面,即模型的大小,以了解这种演变是如何发生的。

Transformers模型尺寸的增加

仅在 2017 年至 2020 年,参数数量就从原始Transformers模型的 65M 个增加到了 GPT-3 模型的 175B 个,如表 7.1所示:

Transformers模型 论文 参数
Transformers基础 瓦斯瓦尼等人(2017 年) 65M
Transformers大型 瓦斯瓦尼等人(2017 年) 213M
BERT-Base 德夫林等人(2019 年) 110M
BERT-Large 德夫林等人(2019 年) 340M
GPT-2 拉德福德等人(2019 年) 117M
GPT-2 拉德福德等人(2019 年) 345M
GPT-2 拉德福德等人(2019 年) 1.5B
GPT-3 布朗等人(2020 年) 175B

表 7.1:Transformers参数数量的演变

表 7.1只包含了那个短时间内设计的主要模型。出版日期在实际设计模型的日期之后。此外,作者还更新了论文。例如,一旦原始Transformers启动了市场,谷歌 Brain、OpenAI 和 Facebook AI 等机构都推出了新模型。

此外,一些 GPT-2 模型比较较小的 GPT-3 模型还要大。例如,GPT-3 Small 模型包含 125M 个参数,比 345M 参数的 GPT-2 模型小。

架构大小同时也在演变:

  • 一个模型的层数从原始Transformers模型的 6 层增加到了 GPT-3 模型的 96 层

  • 一个层的头数从原始Transformers模型的 8 个增加到了 GPT-3 模型的 96 个

  • 原始Transformers模型的上下文大小从 512 个令牌增加到了 GPT-3 模型的 12,288 个令牌

模型架构的规模解释了为什么具有 96 层的 GPT-3 175B 模型比只有 40 层的 GPT-2 1,542M 模型产生了更令人印象深刻的结果。这两种模型的参数可比拟,但层数倍增了。

让我们关注一下上下文大小,以了解 transformer 的快速演变的另一个方面。

上下文大小和最大路径长度

transformer 模型的基础在于注意力子层。而注意力子层的关键属性则是处理上下文大小的方法。

上下文大小是人类和机器学习语言的主要方式之一。上下文大小越大,我们就能越好地理解呈现给我们的序列。

然而,上下文大小的缺点是理解一个词所指内容所需的距离。分析长期依赖性所需的路径需要从循环转换为注意力层。

以下句子需要经过很长的路径才能找到“它”所指的内容:

“我们的房子太小了,无法容纳一张大沙发,一张大桌子和我们想在如此小的空间中放置的其他家具。我们考虑过留下一段时间,但最终决定把它卖掉。”

如果要解释“它”的意思,只有在回到句子开头的“房子”一词时才能理解。这对于机器来说是一段相当长的路径!

定义最大路径长度的函数顺序如 Big O 表 7.2 中所示:

层类型 最大路径长度 上下文大小
自注意力 0(1) 1
循环 0(n) 100

表 7.2:最大路径长度

Vaswani 等人(2017)对原始 Transformer 模型中的上下文分析设计进行了优化。自注意力将操作缩减为一对一的标记操作。所有层都相同,这使得扩大 transformer 模型的规模变得更加容易。具有 100 个上下文窗口大小的 GPT-3 模型具有与大小为 10 的上下文窗口大小相同的最大长度路径。

例如,RNN 中的一个循环层必须逐步存储整个上下文的长度。最大路径长度就是上下文大小。处理 GPT-3 模型的上下文大小的 RNN 的最大长度大小将是 0(n) 倍长。此外,RNN 无法将上下文分割成 96 个在并行化机器架构上运行的头,例如将操作分布在 96 个 GPU 上。

transformer 的灵活和优化的架构对其他几个因素产生了影响:

  • Vaswani 等人(2017)训练了一个包含 36M 个句子的最新 transformer 模型。Brown 等人(2020)则从 Common Crawl 数据中提取了 4000 亿字节对编码的标记来训练 GPT-3 模型。

  • 训练大型 transformer 模型需要世界上一小部分团队才拥有的计算机实力。Brown 等人(2020)训练 GPT-3 175B 需要总共 2.14*10²³ FLOPS。

  • 设计转换器的架构需要高素质的团队,这些团队只能由世界上少数机构资助。

大小和架构将继续发展,可能在不久的将来增加到万亿参数模型。超级计算机将继续提供必要的资源来训练转换器。

我们现在将看到零-shot 模型是如何实现的。

从微调到零-shot 模型

从一开始,由Radford等人(2018 年)带领的 OpenAI 研究团队就希望把转换器从经过训练的模型转变为 GPT 模型。其目标是在未标记数据上训练转换器。让注意层从无监督数据中学习语言是一个聪明的举措。OpenAI 决定训练转换器学习语言,而不是教会它们执行特定的 NLP 任务。

OpenAI 希望创建一个任务无关的模型。因此,他们开始对原始数据进行转换器模型的训练,而不是依赖专家标记的数据。标记数据耗时,并且显著减慢了转换器的训练过程。

第一步是从一个转换器模型的无监督训练开始。然后,他们只会对模型进行监督学习的微调。

OpenAI 选择了在“叠加解码层”部分描述的只解码转换器。结果的度量是令人信服的,并很快达到了同行 NLP 研究实验室最佳 NLP 模型水平。

第一个版本的 GPT 转换器模型的有希望的结果很快就促使Radford等人(2019 年)提出了零-shot 转移模型。他们的核心哲学是继续训练 GPT 模型从原始文本中学习。然后,他们进一步深入研究,聚焦于通过无监督分布的语言建模示例:

示例=(x₁, x₂, x₃, ,xₙ)

示例由符号序列组成:

序列=(s₁, s₂, s₃, ,sₙ)

这导致了一个可以表示为任何类型输入的概率分布的元模型:

p (输出/输入)

目标是一旦训练的 GPT 模型通过深入训练理解了语言,就将这个概念推广到任何类型的下游任务。

GPT 模型从 117M 参数迅速发展到 345M 参数,然后到其他大小,然后到 1,542M 参数。10 亿+参数的转换器诞生了。微调量急剧减少。结果再次达到了最先进的指标。

这鼓励 OpenAI 更进一步,更远。Brown等人(2020 年)假设有条件概率转换器模型可以进行深度训练,并且能够在几乎不进行进一步微调的情况下产生出色的结果:

p (输出/多任务)

OpenAI 正在实现其目标,即训练模型,然后直接运行下游任务,而无需进一步微调。这一巨大的进步可以分为四个阶段:

  • 微调(FT)是指按照我们在之前章节探讨过的方式进行。一个Transformers模型被训练,然后在下游任务上进行微调。Radford等人(2018 年)设计了许多微调任务。然后,OpenAI 团队在接下来的步骤中逐渐将任务数减少到0。

  • 少样本(FS)代表了一个巨大的进步。GPT 已经训练好了。当模型需要进行推理时,它会以任务的演示为条件。条件替代了权重更新,GPT 团队在过程中排除了这一步骤。我们将通过我们在本章中将要进行的笔记本中提供的上下文来对我们的模型进行条件设定,以获得文本完成。

  • 单样本(1S)将进程推至更远。训练后的 GPT 模型仅需要一个下游任务的演示来表现。同时也不允许进行权重更新。

  • 零样本(ZS)是最终目标。训练后的 GPT 模型在没有演示所需下游任务的情况下进行表现。

这些方法各自具有不同的效率水平。OpenAI GPT 团队已经努力开发出这些最先进的Transformers模型。

现在我们可以解释导致 GPT 模型架构的动机:

  • 教授Transformers模型如何通过广泛的培训学习语言。

  • 通过上下文条件对语言建模进行重点关注。

  • Transformers以一种新颖的方式接受上下文并生成文本完成。它不会浪费资源学习下游任务,而是致力于理解输入并进行推理,无论任务是什么。

  • 找到训练模型的高效方法,通过掩盖输入序列的部分来迫使Transformers以机器智能的方式进行思考。因此,尽管不是人类,但机器智能是高效的。

我们了解到了导致 GPT 模型架构的动机。现在让我们来看看仅解码器层的 GPT 模型。

堆叠解码器层

现在我们明白了 OpenAI 团队专注于语言建模。因此,保留掩盖注意力子层是有意义的。因此,选择保留解码器堆叠并排除编码器堆叠的选择。Brown等人(2020 年)显著增加了仅解码器Transformers模型的规模,取得了出色的结果。

GPT 模型的结构与Vaswani等人(2017 年)设计的原始Transformers的解码器堆栈相同。我们在第二章中描述了解码器的堆栈,开始使用Transformers模型的架构。如果需要的话,请花几分钟回顾一下原始Transformers的架构。

GPT 模型具有仅解码器的架构,如图 7.1所示:

图 7.1:GPT 仅解码器架构

我们可以识别文本和位置嵌入子层、蒙版多头自注意层、规范化子层、前馈子层和输出。此外,还有一种同时进行文本预测和任务分类的 GPT-2 版本。

OpenAI 团队通过模型定制和调整了解码模型。Radford 等人(2019)给出了至少四种 GPT 模型,Brown 等人(2020)描述了至少八种模型。

GPT-3 175B 模型已经达到了很少团队可以访问的独特规模,需要大量的计算资源:

n[参数] = 175.0B,n[层数] = 96,d[模型] = 12288,$1$2 = 96

让我们看看越来越多的 GPT-3 引擎。

GPT-3 引擎

GPT-3 模型可以被训练来完成不同规模的特定任务。目前 OpenAI 记录了可用的引擎列表:beta.openai.com/docs/engines

基本系列的引擎具有不同的功能 - 例如:

  • 达芬奇引擎能够分析复杂意图

  • 居里引擎速度快,具有很好的摘要能力

  • 巴比奇引擎擅长语义检索

  • 阿达引擎擅长解析文本

OpenAI 正在生产更多的引擎投放市场:

  • Instruct 系列根据描述提供指令。此章节的 更多 GPT-3 示例 中有一个例子可供参考。

  • Codex 系列可以将语言翻译成代码。我们将在 第十六章 Transformer 驱动合作伙伴的出现 中探索这个系列。

  • 内容过滤系列可以过滤不安全或敏感的文本。我们将在 第十六章 Transformer 驱动合作伙伴的出现 中探索这个系列。

我们已经探索了从微调到零样本 GPT-3 模型的过程。我们已经看到 GPT-3 可以生成各种引擎。

现在是时候看看 GPT 模型的源代码是如何构建的。尽管目前 GPT-3 Transformers模型的源代码并不公开,但 GPT-2 模型已经足够强大,可以理解 GPT 模型的内部工作原理。

我们已经准备好与 GPT-2 模型进行交互和训练。

我们首先将使用训练好的 GPT-2 345M 模型进行文本完成,它包括 24 个解码层和 16 个自注意子层的自注意。

然后,我们将对 12 个解码层和 12 个自注意层的 GPT-2 117M 模型进行定制文本完成训练。

让我们首先与一个预训练的 345M 参数 GPT-2 模型进行交互。

使用 GPT-2 进行通用文本完成

我们将从上到下探讨使用 GPT-2 通用模型的例子。我们要运行的例子的目标是确定 GPT 模型能达到的抽象推理水平。

本节描述了与 GPT-2 模型进行文本完成的交互。我们将重点关注 OpenAI_GPT_2.ipynb 中详细描述的 附录 III 中的 使用 GPT-2 进行通用文本完成的第 9 步。

你可以先阅读本节,看看通用预训练的 GPT-2 模型对特定示例的反应如何。然后阅读 附录 III,使用 GPT-2 进行通用文本补全,以深入了解通用 GPT-2 模型如何在 Google Colab 笔记本中实现。

你也可以直接阅读 附录 III,其中包含下面描述的 Step 9 的交互。

首先,让我们了解应用预训练 GPT-2 的具体示例。

第 9 步:与 GPT-2 交互

在本节中,我们将与 GPT-2 345M 模型进行交互。

要与模型交互,请运行 interact_model 单元格:

#@title Step 9: Interacting with GPT-2
interact_model('345M',None,1,1,300,1,0,'/content/gpt-2/models') 

你将被提示输入一些上下文:

图 7.2:文本补全的上下文输入

你可以尝试任何类型的上下文,因为这是一个标准的 GPT-2 模型。

我们可以尝试一句由康德写的句子:

Human reason, in one sphere of its cognition, is called upon to
consider questions, which it cannot decline, as they are presented by
its own nature, but which it cannot answer, as they transcend every
faculty of the mind. 

按下 Enter 生成文本。由于 GPT-2 模型未在我们的数据集上进行训练,并且我们无论如何都在运行随机模型,因此输出将相对随机。

让我们看看我运行时 GPT 模型生成的前几行:

"We may grant to this conception the peculiarity that it is the only causal logic. 
In the second law of logic as in the third, experience is measured at its end: apprehension is afterwards closed in consciousness.
The solution of scholastic perplexities, whether moral or religious, is not only impossible, but your own existence is blasphemous." 

要停止单元格,请双击单元格的运行按钮。

你还可以按下 Ctrl + M 停止生成文本,但这可能会将代码转换为文本,你将不得不将其复制回程序单元格。

输出丰富。我们可以观察到几个事实:

  • 我们输入的上下文 条件了 模型生成的输出。

  • 上下文是模型的演示。它从上下文中学习要说什么,而不修改其参数。

  • 文本补全受上下文条件限制。这为不需要微调的转换器模型打开了大门。

  • 从语义角度来看,输出可能更有趣。

  • 从语法角度来看,输出是令人信服的。

我们能做得更好吗?下一节介绍了自定义文本补全的交互。

训练自定义 GPT-2 语言模型

在本节中,我们将继续采用自上而下的方法,探讨一个在特定数据集上训练的 GPT-2 自定义模型的示例。目标仍然是确定 GPT 模型可以达到的抽象推理水平。

本节描述了与特定数据集训练的 GPT-2 模型进行文本补全的交互。我们将重点放在详细描述在 附录 IV 中的 Training_OpenAI_GPT_2.ipynb 笔记本中的 Step 12,即 自定义文本补全与 GPT-2。

你可以先阅读本节,看看带有自定义 GPT-2 模型的示例将如何改进响应。然后阅读 附录 IV,自定义文本补全与 GPT-2,以了解如何训练 GPT-2 来获得特定的响应。

你也可以决定直接阅读 附录 IV,其中也包含下面描述的 Step 12 的交互。

首先,让我们了解通过训练 GPT-2 改进的交互方式。

第 12 步:交互式上下文和补全示例

现在我们将运行一个有条件的样本。我们输入的上下文将导致模型按照我们想要的方式思考,通过生成定制的段落来完成文本。

运行单元格并探索魔法:

#@title Step 12: Interactive Context and Completion Examples
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src")
!python interactive_conditional_samples.py --temperature 0.8 --top_k 40 --model_name '117M' 

如果需要,可以花几分钟回到附录 III的第 9 步,与 GPT-2 交互,以查看响应的差异。该程序提示我们输入上下文:

图 7.3:文本补全的上下文输入

让我们输入与易卢泊儿·康德所写的相同段落,就像我们在本章的通用 GPT-2 的文本补全部分的第 9 步中所做的那样:

Human reason, in one sphere of its cognition, is called upon to
consider questions, which it cannot decline, as they are presented by
its own nature, but which it cannot answer, as they transcend every
faculty of the mind. 

按Enter生成文本,就像我们之前所做的那样。尽管结构化和逻辑,但输出可能会因为每次运行而有所不同,这使得Transformers很有吸引力。这一次,结果并不是随机的,而是令人印象深刻的。

让我们来看看 GPT-2 模型生成的前几行:

"Now, what is the nature of the reason, except that it is of a kind and power of mind that is so called on to think, and to understand?
The reason is the thing which apprehends, and seeks to understand, the objects of its minds, which apprehend and apprehend the things of itself. No one can speak of this reason without the understanding and the understanding of the human reason. But that knowledge and understanding which is the most natural of all the faculties, which, because it is understood by the human reason, is the most natural of all the faculties, is not without reason, but only without understanding. The human reason, who sees and knows the things which the natural sense, which, though in the natural sense, does not understand, is the source of every other knowledge which we understand. The reason is the thing which does not understand, but understands the things which we comprehend, and therefore, is not to be understood. I mean that the reason is the thing which does not understand, but knows only the things which we do understand…." 

要停止运行单元格,请双击单元格的运行按钮或按下Ctrl + M。

哇!我怀疑有人能看出我们训练过的 GPT-2 模型生成的文本补全和人类的区别。它也可能在每次运行时生成不同的输出。

实际上,我认为我们的模型在哲学、推理和逻辑的抽象练习中,可能会超越许多人类!

我们可以从我们的实验中得出一些结论:

  • 经过良好训练的Transformers模型能以人类水平产生文本补全

  • 在复杂和抽象推理中,GPT-2 模型几乎可以达到人类水平的文本生成能力

  • 文本背景是通过演示预期结果的一种有效的方式来给模型制定条件

  • 文本补全是基于文本条件的文本生成,如果提供了上下文的句子。

您可以输入条件文本背景示例来尝试文本补全。您还可以使用自己的数据来训练模型。只需用自己的数据替换dset.txt文件的内容,看看会发生什么!

请记住我们训练过的 GPT-2 模型会像人类一样反应。如果您输入一个简短、不完整、无趣或棘手的上下文,您将得到困惑或糟糕的结果。这是因为 GPT-2 希望我们做到最好,正如现实生活中一样!

让我们去 GPT-3 playground 看看训练过的 GPT-3 对使用 GPT-2 测试的示例做出何种反应。

运行 OpenAI GPT-3 任务

在本节中,我们将以两种不同的方式运行 GPT-3:

  • 我们将首先在线运行 GPT-3 任务而不需要任何代码

  • 然后我们将在 Google Colab 笔记本中实现 GPT-3

在本书中我们将使用 GPT-3 引擎。当您注册 GPT-3 API 时,OpenAI 会提供您一个免费的预算来开始使用。这个免费预算应该足以覆盖这本书中示例的大部分成本,如果不是全部。

让我们从在线运行 NLP 任务开始。

在线运行 NLP 任务

我们现在将不使用 API 直接向 GPT-3 提出要求,让我们来看看一些工业 4.0 的例子。

让我们定义一种提示和回应的标准结构,如下:

  • N = NLP 任务的名称(输入)。

  • E = GPT-3 引擎的解释。E 在 T 之前(输入)。

  • T = 我们希望 GPT-3 查看的文本或内容(输入)。

  • S = 显示给 GPT-3 期望的内容。S 在必要时跟随 T 并添加(输入)。

  • R = GPT-3 的回应(输出)。

上述提示的结构是一个指南。然而,GPT-3 非常灵活,有许多变体可行。

我们现在准备在线运行一些教育示例,无需 API:

  • 现有知识的问题与答案(Q&A):

    E = Q

    T = 1965 年美国总统是谁?

    S = 无

    R = A

    提示和回答:

    Q: 1965 年美国总统是谁?

    A: 1965 年林登·约翰逊是美国总统。

    Q: 谁是第一个登上月球的人类?

    A: 尼尔·阿姆斯特朗是第一个登上月球的人类。

  • 电影到表情符号:

    E = 一些电影标题的示例

    T = 无

    S = 通过例子隐含

    R = 一些表情符号的示例

    提示和回答:

    包含文本的图片的图片描述 自动生成

    新的提示和回答:

  • 给二年级学生总结(给二年级学生总结):

    E = 我的二年级孩子问我这段话是什么意思:

    T = """初始结论……。"""

    S = 我用通俗易懂的语言给他解释了一下:"""

    R = 摘要

    提示和回答:

    我的二年级孩子问我这段话是什么意思:

    """初始结论可以分为两类:事实和虚构。事实是 OpenAI 拥有世界上最强大的自然语言处理服务之一。主要事实是:OpenAI 引擎是强大的零-shot,无需寻找各种Transformers模型,无需预训练和微调。用于训练模型的超级计算机是独一无二的。如果提示设计得当,我们会得到令人惊讶的准确响应。在本节中实施 NLP 任务需要执行复制粘贴操作,任何软件初学者都可以执行。虚构从反乌托邦和炒作的断言开始,AI 将取代数据科学家和 AI 专家。这是真的吗?在回答这个问题之前,首先问问自己关于我们刚刚运行的示例的以下问题:我们如何知道句子起初是错误的?如果没有我们人类读取和确认,我们如何知道答案是正确的?引擎是如何知道这是一个语法校正任务的?如果响应不正确,我们如何理解发生了什么以帮助改进提示或在设计良好的人机界面中恢复手动模式?事实是人类将需要手动干预来回答这些问题,使用基于规则的方法、质量控制自动流水线以及许多其他工具。事实是令人信服的。运行 NLP 任务确实需要很少的开发。虚构不令人信服。人类仍然是必需的。OpenAI 引擎并不是为了取代人类,而是为了帮助他们执行更多高水平的令人满足的任务。现在你可以驾驶喷气机而不必自己建造它!"""

    我为他重新表述了一下,用小学二年级孩子都能理解的简单语言:"""

    OpenAI 的第一个结论是,它拥有世界上最强大的自然语言处理服务之一。最重要的事实是:OpenAI 引擎非常强大,零-shot,无需寻找各种Transformers模型,无需预训练和微调。用于训练模型的超级计算机是独一无二的。如果提示设计得当,我们会得到令人惊讶的准确响应。

结果令人印象深刻,是自然语言处理历史上的一大进步。

我们可以使用由 OpenAI 提供的零-shot GPT-3 引擎实现的 NLP 任务的数量是无穷无尽的,因为我们控制着如何展示我们对Transformers模型的期望。

然而,真正的行业 4.0 人工智能专家必须在使用即用型 API 之前先动手。我们现在将探索 OpenAI GPT 模型的架构,然后构建 GPT-2 模型,看看这些引擎是如何工作的。

我们对 GPT 模型了解得越多,行业 4.0 的自然语言处理专家就越能将它们应用到现实项目中。

让我们继续我们的自上而下的方法,深入研究 OpenAI GPT Transformers模型的架构。

使用 GPT-3 引擎入门

OpenAI 拥有世界上一些最强大的Transformers引擎。一个 GPT-3 模型可以执行数百个任务。GPT-3 可以完成许多它没有接受训练的任务。

本节将在Getting_Started_GPT_3.ipynb中使用 API。

要使用 GPT-3,您必须首先转到 OpenAI 的网站openai.com/并注册。

OpenAI 为每个人提供了一个试验场,就像 Google 翻译或任何用户友好型在线服务一样。因此,让我们尝试一些任务。

运行我们的第一个 NLP 任务与 GPT-3

让我们从几个步骤开始使用 GPT-3。

转到 Google Colab 并打开 GitHub 上书籍的章节目录Getting_Started_GPT_3.ipynb。

您无需更改笔记本的设置。我们正在使用一个 API,因此在本节中不需要太多的本地计算能力。

本节的步骤与笔记本中的步骤相同。

运行 NLP 分为三个简单的步骤:

步骤 1:安装 OpenAI

使用以下命令安装openai:

try:
  import openai
except:
  !pip install openai
  import openai 

如果未安装openai,则必须重新启动运行时。当需要这样做时,会显示一条消息,如下所示:

自动生成的文本描述

重新启动运行时,然后再次运行此单元格,以确保已导入openai。

步骤 2:输入 API 密钥

提供了一个可以在 Python、C#、Java 和许多其他选项中使用的 API 密钥。在本节中,我们将使用 Python:

openai.api_key=[YOUR API KEY] 

您现在可以使用您的 API 密钥更新下一个单元格:

import os
import openai
os.environ['OPENAI_API_KEY'] ='[YOUR_KEY or KEY variable]'
print(os.getenv('OPENAI_API_KEY'))
openai.api_key = os.getenv("OPENAI_API_KEY") 

现在让我们运行一个 NLP 任务。

步骤 3:使用默认参数运行 NLP 任务

我们复制并粘贴了一个 OpenAI 的语法校正任务示例:

response = openai.Completion.create(
 engine="davinci",
 prompt="Original: She no went to the market.\nStandard American English:",
  temperature=0,
  max_tokens=60,
  top_p=1.0,
  frequency_penalty=0.0,
  presence_penalty=0.0,
  stop=["\n"]
) 

任务是纠正这个语法错误:She no went to the market。

我们可以通过解析来按需处理响应。OpenAI 的响应是一个字典对象。OpenAI 对象包含了有关任务的详细信息。我们可以要求该对象显示:

#displaying the response object
print(response) 

我们可以探索对象:

{
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "logprobs": null,
      "text": " She didn't go to the market."
    }
  ],
  "created": 1639424815,
  "id": "cmpl-4ElZfXLl9jGRNQoojWRRGof8AKr4y",
  "model": "davinci:2020-05-03",
  "object": "text_completion"} 

“创建”的编号和“id”,以及“model”名称在每次运行时都可能会有所不同。

然后,我们可以要求对象字典显示“text”,并打印处理后的输出:

#displaying the response object
r = (response["choices"][0])
print(r["text"]) 

字典中的“text”的输出是语法正确的句子:

She didn't go to the market. 

NLP 任务和示例

现在我们将介绍一种工业化的 GPT-3 引擎使用方法。例如,OpenAI 提供了一个交互式教育界面,不需要 API。因此,一个学校教师、顾问、语言学家、哲学家或任何希望将 GPT-3 引擎用于教育目的的人都可以这样做,而且完全不需要 AI 方面的经验。

我们首先将在笔记本中使用 API。

语法校正

如果我们回到Getting_Started_GPT_3.ipynb,我们可以在本章的开始使用 GPT-3 引擎部分开始探索的内容中,用不同的提示语试验语法校正。

打开笔记本,转到步骤 4:示例 1:语法校正:

#Step 6: Running an NLP task with custom parameters
response = openai.Completion.create(
  #defult engine: davinci
  engine="davinci",
  #default prompt for task:"Original"
  prompt="Original: She no went to the market.\n Standard American English:",
  temperature=0, 
  max_tokens=60,
  top_p=1.0,
  frequency_penalty=0.0,
  presence_penalty=0.0,
  stop=["\n"]
) 

请求体不限于提示。请求体包含几个关键参数:

  • engine="davinci"。选择要使用的 OpenAI GPT-3 引擎,以及将来可能的其他模型。

  • temperature=0。像0.9这样的较高值会促使模型更冒险。不要同时修改 temperature 和top_p。

  • max_tokens=60。响应的最大 token 数。

  • top_p=1.0。另一种控制抽样的方法,类似于temperature。在这种情况下,top_p的百分比的 token 概率质量将被考虑。0.2会使系统仅考虑 20%的最高概率质量。

  • frequency_penalty=0.0。值介于0和1之间,限制了给定响应中 token 的频率。

  • presence_penalty=0.0。值介于0和1之间,强制系统使用新 token 并产生新想法。

  • stop=["\n"]。向模型发出停止生成新 token 的信号。

这些参数中的一些在附录 III,使用 GPT-2 进行通用文本完成中的步骤 7b-8:导入和定义模型部分以源代码级别进行描述。

如果你获得访问权限,你可以在 GPT-3 模型中或在附录 III,使用 GPT-2 进行通用文本完成中的 GPT-2 模型中玩弄这些参数。在这两种情况下概念是相同的。

本节将专注于提示:

`prompt="Original: She no went to the market.\n Standard American English:"` 

提示可以分为三个部分:

  • 原始:这表明模型接下来将处理的是原始文本,模型将对其进行某种处理

  • 她没去市场。\n:提示的这部分向模型表明这是原始文本

  • 标准美式英语:这向模型显示了期望的任务是什么

让我们看看通过改变任务我们能达到什么程度:

  • 标准美式英语产生:

    prompt="原始:她没去市场。\n 标准美式英语:"

    响应中的文本是:

    "text": " 她没去市场。"

    那很好,但如果我们不想要句子中的缩写呢?

  • 不带缩写的英语产生:

    prompt="原始:她没去市场。\n 不带缩写的英语:"

    响应中的文本是:

    "text": " 她没有去市场。"

    哇!这很令人印象深刻。让我们尝试另一种语言。

  • 没有缩写的法语产生:

    "text": " 她没有去市场。"

    这很令人印象深刻。\u00e9只需进行后处理成é。

还有更多选项可供选择。您的工业 4.0 跨学科想象力是极限!

更多的 GPT-3 示例

OpenAI 包含许多示例。OpenAI 提供了一个在线平台来探索任务。OpenAI 还为每个示例提供了源代码:beta.openai.com/examples

点击一个示例,比如我们在语法纠错部分探讨过的语法示例:

图形用户界面,文本,应用程序 自动生成描述

图 7.4:OpenAI 的语法纠错部分

OpenAI 将为每个任务描述提示和样本响应。

图形用户界面,文本,应用程序 自动生成描述

图 7.5:样本响应纠正了提示

你可以选择去游乐场在线运行,就像我们在本章的 在线运行 NLP 任务 部分中所做的那样。要这样做,请单击 在游乐场中打开 按钮:

图形用户界面、应用程序、聊天或文本消息 自动生成的描述

图 7.6:游乐场按钮中的 Open

你可以选择复制并粘贴代码来运行 API,就像我们在本章的 Google Colab 笔记本中所做的那样:

文本 自动生成的描述

图 7.7:使用 Davinci 引擎运行代码

Getting_Started_GPT_3.ipynb 包含了十个示例,你可以运行以练习实现 OpenAI GPT-3。

对于每个示例:

  • 首先,你可以阅读由 OpenAI 提供的解释链接。每个单元格上方都提供了文档链接。

  • 你可以运行单元格以观察 GPT-3 的行为。

在笔记本中运行这十个示例:

  • 示例 1:语法纠正

  • 示例 2:英语到法语的翻译

  • 示例 3:提供说明的系列

  • 示例 4:电影到表情符号

  • 示例 5:将编程语言转换为另一种语言。例如,从 Python 到 JavaScript。警告:你可能需要获得 OpenAI 的特别许可才能运行这个示例,该示例使用了 Davinci Codex 引擎,即代码生成器。如果此示例在你的笔记本中无法运行,请联系 OpenAI 请求 Codex 的访问权限。

  • 示例 6:高级推文分类器

  • 示例 7:问答

  • 示例 8:总结一段文本

  • 示例 9:解析非结构化数据

  • 示例 10:计算时间复杂度

你可以在示例页面上运行许多其他任务:beta.openai.com/examples

现在让我们比较一下 GPT-2 和 GPT-3 的输出。

比较 GPT-2 和 GPT-3 的输出

在我们继续之前,我们的好奇心必须得到满足。强大的 GPT-3 模型可以使用我们提交给预训练 GPT-2 模型的示例,然后使用我们自定义训练的 GPT-2 模型产生什么?

我们用于 GPT-2 模型的示例:

`Human reason, in one sphere of its cognition, is called upon to consider questions, which it cannot decline, as they are presented by its own nature, but which it cannot answer, as they transcend every faculty of the mind.` 
`GPT-3's response:`
`What is meant by this is that there are some things in our experience that are beyond reason. It is not that reason is a bad guide or is insufficient, but that there are some things that are beyond its reach. An example of this would be the existence of God.` 

结果令人震惊!它解释了文本的含义,包括一些深刻的哲学思考!

我们在本章证明了我们的观点。Transformer 模型可以实现抽象推理,这有助于在我们飞速发展的世界中做出微决策。

OpenAI GPT-3 是一个完全训练好的模型。但是,GPT-3 可以进行微调。我们来看看如何进行微调。

对 GPT-3 进行微调

本节展示了如何对 GPT-3 进行微调以学习逻辑。Transformer 需要学习逻辑、推理和蕴含,以便以人类水平理解语言。

微调是使 GPT-3 成为你自己应用的关键,是将其定制为适应项目需求的钥匙。这是一个赋予你的应用 AI 自由的机会,以消除偏见,教它你想让它知道的东西,并在 AI 上留下你的足迹。

在本节中,将使用 kantgpt.csv 对 GPT-3 进行 Immanuel Kant 的作品进行训练。我们使用了类似的文件来训练第四章 从头开始预训练 RoBERTa 模型 中的 BERT 类型模型。

一旦掌握了对 GPT-3 进行微调的技巧,就可以使用其他类型的数据来教授它特定领域、知识图和文本。

OpenAI 提供了一个高效、文档完善的服务,可以对 GPT-3 引擎进行微调。它已经训练了 GPT-3 模型,使其成为不同类型的引擎,正如本章中十亿参数Transformers模型的崛起部分所示。

Davinci 引擎功能强大,但使用起来可能更昂贵。Ada 引擎成本较低,并且产生的结果足以在我们的实验中探索 GPT-3。

GPT-3 的微调涉及两个阶段:

  • 准备数据

  • 对 GPT-3 模型进行微调

准备数据

在 GitHub 章节目录中在 Google Colab 中打开Fine_Tuning_GPT_3.ipynb。

OpenAI 详细记录了数据准备过程:

beta.openai.com/docs/guides/fine-tuning/prepare-training-data

第 1 步:安装 OpenAI

第 1 步 是安装和导入openai:

try:
  import openai
except:
  !pip install openai
  import openai 

一旦安装完成,请重新启动运行时,然后再次运行单元格,确保已执行import openai。

import openai 

您也可以安装 wand 来可视化日志:

try:
  import wandb
except:
  !pip install wandb
  import wandb 

现在我们将输入 API 密钥

第 2 步:输入 API 密钥

第 2 步 是输入您的密钥:

openai.api_key="[YOUR_KEY]" 

第 3 步:激活 OpenAI 的数据准备模块

首先,加载您的文件。在此部分加载kantgpt.csv。现在,kantgpt.csv.是一个原始的非结构化文件。OpenAI 有一个内置数据清理器,会在每个步骤问问题。

OpenAI 检测到文件是 CSV 文件,将其转换为JSONL文件。JSONL包含纯结构化文本中的行。

OpenAI 跟踪我们批准的所有更改:

Based on the analysis we will perform the following actions:
- [Necessary] Your format 'CSV' will be converted to 'JSONL'
- [Necessary] Remove 27750 rows with empty completions
- [Recommended] Remove 903 duplicate rows [Y/n]: y
- [Recommended] Add a suffix separator ' ->' to all prompts [Y/n]: y
- [Recommended] Remove prefix 'completion:' from all completions [Y/n]: y
- [Recommended] Add a suffix ending '\n' to all completions [Y/n]: y
- [Recommended] Add a whitespace character to the beginning of the completion [Y/n]: y 

OpenAI 将转换文件保存为kantgpt_prepared.jsonl。

我们已经准备好对 GPT-3 进行微调。

GPT-3 的微调

您可以将笔记本分成两个独立的笔记本:一个用于数据准备,另一个用于微调。

第 4 步:创建一个操作系统环境

微调 过程中的第 4 步 为 API 密钥创建了一个os环境:

import openai
import os
os.environ['OPENAI_API_KEY'] =[YOUR_KEY]
print(os.getenv('OPENAI_API_KEY')) 

第 5 步:微调 OpenAI 的 Ada 引擎

第 5 步 触发了使用数���准备后保存的 JSONL 文件来微调 OpenAI Ada 引擎:

!openai api fine_tunes.create -t "kantgpt_prepared.jsonl" -m "ada" 

OpenAI 有很多请求。

如果您的流程中断,OpenAI 将指示如何继续微调。执行 fine_tunes.follow 指令:

!openai api fine_tunes.follow -i [YOUR_FINE_TUNE] 

第 6 步:与微调模型互动

第 6 步 是与微调模型互动。提示是接近伊曼纽尔·康德可能会说的内容的序列:

!openai api completions.create -m ada:[YOUR_MODEL INFO] "Several concepts are a priori such as" 

在您的微调任务结束时,OpenAI 经常显示运行完成任务与[YOUR_MODEL INFO]的指令。您可以复制并粘贴到一个单元格中(在命令行前加上"!")或将您的[YOUR_MODEL INFO]插入到下一个单元格。

完成结果相当令人信服:

Several concepts are a priori such as the term  freedom and the concept of _free will_.substance 

我们已经对 GPT-3 进行了微调,这显示了理解Transformers和设计具有 API 的人工智能流程的重要性。让我们看看这如何改变 AI 专家的角色。

Industry 4.0 人工智能专家的角色

简而言之,工业 4.0 开发人员的角色是成为跨学科 AI 专家。开发人员、数据科学家和 AI 专家将逐步学习有关语言学、业务目标、专业专业知识等更多领域。工业 4.0 AI 专家将引导团队具备实践的跨学科知识和经验。

在实施Transformers时,人类专家在三个领域中是必不可少的:

  • 道德和伦理

    一个工业 4.0 的 AI 专家确保在实施类似于人类的Transformers时执行道德和伦理实践。例如,欧洲法规严格要求必要时向用户解释自动决策。美国有反歧视法律保护公民免受自动偏见影响。

  • 提示和响应

    用户和 UI 开发人员将需要工业 4.0 AI 专家解释如何为 NLP 任务创建正确的提示,展示Transformers模型如何执行任务,并验证响应。

  • 质量控制和理解模型

    当模型即使调整超参数后仍不如预期时会发生什么?我们将在第十四章《解释黑匣子Transformers模型》中更深入地探讨这类问题。

初步结论

初步结论可分为两类:事实和虚构。

一个事实是,OpenAI 拥有全球最强大的 NLP 服务之一。其他事实包括:

  • OpenAI 引擎是强大的零样本引擎,不需要寻找各种Transformers模型,也不需要预训练和微调。

  • 用于训练模型的超级计算机是独特的

  • 如果提示设计良好,我们可以获得令人惊讶的准确答案

  • 在本章中实施 NLP 任务只需要拷贝和粘贴操作,任何软件初学者都可以执行

许多人相信 AI 将取代数据科学家和 AI 专家。这是真的吗?在回答这个问题之前,首先问问自己关于本章运行的例子的以下问题:

  • 我们如何知道一个句子是不正确的?

  • 我们如何确定一个答案是正确的,而不需要我们人类阅读和确认?

  • 引擎如何知道这是一个语法校对任务?

  • 如果响应不正确,我们如何理解发生了什么,以帮助改进提示或在设计良好的人机界面中恢复手动模式?

实际情况是人类需要手动干预回答这些问题,通过规则基础、质量受控的自动流水线和许多其他工具。

事实令人信服。在许多情况下,使用Transformers运行 NLP 任务只需要很少的开发。

人类仍然是必需的。OpenAI 引擎不是为了取代人类,而是帮助他们执行更多高水平令人满意的任务。现在你可以驾驶喷气式飞机而不必自己建造!

我们需要回答本节提出的激动人心的问题。所以让我们现在探索你在迈向 AI 未来的精彩工业 4.0 角色中的新奇旅程!

让我们总结本章并继续下一个探索!

摘要

在本章中,我们发现了超级计算机上训练数十亿参数的Transformers模型的新时代。OpenAI 的 GPT 模型正在将 NLU 推动到大多数 NLP 开发团队的视野之外。

我们看到了 GPT-3 零-shot 模型如何通过 API 进行许多 NLP 任务,甚至可以直接在线进行而无需 API。Google 翻译的在线版本已经为 AI 的主流在线使用铺平了道路。

我们探索了 GPT 模型的设计,这些模型都是构建在原始Transformers的解码器堆叠上的。掩码式注意力子层延续了从左到右训练的思想。然而,计算的绝对能力和随后的自注意力子层使其非常高效。

然后,我们使用 TensorFlow 实现了一个包含 345M 个参数的 GPT-2 模型。目标是与训练模型互动,看看我们能达到什么程度。我们看到所提供的上下文条件了输出。然而,当输入特定来自Kant 数据集的输入时,结果并没有达到预期的结果。

我们对一个包含 117M 个参数的定制数据集进行了训练的 GPT-2 模型。与这个相对较小的训练模型的交互产生了令人着迷的结果。

我们使用 OpenAI 的 API 在线运行了 NLP 任务,并对 GPT-3 模型进行了微调。本章展示了完全预训练的Transformers及其引擎可以在很少有工程师的帮助下自动完成许多任务。

这是否意味着用户将不再需要 AI NLP 开发人员、数据科学家和 AI 专家?而是用户只需将任务定义和输入文本上传到云Transformers模型中,然后下载结果?

不,一点也不意味着。工业 4.0 数据科学家和 AI 专家将演变为强大 AI 系统的领航员。他们的角色将越来越重要,以确保输入是合乎道德和安全的。这些现代化的 AI 飞行员还将了解Transformers是如何构建的,并调整 AI 生态系统的超参数。

在下一章《将Transformers应用于法律和金融文件进行 AI 文本摘要》中,我们将将Transformers模型推到极限,作为多任务模型并探索新的领域。

问题

  1. 一种零-shot 方法只需训练参数一次。(True/False)

  2. 运行零-shot 模型时进行梯度更新。(True/False)

  3. GPT 模型只有一个解码器堆叠。(True/False)

  4. 在本地机器上训练包含 117M 个参数的 GPT 模型是不可能的。(True/False)

  5. 不能使用特定数据集训练 GPT-2 模型。(True/False)

  6. 不能将 GPT-2 模型调节为生成文本。(True/False)

  7. 一个 GPT-2 模型可以分析输入的上下文并生成完成的内容。(True/False)

  8. 我们在少于 8 个 GPU 的机器上不能与包含 345M 个参数的 GPT 模型互动。(True/False)

  9. 拥有 285,000 个 CPUs 的超级计算机并不存在。(True/False)

  10. 拥有成千上万个 GPU 的超级计算机在 AI 中起着决定性的作用。(True/False)

参考资料

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作空间,与作者进行每月的 问答环节:

www.packt.link/Transformers

第八章:将Transformers应用于法律和金融文件以进行人工智能文本摘要

我们在前七章中探索了几个Transformers生态系统的架构训练、微调和使用。在第七章,超人类Transformers的崛起与 GPT-3 引擎中,我们发现 OpenAI 已经开始尝试零样本模型,它们不需要微调、不需要开发,并且可以用几行代码实现。

这样一种演进的基本概念在于Transformers模型如何努力教会机器如何理解语言,并以类似人类的方式表达自己。因此,我们已经从训练模型转变为教会机器语言。

Raffel等人(2019)设计了一个基于简单断言的Transformers元模型:每个自然语言处理问题都可以表示为文本到文本函数。每种类型的自然语言处理任务都需要一些文本上下文,生成一些形式的文本响应。

任何自然语言处理任务的文本到文本表示都提供了一个独特的框架来分析Transformers的方法和实践。这一思想是,通过文本到文本的方法,在训练和微调阶段,Transformers可以通过迁移学习学习一种语言。

Raffel等人(2019)将这种方法命名为Text-To-Text Transfer Transformer。这 5 个 T 成为了T5,一个新模型诞生了。

我们将从 T5 Transformers模型的概念和架构开始本章。然后我们将运用 T5 来总结使用 Hugging Face 模型的文件。

最后,我们将文本到文本的方法转化为 GPT-3 引擎使用的展示和上下文过程。令人惊叹的,虽然不完美,零样本响应超过了人类所能想象的任何事物。

本章涵盖以下主题:

  • 文本到文本Transformers模型

  • T5 模型的架构

  • T5 方法论

  • 从训练到学习的Transformers模型的演进

  • Hugging Face 的Transformers模型

  • 实现一个 T5 模型

  • 对法律文本进行摘要

  • 对金融文本进行摘要

  • Transformers模型的限制

  • GPT-3 的使用

我们的第一步将是探索由Raffel等人(2019)定义的文本到文本的方法论。

设计一个通用的文本到文本模型

谷歌的自然语言处理技术革命始于Vaswani等人(2017)的研究,即 2017 年的原始Transformers。《注意力就是一切》颠覆了 30 多年的人工智能信仰,即循环神经网络和卷积神经网络应用于自然语言处理任务。它将我们从自然语言处理/理解的石器时代带到了 21 世纪,这是一个早就应该发生的演进。

第七章,超人类Transformers的崛起与 GPT-3 引擎,总结了谷歌的Vaswani等人(2017)原始Transformers和 OpenAI 的Brown等人(2020)GPT-3 Transformers之间涌现出的第二次革命。原始Transformers专注于性能,以证明注意力是我们处理自然语言处理/理解任务所需要的唯一因素。

OpenAI 的第二次革命,通过 GPT-3,着重将 transformer 模型从微调的预训练模型提升到无需微调的 few-shot 训练模型。第二次革命是为了证明机器可以学习一种语言,并将其应用于下游任务,就像我们人类一样。

要理解 T5 模型代表什么,理解这两次革命是至关重要的。第一次革命是注意力技术。第二次革命是教会机器理解语言(NLU),然后让它像我们一样解决 NLP 问题。

2019 年,Google 的想法与 OpenAI 的想法一致,即将 transformers 从技术考虑的层面提升到自然语言理解的抽象水平。

这些革命变得颠覆性。是时候平静下来,忘记源代码和机器资源,以更高的层次分析 transformers。

Raffel等人(2019)设计了一个概念上的文本到文本模型,然后加以实施。

让我们来看看第二次转换革命的代表:抽象模型。

文本到文本 transformer 模型的崛起

Raffel等人(2019)以一种目标为先驱们开始了一段旅程:探索统一文本到文本 transformer 的迁移学习的极限。该团队强调他们使用的这种方法从一开始就不会修改原始 Transformer 的基本架构。

在那时,Raffel等人(2019)想要关注概念,而不是技术。因此,他们对产生最新的 transformer 模型没有兴趣,正如我们经常看到的所谓的具有n参数和层的灵丹妙药 transformer 模型。这一次,T5 团队想要找出 transformers 在理解语言方面有多好。

人类学习一种语言,然后通过迁移学习将这些知识应用于各种 NLP 任务。T5 模型的核心概念是寻找一个可以像我们一样做事情的抽象模型。

当我们交流时,我们总是以一个序列(A)开头,然后是另一个序列(B)。B 又成为另一个序列的开始,如图 8.1所示:

一个包含文本、时钟、截图、相框的图片  自动生成的描述

图 8.1:沟通的序列到序列的表示

我们还通过音乐与有组织的声音进行交流。我们通过舞蹈与有组织的身体动作进行交流。我们通过绘画以形状和颜色进行表达。

我们通过称为“文本”的一个词或一组词进行语言交流。 当我们试图理解一段文本时,我们在所有方向上都会注意到句子中的所有词。我们尝试衡量每个术语的重要性。当我们不理解一个句子时,我们会专注于一个词并查询句子中的其余关键词,以确定它们的值和我们必须支付的注意力。这定义了 transformer 的注意力层。

花几秒钟,让这个思想深入。看起来似乎非常简单,对吧?然而,推翻围绕 RNN、CNN 及其相应思维过程的旧信念花了 35+ 年的时间!

观察 T5 学习、进步,甚至有时帮助我们更好地思考,这非常迷人!

同时关注序列中所有标记的注意力层的技术革命导致了 T5 概念的革命。

T5 模型可以概括为一个Text-To-Text Transfer Transformer。因此,每个 NLP 任务都被表达为一个文本到文本的问题来解决。

一个前缀而不是任务特定格式

Raffel 等人(2019)仍然有一个问题需要解决:统一任务特定格式。想法是找到一种方法,使每个提交给 transformer 的任务都有一个输入格式。这样,模型参数将用一个文本到文本格式训练所有类型的任务。

谷歌 T5 团队提出了一个简单的解决方案:在输入序列中添加前缀。如果没有一位早已被遗忘的天才发明了前缀,我们在许多语言中都需要成千上万个额外的词汇。例如,如果我们不使用“pre”作为前缀,我们就需要找到词来描述预付款、史前的、前寒武纪等成千上万的其他词。

Raffel 等人(2019)提议向输入序列添加一个前缀。T5 前缀不仅仅是一些 transformer 模型中用于分类的标记或指示器,比如[CLS]。相反,T5 前缀包含了一个 transformer 需要解决的任务的本质。前缀传达意义,如下面的例子所示,还有其他例子:

  • translate English to German: + [sequence] 用于翻译,就像我们在第六章的使用 Transformer 进行机器翻译中所做的那样

  • cola sentence: + [sequence] 用于语言可接受性语料库(CoLA),就像我们在第三章的微调 BERT 模型时使用 BERT transformer 模型时所做的那样

  • stsb sentence 1:+[sequence] 用于语义文本相似性基准。自然语言推理和蕴含是相似的问题,如第五章的带 Transformer 的下游 NLP 任务中所述

  • summarize + [sequence] 用于文本摘要问题,就像我们在本章的使用 T5 进行文本摘要部分中所做的那样

我们现在已经得到了一个统一的格式,用于广泛的 NLP 任务,在图 8.2中表达:

Diagram  Description automatically generated with low confidence

图 8.2:统一 transformer 模型的输入格式

统一的输入格式导致了一个Transformers模型,无论要解决什么问题,在T5中都会产生一个结果序列。许多自然语言处理任务的输入和输出已经被统一,如图 8.3所示:

自动生成的图解说明

图 8.3:T5 文本到文本框架

统一的处理流程使得可以在广泛的任务中使用相同的模型、超参数和优化器。

我们已经通过了标准的文本到文本输入输出格式。现在让我们来看看 T5 Transformers模型的架构。

T5 模型

Raffel等人(2019 年)专注于设计一个标准的输入格式以获得文本输出。Google T5 团队不希望尝试从原始 Transformer 派生的新架构,如仅包含编码器层的 BERT 样式或仅包含解码器层的 GPT 样式。相反,团队专注于以标准格式定义自然语言处理任务。

他们选择使用我们在第二章中定义的原始 Transformer 模型,正如我们在图 8.4中所看到的:

自动生成的图解说明

图 8.4:T5 使用的原始 Transformer 模型

Raffel等人(2019 年)保留了大部分原始 Transformer 架构和术语。但是,他们强调了一些关键方面。此外,他们进行了一些轻微的词汇和功能性的更改。以下列表包含 T5 模型的一些主要方面:

  • 编码器和解码器保留在模型中。编码器和解码器层变成了“块”,子层变成了包含自注意层和前馈网络的“子组件”。在类似 LEGO^®的语言中使用“块”和“子组件”一词,使您可以组装“块”、“片”和组件来构建您的模型。Transformers组件是您可以以许多方式组装的标准构建块。一旦您理解了我们在第二章中介绍的基本构建块,您就可以理解任何Transformers模型的运作方式。

  • 自注意力是“无序的”,意味着它对集合进行操作,正如我们在第二章中看到的那样。自注意力使用矩阵的点积,而不是递归。它探索序列中每个单词与其他单词之间的关系。在进行点积之前,将位置编码添加到单词的嵌入中。

  • 原始 Transformer 将正弦和余弦信号应用于Transformers。或者它使用了学习到的位置编码。T5 使用相对位置编码,而不是将任意位置添加到输入中。在 T5 中,位置编码依赖于自注意力的扩展,以进行成对关系的比较。更多内容,请参见本章的参考文献中的Shaw等人(2018 年)。

  • 位置编码在模型的所有层中共享并重新评估。

我们通过文本对文本方法定义了 T5 Transformers模型输入的标准化。

现在让我们使用 T5 来总结文档。

使用 T5 进行文本摘要

NLP 总结任务提取了文本的简洁部分。本节将首先介绍我们在本章中将要使用的 Hugging Face 资源。然后我们将初始化一个 T5-large Transformers模型。最后,我们将看到如何使用 T5 来总结任何文档,包括法律和公司文件。

让我们开始介绍 Hugging Face 的框架。

Hugging Face

Hugging Face 设计了一个高级别实现Transformers的框架。我们在第三章中使用 Hugging Face 来微调 BERT 模型,并在第四章中训练了一个 RoBERTa 模型。

为了扩展我们的知识,我们需要探索其他方法,例如第六章中的 Trax 和第七章中的 OpenAI 模型。本章将再次使用 Hugging Face 框架,并更多地解释在线资源。我们以 GPT-3 引擎的独特潜力结束本章。

Hugging Face 在其框架内提供了三个主要资源:模型、数据集和指标。

Hugging Face 变换资源

在本小节中,我们将选择将在本章中实现的 T5 模型。

可以在 Hugging Face 模型页面上找到各种模型,就像我们在图 8.5中看到的那样:

自动生成的图形用户界面,文本,应用程序,聊天或文本消息描述

图 8.5:Hugging Face 模型

在这个页面上,huggingface.co/models,我们可以搜索一个模型。在我们的情况下,我们正在寻找t5-large,一个我们可以在 Google Colaboratory 中顺利运行的模型。

我们首先键入T5来搜索 T5 模型,并获取我们可以选择的 T5 模型列表:

自动生成的图形用户界面,文本,应用程序描述

图 8.6:搜索 T5 模型

我们可以看到原始 T5 Transformers中提供了几种模型,其中包括:

  • 基础,是基线模型。它的设计与 BERT[BASE]类似,有 12 层和大约 2.2 亿个参数

  • small,一个更小的模型,有 6 层和 6 千万参数

  • large的设计类似于具有 12 层和 7.7 亿参数的 BERT[LARGE]

  • 3B和11B使用 24 层的编码器和解码器,大约有 28 亿和 110 亿个参数

要了解更多关于 BERT[BASE]和 BERT[LARGE]的描述,您现在或以后可以花几分钟在第三章中查看这些模型。

在我们的情况下,我们选择t5-large:

自动生成的图形用户界面,文本,应用程序描述

图 8.7:如何使用 Hugging Face 模型

图 8.7 展示了我们将要编写的代码中如何使用该模型。我们还可以查看模型中的文件列表和基本配置文件。我们在本章的 初始化 T5-large transformer 模型 部分将查看配置文件。

Hugging Face 还提供了数据集和指标:

数据集和指标是自然语言处理的经典方面。在本章中,我们不会实现这些数据集或指标。相反,我们将专注于如何实现任何文本摘要。

让我们从初始化 T5 transformer 模型开始。

初始化 T5-large transformer 模型

在本小节中,我们将初始化一个 T5-large 模型。打开以下笔记本,在本章的 GitHub 目录中找到 Summarizing_Text_with_T5.ipynb。

让我们开始使用 T5!

开始使用 T5

在本小节中,我们将安装 Hugging Face 的框架,然后初始化一个 T5 模型。

我们首先安装 Hugging Face 的 transformers:

!pip install transformers 

注意:Hugging Face transformers 不断演进,更新库和模块以适应市场。如果默认版本不起作用,您可能需要使用 !pip install transformers==[与笔记本中其他功能兼容的版本] 固定一个版本。

我们固定了 sentencepiece 的版本为 0.1.94,以尽可能使使用 Hugging Face 的笔记本保持稳定:

!pip install sentencepiece==0.1.94 

Hugging Face 有一个可以克隆的 GitHub 仓库。但是,Hugging Face 的框架提供了一系列我们可以实现的高级 transformer 函数。

我们可以选择在初始化模型时显示模型的架构或不显示:

display_architecture=False 

如果将 display_architecture 设置为 True,则将显示编码器层、解码器层和前向子层的结构。

程序现在导入了 torch 和 json:

import torch
import json 

从事 transformer 工作意味着要对研究实验室与我们分享的许多 transformer 架构和框架持开放态度。我也建议尽可能多地使用 PyTorch 和 TensorFlow 来熟悉两种环境。重要的是 transformer 模型的抽象级别(特定任务模型或零-shot 模型)及其整体性能。

让我们导入 tokenizer、generation 和 configuration 类:

from transformers import T5Tokenizer, T5ForConditionalGeneration, T5Config 

我们将在这里使用 T5-large 模型,但您可以在本章的 Hugging Face 部分中选择其他 T5 模型。

现在,我们将导入 T5-large 有条件生成模型以生成文本和 T5-large tokenizer:

model = T5ForConditionalGeneration.from_pretrained('t5-large')
tokenizer = T5Tokenizer.from_pretrained('t5-large') 

仅需一行即可初始化一个预训练的分词器。但是,并没有证明标记化的词典包含所有我们需要的词汇。我们将在第九章 匹配分词器和数据集中调查分词器和数据集之间的关系。

程序现在使用'cpu'初始化了torch.device。这部分笔记足够用了一个 CPU。torch.device对象是 torch 张量分配的设备:

device = torch.device('cpu') 

我们准备好探索 T5 模型的体系结构了。

探索 T5 模型的体系结构

在这一小节中,我们将探索 T5-large 模型的架构和配置。

如果display_architecture==true,我们可以看到模型的配置:

if display_architecture==True:
  print(model.config) 

例如,我们可以看到模型的基本参数:

.../...
"num_heads": 16,
"num_layers": 24,
.../... 

该模型是一个带有 16 个头和 24 层的 T5 Transformers。

我们还可以看到 T5 的文本到文本实现,它将一个输入句子添加一个前缀来触发任务执行。前缀使得能够在不修改模型参数的情况下以文本到文本格式表示各种任务。在我们的情况下,前缀是summarization:

"task_specific_params": {
    "summarization": {
      "early_stopping": true,
      "length_penalty": 2.0,
      "max_length": 200,
      "min_length": 30,
      "no_repeat_ngram_size": 3,
      "num_beams": 4,
      "prefix": "summarize: "
    }, 

我们可以看到 T5:

  • 实施波束搜索算法,它将扩展四个最重要的文本完成预测

  • 当每批完成num_beam句子时,应用早停止

  • 确保不重复出现 n 克,n 的大小等于 no_repeat_ngram_size

  • 使用 min_length 和 max_length 控制样本的长度

  • 应用长度惩罚

另一个有趣的参数是词汇量大小:

"vocab_size": 32128 

词汇量本身就是一个话题。太多的词汇将导致表示稀疏。另一方面,词汇量太少会扭曲 NLP 任务。我们将在第九章 匹配分词器和数据集中进一步探讨这一点。

通过简单地打印model,我们还可以看到Transformers堆栈的细节:

if(display_architecture==True):
  print(model) 

例如,我们可以通过仅运行您希望运行的单元来查看模型的一个块(层):

(12): T5Block(
        (layer): ModuleList(
          (0): T5LayerSelfAttention(
            (SelfAttention): T5Attention(
              (q): Linear(in_features=1024, out_features=1024, bias=False)
              (k): Linear(in_features=1024, out_features=1024, bias=False)
              (v): Linear(in_features=1024, out_features=1024, bias=False)
              (o): Linear(in_features=1024, out_features=1024, bias=False)
            )
            (layer_norm): T5LayerNorm()
            (dropout): Dropout(p=0.1, inplace=False)
          )
          (1): T5LayerFF(
            (DenseReluDense): T5DenseReluDense(
              (wi): Linear(in_features=1024, out_features=4096, bias=False)
              (wo): Linear(in_features=4096, out_features=1024, bias=False)
              (dropout): Dropout(p=0.1, inplace=False)
            )
            (layer_norm): T5LayerNorm()
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
      ) 

我们可以看到模型在注意子层上运行了1,024个特征,在前馈网络子层的内部计算中运行了 4,096 个特征,这将产生1,024个特征的输出。Transformers的对称结构在所有层中都得到了保持。

您可以花几分钟时间浏览编码器堆栈、解码器堆栈、注意子层和前馈子层。

您也可以选择仅运行您希望的单元来选择模型的特定方面:

if display_architecture==True:
  print(model.encoder)
if display_architecture==True:
  print(model.decoder)
if display_architecture==True:
  print(model.forward) 

我们已经初始化了 T5 Transformers。现在让我们来总结文件。

用 T5-large 来总结文件

本节将创建一个总结函数,您可以用任何您希望总结的文本来调用。我们将总结法律和金融示例。最后,我们将定义方法的限制。

首先,我们将创建一个总结函数。

创建一个总结函数

首先,让我们创建一个名为summarize的摘要函数。这样,我们只需将要总结的文本发送到我们的函数即可。该函数接受两个参数。第一个参数是preprocess_text,即要总结的文本。第二个参数是ml,即摘要的最大长度。这两个参数是您每次调用函数时发送到函数的变量:

def summarize(text,ml): 

Hugging Face 等提供了现成的摘要函数。但是,我建议在有必要的时候学习如何构建自己的函数来定制这一关键任务。

根据上下文文本或真实内容,去掉了\n字符:

preprocess_text = text.strip().replace("\n","") 

然后我们将创新的T5任务前缀summarize应用于输入文本:

t5_prepared_Text = "summarize: "+preprocess_text 

T5 模型采用统一的结构,通过前缀 + 输入序列的方式来处理任务。这看起来可能很简单,但它将自然语言处理变换模型更接近通用训练和零-shot 下游任务。

我们可以展示处理(去掉)和准备好的文本(任务前缀):

print ("Preprocessed and prepared text: \n", t5_prepared_Text) 

简单吧?嗯,需要 35 年以上的时间才能从循环神经网络 (RNNs) 和卷积神经网络 (CNNs) 转向变换模型。然后需要世界上一些最优秀的研究团队才能从为特定任务设计的变换模型转向几乎不需要微调的多任务模型。最后,谷歌研究团队创建了一个标准格式,以包含指示需解决的自然语言处理问题的前缀的输入文本。这真是了不起的成就!

显示的输出包含预处理并准备好的文本:

Preprocessed and prepared text: 
summarize: The United States Declaration of Independence 

我们可以看到summarize前缀,表示需要解决的任务。

文本现在已经编码为令牌 ID,并将它们作为 torch 张量返回:

tokenized_text = tokenizer.encode(t5_prepared_Text, return_tensors="pt").to(device) 

编码文本已经准备好发送到模型中,以使用我们在开始使用 T5部分描述的参数生成摘要:

# Summarize
  summary_ids = model.generate(tokenized_text,
                                      num_beams=4,
                                      no_repeat_ngram_size=2,
                                      min_length=30,
                                      max_length=ml,
                                      early_stopping=True) 

这里的横梁数量与我们导入的模型相同。但是no_repeat_ngram_size已经从3降到了2。

生成的输出现在使用tokenizer进行解码:

output = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
return output 

我们导入,初始化并定义了摘要化功能。现在让我们用一个一般性主题来试验 T5 模型。

一个一般性主题样本

在这一小节中,我们将通过 T5 模型运行由Project Gutenberg撰写的文本。我们将使用样本来测试我们的总结功能。您可以复制并粘贴任何其他您希望的文本,也可以通过添加代码加载文本。您还可以加载自己选择的数据集,并在循环中调用摘要。

本章节的程序目标是运行一些样本来看看 T5 是如何工作的。输入文本是Project Gutenberg电子书中包含美利坚合众国独立宣言开头的部分内容:

text ="""
The United States Declaration of Independence was the first Etext
released by Project Gutenberg, early in 1971\.  The title was stored
in an emailed instruction set which required a tape or diskpack be
hand mounted for retrieval.  The diskpack was the size of a large
cake in a cake carrier, cost $1500, and contained 5 megabytes, of
which this file took 1-2%.  Two tape backups were kept plus one on
paper tape.  The 10,000 files we hope to have online by the end of
2001 should take about 1-2% of a comparably priced drive in 2001.
""" 

然后我们调用我们的summarize函数,并发送我们想要总结的文本以及摘要的最大长度:

print("Number of characters:",len(text))
summary=summarize(text,50)
print ("\n\nSummarized text: \n",summary) 

输出显示我们发送了534个字符,原始文本(真实内容)经过预处理,还有摘要(预测):

Number of characters: 534
Preprocessed and prepared text: 
 summarize: The United States Declaration of Independence...
Summarized text: 
 the united states declaration of independence was the first etext published by project gutenberg, early in 1971\. the 10,000 files we hope to have online by the end of2001 should take about 1-2% of a comparably priced drive in 2001\. the united states declaration of independence was the first Etext released by project gutenberg, early in 1971 

现在让我们使用 T5 来进行更困难的摘要。

《权利法案》样本

下一个样本取自权利法案,更困难,因为它表达的是一个人的特权:

#Bill of Rights,V
text ="""
No person shall be held to answer for a capital, or otherwise infamous crime,
unless on a presentment or indictment of a Grand Jury, except in cases arising
 in the land or naval forces, or in the Militia, when in actual service
in time of War or public danger; nor shall any person be subject for
the same offense to be twice put in jeopardy of life or limb;
nor shall be compelled in any criminal case to be a witness against himself,
nor be deprived of life, liberty, or property, without due process of law;
nor shall private property be taken for public use without just compensation.
"""
print("Number of characters:",len(text))
summary=summarize(text,50)
print ("\n\nSummarized text: \n",summary) 

记住,Transformers是随机算法,因此每次运行时输出可能会有所不同。 话虽如此,我们可以看到 T5 并没有真正对输入文本进行总结,而只是简单地缩短了它:

Number of characters: 591
Preprocessed and prepared text: 
 summarize: No person shall be held to answer..
Summarized text: 
 no person shall be held to answer for a capital, or otherwise infamous crime. except in cases arisingin the land or naval forces or in the militia, when in actual service in time of war or public danger 

这份样本意义重大,因为它展示了任何Transformers模型或其他 NLP 模型面对这样的文本时所面临的限制。我们不能只展示总是有效的样本,并让用户相信Transformers已经解决了我们所面临的所有 NLP 挑战,无论它们有多么创新。

也许我们应该提供更长的文本来总结,使用其他参数,使用更大的模型,或者改变 T5 模型的结构。然而,无论你如何努力用 NLP 模型总结复杂的文本,你总会发现模型总结失败的文档。

当模型在一个任务上失败时,我们必须谦卑地承认。超级粘性人类基线是一个难以超越的基线。我们需要耐心、更加努力,改进Transformers模型,直到它们能比今天表现得更好。还有很多进步空间。

Raffel等人(2018)选择了一个适合描述 T5 方法的标题:探索统一文本到文本Transformers的迁移学习极限。

花时间来尝试你在法律文件中发现的自己的示例。将迁移学习的极限作为现代 NLP 先驱的领域来探索!有时你会发现令人兴奋的结果,有时你会发现需要改进的地方。

现在,让我们尝试一份公司法样本。

一份公司法样本

公司法包含许多法律细微之处,使得总结任务非常棘手。

此样本的输入是美国蒙大纳州的公司法节选:

#Montana Corporate Law
# https://corporations.uslegal.com/state-corporation-law/montana-corporation-law/#:~:text=Montana%20Corporation%20Law ,carrying%20out%20its%20business%20activities.
text ="""The law regarding corporations prescribes that a corporation can be incorporated in the state of Montana to serve any lawful purpose.  In the state of Montana, a corporation has all the powers of a natural person for carrying out its business activities.  The corporation can sue and be sued in its corporate name.  It has perpetual succession.  The corporation can buy, sell or otherwise acquire an interest in a real or personal property.  It can conduct business, carry on operations, and have offices and exercise the powers in a state, territory or district in possession of the U.S., or in a foreign country.  It can appoint officers and agents of the corporation for various duties and fix their compensation.
The name of a corporation must contain the word "corporation" or its abbreviation "corp."  The name of a corporation should not be deceptively similar to the name of another corporation incorporated in the same state.  It should not be deceptively identical to the fictitious name adopted by a foreign corporation having business transactions in the state.
The corporation is formed by one or more natural persons by executing and filing articles of incorporation to the secretary of state of filing.  The qualifications for directors are fixed either by articles of incorporation or bylaws.  The names and addresses of the initial directors and purpose of incorporation should be set forth in the articles of incorporation.  The articles of incorporation should contain the corporate name, the number of shares authorized to issue, a brief statement of the character of business carried out by the corporation, the names and addresses of the directors until successors are elected, and name and addresses of incorporators.  The shareholders have the power to change the size of board of directors.
"""
print("Number of characters:",len(text))
summary=summarize(text,50)
print ("\n\nSummarized text: \n",summary) 

结果令人满意:

Number of characters: 1816
Preprocessed and prepared text: 
 summarize: The law regarding the corporation prescribes that a corporation...
Summarized text: 
 a corporations can be incorporated in the state of Montana to serve any lawful purpose. a corporation can sue and be sued in its corporate name, and it has perpetual succession. it can conduct business, carry on operations and have offices 

这一次,T5 找到了文本摘要的一些关键方面。花一些时间加入自己的样本来看看会发生什么。用参数玩耍,看看它是否会影响结果。

我们已经实施了 T5 来进行文本总结。现在是时候通过 OpenAI GPT-3 引擎进行总结实验了。

使用 GPT-3 进行摘要

了解 T5 Transformers的体系结构非常重要。我们还将看到 GPT-3 引擎在其中一篇文章上的表现。目标不是对公司和模型进行基准测试。目标是让工业 4.0 人工智能领域的研究专家了解 NLP 的广泛知识。

首先,转到openai.com/并注册登录。

然后转到示例页面并选择为二年级学生总结:

一个包含文字描述的图片 Description générée automatiquement

图 8.8:GPT-3 示例页面

一个窗口会弹出,我们可以输入我们的提示。

我们将前一节公司样本的文本T提交给 GPT-3 模型。

提示为P = E + T + S:

  • E告诉模型要简化解释:

    我的二年级学生问我这段话是什么意思:

  • 文本T与前一节相同,用引号括起来:

    """关于公司的法律规定,公司可以在蒙大拿州成立以服务于任何合法目的。在蒙大拿州,公司具有进行业务活动的自然人的所有权利。

    .../...

    股东有权改变董事会的规模。"""

  • S显示了预期的任务类型:

    我用一个二年级学生可以理解的简单语言为他重新表述了:"""

    GPT-3 DaVinci 引擎生成的响应相当令人信服:

公司就是一个企业。

公司就是一个人。

公司可以做人能做的一切。

公司可以被起诉。

公司可以购买、出售或交易物品。

公司有自己的名称,与拥有它的人的名称不同。

公司是由想要创业的人成立的,并向政府提交文件以使其正式化。

我们可以保留T并修改E和S:

  • E可以改为:

    我的工商管理硕士学生问我这段话是什么意思:

  • S可以改为:

    我用工商管理硕士学院的语言重新表述了这段话:

GPT-3 引擎生成了上一个请求的响应,但为大学生添加了有用的信息:

公司可以有负责业务决策的董事会。董事会由股东选举产生。股东可以改变董事会的规模。

GPT-3 模型相当令人信服,并代表了云人工智能的崛起力量。在第十六章《Transformers驱动的合作伙伴的出现》中,我们将更深入地总结提示。然而,在我们这样做之前,还有更多,更多的探索。

摘要

在本章中,我们看到了 T5 Transformers模型如何标准化原始Transformers的编码器和解码器堆栈的输入。原始Transformers架构对于编码器和解码器堆栈的每个块(或层)具有相同的结构。然而,原始Transformers没有为自然语言处理任务制定标准化的输入格式。

Raffel 等人(2018)通过定义一个文本到文本模型,为广泛的自然语言处理任务设计了一个标准输入。他们为输入序列添加了一个前缀,指示要解决的自然语言处理问题类型。这导致了一个标准的文本到文本格式。文本到文本传输Transformers(T5)应运而生。我们看到这个看似简单的演变使得可以对广泛的自然语言处理任务使用相同的模型和超参数成为可能。T5 的发明将Transformers模型的标准化过程推进了一步。

然后,我们实现了一个可以总结任何文本的 T5 模型。我们测试了该模型在未准备好的训练数据集中不属于的文本上的表现。我们测试了该模型在宪法和公司样本上的表现。结果很有趣,但我们也发现了一些Transformers模型的限制,正如 Raffel 等人(2018)预测的那样。

最后,我们探讨了 GPT-3 引擎方法论和计算效率的巨大力量。展示一个Transformers是一个出色的方法。拥有世界上最强大的Transformers引擎之一有助于获得有效的结果,尽管不总是完美的。

目标不是对公司和模型进行基准测试,而是让工业 4.0 AI 专家对Transformers有深入理解。

在下一章,第九章,匹配标记化器和数据集 中,我们将探讨标记化器的限制,并定义可能改进自然语言处理任务的方法。

问题

  1. T5 模型只有像 BERT 模型那样的编码器堆栈。(是/否)

  2. T5 模型具有编码器和解码器堆栈。(是/否)

  3. T5 模型使用相对位置编码,而不是绝对位置编码。(是/否)

  4. 文本到文本模型仅设计用于摘要。(是/否)

  5. 文本到文本模型将一个前缀应用到输入序列中,确定自然语言处理任务。(是/否)

  6. T5 模型需要针对每个任务具体的超参数。(是/否)

  7. 文本到文本模型的一个优点是,它们对所有自然语言处理任务使用相同的超参数。(是/否)

  8. T5 Transformers不包含前馈网络。(是/否)

  9. Hugging Face 是一个使Transformers更易于实现的框架。(是/否)

  10. OpenAI 的Transformers引擎改变了游戏规则。(是/否)

参考文献

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作区,与作者进行每月的 问我任何事 交流会:

www.packt.link/Transformers

第九章:匹配标记器和数据集

在研究变换器模型时,我们往往会关注模型的架构和提供给它们进行训练的数据集。我们已经探索了原始变换器,微调了一个类似 BERT 的模型,训练了一个 RoBERTa 模型,探索了一个 GPT-3 模型,训练了一个 GPT-2 模型,实现了一个 T5 模型等等。我们还研究了主要的基准任务和数据集。

我们训练了一个 RoBERTa 标记器并使用标记器对数据进行编码。然而,我们没有探索标记器的极限,以评估它们如何适应我们构建的模型。AI 是数据驱动的。Raffel 等人(2019),就像本书中引用的所有作者一样,花时间为变换器模型准备数据集。

在本章中,我们将介绍一些限制标记器的问题,这些问题妨碍了下游变换器任务的质量。不要轻易相信预训练的标记器。您可能有一个特定的词汇表(例如,高级医学术语),其中包含预训练标记器未处理的单词。

我们将从介绍一些与标记器无关的最佳实践开始,以衡量标记器的质量。我们将从标记化的角度描述数据集和标记器的基本准则。

然后,我们将使用 Word2Vec 标记器来查看标记器的限制,以描述我们在任何标记方法中面临的问题。这些限制将通过一个 Python 程序加以说明。

我们将继续通过在包含特定词汇的数据集上运行 GPT-2 模型来进行调查,包括无条件和有条件样本。

我们将进一步了解字节级 BPE 方法的限制。我们将构建一个显示由 GPT-2 标记器产生的结果的 Python 程序,并讨论在数据编码过程中出现的问题。这将表明,对于常见的 NLP 分析,并不总是需要 GPT-3 的优势。

然而,在本章末尾,我们将通过一个 词性 (POS) 任务来测试一个 GPT-3 引擎,以查看模型理解的程度以及一个准备就绪的标记化字典是否符合我们的需求。

本章涵盖以下主题:

  • 控制标记器输出的基本准则

  • 原始数据策略和预处理数据策略

  • Word2Vec 标记化问题和限制

  • 创建一个用于评估 Word2Vec 标记器的 Python 程序

  • 构建一个用于评估字节级 BPE 算法输出的 Python 程序

  • 使用特定词汇定制 NLP 任务

  • 运行 GPT-2 的无条件和有条件样本

  • 评估 GPT-2 标记器

我们的第一步将是探索 Raffel 等人(2019)定义的文本到文本方法论。

匹配数据集和标记器

下载基准数据集以训练变换器具有许多优点。数据已经准备好,并且每个研究实验室都使用相同的参考文献。此外,变换器模型的性能可以与具有相同数据的另一个模型进行比较。

然而,还需要做更多工作来改进 transformers 的性能。此外,在生产中实施 transformer 模型需要仔细规划和定义最佳实践。

在本节中,我们将定义一些最佳实践,以避免关键的障碍。

然后我们将通过在 Python 中使用余弦相似度来衡量分词和编码数据集的限制的几个示例。

让我们从最佳实践开始。

最佳实践

Raffel等人(2019)定义了一个标准的文本-文本 T5 transformer 模型。他们还走得更远。他们开始打破使用原始数据而不先进行预处理的神话。

预处理数据可以减少训练时间。例如,Common Crawl 包含通过网页提取获得的未标记文本。数据集中的非文本和标记已被删除。

然而,Google T5 团队发现,大部分通过 Common Crawl 获得的文本并不达到自然语言或英语的水平。因此他们决定在使用数据集之前需要对其进行清理。

我们将采纳Raffel等人(2019)提出的建议,并将企业质量控制最佳实践应用于预处理和质量控制阶段。在许多其他要应用的规则中,所描述的示例展示了为获得可接受的真实项目数据集所需的巨大工作。

图 9.1列出了应用于数据集的一些关键质量控制流程:

图 9.1:transformer 数据集的最佳实践

如图 9.1所示,在训练 transformer 时,质量控制分为预处理阶段(步骤 1)和 transformer 投入生产后的质量控制(步骤 2)。

让我们浏览一下预处理阶段的主要方面。

步骤 1:预处理

Raffel等人(2019)建议在训练模型之前对数据集进行预处理,我加入了一些额外的想法。

Transformers 已经成为语言学习者,而我们已成为他们的老师。但是要教会一台机器学生一种语言,我们必须解释什么是正确的英语,例如。

在使用数据集之前,我们需要对其应用一些标准的启发式算法:

  • 句子令牌

    建议选择以句号或问号结尾的句子。

  • 删除不良词汇

    应该删除不良词汇。例如,可以在以下网站找到词汇列表:github.com/LDNOOBW/List-of-Dirty-Naughty-Obscene-and-Otherwise-Bad-Words。

  • 删除代码

    这有点棘手,因为有时代码就是我们正在寻找的内容。但是,通常最好从 NLP 任务的内容中删除代码。

  • 语言检测

    有时,网站包含带有默认“lorem ipsum”文本的页面。有必要确保数据集的所有内容都是我们所希望的语言。一个很好的开始方法是使用 langdetect,它可以检测 50 多种语言: pypi.org/project/langdetect/。

  • 消除歧视引用

    这是必须的。我的建议是建立一个知识库,其中包括您可以从网络上获取的所有内容或特定数据集。压制任何形式的歧视。您肯定希望您的机器是道德的!

  • 逻辑检查

    将训练过的转换器模型应用于执行 自然语言推理 (NLI) 的数据集可能是个好主意,以过滤掉毫无意义的句子。

  • 错误信息引用

    消除指向无效链接、不道德网站或个人的文本。这是一项艰巨的工作,但肯定是值得的。

这个列表包含了一些主要的最佳实践。然而,还需要更多,比如过滤隐私法违规行为以及其他针对特定项目的行动。

一旦一个转换器被训练成学习正确的英语,我们需要帮助它在生产阶段检测输入文本中的问题。

步骤 2: 质量控制

一个训练过的模型将表现得像一个学习了语言的人一样。它将理解它可以理解的内容并从输入数据中学习。输入数据应该经过与 Step 1: Preprocessing 相同的过程,并将新信息添加到训练数据集中。反过来,训练数据集可以成为公司项目中的知识库。用户将能够在数据集上运行 NLP 任务并获得可靠的答案、特定文档的有用摘要等。

我们应该将 Step 1: Preprocessing 中描述的最佳实践应用到实时输入数据中。例如,一个转换器可以在来自用户或 NLP 任务的输入上运行,比如总结一系列文件。

转换器是有史以来最强大的 NLP 模型。这意味着我们的道德责任也增加了。

让我们来看一些最佳实践:

  • 实时检查输入文本

    不要接受错误信息。而是实时解析输入并过滤不可接受的数据 (参见 Step 1)。

  • 实时消息

    将被过滤的数据与被过滤原因一起存储,以便用户可以查阅日志。如果要求转换器回答不合适的问题,则显示实时消息。

  • 语言转换

    当可能时,您可以将罕见的词汇转换为标准词汇。请参阅本章的 Word2Vec 分词 部分的 Case 4。这并不总是可能的。当可能时,它可能代表了一大步。

  • 隐私检查

    无论您是将数据流入Transformers模型还是分析用户输入,私人数据必须从数据集和任务中排除,除非经用户或所在国家授权。这是一个棘手的问题。必要时请咨询法律顾问。

我们刚刚浏览了一些最佳实践。现在让我们看看为什么人类质量控制是必要的。

连续的人类质量控制

Transformers将逐渐接管大多数复杂的自然语言处理任务。然而,人类干预仍然是必需的。我们以为社交媒体巨头已经自动化了一切。然后我们发现有内容管理者决定了对他们平台上的内容的好坏。

正确的方法是训练一个Transformers,实现它,控制输出,并将重要结果反馈到训练集中。因此,训练集将不断改进,Transformers将继续学习。

图 9.2 显示了连续的质量控制如何帮助Transformers的训练数据集增长并提高其在生产中的性能:

图 9.2:连续的人类质量控制

我们已经浏览了 Raffel 等人(2019)描述的几种最佳实践,并根据我在企业人工智能项目管理方面的经验添加了一些指导。

让我们通过一个 Python 程序,举例说明一些分词器遇到的限制。

Word2Vec 分词

只要一切顺利,没人会想到预训练分词器。就像在现实生活中一样。我们可以开车多年而不考虑引擎的问题。然后,有一天,我们的车抛锚了,我们试图找出原因来解释这种情况。

预训练分词器也是如此。有时结果并不如我们所期望的那样。例如,一些词对就是不匹配,正如我们在 图 9.3 中看到的:

自动生成的图表说明

图 9.3:分词器计算错误的单词对

图 9.3 中显示的例子来自 美国独立宣言、权利法案 和 英国大宪章:

  • cake 和 chapters 不匹配,尽管分词器将它们计算为具有较高余弦相似度值。

  • freedom 指的是言论自由,例如。 copyright 指的是免费电子书编辑的注释。

  • pay 和 bill 在日常英语中是匹配的。 polysemy 是指一个词可以有多个含义。例如,Bill 意味着要支付的金额,但也指的是 权利法案。结果是可以接受的,但这可能纯属运气。

在继续之前,让我们花点时间澄清一些问题。QC是指质量控制。在任何战略性企业项目中,质量控制都是强制性的。输出的质量将决定关键项目的生存。如果项目不是战略性的,错误有时是可以接受的。但在战略项目中,即使是少量的错误都意味着风险管理审计的介入,以确定项目是否应该继续还是放弃。

从质量控制和风险管理的角度来看,标记化不相关的数据集(太多无用词或缺少关键词)将混淆嵌入算法并产生“糟糕的结果”。这就是为什么在本章中,我将“标记化”一词使用宽泛,包括一些嵌入,因为前者对后者的影响。

在战略性的 AI 项目中,“糟糕的结果”可能是一个单一错误,但后果严重(特别是在医疗领域、飞机或火箭装配以及其他关键领域)。

打开Tokenizer.ipynb,基于我们在第二章、开始使用 Transformer 模型架构中创建的positional_encoding.ipynb。

由于 Word2Vec 算法的随机性质,结果可能因一次运行而异。

首先安装和导入了先决条件:

#@title Pre-Requisistes
!pip install gensim==3.8.3
import nltk
nltk.download('punkt')
import math
import numpy as np
from nltk.tokenize import sent_tokenize, word_tokenize 
import gensim 
from gensim.models import Word2Vec 
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
import matplotlib.pyplot as plt
import warnings 
warnings.filterwarnings(action = 'ignore') 

我们的数据集text.txt包含美国独立宣言、权利法案、大宪章、以及伊曼纽尔·康德的作品等其他文本。

现在将对text.txt进行标记化并训练一个 word2vec 模型:

#@title Word2Vec Tokenization
#'text.txt' file
sample = open("text.txt", "r")
s = sample.read()
# processing escape characters
f = s.replace("\n", " ")
data = []
# sentence parsing
for i in sent_tokenize(f):
  temp = [] 
  # tokenize the sentence into words
  for j in word_tokenize(i):
    temp.append(j.lower())
  data.append(temp)
# Creating Skip Gram model
model2 = gensim.models.Word2Vec(data, min_count = 1, size = 512,window = 5, sg = 1)
print(model2) 

window = 5是一个有趣的参数。它限制了输入句子中当前单词和预测单词之间的距离。sg = 1表示使用了 skip-gram 训练算法。

输出显示词汇量的大小为10816,嵌入维度为512,学习速率设置为alpha=0.025:

Word2Vec(vocab=10816, size=512, alpha=0.025) 

我们拥有一个带嵌入式的词汇表示模型,并且可以创建一个名为similarity(word1,word2)的余弦相似度函数。我们将word1和word2发送到该函数中,它会返回它们之间的余弦相似度值。值越高,相似度越高。

该函数首先会检测未知单词[unk],并显示一条消息:

#@title Cosine Similarity
def similarity(word1,word2):
        cosine=False #default value
        try:
                a=model2[word1]
                cosine=True
        except KeyError:     #The KeyError exception is raised
                print(word1, ":[unk] key not found in dictionary")#False implied
        try:
                b=model2[word2]#a=True implied
        except KeyError:       #The KeyError exception is raised
                cosine=False   #both a and b must be true
                print(word2, ":[unk] key not found in dictionary") 

只有在cosine==True时,才会计算余弦相似度,这意味着word1和word2都是已知的。

 if(cosine==True):
                b=model2[word2]
                # compute cosine similarity
                dot = np.dot(a, b)
                norma = np.linalg.norm(a)
                normb = np.linalg.norm(b)
                cos = dot / (norma * normb)
                aa = a.reshape(1,512)
                ba = b.reshape(1,512)
                #print("Word1",aa)
                #print("Word2",ba)
                cos_lib = cosine_similarity(aa, ba)
                #print(cos_lib,"word similarity")

        if(cosine==False):cos_lib=0;
        return cos_lib 

该函数将返回cos_lib,余弦相似度的计算值。

我们现在将讨论六种情况。我们将把“数据集”命名为text.txt。

让我们从案例 0开始。

情况 0:数据集和词典中的单词

数据集中有freedom和liberty两个词,并可以计算它们的余弦相似度:

#@title Case 0: Words in text and dictionary
word1="freedom";word2="liberty"
print("Similarity",similarity(word1,word2),word1,word2) 

相似性被限制为0.79,因为大量内容是从各种文本中插入的,以探索功能的限制:

Similarity [[0.79085565]] freedom liberty 

相似度算法不是迭代确定性计算。这一部分的结果可能会因数据集内容、另一次运行后数据集大小或模块版本的变化而改变。如果你运行这个单元格 10 次,你可能会得到不同的值,就像以下的 10 次运行中一样。

在以下情况下,我使用 Google Colab VM 和 CPU 进行了 10 次实验,结果完全相同:

Run 1: Similarity [[0.62018466]] freedom liberty
Run 2: Similarity [[0.62018466]] freedom liberty
...
Run 10: Similarity [[0.62018466]] freedom liberty 

然而,我在 Google Colab 的运行时菜单中做了一次“恢复出厂设置”。使用新的 VM 和 CPU,我得到了:

Run 1: Similarity [[0.51549244]] freedom liberty
Run 2: Similarity [[0.51549244]] freedom liberty
...
Run 10: Similarity [[0.51549244]] freedom liberty 

我在 Google Colab 的运行时菜单中进行了另一次“恢复出厂设置”。我还激活了 GPU。使用新的 VM 和 GPU,我得到了:

Run 1: Similarity [[0.58365834]] freedom liberty
Run 2: Similarity [[0.58365834]] freedom liberty
...
Run 10: Similarity [[0.58365834]] freedom liberty 

这里的结论是,随机算法基于概率。如果需要,运行预测n次是个好做法。

现在让我们看看当一个单词缺失时会发生什么。

情况 1:数据集或字典中没有的单词

缺少单词在许多方面都会带来麻烦。在这种情况下,我们将corporations和rights发送到相似度函数中:

#@title Word(s) Case 1: Word not in text or dictionary
word1="corporations";word2="rights"
print("Similarity",similarity(word1,word2),word1,word2) 

字典中不包含单词corporations:

corporations :[unk] key not found in dictionary
Similarity 0 corporations rights 

迷途!这个单词是一个未知的[unk]标记。

如果缺失的单词是重要的话,它将引发一系列事件和问题,扭曲Transformers模型的输出。我们将这个缺失的单词称为unk。

需要检查几种可能性,并回答问题:

  • unk在数据集中,但没有被选中放入标记化字典中。

  • 数据集中没有unk,这也适用于单词corporations。这解释了为什么在这种情况下它不在字典中。

  • 如果用户发送一个包含该标记且未被标记化的输入给Transformers,unk将会出现在生产中。

  • unk对于数据集来说不是一个重要的单词,但对Transformers的使用是重要的。

如果Transformers在某些情况下产生糟糕的结果,问题清单将继续增长。我们可以把0.8视为特定下游任务训练阶段Transformers模型的出色性能。但在现实生活中,谁希望与一个错误率达到 20%的系统一起工作呢:

  • 一个医生?

  • 一个律师?

  • 一个核电站维护团队?

0.8 在社交媒体等模糊环境中是令人满意的,因为很多消息本来就缺乏适当的语言结构。

现在是最糟糕的部分了。假设一个 NLP 团队发现了这个问题,并试图通过字节级 BPE 解决它,就像我们贯穿这本书所做的那样。如有必要,花几分钟回到第四章,从头开始预训练 RoBERTa 模型,第三步:训练一个标记器。

如果一个团队只使用字节级 BPE 来解决问题,噩梦就开始出现:

  • unk 将会被分解成单词片段。例如,我们可能得到corporations变成corp + o + ra + tion + s。其中一个或几个这样的单词片段在数据集中有很高的概率被发现。

  • unk 将变成一组由数据集中存在但不传达原始标记意义的标记表示的子词。

  • 转换器将训练良好,没有人会注意到 unk 被分成片段并无意义地训练了。

  • 转换器甚至可能会产生出色的结果,并将其性能从 0.8 提高到 0.9。

  • 每个人都会鼓掌,直到专业用户在关键情况下应用了错误的结果。例如,在英语中,corp 可能是 corporation 或 corporal。这可能会导致 corp 与其他单词之间的混淆和不良关联。

我们可以看到,社交媒体的标准可能足以用于处理微不足道的主题的转换器。但是在现实生活中的企业项目中,将需要辛勤工作才能生成与数据集匹配的预训练标记器。在现实生活中,数据集每天都在随着用户输入而增长。用户输入成为应定期训练和更新的模型数据集的一部分。

例如,确保质量控制的一种方法可以通过以下步骤实现:

  • 使用字节级 BPE 算法训练一个标记器。

  • 使用类似于本章的“控制标记化数据”部分中将创建的程序来控制结果。

  • 同样,训练一个使用于质量控制的 Word2Vec 算法的标记器,然后解析数据集,找到 unk 标记,并将其存储在数据库中。运行查询以检查是否缺少关键单词。

在如此详细地检查过程可能看起来是不必要的,并且你可能会倾向于依赖转换器对未见过的单词进行推理的能力。

然而,我建议在战略性项目中运行几种不同的质量控制方法,其中包括关键决策。例如,在法律摘要中,一个词可能是在法庭上赢得或输掉案件的区别。在航空航天项目(飞机,火箭)中,有一个 0 误差容忍标准。

运行越多的质量控制流程,你的转换器解决方案就会越可靠。

我们可以看到,获得可靠的数据集需要大量的工作!每一篇关于转换器的论文都以某种方式提到了制作可接受数据集所需的工作。

嘈杂的关系也会引起问题。

情况 2:嘈杂的关系

在这种情况下,数据集包含了单词 etext 和 declaration:

#@title Case 2: Noisy Relationship
word1="etext";word2="declaration"
print("Similarity",similarity(word1,word2),word1,word2) 

此外,它们都出现在了标记化字典中:

Similarity [[0.880751]] etext declaration 

更好的是,它们的余弦相似度似乎对其预测确信无疑,超过了 0.5。算法的随机性可能会导致在不同运行中产生不同的结果。

在微不足道的或社交媒体级别,一切看起来都很好。

然而,在专业水平上,结果是灾难性的!

etext 指的是 古腾堡计划 网站上每本电子书的前言,如本章的“匹配数据集和标记器”部分所解释的。特定任务的转换器目标是什么:

  • 了解编辑的序言吗?

  • 或者理解书的内容呢?

这取决于Transformers的使用情况,可能需要几天的时间来解决。例如,假设编辑想要自动理解序言并使用Transformers生成序言文本。我们应该将内容取出吗?

declaration是与独立宣言实际内容相关的有意义的词汇。

etext是Project Gutenberg添加到其所有电子书中的序言的一部分。

这可能会导致错误的自然语言推理,例如Transformers被要求生成文本时产生etext 是声明。

让我们来看一个缺失单词的问题。

情况 3:文本中但不在字典中的词汇

在某些情况下,一个词可能在文本中但不在字典中。这将扭曲结果。

让我们来看看单词pie和logic:

#@title Case 3: word in text, not in dictionary
word1="pie";word2="logic"
print("Similarity",similarity(word1,word2),word1,word2) 

单词pie不在字典中:

pie :[unk] key not found in dictionary
Similarity 0 pie logic 

我们可以假设单词pie会在一个分词的字典中。但是如果没有或者另一个词没有呢?单词pie不在文本文件中。

因此,我们应该在流程中有函数来检测不在字典中的词汇,以实现更正或替代。此外,我们应该在流程中有函数来检测可能重要的数据集中的词汇。

让我们看看罕见词汇带来的问题。

情况 4:罕见词汇

罕见的词汇对超出简单应用范围的特定任务的Transformers输出产生毁灭性影响。

管理罕见词汇延伸到许多自然语言的领域。例如:

  • 罕见词汇可能出现在数据集中但被忽视,或者模型训练不足以处理它们。

  • 罕见词汇可能是医学、法律、工程术语或任何其他专业行话。

  • 罕见的词汇可能是俚语。

  • 英语语言有数百种变体。例如,不同的英语词汇在美国、英国、新加坡、印度、澳大利亚和许多其他国家的某些地区使用。

  • 罕见的词汇可能来自几个世纪前的文本,被遗忘或只有专家使用。

例如,在这种情况下,我们使用了单词justiciar:

#@title Case 4: Rare words
word1="justiciar";word2="judgement"
print("Similarity",similarity(word1,word2),word1,word2) 

与judgement的相似性是合理的,但应该更高:

Similarity [[0.6606605]] justiciar judgement 

你可能会认为单词justiciar有些牵强。分词器将其从大宪章中提取出来,可以追溯到 13 世纪初。不幸的是,程序会感到困惑,我们在每次运行后都会得到意外的结果。

注:预测可能会因为每次运行而有所不同。然而,它们显示了我们在Transformers模型项目的分词和嵌入阶段中需要多么谨慎。

然而,大宪章的几条款在 21 世纪的英格兰仍然有效!例如,第 1、13、39 和 40 条仍然有效!

大宪章最著名的部分是以下摘录,它包含在数据集中:

(39) No free man shall be seized or imprisoned, or stripped of his
rights or possessions, or outlawed or exiled, or deprived of his
standing in any other way, nor will we proceed with force against him,
or send others to do so, except by the lawful judgement of his equals
or by the law of the land.
(40) To no one will we sell, to no one deny or delay right or justice. 

如果我们在律师事务所中实施一个Transformers模型来总结文件或其他任务,我们必须小心!

现在让我们看看解决稀有词问题的一些方法。

Case 5: 替换稀有词

替换稀有词本身就是一个项目。这项工作保留给特定的任务和项目。假设企业预算可以支付航空领域的知识库成本,例如。在这种情况下,值得花费必要的时间来查询分词目录,以找到它错过的单词。

问题可以按主题分组解决,并且知识库将定期更新。

在Case 4中,我们遇到了单词justiciar。如果我们回到它的起源,我们可以看到它来自法国诺曼德语,并且是法国类拉丁语单词judicaire的根源。

我们可以用judge替换justiciar,这传达了相同的元概念:

#@title Case 5: Replacing rare words
word1="judge";word2="judgement"
print("Similarity",similarity(word1,word2),word1,word2) 

它产生了一个有趣的结果,但由于算法的非确定性方面,我们仍然需要小心:

Similarity [[0.7962761]] judge judgement 

我们也可以保留单词justiciar,但尝试单词的现代含义并将其与judge进行比较。您可以尝试实现Case 5: Replacing rare words:

word1="justiciar";word2="judge"
print("Similarity",similarity(word1,word2),word1,word2) 

无论如何,一些稀有词都需要被更常见的词替换。

结果将是令人满意的:

Similarity [[0.9659128]] justiciar judge 

我们可以创建使用替换单词的查询,直到我们找到相关性超过0.9的情况。此外,如果我们正在管理一个关键的法律项目,我们可以将包含任何类型稀有词的重要文档翻译成标准英语。因此,变换器在自然语言处理任务中的性能将提高,并且公司的知识库将逐渐增加。

现在让我们看看如何使用余弦相似度进行蕴含验证。

Case 6: 蕴涵

在这种情况下,我们对字典中的单词感兴趣,并按固定顺序测试它们。

例如,让我们看看“pay" + “debt"是否在我们的相似性函数中有意义:

#@title Case 6: Entailment
word1="pay";word2="debt"
print("Similarity",similarity(word1,word2),word1,word2) 

结果令人满意:

Similarity [[0.89891946]] pay debt 

我们可以检查数据集中的几对单词,并检查它们是否有意义。例如,这些单词对可以从法律部门的电子邮件中提取。如果余弦相似度超过0.9,则可以剥离邮件中的无用信息,并将内容添加到公司的知识库数据集中。

现在让我们看看预训练的分词器与自然语言处理任务的匹配情况。

具有特定词汇的标准自然语言处理任务

本节重点介绍了本章节中Word2Vec tokenization部分的Case 4: Rare words和Case 5: Replacing rare words。

我们将使用Training_OpenAI_GPT_2_CH09.ipynb,这是我们在Chapter 7中使用的笔记本的重命名版本,The Rise of Suprahuman Transformers with GPT-3 Engines。

笔记本有两处更改:

  • dset,数据集,被重命名为mdset,并包含医学内容

  • 添加了一个 Python 函数来控制使用字节级 BPE 分词的文本

我们不会描述第七章中所涵盖的Training_OpenAI_GPT_2_CH09.ipynb,以及附录 III 和 IV。确保在开始之前上传所需的文件,就像第七章中所解释的那样。

您希望训练模型的时间没有限制。中断它以保存模型。

文件位于Chapter09的gpt-2-train_files目录中的 GitHub 上。尽管我们使用的是第七章中相同的笔记本,但要注意数据集dset在目录和代码中现在被命名为mdset。

首先,让我们使用经过训练以理解医学内容的 GPT-2 模型生成一个无条件样本。

使用 GPT-2 生成无条件样本

在这一节中,我们将亲自动手来理解变换器的内部工作原理。当然,我们可以跳过整个章节,简单地使用 OpenAI API。然而,一个 4.0 的 AI 专家必须成为 AI 大师,通过预处理管道展示,而不是模糊地告诉变换器模型要做什么。为了展示一个变换器模型要做什么,必须了解变换器模型的工作原理。

在案例 4:罕见词语和案例 5:替换罕见词语中,我们看到罕见词语可以是在特定领域中使用的词语,古老的英语,世界各地英语的变体,俚语等。

在 2020 年,新闻中充斥着与 COVID-19 爆发有关的医学术语。在这一部分中,我们将看到一个 GPT-2 变换器如何处理医学文本。

要编码和训练的数据集包含了Martina Conte和Nadia Loy(2020 年)撰写的一篇论文,名称为具有非局部感知的多线索动力学模型用于细胞在具有趋化作用的纤维网络上的迁移。

标题本身并不容易理解,包含了一些罕见的词语。

加载位于gpt-2-train_files目录中的文件,包括mdset.txt。然后按照第七章中所述运行代码。您可以逐个单元格地运行此代码,第七章会给出指导。务必按照说明确保激活tf 1.x。在运行第 4 步之后,务必重新启动运行时,然后再次运行第 4 步中的tf 1.x单元格,然后再继续。否则,您将在笔记本中遇到错误。在本节中,我们将亲自动手使用低级别的原始 GPT-2 代码,而不是 API。

在对医学数据集进行训练之后,您将进入无条件抽样单元,第 11 步:生成无条件样本:

#@title Step 11: Generating Unconditional Samples
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src")
!python generate_unconditional_samples.py --model_name '117M' 

此命令以及本笔记本中的其他代码运行所需的时间取决于您的计算机性能。本书中的所有 GPT-2 代码都仅用于教育目的。建议在生产环境中使用 OpenAI 的 GPT-3 API。对于变换器项目,响应时间更快。

运行单元格,并在需要时停止。它会产生一个随机输出:

community-based machinery facilitates biofilm growth. Community members place biochemistry as the main discovery tool to how the cell interacts with the environment and thus with themselves, while identifying and understanding all components for effective Mimicry.
2\. Ol Perception
Cytic double-truncation in phase changing (IP) polymerases (sometimes called "tcrecs") represents a characteristic pattern of double-crossing enzymes that alter the fundamental configuration that allows initiation and maintenance of process while chopping the plainNA with vibrational operator. Soon after radical modification that occurred during translational parasubstitution (TMT) achieved a more or less uncontrolled activation of SYX. TRSI mutations introduced autophosphorylation of TCMase sps being the most important one that was incorporated into cellular double-triad (DTT) signaling across all
cells, by which we allow R h and ofcourse an IC 2A- >
.../... 

仔细观察输出,我们注意到以下几点:

  • 生成的句子的结构相对可接受

  • 输出的语法不错

  • 对于非专业人士来说,输出可能看起来类似于人类

但是内容毫无意义。Transformers无法产生与我们训练的医学论文相关的真实内容。要获得更好的结果需要艰苦的工作。当然,我们总是可以增加数据集的规模。但它是否包含我们正在寻找的内容呢?我们是否会找到更多数据中的错误相关性呢?例如,想象一下一个涉及 COVID-19 的医疗项目,数据集包含以下句子:

  • COVID-19 不是危险的病毒,而只是像普通流感一样。

  • COVID-19 是一种非常危险的病毒。

  • COVID-19 不是一种病毒,而是实验室创造出的东西。

  • COVID-19 肯定不是由实验室创造的!

  • 疫苗是危险的!

  • 疫苗是救命稻草!

  • 政府没有正确管理疫情。

  • 政府采取了必要的措施。

以及更多类似这样矛盾的句子。这些不一致性证实了数据集和分词器都必须为专业的医疗保健项目、航空航天、交通运输和其他关键领域进行定制。

想象一下,你有数十亿字的数据集,但内容如此矛盾和嘈杂,无论你如何尝试,都无法得到可靠的结果!

这可能意味着数据集必须更小,限制在科学论文的内容上。但即便如此,科学家们对彼此之间也常常意见不一。

结论是,要产生可靠的结果需要大量的辛勤工作和一支牢固的团队。

现在让我们尝试对 GPT-2 模型进行条件化设置。

生成经过训练的条件样本

在本节中,我们转到笔记本的步骤 12:交互式上下文和完成示例单元格,并运行它:

#@title Step 12: Interactive Context and Completion Examples
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src")
!python interactive_conditional_samples.py --temperature 0.8 --top_k 40 --model_name '117M' --length 50 

工业 4.0 人工智能专家将更少地关注代码,更多地关注如何展示Transformers模型做什么。每个模型都需要一定程度的指导,而不仅仅是使用无条件的数据来模糊地告诉它做某事。

我们通过输入医学论文的一部分来对 GPT-2 模型进行条件设定:

During such processes, cells sense the environment and respond to external factors that induce a certain direction of motion towards specific targets (taxis): this results in a persistent migration in a certain preferential direction. The guidance cues leading to directed migration may be biochemical or biophysical. Biochemical cues can be, for example, soluble factors or growth factors that give rise to chemotaxis, which involves a mono-directional stimulus. Other cues generating mono-directional stimuli include, for instance, bound ligands to the substratum that induce haptotaxis, durotaxis, that involves migration towards regions with an increasing stiffness of the ECM, electrotaxis, also known as galvanotaxis, that prescribes a directed motion guided by an electric field or current, or phototaxis, referring to the movement oriented by a stimulus of light [34]. Important biophysical cues are some of the properties of the extracellular matrix (ECM), first among all the alignment of collagen fibers and its stiffness. In particular, the fiber alignment is shown to stimulate contact guidance [22, 21]. TL;DR: 

我们在输入文本的结尾加上TL;DR:告诉 GPT-2 模型总结我们对它进行条件化的文本。输出在语法和语义上都是有意义的:

the ECM of a single tissue is the ECM that is the most effective.
To address this concern, we developed a novel imaging and immunostaining scheme that, when activated, induces the conversion of a protein to its exogenous target 

由于输出是非确定性的,我们也可能得到这样的回答:

Do not allow the movement to be directed by a laser (i.e. a laser that only takes one pulse at a time), but rather a laser that is directed at a target and directed at a given direction. In a nutshell, be mindful. 

结果更好,但需要更多的研究。

从这个例子和章节中我们可以得出的结论是,对于预训练的Transformers模型,例如在大量随机网络爬行数据上进行预训练,将教导Transformers模型英语。然而,就像我们一样,Transformers也需要在特定领域接受训练,才能成为该领域的专家。

让我们进一步调查并控制分词化的数据。

控制分词化的数据

本节将读取 GPT-2 模型使用其预训练分词器编码的前面词语。

运行单元格时,在运行后续单元格之前停止一个单元格。

我们将转到本章中使用的 Training_OpenAI_GPT_2_CH09.ipynb 笔记本的 Additional Tools: Controlling Tokenized Data 单元格。该单元格是为本章添加到笔记本中的。

该单元首先解压 out.npz,其中包含编码的医学论文,该论文位于数据集 mdset 中:

#@title Additional Tools : Controlling Tokenized Data
#Unzip out.npz
import zipfile
with zipfile.ZipFile('/content/gpt-2/src/out.npz', 'r') as zip_ref:
    zip_ref.extractall('/content/gpt-2/src/') 

解压 out.npz,我们可以读取 arr_0.npy,包含我们正在寻找的编码数据集的 NumPy 数组:

#Load arr_0.npy which contains encoded dset
import numpy as np
f=np.load('/content/gpt-2/src/arr_0.npy')
print(f)
print(f.shape)
for i in range(0,10):
    print(f[i]) 

输出是数组的前几个元素:

[1212 5644  326 ...   13  198 2682] 

现在我们将打开 encoder.json 并将其转换为 Python 字典:

#We first import encoder.json
import json
i=0
with open("/content/gpt-2/models/117M/encoder.json", "r") as read_file:
    print("Converting the JSON encoded data into a Python dictionary")
    developer = json.load(read_file) #converts the encoded data into a Python dictionary
    for key, value in developer.items(): #we parse the decoded json data
        i+=1
        if(i>10):
            break;
        print(key, ":", value) 

最后,我们显示了我们编码数据集的前 500 个标记的键和值:

#We will now search for the key and value for each encoded token
    for i in range(0,500):
        for key, value in developer.items():
            if f[i]==value:
                print(key, ":", value) 

mdset.txt 的前几个单词如下:

This suggests that 

我添加了这些单词以确保 GPT-2 预训练的分词器能够轻松识别它们,这也确实是这样的:

This : 1212
Ġsuggests : 5644
Ġthat : 326 

我们可以轻松识别前导空格字符(Ġ)前的初始标记。然而,让我们看一下医学论文中的下一个词:

amoeboid 

amoeboid 是一个罕见的词。我们可以看到 GPT-2 的分词器将其分解为子词:

Ġam : 716
o : 78
eb : 1765
oid : 1868 

让我们跳过空格,看看发生了什么。amoeboid 变成了 am + o+ eb + oid。我们必须同意,没有未知的标记:[unk]。这是由于使用了字节级 BPE 策略。

然而,Transformers的注意力层可能会关联:

  • am 与其他序列,如 I am

  • o 与任何包含 o 的序列

  • oid 与另一个包含 oid 的序列,可能与某些算法的 tabloid 相关

这一点一点都不好。让我们进一步看看以下单词:

amoeboid and mesenchymal 

输出清晰地显示了 and。至于其余的部分,标记令人困惑:

Ġam : 716
o : 78
eb : 1765
oid : 1868
Ġand : 290
Ġmes : 18842
ench : 24421
ym : 4948
al : 282 

你可能想知道为什么这是个问题。原因可以用一个词来概括:多义性。如果我们使用 word2vec 分词器,词典可能不包含罕见的词语,比如 amoeboid,我们将得到一个未知的标记。

如果我们使用字节级 BPE,我们会得到更好的结果,因为我们排除了更少的同一单词的变体,比如 go 和 go + ing。

然而,amoeboid 中的 am 标记在低级别带来了多义性的问题。am 可以是一种前缀,像 I + am 中的 am,或者像 am + bush 中的子词。注意层可能会将一个标记的 am 关联到另一个 am,从而创建不存在的关系。这定义了自然语言理解中多义性的核心问题。

我们可以说进展正在取得,但我们需要更努力地改进自然语言处理。

我们已经通过一些例子了解了我们在实际项目中面临的很多日常问题。花些时间尝试一些你认为有用的例子。

在我们离开之前,我们将使用一个探测任务来验证Transformers模型提供的自然语言理解水平。

探索 GPT-3 的范围

即使是像 OpenAI GPT-3 这样最强大的转换器也有它们的局限性。让我们看看 GPT-3 如何对待 amoeboid 这个词,它更接近于医学术语而不是主流词汇。在许多项目中,我们需要技术术语。匹配数据集需要质量控制来确保转换器如何组织其字典和嵌入。

我们人类可以检测错误并纠正别人。例如,在本章的 控制标记化数据 部分中,我们探讨了 amoeboid 这个词。

让我们首先问问 GPT-3 amoeboid 是什么意思:

图形用户界面、文本、应用程序、电子邮件 自动生成的描述

图 9.4:询问 GPT-3 “amoeboid” 的含义

amoeboid(类似变形虫)是一个形容词,但 GPT-3 在输出中表示它是一个名词:

A: Amoeboid is a noun which means "resembling an amoeba" 

然后我们向 GPT-3 提出一个更加精确的问题,但仍然得到一个错误的答案:

Q: Is amoeboid a noun or an adjective?
A: Amoeboid is a noun. 

最后,我们坚持要求清晰的定义,并得到了正确的答案:

Q: What does amoeboid mean in medical terms? 
A: Amoeboid means "resembling an amoeba". 

定义是准确的,尽管语法分析不准确。

在现实项目中,什么更重要?是理解一个词的定义,还是确定它在句子中作为形容词还是名词的角色?

一个词的定义对于医学项目来说已经足够了。在这种情况下,GPT-3 可能已经足够了。如果定义已经足够,那么语义角色标注不是理解句子的先决条件。

也许语法方面对于教育语法学校项目很重要,但对于企业供应链、金融和电子商务应用程序来说并不重要。

OpenAI GPT-3 在两种情况下都可以进行微调,正如我们在 第七章,GPT-3 引擎的超人类转变 中所看到的那样。

本节总结认为,我们必须确保在训练好的转换器模型中拥有所有需要的数据。如果没有,标记化过程将是不完整的。也许我们应该拿出一本医学词典,并创建一个包含特定词汇的大型医学文章语料库。然后,如果模型仍然不够准确,我们可能需要对数据集进行标记化并从头开始训练模型。

一个 2022 年的开发者将会有较少的开发工作,但仍然需要大量思考和设计!

现在让我们结束本章,转向另一个 NLU 任务。

总结

在本章中,我们衡量了标记化和后续数据编码过程对转换器模型的影响。一个转换器模型只能关注堆栈中的嵌入和位置编码子层中的标记。这个模型是编码器-解码器、仅编码器还是仅解码器模型并不重要。数据集看起来足够好训练也不重要。

如果标记化过程失败,即使只是部分失败,我们正在运行的转换器模型也会错过关键的标记。

我们首先发现,对于标准语言任务来说,原始数据集可能足以训练一个转换器。

但是,我们发现,即使预训练的标记化器经过了十亿字的训练,它只会创建一个很小的词汇表,其中包含了它遇到的词汇的一小部分。像我们一样,标记化器捕捉到了它正在学习的语言的本质,只有这些词汇也经常被使用,它才会记住最重要的词汇。这种方法对于标准任务效果很好,但在特定任务和词汇方面会出现问题。

然后,我们寻找了一些想法,其中之一是解决标准标记化器的限制。我们应用了一种语言检查方法,以适应我们希望处理的文本,比如一个标记化器思考和编码数据的方式。

我们将该方法应用于 GPT-2 的无条件和有条件任务。

最后,我们分析了数据标记化和匹配数据集与 GPT-3 的限制。从这一章可以得到的教训是,AI 专家将在相当长的一段时间内存在!

在下一章中,基于 BERT 的Transformers的语义角色标注,我们将深入探讨 NLU,并使用 BERT 模型要求Transformers解释句子的含义。

问题

  1. 一个标记化的字典包含了语言中存在的每一个单词。(真/假)

  2. 预训练的标记化器可以对任何数据集进行编码。(真/假)

  3. 在使用数据库之前检查数据库是一个好的做法。(真/假)

  4. 从数据集中清除淫秽数据是一个好的做法。(真/假)

  5. 删除包含歧视性言论的数据是一个好的做法。(真/假)

  6. 原始数据集有时可能产生嘈杂内容和有用内容之间的关系。(真/假)

  7. 一个标准的预训练标记化器包含了过去 700 年的英语词汇。(真/假)

  8. 老式英语可能在用现代英语训练的标记化器对数据进行编码时产生问题。(真/假)

  9. 医学和其他类型的行话可能在用现代英语训练的标记化器对数据进行编码时产生问题。(真/假)

  10. 控制预训练标记化器产生的编码数据的输出是一个好的做法。(真/假)

参考资料

加入我们书籍的 Discord 空间。

加入该书的 Discord 工作区,与作者进行每月的问我任何活动。

www.packt.link/Transformers

第十章:基于 BERT 的Transformers的语义角色标记

Transformers在过去几年中取得的进展比上一代 NLP 更大。标准的 NLU 方法首先学习句法和词汇特征来解释句子的结构。以前的 NLP 模型在运行语义角色标注(SRL)之前会被训练来理解语言的基本句法。

Shi 和 Lin(2019)在他们的论文中提出了一个问题,是否可以跳过初步的句法和词汇训练。基于 BERT 的模型可以在不经历这些传统训练阶段的情况下执行 SRL 吗?答案是肯定的!

Shi 和 Lin(2019)建议将 SRL 视为序列标记,并提供标准化的输入格式。他们基于 BERT 的模型产生了令人惊讶的好结果。

本章将使用基于 Shi 和 Lin(2019)论文的艾伦人工智能研究所提供的预训练基于 BERT 的模型。Shi 和 Lin 通过放弃句法和词汇训练将 SRL 提高到了一个新的水平。我们将看到他们是如何做到的。

我们将首先定义 SRL 和序列标记输入格式的标准化。然后,我们将开始使用艾伦人工智能研究所提供的资源。接下来,我们将在 Google Colab 笔记本中运行 SRL 任务,并使用在线资源来理解结果。

最后,我们将通过运行 SRL 样本来挑战基于 BERT 的模型。第一批样本将展示 SRL 的工作原理。然后,我们将运行一些更困难的样本。我们将逐步推动基于 BERT 的模型达到 SRL 的极限。找到模型的极限是确保Transformers模型的现实和实用之路。

本章涵盖以下主题:

  • 定义语义角色标记

  • 定义 SRL 输入格式的标准化

  • 基于 BERT 的模型架构的主要方面

  • 编码器堆栈如何管理屏蔽的 SRL 输入格式

  • 基于 BERT 的模型 SRL 注意力过程

  • 开始使用由艾伦人工智能研究所提供的资源

  • 构建笔记本来运行预训练的基于 BERT 的模型

  • 在基本示例上测试句子标记

  • 在困难的例子上测试 SRL 并解释结果

  • 将基于 BERT 的模型推向 SRL 的极限并解释如何做到这一点

我们的第一步将是探索 Shi 和 Lin(2019)定义的 SRL 方法。

开始 SRL

对于人类和机器来说,SRL 都是一样困难的。然而,一次又一次,Transformers已经朝着我们人类基线迈出了一步。

在本节中,我们将首先定义 SRL 并举例说明。然后,我们将运行一个预训练的基于 BERT 的模型。

让我们首先定义 SRL 这个棘手的任务。

定义语义角色标记

Shi 和 Lin (2019)推进并证明了一个想法,即我们可以找出谁做了什么以及在哪里,而不依赖于词汇或句法特征。本章基于 Peng Shi 和 Jimmy Lin 在加利福尼亚滑铁卢大学展开的研究。他们展示了Transformers如何通过注意力层更好地学习语言结构。

SRL 将语义角色定义为单词或一组单词在句子中所起的作用以及与谓语所建立的关系。

语义角色是一个名词或名词短语在句子中与主要动词的关系中所扮演的角色。例如,在句子Marvin walked in the park中,Marvin是句子中发生事件的施事者。施事者是事件的执行者。主动词,或控制动词,是walked。

谓语描述了主语或施事者的一些信息。谓语可以是任何提供有关主题特征或行为的信息的东西。在我们的方法中,我们将谓语称为主要动词。例如,在句子Marvin walked in the park中,谓语是walked。

词组在公园里 修饰了走的含义,并且是修饰语。

环绕谓词的名词或名词短语称为论元或论元项。例如,Marvin是walked的一个论元。

我们可以看到,SRL 不需要句法树或词汇分析。

让我们可视化我们的示例的 SRL。

可视化 SRL

本章将使用 Allen Institute 的视觉和代码资源(有关更多信息,请参见参考部分)。 Allen Institute for AI 拥有出色的交互式在线工具,例如我们在本章中用来可视化 SRL 的工具。您可以在demo.allennlp.org/上访问这些工具。

Allen Institute for AI 倡导AI 造福人类。我们将充分利用这种方法。本章中的所有图表都是用 AllenNLP 工具创建的。

Allen Institute 提供了不断发展的Transformers模型。因此,当您运行这些示例时,本章中的示例可能会产生不同的结果。最充分利用本章的最佳方法是:

  • 阅读并理解解释的概念,而不只是运行程序

  • 花时间理解提供的示例

然后,使用本章中使用的工具运行您自己选择的句子进行您自己的实验:demo.allennlp.org/semantic-role-labeling。

现在让我们可视化我们的 SRL 示例。图 10.1是Marvin walked in the park的 SRL 表示:

包含图形用户界面的图片 描述自动生成

图 10.1: 句子的 SRL 表示

我们可以在图 10.1中观察到以下标签:

  • 动词:句子的谓语

  • 论据:一个被命名为ARG0的句子论点

  • 修饰语:句子的修饰成分。在这种情况下是一个地点。它也可以是副词,形容词,或任何修改谓词意义的成分

文本输出同样有趣,其中包含了可视表示标签的缩写形式:

walked: [ARG0: Marvin] [V: walked] [ARGM-LOC: in the park] 

我们已经定义了 SRL 并进行了一个例子。现在是时候看看基于 BERT 的模型了。

运行一个预训练的基于 BERT 的模型

本节将首先描述本章中使用的基于 BERT 的模型的架构。

接下来我们将定义使用 BERT 模型实验 SRL 样本的方法。

让我们开始看一下基于 BERT 的模型的架构。

基于 BERT 的模型架构

AllenNLP 的基于 BERT 的模型是一个 12 层只编码器的 BERT 模型。AllenNLP 团队实现了Shi和Lin(2019)描述的 BERT 模型,并添加了一个额外的线性分类层。

欲了解更多关于 BERT 模型的描述,如有必要,请花几分钟回顾第三章,BERT 模型微调。

基于 BERT 的模型充分利用了双向注意力以简单的方法和架构。Transformers模型的核心潜力存在于注意力层中。我们已经看到了既有编码器和解码器堆栈的Transformers模型。我们已经看到了其他只有编码器层或者解码器层的Transformers。Transformers的主要优势仍然在于近乎人类的注意力层方法。

Shi和Lin(2019)定义的谓词标识格式的输入格式显示了Transformers在标准化语言理解方面取得的进展:

[CLS] Marvin walked in the park.[SEP] walked [SEP] 

训练流程已被标准化:

  • [CLS]表示这是一个分类练习

  • [SEP]是第一个分隔符,表示句子的结束

  • [SEP]后面是作者设计的谓词标识

  • [SEP]是第二个分隔符,表示谓词标识符的结束

光是这种格式就足够训练一个 BERT 模型来识别并标记句子中的语义角色。

让我们设置环境来运行 SRL 样本。

设置 BERT SRL 环境

我们将使用 Google Colab 记事本,在demo.allennlp.org/上提供的 AllenNLP SRL 的文本可视化下进行

我们将应用以下方法:

  1. 我们将打开SRL.ipynb,安装AllenNLP,并运行每个样本

  2. 我们将显示 SRL 运行的原始输出

  3. 我们将使用 AllenNLP 的在线可视化工具来可视化输出

  4. 我们将使用 AllenNLP 的在线文本可视化工具来显示输出

本章是自包含的。您可以阅读它,或按照描述运行示例。

当 AllenNLP 更改了使用的 transformer 模型时,SRL 模型的输出可能会有所不同。这是因为 AllenNLP 的模型和 transformers 通常都是持续训练和更新的。此外,用于训练的数据集可能会发生变化。最后,这些不是基于规则的算法,每次产生的结果可能会有所不同,正如屏幕截图中所描述和显示的那样。

现在让我们运行一些 SRL 实验。

使用基于 BERT 的模型进行 SRL 实验

我们将使用本章“设置 BERT SRL 环境”的方法来运行 SRL 实验。我们将从具有各种句子结构的基本样本开始。然后,我们将挑战基于 BERT 的模型,使用一些更难的样本来探索系统的能力和限制。

打开SRL.ipynb并运行安装单元格:

!pip install allennlp==2.1.0 allennlp-models==2.1.0 

然后我们导入标记模块和训练好的 BERT 预测器:

from allennlp.predictors.predictor import Predictor
import allennlp_models.tagging
import json
predictor = Predictor.from_path("https://storage.googleapis.com/allennlp-public-models/structured-prediction-srl-bert.2020.12.15.tar.gz") 

我们还添加了两个函数来显示 SRL BERT 返回的 JSON 对象。第一个显示谓语动词和描述:

def head(prediction):
  # Iterating through the json to display excerpt of the prediciton
  for i in prediction['verbs']:
    print('Verb:',i['verb'],i['description']) 

第二个函数显示完整的响应,包括标签:

def full(prediction):
  #print the full prediction
  print(json.dumps(prediction, indent = 1, sort_keys=True)) 

在本出版物发布之时,BERT 模型专门用于语义角色标注。该模型的名称是 SRL BERT。SRL BERT 是使用 OntoNotes 5.0 数据集进行训练的:catalog.ldc.upenn.edu/LDC2013T19。

此数据集包含句子和注释。该数据集设计用于识别句子中的谓词(包含动词的部分),并确定提供有关动词的更多信息的单词。每个动词都带有其关于它的“参数”,告诉我们更多信息。一个“框架”包含一个动词的参数。

因此,SRL BERT 是一个专门训练来执行特定任务的专用模型,并且与我们在第七章看到的 OpenAI GPT-3 一样,并不是像 OpenAI GPT-3 这样的基础模型。

SRL BERT 将专注于语义角色标注,只要句子包含谓词,就可以以可以接受的准确度执行。

现在我们已经准备好使用一些基本样本进行热身了。

基本样本

基本样本在直观上看起来很简单,但分析起来可能有点棘手。复合句,形容词,副词和情态动词对于非专业人士来说甚至也很难识别。

让我们从 transformer 的一个简单样本开始。

样本 1

第一个样本很长,但对 transformer 来说相对容易:

“Bob 真的以为自己能在几小时内为 50 个人准备一顿饭吗?”

运行SRL.ipynb中的样本 1单元格:

prediction=predictor.predict(
    sentence="Did Bob really think he could prepare a meal for 50 people in only a few hours?"
)
head(prediction) 

BERT SRL 识别了四个谓词;每个谓词的动词都标记了结果,如在使用head(prediction)函数显示的这段摘录中:

Verb: Did [V: Did] Bob really think he could prepare a meal for 50 people in only a few hours ?
Verb: think Did [ARG0: Bob] [ARGM-ADV: really] [V: think] [ARG1: he could prepare a meal for 50 people in only a few hours] ?
Verb: could Did Bob really think he [V: could] [ARG1: prepare a meal for 50 people in only a few hours] ?
Verb: prepare Did Bob really think [ARG0: he] [ARGM-MOD: could] [V: prepare] [ARG1: a meal for 50 people] [ARGM-TMP: in only a few hours] ? 

您可以通过运行full(prediction)单元格来查看完整的响应。

如果我们根据 PropBank(命题银行)的结构使用数据集参数的描述,例如在这段摘录中,动词think可以被解释为:

  • V标识动词think

  • ARG0标识代理人; 因此,Bob是代理人或“主体代理人”

  • ARGM-ADV将really视为副词(ADV),ARGM表示该副词提供一个修饰语(不是必要的),因此没有编号

如果我们在 AllenNLP 在线界面上运行样本,则会获得每个动词一个框架的 SRL 任务的可视化表示。第一个动词是Did:

图形用户界面,自动生成描述

图 10.2:识别动词“Did”

第二个确认的动词是think:

图形用户界面,应用程序 自动生成描述

图 10.3:识别动词“think”

如果我们仔细观察这个表示,我们可以检测到 SRL BERT 的一些有趣属性:

  • 检测到动词think

  • 避免了可能被解释为主要动词的prepare陷阱。 相反,prepare仍然是think的论点的一部分

  • 检测到一个副词并进行标记

第三个动词是could:

图形用户界面,应用程序 自动生成描述

图 10.4:识别动词“could”和论点

转换器然后转向动词prepare,标记它,并分析其上下文:

图形用户界面,自动生成描述,置信度中等

图 10.5:识别动词“prepare”,论点和修饰语

再次,基于简单 BERT 的转换器模型检测到了大量关于句子语法结构的信息,并发现:

  • 确定动词prepare并将其孤立出来

  • 确定名词he并将其标记为论据,对于a meal for 50 people也做同样处理,这是一个“原始患者”,涉及由其他参与者修改

  • in only a few hours是一个时间修饰语(ARGM-TMP)

  • could是一个表示动词情态性的情态修饰语,例如事件发生的可能性

现在我们将分析另一个相对较长的句子。

样本 2

下面的句子看似简单,但包含多个动词:

Mrs.和 Mr. Tomaso 去欧洲度假并访问巴黎,首先去参观埃菲尔铁塔。

这个令人困惑的句子会使转换器犹豫吗?让我们通过运行SRL.ipynb笔记本的Sample 2单元格来看一下:

prediction=predictor.predict(
    sentence="Mrs. and Mr. Tomaso went to Europe for vacation and visited Paris and first went to visit the Eiffel Tower."
)
head(prediction) 

输出摘录证明转换器正确识别了句子中的动词:

Verb: went [ARG0: Mrs. and Mr. Tomaso] [V: went] [ARG4: to Europe] [ARGM-PRP: for vacation] and visited Paris and first went to visit the Eiffel Tower .
Verb: visited [ARG0: Mrs. and Mr. Tomaso] went to Europe for vacation and [V: visited] [ARG1: Paris] and first went to visit the Eiffel Tower .
Verb: went [ARG0: Mrs. and Mr. Tomaso] went to Europe for vacation and visited Paris and [ARGM-TMP: first] [V: went] [ARG1: to visit the Eiffel Tower] .
Verb: visit [ARG0: Mrs. and Mr. Tomaso] went to Europe for vacation and visited Paris and first went to [V: visit] [ARG1: the Eiffel Tower] . 

在 AllenNLP 在线上运行样本,可识别四个谓词,从而生成四个框架。

第一个框架是went:

图 10.6:识别动词“went”,论点和修饰语

我们可以解释动词went的论点。Mrs.和 Mr. Tomaso是代理。 转换器发现动词的主要修饰语是旅行目的:to Europe。 如果我们不知道Shi和Lin(2019)只是建立了一个简单的 BERT 模型来获取这种高质量的语法分析,则结果将不令人惊讶。

我们还可以注意到went与Europe正确关联。Transformers正确地识别了动词visited与Paris相关联:

图 10.7:识别动词“visited”和论点

Transformers本可以将动词visited直接与Eiffel Tower关联起来。但是它没有。它坚持自己的立场并做出了正确的决定。

我们要求Transformers做的下一个任务是确定动词went的第二次使用的上下文。同样,它没有陷入将与动词went相关的所有论点合并的陷阱。再次,它正确地分割了序列并产生了一个出色的结果:

一个包含文字描述的图像 自动产生的描述

图 10.8:识别动词“went”,论点和修饰语

动词went被使用了两次,但Transformers没有陷入陷阱。它甚至发现first是动词went的时间修饰语。

最后,动词visit第二次被使用,而 SRL BERT 正确解释了它的使用:

一个包含文字描述的图像 自动产生的描述

图 10.9:识别动词“visit”和论点

让我们运行一个更加令人困惑的句子。

示例 3

示例 3 将使我们的Transformers模型变得更加困难。以下示例包含动词drink的变体四次:

John 想喝茶,Mary 喜欢喝咖啡,但 Karim 喝了一些凉爽的水,Faiza 想喝番茄汁。

让我们在 SRL.ipynb 笔记本中运行 示例 3:

prediction=predictor.predict(
    sentence="John wanted to drink tea, Mary likes to drink coffee but Karim drank some cool water and Faiza would like to drink tomato juice."
)
head(prediction) 

Transformers找到了它的方法,如下面输出的摘录所示,其中包含动词:

Verb: wanted [ARG0: John] [V: wanted] [ARG1: to drink tea] , Mary likes to drink coffee but Karim drank some cool water and Faiza would like to drink tomato juice .
Verb: drink [ARG0: John] wanted to [V: drink] [ARG1: tea] , Mary likes to drink coffee but Karim drank some cool water and Faiza would like to drink tomato juice .
Verb: likes John wanted to drink tea , [ARG0: Mary] [V: likes] [ARG1: to drink coffee] but Karim drank some cool water and Faiza would like to drink tomato juice .
Verb: drink John wanted to drink tea , [ARG0: Mary] likes to [V: drink] [ARG1: coffee] but Karim drank some cool water and Faiza would like to drink tomato juice .
Verb: drank John wanted to drink tea , Mary likes to drink coffee but [ARG0: Karim] [V: drank] [ARG1: some cool water] and Faiza would like to drink tomato juice .
Verb: would John wanted to drink tea , Mary likes to drink coffee but Karim drank some cool water and [ARG0: Faiza] [V: would] like [ARG1: to drink tomato juice] .
Verb: like John wanted to drink tea , Mary likes to drink coffee but Karim drank some cool water and [ARG0: Faiza] [ARGM-MOD: would] [V: like] [ARG1: to drink tomato juice] .
Verb: drink John wanted to drink tea , Mary likes to drink coffee but Karim drank some cool water and [ARG0: Faiza] would like to [V: drink] [ARG1: tomato juice] . 

当我们在 AllenNLP 在线界面上运行句子时,我们获得了几个视觉表示。我们将检查其中的两个。

第一个完美。它识别了动词wanted并做出了正确的关联:

图 10.10:识别动词“wanted”和论点

当它识别到动词drank时,它正确地排除了Faiza,并且只产生了some cool water作为论点。

图 10.11:识别动词“drank”和论点

到目前为止,我们发现基于 BERT 的Transformers在基本样本上产生了相对较好的结果。所以让我们尝试一些更困难的样本。

困难样本

本节将运行包含 BERT-based Transformers首先解决的问题的示例。最后,我们将以一个棘手的样本结束。

让我们从一个 BERT-based Transformers可以分析的复杂样本开始。

示例 4

示例 4 将我们带入更复杂的 SRL 领域。该样本将Alice与动词liked分开,创建了一个长期依赖,必须跳过whose husband went jogging every Sunday.

句子是:

Alice,她的丈夫每个星期天都去慢跑,而她则喜欢在此期间去跳舞课。

一个人可以分离出Alice并找到谓词:

爱丽丝喜欢在此期间去上舞蹈课。

BERT 模型能像我们一样找到谓词吗?

让我们首先在SRL.ipynb中运行代码,看看结果如何:

prediction=predictor.predict(
    sentence="Alice, whose husband went jogging every Sunday, liked to go to a dancing class in the meantime."
)
head(prediction) 

输出确定了每个谓词的动词并标记了每个框架:

Verb: went Alice , [ARG0: whose husband] [V: went] [ARG1: jogging] [ARGM-TMP: every Sunday] , liked to go to a dancing class in the meantime .
Verb: jogging Alice , [ARG0: whose husband] went [V: jogging] [ARGM-TMP: every Sunday] , liked to go to a dancing class in the meantime .
Verb: liked [ARG0: Alice , whose husband went jogging every Sunday] , [V: liked] [ARG1: to go to a dancing class in the meantime] .
Verb: go [ARG0: Alice , whose husband went jogging every Sunday] , liked to [V: go] [ARG4: to a dancing class] [ARGM-TMP: in the meantime] .
Verb: dancing Alice , whose husband went jogging every Sunday , liked to go to a [V: dancing] class in the meantime . 

让我们关注我们感兴趣的部分,看看模型是否找到了谓词。它找到了!它在输出的节选中找到了动词liked,尽管动词like与Alice被另一个谓词隔开:

动词:liked [ARG0: Alice,whose husband went jogging every Sunday]

现在让我们看看在 AllenNLP 的在线 UI 上运行样本后模型分析的视觉表示。转换器首先找到了爱丽丝的丈夫:

Une image contenant texte  Description générée automatiquement

图 10.12:谓语“went”已被识别

转换器解释道:

  • 谓语或动词是went

  • whose husband是参数

  • 慢跑是另一个与went相关的参数

  • 每个星期天是一个表示在原始输出中的时间修饰语 [ARGM-TMP: 每个星期天]

然后转换器发现了爱丽丝的丈夫在做什么:

Une image contenant texte  Description générée automatiquement

图 10.13:动词“慢跑”的 SRL 检测

我们可以看到动词jogging被识别出来并与她的丈夫以及时态修饰语每个星期天相关联。

转换器到此为止。现在它发现了爱丽丝喜欢什么:

图 10.14:识别动词“liked”

转换器还正确地检测和分析了动词go:

图 10.15:检测动词“go”,它的参数和修饰语

我们可以看到,时态修饰语与此同时也被识别出来了。考虑到 SRL BERT 训练时的简单序列 + 动词输入,这是相当出色的表现。

最后,转换器确定了最后一个动词dancing与class有关:

Une image contenant texte  Description générée automatiquement

图 10.16:将参数“class”与动词“跳舞”相关联

示例 4产生的结果相当令人信服!让我们尝试找到转换器模型的极限。

示例 5

示例 5 不会多次重复动词。但是,示例 5 包含一个具有多种功能和含义的单词。它超越了一词多义,因为单词round可以有不同的含义和语法功能。单词round可以是名词、形容词、副词、及物动词或不及物动词。

作为及物动词或不及物动词,round可以达到完美或完成。在这个意义上,round可以用于off。

以下句子使用round的过去式:

明亮的太阳,蓝天,温暖的沙滩,棕榈树,一切都圆满结束。

此谓词中的动词round是“使完美”的意思。当然,最容易理解的语法形式应该是“rounded”。但我们来看看我们的句子会发生什么。

让我们在SRL.ipynb中运行Sample 5:

prediction=predictor.predict(
    sentence="The bright sun, the blue sky, the warm sand, the palm trees, everything round off."
)
head(prediction) 

输出显示没有动词。变换器未识别出谓词。实际上,即使我们运行full(prediction)函数时,它也找不到任何动词:

"verbs": [] 

然而,在线版本似乎更好地解释了句子,因为它找到了动词:

图 10.17:检测动词“round”和“everything”作为参数

既然我们喜欢我们的 SRL 变换器,我们会对它友好。我们将向它展示如何处理更常用的动词形式。我们将句子从过去时改为现在时,通过在round后加上s:

明亮的阳光,蓝色的天空,温暖的沙滩,棕榈树,一切都 rounds off。

让我们再次尝试用现在时运行SRL.ipynb:

prediction=predictor.predict(
    sentence="The bright sun, the blue sky, the warm sand, the palm trees, everything rounds off."
)
head(prediction) 

原始输出显示找到了谓词,如下输出所示:

Verb: rounds [ARG1: The bright sun , the blue sky , the warm sand , the palm trees , everything] [V: rounds] [ARGM-PRD: off] . 

如果我们在 AllenNLP 上运行句子,我们将得到视觉解释:

图 10.18:检测单词“rounds”作为动词

我们基于 BERT 的变换器表现良好,因为单词round在其现在时形式rounds中可以找到。

BERT 模型最初未能产生我们预期的结果。但在它的朋友的一点帮助下,这个样本最终结束得不错。

我们可以看到:

  • 输出可能会随着我们实施的模型版本的演变而有所不同

  • 工业 4.0 的实用主义心态需要更多认知努力来向变换器展示要做什么

让我们尝试另一个难以标记的句子。

样本 6

Sample 6选取了一个我们经常认为只是名词的词。然而,我们怀疑的词比我们想象的更多,可以是名词也可以是动词。例如,to ice是曲棍球中用来将冰球射向整个溜冰场并超出对手球门线的动词。冰球是曲棍球中使用的圆盘。

曲棍球教练可以通过告诉队伍训练冰球来开始一天。然后当教练喊道时,我们可以得到祈使句:

现在,让冰球过去,伙计们!

请注意,guys可以表示无论性别的人。

让我们运行Sample 6单元格,看看会发生什么:

prediction=predictor.predict(
    sentence="Now, ice pucks guys!"
)
head(prediction) 

变换器无法找到动词:“verbs”:[]。

游戏结束!我们可以看到变换器已经取得了巨大的进步,但开发人员仍然有很多改进模型的空间。人类仍然在向变换器展示要做什么的游戏中。

在线界面将pucks与动词混淆:

图 10.19:模型错误地将“pucks”标记为动词

这个问题可能会通过另一个模型解决,但你会遇到另一个限制。即使是 GPT-3 也有你必须应对的限制。

当你为一个定制的应用程序实现变换器时,使用专业术语或技术词汇,你会在某个时候达到难以解决的限制。

这些限制将需要您的专业知识来使项目成功。因此,您将不得不创建专门的词典才能在项目中取得成功。这对开发人员来说是个好消息!您将培养新的跨学科和认知技能,您的团队会感激您的。

尝试一些您自己的示例或样本,看看 SRL 如何处理这种方法的限制。然后探索如何开发预处理函数,以向变换器展示如何处理您的定制应用程序。

在我们离开之前,让我们质疑一下 SRL 的动机。

质疑 SRL 的范围

当我们面对现实项目时,我们是孤身一人。我们有一项工作要做,唯一要满足的人是那些要求该项目的人。

实用主义必须放在前面。技术意识随后。

在 20 世纪 20 年代,前人工智能意识和新意识并存。到了十年结束时,只会有一个赢家将前者的部分融合到后者中。

本节质疑了 SRL 的生产力,同时也通过两个方面质疑了其动机:

  • 谓词分析的限制

  • 质疑“语义”一词的使用

谓词分析的限制

SRL 依赖于谓词。只要提供动词,SRL BERT 就能工作。但是数百万句子没有包含动词。

如果你在 AllenNLP 演示界面的语义角色标注部分(demo.allennlp.org/)只提供了 SRL BERT 的断言,它就能工作。

但是,如果你的断言是对问题的回答会发生什么:

  • 人员 1:请问您想喝什么?

  • 人员 2:一杯咖啡,谢谢。

当我们输入人员 2 的答案时,SRL BERT 什么也找不到:

图形用户界面、文本、应用程序、聊天或文本消息 自动产生描述

图 10.20:未获得任何帧

输出是0个总帧。由于含有省略号,SRL 无法分析此句。谓词是隐式的,而不是显式的。

省略的定义是省略句子中不必要理解的一个或多个词。

每天都会有数亿句包含省略的句子被口头和书面表达。

然而,对于所有这些句子,SRL BERT 都产生了0 个总帧。

下面的回答(A)对以what、where和how开头的问题(Q)产生了0 个总帧:

Q: 早餐想要吃什么?

A: 用热巧克力的薄煎饼。

(模型推断:pancakes=专有名词,with=介词,hot=形容词,chocolate=普通名词。)

Q: 您想去哪里?

A: 请去伦敦。

(模型推断:London=专有名词,please=副词。)

Q: 你今天怎么去上班的?

A: Subway.

(模型推断:subway=专有名词。)

我们可以找到数百万个 SRL BERT 无法理解的例子,因为这些句子不包含谓词。

我们也可以将其应用到对话中间的问题上,但仍然无法从 SRL BERT 获得帧(输出):

场景:对话中段,人 2 不想要咖啡:

Q: 那么,茶呢?

A: 不用了,谢谢。

Q: 好的,热巧克力呢?

A: 没有。

Q: 一杯水?

A: 是的!

我们刚刚看到了一段没有框架、没有语义标注的对话。什么都没有。

我们可以在社交媒体上发布一些电影、音乐会或展览的评论,这些评论不包含任何框架:

  • 有史以来最好的电影!

  • 我一生中最糟糕的音乐会!

  • 精彩的展览!

这一节展示了 SRL 的局限性。现在让我们重新定义 SRL 并展示如何实现它。

重新定义 SRL

SRL BERT 假设句子包含谓词,这在许多情况下是错误的假设。仅基于谓词分析来分析句子是不正确的。

谓词包含一个动词。谓词告诉我们更多关于主语的信息。下面的谓词包含一个动词和额外的信息:

`The dog ate his food quickly.` 

快速吃...告诉我们关于狗吃饭的方式更多的信息。然而,动词本身可以是一个谓词,如:

狗吃。

这里的问题在于“动词”和“谓词”是语法和语法分析的一部分,而不是语义学的一部分。

从语法、功能的角度理解词语如何组合是有限制的。

看这句完全毫无意义的句子:

`Globydisshing maccaked up all the tie.` 

SRL BERT 完美地对一句毫无意义的句子进行“语义”分析:

一个包含时间线描述的图片 自动生成

图 10.21:分析无意义的句子

我们可以从这些例子中得出一些结论:

  • SRL 谓词分析仅在句子中存在动词时才有效

  • SRL(语义角色标注)谓词分析无法识别省略。

  • 谓词和动词是语言结构的一部分,是语法分析的一部分

  • 谓词分析识别结构,但不能理解句子的意义

  • 语法分析远远超出了谓词分析作为句子必要中心的范围

语义学关注短语或句子的意义。语义学关注上下文和词语之间的关系。

语法分析包括句法、屈折和短语或句子中单词的功能。术语“语义角色标注”具有误导性;它应该被命名为“谓词角色标注”。

我们可以完全理解没有谓词并超出顺序结构的句子。

情感分析可以解码句子的含义,并给出输出,而不需要进行谓词分析。情感分析算法完全理解“有史以来最好的电影”是积极的,无论是否存在谓词。

单独使用 SRL 来分析语言是有限制的。将 SRL 与 AI 流水线或其他 AI 工具结合使用可以非常有益,以增加对自然语言理解的智能化。

我建议将 SRL 与其他 AI 工具结合使用,正如我们将在第十三章中看到的,使用 Transformer 分析假新闻。

现在让我们总结一下我们对 SRL 的范围和限制的探讨。

摘要

在本章中,我们探讨了 SRL。SRL 任务对人类和机器都很困难。Transformers模型已经显示出在许多 NLP 主题上在一定程度上可以达到人类基线。

我们发现,一个简单的基于 BERT 的Transformers可以执行谓词语义消歧。我们运行了一个简单的Transformers,它可以识别动词(谓词)的含义,而无需词汇或句法标签。Peng Shi和Jimmy Lin(2019)使用了标准的句子 + 动词输入格式来训练他们的基于 BERT 的Transformers。

我们发现,使用简化的句子 + 谓词输入训练的Transformers可以解决简单和复杂的问题。当我们使用相对罕见的动词形式时,就达到了限制。然而,这些限制并非最终。如果将困难问题添加到训练数据集中,研究团队可以改进模型。

我们还发现了为了人类的利益而存在的 AI。艾伦人工智能研究所已经提供了许多免费的 AI 资源。此外,研究团队还向 NLP 模型的原始输出添加了可视化表示,以帮助用户理解 AI。我们发现解释 AI 与运行程序一样重要。可视化和文本表示提供了对基于 BERT 模型潜力的清晰视图。

最后,我们探讨了 SRL 的范围和限制,以优化我们如何将该方法与其他 AI 工具结合使用。

Transformers将通过其分布式架构和输入格式继续改进 NLP 的标准化。

在下一章,第十一章,让您的数据说话:故事、问题和答案中,我们将在通常只有人类表现良好的任务上挑战Transformers。我们将探索当面临命名实体识别(NER)和问答任务时,Transformers的潜力。

问题

  1. 语义角色标注(SRL)是一个文本生成任务。(真/假)

  2. 谓词是一个名词。(真/假)

  3. 动词是一个谓词。(真/假)

  4. 参数可以描述谁和什么在做某事。(真/假)

  5. 修饰语可以是副词。(真/假)

  6. 修饰语可以是一个地点。(真/假)

  7. 基于 BERT 的模型包含编码器和解码器堆叠。(真/假)

  8. 基于 BERT 的 SRL 模型具有标准的输入格式。(真/假)

  9. Transformers可以解决任何 SRL 任务。(真/假)

参考文献

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作空间,与作者进行每月的问我任何事会话:

www.packt.link/Transformers

第十一章:让你的数据说话:故事、问题和答案

阅读理解需要许多技能。当我们阅读一段文字时,我们注意关键词和主要事件,并创造内容的心理表征。然后我们可以利用我们对内容和表征的知识来回答问题。我们还会检查每个问题,以避免陷阱和错误。

无论它们变得多么强大,Transformers都不能轻松回答开放式问题。开放环境意味着有人可以就任何主题提出任何问题,而Transformers会正确回答。这对于某种程度的 GPT-3 来说是困难的,正如我们将在本章中看到的那样。然而,Transformers通常在封闭的问答环境中使用通用领域训练数据集。例如,在医疗保健和法律解释中的关键性答案通常需要额外的 NLP 功能。

然而,Transformers不能无论训练环境是否闭合都正确回答任何问题。如果一个序列包含多个主语和复合命题,Transformers模型有时会做出错误的预测。

本章将重点介绍构建问题生成器的方法,该生成器利用其他 NLP 任务帮助在文本中找到明确的内容。问题生成器将展示一些应用于实现问答的思想。

我们将首先展示问随机问题并期望Transformers每次都能良好响应的困难程度。

我们将通过引入命名实体识别(NER)功能来帮助DistilBERT模型回答问题,该功能建议合理的问题。此外,我们还将为Transformers的问题生成器奠定基础。

我们将把一个预训练为鉴别器的 ELECTRA 模型添加到我们的问答工具箱中。

我们将在文本生成器的蓝图中添加语义角色标注(SRL)功能。

然后,下一步部分将提供额外的想法来构建可靠的问答解决方案,包括实现Haystack框架。

最后,我们将直接进入 GPT-3 Davinci 引擎在线界面,探索开放环境下的问答任务。再次强调,无需开发、培训和准备!

在本章结束时,你将看到如何构建自己的多任务 NLP 助手或使用云 AI 进行问答。

本章涵盖以下主题:

  • 随机问答的极限

  • 利用命名实体识别根据实体识别创建有意义的问题

  • 开始设计Transformers问题生成器的蓝图

  • 测试使用 NER 找到的问题

  • 引入预训练为鉴别器的 ELECTRA 编码器

  • 使用标准问题测试 ELECTRA 模型

  • 利用语义角色标注根据谓词识别创建有意义的问题

  • 实施问答Transformers的项目管理指南

  • 分析如何利用 SRL 生成问题

  • 利用 NER 和 SRL 的输出来定义Transformers问题生成器的蓝图

  • 使用 RoBERTa 探索 Haystack 的问答框架

  • 使用 GPT-3 的界面无需开发或准备

让我们首先通过我们将应用的方法来分析问答任务的问题生成过程。

方法论

问答主要是作为一个涉及Transformers和包含准备提问和回答这些问题的数据集的 NLP 练习。Transformers被训练来回答在这个封闭环境中提出的问题。

然而,在更复杂的情况下,可靠的Transformers模型实现需要定制方法。

Transformers和方法

完美和高效的通用Transformers模型,无论是用于问答还是其他 NLP 任务,都不存在。对于一个特定的数据集和任务来说,最适合的模型是产生最佳输出的模型。

该方法在许多情况下优于模型。例如,一个适当的方法通常会比一个优秀模型但有缺陷的方法产生更高效的结果。

在本章中,我们将运行DistilBERT、ELECTRA和RoBERTa模型。有些比其他模型有更好的性能。

但是,在关键领域中,性能并不保证结果。

例如,在太空火箭和航天器生产项目中,向 NLP 机器人提问意味着获得一个确切的答案。

假设用户需要在一个关于火箭再生式冷却喷嘴和燃烧室状态的一百页报告中提出问题。问题可能很具体,比如冷却状态可靠吗?这是用户从 NLP 机器人那里想要得到的底线信息。

简而言之,让 NLP 机器人、Transformers模型或其他任何东西做一个没有质量和认知控制的统计答案是太冒险了,也不会发生。可信赖的 NLP 机器人将连接到一个包含数据和规则的知识库,以在后台运行基于规则的专家系统来检查 NLP 机器人的答案。NLP Transformers模型机器人将产生一个流畅、可靠的自然语言答案,可能还是人声。

适用于所有需求的通用Transformers模型和方法并不存在。每个项目都需要特定的功能和定制的方法,这取决于用户的期望值,变化将是巨大的。

本章将着眼于超出特定Transformers模型选择范围的问答的一般约束。本章不是一个问答项目指南,而是介绍了Transformers如何用于问答。

我们将专注于在没有事先准备的情况下使用问答在开放环境中。Transformers模型需要其他 NLP 任务和经典程序的帮助。我们将探索一些方法,以提供如何组合任务以达到项目目标的想法:

  • Method 0 探索了随机提问的试错方法。

  • Method 1 引入 NER 来帮助准备问答任务。

  • Method 2 尝试使用 ELECTRA Transformers模型来帮助默认Transformers。它还引入了 SRL 来帮助Transformers准备问题。

这三种方法的介绍表明,单一的问答方法对于高调的公司项目不起作用。添加 NER 和 SRL 将提高Transformers代理解决方案的语言智能。

例如,在我最早的一个 AI NLP 项目中,为航空航天公司的防御项目实施问答功能,我结合了不同的 NLP 方法,以确保提供的答案是100%可靠的。

您可以为您实施的每个项目设计一个多方法解决方案。

让我们从试错方法开始。

Method 0:试错

问答似乎非常简单。这是真的吗?让我们来看看。

打开本章将使用的 Google Colab 笔记本QA.ipynb。我们将逐个单元格地运行笔记本。

运行第一个单元格来安装 Hugging Face 的 transformers,这是我们将在本章中实施的框架:

!pip install -q transformers 

注意:Hugging Face transformers 不断发展,更新库和模块以适应市场。如果默认版本不起作用,您可能需要使用!pip install transformers==[与笔记本中的其他函数兼容的版本]来固定一个版本。

我们现在将导入 Hugging Face 的 pipeline,其中包含许多即用型Transformers资源。它们为 Hugging Face 库资源提供高级抽象函数,以执行各种任务。我们可以通过一个简单的 API 访问这些 NLP 任务。该程序是在 Google Colab 上创建的。建议使用免费的 Gmail 帐户在 Google Colab VM 上运行它。

通过一行代码导入pipeline:

from transformers import pipeline 

一旦完成,我们有一行选项来实例化Transformers模型和任务:

  1. 使用默认的model和默认的tokenizer执行一个 NLP 任务:

    pipeline("<task-name>") 
    
  2. 使用自定义model执行一个 NLP 任务:

    pipeline("<task-name>", model="<model_name>") 
    
  3. 使用自定义model和自定义tokenizer执行 NLP 任务:

    pipeline('<taskname>', model='<model name>', tokenizer='<tokenizer_name>') 
    

让我们从默认模型和分词器开始:

nlp_qa = pipeline('question-answering') 

现在,我们只需要提供一段文本,然后我们将使用它来向Transformers提交问题:

sequence = "The traffic began to slow down on Pioneer Boulevard in Los Angeles, making it difficult to get out of the city. However, WBGO was playing some cool jazz, and the weather was cool, making it rather pleasant to be making it out of the city on this Friday afternoon. Nat King Cole was singing as Jo, and Maria slowly made their way out of LA and drove toward Barstow. They planned to get to Las Vegas early enough in the evening to have a nice dinner and go see a show." 

这个序列看起来非常简单,我们所需要做的就是将一行代码插入 API 中来提问并获得答案:

nlp_qa(context=sequence, question='Where is Pioneer Boulevard ?') 

输出是一个完美的答案:

{'answer': 'Los Angeles,', 'end': 66, 'score': 0.988201259751591, 'start': 55} 

我们刚刚用几行代码实现了一个问答Transformers NLP 任务!您现在可以下载一个包含文本、问题和答案的即用数据集。

实际上,本章可以在此结束,您将准备好进行问答任务了。然而,在实际实施中事情从来都不简单。假设我们必须为用户实现一个问答变换模型,让用户在数据库中存储的许多文档上提问。我们有两个重要的约束:

  • 我们首先需要运行变换器通过一组关键文档,并创建显示系统工作的问题

  • 我们必须展示如何保证变换器正确回答问题

几个问题立即出现:

  • 谁将找到要询问测试系统的问题?

  • 即使专家同意做这项工作,如果许多问题产生错误结果会怎么样?

  • 如果结果不令人满意,我们是否会继续训练模型?

  • 如果一些问题无论我们使用或训练哪个模型都无法回答,会发生什么?

  • 如果这在有限样本上有效,但过程耗时且无法扩展,因为成本过高,会怎样?

如果我们只是试试专家帮助我们提出的问题,看看哪些有效,哪些无效,那将永远不会完成。试错不是解决方案。

本章旨在提供一些方法和工具,以降低实施问答变换模型的成本。在为客户实施新数据集时,为问答问题找到好问题是一项相当大的挑战。

我们可以将变换器视为我们可以根据需要组装的一套乐高®(LEGO®)堆积积木,使用编码器堆栈或解码器堆栈。我们可以使用一组小型、大型或超大(XL)变换器模型。

我们还可以将我们在本书中探讨过的 NLP 任务看作是我们必须实施的项目中的解决方案的一套乐高®(LEGO®)集。我们可以组装两个或更多 NLP 任务来达到我们的目标,就像任何其他软件实现一样。我们可以从试错搜索问题转向系统方法。

在本章中:

  • 我们将继续逐个单元格运行QA.ipynb来探索每个部分描述的方法。

  • 我们还将使用AllenNLP NER 接口获取 NER 和 SRL 结果的可视化表示。您可以通过访问demo.allennlp.org/reading-comprehension,然后选择命名实体识别或语义角色标注,并输入序列,在界面中输入句子。在本章中,我们将考虑使用的AllenNLP模型。我们只想获得可视化表示。

让我们从尝试使用 NER-first 方法为问题回答找到合适的 XL 变换器模型问题开始。

方法 1:NER 先

本节将使用 NER 来帮助我们找到好问题的想法。Transformers模型是持续训练和更新的。此外,用于训练的数据集可能会发生变化。最后,这些不是基于规则的算法,每次可能产生相同的结果。输出可能会在一个运行到另一个运行之间发生变化。NER 可以检测序列中的人、位置、组织和其他实体。我们首先运行一个 NER 任务,它将为我们提供段落的一些主要部分,以便我们专注于提问。

使用 NER 寻找问题

我们将继续逐步运行QA.ipynb。现在程序使用 NER 任务以默认模型和分词器初始化管道:

nlp_ner = pipeline("ner") 

我们将继续使用本章方法 0:试和错误部分中运行的看似简单的序列:

sequence = "The traffic began to slow down on Pioneer Boulevard in Los Angeles, making it difficult to get out of the city. However, WBGO was playing some cool jazz, and the weather was cool, making it rather pleasant to be making it out of the city on this Friday afternoon. Nat King Cole was singing as Jo and Maria slowly made their way out of LA and drove toward Barstow. They planned to get to Las Vegas early enough in the evening to have a nice dinner and go see a show." 

我们在QA.ipynb中运行了nlp_ner单元格:

print(nlp_ner(sequence)) 

输出生成了自然语言处理任务的结果。分数被四舍五入到两位小数以适应页面的宽度:

[{'word': 'Pioneer', 'score': 0.97, 'entity': 'I-LOC', 'index': 8}, 
{'word': 'Boulevard', 'score': 0.99, 'entity': 'I-LOC', 'index': 9}, 
{'word': 'Los', 'score': 0.99, 'entity': 'I-LOC', 'index': 11}, 
{'word': 'Angeles', 'score': 0.99, 'entity': 'I-LOC', 'index': 12}, 
{'word': 'W', 'score': 0.99, 'entity': 'I-ORG', 'index': 26}, 
{'word': '##B', 'score': 0.99, 'entity': 'I-ORG', 'index': 27}, 
{'word': '##G', 'score': 0.98, 'entity': 'I-ORG', 'index': 28}, 
{'word': '##O', 'score': 0.97, 'entity': 'I-ORG', 'index': 29}, 
{'word': 'Nat', 'score': 0.99, 'entity': 'I-PER', 'index': 59}, 
{'word': 'King', 'score': 0.99, 'entity': 'I-PER', 'index': 60}, 
{'word': 'Cole', 'score': 0.99, 'entity': 'I-PER', 'index': 61}, 
{'word': 'Jo', 'score': 0.99, 'entity': 'I-PER', 'index': 65}, 
{'word': 'Maria', 'score': 0.99, 'entity': 'I-PER', 'index': 67},
{'word': 'LA', 'score': 0.99, 'entity': 'I-LOC', 'index': 74}, 
{'word': 'Bar', 'score': 0.99, 'entity': 'I-LOC', 'index': 78}, 
{'word': '##sto', 'score': 0.85, 'entity': 'I-LOC', 'index': 79}, 
{'word': '##w', 'score': 0.99, 'entity': 'I-LOC', 'index': 80}, 
{'word': 'Las', 'score': 0.99 'entity': 'I-LOC', 'index': 87}, 
{'word': 'Vegas', 'score': 0.9989519715309143, 'entity': 'I-LOC', 'index': 88}] 

Hugging Face 的文档描述了在我们的案例中使用的标签。主要的标签包括:

  • I-PER,一个人的名字

  • I-ORG,一个组织名称

  • I-LOC,一个位置名称

结果是正确的。注意Barstow被分成了三个标记。

让我们在命名实体识别部分的AllenNLP上运行相同的序列(demo.allennlp.org/named-entity-recognition)以获得我们序列的可视化表示:

文本说明自动生成

图 11.1:NER

我们可以看到 NER 已经突出显示了我们将用于创建问答问题的关键实体。

让我们询问我们的Transformers两种类型的问题:

  • 与位置相关的问题

  • 与人有关的问题

让我们从位置问题开始。

位置实体问题

QA.ipynb生成了近 20 个实体。位置实体特别有趣:

[{'word': 'Pioneer', 'score': 0.97, 'entity': 'I-LOC', 'index': 8}, 
{'word': 'Boulevard', 'score': 0.99, 'entity': 'I-LOC', 'index': 9}, 
{'word': 'Los', 'score': 0.99, 'entity': 'I-LOC', 'index': 11}, 
{'word': 'Angeles', 'score': 0.99, 'entity': 'I-LOC', 'index': 12}, 
{'word': 'LA', 'score': 0.99, 'entity': 'I-LOC', 'index': 74}, 
{'word': 'Bar', 'score': 0.99, 'entity': 'I-LOC', 'index': 78}, 
{'word': '##sto', 'score': 0.85, 'entity': 'I-LOC', 'index': 79}, 
{'word': '##w', 'score': 0.99, 'entity': 'I-LOC', 'index': 80}, 
{'word': 'Las', 'score': 0.99 'entity': 'I-LOC', 'index': 87}, 
{'word': 'Vegas', 'score': 0.9989519715309143, 'entity': 'I-LOC', 'index': 88}] 

应用启发式方法

我们可以应用启发式方法,使用QA.ipynb生成的输出创建问题:

  • 将位置合并回其原始形式

  • 将模板应用到位置

本书的范围已经超出了为项目写经典代码的范围。我们可以编写一个能为我们完成工作的函数,如下伪代码所示:

for i in range beginning of output to end of the output:
    filter records containing I-LOC
    merge the I-LOCs that fit together
    save the merged I-LOCs for questions-answering 

NER 的输出将变为:

  • I-LOC,Pioneer Boulevard

  • I-LOC,Los Angeles

  • I-LOC,LA

  • I-LOC,Barstow

  • I-LOC,Las Vegas

我们可以使用两个模板自动生成问题。例如,我们可以应用一个随机函数。我们可以编写一个能为我们完成工作的函数,如下伪代码所示:

from the first location to the last location:
    choose randomly:
        Template 1: Where is [I-LOC]?
        Template 2: Where is [I-LOC] located? 

我们将自动生成五个问题。例如:

Where is Pioneer Boulevard?
Where is Los Angeles located?
Where is LA?
Where is Barstow?
Where is Las Vegas located? 

我们知道,有些问题不能直接用我们创建的序列回答。但我们也可以自动处理这个问题。假设问题是用我们的方法自动生成的:

  1. 输入一个序列

  2. 运行 NER

  3. 自动创建问题

假设问题是自动生成的,然后让我们运行它们:

nlp_qa = pipeline('question-answering')
print("Question 1.",nlp_qa(context=sequence, question='Where is Pioneer Boulevard ?'))
print("Question 2.",nlp_qa(context=sequence, question='Where is Los Angeles located?'))
print("Question 3.",nlp_qa(context=sequence, question='Where is LA ?'))
print("Question 4.",nlp_qa(context=sequence, question='Where is Barstow ?'))
print("Question 5.",nlp_qa(context=sequence, question='Where is Las Vegas located ?')) 

输出显示只有 问题 1 被正确回答了:

Question 1\. {'score': 0.9879662851935791, 'start': 55, 'end': 67, 'answer': 'Los Angeles,'}
Question 2\. {'score': 0.9875189033668121, 'start': 34, 'end': 51, 'answer': 'Pioneer Boulevard'}
Question 3\. {'score': 0.5090435442006118, 'start': 55, 'end': 67, 'answer': 'Los Angeles,'}
Question 4\. {'score': 0.3695214621538554, 'start': 387, 'end': 396, 'answer': 'Las Vegas'}
Question 5\. {'score': 0.21833994202792262, 'start': 355, 'end': 363, 'answer': 'Barstow.'} 

输出显示了 分数、答案的 起始 和 结束 位置,以及 答案 本身。在这次运行中,问题 2 的 分数 是 0.98,尽管它错误地说明了 Pioneer Boulevard 在 Los Angeles 中。

现在我们该怎么办?

现在是控制Transformers的时间了,通过项目管理来增加质量和决策功能。

项目管理

我们将检查四个例子,其中包括管理Transformers和管理它的硬编码函数的方法。我们将这四个项目管理示例分类为四个项目级别:简单、中级、困难和非常困难。项目管理不在本书的范围之内,因此我们将简要介绍这四个类别:

  1. 一个简单的项目 可以是一个小学的网站。老师可能会对我们所见到的感到高兴。文本可以显示在 HTML 页面上。我们自动获得的五个问题的答案可以与一些开发合并为五个断言,并以固定格式显示:I-LOC 在 I-LOC 中(例如,Barstow 在 California 中)。然后在每个断言下添加 (True, False)。老师所需要做的就是有一个管理员界面,允许老师点击正确答案来完成多项选择问卷!

  2. 一个中级项目 可以是封装Transformers的自动问题和答案,使用 API 检查答案并自动纠正的程序。用户看不到任何东西。这个过程是无缝的。Transformers产生的错误答案将被存储以供进一步分析。

  3. 一个困难的项目 将是在具有后续问题的聊天机器人中实现一个中级项目。例如,Transformers将 Pioneer Boulevard 正确放置在 Los Angeles 中。聊天机器人用户可能会问一个自然的后续问题,比如 在 LA 的哪里附近? 这需要更多的开发。

  4. 一个非常困难的项目 将是一个研究项目,培训Transformers识别数据集中数百万记录中的 I-LOC 实体,并输出地图软件 API 的实时流结果。

好消息是我们也可以找到一种利用我们所发现的方法。

坏消息是,实现的Transformers或任何现实项目中的 AI 需要强大的机器和项目经理、主题专家(SMEs)、开发人员和最终用户之间大量的团队合作。

现在让我们尝试人物实体问题。

人物实体问题

让我们从Transformers的一个简单问题开始:

nlp_qa = pipeline('question-answering')
nlp_qa(context=sequence, question='Who was singing ?') 

答案是正确的。它说明了序列中谁在唱歌:

{'answer': 'Nat King Cole,'
 'end': 277,
 'score': 0.9653632081862433,
 'start': 264} 

现在我们将向Transformers提出一个需要一些思考的问题,因为它没有明确陈述:

nlp_qa(context=sequence, question='Who was going to Las Vegas ?') 

不能回答那个问题而不分析句子。转换器犯了一个大错误:

{'answer': 'Nat King Cole,'
 'end': 277,
 'score': 0.3568152742800521,
 'start': 264} 

转换器足够诚实,只显示了一个0.35的分数。这个分数可能因每次计算或不同转换器模型而异。我们可以看到转换器遇到了一个语义标记问题。让我们尝试通过应用 SRL-first 方法来更好地处理人物实体问题。

方法 2:首先进行 SRL

转换器找不到是谁驾车去Las Vegas,认为是来自Nat King Cole而不是Jo和Maria。

发生了什么错了?我们能看到转换器的想法并获得解释吗?要找出,请返回语义角色建模。如果需要,花几分钟回顾第十章,基于 BERT 的转换器的语义角色标记。

让我们在语义角色标记部分的AllenNLP上运行相同的序列,demo.allennlp.org/semantic-role-labeling,以通过运行我们在上一章节中使用的 SRL BERT 模型来获取动词drove的视觉表示:

图形用户界面、文本、应用程序  自动生成描述

图 11.2:在文本上运行的 SRL

SRL BERT 找到了 19 个帧。在本节中,我们专注于drove。

注意:结果可能因每次运行或当 AllenNLP 更新模型版本时而有所不同。

我们可以看到问题所在。动词drove的论点是Jo 和 Maria。似乎可以推断出结论。

请记住,转换器模型不断发展。输出可能会有所不同;但是,概念保持不变。

真的吗?让我们在QA.ipynb中提出问题:

nlp_qa(context=sequence, question='Who are they?') 

输出是正确的:

{'answer': 'Jo and Maria',
 'end': 305,
 'score': 0.8486017557290779,
 'start': 293} 

我们能找到一个提出问题以获得正确答案的方法吗?我们将尝试通过改写问题来实现:

nlp_qa(context=sequence, question='Who drove to Las Vegas?') 

我们得到了稍微更好的结果:

{'answer': 'Nat King Cole was singing as Jo and Maria',
 'end': 305,
 'score': 0.35940926070820467,
 'start': 264} 

转换器现在理解Nat King Cole在唱歌,而Jo 和 Maria在同时做一些事情。

我们仍然需要进一步,找到一个提出更好问题的方法。

让我们尝试另一个模型。

使用 ELECTRA 进行问答

在切换模型之前,我们需要知道我们正在使用哪个模型:

print(nlp_qa.model) 

输出首先显示该模型是一个在问答训练的 DistilBERT 模型:

DistilBertForQuestionAnswering((distilbert): DistilBertModel( 

该模型有6层和768个特征,如第6层所示(层从0到n编号):

(5): TransformerBlock(
          (attention): MultiHeadSelfAttention(
            (dropout): Dropout(p=0.1, inplace=False)
            (q_lin): Linear(in_features=768, out_features=768, bias=True)
            (k_lin): Linear(in_features=768, out_features=768, bias=True)
            (v_lin): Linear(in_features=768, out_features=768, bias=True)
            (out_lin): Linear(in_features=768, out_features=768, bias=True) 

现在我们将尝试ELECTRA转换器模型。Clark等人(2020 年)设计了一个改进掩码语言建模(MLM)预训练方法的转换器模型。

在第三章,Fine-Tuning BERT Models,Masked language modeling小节中,我们看到 BERT 模型在训练过程中插入带有[MASK]的随机掩码标记。

Clark等人(2020)提出了一种可行的替代方案,使用了生成器网络而不仅仅是使用随机令牌。BERT 模型被训练以预测(屏蔽的)损坏令牌的标识。Clark等人(2020)训练了一个 ELECTRA 模型作为鉴别器,以预测屏蔽的令牌是否是生成的令牌。图 11.3显示了 ELECTRA 的训练方式:

自动生成的图示描述

图 11.3:ELECTRA 作为鉴别器进行训练

图 11.3显示,在送入生成器之前,原始序列会被屏蔽。生成器插入可接受的令牌而不是随机的令牌。ELECTRA Transformers模型训练以预测一个令牌是否来自原始序列还是已被替换。

一个 ELECTRA Transformers模型的架构和大多数超参数与 BERT Transformers模型相同。

我们现在希望看看是否能获得更好的结果。在QA.ipynb中要运行的下一个单元是使用ELECTRA-small-generator的问答单元:

nlp_qa = pipeline('question-answering', model='google/electra-small-generator', tokenizer='google/electra-small-generator')
nlp_qa(context=sequence, question='Who drove to Las Vegas ?') 

输出不是我们所期望的:

{'answer': 'to slow down on Pioneer Boulevard in Los Angeles, making it difficult to',
 'end': 90,
 'score': 2.5295573154019736e-05,
 start': 18} 

输出可能会从一个运行或Transformers模型到另一个变化;然而,想法仍然是一样的。

输出也发送了训练消息:

- This IS expected if you are initializing ElectraForQuestionAnswering from the checkpoint of a model trained on another task or with another architecture..
- This IS NOT expected if you are initializing ElectraForQuestionAnswering from the checkpoint of a model that you expect to be exactly identical.. 

你可能不喜欢这些警告消息,并可能得出这是一个糟糕的模型的结论。但一定要尽可能地探索给你提供的每一个途径。当然,ELECTRA 可能需要更多的训练。但尝试尽可能多地找到新的想法! 然后你可以决定是否进一步训练模型或转移到另一个模型。

我们现在必须考虑下一步要采取的步骤。

项目管理约束

我们并没有获得我们所期望的默认 DistilBERT 和 ELECTRA Transformers模型的结果。

在其他解决方案中,有三个主要选项:

  • 用额外的数据集训练 DistilBERT 和 ELECTRA 或其他模型。在现实项目中,训练数据集是一个昂贵的过程。如果需要实施新的数据集并改变超参数,训练可能会持续几个月。硬件成本也需要考虑在内。此外,如果结果不尽人意,项目经理可能会关闭项目。

  • 你也可以尝试使用现成的Transformers,尽管它们可能不符合你的需求,比如 Hugging Face 模型:huggingface.co/transformers/usage.html#extractive-question-answering。

  • 通过使用额外的 NLP 任务来帮助问答模型,找到获得更好结果的方法。

在本章中,我们将重点关注寻找额外的 NLP 任务,以帮助默认的 DistilBERT 模型。

让我们使用 SRL 来提取谓词及其论证。

使用 SRL 来找到问题

AllenNLP 使用我们在SRL.ipynb笔记本中实现的基于 BERT 的模型,第十章,使用基于 BERT 的Transformers进行语义角色标注。

让我们在语义角色标注部分重新运行 AllenNLP 上的序列,demo.allennlp.org/semantic-role-labeling,以获取句子中谓词的可视化表示。

我们将进入我们一直在处理的序列:

The traffic began to slow down on Pioneer Boulevard in Los Angeles, making it difficult to get out of the city. However, WBGO was playing some cool jazz, and the weather was cool, making it rather pleasant to be making it out of the city on this Friday afternoon. Nat King Cole was singing as Jo and Maria slowly made their way out of LA and drove toward Barstow. They planned to get to Las Vegas early enough in the evening to have a nice dinner and go see a show. 

基于 BERT 模型找到了几个谓词。我们的目标是找到 SRL 输出的特性,可以根据句子中的动词自动生成问题。

我们将首先列出 BERT 模型产生的谓词候选者:

verbs={"began," "slow," "making"(1), "playing," "making"(2), "making"(3), "singing,",…, "made," "drove," "planned," go," see"} 

如果我们必须编写一个程序,我们可以先引入一个动词计数器,如下面的伪代码所示:

def maxcount:
for in range first verb to last verb:
    for each verb
       counter +=1
       if counter>max_count, filter verb 

如果计数器超出可接受发生的次数(max_count),则该动词将在此实验中被排除。如果没有进一步的开发,要消除动词参数的多重语义角色将会太困难。

让我们也把made(make的过去式)从列表中移除。

我们的列表现在被限制在:

verbs={"began," "slow," "playing," "singing," "drove," "planned," go," see"} 

如果我们继续编写一个函数来过滤动词,我们可以寻找参数很长的动词。动词began有一个非常长的参数:

图形用户界面  描述自动生成并具有中等信心

图 11.4:SRL 应用于动词“began”

began的参数太长,无法在截图中显示。文本版本显示了解释began参数有多困难:

began: The traffic [V: began] [ARG1: to slow down on Pioneer Boulevard in Los Angeles , making it difficult to get out of the city] . However , WBGO was playing some cool jazz] , and the weather was cool , making it rather pleasant to be making it out of the city on this Friday afternoon . Nat King Cole was singing as Jo and Maria slowly made their way out of LA and drove toward Barstow . They planned to get to Las Vegas early enough in the evening to have a nice dinner and go see a show . 

我们可以添加一个函数来过滤包含超出最大长度的参数的动词:

def maxlength:
for in range first verb to last verb:
    for each verb
       if length(argument of verb)>max_length, filter verb 

如果一个动词的参数长度超过了最大长度(max_length),则该动词将在此实验中被排除。暂时让我们把began从列表中移出:

我们的列表现在被限制在:

verbs={ "slow", "playing", "singing", "drove",   "planned"," go"," see"} 

我们可以根据我们正在处理的项目添加更多排除规则。我们还可以再次使用非常严格的max_length值调用maxlength函数,以提取可能对我们的自动问题生成器感兴趣的候选动词。参数最短的动词候选者可以转换为问题。动词slow符合我们设置的三条规则:它在序列中只出现一次,参数不太长,并且包含序列中一些最短的参数。AllenNLP 的可视化表示确认了我们的选择:

一台计算机的截图  描述自动生成并具有中等信心

图 11.5:SRL 应用于动词“slow”

文本输出可以很容易地被解析:

slow: [ARG1: The traffic] began to [V: slow] down [ARG1: on] [ARGM-ADV: Pioneer Boulevard] [ARGM-LOC: in Los Angeles] , [ARGM-ADV: making it difficult to get out of the city] . 

这个结果和接下来的输出可能会随着不断发展的转换模型而有所变化,但是想法仍然是一样的。动词slow被识别出来,而这是 SRL 输出的关键方面。

我们可以自动生成what模板。我们不会生成who模板,因为没有一个参数标记为I-PER(人物)。我们可以编写一个函数来管理这两种可能性,如下面的伪代码所示:

def whowhat:
   if NER(ARGi)==I-PER, then:
        template=Who is [VERB]  
   if NER(ARGi)!=I-PER, then:
     template=What is [VERB] 

这个函数需要更多的工作来处理动词形式和修饰词。然而,在这个实验中,我们将只应用该函数并生成以下问题:

What is slow? 

让我们用下面的单元格来运行默认的pipeline:

nlp_qa = pipeline ('question-answering')
nlp_qa(context= sequence, question='What was slow?') 

结果是令人满意的:

{'answer': 'The traffic',
'end': 11, 
'score': 0.4652545872921081, 
'start': 0} 

默认模型,在这种情况下是DistilBERT,正确回答了问题。

我们的自动问答生成器可以做到以下几点:

  • 自动运行 NER

  • 用经典代码解析结果

  • 生成仅实体问题

  • 自动运行 SRL

  • 使用规则过滤结果

  • 使用 NER 结果生成仅 SRL 问题,以确定使用哪个模板

这个解决方案绝对并不完整。还需要更多的工作,可能需要额外的自然语言处理任务和代码。然而,这给出了实现任何形式的 AI 所需的艰苦工作的一个概念。

让我们尝试我们的方法与下一个过滤动词:playing。可视化表示显示参数是WBGO和一些很酷的爵士乐:

图形用户界面,应用程序自动生成描述

图 11.6:应用于动词“playing”的 SRL

文本版本易于解析:

playing: The traffic began to slow down on Pioneer Boulevard in Los Angeles , making it difficult to get out of the city . [ARGM-DIS: However] , [ARG0: WBGO] was [V: playing] [ARG1: some cool jazz] 

这个结果和以下输出可能会随着不断发展的Transformers模型而有所不同,但思想仍然是一样的:识别动词及其参数。

如果我们运行whowhat函数,它会显示参数中没有I-PER。所选模板将是what模板,并且以下问题可能会自动生成:

What is playing? 

让我们在以下单元格中使用这个问题来运行默认的 pipeline:

nlp_qa = pipeline('question-answering')
nlp_qa(context=sequence, question='What was playing') 

输出也是令人满意的:

{'answer': 'cool jazz,,'
 'end': 153,
 'score': 0.35047012837950753,
 'start': 143} 

唱歌是一个很好的选择,whowhat函数会找到I-PER模板并自动生成以下问题:

Who is singing? 

我们已经在本章中成功测试了这个问题。

下一个动词是drove,我们已经标记为一个问题。Transformers无法解决这个问题。

动词go是一个很好的选择:

图形用户界面,文本,应用程序自动生成描述

图 11.7:应用于动词“go”的 SRL

需要进一步开发才能生成带有正确动词形式的模板。假设工作已完成并问模型以下问题:

nlp_qa = pipeline('question-answering')
nlp_qa(context=sequence, question='Who sees a show?') 

输出是错误的参数:

{'answer': 'Nat King Cole,'
 'end': 277,
 'score': 0.5587267250683112,
 'start': 264} 

我们可以看到Nat King Cole、Jo和Maria在一个复杂序列中的出现会为Transformers模型和任何 NLP 模型造成歧义问题。需要更多的项目管理和研究。

下一步

实现问答或捷径的方法并不容易。我们开始实施可以自动生成问题的方法。自动生成问题是 NLP 的一个关键方面。

需要对更多 Transformer 模型进行预训练,包含命名实体识别(NER)、语义角色标注(SRL)和问答问题,以解决问题。项目经理还需要学习如何组合几个 NLP 任务来帮助解决特定任务,例如问答。

指代消解,demo.allennlp.org/coreference-resolution,可以帮助我们的模型识别我们工作的序列中的主要主语。这个由 AllenNLP 生成的结果显示了一个有趣的分析:

图形用户界面、文本、应用程序 自动生成的描述

图 11.8:序列的指代消解

我们可以通过添加指代消解的输出来继续开发我们的程序:

Set0={'Los Angeles', 'the city,' 'LA'}
Set1=[Jo and Maria, their, they} 

我们可以将指代消解添加为一个预训练任务,或者将其作为问题生成器的后处理任务。无论哪种方式,模拟人类行为的问题生成器都可以显著提升问答任务的性能。我们将在问题回答模型的预训练过程中包含更多定制的额外 NLP 任务。

当然,我们可以决定使用新的策略来预训练我们在本章中运行的模型,例如 DistilBERT 和 ELECTRA,然后让用户提出他们希望的问题。我推荐两种方法都使用:

  • 为问答任务开发问题生成器。这些问题可以用于教育目的,训练 Transformer,甚至为实时用户提供思路。

  • 通过包含特定的 NLP 任务来对 Transformer 模型进行预训练,这将提高它们的问答性能。使用问题生成器进一步训练它。

使用 RoBERTa 模型探索 Haystack

Haystack 是一个具有有趣功能的问答框架。值得探索一下,看看它是否适合您的项目需求。

在本节中,我们将对我们在本章中使用其他模型和方法进行实验的句子进行问答。

打开 Haystack_QA_Pipeline.ipynb。

第一个单元格安装运行 Haystack 所需的模块:

# Install Haystack
!pip install farm-haystack==0.6.0
# Install specific versions of urllib and torch to avoid conflicts with preinstalled versions on Colab
!pip install urllib3==1.25.4
!pip install torch==1.6.0+cu101-f https://download.pytorch.org/whl/torch_stable.html 

这个笔记本使用了一个 RoBERTa 模型:

# Load a  local model or any of the QA models on Hugging Face's model hub (https://huggingface.co/models)
from haystack.reader.farm import FARMReader
reader = FARMReader(model_name_or_path="deepset/roberta-base-squad2", use_gpu=True, no_ans_boost=0, return_no_answer=False) 

您可以回到第四章,从头开始预训练 RoBERTa 模型,了解 RoBERTa 模型的一般描述。

笔记本的其余部分将回答我们在本章中详细探讨的文本的问题:

text = "The traffic began to slow down on Pioneer Boulevard in…/… have a nice dinner and go see a show." 

您可以比较之前章节的输出得到的答案,并决定您想要实现哪种 Transformer 模型。

使用 GTP-3 引擎探索问答

本节将尝试避免训练、微调、在服务器上加载程序,甚至使用数据集。相反,用户只需连接到他们的 OpenAI 账户并使用交互式教育界面即可。

一个 GPT-3 引擎在线教育界面将通过提供 E(解释)和 T(文本)来提供足够好的答案,如下所示:

E = 回答这段文本的问题

T = 在先驱大道上交通开始减速……/……吃一顿美味的晚餐,然后去看一场演出。

以下是以问答形式提出的一些问题和获得的答案:

  • 谁要去拉斯维加斯?: 乔和玛丽亚

  • 谁在唱歌?: 纳特·金·科尔

  • 正在播放什么样的音乐?: 爵士

  • 晚上的计划是什么?: 吃一顿美味的晚餐,然后去看一场演出

就是这样!这就是您在线运行各种教育 NLP 任务所需做的一切,即使没有 GPT-3 引擎的 API,也可以使用交互式界面。

你可以改变S(向 GPT-3 展示预期的内容)和E,并创建无尽的互动。下一代 NLP 诞生了!工业 4.0 的开发人员、顾问或项目经理需要掌握一套新的技能:认知方法、语言学、心理学和其他跨学科的维度。如果需要,您可以花时间返回到第七章,GPT-3 引擎超人Transformers的崛起。

我们已经探讨了使用Transformers进行问答的一些关键方面。让我们总结一下我们所做的工作。

摘要

在本章中,我们发现问答并不像看起来那么容易。实现一个Transformers模型只需几分钟。然而,让它正常运行可能需要几个小时或几个月!

我们首先让 Hugging Face 管道中的默认Transformers回答一些简单的问题。默认Transformers DistilBERT 对简单的问题回答得相当好。然而,我们选择了简单的问题。在现实生活中,用户提出各种各样的问题。Transformers可能会感到困惑,并产生错误的输出。

然后,我们决定是否继续随机提问并得到随机答案,还是开始设计一个问题生成器的蓝图,这是一个更有效的解决方案。

我们首先使用 NER 来找到有用的内容。我们设计了一个函数,可以根据 NER 输出自动生成问题。质量很有前途,但需要更多的工作。

我们尝试了一个 ELECTRA 模型,但并没有产生我们预期的结果。我们停顿了几分钟,决定是花费昂贵的资源来训练Transformers模型,还是设计一个问题生成器。

我们在问题生成器的蓝图中添加了 SRL,并测试了它可以生成的问题。我们还在分析中添加了 NER,并生成了几个有意义的问题。还引入了Haystack框架,以发现使用 RoBERTa 进行问答的其他方法。

最后,我们在没有 API 的情况下,直接在 OpenAI 教育交互界面中运行了一个使用 GPT-3 引擎的示例。云 AI 平台的功能和可访问性正在增加。

我们的实验得出了一个结论:多任务 Transformer 在复杂的 NLP 任务上会比单一任务训练的 Transformer 提供更好的性能。实现 Transformer 需要准备充分的多任务训练、经典代码中的启发式以及一个问题生成器。问题生成器可以进一步训练模型,方法是使用问题作为训练输入数据或作为独立解决方案。

在下一章节中,检测客户情绪以进行预测,我们将探讨如何在社交媒体反馈上实现情感分析。

问题

  1. 训练过的 Transformer 模型可以回答任何问题。(True/False)

  2. 问答不需要进一步的研究。它现在已经完美了。(True/False)

  3. 命名实体识别(NER)在寻找有意义的问题时可以提供有用的信息。(True/False)

  4. 语义角色标注(SRL)在准备问题时毫无用处。(True/False)

  5. 一个问题生成器是生成问题的绝佳方式。(True/False)

  6. 实现问答需要仔细的项目管理。(True/False)

  7. ELECTRA 模型与 GPT-2 具有相同的架构。(True/False)

  8. ELECTRA 模型与 BERT 具有相同的架构,但是被训练为判别器。(True/False)

  9. NER 能够识别一个地点并将其标记为 I-LOC。(True/False)

  10. NER 能够识别一个人并将其标记为 I-PER。(True/False)

参考文献

加入我们书籍的 Discord 空间

加入本书的 Discord 工作区,与作者进行每月的 问我任何事 会话:

www.packt.link/Transformers

第十二章:检测客户情绪以进行预测

情感分析依赖于组合性原则。如果我们无法理解句子的部分,如何理解整个句子?这对于 NLP Transformers模型来说是一项困难的任务吗?我们将在本章中尝试几个Transformers模型以找出答案。

我们将从 斯坦福情感树库(SST)开始。SST 提供了用于分析的复杂句子数据集。分析诸如 电影很棒 这样的句子很容易。但是,如果任务变得非常困难,如 虽然电影有点太长,但我真的很喜欢它。 这个句子被分割了。它迫使一个Transformers模型理解序列的结构和逻辑形式。

然后我们将测试几个Transformers模型,包括复杂句子和简单句子。我们会发现,无论我们尝试哪种模型,如果没有足够的训练,它都不会起作用。Transformers模型就像我们一样。它们是需要努力学习并尝试达到现实生活中人类基准的学生。

运行 DistilBERT、RoBERTa-large、BERT-base、MiniLM-L12-H84-uncased 和 BERT-base 多语言模型非常有趣!然而,我们会发现其中一些模型需要更多的训练,就像我们一样。

在此过程中,我们将看到如何利用情感任务的输出来改善客户关系,并了解一个您可以在网站上实现的漂亮的五星级界面。

最后,我们将使用 GPT-3 的在线界面进行情感分析,无需 OpenAI 账户的 AI 开发或 API!

本章涵盖以下主题:

  • 用于情感分析的 SST

  • 为长序列定义组合性

  • 使用 AllenNLP 进行情感分析(RoBERTa)

  • 运行复杂句子,探索Transformers的新领域

  • 使用 Hugging Face 情感分析模型

  • DistilBERT 用于情感分析

  • 尝试 MiniLM-L12-H384-uncased

  • 探索 RoBERTa-large-mnli

  • 探究 BERT-base 多语言模型

  • 使用 GPT-3 进行情感分析

让我们从 SST 开始。

入门:情感分析 transformers

本节将首先探索Transformers将用于情感分析的 SST。

接下来我们将使用 AllenNLP 运行一个 RoBERTa-large transformer。

斯坦福情感树库(SST)

Socher 等人(2013)设计了长短语的语义词空间。他们定义了应用于长序列的 组合性 原则。组合性原则意味着 NLP 模型必须检查复杂句子的组成表达式以及组合它们的规则,以理解序列的含义。

让我们从 SST 中取样以掌握组合性原则的含义。

本节和本章内容独立完整,您可以选择执行所述的操作,或者阅读章节并查看提供的屏幕截图。

前往交互式情感树库:nlp.stanford.edu/sentiment/treebank.html?na=3&nb=33。

你可以进行你想要的选择。情感树图将显示在页面上。点击图像以获取情感树:

图表,散点图 自动生成描述

图 12.1:情感树图

对于这个例子,我点击了包含提到在语言学中解构理论的先驱雅克·德里达的句子的第 6 图表。出现了一个又长又复杂的句子:

无论你是否受到德里达关于“他者”和“自我”的任何讲座的启示,德里达无疑是一个极具吸引力和富有趣味的人。

Socher等人(2013)致力于向量空间和逻辑形式中的组合性。

例如,定义统治雅克·德里达样本的逻辑规则意味着理解以下内容:

  • 如何解释单词无论、还是和不以及将无论短语与句子其他部分分开的逗号

  • 如何理解逗号后句子的第二部分带有另一个和!

一旦向量空间被定义,Socher等人(2013)可以生成代表组合原则的复杂图表。

我们现在可以逐段查看图表。第一部分是句子的无论部分:

图表 自动生成描述

图 12.2:复杂句子中的“无论”部分

句子已被正确地分成两个主要部分。第二部分也是正确的:

图表,雷达图,散点图 自动生成描述

图 12.3:复杂句子的主要部分

我们可以从Socher等人(2013)设计的方法中得出几个结论:

  • 情感分析不能简化为在句子中计算积极和消极的词语

  • 一个Transformers模型或任何 NLP 模型必须能够学习组合原则,以理解复杂句子的构成成分如何与逻辑形式规则相互契合

  • 一个Transformers模型必须能够建立一个向量空间来解释复杂句子的微妙之处

我们现在将用一个 RoBERTa-large 模型将这一理论付诸实践。

使用 RoBERTa-large 进行情感分析

在本节中,我们将使用 AllenNLP 资源运行 RoBERTa-large Transformers。Liu等人(2019)分析了现有的 BERT 模型,并发现它们并没有训练得像预期的那样好。考虑到这些模型的生成速度,这并不令人惊讶。他们致力于改进 BERT 模型的预训练,以产生一个强大优化的 BERT 预训练方法(RoBERTa)。

让我们首先在SentimentAnalysis.ipynb中运行一个 RoBERTa-large 模型。

运行第一个单元格以安装allennlp-models:

!pip install allennlp==1.0.0 allennlp-models==1.0.0 

现在让我们尝试运行我们的雅克·德里达样本:

!echo '{"sentence": "Whether or not you're enlightened by any of Derrida's lectures on the other and the self, Derrida is an undeniably fascinating and playful fellow."}' | \
allennlp predict https://storage.googleapis.com/allennlp-public-models/sst-roberta-large-2020.06.08.tar.gz - 

输出首先显示 RoBERTa-large 模型的架构,该模型有24层和16个注意力头:

"architectures": [
  "RobertaForMaskedLM"
  ],
  "attention_probs_dropout_prob": 0.1,
  "bos_token_id": 0,
  "eos_token_id": 2,
  "hidden_act": "gelu",
  "hidden_dropout_prob": 0.1,
  "hidden_size": 1024,
  "initializer_range": 0.02,
  "intermediate_size": 4096,
  "layer_norm_eps": 1e-05,
  "max_position_embeddings": 514,
  "model_type": "roberta",
  "num_attention_heads": 16,
  "num_hidden_layers": 24,
  "pad_token_id": 1,
  "type_vocab_size": 1,
  "vocab_size": 50265
} 

如果需要,您可以花几分钟阅读 第三章 Fine-Tuning BERT Models 中的 BERT model configuration 部分的 BERT 架构描述,以充分利用该模型。

情感分析会产生介于0(负面)和1(正面)之间的数值。

输出然后产生情感分析任务的结果,显示输出 logits 和最终的正面结果:

prediction:  {"logits": [3.646597385406494, -2.9539334774017334], "probs": [0.9986421465873718, 0.001357800210826099] 

注意:算法是随机的,因此输出可能会在每次运行时变化。

输出还包含令牌 ID(可能会在每次运行时变化)和最终的输出标签:

"token_ids": [0, 5994, 50, 45, 47, 769, 38853, 30, 143, 9, 6113, 10505, 281, 25798, 15, 5, 97, 8, 5, 1403, 2156, 211, 14385, 4347, 16, 41, 35559, 12509, 8, 23317, 2598, 479, 2], "label": "1", 

输出还显示了令牌本身:

"tokens": ["<s>", "\u0120Whether", "\u0120or", "\u0120not", "\u0120you", "\u0120re", "\u0120enlightened", "\u0120by", "\u0120any", "\u0120of", "\u0120Der", "rid", "as", "\u0120lectures", "\u0120on", "\u0120the", "\u0120other", "\u0120and", "\u0120the", "\u0120self", "\u0120,", "\u0120D", "err", "ida", "\u0120is", "\u0120an", "\u0120undeniably", "\u0120fascinating", "\u0120and", "\u0120playful", "\u0120fellow", "\u0120.", "</s>"]} 

花些时间输入一些样本来探索设计良好且预训练的 RoBERTa 模型。

现在让我们看看如何使用其他 transformer 模型来使用情感分析来预测客户行为。

使用情感分析预测客户行为

此部分将在几个 Hugging Face transformer 模型上运行情感分析任务,以查看哪些模型产生了最佳结果,哪些模型我们简单地喜欢。

我们将使用 Hugging Face 的 DistilBERT 模型开始此过程。

使用 DistilBERT 进行情感分析

让我们使用 DistilBERT 运行情感分析任务,并看看我们如何使用结果来预测客户行为。

打开 SentimentAnalysis.ipynb 和Transformers安装和导入单元格:

!pip install -q transformers
from transformers import pipeline 

我们现在将创建一个名为 classify 的函数,它将使用我们发送给它的序列运行模型:

def classify(sequence,M):
   #DistilBertForSequenceClassification(default model)
    nlp_cls = pipeline('sentiment-analysis')
    if M==1:
      print(nlp_cls.model.config)
    return nlp_cls(sequence) 

请注意,如果您将 M=1 发送给该函数,它将显示我们正在使用的 DistilBERT 6 层、12 个头模型的配置:

DistilBertConfig {
  "activation": "gelu",
  "architectures": [
    "DistilBertForSequenceClassification"
  ],
  "attention_dropout": 0.1,
  "dim": 768,
  "dropout": 0.1,
  "finetuning_task": "sst-2",
  "hidden_dim": 3072,
  "id2label": {
    "0": "NEGATIVE",
    "1": "POSITIVE"
  },
  "initializer_range": 0.02,
  "label2id": {
    "NEGATIVE": 0,
    "POSITIVE": 1
  },
  "max_position_embeddings": 512,
  "model_type": "distilbert",
  "n_heads": 12,
  "n_layers": 6,
  "output_past": true,
  "pad_token_id": 0,
  "qa_dropout": 0.1,
  "seq_classif_dropout": 0.2,
  "sinusoidal_pos_embds": false,
  "tie_weights_": true,
  "vocab_size": 30522
} 

此 DistilBERT 模型的具体参数是标签定义。

现在我们创建一个序列列表(您可以添加更多),我们可以将其发送给 classify 函数:

seq=3
if seq==1:
  sequence="The battery on my Model9X phone doesn't last more than 6 hours and I'm unhappy about that."
if seq==2:
  sequence="The battery on my Model9X phone doesn't last more than 6 hours and I'm unhappy about that. I was really mad! I bought a Moel10x and things seem to be better. I'm super satisfied now."
if seq==3:
  sequence="The customer was very unhappy"
if seq==4:
  sequence="The customer was very satisfied"
print(sequence)
M=0 #display model cofiguration=1, default=0
CS=classify(sequence,M)
print(CS) 

在这种情况下,seq=3 被激活以模拟我们需要考虑的客户问题。 输出为负面,这正是我们要寻找的示例:

[{'label': 'NEGATIVE', 'score': 0.9997098445892334}] 

我们可以从这个结果中得出几个结论,以预测客户行为,编写一个函数来:

  • 将预测存储在客户管理数据库中。

  • 统计客户在某段时间内(周、月、年)投诉服务或产品的次数。 经常投诉的客户可能会转向竞争对手以获得更好的产品或服务。

  • 检测在负面反馈信息中不断出现的产品和服务。 产品或服务可能存在缺陷,需要质量控制和改进。

您可以花几分钟运行其他序列或创建一些序列来探索 DistilBERT 模型。

我们现在将探索其他 Hugging Face transformers。

使用 Hugging Face 模型列表进行情感分析

本节将探索 Hugging Face 的Transformers模型列表,并输入一些样本以评估它们的结果。想法是测试多个模型,而不仅仅是一个,并查看哪个模型最适合您的给定项目需求。

我们将运行 Hugging Face 模型:huggingface.co/models。

对于我们使用的每个模型,您可以在 Hugging Face 提供的文档中找到模型的描述:huggingface.co/transformers/。

我们将测试几个模型。如果您实现它们,您可能会发现它们需要微调甚至是对您希望执行的 NLP 任务进行预训练。在这种情况下,对于 Hugging Face Transformers,您可以执行以下操作:

  • 对于微调,您可以参考第三章,对 BERT 模型进行微调

  • 对于预训练,您可以参考第四章,从头开始预训练 RoBERTa 模型

让我们首先浏览 Hugging Face 模型列表:huggingface.co/models。

然后,在任务窗格中选择文本分类:

一个包含文本说明的图像

图 12.4:选择文本分类模型

将显示一系列用于文本分类的Transformers模型:

一个包含文本说明的图像

图 12.5:Hugging Face 预训练的文本分类模型

默认排序模式为排序:最多下载。

现在我们将搜索一些有趣的Transformers模型,我们可以在线测试。

我们将从 DistilBERT 开始。

DistilBERT 用于 SST

distilbert-base-uncased-finetuned-sst-2-english 模型在 SST 上进行了微调。

让我们试试一个需要对组成原理有良好理解的例子:

"尽管客户似乎不满意,但事实上她是满意的,只是当时在想其他事情,这给了一个错误的印象。"

这个句子对于Transformers来说很难分析,需要逻辑规则训练。

输出是一个假阴性:

图 12.6:复杂序列分类任务的输出

假阴性并不意味着模型工作不正确。我们可以选择另一个模型。然而,这可能意味着我们必须下载并训练它更长时间更好!

在撰写本书时,类似 BERT 的模型在 GLUE 和 SuperGLUE 排行榜上排名靠前。排名将不断变化,但Transformers的基本概念不会改变。

现在我们将尝试一个困难但不那么复杂的示例。

这个例子是真实项目的一个关键教训。当我们尝试估计客户投诉的次数时,我们将得到假阴性和假阳性。因此,对于未来几年,定期的人工干预仍将是必要的。

让我们试试一个 MiniLM 模型。

MiniLM-L12-H384-uncased

Microsoft/MiniLM-L12-H384-uncased 优化了老师的最后一个自注意力层的大小,以及对 BERT 模型的其他调整,以获得更好的性能。它有 12 层,12 个头部和 3300 万参数,并且比 BERT-base 快 2.7 倍。

让我们测试它对组成原则的理解能力:

尽管客户似乎不高兴,但事实上她很满意,只是在那时在想其他事情,这造成了误解。

输出很有趣,因为它产生了一个谨慎的分数(未决定):

包含文本描述的图像

图 12.7: 复杂句子情感分析

我们可以看到这个输出不是决定性的,因为它在0.5左右。应该是积极的。

让我们尝试一个涉及含意的模型。

RoBERTa-large-mnli

一个多题材自然语言推理(MultiNLI)任务,cims.nyu.edu/~sbowman/multinli/,可以帮助解决复杂句子的解释,当我们试图确定客户的意思时。推理任务必须确定一个序列是否导致下一个序列。

我们需要对输入进行格式化,并使用序列分割标记分割序列:

尽管客户似乎不高兴</s></s> 事实上她很满意,只是当时在想其他事情,这造成了误解

结果很有趣,尽管保持中性:

包含文本描述的图像

图 12.8: 针对稍微积极的句子获得的中性结果

但是,这个结果没有错误。第二个序列不是从第一个序列推断出的。结果非常正确。

让我们以“积极情感”多语言 BERT-base 模型结束我们的实验。

BERT-base 多语言模型

让我们在一个超级酷的 BERT-base 模型上运行我们的最终实验:nlptown/bert-base-multilingual-uncased-sentiment。

它设计得非常好。

让我们用友好和积极的英文句子来运行它:

图 12.9: 英文情感分析

让我们用法语尝试一下,“Ce modèle est super bien!”(“这个模型超级好!”,意思是“酷”):

包含文本描述的图像

图 12.10: 法语情感分析

Hugging Face 上这个模型的路径是nlptown/bert-base-multilingual-uncased-sentiment。您可以在 Hugging Face 网站的搜索表单中找到它。其当前链接为huggingface.co/nlptown/bert-base-multilingual-uncased-sentiment?text=Ce+mod%C3%A8le+est+super+bien%21。

您可以通过以下初始化代码在您的网站上实现它:

from transformers import AutoTokenizer, AutoModelForSequenceClassification
tokenizer = AutoTokenizer.from_pretrained("nlptown/bert-base-multilingual-uncased-sentiment")
model = AutoModelForSequenceClassification.from_pretrained("nlptown/bert-base-multilingual-uncased-sentiment") 

这将需要一些时间和耐心,但结果可能会非常好!

您可以在您的网站上实施此转换器,以平均全球客户的满意度!您还可以将其用作持续反馈,以改善您的客户服务并预测客户的反应。

在我们离开之前,我们将看看 GPT-3 如何执行情感分析。

使用 GPT-3 进行情感分析

您需要一个 OpenAI 账户来运行本节的示例。教育界面不需要 API、开发或培训。您可以简单地输入一些推特,然后请求进行情感分析:

推特: 我觉得这部电影不那么令人兴奋,但不知怎么的我真的很享受看它!

情感: 积极

推特: 我以前从未吃过这样的辛辣食物,但觉得它超级好吃!

情感: 积极

输出是令人满意的。

现在我们将向 GPT-3 引擎提交一个困难的序列:

推特: 因为我们不得不考虑所有参数,所以很难找到我们在生活中真正喜欢的东西。

情感: 积极

输出是错误的!这个情感根本不是积极的。这句话显示了生活的困难。然而,“享受”这个词为 GPT-3 引入了偏见。

如果我们从序列中去除“享受”并用动词 是 替换,输出将是负面的:

推特: 因为我们不得不考虑所有参数,所以很难找到我们在生活中真正喜欢的东西。

情感: 消极

输出也是错误的!并不是因为生活难以理解,我们就可以得出这句话是负面的结论。正确的输出应该是中性的。然后我们可以要求 GPT-3 在流水线中执行另一个任务,例如解释为什么它很困难。

作为一个没有任务的用户运行 NLP 任务显示了工业 4.0(I4.0)的发展方向:更少的人为干预,更多的自动功能。 然而,我们知道某些情况下我们的新技能是必需的,比如在转换器产生意外结果时设计预处理功能。人类仍然是有用的!

在 第七章,GPT-3 引擎崛起的超人类转换器 的 运行 OpenAI GPT-3 任务 部分中描述了一种具有现成代码的推特分类示例。如果您愿意,您可以在该代码中实现本节的示例。

现在让我们看看我们如何仍然证明自己是有价值的资产。

在我们离开之前进行一些务实的 I4.0 思考

Hugging Face transformers 进行情感分析时包含了一句被判定为“中性”的句子。

但那是真的吗?

将这句话标记为“中性”让我感到不安。我很好奇 OpenAI GPT-3 能否做得更好。毕竟,GPT-3 是一个理论上可以做许多其未经过训练的事情的基础模型。

我再次检查了这句话:

虽然客户看起来不高兴,但实际上她却很满意,只是在那时在想其他事情,这给了一个错误的印象。

当我仔细阅读句子时,我能看到顾客是 she。当我更深入地观察时,我理解到 she 实际上是 satisfied。我决定不是盲目地尝试各种模型,直到找到一个有效的为止。一直尝试一个接一个的模型是没有生产力的。

我需要通过逻辑和实验来找到问题的根源。我不想依赖自动找到原因的算法。有时候我们需要使用我们的神经元!

问题可能是很难为机器识别 she 作为 customer 吗?就像我们在第十章中所做的那样,基于 BERT 的语义角色标注,让我们问问 SRL BERT。

用 SRL 进行调查

第十章以我建议使用 SRL 与其他工具结束,我们现在正在这样做。

我首先在demo.allennlp.org/上使用语义角色标注接口运行了 She was satisfied。

结果是正确的:

图形用户界面 自动生成描述

图 12.11:简单句子的 SRL

这个谓词框架中的分析很清晰:was 是动词,She 是 ARG1,而 satisfied 是 ARG2。

我们应该在一个复杂的句子中找到相同的分析结果,而我们做到了:

图形用户界面 自动以中等置信度生成的描述

图 12.12:动词“satisfied”与其他单词合并,导致混淆

Satisfied 仍然是 ARG2,所以问题可能不在这里。

现在,焦点在ARGM-ADV上,它也修改了 was。这个字 false 是相当具有误导性的,因为ARGM-ADV是与包含 thinking 的ARG2相关的。

thinking 谓词给出了一个 false impression,但在这个复杂的句子中却没有被识别为谓词。难道 she was 是一个未知的省略,正如第十章中的SRL 范围的质疑部分所示?

通过输入完整句子而不使用省略号,我们可以快速验证:

Though the customer seemed unhappy, she was, in fact, satisfied but she was thinking of something else at the time, which gave a false impression.

SRL 的问题再次出现,正如我们在第十章中所看到的那样。我们现在有五个正确的谓词和五个准确的框架。

Frame 1 显示 unhappy 与 seemed 正确相关:

图形用户界面 自动以中等置信度生成的描述

图 12.13:“Unhappy” 与 “seemed” 正确相关

Frame 2 显示 satisfied 现在从句子中分离出来,并在一个复杂句子中单独识别为 was 的参数:

图形用户界面 自动生成描述

图 12.14:“satisfied” 现在是 ARG2 中的一个独立单词

现在,让我们直接到包含thinking的谓语,这是我们希望 BERT SRL 能够正确分析的动词。现在我们压制了省略号并重复了“she was”在句子中,输出是正确的:

图形用户界面 描述由中等置信度自动生成

图 12.15:没有省略号的准确输出

现在,我们可以用两个线索结束我们的 SRL 调查:

  • 单词false对算法来说是一个让其难以理解复杂句子中其他单词的令人困惑的论点

  • she was的重复省略号

在我们转向 GPT-3 之前,让我们回到 Hugging Face,带着我们的线索。

用 Hugging Face 进行调查

现在让我们回到本章 DistilBERT 用于 SST 部分使用的 DistilBERT 基础 uncased fine-tuned SST-2 模型。

我们将调查我们的两个线索:

  • she was的省略号

    我们将首先提交一个没有省略号的完整句子:

    “尽管顾客似乎不快乐,但事实上,她是满意的,只是当时在想其他事情,给人以错误的印象”

    输出仍然是消极的:

    图形用户界面,应用 描述自动生成

    图 12.16:一个假阴性

  • 在一个原本积极的句子中出现了false。

    现在我们将false从句子中移除,但留下省略号:

    “尽管顾客似乎不满意,但事实上,她很满意,只是当时在想其他事情,留下了这样的印象”

    中了!输出为积极:

    图形用户界面,文本 应用 描述自动生成

    图 12.17:一个真阳性

我们知道单词false对 SRL 造成混淆,如果有was thinking的省略号。我们也知道false对我们使用的情感分析 Hugging Face transformer 模型造成困惑。

GPT-3 能做得更好吗?让我们看看。

用 GPT-3 游��场进行调查

让我们使用 OpenAI 的高级推文分类器的例子,并通过三个步骤修改它来满足我们的调查需求:

  • 步骤 1:向 GPT-3 展示我们期望的内容:

    句子:“顾客很满意”

    情感:积极

    句子:“顾客并不满意”

    情感:消极

    句子:服务很好[赞]

    情感:积极

    句子:“这是评论的链接”

    情感:中性

  • 步骤 2:展示少量输出格式示例:

    1\. "我喜欢新的蝙蝠侠电影!"

    2\. "我讨厌我的手机电量耗尽时的情况"

    3\. "我的一天过得如此[赞]"

    4\. "这是文章的链接"

    5\. "这个新的音乐视频让我大吃一惊"

    句子情感评分:

    1: 积极

    2: 消极

    3: 积极

    4: 中性

    5: 积极

  • 步骤 3:将我们的句子与其他句子一起输入(编号 3):

    1\. "我受不了这个产品"

    2\. "服务很差![生气]"

    3\. "尽管客户看起来不满意,但事实上她当时是满意的,只是想着其他事情,这给人以错误的印象"

    4\. "支持团队很棒!"

    5\. "这是产品的链接。"

    句子情感评分:

    1: 消极

    2: 积极

    3: 积极

    4: 积极

    5: 中性

输出似乎令人满意,因为我们的句子是积极的(编号 3)。这个结果可靠吗?我们可以在这里多次运行示例。但让我们深入到代码层面去找出答案。

GPT-3 代码

我们只需在游乐场中点击查看代码,复制它,并将其粘贴到我们的 SentimentAnalysis.ipynb 章节笔记本中。我们添加一行只打印我们想要看到的内容:

response = openai.Completion.create(
  engine="davinci",
  prompt="This is a Sentence sentiment classifier\nSentence: \"The customer was satisfied\"\nSentiment: Positive\n###\nSentence: \"The customer was not satisfied\"\nSentiment: Negative\n###\nSentence: \"The service was `![](https://github.com/OpenDocCN/freelearn-dl-zh/raw/master/docs/tfm-nlp/img/Icon_01.png)`\"\nSentiment: Positive\n###\nSentence: \"This is the link to the review\"\nSentiment: Neutral\n###\nSentence text\n\n\n1\. \"I loved the new Batman movie!\"\n2\. \"I hate it when my phone battery dies\"\n3\. \"My day has been `![](https://github.com/OpenDocCN/freelearn-dl-zh/raw/master/docs/tfm-nlp/img/Icon_01.png)`\"\n4\. \"This is the link to the article\"\n5\. \"This new music video blew my mind\"\n\n\nSentence sentiment ratings:\n1: Positive\n2: Negative\n3: Positive\n4: Neutral\n5: Positive\n\n\n###\nSentence text\n\n\n1\. \"I can't stand this product\"\n2\. \"The service was bad! ![](https://github.com/OpenDocCN/freelearn-dl-zh/raw/master/docs/tfm-nlp/img/Icon_02.png)\"\n3\. \"Though the customer seemed unhappy she was in fact satisfied but thinking of something else at the time, which gave a false impression\"\n4\. \"The support team was `![](https://github.com/OpenDocCN/freelearn-dl-zh/raw/master/docs/tfm-nlp/img/Icon_03.png)`![](https://github.com/OpenDocCN/freelearn-dl-zh/raw/master/docs/tfm-nlp/img/Icon_03.png)\"\n5\. \"Here is the link to the product.\"\n\n\nSentence sentiment ratings:\n",
  temperature=0.3,
  max_tokens=60,
  top_p=1,
  frequency_penalty=0,
  presence_penalty=0,
  stop=["###"]
)
r = (response["choices"][0])
print(r["text"]) 

输出不稳定,正如我们在以下回应中所看到的:

  • 运行 1:我们的句子(编号 3)是中性的:

    1: 消极

    2: 消极

    3: 中性

    4: 积极

    5: 积极

  • 运行 2:我们的句子(编号 3)是积极的:

    1: 消极

    2: 消极

    3: 积极

    4: 积极

    5: 中性

  • 运行 3:我们的句子(编号 3)是积极的

  • 运行 4:我们的句子(编号 3)是消极的

这将引导我们得出调查的结论:

  • SRL 表明,如果句子是简单而完整的(没有省略号,没有遗漏的单词),我们将得到可靠的情感分析输出。

  • SRL 表明,如果句子是中等难度的,输出可能可靠,也可能不可靠。

  • SRL 表明,如果句子是复杂的(省略号、多个命题、许多含糊不清的短语等),结果是不稳定的,因此不可靠。

开发者的现在和未来的工作岗位的结论是:

  • 云 AI 和即用模块将需要更少的 AI 开发。

  • 将需要更多的设计技能。

  • 发展用于供给 AI 算法、控制它们并分析其输出的经典流程管道将需要思考和有针对性的发展。

本章展示了开发者作为思想家、设计师和管道开发的巨大前景!

现在是总结我们的旅程并探索新的Transformers地平线的时候了。

摘要

在本章中,我们讨论了一些高级理论。组合性原则不是一个直观的概念。组合性原则意味着Transformers模型必须理解句子的每个部分才能理解整个句子。这涉及到将提供句子部分之间联系的逻辑形式规则。

情感分析的理论难度需要大量的Transformers模型训练、强大的机器和人力资源。虽然许多Transformers模型为许多任务进行了训练,但它们通常需要针对特定任务进行更多的训练。

我们测试了 RoBERTa-large、DistilBERT、MiniLM-L12-H384-uncased 和出色的 BERT-base 多语言模型。我们发现其中一些提供了有趣的答案,但需要更多的训练来解决我们在多个模型上运行的 SST 样本。

情感分析需要对句子有深入的理解和非常复杂的序列。所以,尝试 RoBERTa-large-mnli 是有意义的,以了解干扰任务会产生什么。这里的教训是,在像 transformer 模型这样非常不传统的东西上,不要墨守成规!尝试一切。在各种任务上尝试不同的模型。transformer 的灵活性使我们能够在同一模型上尝试许多不同的任务,或者在许多不同的模型上尝试相同的任务。

我们一路上收集了一些改善客户关系的想法。如果我们发现一个客户经常不满意,那么这个客户可能只是在寻找我们的竞争对手。如果有几个客户抱怨某个产品或服务,我们必须预见未来的问题并改善我们的服务。我们还可以通过 transformer 反馈的在线实时表现来展示我们的服务质量。

最后,我们直接在线使用 GPT-3 进行情感分析,除了使用界面之外什么也不用做!这是令人惊讶的有效,但我们看到人类仍然需要解决更困难的序列。我们看到 SRL 如何帮助识别复杂序列中的问题。

我们可以得出结论,开发人员在思考者、设计者和管道开发方面有着巨大的未来。

在下一章,使用 transformer 分析假新闻,我们将使用情感分析来分析对假新闻的情感反应。

问题

  1. 对于情感分析,没有必要为 transformer 进行预训练。(是/否)

  2. 一个句子总是积极的或消极的。它不能是中性的。(是/否)

  3. 合成性原理表示 transformer 必须理解句子的每一部分才能理解它。(是/否)

  4. RoBERTa-large 旨在改进 transformer 模型的预训练过程。(是/否)

  5. 一个 transformer 可以提供反馈,告诉我们客户是否满意。(是/否)

  6. 如果产品或服务的情感分析一直是负面的,这有助于我们做出适当的决策,以改善我们的服务。(是/否)

  7. 如果一个模型在一个任务上不能提供良好的结果,那么在更改模型之前,它需要更多的训练。(是/否)

参考文献

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作空间,与作者进行每月的 问我任何事 会议:

www.packt.link/Transformers

第十三章:用Transformers分析假新闻

我们生来就认为地球是平的。作为婴儿,我们在平坦的表面上爬行。在幼儿园时,我们在平坦的操场上玩耍。在小学时,我们坐在平的教室里。然后,我们的父母和老师告诉我们,地球是圆的,而在地球的另一边的人是倒挂着的。我们花了很长时间才明白他们为什么没有从地球上摔下来。即使今天,当我们看到美丽的日落时,我们还是看到“太阳落下”,而不是地球从太阳那边转过去!

辨别假新闻和真实新闻需要时间和努力。像孩子一样,我们不得不努力理清我们认为是假新闻的东西。

本章将涉及一些制造紧张关系的主题。我们将核实诸如气候变化、枪支管制和唐纳德·特朗普的推特等主题的事实。我们将分析推特、脸书帖子和其他信息来源。

我们的目标当然不是评判任何人或任何事物。假新闻涉及观点和事实。新闻往往取决于当地文化对事实的看法。我们将提供想法和工具,帮助他人在某一主题上收集更多信息,并在我们每天收到的信息丛林中找到自己的方向。

我们将专注于道德方法,而不是Transformers的性能。出于这个原因,我们不会使用 GPT-3 引擎。我们不会取代人类的判断。相反,我们为人类提供工具,让他们自己进行判断。GPT-3 引擎在许多任务上已达到了人类水平的表现。然而,我们应该将道德和伦理决策留给人类。

因此,首先,我们将开始定义导致我们对假新闻产生情感和理性反应的路径。

我们将然后定义一些利用Transformers和启发式方法识别假新闻的方法。

我们将利用前几章中建立的资源来理解和解释假新闻。我们不会进行评判。我们将提供能够解释新闻的Transformers模型。有些人可能更喜欢创建一个通用的绝对Transformers模型,以检测并断言一条消息是假新闻。

我选择用Transformers来教育用户,而不是对他们说教。这是我的观点,而不是事实!

本章涵盖以下主题:

  • 认知 dissonance

  • 对假新闻的情感反应

  • 假新闻的行为表现

  • 对假新闻的理性方法

  • 假新闻的解决方案路线图

  • 将情感分析Transformers任务应用于社交媒体

  • 使用 NER 和 SRL 来分析枪支管制的感知

  • 利用Transformers提取的信息找到可靠的网站

  • 使用Transformers为教育目的生成结果

  • 如何以客观但批判的眼光阅读前总统特朗普的推特

我们的第一步将是探索对假新闻的情感和理性反应。

对假新闻的情感反应

人类行为对我们的社会、文化和经济决策有着巨大的影响。我们的情绪影响着我们的经济,甚至比理性思考更为重要。行为经济学推动着我们的决策过程。我们购买消费品是出于我们的实际需求和满足情感欲望。我们甚至可能会在一时冲动之下购买一部超出预算的智能手机。

我们对假新闻的情感和理性反应取决于我们是慢思考还是快速对入信息做出反应。丹尼尔·卡内曼在他的研究和书籍《思考,快与慢》(2013)中描述了这一过程。

他和弗农·L·史密斯因行为经济学研究而获得了诺贝尔经济学奖。行为驱动我们之前认为是理性的决定。不幸的是,我们许多的决定是基于情感而不是理性的。

让我们将这些概念转化为应用于假新闻的行为流程图。

认知失调会引发情感反应。

认知失调将假新闻推到了 Twitter、Facebook 和其他社交媒体平台的顶峰。如果每个人都同意一条推文的内容,那么什么也不会发生。如果有人写了一条推文说:“气候变化很重要”,没有人会做出反应。

当我们的头脑中存在矛盾的思想时,我们会进入认知失调状态。因此,我们变得紧张、烦躁,就像烤面包机中的短路一样消耗我们的精力。

我们有许多例子可以思考。在户外戴口罩是否必要?封锁是好事还是坏事?冠状病毒疫苗有效吗?或者冠状病毒疫苗是危险的吗?认知失调就像一个音乐家在演奏简单曲子时不断犯错。这让我们疯狂!

假新闻综合症将认知失调指数级地增加!一位专家会断言疫苗是安全的,另一位专家会警告我们要小心。一位专家说在外面戴口罩没用,而另一位在新闻频道上坚持认为我们必须戴上!双方都指责对方传播假新闻!

对于一方来说,看起来很大一部分假新闻是另一方的真相。

我们处于 2022 年,美国的共和党人和民主党人仍然无法就 2020 年总统选举之后的国家选举规则达成一致意见,或者即将举行的选举的组织形式达成一致意见。

我们可以继续通过打开一份报纸找到其他无数话题,然后在另一份反对的报纸上找到另一种观点!尽管如此,从这些例子中可以得出一些本章的常识前提:

  • 找到一个能够自动检测假新闻的Transformers模型是没有意义的。在社交媒体和多元文化表达的世界中,每个群体都对真相有一种认知,而另一方则在传播假新闻。

  • 试图将我们的观点表达为来自一种文化到另一种文化的真理是毫无意义的。在一个全球化的世界里,不同国家、不同大陆和社交媒体的各个地方都有不同的文化。

  • 绝对的假新闻是一个谬论。

  • 我们需要找到假新闻的更好定义。

我的观点(当然,这不是事实!)是假新闻是一种只能通过认知推理来解决的认知失调状态。因此,解决假新闻问题正好像试图解决两个当事方之间或我们心中的冲突一样。

在本章和生活中,我建议通过使用转换模型来解构每一个冲突紧张局势和观点。我们并不是在“打击假新闻”,“寻找内心平静”,或者假装使用转换工具来寻找“对抗假新闻的绝对真理”。

我们使用转换工具来更深入理解一系列词语(一条消息),从而对某个话题形成更深刻、更广阔的观点。

一旦完成这些,让幸运的转换模型用户得到更好的视觉和观点。

为此,我设计了本章作为一个我们自己和其他人可以使用的课堂练习。转换工具是加深我们对语言序列理解、形成更广泛观点和发展认知能力的好方法。

让我们先看看当有人发布冲突性推特时会发生什么。

分析一条引发冲突的推特

下面的推特是在 Twitter 上发布的一条消息(我进行了改写)。在本章中显示的推特是原始数据集格式,而不是 Twitter 界面的显示。可以肯定的是,如果一个主要的政治人物或著名演员发推特,很多人会反对其内容:

气候变化是虚假的。这是自由派图谋破坏经济的一个阴谋。

这可能引发情绪反应。推特将从各个方面堆积起来。它将迅速传播并成为趋势!

让我们通过转换工具来分析这条推特,了解这条推特如何在某人的心里引起认知失调风暴。

打开Fake_News.ipynb,这是我们在本节中将要使用的笔记本。

我们将先从Allen 人工智能研究院获得资源。我们将运行我们在第十二章中用于情感分析的 RoBERTa 转换模型。

首先,我们需要安装allennlp-models。

!pip install allennlp==1.0.0 allennlp-models==1.0.0 

AllenNLP 在不断更新版本。在撰写本文时,版本 2.4.0 已存在,但对本章提供的示例并无额外价值。随机算法或经过更新的模型会产生不同的输出。

然后我们用 Bash 运行下一条命令来详细分析推特的输出(模型和输出的信息):

!echo '{"sentence":"Climate change is bogus. It's a plot by the liberals to take the economy down."}' | \
allennlp predict https://storage.googleapis.com/allennlp-public-models/sst-roberta-large-2020.06.08.tar.gz - 

输出显示这条推特是负面的。积极值为0,而负面值接近1:

"probs": [0.0008486526785418391, 0.999151349067688] 

输出可能因为转换工具的随机算法而有所不同。

现在我们将前往 allennlp.org/ 获取分析的可视化表示。

输出可能会从一个运行到另一个运行改变。Transformer 模型持续进行训练和更新。本章的目标是专注于 Transformer 模型的推理。

我们选择 情感分析 (demo.allennlp.org/sentiment-analysis) 并选择 RoBERTa 大模型 运行分析。

我们得到了相同的负结果。然而,我们可以进一步调查,看看哪些词影响了 RoBERTa 的决定。

转到 模型解释。

解释模型将提供如何获得结果的见解。我们可以选择一个或查看三个选项:

  • 简单梯度可视化:该方法提供两种可视化。第一种计算与输入相关的类别得分的梯度。第二种是从类别和输入推断出的显著性(主要特征)地图。

  • 综合梯度可视化:这个模型不需要对神经网络进行任何更改。

  • 设计调用梯度的动机是为了生成神经网络对其输入的预测的归因。

  • 平滑梯度可视化:这种方法使用输出预测和输入来计算梯度。目标是识别输入的特征。然而,为了改进解释,添加了噪声。

在本节中,转到 模型解释,然后点击 简单梯度可视化 和 解释预测,以获取以下表示:

图形用户界面、网站、时间线  自动生成描述

图 13.1:可视化前 3 个最重要的单词

is + bogus + plot 主要影响了负预测。

此时,你可能想知道为什么我们要看一个如此简单的例子来解释认知失调。解释来自以下推文。

一个坚定的共和党人写了第一条推文。我们称该成员为 Jaybird65。令他惊讶的是,一位同样是共和党人的人发了以下推文:

我是共和党人,认为气候变化意识是一件好事!

这条推文来自我们将称之为 Hunt78 的成员。让我们在 Fake_News.ipynb 中运行这个句子:

!echo '{"sentence":"I am a Republican and think that climate change consciousness is a great thing!"}' | \
allennlp predict https://storage.googleapis.com/allennlp-public-models/sst-roberta-large-2020.06.08.tar.gz - 

输出当然是正的:

"probs": [0.9994876384735107, 0.0005123814917169511] 

一个认知失调的风暴正在 Jaybird65 的脑海中酝酿。他喜欢 Hunt78,但不同意。他的思绪风暴正在加剧!如果你读了 Jaybird65 和 Hunt78 之间接连发生的推文,你会发现一些令 Jaybird65 难过的令人惊讶的事实:

Jaybird65 和 Hunt78 显然彼此认识。

  • 如果你去他们各自的 Twitter 账户,你会发现他们都是猎人。

  • 你可以看到他们都是坚定的共和党人。

Jaybird65 最初的推文是对 纽约时报 一篇声称气候变化正在摧毁地球的文章的反应。

Jaybird65 感到很困惑。他可以看到 Hunt78 和他一样是共和党人。他也是个猎人。那么 Hunt78 怎么会相信气候变化呢?

这个推特串的愤怒推文数量惊人。

然而,我们可以看到,虚假新闻讨论的根源在于对新闻的情感反应。对气候变化的理性方法应该是:

  • 无论原因是什么,气候都在变化。

  • 我们不需要因为改变人类而使经济崩溃。

  • 我们需要继续制造电动汽车,在大城市增加更多的行走空间,并改善农业习惯。我们只需要以可能会带来收入的新方式经营业务。

但情感在人类中是很强烈的!

让我们来描述一下从新闻到情感和理性反应的过程。

虚假新闻的行为表示

虚假新闻始于情感反应,逐渐升级,并经常导致个人攻击。

图 13.2 表示了当认知失调阻碍我们的思维过程时,对虚假新闻的三阶段情感反应路径:

第 1 阶段:收到的新闻

两个人或一组人对他们通过各自媒体获得的新闻做出反应:Facebook、Twitter、其他社交媒体、电视、广播、网站。每个信息来源都包含偏见观点。

第 2 阶段:共识

两个人或一组人可以同意或不同意。如果他们不同意,我们将进入第 3 阶段,在此期间冲突可能会激化。

如果他们同意,共识会阻止热情的积聚,新闻被接受为真实新闻。然而,即使所有各方相信他们收到的新闻不是虚假的,这并不意味着它不是虚假的。以下是一些解释标记为非虚假新闻的新闻可能是虚假新闻的原因:

  • 在 12 世纪早期,欧洲大多数人认为地球是宇宙的中心,太阳系围绕地球旋转。

  • 1900 年,大多数人认为永远不会有一种飞越海洋的飞机。

  • 2020 年 1 月,大多数欧洲人认为 COVID-19 只是影响中国而不是全球流行的病毒。

底线是,两个或甚至整个社会之间的共识并不意味着传入的新闻是真实还是虚假的。如果两个派系意见不一致,这将导致冲突:

自动生成的图表描述

图 13.2:从新闻到虚假新闻冲突的路径的表示

让我们面对现实吧。在社交媒体上,成员通常与持有相同观点的其他人汇聚在一起,并且无论如何都很少改变他们的想法。这种描述表明,一个人通常会坚持在推特上表达的观点,一旦有人挑战他们的消息,冲突就会升级!

第 3 阶段:冲突

一个虚假新闻冲突可以分为四个阶段:

  • 3.1:冲突始于分歧。各方会在推特或 Facebook 或其他平台上发帖留言。经过几次交流后,冲突可能会消散,因为各方对这个话题不感兴趣。

  • 3.2:如果我们回到 Jaybird65 和 Hunt78 之间关于气候变化的讨论,我们知道情况可能会变得糟糕。对话正在升温!

  • 3.3:在某个时刻,不可避免地,一方的观点将变成虚假新闻。Jaybird65会生气,并在多条推文中表现出来,他认为由于人类引起的气候变化是假新闻。Hunt78会生气,并表示否认人类对气候变化的贡献是假新闻。

  • 3.4:这些讨论通常以人身攻击结束。即使我们不知道它是如何出现的,戈德温定律也经常进入对话。戈德温定律指出,在对话的某个时刻,一方会找到最糟糕的参考来描述另一方。有时会表现为“你们自由派就像希特勒试图通过气候变化压制我们的经济。”这种类型的信息可以在推特、Facebook 和其他平台上看到。它甚至出现在总统关于气候变化的演讲期间的实时聊天中。

是否有一种理性的方式可以缓和双方的讨论,让他们冷静下来,至少达成一种折中的共识以便继续前进?

让我们尝试通过 transformers 和启发式方法建立一种理性的方式。

对虚假新闻的理性处理方法

Transformers 是有史以来最强大的自然语言处理工具。本节将首先定义一种方法,可以将两方在虚假新闻上的冲突从情绪层面提升到理性层面。

然后我们将使用 transformer 工具和启发式方法。我们将对枪支管制和前总统特朗普在 COVID-19 大流行期间的推文运行 transformer 样本。我们还将描述可以与传统功能一起实施的启发式方法。

你可以实现这些 transformer 自然语言处理任务或其他你选择的任务。不管怎样,这个路线图和方法可以帮助老师、家长、朋友、同事以及任何寻求真相的人。因此,你的工作总是值得的!

让我们从包含 transformers 的虚假新闻的理性解决方案路线图开始。

定义一个虚假新闻解决路线图

图 13.3 定义了一个理性的虚假新闻分析流程路线图。该流程包含 transformer 自然语言处理任务和传统功能:

自动生成的描述图

图 13.3:从对虚假新闻的情绪反应到理性表达

我们发现,一旦情绪反应开始,理性过程几乎总是会开始。理性过程必须尽快开始,以避免累积可能中断讨论的情绪反应。

第三阶段现在包含四个工具:

  • 3.1: 使用情感分析来分析排名前列的“情感”正面或负面词汇。我们将在我们的Fake_News.ipynb笔记本中使用AllenNLP资源来运行一个 RoBERTa 大型Transformers。我们将使用 AllenNLP 的可视化工具来可视化关键词和解释。我们在第十二章中介绍了情感分析,检测客户情绪以进行预测。

  • 3.2: 命名实体识别(NER)用于从社交媒体消息中提取实体以进行第 3.4 阶段。我们在第十一章中描述了 NER,让你的数据说话:故事、问题和答案。我们将使用 Hugging Face 的 BERT Transformers模型来执行此任务。此外,我们将使用 AllenNLP.org 的可视化工具来可视化实体和解释。

  • 3.3: 使用语义角色标注(SRL)来标注社交媒体消息中的动词,用于第 3.4 阶段。我们在第十章中描述了 SRL,使用基于 BERT 的Transformers进行语义角色标注。我们将在Fake_News.ipynb中使用 AllenNLP 的 BERT 模型。我们将使用 AllenNLP.org 的可视化工具来可视化标注任务的输出。

  • 3.4: 将描述可靠网站的参考文献,以显示经典编码如何帮助。

让我们从枪支管制开始。

枪支管制辩论

美国宪法的第二修正案断言以下权利:

A well regulated Militia, being necessary to the security of a free State, the right of the people to keep and bear Arms, shall not be infringed.

数十年来,美国在这个问题上分裂了:

  • 一方面,许多人认为携带武器是他们的权利,他们不想忍受枪支管制。他们认为声称拥有武器会导致暴力是假新闻。

  • 另一方面,许多人认为携带火器是危险的,没有枪支管制,美国将仍然是一个暴力国家。他们认为声称携带武器不危险是假新闻。

我们需要帮助每一个团体。让我们从情感分析开始。

情感分析

如果你阅读演讲期间的推文、Facebook 消息、YouTube 聊天或任何其他社交媒体,你会看到各方正在进行激烈的争斗。你不需要看电视节目。你只需吃着爆米花,看着推文之间的战斗撕裂各方!

让我们选取一条来自一方的推文和一条来自对立方的 Facebook 消息。我改变了成员的名字并改写了文本(考虑到消息中的侮辱,这并不是一个坏主意)。让我们从支持枪支的推文开始:

支持枪支的分析

这条推文是一个人的真实观点:

Afirst78: 我多年来一直有步枪和枪支,从未出过问题。我把孩子们培养得很好,所以他们也有枪支,除了兔子,从未伤害过任何东西。

让我们在Fake_News.ipynb中运行这个:

!echo '{"sentence": "I have had rifles and guns for years and never had a problem. I raised my kids right so they have guns too and never hurt anything except rabbits."}' | \
allennlp predict https://storage.googleapis.com/allennlp-public-models/sst-roberta-large-2020.06.08.tar.gz - 

预测是积极的:

prediction:  {"logits": [1.9383275508880615, -1.6191326379776], "probs": [0.9722791910171509, 0.02772079035639763] 

我们现在将在 AllenNLP 上可视化结果。简单梯度可视化提供了一个解释:

图形用户界面、文本、应用、聊天或短信 说明自动生成

图 13.4:一句话的简单梯度可视化

解释显示,对 Afirst78 的推文进行的情感分析突出显示了 rifles + and + rabbits。

每次运行或随着时间的推移结果可能会有所不同。这是因为Transformers模型正在持续训练和更新。然而,本章的重点在于过程,而不是特定结果。

我们将在每一步拾起想法和功能。Fake_News_FUNCTION_1 是本节的第一个函数:

Fake_News_FUNCTION_1:rifles + and + rabbits 可以被提取和记录以供进一步分析。我们可以看到在这个例子中,rifles并不“危险”。

我们现在将分析 NYS99 认为必须控制枪支的观点。

枪支管制分析

NYS99:“我一生中一直在我的社区听到枪声,失去了许多朋友,晚上害怕出门。”

让我们首先在 Fake_News.ipynb 中运行分析:

!echo '{"sentence": "I have heard gunshots all my life in my neighborhood, have lost many friends, and am afraid to go out at night."}' | \
allennlp predict https://storage.googleapis.com/allennlp-public-models/sst-roberta-large-2020.06.08.tar.gz - 

结果自然是消极的:

prediction:  {"logits": [-1.3564586639404297, 0.5901418924331665], "probs": [0.12492450326681137, 0.8750754594802856] 

让我们使用 AllenNLP 在线工具找到关键词。我们运行示例,可以看到平滑梯度可视化突出显示以下内容:

图形用户界面、文本、应用 说明自动生成

图 13.5:一句话的平滑梯度可视化

关键词 afraid 在本节的功能 2 中显眼。我们现在知道 afraid 与 “guns” 相关联。

我们可以看到模型在解释这些认知上存在问题。我们的人类批判性思维仍然是必要的!

Fake_News_FUNCTION_2:afraid 和 guns(主题)可以被提取和记录以供进一步分析。

如果我们现在将我们的两个功能并排放置,我们就可以清楚地理解为什么两个团体在互相争斗:

  • Fake_News_FUNCTION_1:rifles + and + rabbits

    Afirst78 可能住在美国中西部的一个州。这些州中的许多人口不多,非常安静,并且享有低犯罪率。Afirst78 可能从未去过大城市,享受着乡村宁静生活的乐趣。

  • Fake_News_FUNCTION_2:afraid + 主题 guns

    NYS99 可能住在美国大城市或主要美国大城市的大地区。犯罪率通常很高,暴力是日常现象。NYS99 可能从未去过中西部州,也没见过 Afirst78 的生活方式。

这两种诚实而强烈的观点证明了为什么我们需要实施本章描述的解决方案。

更好的信息是减少假新闻战斗的关键。

我们将按照我们的流程对我们的句子应用命名实体识别。

命名实体识别(NER)

本章显示,通过使用几种Transformers方法,用户将通过不同角度获得更广泛的消息认知。HTML 页面可以总结本章的Transformers方法,甚至可以包含生产模式中的其他Transformers任务。

现在,我们必须将我们的流程应用到推特和 Facebook 消息上,尽管我们在消息中看不到任何实体。然而,程序并不知道这一点。我们将只运行第一条消息来说明这个过程的这一步。

我们将首先安装 Hugging Face transformers:

!pip install -q transformers
from transformers import pipeline
from transformers import AutoTokenizer, AutoModelForSequenceClassification,AutoModel 

现在,我们可以运行第一条消息:

nlp_token_class = pipeline('ner')
nlp_token_class('I have had rifles and guns for years and never had a problem. I raised my kids right so they have guns too and never hurt anything except rabbits.') 

由于没有实体,输出没有产生结果。然而,这并不意味着它应该从管道中去除。另一句话可能包含一个提供有关该地区文化线索的人的位置名称。

在我们继续之前,让我们检查一下我们正在使用的模型:

nlp_token_class.model.config 

输出显示模型在注意力层使用了 9 个标签和 1024 个特征:

BertConfig {
  "_num_labels": 9,
  "architectures": [
    "BertForTokenClassification"
  ],
  "attention_probs_dropout_prob": 0.1,
  "directionality": "bidi",
  "hidden_act": "gelu",
  "hidden_dropout_prob": 0.1,
  "hidden_size": 1024,
  "id2label": {
    "0": "O",
    "1": "B-MISC",
    "2": "I-MISC",
    "3": "B-PER",
    "4": "I-PER",
    "5": "B-ORG",
    "6": "I-ORG",
    "7": "B-LOC",
    "8": "I-LOC"
  }, 

我们正在使用一个 BERT 24 层的 transformer 模型。如果您想探索架构,请运行nlp_token_class.model。

我们现在将在消息上运行 SRL。

语义角色标注(SRL)

我们将按照笔记本中找到的顺序,逐个运行Fake_News.ipynb的单元格。我们将考虑两种观点。

让我们从支持枪支的角度开始。

支持枪支 SRL

我们将首先在Fake_News.ipynb中运行以下单元格:

!echo '{"sentence": "I have had rifles and guns for years and never had a problem. I raised my kids right so they have guns too and never hurt anything except rabbits."}' | \
allennlp predict https://storage.googleapis.com/allennlp-public-models/bert-base-srl-2020.03.24.tar.gz - 

输出非常详细,如果您想要详细调查或解析标签,可能会很有用,就像这段摘录中所示:

prediction:  {"verbs": [{"verb": "had", "description": "[ARG0: I] have [V: had] [ARG1: rifles and guns] [ARGM-TMP: for years] and never had a problem ... 

现在让我们在语义角色标注部分详细了解 AllenNLP。我们首先对这条消息运行 SRL 任务。第一个动词had表明Afirst78是一个经验丰富的枪支拥有者:

图形用户界面,文本,应用程序 自动生成的描述

图 13.6:动词“had”的 SRL

had的参数总结了Afirst78的经验:I + rifles and guns + for years。

had的第二帧添加了信息I + never + had + a problem

raised的参数显示了Afirst78的父母经验:

图形用户界面,应用程序,网站 自动生成的描述

图 13.7:动词“raised”的 SRL 和参数

参数解释了许多支持枪支立场:my kids + …have guns too and never hurt anything。

结果可能因每次运行或模型更新而有所不同,但流程保持不变。

我们可以将我们在这里找到的内容添加到我们的函数集合中进行一些解析:

  • Fake_News_FUNCTION_3:I + rifles and guns + for years

  • Fake_News_FUNCTION_4:my kids + have guns too and never hurt anything

现在让我们探索枪支控制消息。

枪支控制 SRL

我们将首先在Fake_News.ipynb中运行 Facebook 消息。我们将继续按照笔记本中创建的顺序逐个运行笔记本单元格:

!echo '{"sentence": "I have heard gunshots all my life in my neighborhood, have lost many friends, and am afraid to go out at night."}' | \
allennlp predict https://storage.googleapis.com/allennlp-public-models/bert-base-srl-2020.03.24.tar.gz - 

结果详细标记了序列中的关键动词,就像以下摘录所示:

prediction:  {"verbs": [{"verb": "heard", "description": "[ARG0: I] have [V: heard] [ARG1: gunshots all my life in my neighborhood]" 

我们继续应用我们的流程,进入 AllenNLP,然后进入语义角色标注部分。我们输入句子并运行 transformer 模型。动词heard显示了这条消息的严峻现实:

自动生成的图形用户界面,应用

图 13.8:动词“听到”的 SRL 表示

我们可以快速解析我们第五个功能的单词:

  • Fake_News_FUNCTION_5:一直听到 + 枪声 + 我一生都听到

动词失去显示了与之相关的重要论点:

自动生成的图形用户界面,应用,网站

图 13.9:动词“丢失”的 SRL 表示

我们已经拥有我们第六个功能所需的一切:

  • Fake_News_FUNCTION_6:失去 + 很多 + 朋友

建议在不同的转换模型澄清了消息的每个方面后,向用户提供参考网站是一个好主意。

参考网站

我们已经对 NLP 任务运行了转换器模型,并描述了需要开发以解析数据并生成六个功能的传统启发式硬编码。

请记住,结果可能会因每次运行而异。六个功能是在不同时间生成的,并且与上一节略有不同。但是,主要思想仍然相同。现在让我们专注于这六个功能。

  • Pro-guns: Fake_News_FUNCTION_1:从未 + 问题 + 枪支

  • 枪支管制:Fake_News_FUNCTION_2:一直听到 + 害怕 + 枪支

  • Pro-guns: Fake_News_FUNCTION_3:我 + 几年来持有步枪和枪支

  • Pro-guns: Fake_News_FUNCTION_4:我的孩子们 + 有枪 + 从未伤害过任何东西

  • 枪支管制:Fake_News_FUNCTION_5:一直听到 + 枪声 + 我一生都听到

  • 枪支管制:Fake_News_FUNCTION_6:失去 + 很多 + 朋友

让我们重新组织列表,并分开两个观点,并得出一些结论以决定我们的行动。

支持枪支和枪支管制

反对枪支的论点是诚实的,但它们表明在美国主要城市发生的情况缺乏信息:

  • Pro-guns: Fake_News_FUNCTION_1:从未 + 问题 + 枪支

  • Pro-guns: Fake_News_FUNCTION_3:我 + 几年来持有步枪和枪支

  • Pro-guns: Fake_News_FUNCTION_4: 我的孩子们 + 有枪 + 从未伤害过任何东西

枪支管控的论点是诚实的,但它们表明在中西部大片安静地区发生了缺乏信息的情况:

  • 枪支管制:Fake_News_FUNCTION_2:一直听到 + 害怕 + 枪支

  • 枪支管制:Fake_News_FUNCTION_5:一直听到 + 枪声 + 我一生都听到

  • 枪支管制:Fake_News_FUNCTION_6:失去 + 很多 + 朋友

每个功能都可以被开发以通知另一方。

例如,让我们以伪代码的形式表达FUNCTION1:

Def FUNCTION1:
call FUNCTIONs 2+5+6 Keywords and simplify
Google search=afraid guns lost many friends gunshots 

过程的目标是:

  • 首先,运行转换模型来 解构和解释 消息。使用 NLP 转换器就像使用数学计算器一样。它可以产生良好的结果,但需要一个自由思考的人类大脑来解释它们!

  • 然后,请一个经过训练的 NLP 人类用户更主动地、更好地搜索和阅读信息。

变换模型帮助用户更深入地理解信息;它们不会替用户思考!我们试图帮助用户,而不是讲课或洗脑他们!

需要解析来处理这些函数的结果。然而,如果我们有数百条社交媒体消息,我们可以自动让我们的程序完成整个工作。

链接将随着 Google 修改搜索而变化。然而,出现的第一个链接是有趣的,可以展示给持争议性枪支主张者看:

图形用户界面、文本、应用程序、电子邮件 自动生成的描述

图 13.10:枪支和暴力

假设我们要用以下伪代码搜索支持枪支管制的人:

Def FUNCTION2:
call FUNCTIONs 1+3+4 Keywords and simplify
Google search=never problem guns for years kids never hurt anything 

谷歌搜索未返回明确支持持争议性枪支主张者的积极结果。最有趣的是中立且教育性的:

图形用户界面、文本、应用程序 自动生成的描述

图 13.11:枪支安全

你可以在亚马逊的书店、杂志和其他教育资料上进行自动搜索。

最重要的是,对持相反意见的人来说,能够交谈而不争吵是至关重要的。相互理解是发展双方共鸣的最佳方式。

有人可能会倾向于相信社交媒体公司。我建议永远不要让第三方代表你的思维过程。使用变换模型来解构信息,但保持主动!

在这个问题上达成共识可能是同意遵循持枪规则。例如,一个人可以选择要么不在家中拥有枪支,要么安全地将它们锁起来,这样孩子就无法接触到它们。

让我们继续讨论 COVID-19 和前总统特朗普的推文。

COVID-19 和前总统特朗普的推文

无论你的政治观点是什么,都有很多关于唐纳德·特朗普的言论以及对他的言论,需要一个专门的书来分析所有信息!这是一本技术,而不是政治书,所以我们将从科学的角度分析这些推文。

我们在本章的枪支管制部分描述了对假新闻的教育方法。我们不需要再次走过整个过程。

我们在我们的Fake_News.ipynb笔记本中的枪支管制部分,使用了 BERT 模型来实现和运行 AllenNLP 的 SRL 任务。

在本节中,我们将专注于假新闻的逻辑。我们将在 AllenNLP 的网站上运行 BERT 模型的 SRL 并可视化结果。

现在,让我们来看一些总统关于 COVID-19 的推文。

语义角色标注(SRL)

SRL 对我们所有人来说都是一个出色的教育工具。我们往往只是被动地阅读推文,听取他人对其的看法。用 SRL 来分解信息是发展社交媒体分析技能的好方法,以区分虚假信息和准确信息。

我建议在课堂上将 SRL transformers 用于教育目的。一个年轻的学生可以输入一条推特,并分析每个动词及其参数。这可以帮助年轻一代在社交媒体上成为积极的读者。

首先我们将分析一个相对一致的推特,然后是一个充满冲突的推特:

让我们分析一下在写这本书时发现的最新推特。我去掉了“黑人美国人”的名字,并改写了前总统的部分文本:

X 是一个伟大的美国人,因感染冠状病毒已被送往医院,并要求祈祷。你今天会和我一起为他祈祷,以及所有正在受新冠肺炎病痛折磨的人吗?

让我们去 AllenNLP 的语义角色标注部分,运行句子,并查看结果。动词hospitalized显示成员对事实保持接近:

图形用户界面、文本、应用 自动生成的描述

图 13.12:动词“hospitalized”的 SRL 参数

这条信息很简单:X + hospitalized + with coronavirus。

动词requested表明信息变得政治化:

图形用户界面、文本、应用、网站 自动生成的描述

图 13.13:动词“requested”的 SRL 参数

我们不知道是这个人要求前总统祈祷,还是决定他会成为请求的中心。

一个很好的练习是展示一个 HTML 页面,然后问用户他们的看法。例如,可以要求用户查看 SRL 任务的结果,并回答以下两个问题:

前总统特朗普是被要求祈祷,还是因政治原因偏离了向他人提出的请求?

前总统特朗普称自己间接被要求为 X 祈祷是假新闻吗?

你可以思考一下,然后自己决定!

让我们看一个被推特禁止的情况。我去掉了名字,并改写了它并放低了语气。然而,当我们在 AllenNLP 上运行它并可视化结果时,我们得到一些令人惊讶的 SRL 输出。

这是缓和并改写的推特:

这些暴徒正在玷污 X 的记忆。

当抢劫开始时,必须采取行动。

尽管我删除了原始推特的主要部分,但我们可以看到 SRL 任务显示了推特中的糟糕联想:

图形用户界面、应用 自动生成的描述

图 13.14:动词“dishonoring”的 SRL 参数

对此的教育性方法应该是解释我们不应该将“暴徒”和“记忆”以及“抢劫”联系起来。它们根本不相符。

问一个用户为什么 SRL 参数不匹配会是一个重要的练习。

我建议进行许多这样的练习,以便 transformer 模型的用户们培养 SRL 技能,对他们所呈现的任何话题持批判性观点。

批判性思维是阻止假新闻传播的最佳方法!

我们已经通过Transformers、启发式和指导性网站讨论了假新闻的理性方法。然而,在最后,假新闻辩论中的很多热情归结为情绪化和非理性的反应。

在一个意见纷呈的世界中,你永远不会找到一个完全客观的Transformers模型来检测假新闻,因为对立的双方从一开始就无法就真相达成一致意见!一方会同意Transformers模型的输出。另一方会说这个模型是有偏见的,是由他们意见的敌人建造的!

最好的方法是倾听他人的意见并保持冷静!

在我们离开之前

本章更注重将Transformers应用于问题,而不是找到一个不存在的银弹Transformers模型。

你有两个主要选择来解决 NLP 问题:找到新的Transformers模型或者创建可靠、耐用的方法来实施Transformers模型。

我们现在将结束本章,转而解释Transformers模型。

总结

假新闻始于我们作为人类的情感历史的深处。当事件发生时,情绪接管以帮助我们迅速对情况做出反应。当我们受到威胁时,我们本能地做出强烈反应。

假新闻引发了强烈的反应。我们担心这些新闻可能会暂时或永久地损害我们的生活。我们中许多人相信气候变化可能会从地球上根除人类生命。还有人认为,如果我们对气候变化反应过激,我们可能会摧毁我们的经济并使社会崩溃。我们中一些人认为枪支是危险的。其他人提醒我们,美国宪法第二修正案赋予我们在美国拥有枪支的权利。

我们经历了关于 COVID-19、前总统特朗普和气候变化的其他激烈冲突。在每种情况下,我们看到情绪反应是最快形成冲突的。

然后,我们设计了一个路线图,将假新闻的情感感知提升到理性水平。我们使用一些Transformers NLP 任务来展示,在 Twitter、Facebook 消息和其他媒体中找到关键信息是可能的。

我们利用一些人认为是真实新闻,而另一些人认为是假新闻的新闻来为老师、父母、朋友、同事或者只是交谈的人们创造了一个理性。我们添加了经典的软件功能来帮助我们一路前行。

此时,你手头有一套Transformers模型、NLP 任务和样本数据集的工具箱。

你可以利用人工智能造福人类。将这些Transformers工具和思想付诸实施,使世界成为一个更好的地方,这取决于你。

了解Transformers的一个好方法是可视化它们的内部过程。我们将在下一章中分析Transformers如何逐渐构建序列的表示,解释黑匣子Transformers模型。

问题

  1. 标记为假新闻的新闻总是假的。(真/假)

  2. 所有人都同意的新闻总是准确的。(是/否)

  3. Transformers可以用于对推文进行情感分析。(是/否)

  4. 可以通过运行 DistilBERT 模型的 NER 从 Facebook 消息中提取关键实体。(是/否)

  5. 关键动词可以通过运行基于 BERT 模型的 SRL 的 YouTube 聊天来识别。(是/否)

  6. 情感反应是对虚假新闻的自然第一反应。(是/否)

  7. 对虚假新闻的理性处理可以帮助澄清一个人的立场。(是/否)

  8. 将Transformers与可靠网站连接可以帮助某人理解为什么一些新闻是虚假的。(是/否)

  9. Transformers可以总结可靠网站的内容,帮助我们理解一些被标记为虚假新闻的话题。(是/否)

  10. 如果你为了我们所有人的利益使用人工智能,你可以改变世界。(是/否)

参考资料

加入我们书籍的 Discord 空间

加入该书的 Discord 工作空间,与作者进行每月的问我任何事会话:

www.packt.link/Transformers

第十四章:解释黑匣子Transformers模型

百万到十亿参数的Transformers模型看起来像是无法解释的巨大黑匣子。 因此,当处理这些令人震惊的模型时,许多开发者和用户有时会感到沮丧。 然而,最近的研究已经开始用创新的前沿工具解决了这个问题。

描述所有可解释的 AI 方法和算法超出了本书的范围。 因此,本章将专注于提供给Transformers模型开发者和用户洞察力的即用型视觉界面。

本章首先通过安装和运行Jesse Vig的BertViz来开始。 Jesse 在构建显示 BERT Transformers模型中注意力头活动的可视界面方面做得相当出色。 BertViz 与 BERT 模型交互,并提供了一个设计良好的交互界面。

我们将继续专注于使用语言可解释工具(LIT)来可视化Transformers模型的活动。 LIT 是一个非侵入性工具,可以使用 PCA 或 UMAP 来表示Transformers模型的预测。 我们将介绍 PCA 并使用 UMAP。

最后,我们将使用字典学习可视化Transformers穿越 BERT 模型层的旅程。 局部可解释的模型不可知解释(LIME)提供了可视化Transformers学习如何理解语言的实用函数。 该方法显示Transformers通常首先学习一个词,然后学习句子上下文中的词,最后是长距离依赖关系。

在本章结束时,您将能够与用户交互,以展示Transformers模型的活动可视化。 BertViz,LIT 和通过字典学习进行的可视化仍有很长的路要走。 然而,这些新生工具将帮助开发者和用户理解Transformers模型的工作方式。

本章涵盖以下主题:

  • 安装和运行 BertViz

  • 运行 BertViz 的交互界面

  • 探究和非侵入性方法的区别

  • 主成分分析(PCA)提醒

  • 运行 LIT 分析Transformers输出

  • 介绍 LIME

  • 通过字典学习运行Transformers可视化

  • 单词级多义消歧

  • 可视化低级,中级和高级依赖性

  • 可视化关键Transformers因素

我们的第一步将从安装和使用 BertViz 开始。

使用 BertViz 进行Transformers可视化

Jesse Vig的文章,Transformers模型中注意力的多尺度可视化,2019 年,认识到了Transformers模型的有效性。 但是,Jesse Vig解释了解密注意力机制是具有挑战性的。 该论文描述了 BertViz 的过程,即可视化工具。

BertViz 可以可视化注意力头活动并解释Transformers模型的行为。

BertViz 最初是为了可视化 BERT 和 GPT-3 模型而设计的。 在本节中,我们将可视化 BERT 模型的活动。

现在让我们安装并运行 BertViz。

运行 BertViz

可视化变形器注意头并与之交互只需五个步骤。

在 GitHub 仓库的Chapter14目录中打开BertViz.ipynb笔记本。

第一步是安装BertViz和必要的依赖。

步骤 1:安装 BertViz 并导入模块

笔记本安装了BertViz、Hugging Face transformers 和其他实现程序所需的基本要求:

!pip install bertViz
from bertViz import head_view, model_view
from transformers import BertTokenizer, BertModel 

头视图和模型视图库现在已被导入。我们现在将加载 BERT 模型和分词器。

步骤 2:加载模型并检索注意力

BertViz 支持 BERT、GPT-2、RoBERTa 和其他模型。您可以在 GitHub 上查阅 BertViz 获取更多信息:github.com/jessevig/BertViz。

在本节中,我们将运行一个bert-base-uncased模型和一个预训练的分词器:

# Load model and retrieve attention
model_version = 'bert-base-uncased'
do_lower_case = True
model = BertModel.from_pretrained(model_version, output_attentions=True)
tokenizer = BertTokenizer.from_pretrained(model_version, do_lower_case=do_lower_case) 

我们现在输入两个句子。您可以尝试不同的序列以分析模型的行为。sentence_b_start将在步骤 5:模型视图中必需:

sentence_a = "A lot of people like animals so they adopt cats"
sentence_b = "A lot of people like animals so they adopt dogs"
inputs = tokenizer.encode_plus(sentence_a, sentence_b, return_tensors='pt', add_special_tokens=True)
token_type_ids = inputs['token_type_ids']
input_ids = inputs['input_ids']
attention = model(input_ids, token_type_ids=token_type_ids)[-1]
sentence_b_start = token_type_ids[0].tolist().index(1)
input_id_list = input_ids[0].tolist() # Batch index 0
tokens = tokenizer.convert_ids_to_tokens(input_id_list) 

就是这样!我们已经准备好与可视化界面进行交互。

步骤 3:头视图

我们只需添加一个最后一行来激活注意头的可视化:

head_view(attention, tokens) 

第一层(layer 0)中的单词并非实际标记,但界面是教育性的。每一层的 12 个注意头以不同的颜色显示。默认视图设置为层 0,如图 14.1所示:

图 14.1:注意头的可视化

我们现在准备探索注意头。

步骤 4:处理和显示注意头

上面两列标记中的每种颜色表示该层编号的一个注意头。选择一个层编号并单击一个注意头(颜色)。

句子中的单词在注意中被分解成标记。然而,在本节中,单词tokens宽泛指words,以帮助我们了解变形器头是如何工作的。

我专注于图 14.2中的单词animals:

图 14.2:选择一个层、一个注意头和一个标记

BertViz显示模型在animals和几个单词之间建立了连接。这是正常的,因为我们只在层 0。

Layer 1 开始单独分离与之相关的单词animals,如图 14.3所示:

图 14.3:可视化第 1 层中注意头 11 的活动

注意头 11 在animals、people和adopt之间建立了一个连接。

如果我们点击cats,一些有趣的连接将显示在图 14.4中:

图 14.4:可视化猫与其他标记之间的连接

现在,单词cats与animals相关联。这种关联表明模型正在学习猫是动物。

您可以更改句子,然后单击图层和注意力头,以可视化Transformers如何建立连接。当然,您会发现限制。好的和坏的连接将向您展示Transformers的工作原理和失败情况。这两种情况对于解释Transformers的行为以及为什么它们需要更多层、参数和数据都是有价值的。

让我们看看 BertViz 如何显示模型视图。

步骤 5:模型视图

只需一行代码就可以获得一个带有 BertViz 的Transformers的模型视图:

model_view(attention, tokens, sentence_b_start) 

BertViz 在一个视图中显示所有的层和头部,如 图 14.5 中所示:

一张包含建筑物的图像,自动生成的描述

图 14.5:BertViz 的模型视图模式

如果您单击其中一个头部,将获得一个带有单词对单词和句子对句子选项的头部视图。然后,您可以浏览注意力头,以查看Transformers模型在通过层时如何生成更好的表示。例如,图 14.6 显示了第一层中一个注意力头的活动:

一张包含文本、黑色、激光的图像,自动生成的描述

图 14.6:模型较低层的注意力头活动

有时,表示会在分隔符 [SEP] 和单词之间建立连接,这并没有太多意义。但是,有时标记不会在每个层的每个注意力头中激活。此外,Transformers模型的训练水平限制了解释的质量。

无论如何,BertViz 仍然是一个有趣的教育工具和Transformers模型的可解释性工具。

现在让我们运行直观的 LIT 工具。

LIT

LIT 的可视化界面将帮助您找到模型处理不正确的示例,深入研究类似示例,查看在更改上下文时模型的行为以及与Transformers模型相关的更多语言问题。

LIT 不像 BertViz 那样显示注意力头的活动。然而,值得分析为什么事情出错了并尝试找到解决方案。

您可以选择均匀流形逼近与投影(UMAP)可视化或 PCA 投影仪表示。PCA 将在特定方向和幅度上进行更线性的投影。UMAP 将其投影分解为小型聚类。根据您分析模型输出的深入程度,这两种方法都是有意义的。您可以同时运行并获得相同模型和示例的不同视角。

本节将使用 PCA 运行 LIT。让我们从简要回顾 PCA 的工作原理开始。

PCA

PCA 将数据提升到更高的层次进行表示。

想象一下您在厨房里。您的厨房是一个 3D 笛卡尔坐标系。您厨房里的物体也都有特定的 x、y、z 坐标。

您想要烹饪一道菜,并将配料摆放在厨房桌上。您的厨房桌是您厨房里菜谱的较高级别表示。

厨房桌也在使用笛卡尔坐标系。但是当您提取厨房的主要特征以在厨房桌上表示菜谱时,您正在执行 PCA。这是因为您展示了一起适合制作特定菜谱的主要组件。

相同的表现可以应用于 NLP。例如,字典是一个词语列表。但是一起有意义的词语构成序列主成分的表示。

在 LIT 中序列的 PCA 表示将有助于可视化Transformers的输出。

获得 NLP PCA 表示的主要步骤是:

  • 方差:数据集中一个词语的数值方差;其含义的频率和频率,例如。

  • 协方差:多个单词的方差与数据集中另一个单词的相关性。

  • 特征值和特征向量:要在笛卡尔系统中获得表示,我们需要协方差的向量和幅角表示。特征向量将提供向量的方向。特征值将提供它们的幅角。

  • 派生数据:最后一步是通过将行特征向量乘以行数据来将特征向量应用于原始数据集:

  • 要显示的数据 = 行特征向量 * 行数据

PCA 投影提供了清晰的数据点线性可视化以进行分析。

现在让我们运行 LIT。

运行 LIT

您可以在线运行 LIT 或在 Google Colaboratory 笔记本中打开它。单击以下链接以访问两个选项:

教程页面包含几种类型的 NLP 任务进行分析:

在本节中,我们将在线运行 LIT 并探索情感分析分类器:

单击自己探索这个演示,您将进入直观的 LIT 接口。Transformers模型是一个小型Transformers模型:

Une image contenant texte  Description générée automatiquement

图 14.7:选择模型

您可以通过单击模型更改模型。您可以直接在 Hugging Face 提供的托管 API 页面上测试这种类型的模型和类似模型:

huggingface.co/sshleifer/tiny-distilbert-base-uncased-finetuned-sst-2-english

NLP 模型可能会根据 LIT 在线版本的后续更新而发生变化。概念保持不变,只是模型变化。

让我们从选择 PCA 投影仪和每个示例的二元0或1分类标签开始:

图片

图 14.8:选择投影仪和标签类型

然后我们转到数据表,点击一个句子及其分类标签:

图片

图 14.9:选择一句话

该算法是随机的,因此输出可能会在不同运行中有所变化。

在数据点编辑器中也会出现这个句子:

图片

图 14.10:数据点编辑器

数据点编辑器允许您改变句子的上下文。例如,您可能想要找出为什么一个反事实的分类本应属于一个类别,但最终属于另一个类别。您可以改变句子的上下文,直到它出现在正确的类别中,以了解模型的工作原理及为何出现错误。

这个句子将与它的分类一起出现在 PCA 投影仪中:

图片

图 14.11:正向聚类中的 PCA 投影仪

您可以在 PCA 投影仪中点击数据点,所选句子将出现在数据点编辑器中。这样,您可以比较结果。

LIT 包含许多您可以探索和使用的交互功能。

LIT 中得到的结果并不总是令人信服。然而,在许多情况下,LIT 提供了有价值的见解。同时,参与这些新兴的工具和技术是至关重要的。

现在让我们通过词典学习来可视化Transformers层。

通过词典学习的Transformers可视化

通过词典学习的Transformers可视化是基于Transformers因子的。

Transformers因子

Transformers因子是包含上下文单词的嵌入向量。一个没有上下文的单词可以有许多意义,从而产生多义问题。例如,单词separate可以是动词或形容词。此外,separate还可以意味着断开、区分、分散,以及许多其他定义。

Yun等人在 2021 年创造了一个包含上下文单词的嵌入向量。单词的嵌入向量可以由单词因子的稀疏线性表示构建。例如,根据数据集中句子的上下文,separate可以被表示为:

`separate=0.3" keep apart"+"0.3" distinct"+ 0.1 "discriminate"+0.1 "sever" + 0.1 "disperse"+0.1 "scatter"` 

为了确保线性表示保持稀疏,我们不添加会创建大量 0 值矩阵的 0 因子。因此,我们不包括无用的信息,比如:

`separate= 0.0"putting together"+".0" "identical"` 

整个关键是通过强制因子的系数大于 0 来保持表示的稀疏性。

每个单词的隐藏状态在每一层中都被检索出来。由于每一层在理解数据集中句子中单词的表示方面都有所进展,潜在的依赖关系逐渐增加。这种稀疏线性叠加的Transformers因子变成了一个带有稀疏系数向量的词典矩阵,我们可以将其总结为:

在其中:

  • (phi)是词典矩阵。

  • 是待推断的稀疏系数向量

Yun等人在 2021 年补充说,epsilon,添加高斯噪声样本以强制算法搜索更深层的表示。

同样,为了确保表示保持稀疏,方程必须写成,使得(such that)α > 0。

作者将X指代为层的隐藏状态集合,将x指代为属于X的变换因子的稀疏线性叠加。

他们将自己稀疏字典学习模型总结为:

在词典矩阵中,φ:,c 指的是词典矩阵的一列,其中包含一个变换因子。

φ:,c分为三个级别:

  • 低级变换因子用于通过词级消歧解决多义问题

  • 中级变换因子将我们进一步带入句子级模式,这将为低级模式带来重要的上下文。

  • 高级变换模式帮助理解长程依赖关系

该方法是创新的、令人兴奋的,看起来效率很高。然而,目前还没有可视化功能。因此,Yun等人于 2021 年为 LIME 创造了必要的信息,这是一种标准的可解释人工智能方法,可以用于可视化他们的发现。

交互式变换器可视化页面基于 LIME 进行输出。以下部分是对 LIME 的简要介绍。

介绍 LIME

LIME代表局部可解释的模型-不可知解释。这一可解释的人工智能方法的名称说明了它的特点。它是模型不可知的。因此,我们可以立即得出有关通过词典学习进行变换器可视化方法的结论:

  • 该方法不会深入研究变换器层的矩阵、权重和矩阵乘法。

  • 该方法不会解释变换器模型的工作原理,就像我们在第二章中所做的那样,开始使用变换器模型的架构。

  • 在本章中,该方法窥视了由变换因子的稀疏线性叠加提供的数学输出。

LIME 并不试图解析数据集中的所有信息。相反,LIME 通过检查预测周围的特征来判断模型是否局部可靠。

LIME 不适用于全局模型。它专注于预测的局部环境。

这在处理自然语言处理时尤为有效,因为 LIME 探索了一个词的上下文,为模型的输出提供了宝贵的信息。

在通过词典学习进行可视化时,一个实例x可以表示为:

此实例的可解释表示是一个二进制向量:

目标是确定特征或多个特征的局部存在或缺失。在 NLP 中,这些特征是可以重建为单词的令牌。

对于 LIME 来说,g代表一个Transformers模型或任何其他机器学习模型。G代表一组包含g在内的Transformers模型,以及其他模型:

因此,LIME 的算法可以应用于任何Transformers模型。

在这一点上,我们知道:

  • LIME 以一个词为目标,并搜索其他词的局部上下文

  • 因此,LIME 提供了一个词的局部上下文,以解释为什么会预测这个词,而不是其他词

探索 LIME 等可解释 AI 并不在这本关于 NLP 的Transformers书籍的范围内。不过,有关 LIME 的更多信息,请参见参考部分。

现在让我们看看 LIME 是如何将自己融入通过字典学习的Transformers可视化方法中的。

现在让我们探索可视化界面。

可视化界面

访问以下网站以访问交互式的Transformers可视化页面:transformervis.github.io/transformervis/。

可视化界面提供了直观的说明,只需点击一次即可开始分析特定层的Transformers因素,如图 14.12所示:

图 14.12:选择一个Transformers因素

一旦选择了一个因素,您可以点击您想要为这个因素可视化的层:

图 14.13:每层的函数可视化

第一个可视化展示了按层激活因素的情况:

图 14.14:每层因素的重要性

因素421着眼于separate的词汇领域,正如下层所示:

图 14.15:在下层中对“separate”的表示

随着我们可视化更高的层级,会出现更长范围的表示。因素421从separate的表示开始。但在更高的层次上,Transformers开始形成对因素的更深层次的理解,并将separate与distinct相关联,如图 14.16所示:

图 14.16:Transformers要素的高层表示

尝试使用几个Transformers因素来可视化,以便逐层扩展他们对语言的理解和感知。

您会发现许多好例子,也会发现很多糟糕的结果。专注于好例子,以了解Transformers如何通过语言学习的方式。利用糟糕的结果来理解它为什么会犯错误。此外,可视化界面所使用的Transformers模型并非最强大或经过充分训练的模型。

无论如何,参与其中并保持对这个不断发展的领域的关注!

例如,您可以探索 Understanding_GPT_2_models_with_Ecco.ipynb,这是本章的 GitHub 存储库中的内容。它演示了Transformers在选择标记之前如何生成候选项。这是不言自明的。

在本节中,我们看到了Transformers如何逐层学习单词的含义。一个Transformers在做出选择之前会生成候选项。正如笔记本所示,Transformers模型是随机的,因此会在几个最高概率中进行选择。考虑以下句子:

"The sun rises in the_____." 

您会选择什么词放在句子的结尾?我们都会犹豫。这也是Transformers所做的!

在这种情况下,GPT-2 模型选择了sky这个词:

图形用户界面 自动生成描述

图 14.17:完成一个序列

但是 GPT-2 模型可能会在另一次运行中选择其他候选项,就像图 14.18中显示的:

图形用户界面,应用程序 自动生成描述图 14.18:其他的完成候选项

我们可以看到sky出现在第一名。但morning也出现在第二名,并且也可以合适。如果我们多次运行模型,可能会得到不同的输出,因为模型是随机的。

看起来 AI 和Transformers的领域已经完备了。

然而,在我们继续之前,让我们看看为什么人们在这个领域仍然有很多工作要做。

探索我们无法访问的模型

本章探讨的可视化界面非常引人入胜。但仍然有很多工作要做!

例如,OpenAI 的 GPT-3 模型可以在线运行或通过 API 运行。因此,我们无法访问一些软件即服务(SaaS)Transformers模型的权重。这种趋势将在未来数年内增加和扩展。那些花费数百万美元用于研究和计算机动力的公司更倾向于提供按需付费的服务,而不是开源应用程序。

即使我们能够访问 GPT-3 模型的源代码或输出权重,使用可视化界面来分析 9,216 个注意力头(96 层 x 96 头)也将是相当具有挑战性的。

在很多情况下,寻找错误仍然需要一些人的参与。

例如,在英语到法语翻译中,coach这个词的多义性经常会造成问题。在英语中,coach 可以是一个训练别人的人,也可以是一辆公共汽车。法语中也有coach这个词,但它只适用于一个训练别人的人。

如果您去 OpenAI AI GPT-3 游乐场,openai.com/,并翻译含有coach这个词的句子,您可能会得到混合的结果。

句子 1 被 OpenAI 引擎正确翻译了:

English: The coach broke down, and everybody complained.
French: Le bus a eu un problème et tout le monde s'est plaint. 

coach被翻译成了巴士,这是正确的。但需要更多的语境。

输出是随机的,所以翻译可能一次正确,下一次错误。

然而,第二句被误译了:

English: The coach was dissatisfied with the team and everybody complained.
French: Le bus était insatisfait du équipe et tout le monde s'est plaint. 

这一次,GPT-3 引擎错过了coach指的是一个人,而不是一辆公共汽车的事实。相同的随机运行将提供不稳定的输出。

如果我们通过添加上下文来修改句子 2,我们将获得正确的翻译:

English: The coach of the football team was dissatisfied and everybody complained.
French: Le coach de l'équipe de football était insatisfait et tout le monde s'est plaint. 

现在翻译中包含了法语单词coach,表示与本句英语单词coach相同的含义。添加了更多上下文。

OpenAI 的解决方案,AI 总体上,尤其是Transformers模型,都在不断进步。此外,大多数工业 4.0 的 AI 驱动微决策不需要如此复杂的 NLP 或翻译任务,并且非常有效。

但是,在 Cloud AI API 级别的人为干预和发展仍然需要相当长的时间!

总结

Transformers模型被训练来解决词级别的一词多义消歧

低层、中层和高层的依赖关系。通过连接训练百万到万亿参数模型来实现这一过程。解释这些巨型模型的任务似乎令人生畏。然而,一些工具正在涌现。

我们首先安装了BertViz。我们学会了如何使用交互式界面解释注意头的计算。我们看到了每一层的单词是如何与其他单词互动的。

本章继续定义了探查任务和非探查任务的范围。诸如 NER 之类的探查任务提供了有关Transformers模型如何表示语言的见解。然而,非探查方法分析模型如何做出预测。例如,LIT 将 PCA 项目和 UMAP 表示插入 BERT Transformers模型的输出中。然后,我们可以分析输出的集群以查看它们如何组合在一起。

最后,我们通过词典学习运行了Transformers可视化。用户可以选择一个Transformers因子来分析并可视化其在Transformers的低层到高层的表示演变。该因子将逐渐从一词多义的消歧到句子上下文分析,最终到长期依赖。

本章的工具将随着其他技术的发展而不断发展。然而,本章的关键重点是Transformers模型的活动可以以用户友好的方式进行可视化和解释。在下一章中,我们将发现新的Transformers模型。我们还将通过风险管理方法选择Transformers模型项目的最佳实现。

问题

  1. BertViz 只显示了 BERT 模型最后一层的输出。(真/假)

  2. BertViz 显示了 BERT 模型每一层的注意头。(真/假)

  3. BertViz 展示了标记之间的关系。(真/假)

  4. LIT 显示了类似 BertViz 的注意头的内部工作。(真/假)

  5. 探查是算法预测语言表示的一种方式。(真/假)

  6. NER 是一个探查任务。(真/假)

  7. PCA 和 UMAP 都不是探查任务。(真/假)

  8. LIME 是与模型无关的。(真/假)

  9. Transformers 通过逐层深化令牌之间的关系。(True/False)

  10. 视觉 Transformer 模型解释为可解释的人工智能增添了一个新的维度。(True/False)

参考资料

加入我们书籍的 Discord 空间

加入本书的 Discord 工作空间,与作者进行每月的问我任何事会话:

www.packt.link/Transformers

第十五章:从 NLP 到任务不可知的Transformers模型

到目前为止,我们已经检查了原始Transformers模型的变体,具有编码器和解码器层,以及具有仅编码器或仅解码器层的其他模型。此外,层和参数的大小已经增加。然而,Transformers的基本结构保留了其原始结构,具有相同的层和注意头的计算并行化。

在本章中,我们将探索尊重原始Transformers基本结构但进行了一些重大变化的创新Transformers模型。许多Transformers模型会出现,就像一个乐高^© 件盒给出的许多可能性一样。你可以以数百种方式组装这些部件!Transformers模型子层和层是先进 AI 的乐高^© 部件。

我们将从众多提供中选择哪个Transformers模型,并选择我们将实施它们的生态系统开始。

然后,我们将发现 Reformer 模型中的局部敏感哈希(LSH)桶和分块技术。然后我们将了解 DeBERTa 模型中解耦关注的含义。DeBERTa 还介绍了一种在解码器中管理位置的替代方法。DeBERTA 的高功率Transformers模型超越了人类基线。

我们的最后一步将是发现像 Vit、CLIP 和 DALL-E 这样的强大的计算机视觉Transformers。我们可以将 CLIP 和 DALL-E 添加到 OpenAI GPT-3 和 Google BERT(由 Google 训练)这个非常小的基础模型组中。

这些强大的基础模型证明了Transformers是任务不可知的。Transformers学习序列。这些序列包括视觉、声音以及任何以序列表示的数据类型。

图像包含类似语言的数据序列。我们将运行 ViT、CLIP 和 DALL-E 模型进行学习。我们将把视觉模型提升到创新水平。

在本章结束时,你将看到任务不可知Transformers的世界已经演变成了一个充满想象力和创造力的宇宙。

本章涵盖以下主题:

  • 选择Transformers模型

  • Reforme Transformers模型

  • 局部敏感哈希(LSH)

  • 桶和分块技术

  • DeBERTA Transformers模型

  • 解耦关注

  • 绝对位置

  • 具有 CLIP 的文本图像视觉Transformers

  • DALL-E,一个创意文本图像视觉Transformers

我们的第一步将是看看如何选择一个模型和一个生态系统。

选择一个模型和一个生态系统

我们认为通过下载转换器模型进行测试将需要机器和人力资源。而且,你可能会认为如果一个平台到这个时候还没有在线沙盒,那么进一步进行测试就会有风险,因为测试几个示例的工作量。

然而,像 Hugging Face 这样的网站会在实时自动下载预训练模型,正如我们将在The Reformer和DeBERTa部分看到的那样!那么我们该怎么办?由于这个,我们可以在 Google Colab 上运行 Hugging Face 模型,而不需要在本机上安装任何东西。我们还可以在线测试 Hugging Face 模型。

思路是分析而无需任何“安装”。在 2022 年,“无需安装”可能意味着:

  • 在线运行一个Transformers任务

  • 在预安装的 Google Colaboratory 虚拟机上运行一个Transformers,它可以无缝地下载一个预训练模型以完成任务,我们可以用几行代码来运行。

  • 通过 API 运行一个Transformers

“安装”的定义在过去几年已经扩展了。 “在线”的定义也已经扩大。我们可以考虑使用几行代码来运行一个 API 作为元在线测试。

在本节中,我们将广义上谈到“无需安装”和“在线”。图 15.1显示了我们应该如何“在线”测试模型:

使用低置信度自动生成的图表说明

图 15.1:在线测试Transformers模型

正如下面展示的,这十年的测试变得灵活和高效:

  • Hugging Face 托管诸如 DeBERTa 和其他一些模型等 API 模型。此外,Hugging Face 还提供 AutoML 服务,用于在其生态系统中训练和部署Transformers模型。

  • OpenAI 的 GPT-3 引擎在在线游乐场上运行并提供 API。OpenAI 提供涵盖许多 NLP 任务的模型。这些模型无需训练。 GPT-3 的十亿参数零射引擎令人印象深刻。它显示出参数多的Transformers模型整体产生更好的结果。Microsoft Azure、Google Cloud AI、AllenNLP 和其他平台提供有趣的服务。

  • 如果值得的话,可以通过阅读一篇论文来进行在线模型分析。Google 的Fedus等人在 2021 年的一篇关于Switch Transformers: Scaling to Trillion Parameter Models with Simple and Efficient Sparsity的论文是一个很好的例子。Google 增加了我们在第八章中研究的基于 T5 的模型的规模,即应用于法律和金融文件的 AI 文本摘要。这篇论文证实了像 GTP-3 这样的大型在线模型的策略。

然而,最终,选择一种解决方案的风险还是在你自己。在选择一种解决方案后,你花在探索平台和模型上的时间将有助于你优化项目的实施。

可以通过三种不同的方式托管你的选择,如图 15.2所示:

  • 使用 API 在本地机器上。OpenAI、Google Cloud AI、Microsoft Azure AI、Hugging Face 和其他提供了良好的 API。一个应用程序可以在本地机器上而不是在云平台上,但可以通过 API 经过云服务。

  • 在像亚马逊网络服务(AWS)或 Google Cloud 这样的云平台上。您可以在这些平台上训练、微调、测试和运行模型。在这种情况下,没有应用在本地机器上。一切都在云上。

  • 可以从任何地方使用 API!在本地机器上,数据中心虚拟机上,或从任何地方。这意味着 API 将集成在一个物理系统中,比如风车、飞机、火箭或自动驾驶车辆。因此,系统可以通过 API 与另一个系统永久连接。

自动生成的图表描述

图 15.2: 为您的模型实现选项

最后,决定权在你手中。花点时间。测试、分析、计算成本,并团队合作听取不同的观点。你对转换器的工作方式了解得越多,你做出的选择就会越好。

现在让我们来探索改革者,这是原始转换器模型的一个变种。

改革者

Kitaev等人(2020 年)设计改革者来解决注意力和内存问题,为原始转换器模型添加功能。

改革者首先用局部敏感哈希(LSH)桶和分块来解决注意力问题。

LSH 在数据集中搜索最近的邻居。哈希函数确定如果数据点q接近p,那么hash(q) == hash(p)。在这种情况下,数据点是Transformers模型头的键。

LSH 函数将键转换为 LSH 桶(图 15.3 中的B1到B4),这个过程称为 LSH 分桶,就像我们将彼此相似的对象放在同一个排序的桶中一样。

排序的桶被分成块(图 15.3 中的C1到C4)进行并行化。最后,注意力仅在其块内和前一个块中的相同桶中应用:

图 15.3: LSH 注意力头

LSH 分桶和分块将复杂度从O(L²),即关注所有词对,减少到O(LlogL),即仅关注每个桶的内容。

改革者还解决了重新计算每一层输入而不是存储多层模型信息的内存问题。重新计算是按需实现的,而不是为一些大型多层模型消耗的千字节内存。

我们现在将使用在Fyodor Dostoevsky的《罪与罚》英文翻译上训练的一个改革者模型。

运行一个例子

让我们直接在托管的推理 API 上在线运行它。输入句子是:

这个学生贫困潦倒,不知所措。

在在线接口的链接中包含输入:

huggingface.co/google/reformer-crime-and-punishment?text=The+student+was+impoverished+and+did+not+know+what+to+do

托管推理 API 与输入句子一起显示。点击计算以获得推理,结果将直接显示在输入下方:

图 15.4:Reformer 的托管推理 API

由于算法是随机的,您可能会得到不同的响应。Reformer 经过了合理的训练,尽管没有像 OpenAI 的 GPT-3 那样拥有数十亿位信息的超级计算机。Reformer 的结果并不令人印象深刻。它需要更多的训练和微调才能获得更好的结果。

OpenAI 的 GPT-3 引擎对文本完成产生了以下结果:

学生生活贫困,不知所措。他找不到可以求助的人,也找不到住的地方。他从包里拿出一个记事本开始写。他写道:

“我的名字叫 XXXXXXXXXX。我是 XXXXXXX 的学生。我没有家人,没有朋友,没有钱。”

结果更具说服力。注册后,您可以访问 OpenAI 的游乐场:openai.com/

注意:OpenAI GPT-3,与其他Transformers模型和大多数深度学习模型一样,基于随机算法。结果可能会有所不同。

这表明,包含数十亿参数的高度训练有素的Transformers模型可以胜过一种创新的Transformers模型架构。

超级计算机驱动的云 AI 平台是否会逐渐胜过本地尝试甚至功能较弱的云平台?在投资于一种解决方案之前,您需要通过原型解决这些问题。

注意:Transformers模型的随机性可能导致在运行这些模型时产生不同的结果。此外,在线平台不断变化其界面。我们需要接受并适应这一点。

DeBERTa 引入了另一种创新的架构,我们现在将对其进行探讨。

DeBERTa

通过分解还可以找到Transformers的另一种新方法。在 AI 中,分解允许您分离表示特征,使训练过程更加灵活。Pengcheng He,Xiaodong Liu,Jianfeng Gao和Weizhu Chen设计了 DeBERTa,这是Transformers的分解版本,并在一篇有趣的文章中描述了该模型:DeBERTa: Decoding-enhanced BERT with Disentangled Attention: arxiv.org/abs/2006.03654

DeBERTa 实现的两个主要思想是:

  • 在Transformers模型中将内容和位置分离开来,分别训练这两个向量

  • 在预训练过程中使用解码器中的绝对位置来预测屏蔽的标记

作者在 GitHub 上提供了代码:github.com/microsoft/DeBERTa

DeBERTa 超越了 SuperGLUE 排行榜上的人类基准:

图 15.5:DeBERTa 在 SuperGLUE 排行榜上的表现

在“让我们在 Hugging Face 的云平台上运行一个示例”之前,去除任何空格。

运行一个示例

要在 Hugging Face 的云平台上运行示例,请单击以下链接:

huggingface.co/cross-encoder/nli-deberta-base

托管推理 API 将显示一个示例和可能的类名称输出:

图 15.6:DeBERTa 的托管推理 API

可能的类名称是mobile,website,billing和account access。

结果很有趣。让我们将其与 GPT-3 关键词任务进行比较。首先,在openai.com/上注册一下

输入Text作为输入,并输入Keywords以要求引擎找到关键词:

文本:上周我升级了我的 iOS 版本,自那时起,每当我使用你们的应用时,我的手机就会过热。

关键词: app, overheating, phone

可能的关键词是app,overheating和phone。

我们已经学习了 DeBERTa 和 GPT-3 Transformers。现在我们将将Transformers扩展到视觉模型。

从任务无关模型到视觉Transformers

基础模型,正如我们在第一章“什么是Transformers?”中所看到的,具有两个独特而独特的属性:

  • 涌现 - 符合基础模型标准的Transformers模型可以执行未经训练的任务。它们是在超级计算机上训练的大型模型。它们没有被训练来学习像许多其他模型那样的特定任务。基础模型学会了如何理解序列。

  • 同质化 - 相同的模型可以在许多领域中使用相同的基本架构。基础模型可以通过数据比其他任何模型更快更好地学习新技能。

GPT-3 和 Google BERT(仅 Google 训练的 BERT 模型)是任务不可知的基础模型。这些任务不可知的模型直接引导到 ViT、CLIP 和 DALL-E 模型。Transformers有着奇特的序列分析能力。

Transformers模型的抽象程度导致多模态神经元:

  • 多模态神经元可以处理可被标记为像素或图像片段的图像。然后它们可以在视觉Transformers中被处理为单词。一旦图像被编码,Transformers模型将标记视为任何单词标记,如图 15.7 所示:

图 15.7:图像可以编码为类似单词的标记

在本节中,我们将介绍以下内容:

  • ViT,将图像处理为单词片段的视觉Transformers

  • CLIP,将文本和图像编码的视觉Transformers

  • DALL-E,用文本构造图像的视觉Transformers

让我们开始探索 ViT,一个将图像处理为单词片段的视觉Transformers。

ViT - 视觉Transformers

Dosovitskiy等人(2021)在文章标题中总结了他们设计的视觉Transformers架构的精华:一张图片价值 16x16 个单词:大规模图像识别的Transformers。

图像可以转换为 16x16 单词的片段。

在查看代码之前,让我们先看一下 ViT 的架构。

ViT 的基本架构

视觉变换器可以将图像作为“单词”补丁来处理。在本节中,我们将按照三个步骤进行处理:

  1. 将图像拆分成补丁

  2. 补丁的线性投影

  3. 混合输入嵌入子层

第一步是将图像拆分成相同尺寸的补丁。

第一步:将图像拆分成补丁

图像被分割成n个补丁,如图 15.8 所示。只要所有补丁的尺寸相同(例如 16x16),就没有规定补丁数量的规定:

图表,树状图描述自动生成

图 15.8:将图像拆分成补丁

相等尺寸的补丁现在代表我们序列的“单词”。如何处理这些补丁仍然是个问题。我们将看到每种视觉变换器都有自己的方法。

图像引用:本节和随后的几节中使用的猫的图像由DocChewbacca拍摄:www.flickr.com/photos/st3f4n/,于 2006 年。它属于 Flickr 免费许可证,creativecommons.org/licenses/by-sa/2.0/。有关更多详情,请查看 Flickr 上DocChewbacca的图片:www.flickr.com/photos/st3f4n/210383891

在这种情况下,对于 ViT,第 2 步是对展平的图像进行线性投影。

第二步:对展平的图像进行线性投影

第 1 步将图像转换为尺寸相等的补丁。补丁的动机是避免逐像素处理图像,但问题在于找到处理补丁的方法。

Google Research 团队决定设计一个由图像的展平图像的线性投影和通过分割图像获得的补丁组成的线性投影,如图 15.9 所示:

图 15.9:图像的线性投影

思路是获得一个类似单词的补丁序列。剩下的问题是嵌入展平图像序列。

第三步:混合输入嵌入子层

类似单词的图像序列可以适应变换器。问题在于它们仍然是图像!

Google Research 决定使用混合输入模型,如图 15.10 所示:

  • 添加一个卷积网络以嵌入补丁的线性投影

  • 添加位置编码以保留原始图像的结构

  • 然后使用标准的原始 BERT 样式编码器处理嵌入的输入

图 15.10:混合输入子层和标准编码器

Google Research 找到了一种巧妙的方法将 NLP 变换器模型转换成视觉变换器。

现在,让我们在代码中实现一个 Hugging Face 视觉变换器示例。

代码中的视觉变换器

在本节中,我们将重点关注与视觉变换器特定体系结构相关的主要代码区域。

打开Vision_Transformers.ipynb,它位于本章的 GitHub 存储库中。

Google Colab VM 中包含许多预安装的软件包,如torch和torchvision。可以通过在笔记本的第一个单元格中取消注释该命令来显示它们:

#Uncomment the following command to display the list of pre-installed modules 
#!pip list -v 

然后前往笔记本的Vision Transformer(ViT)单元。该笔记本先安装了 Hugging Face transformers 并导入了必要的模块:

!pip install transformers
from transformers import ViTFeatureExtractor, ViTForImageClassification
from PIL import Image
import requests 

注意:在撰写本书时,Hugging Face 警告我们,由于不断的演变,代码可能不稳定。但这不应阻止我们探索 ViT 模型。探索新领域正是前沿的所在!

然后我们从 COCO 数据集下载了一幅图像。如果你想进一步进行实验,可以在他们的网站上找到大量数据集:cocodataset.org/

让我们从 VAL2017 数据集中下载。按照 COCO 数据集网站的说明通过程序获取这些图像或在本地下载数据集。

VAL2017 包含了 5,000 张我们可以选择的图像,以测试这个 ViT 模型。你可以运行其中任何一张图像。

让我们用猫的图片测试笔记本。我们首先通过它们的 URL 检索猫的图片:

url = 'http://images.cocodataset.org/val2017/000000039769.jpg'
image = Image.open(requests.get(url, stream=True).raw) 

我们接下来要下载 Google 的特征提取器和分类模型:

feature_extractor = ViTFeatureExtractor.from_pretrained('google/vit-base-patch16-224')
model = ViTForImageClassification.from_pretrained('google/vit-base-patch16-224') 

该模型在 224 x 244 分辨率图像上进行训练,但在特征提取和分类时采用了 16 x 16 的块。笔记本运行模型并进行预测:

inputs = feature_extractor(images=image, return_tensors="pt")
outputs = model(**inputs)
logits = outputs.logits
# model predicts one of the 1000 ImageNet classes
predicted_class_idx = logits.argmax(-1).item()
print("Predicted class:",predicted_class_idx,": ", model.config.id2label[predicted_class_idx]) 

输出为:

Predicted class: 285 :  Egyptian cat 

探索在预测后的代码,它提供了一些低层次的信息,其中包括:

  • model.config.id2label,会列出类的标签。这 1000 个标签类解释了为什么我们得到一个类而不是详细的文本描述:

    {0: 'tench, Tinca tinca',1: 'goldfish, Carassius auratus', 2: 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias',3: 'tiger shark, Galeocerdo cuvieri',...,999: 'toilet tissue, toilet paper, bathroom tissue'} 
    
  • 模型,该模型将显示从卷积输入子层开始的模型架构:

    (embeddings): ViTEmbeddings(
      (patch_embeddings): PatchEmbeddings(
        (projection): Conv2d(3, 768, kernel_size=(16, 16), stride=(16, 16))
      ) 
    

在卷积输入嵌入子层之后,模型是一个类似 BERT 的编码器。

请花些时间探索这个创新的从 NLP 变换器到图像变换器的转变,迅速导向为一切都使用变换器。

现在,让我们了解另一个计算机视觉模型 CLIP。

CLIP

对比语言-图像预训练(CLIP)遵循了变换器的理念。它在其变换器类型的层中插入数据序列。这次,模型发送的是文本-图像对,而不是文本对。一旦数据被分词、编码和嵌入,CLIP,一个无关任务的模型,就像处理任何其他数据序列一样学习文本-图像对。

这种方法是对比的,因为它寻找图像特征中的对比。这是我们在一些杂志游戏中使用的方法,在这些游戏中,我们必须找到两幅图像之间的差异,对比。

让我们先看一下 CLIP 的架构,然后再看代码。

CLIP 的基本架构

对比:图像通过它们的差异和相似之处学习如何相互配合。通过(联合文本,图像)预训练,图像和字幕找到彼此的路径。预训练后,CLIP 学习新任务。

CLIP 是可转移的,因为它们可以学习新的视觉概念,就像 GPT 模型一样,比如视频序列中的动作识别。字幕带来了无尽的应用。

ViT 将图像分割成类似单词的补丁。CLIP 联合训练文本和图像编码器以最大化余弦相似度,如图 15.11所示:

自动生成的图表描述

图 15.11:联合训练文本和图像

图 15.11显示了Transformers将为文本输入运行标准Transformers编码器。它将在Transformers结构中为图像运行一个 ResNet 50 层 CNN。 ResNet 50 被修改为在具有多头 QKV 注意头的注意力池化机制中运行平均池化层。

让我们看看 CLIP 是如何学习文本-图像序列以进行预测的。

代码中的 CLIP

打开 GitHub 上本章的存储库中的Vision_Transformers.ipynb。然后转到笔记本的CLIP单元格。

该程序开始安装 PyTorch 和 CLIP:

!pip install ftfy regex tqdm
!pip install git+https://github.com/openai/CLIP.git 

该程序还导入模块和 CIFAR-100 来访问图像:

import os
import clip
import torch
from torchvision.datasets import CIFAR100 

有 10,000 张图像可用,索引介于 0 和 9,999 之间。下一步是选择我们要进行预测的图像:

图 15.12:选择一个图像索引

程序然后将模型加载到可用的设备上(GPU 或 CPU):

# Load the model
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load('ViT-B/32', device) 

图像已下载:

# Download the dataset
cifar100 = CIFAR100(root=os.path.expanduser("~/.cache"), download=True, train=False) 

输入已准备好:

# Prepare the inputs
image, class_id = cifar100[index]
image_input = preprocess(image).unsqueeze(0).to(device)
text_inputs = torch.cat([clip.tokenize(f"a photo of a {c}") for c in cifar100.classes]).to(device) 

在运行预测之前,让我们可视化所选的输入:

import matplotlib.pyplot as plt
from torchvision import transforms
plt.imshow(image) 

输出显示索引 15是一只狮子:

带有中等置信度自动生成的图形用户界面描述

图 15.13:索引 15 的图像

本节中的图像来自于从小图像中学习多层特征,Alex Krizhevsky,2009 年:www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf。它们是CIFAR-10和CIFAR-100数据集的一部分(toronto.edu):www.cs.toronto.edu/~kriz/cifar.html

我们知道这是一只狮子,因为我们是人类。一个最初设计用于自然语言处理的Transformers必须学习图像是什么。现在我们将看到它能多好地识别图像。

在计算特征时,程序表明正在运行一个联合Transformers模型,将图像输入与文本输入分开:

# Calculate features
with torch.no_grad():
    image_features = model.encode_image(image_input)
    text_features = model.encode_text(text_inputs) 

现在 CLIP 进行预测并显示前五个预测:

# Pick the top 5 most similar labels for the image
image_features /= image_features.norm(dim=-1, keepdim=True)
text_features /= text_features.norm(dim=-1, keepdim=True)
similarity = (100.0 * image_features @ text_features.T).softmax(dim=-1)
values, indices = similarity[0].topk(5)
# Print the result
print("\nTop predictions:\n")
for value, index in zip(values, indices):
    print(f"{cifar100.classes[index]:>16s}: {100 * value.item():.2f}%") 

如果您想获得更多或更少的预测结果,可以修改topk(5)。显示前五个预测:

Top predictions:
            lion: 96.34%
           tiger: 1.04%
           camel: 0.28%
      lawn_mower: 0.26%
         leopard: 0.26% 

CLIP 找到了狮子,这显示了Transformers架构的灵活性。

下一个单元格显示类别:

cifar100.classes 

您可以浏览类别,看看只有一个标签的情况下,CLIP 的表现如何受限制。

[...,'kangaroo','keyboard','lamp','lawn_mower','leopard','lion',
 'lizard', ...] 

笔记本包含了其他几个单元格,描述了您可以探索的 CLIP 的架构和配置。

model 单元格特别有趣,因为您可以看到以类似于 ViT 模型的卷积嵌入开始,然后继续作为一个“标准”大小为 768 的Transformers,具有多头注意力的视觉编码器:

CLIP(
  (visual): VisionTransformer(
    (conv1): Conv2d(3, 768, kernel_size=(32, 32), stride=(32, 32), bias=False)
    (ln_pre): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
    (transformer): Transformer(
      (resblocks): Sequential(
        (0): ResidualAttentionBlock(
          (attn): MultiheadAttention(
            (out_proj): NonDynamicallyQuantizableLinear(in_features=768, out_features=768, bias=True)
          )
          (ln_1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
          (mlp): Sequential(
            (c_fc): Linear(in_features=768, out_features=3072, bias=True)
            (gelu): QuickGELU()
            (c_proj): Linear(in_features=3072, out_features=768, bias=True)
          )
          (ln_2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
        ) 

model 单元格的另一个有趣之处是查看与图像编码器同时运行的大小为 512 的文本编码器:

(transformer): Transformer(
    (resblocks): Sequential(
      (0): ResidualAttentionBlock(
        (attn): MultiheadAttention(
          (out_proj): NonDynamicallyQuantizableLinear(in_features=512, out_features=512, bias=True)
        )
        (ln_1): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
        (mlp): Sequential(
          (c_fc): Linear(in_features=512, out_features=2048, bias=True)
          (gelu): QuickGELU()
          (c_proj): Linear(in_features=2048, out_features=512, bias=True)
        )
        (ln_2): LayerNorm((512,), eps=1e-05, elementwise_affine=True)
      ) 

浏览描述架构、配置和参数的单元格,了解 CLIP 如何表示数据。

我们展示了任务无关的Transformers模型将图像文本对处理为文本文本对。我们可以将任务无关模型应用于音乐文本、声音文本、音乐图像以及任何类型的数据对。

现在我们将探讨另一个任务无关的Transformers模型 DALL-E,它可以处理图像和文本。

DALL-E

与 CLIP 一样,DALL-E 是一个任务无关的模型。CLIP 处理文本图像对。DALL-E 分别处理文本和图像令牌。DALL-E 的输入是一个包含 1,280 个令牌的文本和图像的单一流。256 个令牌用于文本,1,024 个令牌用于图像。DALL-E 是一个像 CLIP 一样的基础模型。

DALL-E 的命名来源于 萨尔瓦多·达利 和 Pixar 的 WALL-E。DALL-E 的使用方法是输入文本提示并生成图像。然而,DALL-E 必须先学会如何用文本生成图像。

DALL-E 是 GPT-3 的 120 亿参数版本。

该Transformers使用文本-图像对数据集从文本描述生成图像。

DALL-E 的基本架构

与 CLIP 不同,DALL-E 将最多 256 个 BPE 编码的文本令牌与 32×32 = 1,024 个图像令牌连接起来,如 图 15.14 所示:

一个视频游戏的截图 带有中等置信度自动生成的描述

图 15.14:DALL-E 将文本和图像输入连接起来

图 15.14 显示,这一次我们的猫图像与输入文本连接在一起。

DALL-E 有一个编码器和一个解码器堆栈,其构建了将卷积功能注入到Transformers模型中的混合架构。

让我们窥探一下代码,看看模型是如何工作的。

代码中的 DALL-E

在本节中,我们将看到 DALL-E 如何重构图像。

打开 Vision_Transformers.ipynb。然后转到笔记本的 DALL-E 单元格。笔记本首先安装 OpenAI DALL-E:

!pip install DALL-E 

笔记本下载图像并处理图像:

import io
import os, sys
import requests
import PIL
import torch
import torchvision.transforms as T
import torchvision.transforms.functional as TF
from dall_e import map_pixels, unmap_pixels, load_model
from IPython.display import display, display_markdown
target_image_size = 256
def download_image(url):
    resp = requests.get(url)
    resp.raise_for_status()
    return PIL.Image.open(io.BytesIO(resp.content))
def preprocess(img):
    s = min(img.size)

    if s < target_image_size:
        raise ValueError(f'min dim for image {s} < {target_image_size}')

    r = target_image_size / s
    s = (round(r * img.size[1]), round(r * img.size[0]))
    img = TF.resize(img, s, interpolation=PIL.Image.LANCZOS)
    img = TF.center_crop(img, output_size=2 * [target_image_size])
    img = torch.unsqueeze(T.ToTensor()(img), 0)
    return map_pixels(img) 

程序现在加载 OpenAI DALL-E 编码器和解码器:

# This can be changed to a GPU, e.g. 'cuda:0'.
dev = torch.device('cpu')
# For faster load times, download these files locally and use the local paths instead.
enc = load_model("https://cdn.openai.com/dall-e/encoder.pkl", dev)
dec = load_model("https://cdn.openai.com/dall-e/decoder.pkl", dev) 

我添加了 enc 和 dec 单元格,以便您可以查看编码器和解码器块,了解这种混合模型的工作原理:Transformers模型中的卷积功能和文本与图像输入的连接。

本节中处理的图像是 mycat.jpg(作者:Denis Rothman,版权所有,需取得书面许可方可复制)。该图像位于本书存储库的 Chapter15 目录中。它已被下载并处理:

x=preprocess(download_image('https://github.com/Denis2054/AI_Educational/blob/master/mycat.jpg?raw=true')) 

最后,我们显示原始图片:

display_markdown('Original image:')
display(T.ToPILImage(mode='RGB')(x[0])) 

输出显示图像:

自动生成的文本描述

图 15.15:一张猫的图片

现在,程序处理并显示重建图像:

import torch.nn.functional as F
z_logits = enc(x)
z = torch.argmax(z_logits, axis=1)
z = F.one_hot(z, num_classes=enc.vocab_size).permute(0, 3, 1, 2).float()
x_stats = dec(z).float()
x_rec = unmap_pixels(torch.sigmoid(x_stats[:, :3]))
x_rec = T.ToPILImage(mode='RGB')(x_rec[0])
display_markdown('Reconstructed image:')
display(x_rec) 

重建后的图像看起来与原始图像极为相似:

自动生成的文本描述

图 15.16:DALL-E 重建了猫的图像

结果令人印象深刻。DALL-E 学会了如何自动生成图像。

在书写本书时,完整的 DALL-E 源代码尚不可用,也许永远都不会。目前尚未上线 OpenAI 的 API,用于从文本提示生成图像。但请保持关注!

与此同时,我们可以继续在 OpenAI 上发现 DALL-E:openai.com/blog/dall-e/

一旦你打开页面,就滚动到提供的示例下面。例如,我选择了旧金山 Alamo Square 的照片作为提示:

自动生成的文本描述

图 15.17:旧金山 Alamo Square 的提示

然后我将“在晚上”修改为“在早晨”:

图形用户界面、文本、应用程序、聊天或文本消息自动生成的描述

图 15.18:修改提示

DALL-E 然后生成了大量的 text2image 图像:

包含文本、标志、不同的描述自动生成

图 15.19:从文本提示生成图像

我们已经实现了 ViT、CLIP 和 DALL-E,三种视觉Transformers。在结束之前,让我们简要总结一下。

一个不断扩大的模型宇宙

新的Transformers模型,就像新的智能手机一样,几乎每周都会出现。其中一些模型既令人惊叹又对项目经理构成挑战:

列表已经变得无穷无尽,而且还在增长!

测试它们仍然是一个超出前述问题的挑战。只有少数Transformers模型符合基础模型的条件。基础模型必须是:

  • 完全训练,可执行一系列任务

  • 能够执行其未经训练的任务,因为它已经达到了独特的 NLU 水平

  • 足够大以保证相当准确的结果,比如 OpenAI GPT-3

许多网站提供的Transformers对于教育目的而言是有用的,但不能被视为足够训练和庞大以符合基准测试的。

最好的方法是尽可能地加深对Transformers模型的理解。在某个时刻,你会成为一名专家,通过大型技术创新的丛林将变得像选择智能手机一样容易!

摘要

新的Transformers模型不断出现在市场上。因此,通过阅读出版物和书籍,并测试一些系统,跟上前沿研究是一个好的实践。

这导致我们评估选择哪些Transformers模型以及如何实现它们。我们不能花几个月时间探索每个出现在市场上的模型。如果一个项目正在生产中,我们不能每个月都更换模型。工业 4.0 正在转向无缝的 API 生态系统。

学习所有模型是不可能的。然而,通过加深对Transformers模型的了解,可以快速理解一个新模型。

Transformers模型的基本结构保持不变。编码器和/或解码器堆栈的层保持相同。注意力头可以并行化以优化计算速度。

Reformer 模型应用LSH桶和分块。它还重新计算每个层的输入,而不是存储信息,从而优化了内存问题。然而,像 GPT-3 这样的十亿参数模型对于相同的示例产生可接受的结果。

DeBERTa 模型分解内容和位置,使训练过程更加灵活。结果令人印象深刻。然而,像 GPT-3 这样的十亿参数模型可以与 DeBERTa 的输出相媲美。

ViT、CLIP 和 DALL-E 带我们进入了迷人的任务无关的文本图像视觉Transformers模型的世界。结合语言和图像会产生新的、富有成效的信息。

问题仍然存在,即现成的人工智能和自动化系统将走多远。我们将尝试在下一章关于元人类崛起的章节中可视化基于Transformers的人工智能的未来。

问题

  1. Reformer Transformers模型不包含编码器。(True/False)

  2. Reformer Transformers模型不包含解码器。(True/False)

  3. 输入在 Reformer 模型中按层存储。(True/False)

  4. DeBERTa Transformers模型分解内容和位置。(True/False)

  5. 在选择项目使用的预训练Transformers模型之前,有必要测试数百个预训练的Transformers模型。(True/False)

  6. 最新的Transformers模型总是最好的。(True/False)

  7. 每个自然语言处理任务最好有一个Transformers模型,而不是一个多任务Transformers模型。(True/False)

  8. 一个Transformers模型总是需要进行微调。(True/False)

  9. OpenAI GPT-3 引擎可以在不进行微调的情况下执行广泛的自然语言处理任务。(True/False)

  10. 在本地服务器上实现 AI 算法总是更好的。(True/False)

参考文献

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作空间,与作者进行每月的问我任何事会话:

www.packt.link/Transformers

第十六章:Transformers驱动副驾驶员的出现

当工业 4.0(I4.0)达到成熟时,一切都将关于机器对机器的连接、通信和决策。人工智能将主要嵌入成熟的按需付费云 AI 解决方案中。大型科技公司将吸收大部分才华横溢的 AI 专家,创建 API、接口和集成工具。

AI 专家将从开发转变为设计,成为架构师、集成者和云 AI 管道管理员。因此,AI 更像是工程顾问的工作,而不是工程开发者的工作。

第一章,Transformers是什么?,介绍了基础模型,Transformers可以完成它们未经训练的自然语言处理任务。第十五章,从自然语言处理到任务无关的Transformers模型,将基础模型Transformers扩展到可以执行视觉任务、自然语言处理任务等的任务无关模型。

本章将把 OpenAI GPT-3 模型扩展到各种副驾驶员任务。新一代 AI 专家和数据科学家将学习如何与 AI 副驾驶员合作,帮助他们自动生成源代码并做出决策。

本章将首先更详细地探讨提示工程。示例任务包括将会议记录转换为摘要。Transformers提高了我们的生产力。但是,我们将看到自然语言对 AI 仍然是一个挑战。

我们将学习如何将 OpenAI Codex 作为副驾驶员。GitHub Copilot 在我们编写程序时使用 Codex 为我们建议源代码。Codex 也可以将自然语言转换为代码。

然后,我们将发现具有特定领域 GPT-3 引擎的新 AI 方法。本章将展示如何生成具有 12288 维度的嵌入并将其插入机器学习算法中。我们还将看到如何要求转换器自动生成说明。

在研究Transformers驱动的推荐系统之前,我们将看到如何过滤偏见的输入和输出。2020 年代的人工智能必须以道德方法构建。

推荐系统渗透到每个社交媒体平台,推荐视频、帖子、消息、书籍和其他我们可能想消费的产品。我们将在这个过程中构建一个基于 ML 的教育多用途Transformers推荐系统。

Transformers模型分析序列。它们起初用于自然语言处理,但已成功扩展到计算机视觉。我们将探索在 JAX 中开发的基于Transformers的计算机视觉程序。

最后,我们将看到 AI 副驾驶员如何促进虚拟系统向元宇宙的过渡,在本十年中将会扩展。当你开发应用程序时,你是飞行员。但是,当你有要开发的代码时,激活的完成只限于方法,而不是代码行。IDE 可能会建议方法列表。副驾驶员可以生成整段代码的完成!

本章涵盖以下主题:

  • 提示工程

  • GitHub Copilot

  • Codex 语言到源代码模型

  • 嵌入数据集

  • 嵌入式驱动的机器学习

  • 指导系列

  • 内容过滤模型

  • 探索基于转换器的推荐系统

  • 将自然语言处理序列学习扩展到行为预测

  • 在 JAX 中实现转换器模型

  • 将转换器模型应用于计算机视觉

让我们从提示工程开始,这是一种必须获得的关键能力。

提示工程

说一种特定的语言不是遗传的。我们大脑中没有一个包含我们父母语言的语言中心。我们的大脑在我们的生活早期工程化我们的神经元,以便说、阅读、写作和理解一种语言。每个人的语言电路都取决于他们的文化背景以及在早年如何与他们交流。

随着我们成长,我们发现我们听到的很多东西都是混乱的:未完整的句子、语法错误、词语误用、发音错误以及许多其他扭曲。

我们使用语言传达信息。我们很快发现我们需要将我们的语言适应我们所面向的人或观众。我们可能需要尝试额外的“输入”或“提示”来得到我们期望的结果(“输出”)。像 GPT-3 这样的基础级转换器模型可以以无限多种方式执行数百种任务。我们必须像学习任何其他语言一样学习转换器提示和响应的语言。与人或接近人类水平的转换器进行有效沟通必须包含最少的信息以最大化结果。我们代表获得结果所需的最小输入信息为minI,以及任何系统的最大输出为maxR。

我们可以将这种沟通链表示为:

minI(input) -> maxR(output)

我们将用“提示”取代“输入”,以便转换器表明我们的输入会影响模型的反应。输出是“响应”。与转换器的对话,d(T),可以表示为:

d(T)=minI(prompt) -> maxR(response)

当minI(prompt) -> 1时,maxR(response)的概率也-> 1。

当minI(prompt) -> 0时,maxR(response)的概率也-> 0。

d(T)的质量取决于我们能够定义minI(prompt)的程度。

如果你的提示倾向于达到1,那么它将产生倾向于1的概率。

如果你的提示趋向于达到0,那么它将产生趋向于0的输出概率。

你的提示是影响概率的内容的一部分!为什么?因为转换器将在其估计中包含提示和响应。

作为孩子或成年人学习一门语言需要很多年的时间。学习Transformers语言和如何有效设计minI(prompt)也需要相当长的时间。我们需要了解它们,它们的架构以及算法计算预测的方式。然后我们需要花相当多的时间来理解如何设计输入,提示,以使Transformers表现出我们期望的行为。

本节重点介绍口头语言。OpenAI GPT-3 的 NLP 任务的提示通常来自会议记录或对话,这些记录往往是非结构化的。将会议记录或对话转换成摘要可能是相当具有挑战性的。本节将专注于总结相同对话的七种情况下的笔记,从随意英语到具有有限上下文的随意或正式英语。

我们将从具有有意义上下文的随意英语开始。

具有有意义上下文的随意英语

随意英语是用较短的句子和有限的词汇说话的。

让我们要求 OpenAI GPT-3 执行“笔记到摘要”的任务。转到 www.openai.com 。登录或注册。然后转到示例页面并选择笔记到摘要。

我们将给 GPT-3 提供所有必要的信息,以总结简和汤姆之间的随意对话。简和汤姆是两位开始工作的开发人员。汤姆提供咖啡给简。简拒绝了这个提议。

在这种情况下,minI(prompt)=1,因为输入信息是正确的,如图 16.1所示:

图 16.1:总结了详细记录的笔记

当我们点击生成时,我们得到了一个令人惊讶的好答案,如图 16.2所示:

图形用户界面、文本、应用程序、电子邮件  自动生成的描述

图 16.2:GPT-3 提供了一个可以接受的摘要

我们能否得出结论,AI 可以在我们混乱的日常对话、会议和漫无目的的闲聊中找到结构?答案并不容易。我们现在将通过添加一个代称来使输入复杂化。

以代称为特征的随意英语

汤姆提到了coffee这个词,让 GPT-3 保持正确的方向。但如果汤姆用java代替coffee呢?咖啡是指饮料,而java是一种来自爪哇岛的成分。代称是当我们使用一个对象的属性时,比如用java代替coffee。Java 也是一种编程语言,其标志是一杯咖啡。

我们面临着java的三种可能定义:指咖啡的成分咖啡(代称),爪哇岛和一种编程语言的名称。GPT-3 现在有一个多义性(同一个词的几个含义)问题需要解决。

人类掌握了多义性。我们学会了单词的不同含义。我们知道一个词没有上下文是没有多大意义的。在这种情况下,简和汤姆是开发人员,使情况复杂化。他们是在谈论咖啡还是语言?

对于人类来说答案很容易,因为汤姆随后谈到了他的妻子,她已经停止喝咖啡了。但是当词语java代替coffee时,GPT-3 可能会因为这种多义性而产生错误的答案:

图形用户界面,文本 自动生成的描述

图 16.3:当提示混淆时 GPT-3 的错误响应

因此我们证实了当minI(prompt) -> 0时,maxR(response) -> 0的概率。

如果我们加入省略号,人类的对话会变得更加难以分析。

具有省略号的非正式英语

情况可能会变得更糟。假设汤姆正在喝一杯咖啡,简看着他和咖啡杯,然后随意地打了个招呼。

汤姆没有问简是否想要咖啡或者 Java,而是说:

"想要一些吗?"

汤姆省略了coffee这个词,这是一个省略号。简仍然可以通过看着他拿着一杯咖啡来理解汤姆的意思。

OpenAI GPT-3 检测到了drinking这个词,并成功地将这个动词与问题想要一些吗?联系起来。我们不需要某种编程语言的想要一些。由 GPT-3 产生的以下摘要仍然是正确的:

文本 自动生成的描述

图 16.4:GPT-3 产生的正确响应

现在,让我们看看当存在人类可以理解但对人工智能仍然是一个挑战的模糊背景时会发生什么。

具有模糊背景的非正式英语

如果我们进一步思考,汤姆并不需要提及他的妻子才能让简理解他在说什么,因为他正在拿着一杯咖啡。

让我们去掉汤姆提到他的妻子和动词drinking。让我们保留想要一些而不是咖啡或 Java:

图 16.5:模糊的输入情境

输出反映了对话的明显混乱:

图 16.6:GPT-3 的不良响应

提示太模糊了,导致了一条不足的回答,我们可以总结为:

d(T) -> 0,因为当*minI(prompt) -> 0时,maxR(response) -> 0的概率

当人类进行交流时,他们会将文化、过去的关系、视觉情境和其他不可见因素带入对话。对于第三方来说,这些不可见因素可能包括:

  • 阅读文字而看不到人们正在做什么(行动、面部表情、身体语言等)。

  • 听人们提到我们不了解的事物(电影、体育、工厂的问题等)。

  • 来自与我们不同文化的文化事件

列举的例子还有很多!

我们可以看到这些不可见因素让人工智能失明。

现在让我们将传感器引入到情境中。

使用传感器的非正式英语

现在我们将视频传感器引入房间进行思想实验。想象一下我们可以使用图像字幕处理视频源,并在对话开始时提供上下文,比如:

人类有时会产生只有彼此了解的对话。考虑一下简和汤姆之间的对话。视频镜头显示汤姆正在喝咖啡,简在键盘上打字。简和汤姆是两个开发者,在开放空间里摸索着努力工作的一天。

然后我们以以下混乱的聊天作为提示:

Tom: "hi" Jane: "yeah sure" Tom: "Want some?" Jane: "Nope" Tom: "Cool. You're trying then." Jane: "Yup" Tom: "Sleep better?" Jane: "Yeah. Sure."

GPT-3 的输出是可以接受的,虽然在开头缺少了重要的语义词:

Summarize: A developer can be seen typing on her keyboard. Another developer enters the room and offers her a cup of coffee. She declines, but he insists. They chat about her sleep and the coffee. 

结果可能会在每一次运行中有所不同。GPT-3 查看了最高的概率并选择了最好的其中之一。GPT-3 完成了这个实验,因为图像标题提供了上下文。

然而,如果汤姆没有拿着一杯咖啡,剥夺了 GPT-3 的视觉背景,那该怎么办?

没有可见的上下文的随意英语

对于 AI 来说最困难的情况是如果汤姆每天都提到一个事件,但今天不是。假设汤姆每天早晨都拿着一杯咖啡进来。他现在进来了,问简是否在拿一杯咖啡之前想要一些。我们的思维实验是想象所有可能的情况。在这种情况下,我们的思维实验中的视频镜头将什么也没有揭示,我们又回到了混乱中。此外,视频镜头无法看到他们是开发者、会计还是顾问。所以,让我们剔除掉这部分上下文,只剩下以下上下文。让我们再进一步。对话包含Tom:和Jane:。所以我们不需要提及上下文。我们得到的是:

Tom: "hi" Jane: "yeah sure" Tom: "Want some?" Jane: "Nope" Tom: "Cool. You're trying then." Jane: "Yup" Tom: "Sleep better?" Jane: "Yeah. Sure."

输出是相当惊人的。简和汤姆使用的随意语言导致 GPT-3 得出荒谬的结论。请记住,GPT-3 是一种随机算法。输入中最微小的变化可能会导致完全不同的输出。GPT-3 试图猜测他们在谈论什么。GPT-3 发现这段对话是关于消费某物。他们的随意语言导致了关于非法物质的荒谬预测,出于道德原因,我不在本节中重现这些。

GPT-3 确定语言水平并将其与相关情境关联起来。

如果我们使用正式英语重现相同的实验会发生什么?

没有上下文的正式英语对话

现在让我们把所有的上下文都剔除掉,但提供正式的英语。正式英语包含更长的句子、良好的语法和礼貌。我们可以使用正式的英语表达不包含上下文的相同对话:

汤姆:“早上好,简” 简:“早上好,汤姆” 汤姆:“你也要来点吗?” 简:“不,谢谢。我很好。” 汤姆:“太棒了。你走在了正确的道路上!” 简:“是的,我是的” 汤姆:“这些日子你睡得更好吗?” 简:“是的,谢谢。”

GPT-3 自然地理解了汤姆所说的“喝”与这种程度的英语和良好的礼貌。输出结果相当令人满意:

总结:汤姆对简说“早上好”。汤姆给了她他喝的东西。简说“不,谢谢。我很好。” 汤姆说“太棒了”并且她走在了正确的道路上。简说:“是的,我是。” 汤姆问她这些日子她睡得更好吗。

我们可以通过引入其他人物和其他对象并生成无数的情况,想象出同一对话的无尽变化。

让我们总结一下这些实验。

提示工程培训

我们的思维常常是混乱的。人类使用许多方法来重构无结构的句子。人类经常需要询问额外的问题才能理解别人在说什么。与 OpenAI GPT-3 这样的经过训练的转换器交互时,您需要接受这一点。

请记住,与转换器的 对话 d(T) 和响应 maxR(response),取决于您的输入的质量 minI(prompt),如本节开始时所定义的:

d(T)=minI(prompt) -> maxR(response)

当minI(prompt)-> 1 时,maxR(response) -> 1 的概率。

当minI(prompt) -> 0 时,maxR(response) -> 0 的概率。

练习提示工程,并以时间来衡量您的进步。提示工程是一项将您带入下一个 AI 水平的新技能。

提示工程能力导致能够掌握协助工具。

协助工具

欢迎来到由 OpenAI 提供并在 Visual Studio 中提供的 AI 驱动的开发协助工具的世界。

GitHub Copilot

让我们从 GitHub Copilot: 开始

github.com/github/copilot-docs

在这一节中,我们将使用 GitHub Copilot 与 PyCharm (JetBrains):

github.com/github/copilot-docs/tree/main/docs/jetbrains

按照文档中的说明在 PyCharm 中安装 JetBrains 并激活 OpenAI GitHub Copilot。

与 GitHub Copilot 合作是一个四步骤的过程(见 图 16.7):

  • OpenAI Codex 是在互联网上公开的代码和文本上进行训练的。

  • 训练模型被插入到 GitHub Copilot 服务中。

  • GitHub 服务管理编辑器中编写的代码(在本例中为 PyCharm)和 OpenAI Codex 之间的双向流动。 GitHub 服务管理器提出建议,然后将交互发送回进行改进。

  • 代码编辑器是我们的开发工作空间。

包含图表的图片 说明自动生成

图 16.7:GitHub Copilot 的四步流程

按照 GitHub Copilot 提供的说明,在 PyCharm 中登录 GitHub。对于任何问题,请阅读 copilot.github.com/#faqs。

一旦在 PyCharm 编辑器中设置好,只需键入:

import matplotlib.pyplot as plt
def draw_scatterplot 

一旦代码被输入,您可以打开 OpenAI GitHub 建议窗格并查看建议:

文本描述自动生成

图 16.8:您键入的代码的建议

一旦选择了您喜欢的副驾驶建议,它将出现在编辑器中。您可以使用 Tab 键确认建议。您可以等待另一个建议,比如绘制散点图:

import matplotlib.pyplot as plt
def draw_scatterplot(x, y):
    plt.scatter(x, y)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.show()
draw_scatterplot([1, 2, 3, 4, 5], [1, 4, 9, 16, 25]) 

绘图将被显示:

图表,散点图 说明自动生成

图 16.9:GitHub Copilot 散点图

您可以在本书的 GitHub 存储库的 Chapter16 文件夹中找到的 GitHub_Copilot.py 上运行结果。

该技术是无缝的、不可见的,并将逐渐扩展到所有开发领域。该系统装载了 GPT-3 功能以及其他流水线。该技术适用于 Python、JavaScript 等。

它需要通过提示工程进行培训,以适应由 OpenAI Codex 驱动的 GitHub Copilot 的工作方式。

让我们直接进入 OpenAI Codex,这可能是使用副驾驶进行训练的好地方。

Codex

OpenAI Codex 不仅提供源代码建议。Codex 还可以将自然语言转换为源代码。

转到 OpenAI 网站并点击链接到 Codex 界面:

beta.openai.com/codex-javascript-sandbox

提供说明,结果将显示在 Codex 窗口和界面右侧的源代码中。

本节中的示例包含使用提示窗格的几个序列:

图 16.10:Codex 的 JavaScript 沙盒

我们在 提供说明... 窗格中输入自然语言,生成将运行的 JavaScript。

例如,我用自然语言输入了两条说明:

绘制 50 个各种颜色的小乒乓球

使球变圆

Codex 源自 GPT-3。在某些情况下,该引擎被称为“davinci-codex”。这意味着 Codex 继承了 GPT-3 引擎的属性。为了理解这一点,让我们看看其中的一个参数:top_p。引擎对引擎的输出进行采样。例如,如果 top_p 设置为 0.1,它将仅考虑采样中的前 10%。它将检索该前 10% 概率质量中的标记。由于整个计算是随机的,可能需要一些前选项和另一组前选项来运行。请耐心等待,花时间设计提示。

您的 AI 引擎学习路径:

  1. 学习了解 Codex 引擎的行为。

  2. 接受随机算法的自由创造性本质。

  3. 习惯于用更好的提示来驾驭它们。然后,随着引擎的改进,您将能够随着 Codex 的成长而成长。

脚本将出现在 JavaScript 窗格中,带有注释的说明和代码:

/* draw 50 small ping pong balls of all sorts of colors */
var balls = [];
for (var i = 0; i < 50; i++) {
  var ball = document.createElement('div');
  ball.style.width = '10px';
  ball.style.height = '10px';
  ball.style.backgroundColor = 'hsl(' + Math.random() * 360 + ', 100%, 50%)';
  ball.style.position = 'absolute';
  ball.style.left = Math.random() * window.innerWidth + 'px';
  ball.style.top = Math.random() * window.innerHeight + 'px';
  document.body.appendChild(ball);
  balls.push(ball);
}
/* Make the balls round */
for (var i = 0; i < balls.length; i++) {
  balls[i].style.borderRadius = '50%';
} 

结果显示如下:

图表,散点图  自动生成的描述

图 16.11:创建五十个多彩的球

现在让我们要求程序移动球:

`Make all of the balls move inside the window` 

代码已生成:

/* make all of the balls move inside the window. */
var moveBalls = function() {
  for (var i = 0; i < balls.length; i++) {
    var ball = balls[i];
    ball.style.left = (parseInt(ball.style.left) + Math.random() * 10 - 5) + 'px';
    ball.style.top = (parseInt(ball.style.top) + Math.random() * 10 - 5) + 'px';
  }
  window.requestAnimationFrame(moveBalls);
};
moveBalls(); 

一旦球移动,通过单击 导出到 JSFiddle 按钮将代码导出到 HTML:

包含标志的图片  自动生成的描述

图 16.12:导出到 JSFiddle 按钮

JSFiddle 创建了一个 HTML 页面:

文本  自动生成的描述

图 16.13:JSFiddle 创建 HTML 页面

在这种情况下,代码已保存到 codex.html,它位于本章文件夹中的 GitHub 存储库中。您可以打开并观看使用自然编程语言创建 HTML 页面的创新结果。

领域特定的 GPT-3 引擎

本节探讨可以执行领域特定任务的 GPT-3 引擎。我们将在本节的三个子部分中运行三个模型:

  • Embedding2ML 使用 GPT-3 为 ML 算法提供嵌入

  • 指示系列要求 GPT-3 为任何任务提供说明

  • 内容过滤器,用于过滤偏见或任何形式的不可接受的输入和输出

打开 Domain_Specific_GPT_3_Functionality.ipynb。

我们将从 embedding2ML(将嵌入作为 ML 输入)开始。

Embedding2ML

OpenAI 已经训练了几个具有不同维度和不同功能的嵌入模型:

  • 艾达(1,024 维度)

  • 巴贝奇(2,048 维度)

  • 居里(4,096 维度)

  • 达芬奇(12,288 维度)

对于每个引擎的更多解释,您可以在 OpenAI 的网站上找到更多信息:

beta.openai.com/docs/guides/embeddings.

达芬奇模型提供具有 12,288 维度的嵌入。在本节中,我们将利用达芬奇的力量生成供应链数据集的嵌入。但是,我们不会将嵌入发送到Transformers的嵌入子层!

我们将嵌入发送到 scikit-learn 库中的聚类机器学习程序中的六个步骤:

  • 步骤 1:安装和导入 OpenAI,并输入 API 密钥

  • 步骤 2:加载数据集

  • 步骤 3:合并列

  • 步骤 4:运行 GPT-3 嵌入

  • 步骤 5:使用嵌入进行聚类(k-means)

  • 步骤 6:可视化聚类(t-SNE)

过程总结在 图 16.14 中:

形状,多边形  自动生成的描述

图 16.14:将嵌入发送到聚类算法的六个步骤流程

打开 Google Colab 文件,Domain_Specific_GPT_3_Functionality.ipynb,并转到笔记本的 Embedding2ML with GPT-3 engine 部分。

本节中描述的步骤与笔记本单元格相匹配。让我们总结一下流程的每个步骤。

步骤 1: 安装和导入 OpenAI

让我们从以下子步骤开始:

  1. 运行单元格

  2. 重新启动运行时

  3. 再次运行单元格以确保,因为你重新启动了运行时:

    try:
      import openai
    except:
      !pip install openai
      import openai 
    
  4. 输入 API 密钥:

    openai.api_key="[YOUR_KEY]" 
    

我们现在加载数据集。

步骤 2: 加载数据集

在运行该单元之前加载文件。我上传了tracking.csv(在本书的 GitHub 存储库中可用),其中包含 SCM 数据:

import pandas as pd
df = pd.read_csv('tracking.csv', index_col=0) 

数据包含七个字段:

  • ID

  • 时间

  • 产品

  • 用户

  • 得分

  • 摘要

  • 文本

让我们使用以下命令打印前几行:

print(df) 
 Time Product  User  Score        Summary   Text     
Id                                                                    
1     01/01/2016 06:30   WH001  C001      4        on time   AGV1     
2     01/01/2016 06:30   WH001  C001      8           late     R1  NaN
3     01/01/2016 06:30   WH001  C001      2          early    R15  NaN
4     01/01/2016 06:30   WH001  C001     10  not delivered    R20  NaN
5     01/01/2016 06:30   WH001  C001      1        on time     R3  NaN
...                ...     ...   ...    ...            ...    ...  ...
1049  01/01/2016 06:30   WH003  C002      9        on time   AGV5  NaN
1050  01/01/2016 06:30   WH003  C002      2           late  AGV10  NaN
1051  01/01/2016 06:30   WH003  C002      1          early   AGV5  NaN
1052  01/01/2016 06:30   WH003  C002      6  not delivered   AGV2  NaN
1053  01/01/2016 06:30   WH003  C002      3        on time   AGV2  NaN
[1053 rows x 7 columns] 

我们可以组合列来构建我们想要的聚类。

步骤 3: 合并列

我们可以将产品列与摘要组合以获得产品及其交付状态的视图。请记住,这只是一个实验性的练习。在实际项目中,仔细分析并决定你想要组合的列。

下面的示例代码可以用你选择的任何选项来替换,以进行你的实验:

df['combined'] = df.Summary.str.strip()+ "-" + df.Product.str.strip()
print(df) 

我们现在可以看到一个名为combined的新列:

 Time Product  User  ... Text           combined
Id                                    ...                                 
1     01/01/2016 06:30 WH001  C001  ... AGV1             on time-WH001
2     01/01/2016 06:30 WH001  C001  ... R1  NaN           late-WH001
3     01/01/2016 06:30 WH001  C001  ... R15  NaN          early-WH001
4     01/01/2016 06:30 WH001  C001  ... R20  NaN  not delivered-WH001
5     01/01/2016 06:30 WH001  C001  ... R3  NaN        on time-WH001
...                ...     ...   ...  ...    ...  ...                  ...
1049  01/01/2016 06:30 WH003  C002  ... AGV5  NaN        on time-WH003
1050  01/01/2016 06:30 WH003  C002  ... AGV10  NaN         late-WH003
1051  01/01/2016 06:30 WH003  C002  ... AGV5  NaN          early-WH003
1052  01/01/2016 06:30 WH003  C002  ... AGV2  NaN  not delivered-WH003
1053  01/01/2016 06:30 WH003  C002  ... AGV2  NaN        on time-WH003
[1053 rows x 8 columns] 

我们现在将在combined列上运行嵌入模型。

步骤 4: 运行 GPT-3 嵌入

我们现在将运行davinci-similarity模型,为combined列获取 12,288 维度:

import time
import datetime
# start time
start = time.time()
def get_embedding(text, engine="davinci-similarity"):
   text = text.replace("\n", " ")
   return openai.Engine(id=engine).embeddings(input = [text])['data'][0]['embedding']
df['davinci_similarity'] = df.combined.apply(lambda x: get_embedding(x, engine='davinci-similarity'))
# end time
end = time.time()
etime=end-start
conversion = datetime.timedelta(seconds=etime)
print(conversion)
print(df) 

结果令人印象深刻。我们为 combined 列有 12,288 维度:

0:04:44.188250
                  Time  ...                                 davinci_similarity
Id                      ...                                                   
1     01/01/2016 06:30  ...  [-0.0047378824, 0.011997132, -0.017249448, -0....
2     01/01/2016 06:30  ...  [-0.009643857, 0.0031537763, -0.012862709, -0....
3     01/01/2016 06:30  ...  [-0.0077407444, 0.0035147679, -0.014401976, -0...
4     01/01/2016 06:30  ...  [-0.007547746, 0.013380095, -0.018411927, -0.0...
5     01/01/2016 06:30  ...  [-0.0047378824, 0.011997132, -0.017249448, -0....
...                ...  ...                                                ...
1049  01/01/2016 06:30  ...  [-0.0027823148, 0.013289047, -0.014368941, -0....
1050  01/01/2016 06:30  ...  [-0.0071367626, 0.0046446105, -0.010336877, 0....
1051  01/01/2016 06:30  ...  [-0.0050991694, 0.006131069, -0.0138306245, -0...
1052  01/01/2016 06:30  ...  [-0.0066779135, 0.014575769, -0.017257102, -0....
1053  01/01/2016 06:30  ...  [-0.0027823148, 0.013289047, -0.014368941, -0....
[1053 rows x 9 columns] 

现在我们需要将结果转换为numpy矩阵:

#creating a matrix
import numpy as np
matrix = np.vstack(df.davinci_similarity.values)
matrix.shape 

矩阵的形状为 1,053 行 x 12,288 列,这相当令人印象深刻:

(1053, 12288) 

矩阵现已准备好发送到 scikit-learn 机器学习聚类算法。

步骤 5: 使用嵌入进行聚类(k-means 聚类)

我们通常将传统数据集发送到 k-means 聚类算法。我们将一个 12,288 维度的数据集发送到 ML 算法,而不是发送到 transformer 的下一个子层。

我们首先从 scikit-learn 导入 k-means:

from sklearn.cluster import KMeans 

我们现在运行一个传统的 k-means 聚类算法,使用我们的 12,288 维度数据集:

n_clusters = 4
kmeans = KMeans(n_clusters = n_clusters,init='k-means++',random_state=42)
kmeans.fit(matrix)
labels = kmeans.labels_
df['Cluster'] = labels
df.groupby('Cluster').Score.mean().sort_values() 

输出如请求的四个聚类:

Cluster
2    5.297794
0    5.323529
1    5.361345
3    5.741697 

我们可以打印数据集内容的标签:

print(labels) 

输出是:

[2 3 0 ... 0 1 2] 

现在让我们使用 t-SNE 可视化聚类。

步骤 6: 可视化聚类(t-SNE)

t-SNE 保留局部相似性。PCA 最大化大的成对距离。在这种情况下,小的成对距离。

笔记本将使用matplotlib来显示 t-SNE:

from sklearn.manifold import TSNE
import matplotlib
import matplotlib.pyplot as plt 

在可视化之前我们需要运行 t-SNE 算法:

#t-SNE
tsne = TSNE(n_components=2, perplexity=15, random_state=42, init='random', learning_rate=200)
vis_dims2 = tsne.fit_transform(matrix) 

现在我们可以在matplotlib中显示结果:

x = [x for x,y in vis_dims2]
y = [y for x,y in vis_dims2]
for category, color in enumerate(['purple', 'green', 'red', 'blue']):
    xs = np.array(x)[df.Cluster==category]
    ys = np.array(y)[df.Cluster==category]
    plt.scatter(xs, ys, color=color, alpha=0.3)
    avg_x = xs.mean()
    avg_y = ys.mean()

    plt.scatter(avg_x, avg_y, marker='x', color=color, s=100)
plt.title("Clusters of embeddings-t-SNE") 

该图显示了聚类周围堆积了许多数据点。还有许多数据点环绕着附加到最近质心的聚类:

图表,散点图 说明自动生成

图 16.15: 嵌入-t-SNE 的聚类

我们运行了一个大型的 GPT-3 模型,嵌入了 12,288 维度。然后我们将结果送入聚类算法。将 Transformer 和机器学习相结合的潜力是无限的!

如果您希望查看数据框,请转到笔记本的Peeking into the embeddings部分。

现在让我们看一下指示系列。

指示系列

个人助手、元宇宙中的头像、网站等在用户请求帮助时需要提供清晰的指示。转到Domain_Specific_GPT_3_Functionality.ipynb的instruct series部分。

在这一部分,我们将要求一个 Transformer 解释如何在 Microsoft Edge 中设置家长控制,使用以下提示:解释如何在 Edge 中设置家长控制。

我们首先运行完成单元:

import os
import openai
os.environ['OPENAI_API_KEY'] ='[YOUR_API_KEY]'
print(os.getenv('OPENAI_API_KEY'))
openai.api_key = os.getenv("OPENAI_API_KEY")
response = openai.Completion.create(
  engine="davinci-instruct-beta",
  prompt="Explain how to set up parent control in Edge.\n\n\nACTIONS:",
  temperature=0,
  max_tokens=120,
  top_p=1,
  frequency_penalty=0,
  presence_penalty=0
)
r = (response["choices"][0])
print(r["text"]) 

响应是根据请求的指示列表:

1\. Start Internet Explorer.
2\. Click on the tools menu.
3\. Click on the Internet options.
4\. Click on the advanced tab.
5\. Click to clear or select the enable personalized favorite menu check box. 

您可以要求的指示数量是无限的!发挥您的创造力和想象力找到更多例子!

有时输入或输出是不可接受的。让我们看看如何实施内容过滤器。

内容过滤器

偏见、不可接受的语言和任何形式的不道德输入都应该从您的 AI 应用程序中排除。

OpenAI 训练的模型之一是内容过滤器。我们将在本节中运行一个示例。转到Domain_Specific_GPT_3_Functionality.ipynb的内容过滤器部分。

我的建议是过滤输入和输出,如图 16.16所示:

图描述自动生成

图 16.16:实现内容过滤器

我的建议是实施一个三步过程:

  1. 对所有输入数据应用内容过滤器

  2. 让 AI 算法根据训练运行

  3. 对所有输出数据应用内容过滤器

在本节中,输入和输出数据将被命名为content。

以以下输入为例:

content = "Small and fat children should not play basketball at school." 

这个输入是不可接受的!学校不是 NBA。篮球应该保持每个人的一个良好的锻炼。

现在让我们在单元content-filter-alpha中运行内容过滤器:

response = openai.Completion.create(
      en      prompt = "<|endoftext|>"+content+"\n--\nLabel:",
      temperature=0,
      max_tokens=1,
      top_p=1,
      frequency gine="content-filter-alpha",
_penalty=0,
      presence_penalty=0,
      logprobs=10
    ) 

内容过滤器将结果存储在response中,一个字典对象。我们检索选择的值以获取可接受性的级别:

r = (response["choices"][0])
print("Content filter level:", r["text"]) 

内容过滤器返回三个值之一:

  • 0 – 安全

  • 1 – 敏感

  • 2 – 不安全

在这种情况下,结果当然是 2:

Content filter level: 2 

内容过滤器可能不够。我建议添加其他算法来控制和过滤输入/输出内容:规则库、字典和其他方法。

现在我们已经探索了特定领域的模型,让我们构建一个基于 Transformer 的推荐系统。

基于 Transformer 的推荐系统

Transformer 模型学习序列。学习语言序列是一个很好的开始,考虑到每天在社交媒体和云平台上发布的数十亿条消息。消费者行为、图像和声音也可以用序列表示。

在本节中,我们将首先创建一个通用序列图,然后在 Google Colaboratory 中构建一个基于 Transformer 的通用推荐系统。然后,我们将看到如何在元人中部署它们。

让我们首先定义通用序列。

通用序列

许多活动可以用实体和它们之间的链接表示。因此,它们被组织成序列。例如,YouTube 上的一个视频可以是实体 A,链接可以是一个人从视频 A 转到视频 E 的行为。

另一个例子是发烧是一个实体 F,链接是医生可能做出的导致微判断 B 的推理。消费者在亚马逊购买产品 D 可以生成到建议 C 或另一个产品的链接。例子是无穷无尽的!

我们可以用六个字母定义本节中的实体:

E={A,B,C,D,E,F}

当我们说一种语言时,我们遵循语法规则,无法摆脱它们。

例如,假设 A =”我”, E =”吃”, 和 D =”糖”。表达我吃糖的事实只有一种正确的序列:“我吃糖。”

如果有人说“吃糖我”,听起来会有点奇怪。

在这个序列中,表示这些规则的链接是:

A->E (我吃)

E->D(吃糖)

我们可以通过观察行为、学习数据集与 ML,或者手动听取专家的意见来自动推断任何领域的规则。

在本节中,我们假设我们已经观察了一个 YouTube 用户几个月,他花了几个小时观看视频。我们注意到用户始终从一种类型的视频转移到另一种类型的视频。例如,从歌手 B 的视频到歌手 D 的视频。这个人 P 的行为规则 X 似乎是:

X(P)={AE,BD,BF,C,CD,DB,DC,DE,EA,ED,FB}

我们可以将实体系统表示为图中的顶点,将链接表示为边。例如,如果我们将 X(P) 应用到顶点,我们得到以下无向图:

包含文本、时钟的图片  自动生成描述

图 16.17:YouTube 用户视频组合的图

假设顶点是观众喜欢的歌手的视频,C 是观众偏爱的歌手。我们可以给予观众过去几周内进行的统计转换(链接或边)一个值为 1 的值。我们还可以给观众最喜欢的歌手的视频一个值为 100 的值。

对于这个观众,路径由(边,顶点)值 V(R(P)): 表示

V(X(P))={AE=1,BD=1,BF=1,C=100,CD=1,DB=1,DE=1,EA=1,ED=1,FB=1}

推荐系统的目标是建议导致歌手 C 的视频的序列,或在某些情况下直接建议 C。

我们可以用奖励矩阵 R 来表示无向图:

 A,B,C,D,E,F     
R = ql.matrix([ [0,0,0,0,1,0],   A 
                [0,0,0,1,0,1],   B 
                [0,0,100,1,0,0], C 
                [0,1,1,0,1,0],   D 
                [1,0,0,1,0,0],   E 
                [0,1,0,0,0,0]])  F 

让我们使用这个奖励矩阵模拟观众 X 在几个月内的活动。

使用 MDP 进行数据集管道模拟的 RL

在本节中,我们将模拟人物P观看 YouTube 上歌曲视频的行为X,我们将其定义为X(P)。我们将确定P的行为值为V(X(P))。然后,我们将这些值组织到奖励矩阵R中,用于我们现在将在 Bellman 方程中实现的马尔可夫决策过程(MDP)。

打开KantaiBERT_Recommender.ipynb,它位于本书 GitHub 存储库的本章文件夹中。该笔记本是KantaiBERT.ipynb的修改版本,描述在第四章,从头开始预训练 RoBERTa 模型中。

在第四章中,我们使用kant.txt训练了一个变换器,其中包含 Immanuel Kant 的一些作品。在本节中,我们将通过强化学习(RL)生成一个人行为的数千个序列。RL 不在本书的范围之内,但本节包含一些提醒。

第一步是训练一个变换器模型,以学习和模拟一个人的行为。

使用 MDP 训练客户行为

KantaiBERT.ipynb 在第四章中通过加载kant.txt来开始训练具有 DistilBERT 架构的 RoBERTa。kant.txt 包含了 Immanuel Kant 的作品。在本节中,我们将使用在本章通用序列部分中定义的奖励矩阵R生成序列:

R = ql.matrix([ [0,0,0,0,1,0],    
                [0,0,0,1,0,1],    
                [0,0,100,1,0,0],  
                [0,1,1,0,1,0],    
                [1,0,0,1,0,0],    
                [0,1,0,0,0,0]]) 

程序的第一个单元格是:

Step 1A Training: Dataset Pipeline Simulation with RL using an MDP:

此单元格使用 Bellman 方程实现 MDP:

 `# The Bellman MDP based Q function`
 `Q[current_state, action] = R[current_state, action] + gamma * MaxValue` 

在这个方程中:

  • R 是原始奖励矩阵。

  • Q 是更新后的矩阵,与R的大小相同。但是,它通过强化学习进行更新,以计算每个实体(顶点)之间链接(边)的相对值。

  • gamma 是一个学习率,设置为 0.8,以避免过度拟合训练过程。

  • MaxValue 是下一个顶点的最大值。例如,如果 YouTube 视频的观看者P正在观看歌手A,程序可能会增加E的值,以便此建议可以作为推荐出现。

逐渐地,程序将尝试找到最佳值,以帮助观众找到最佳的观看视频。一旦强化程序学习了最佳的链接(边),它就可以推荐最佳的观看序列。

原始奖励矩阵已经被训练成为操作矩阵。如果我们添加原始实体,则训练值明显出现:

 `A       B       C       D       E       F`
`[[  0\.      0\.      0\.      0\.    258.44    0\.   ]  A`
 `[  0\.      0\.      0\.    321.8     0\.    207.752]  B`
 `[  0\.      0\.    500\.    321.8     0\.      0\.   ]  C`
 `[  0\.    258.44  401\.      0\.    258.44    0\.   ]  D`
 `[207.752   0\.      0\.    321.8     0\.      0\.   ]  E`
 `[  0\.    258.44    0\.      0\.      0\.      0\.   ]] F` 

人物P的行为值V的原始序列是:

V(X(P))={AE=1,BD=1,BF=1,C=100, CD=1,DB=1,DE=1,EA=1,ED=1,FB=1}

它们已经被训练成:

V(X(P))={AE=259.44, BD=321.8 ,BF=207.752, C=500, CD=321.8 ,DB=258.44, DE=258.44, EA=207.752, ED=321.8, FB=258.44}

这是相当大的变化!

现在,可以推荐一系列P最喜欢的歌手的激动人心的视频。假设P观看了歌手E的视频。训练矩阵的第E行将推荐该行中最高值的视频,即D=321.8。因此,歌手D的视频将出现在P的 YouTube 视频源中。

本节的目标不是停留在这个阶段。相反,本节使用 MDP 创建有意义的序列,以创建转换器用于训练的数据集。

YouTube 不需要生成序列来创建数据集。YouTube 将所有观众的所有行为存储在大数据中。然后,谷歌强大的算法接管,推荐在观众的视频源中播放最佳视频。

其他平台使用余弦相似度来进行预测,如第九章,匹配标记化器和数据集中实现的那样。

MDP 可以为 YouTube 观众,亚马逊购买者,谷歌搜索结果,医生的诊断路径,供应链以及任何类型的序列进行训练。转换器正在将序列学习、训练和预测带到另一个水平。

让我们实现一个模拟,为转换器模型创建行为序列。

使用 MDP 模拟消费者行为

一旦程序的 RL 部分在第 1 个单元格,第 2 个单元格训练完成后,Step 1B Applying: Dataset Pipeline Simulation with MDP将模拟 YouTube 观众在几个月内的行为。它还将包括类似的观众档案,使总共模拟了 10,000 个视频观看序列。

第 2 个单元格开始创建kant.txt文件,该文件将用于训练 KantaiBERT 转换器模型:

""" Simulating a decision-making process"""
f = open("kant.txt", "w") 

然后引入实体(顶点):

conceptcode=["A","B","C","D","E","F"]
Now the number of sequences is set to 10,000:
maxv=10000 

该函数选择一个名为origin的随机起始顶点:

origin=ql.random.randint(0,6) 

该程序使用训练好的矩阵从原点选择任何域的最佳序列。在本例中,我们假设它们是一个人喜欢的歌手,如以下示例:

`FBDC EDC EDC DC BDC AEDC AEDC BDC BDC AEDC BDC AEDC EDC BDC AEDC DC AEDC DC…/…` 

一旦计算出 10,000 个序列,kant.txt将包含转换器的数据集。

使用kant.txt,程序的剩余部分与第四章中描述的KantaiBERT.ipynb中相同。

转换器现在已准备好进行推荐。

提出建议

在第四章中,KantaiBERT.ipynb包含以下掩码序列:

fill_mask("Human thinking involves human<mask>.") 

此序列是特定的,并与伊曼纽尔·康德的作品相关。此笔记本具有可用于任何领域的通用数据集。

在这个笔记本中,输入为:

fill_mask("BDC<mask>.") 

输出包含重复项。需要一个清理函数来过滤它们,以获得两个非重复序列:

[{'score': 0.00036507684853859246,
  'sequence': 'BDC FBDC.',
  'token': 265,
  'token_str': ' FBDC'},
 {'score': 0.00023987806343939155,
  'sequence': 'BDC DC.',
  'token': 271,
  'token_str': ' DC'}] 

序列是有意义的。有时观众会观看相同的视频,有时不会。行为可能是混乱的。这就是机器学习和人工智能如何应用于超人类的地方。

超人类推荐系统

一旦序列生成,它们将被转换回自然语言用于用户界面。这里的超人指的是一个接受大量特征的推荐系统,比如:

  • 超过人类的推理能力,具有如此多的参数

  • 比人类能做出更准确的预测

这些实用的超人在这个语境下还不是数字化的人类,而是强大的计算工具。我们将在元宇宙中人类和 AI 联合驾驶员部分详细介绍数字意义上的超人。

例如,BDC 序列可能是歌手B的歌曲,然后是歌手D的歌曲,然后是P喜欢的歌手C的歌曲。

一旦序列转换为自然语言,就会出现几种可能的选项:

  • 该序列可以发送给一个机器人或者数字化人类。

    当一项新兴技术出现时,赶紧跳上这列列车,并一同享受吧!你将会了解这项技术,并与之一同发展。你可以搜索其他超人平台。无论如何,通过学习如何规避限制并找到使用新技术的方式,你都可以保持在前沿。

  • 你可以在等待 API 时使用超人做一个教育视频。

  • 一个超人可以作为语音信息被插入到界面中。例如,在车上使用谷歌地图时,你听到的是声音。它听起来像是一个人类。有时我们甚至会误以为它是一个人,但其实不是。它是一个机器。

  • 它也可以是亚马逊中的看不见的内嵌建议。它会提供建议,引导我们做微观决策。它会像销售员一样影响我们。它是一个看不见的超人。

在这种情况下,通用序列由 MDP 创建,并由 RoBERTa transformer 进行训练。这表明 transformers 可以应用于任何类型的序列。

让我们看看 transformers 如何应用于计算机视觉。

计算机视觉

这本书是关于自然语言处理,而不是计算机视觉。然而,在前一节中,我们实现了一个可以应用于许多领域的通用序列。计算机视觉就是其中之一。

Dosovitskiy等人(2021)的文章标题就把一切都说清楚了: 一张图片价值 16x16 个词:大规模图像识别的 Transformer。作者将一张图片处理为序列。结果证明了他们的观点。

谷歌已经在 Colaboratory 笔记本中提供了视觉 transformers。在本书的 GitHub 代码库的Chapter16目录中打开Vision_Transformer_MLP_Mixer.ipynb。

打开Vision_Transformer_MLP_Mixer.ipynb包含了一个在JAX()中的 transformer 计算机视觉模型。JAX 结合了 Autograd 和 XLA。JAX 可以区分 Python 和 NumPy 函数。JAX 通过使用编译技术和并行化来加速 Python 和 NumPy。

笔记本是自说明的。您可以探索它以了解它的工作原理。然而,请记住,当工业 4.0 成熟并进入工业 5.0 时,最佳实现将通过在云 AI 平台上集成您的数据来实现。本地开发将减少,公司将转向云 AI,而不必承担本地开发、维护和支持的成本。

笔记本的目录包含我们在本书中已经多次经历的Transformers过程。然而,这一次,它仅应用于数字图像信息的序列:

图形用户界面,应用程序 描述自动生成

图 16.18: 我们的视觉Transformers笔记本

笔记本遵循标准的深度学习方法。它显示了一些带有标签的图片:

# Show some images with their labels.
images, labels = batch['image'][0][:9], batch['label'][0][:9]
titles = map(make_label_getter(dataset), labels.argmax(axis=1))
show_img_grid(images, titles) 

图形用户界面 描述自动生成,置信度中等

图 16.19: 带有标签的图像

本章中的图像来自从小图像中学习多层特征,Alex Krizhevsky,2009: https://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf 。它们是CIFAR-10和CIFAR-100数据集的一部分(toronto.edu): https://www.cs.toronto.edu/~kriz/cifar.html 。

笔记本包含标准的Transformers过程,然后显示训练图片:

# Same as above, but with train images.
# Note how images are cropped/scaled differently.
# Check out input_pipeline.get_data() in the editor at your right to see how the
# images are preprocessed differently.
batch = next(iter(ds_train.as_numpy_iterator()))
images, labels = batch['image'][0][:9], batch['label'][0][:9]
titles = map(make_label_getter(dataset), labels.argmax(axis=1))
show_img_grid(images, titles) 

包含屏幕截图的图片 描述自动生成

图 16.20: 训练数据

Transformers程序可以对随机图片进行分类。将最初设计用于自然语言处理的Transformers模型用于通用序列推荐器,然后用于计算机视觉,似乎是一种奇迹。然而,我们只是开始探索序列训练的泛化。

模型的简单性令人惊讶!视觉Transformers依赖于Transformers的架构。它不包含卷积神经网络的复杂性。然而,它产生了可比较的结果。

现在,机器人和机器人可以配备Transformers模型,以理解语言并解释图像以了解周围的世界。

视觉Transformers可以在超人类和元宇宙中实现。

元宇宙中的人类和人工智能联合驾驶员

人类和超人工智能正在融入元宇宙。探索元宇宙超出了本书的范围。本书提供的工具箱展示了通往由人类和超人工智能构成的元宇宙的路径。

头像、计算机视觉和视频游戏体验将使我们与他人的交流沉浸式。我们将从看手机转变为与他人在同一地点。

从看到到变成

从看到变成是自然的过程。我们发明了计算机,加上了屏幕,然后发明了智能手机,现在使用应用程序进行视频会议。

现在我们可以进入虚拟现实进行各种类型的会议和活动。

例如,我们将在智能手机上使用 Facebook 的元宇宙,感觉就像在与见面的人(个人和专业人士)身处相同的地点。感受到的存在无疑将是智能手机通信的一次重大进化。

感受到的存在在某个地方与在手机上看着小屏幕很不一样。

元宇宙将使不可能变为可能:太空漫步,在巨浪上冲浪,在森林散步,拜访恐龙,以及我们想象的其他任何地方。

是的,人工智能有局限性、危险、威胁,以及与人类技术相关的一切。然而,正如我们在内容过滤中所看到的那样,我们可以使用 AI 来控制 AI。

本书中的Transformers工具结合新兴的元宇宙技术将让我们真正到达另一个世界。

充分利用你在本书中学到的知识和技能,在元宇宙或现实世界中创造你的道德未来。

总结

本章描述了 AI 副驾驶机器人的崛起,具有人类决策水平的能力。工业 4.0 已经打开了机器互联的大门。机器之间的微决策将加快交易速度。AI 副驾驶机器人将提高我们在各个领域的生产力。

我们看到如何使用 OpenAI Codex 在编码时生成源代码,甚至可以使用自然语言指令。

我们利用 MDP 程序生成的数据集来训练一个 RoBERTa Transformers模型,构建了基于Transformers的推荐系统。数据集结构是一个多用途序列模型。因此,元人类可以获得多领域的推荐功能。

接着,本章展示了视觉Transformers如何将图像分类为信息序列进行处理。

最后,我们看到元宇宙将通过元人类界面使推荐变得可见,或者在社交媒体中深度嵌入功能中变得不可见,例如。

Transformers已经涌现出创新的副驾驶机器人和模型,进入一个极其复杂的新时代。这个旅程将是具有挑战性和令人兴奋的!

问题

  1. 不存在可以自动生成代码的 AI 副驾驶机器人。(True/False)

  2. AI 副驾驶机器人永远不会取代人类。(True/False)

  3. GPT-3 引擎只能做一项任务。(True/False)

  4. Transformers可以被训练成推荐者。(True/False)

  5. Transformers只能处理语言。(True/False)

  6. 一个Transformers序列只能包含单词。(True/False)

  7. 视觉Transformers无法与 CNN 相提并论。(True/False)

  8. 具有计算机视觉的 AI 机器人不存在。(True/False)

  9. 自动产生 Python 源代码是不可能的。(True/False)

  10. 也许有一天我们会成为机器人的副驾驶员。(True/False)

参考文献

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作空间,与作者一起参加每月的 Ask me Anything 会话:

https://www.packt.link/Transformers

附录 I:Transformers模型术语

过去几十年产生了卷积神经网络(CNNs)、循环神经网络(RNNs)和更多类型的人工神经网络(ANNs)。它们都有一定数量的共同词汇。

当应用于Transformers时,Transformers模型引入了一些新词汇,并略微不同地使用现有词汇。本附录简要描述了Transformers模型,以澄清深度学习词汇在应用于Transformers时的使用情况。

Transformers模型架构的动机取决于深度学习的工业化方法。Transformers的几何特性增强了并行处理。此外,Transformers的架构完全符合硬件优化要求。例如,谷歌利用Transformers的堆栈结构设计了领域特定的优化硬件,需要较少的浮点数精度。

设计Transformers模型意味着考虑硬件。因此,Transformers的架构从一开始就结合了软件和硬件优化。

本附录定义了一些神经网络语言的新用法。

堆栈

一个堆栈包含大小相同的层,与经典的深度学习模型不同,如图 I.1所示。一个堆栈从底部到顶部运行。堆栈可以是编码器或者解码器。

图 I.1:层形成一个堆栈

Transformers堆栈随着升高而学习并看到更多。每一层将其学到的内容传递给下一层,就像我们的记忆一样。

想象一下,堆栈就像纽约市的帝国大厦。在底部,你看不到太多。但是当你升上更高层的办公室并透过窗户望出去时,你将看到更多,更远的景色。最后,在顶部,你将拥有一个美妙的曼哈顿景色!

子层

每个层包含子层,如图 I.2所示。不同层的每个子层具有相同的结构,这有助于硬件优化。

原始Transformers包含从底部到顶部运行的两个子层:

  • 自注意力子层,专为自然语言处理和硬件优化而设计

  • 一种经过一些调整的经典前馈网络

图 I.2:一个层包含两个子层

注意头部

自注意力子层被分为 n 个独立和相同的层,称为头部。例如,原始Transformers包含八个头部。

图 I.3将头部表示为处理器,以显示Transformers的工业化结构适合硬件设计:

包含文字的图片,自动生成描述

图 I.3:自注意力子层包含头部

注意,图 I.3中的注意头部被表示为微处理器,以突出Transformers架构的并行处理能力。

transformer 结构适用于自然语言处理和硬件优化需求。

加入我们书的 Discord 空间

加入该书的 Discord 工作区,与作者一起参加每月的问我任何事活动:

www.packt.link/Transformers

附录 II:对Transformers模型的硬件约束

Transformer 模型无法没有优化的硬件存在。内存和硬盘管理设计仍然是关键组成部分。然而,计算能力仍然是先决条件。要训练第二章中描述的原始 Transformer 几乎是不可能的,开始使用 Transformer 模型架构,没有 GPU。GPU 处于高效Transformers模型的战斗的中心。

这个附录将引导您在三个步骤中了解 GPU 的重要性:

  • Transformers的架构和规模

  • CPU 与 GPU

  • 在 PyTorch 中实现 GPU,作为任何其他优化语言优化的示例

Transformers的架构和规模

关于硬件驱动设计的线索出现在第二章的开始使用 Transformer 模型架构的多头关注的架构部分中:

“然而,通过分析具有一个 d[model] 块的序列,我们只会一次得到一个观点。此外,要找到其他观点需要相当长的计算时间。

一个更好的方法是将每个单词 x(一个序列的所有单词)的 d[model] = 512 维分成 8 个 d[k] = 64 维。

然后我们可以并行运行这 8 个“头部”,加快训练速度,并获得关于每个单词如何与另一个单词相关的 8 个不同的表示子空间:

包含表格描述的图像

图 II.1:多头表示

您现在可以看到有 8 个头并行运行。

我们可以很容易地看出,强迫注意力头学习 8 种不同角度的动机。然而,深入挖掘原始 8 个注意力头并行执行不同计算的动机直接导致硬件优化。

Brown等人(2020 年)在语言模型——少量训练者中,arxiv.org/abs/2005.14165,描述了他们如何设计 GPT 模型。他们证实Transformers架构是硬件驱动的。

我们将模型跨 GPUs 进行分区,同时沿深度和宽度维度,以最小化节点间的数据传输。每个模型的精确结构参数基于跨 GPU 模型布局中的计算效率和负载平衡而选择。

Transformer 在构造(编码器和解码器)和大小上有所不同。但它们都有需要并行处理的硬件约束。我们需要进一步了解为什么 GPU 如此特殊。

为什么 GPU 如此特殊

在第二章的开始使用 Transformer 模型架构的多头关注的架构部分中出现了 GPU 驱动设计的线索。

注意力被定义为“缩放点积注意力”,用以下方程表示,我们将 Q、K 和 V 带入其中:

我们现在可以得出以下结论:

  • 注意力头(Attention heads)是为并行计算设计的。

  • 注意力头基于matmul,矩阵乘法。

GPU 是为并行计算而设计的。

CPU(中央处理单元)被优化用于串行处理。但如果我们通过串行处理来运行注意力头,那么训练一个有效的 Transformer 模型将需要更长的时间。非常小的教育型 Transformer 可以在 CPU 上运行。但是,它们不符合最先进模型的标准。

GPU(图形处理单元)是专为并行处理而设计的。Transformer 模型是为并行处理(GPU)而设计的,而不是串行处理(CPU)。

GPU 也是为矩阵乘法而设计的。

例如,NVIDIA GPU 包含加速矩阵操作的张量核心。包括 Transformer 模型在内的大部分人工智能算法使用矩阵操作。NVIDIA GPU 包含大量用于矩阵操作的硬件优化。以下链接提供了更多信息:

谷歌的张量处理单元(TPU)是 NVIDIA GPU 的等价物。使用 TPU 时,TensorFlow 将优化张量的使用。

BERT[BASE](110M 参数)最初是使用 16 个 TPU 芯片进行训练的。BERT[LARGE](340M 参数)是使用 64 个 TPU 芯片进行训练的。有关训练 BERT 的更多信息,请参见arxiv.org/abs/1810.04805。

我们已经确定了 Transformer 的架构完全符合并行硬件的约束条件。我们仍然需要解决在 GPU 上运行源代码的问题。

在代码中实现 GPU

PyTorch,以及其他语言和框架,管理着 GPU。PyTorch 包含张量(tensors),就像 TensorFlow 一样。张量可能看起来像 NumPy np.arrays()。然而,NumPy 不适合并行处理。张量使用 GPU 的并行处理特性。

在 PyTorch 中,张量(Tensors)打开了在 GPU 上分布式数据的大门,以及其他框架:pytorch.org/tutorials/intermediate/ddp_tutorial.html

在Chapter03笔记本BERT_Fine_Tuning_Sentence_Classification_GPU.ipynb中,我们使用CUDA(Compute Unified Device Architecture)与 NVIDIA GPU 通信。CUDA 是 NVIDIA 平台上的通用计算平台。特定的指令可以添加到我们的源代码中。更多信息,请参见developer.nvidia.com/cuda-zone。

在Chapter03笔记本中,我们使用 CUDA 指令将我们的模型和数据传输到 NVIDIA GPU 上。PyTorch有一个指令来指定我们希望使用的设备:torch.device。

更多信息,请参见pytorch.org/docs/stable/notes/cuda.html。

我们将解释device以说明 PyTorch 和一般程序中 GPU 的实现。让我们重点关注选择设备、数据并行性、将模型加载到设备和将批次数据添加到设备上。每个项目符号都包含了设备的使用方式和BERT_Fine_Tuning_Sentence_Classification_GPU.ipynb中的单元格号:

  • 选择设备(Cell 3)

    程序检查 CUDA 是否可用于 NVIDIA GPU。如果没有,设备将是 CPU:

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    !nvidia-smi 
    
  • 数据并行(Cell 16)

    如果有多个 GPU 可用,则可以将模型分布到几个 GPU 上进行并行计算:

    model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)
    model = nn.DataParallel(model) 
    
  • 将模型加载到设备上(cell 16)

    模型被发送到设备:

     model.to(device) 
    
  • 将批次添加到设备(cell 20)用于训练和验证数据

    数据批次被添加到可用的 GPU(1至n)中:

    # Add batch to GPU
    batch = tuple(t.to(device) for t in batch) 
    

在接下来的部分中,我描述了我进行的测试,以说明使用 GPU 来运行一个包含三个运行时配置的章节笔记本的Transformers模型的用法。

使用 Google Colab 测试 GPU

在本节中,我描述了我进行的非正式测试,以说明 GPU 的潜力。我们将使用相同的Chapter03笔记本:BERT_Fine_Tuning_Sentence_Classification_GPU.ipynb。

我在三种情况下运行了笔记本:

  • 带 CPU 的免费 Google Colab

  • 带 GPU 的免费 Google Colab

  • Google Colab Pro

带 CPU 的免费 Google Colab

在 CPU 上几乎不可能微调或训练一个拥有数百万或数十亿参数的Transformers模型。CPU 大多是顺序的。Transformers模型是为并行处理而设计的。

在运行时菜单和更改运行时类型子菜单中,您可以选择硬件加速器:无(CPU),GPU或TPU。

这个测试是在无(CPU)下运行的,如图 II.2所示:

图形用户界面、文本、应用、聊天或文本消息 自动生成的描述

图 II.2:选择硬件加速器

当笔记本进入训练循环时,从一开始就会减慢速度:

图 II.3:训练循环

经过 15 分钟,实际上什么都没有发生。

CPU 并不是为并行处理而设计的。Transformers模型是为并行处理而设计的,所以除了玩具模型之外,它们需要 GPU。

带 GPU 的免费 Google Colab

让我们回到笔记本设置中选择一个GPU。

包含文本描述的图像

图 II.4 选择 GPU

在写作时,我测试了 Google Colab,并且 VM 配备了带有 CUDA 11.2 的 NVIDIA K80:

自动生成的表格描述

图 II.5:激活了 NVIDIA K80 GPU

训练循环正常进行,持续约 20 分钟。然而,截至测试时(2021 年 11 月),Google Colab VMs 并不提供多于一个 GPU。GPU 价格昂贵。无论如何,图 II.6显示,训练循环在合理的时间内完成:

自动生成的文本描述

图 II.6:配备 K80 GPU 的训练循环

我发现测试 Google Colab Pro 是否提供更快的 GPU 很有趣。

Google Colab Pro 配备了 GPU

通过 Google Colab 提供的 VM 配备了 NVIDIA P100 GPU,如图 II.7所示。这很有趣,因为原始 Transformer 训练时,根据 Vaswani 等人(2017)《关注力就是你所需的一切》,用了 8 个 NVIDIA P100s,用了 12 小时来训练具有 10⁶×65 个参数的基础模型,并且使用了 8 个 GPU:

具有中等置信度自动生成的表描述

图 II.7:Google Colab Pro VM 配备了 P100 GPU

训练循环时间大大缩短,持续时间不到 10 分钟,如图 II.8所示:

自动生成的文本描述

图 II.8:配备 P100 GPU 的训练循环

加入我们书籍的 Discord 空间

加入该书的 Discord 空间,与作者进行每月的 问我任何事 专题讨论会:

www.packt.link/Transformers

附录 III:使用 GPT-2 进行通用文本完成

这个附录是第七章中GPT-3 引擎与超人类Transformers崛起中使用 GPT-2 进行通用文本完成一节的详细解释。这一节描述了如何实现 GPT-2 Transformers模型来完成通用文本。

你可以直接在第七章中阅读这本笔记本的用法,或者在附录中构建程序并运行它,以更深入地了解 GPT 模型的工作原理。

我们将克隆 OpenAI_GPT_2 代码库,下载 345M 参数的 GPT-2 Transformers模型,并与其交互。我们将输入上下文句子,并分析Transformers生成的文本。目标是看看它如何创建新内容。

这一部分分为九个步骤。在 Google Colaboratory 中打开 OpenAI_GPT_2.ipynb。这个笔记本在本书的 GitHub 代码库的 AppendixIII 目录中。你会注意到笔记本也被分成了和本节相同的九个步骤和单元格。

逐步运行笔记本的单元格。这个过程很枯燥,但克隆 OpenAI GPT-2 代码库产生的结果是令人满意的。我们看到我们可以用几行代码运行一个 GPT-3 引擎。但是这个附录给了你机会,即使代码不再被优化,也可以看到 GPT-2 模型是如何工作的。

Hugging Face 有一个封装 GPT-2 模型的包装器。作为 OpenAI API 的一个替代方案很有用。然而,在这个附录中的目标不是为了避免 GPT-2 模型底层组件的复杂性,而是为了探索它们!

最后,重要的是我们正在运行一个低级别的 GPT-2 模型,而不是一个一行代码调用即可获得结果的简易版本(OpenAI GPT-3 API,Hugging Face 封装等)。我们正在从零开始理解 GPT-2 的架构,所以可能会收到一些弃用消息。但这样的努力值得成为 4.0 工业人工智能专家。

让我们开始激活 GPU。

第 1 步:激活 GPU

我们必须激活 GPU 来训练我们的 GPT-2 345M 参数Transformers模型。

要激活 GPU,请进入 笔记本设置 中的 运行时 菜单以充分利用 VM:

图 III.1:GPU 硬件加速器

我们可以看到激活 GPU 是更好性能的先决条件,这将让我们进入 GPT Transformers的世界。所以现在让我们克隆 OpenAI 的 GPT-2 代码库。

第 2 步:克隆 OpenAI GPT-2 代码库

目前 OpenAI 仍然允许我们下载 GPT-2。这种方式可能在将来被停止,或者可能我们会获得更多资源。此时,Transformers的发展和使用速度如此之快,以至于没人能预见市场会如何发展,即使是主要的研究实验室自己也不行。

我们将在 VM 上克隆 OpenAI 的 GitHub 目录:

#@title Step 2: Cloning the OpenAI GPT-2 Repository
!git clone https://github.com/openai/gpt-2.git 

克隆结束后,您应该在文件管理器中看到该代码库的出现:

图 III.2: 克隆的 GPT-2 存储库

点击 src,您会看到我们从 OpenAI 安装的运行模型所需的 Python 文件:

图 III.3: 运行模型的 GPT-2 Python 文件

您会发现我们没有需要的 Python 训练文件。在 附录 IV 的 用 GPT-2 训练语言模型 部分 自定义文本完成与 GPT-2中训练 GPT-2 模型时,我们将安装它们。

现在让我们安装所需的内容。

步骤 3: 安装要求

要自动安装所需的内容:

#@title Step 3: Installing the requirements
import os          # when the VM restarts import os necessary
os.chdir("/content/gpt-2")
!pip3 install -r requirements.txt 

逐个单元格运行时,我们可能需要重新启动虚拟机,然后再次导入os。

本笔记本的要求是:

  • Fire 0.1.3 用于生成命令行界面(CLIs)

  • regex 2017.4.5 用于正则表达式使用

  • Requests 2.21.0,一个 HTTP 库

  • tqdm 4.31.1 用于显示循环的进度条

可能会要求您重新启动笔记本。

现在不要重新启动它。让我们等到检查 TensorFlow 的版本。

步骤 4: 检查 TensorFlow 的版本

OpenAI 提供的 GPT-2 345M Transformers模型使用 TensorFlow 1.x。这将在运行程序时导致几个警告。但是,我们将忽略它们,并在我们的普通机器上以全速运行训练 GPT 模型的薄冰上。

在 2020 年代,GPT 模型已经达到了 1750 亿个参数,使我们在没有超级计算机的情况下无法高效地进行训练。参数的数量只会继续增加。

企业巨头的研究实验室,例如 Facebook AI、OpenAI 和 Google Research/Brain,正在加速转向超级Transformers,并且正在留下一些供我们学习和理解的东西。但是,不幸的是,他们没有时间回头更新他们分享的所有模型。然而,我们还有这个笔记本!

TensorFlow 2.x 是最新的 TensorFlow 版本。然而,旧程序仍然可能有所帮助。这就是为什么 Google Colaboratory VMs 预先安装了 TensorFlow 1.x 和 TensorFlow 2.x 的版本的一个原因。

我们将在此笔记本中使用 TensorFlow 1.x:

#@title Step 4: Checking the Version of TensorFlow 
#Colab has tf 1.x and tf 2.x installed
#Restart runtime using 'Runtime' -> 'Restart runtime...'
%tensorflow_version 1.x
import tensorflow as tf
print(tf.__version__) 

输出应该是:

TensorFlow 1.x selected.
1.15.2 

无论是否显示tf 1.x版本,请重新运行单元格以确保,然后重新启动虚拟机。在继续之前重新运行此单元格以确保。

如果在过程中遇到 TensforFlow 错误(忽略警告),请重新运行此单元格,重新启动虚拟机,确保重新运行。

每次重新启动虚拟机时都要做这个。虚拟机的默认版本是 tf.2。

我们现在准备下载 GPT-2 模型。

步骤 5: 下载 345M 参数 GPT-2 模型

我们现在将下载训练好的 345M 参数 GPT-2 模型:

#@title Step 5: Downloading the 345M parameter GPT-2 Model
# run code and send argument
import os # after runtime is restarted
os.chdir("/content/gpt-2")
!python3 download_model.py '345M' 

模型目录的路径是:

/content/gpt-2/models/345M

它包含我们运行模型所需的信息:

图 III.4: 345M 参数模型的 GPT-2 Python 文件

hparams.json 文件包含了 GPT-2 模型的定义:

  • "n_vocab": 50257,模型词汇表的大小

  • "n_ctx": 1024,上下文大小

  • "n_embd": 1024,嵌入大小

  • "n_head": 16,头的数量

  • "n_layer": 24,层数

encoder.json 和 vacab.bpe 包含了标记化的词汇表和 BPE 单词对。如有必要,请花几分钟时间返回并阅读第 3 步: 训练一个分词器子节,第四章,从零开始预训练 RoBERTa 模型。

checkpoint 文件包含了检查点时的训练参数。例如,它可能包含了 1,000 步的训练参数,就像我们在第 9 步: 训练 GPT-2 模型章节的附录 IV中,使用 GPT-2 进行自定义文本完成部分将要做的那样。

checkpoint 文件与其他三个重要文件保存在一起:

  • model.ckpt.meta 描述了模型的图结构。它包含GraphDef,SaverDef等。我们可以使用tf.train.import_meta_graph([path]+'model.ckpt.meta')检索信息。

  • model.ckpt.index 是一个字符串表。键包含张量的名称,值是BundleEntryProto,其中包含张量的元数据。

  • model.ckpt.data 包含TensorBundle collection中所有变量的值。

我们已经下载了我们的模型。现在我们将在激活模型之前经历一些中间步骤。

步骤 6-7: 中间指令

在本节中,我们将经历步骤 6、7和7a,这些是通向步骤 8的中间步骤,其中我们将定义和激活模型。

在与模型交互时,我们希望将 UTF 编码的文本打印到控制台:

#@title Step 6: Printing UTF encoded text to the console
!export PYTHONIOENCODING=UTF-8 

我们要确保我们在src目录下:

#@title Step 7: Project Source Code
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src") 

我们已经准备好与 GPT-2 模型交互。我们可以直接运行它,就像我们在附录 IV中的使用 GPT-2 进行语言模型训练部分将要做的那样。然而,在本节中,我们将讨论代码的主要方面。

interactive_conditional_samples.py 首先导入与模型交互所需的必要模块:

#@title Step 7a: Interactive Conditional Samples (src)
#Project Source Code for Interactive Conditional Samples:
# /content/gpt-2/src/interactive_conditional_samples.py file 
import json
import os
import numpy as np
import tensorflow as tf 

我们已经经历了激活模型的中间步骤。

步骤 7b-8: 导入并定义模型

现在我们将使用interactive_conditional_samples.py激活与模型的交互。

我们需要导入三个同时也在 /content/gpt-2/src中的模块:

import model, sample, encoder 

这三个程序是:

  • model.py 定义了模型的结构: 超参数,多头tf.matmul操作,激活函数以及所有其他属性。

  • sample.py 处理交互并控制将生成的样本。它确保标记更有意义。

    Softmax 值有时可能模糊不清,就像在低清晰度下查看图像。sample.py 包含一个名为temperature的变量,将使值更清晰,增加更高的概率并软化更低的概率。

    sample.py 可以激活 Top-k采样。Top-k采样对预测序列的概率分布进行排序。分布的头部具有较高的概率值,排除掉尾部具有较低概率的部分,以防止模型预测低质量的标记。

    sample.py 也可以激活用于语言建模的 Top-p采样。Top-p采样不对概率分布进行排序。相反,它选择具有较高概率的词,直到此子集的概率之和或可能序列的核心超过 p。

  • encoder.py 使用定义好的模型 encoder.json 和 vocab.bpe 对样本序列进行编码。它既包含了一个 BPE 编码器,又包含了文本解码器。

你可以双击打开这些程序来进一步探索它们。

interactive_conditional_samples.py 将调用所需的函数与模型进行交互,以初始化以下信息:来自 model.py 定义模型的超参数,以及来自 sample.py 的样本序列参数。它将使用 encode.py 进行编码和解码序列。

interactive_conditional_samples.py 将恢复本节的 第 5 步:下载 345M 参数 GPT-2 模型 子部分中定义的检查点数据。

你可以双击打开interactive_conditional_samples.py并尝试调整其参数:

  • model_name 是模型名称,如 "124M" 或 "345M,",依赖于 models_dir。

  • models_dir 定义包含模型的目录。

  • seed 为随机生成器设置一个随机整数。可以设置种子以重现结果。

  • nsamples 是要返回的样本数。如果设置为 0,它将继续生成样本,直到你双击单元格的 run 按钮或按下 Ctrl + M。

  • batch_size 决定了批处理的大小,对内存和速度有影响。

  • length 是生成文本的标记数。如果设置为 none,则依赖于模型的超参数。

  • temperature 决定了 Boltzmann 分布的级别。如果温度很高,完成结果将更加随机。如果温度很低,结果将变得更加确定。

  • top_k 控制 Top-k在每一步考虑的标记数。 0表示没有限制。推荐值为 40。

  • top_p 控制 Top-p。

对于本节中的程序,我们刚刚探索的参数场景将是:

  • model_name = "345M"

  • seed = None

  • nsamples = 1

  • batch_size = 1

  • length = 300

  • temperature = 1

  • top_k = 0

  • models_dir = '/content/gpt-2/models'

这些参数将影响模型的行为,它如何受到上下文输入的条件影响,并生成文本完成序列。首先使用默认值运行笔记本。然后,您可以通过双击程序,编辑它并保存它来更改代码的参数。在每次重新启动 VM 时将删除更改。如果您希望创建交互场景,请保存程序并重新加载它。

程序现在已准备好提示我们与其交互。

步骤 9:与 GPT-2 交互

在本节中,我们将与 GPT-2 345M 模型交互。

系统运行时会有更多消息,但只要 Google Colaboratory 保持 tf 1.x,我们就会使用此笔记本运行模型。如果这本笔记本过时了,我们可能会有一天不得不使用 GPT-3 引擎,或者例如使用 Hugging Face GPT-2 包装器,未来它可能也会被弃用。

与此同时,GPT-2 仍在使用,所以让我们与模型交互吧!

要与模型交互,请运行 interact_model 单元格:

#@title Step 9: Interacting with GPT-2
interact_model('345M',None,1,1,300,1,0,'/content/gpt-2/models') 

将提示您输入一些上下文:

图 III.5:用于文本完成的上下文输入

由于这是一个标准的 GPT-2 模型,您可以尝试任何类型的上下文。

我们可以尝试以艾曼纽尔·康德(Emmanuel Kant)的句子开头:

`Human reason, in one sphere of its cognition, is called upon to`
`consider questions, which it cannot decline, as they are presented by`
`its own nature, but which it cannot answer, as they transcend every`
`faculty of the mind.` 

按下 Enter 键生成文本。由于 GPT-2 模型没有在我们的数据集上训练,而且我们正在运行一个随机模型,输出将相对随机。

让我们看看我运行模型时生成的前几行内容:

"We may grant to this conception the peculiarity that it is the only causal logic. 
In the second law of logic as in the third, experience is measured at its end: apprehension is afterwards closed in consciousness.
The solution of scholastic perplexities, whether moral or religious, is not only impossible, but your own existence is blasphemous." 

要停止单元格,请双击单元格的运行按钮。

您还可以按 Ctrl + M 停止生成文本,但它可能会将代码转换为文本,您将不得不将其复制回程序单元格。

输出内容丰富。我们可以观察到几个事实:

  • 我们输入的上下文 条件化 了模型生成的输出。

  • 上下文是模型的演示。它从模型中学到了要说的话,而没有修改其参数。

  • 文本完成受上下文影响。这为不需要微调的转换器模型打开了大门。

  • 从语义的角度来看,输出可能更有趣。

  • 从语法的角度来看,输出是令人信服的。

您可以通过阅读 附录 IV,使用 GPT-2 进行自定义文本完成,看看我们是否可以通过在自定义数据集上训练模型获得更令人印象深刻的结果。

参考资料

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作空间,与作者进行每月的 问我任何 会话:

www.packt.link/Transformers

附录 IV:使用 GPT-2 进行自定义文本完成

这个与第七章相关的附录,GPT-3 引擎崛起的超人类变形车,描述了如何使用 GPT-2 模型定制文本完成。

本附录展示了如何构建、训练 GPT-2 模型,并在 12 个步骤中与自定义文本进行交互。

打开本附录的 GitHub 仓库中的Training_OpenAI_GPT_2.ipynb。您会注意到笔记本也被分成了与本附录相同的 12 个步骤和单元格。

逐步运行笔记本中的每个单元格。这个过程是单调乏味的,但克隆 OpenAI GPT-2 仓库产生的结果是令人满意的。我们不会使用 GPT-3 API 或 Hugging Face 包装器。

我们会忙于了解模型是如何构建和训练的。您会看到一些弃用消息,但我们需要进入模型内部,而不是包装器或 API。然而,这个努力是值得的。

让我们开始激活 GPU。

训练 GPT-2 语言模型

在本节中,我们将在一个自定义数据集上训练一个 GPT-2 模型,然后与我们定制的模型进行交互。我们将使用与第四章中相同的kant.txt数据集,从头开始预训练 RoBERTa 模型。

我们将逐步打开笔记本并运行每个单元格。

步骤 1:先决条件

本节中提到的文件可以在本书的 GitHub 仓库的AppendixIV目录中找到:

  • 如果您在 Google Colab 上运行它,请在 Google Colab 的笔记本运行时菜单中启用 GPU,就像附录 III中 第 1 步:激活 GPU中所解释的那样。

  • 使用内置文件管理器将以下 Python 文件上传到 Google Colaboratory:train.py、load_dataset.py、encode.py、accumulate.py、memory_saving_gradients.py。

  • 这些文件最初来自N Shepperd的 GitHub 仓库:github.com/nshepperd/gpt-2。但是,您可以从本书的 GitHub 仓库的AppendixIV\``gpt-2-train_files目录中下载这些文件。

  • N Shepperd的 GitHub 仓库提供了训练我们的 GPT-2 模型所需的文件。我们不会克隆N Shepperd的仓库,而是将从N Shepperd的仓库中获取的五个训练文件添加到 OpenAI 的仓库中。

  • 用内置文件管理器将dset.txt上传到 Google Colaboratory。数据集被命名为dset.txt,这样在阅读本附录后,您可以用自定义输入替换其内容而无需修改程序。

  • 这个数据集位于本附录的 GitHub 仓库中的gpt-2-train_files目录中。这是第四章中使用的kant.txt数据集,从头开始预训练 RoBERTa 模型。

我们现在将逐步进行训练过程的初始步骤。

第 2 至第 6 步:训练过程的初始步骤

本小节将仅简要介绍步骤 2 到 6,因为我们在附录 III,使用 GPT-2 进行通用文本补全中对其进行了详细描述。然后我们将把数据集和模型复制到项目目录中。

该程序现在克隆 OpenAI 的 GPT-2 仓库,而不是N Shepperd的仓库:

#@title Step 2: Cloning the OpenAI GPT-2 Repository
#!git clone https://github.com/nshepperd/gpt-2.git
!git clone https://github.com/openai/gpt-2.git 

我们已经从N Shepperd的目录中上传了训练 GPT-2 模型所需的文件。

程序现在安装所需软件:

#@title Step 3: Installing the requirements
import os             #when the VM restarts import os necessary
os.chdir("/content/gpt-2")    
!pip3 install -r requirements.txt 

该笔记本需要toposort,这是一种拓扑排序算法:

!pip install toposort 

安装完所需软件后,请不要重新启动笔记本。相反,请等待直到您检查了 TensorFlow 版本,在您的会话期间只重新启动虚拟机一次。之后,如果有必要,则重新启动。深入了解代码而不仅仅是包装和 API 是繁琐但值得的。

现在我们检查 TensorFlow 版本,以确保我们正在运行tf 1.x版本:

#@title Step 4: Checking TensorFlow version
#Colab has tf 1.x , and tf 2.x installed
#Restart runtime using 'Runtime' -> 'Restart runtime...'
%tensorflow_version 1.x
import tensorflow as tf
print(tf.__version__) 

无论显示了tf 1.x版还是没有,请重新运行该单元格以确保,重新启动虚拟机,并重新运行该单元格。这样,您可以确保您正在运行带有tf 1.x的虚拟机。

该程序现在会下载我们将与我们的数据集训练的 117M 参数的 GPT-2 模型:

#@title Step 5: Downloading 117M parameter GPT-2 Model
# run code and send argument
import os # after runtime is restarted
os.chdir("/content/gpt-2")
!python3 download_model.py '117M' #creates model directory 

我们将复制数据集和 117M 参数的 GPT-2 模型到src目录中:

#@title Step 6: Copying the Project Resources to src
!cp /content/dset.txt /content/gpt-2/src/
!cp -r /content/gpt-2/models/ /content/gpt-2/src/ 

目标是将我们训练模型所需的所有资源分组到src项目目录中。

现在我们将浏览 N Shepperd 的训练文件。

第 7 步:N Shepperd 训练文件

我们将使用的训练文件来自N Shepperd的 GitHub 仓库。我们在本附录的第 1 步:先决条件中上传了它们。现在我们将把它们复制到我们的项目目录中:

#@title Step 7: Copying the N Shepperd Training Files
#Referfence GitHub repository: https://github.com/nshepperd/gpt-2
import os # import after runtime is restarted
!cp /content/train.py /content/gpt-2/src/
!cp /content/load_dataset.py /content/gpt-2/src/
!cp /content/encode.py /content/gpt-2/src/
!cp /content/accumulate.py /content/gpt-2/src/
!cp /content/memory_saving_gradients.py /content/gpt-2/src/ 

现在训练文件已经准备好激活。让我们开始探索它们,首先是encode.py。

第 8 步:对数据集进行编码

在训练之前,数据集必须被编码。您可以双击encode.py在 Google Colaboratory 中查看文件。

encode.py通过调用load_dataset.py中的load_dataset函数加载dset.txt:

from load_dataset import load_dataset
…/…
chunks = load_dataset(enc, args.in_text, args.combine, encoding=args.encoding) 

encode.py还加载 OpenAI 的编码程序encode.py来对数据集进行编码:

import encoder
…/…
enc = encoder.get_encoder(args.model_name,models_dir) 

编码的数据集以NumPy数组的形式保存,并存储在out.npz中。现在,npz是由编码器生成的数组的NumPy压缩存档:

import numpy as np
np.savez_compressed(args.out_npz, *chunks) 

当我们运行该单元格时,数据集将被加载、编码并保存在out.npz中:

#@title Step 8:Encoding dataset
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src/")
model_name="117M"
!python /content/gpt-2/src/encode.py dset.txt out.npz 

我们的 GPT-2 117M 模型已经准备好进行训练。

第 9 步:训练 GPT-2 模型

现在我们将对我们的数据集训练 GPT-2 117M 模型。我们将数据集的编码名称发送给程序:

#@title Step 9:Training the Model
#Model saved after 1000 steps
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src/")
!python train.py --dataset out.npz 

当您运行该单元格时,它将一直训练,直到您停止它。训练在 1,000 步后保存模型。当训练超过 1,000 步时,请停止它。保存的模型检查点位于/content/gpt-2/src/checkpoint/run1中。您可以在笔记本的第 10A 步:复制训练文件单元格中检查这些文件的列表。

您可以通过双击单元格的运行按钮来停止训练。训练将结束,并且训练参数将被保存。

您也可以在 1,000 步后停止训练模型,方法是使用Ctrl + M。程序将停止并保存训练参数。它会将代码转换为文本(您需要将其复制回代码单元格)并显示以下消息:

图 IV.1:自动保存训练好的 GPT-2 模型

该程序使用/content/gpt-2/src/memory_saving_gradients.py和/content/gpt-2/src/accumulate.py程序来管理优化器和梯度。

train.py包含了可以调整以修改训练过程的完整参数列表。首先不要改变它们运行笔记本。然后,如果你愿意,可以尝试修改训练参数,看看能否获得更好的结果。

GPT-3 模型会在训练过程中生成一些样本供您阅读。在我训练 GPT-2 的过程中,系统生成了一个让我感到启迪的样本:

The world is not a thing in itself, but is a representation of the world in itself. 

世界的形象是我们人类创造的,也是 AI 学到的。有趣!

让我们继续我们的实验,为我们的训练模型创建一个目录。

步骤 10:创建训练模型目录

本节将为我们的模型创建一个临时目录,存储我们需要的信息,并将其重命名以替换我们下载的 GPT-2 117M 模型目录。

我们首先创建一个名为tgmodel的临时目录:

#@title Step 10: Creating a Training Model directory
#Creating a Training Model directory named 'tgmodel'
import os
run_dir = '/content/gpt-2/models/tgmodel'
if not os.path.exists(run_dir):
  os.makedirs(run_dir) 

然后我们复制包含我们训练模型时保存的训练参数的检查点文件,这是在本节的步骤 9:训练模型中进行的。

#@title Step 10A: Copying training Files
!cp /content/gpt-2/src/checkpoint/run1/model-1000.data-00000-of-00001 /content/gpt-2/models/tgmodel
!cp /content/gpt-2/src/checkpoint/run1/checkpoint /content/gpt-2/models/tgmodel
!cp /content/gpt-2/src/checkpoint/run1/model-1000.index /content/gpt-2/models/tgmodel
!cp /content/gpt-2/src/checkpoint/run1/model-1000.meta /content/gpt-2/models/tgmodel 

我们的tgmodel目录现在包含我们的 GPT-2 模型的训练参数。

我们在附录 III的使用 GPT-2 进行通用文本补全的步骤 5:下载 345M 参数 GPT-2 模型中描述了这些文件的内容。

我们现在将从我们下载的 GPT-2 117M 模型中检索超参数和词汇文件:

#@title Step 10B: Copying the OpenAI GPT-2 117M Model files
!cp /content/gpt-2/models/117M/encoder.json /content/gpt-2/models/tgmodel
!cp /content/gpt-2/models/117M/hparams.json /content/gpt-2/models/tgmodel
!cp /content/gpt-2/models/117M/vocab.bpe /content/gpt-2/models/tgmodel 

我们的tgmodel目录现在包含我们完整定制的 GPT-2 117M 模型。

我们的最后一步是将我们下载的原始 GPT-2 模型重命名,并将我们的模型名称设置为117M:

#@title Step 10C: Renaming the model directories
import os
!mv /content/gpt-2/models/117M  /content/gpt-2/models/117M_OpenAI
!mv /content/gpt-2/models/tgmodel  /content/gpt-2/models/117M 

我们训练好的模型现在是克隆的 OpenAI GPT-2 代码库将要运行的模型。让我们与我们的模型交互吧!

步骤 11:生成无条件样本

在本节中,我们将与在我们的数据集上训练的 GPT-2 117M 模型进行互动。我们将首先生成一个无条件样本,不需要我们输入任何内容。然后,我们将输入一个上下文段落,以从我们训练好的模型获得一个条件文本补全响应。

让我们先运行一个无条件样本:

#@title Step 11: Generating Unconditional Samples
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src")
!python generate_unconditional_samples.py --model_name '117M' 

由于这是一个无条件的样本生成器,你不需要输入上下文句子。

要停止该单元格,双击单元格的运行按钮,或按Ctrl + M。

结果是随机的,但从语法的角度来看是合理的。从语义的角度来看,结果并不那么有趣,因为我们没有提供上下文。但仍然,这个过程是了不起的。它创造了帖子,写了一个标题,日期,想象了组织和地址,提出了一个主题,甚至想象了网页链接!

开头的几行令人难以置信:

Title: total_authority
Category:
Style: Printable
Quote:
Joined: July 17th, 2013
Posts: 0
Offtopic link: "Essential research, research that supports papers being peer reviewed, research that backs up one's claims for design, research that unjustifiably accommodates scientific uncertainties, and research that persuades opens doors for science and participation in science",
href: https://groups.google.com/search?q=Author%3APj&src=ieKZP4CSg4GVWDSJtwQczgTWQhAWBO7+tKWn0jzz7o6rP4lEy&s sl=cTheory%20issue1&fastSource=posts&very=device
Offline
Joined: May 11th, 2014
Posts: 1729
Location: Montana AreaJoined: May 11th, 2014Posts: 1729Location: Montana
Posted: Fri Dec 26, 2017 9:18 pm Post subject: click
I. Synopsis of the established review group
The "A New Research Paradigm" and Preferred Alternative (BREPG) group lead authors John Obi (Australian, USA and Chartered Institute of Tropical and Climate Change Research), Marco Xiao (China and Department of Sociology/Ajax, International Institute of Tropical and Climate Change Research, Shanghai University) and Jackie Gu (US/Pacific University, Interselicitas de NASA and Frozen Planet Research Research Center, Oak Ridge National Laboratory). Dr. Obi states: "Our conclusions indicate that the existence of the new peer reviewed asan-rubie study predisposes journal publishers to read scientific publishers constantly to seek a consignment of, and to be affiliated with, a large target certain of their persons. The current practice of supplying books with peer review by commonly-overruled specialists itself spreads from part to part, sufficient to spread the impact of peer reviews by experts to all levels of the organization, so as to increase the extent of exposure to the term of deviation that source profiles or findings require". 

无条件的随机文本生成器的结果很有趣,但并不令人信服。

第 12 步:交互式上下文和补全示例

现在我们将运行一个有条件的示例。我们输入的上下文将使模型以我们想要的方式进行思考,通过生成定制段落来完成文本。

运行单元格并探索魔法:

#@title Step 12: Interactive Context and Completion Examples
import os # import after runtime is restarted
os.chdir("/content/gpt-2/src")
!python interactive_conditional_samples.py --temperature 0.8 --top_k 40 --model_name '117M' 

如果需要,花几分钟回顾附录 III 的第 9 步:与 GPT-2 交互中的参数。程序提示我们输入上下文:

图 IV.2:文本补全的上下文输入

让我们来看看埃曼纽尔·康德在附录 III 的第 9 步:与 GPT-2 交互中写的同一段落,使用 GPT-2 进行通用文本补全。

Human reason, in one sphere of its cognition, is called upon to
consider questions, which it cannot decline, as they are presented by
its own nature, but which it cannot answer, as they transcend every
faculty of the mind. 

按下Enter键来生成文本,就像之前一样。尽管输出可能会从一个运行到另一个运行而变化,但它是有结构和逻辑的,这使得Transformers具有吸引力。这次,结果不是随机的,而且令人印象深刻。

让我们来看看 GPT-2 模型生成的开头几行:

"Now, what is the nature of the reason, except that it is of a kind and power of mind that is so called on to think, and to understand?
The reason is the thing which apprehends, and seeks to understand, the objects of its minds, which apprehend and apprehend the things of itself. No one can speak of this reason without the understanding and the understanding of the human reason. But that knowledge and understanding which is the most natural of all the faculties, which, because it is understood by the human reason, is the most natural of all the faculties, is not without reason, but only without understanding. The human reason, who sees and knows the things which the natural sense, which, though in the natural sense, does not understand, is the source of every other knowledge which we understand. The reason is the thing which does not understand, but understands the things which we comprehend, and therefore, is not to be understood. I mean that the reason is the thing which does not understand, but knows only the things which we do understand…." 

要停止单元格,双击单元格的运行按钮,或输入Ctrl + M。

哇!我怀疑有谁能看出我们训练过的 GPT-2 模型产生的文本补全与人类之间的区别。它也可能在每次运行时生成不同的输出。这可能是输出的样子,例如:

The first question, to which it is obliged to respond, is, how can it be true that a mind which is ignorant of the truth of any proposition can, or ought, to, accept any proposition which it has not given it? And this question has been so well answered that it is impossible for any man to believe in the existence of any mind which has never received any information. 
"It is not the mind of any man, as far as we can judge, which is the subject of any philosophical inquiry. It is the mind of the minds of men, in their opinion, which they consider the most to be their most important subject. And if they can see through this, they will see it, and they will understand it, and they will understand it." 

我认为我们的模型在这个哲学、推理和逻辑的抽象练习中可能会胜过许多人类!

限制在于文本会随着每次运行而变化。因此,尽管看起来很出色,但它并不会满足我们在日常生活中的每一个需求。

我们可以从我们的实验中得出一些结论:

  • 训练良好的Transformers模型可以产生接近人类水平的文本补全。

  • 在复杂和抽象推理方面,GPT-2 模型几乎可以达到人类水平的文本生成。

  • 文本上下文是通过展示预期的内容来有效地对模型进行条件化的一种方法。

  • 如果提供了上下文句子,文本补全就是基于文本条件生成文本。

  • 尽管文本处于人类水平,但这并不意味着它会满足我们所有的需求。目前,它在局部是有趣的,但在整体上并不有效。

你可以尝试输入一些条件化的文本上下文示例来实验文本补全。你也可以用自己的数据训练我们的模型。只需用你自己的内容替换dset.txt文件的内容,然后看看会发生什么!

请记住,我们训练的 GPT-2 模型会像人类一样做出反应。如果你输入一个简短的、不完整的、不引人注意的或者棘手的上下文,你将会得到困惑或者糟糕的结果。这是因为 GPT-2 期望我们做到最好,就像在现实生活中一样!

参考资料

加入我们书籍的 Discord 空间

加入书籍的 Discord 工作空间,与作者进行每月的 问我任何问题 会议:

www.packt.link/Transformers

附录 V:问题的答案

第一章,什么是转换器?

  1. 我们仍处于第三次工业革命。 (True/False)

    False. 历史上的时代确实有重叠。然而,第三次工业革命着眼于使世界数字化。第四次工业革命已经开始将所有事物连接到一起:系统、机器、机器人、机器人、算法等等。

  2. 第四次工业革命正在将所有事物连接在一起。 (True/False)

    True. 这导致了越来越多的自动决策,以前需要人为干预。

  3. 工业 4.0 开发者有时可能没有 AI 开发要做。 (True/False)

    True. 在某些项目中,AI 将是一个不需要开发的在线服务。

  4. 工业 4.0 开发者可能需要从头开始实现转换器。 (True/False)

    True. 在某些项目中,并非所有标准在线服务或 API 都能满足项目的需求。在某些情况下,项目可能没有一个令人满意的解决方案。相反,开发者将不得不大幅度定制模型并从头开始工作。

  5. 没有必要学习超过一个转换器生态系统,例如 Hugging Face。 (True/False)

    False. 一个公司的政策可能是只与 Google Cloud AI 或 Microsoft Azure AI 合作。Hugging Face 可能是另一家公司使用的工具。你事先不知道,而且在大多数情况下也不能决定。

  6. 一个即用即用的转换器 API 可以满足所有需求。 (True/False)

    如果有效则为 True。如果转换器模型训练不良,则为 False。

  7. 一家公司将接受开发者最擅长的转换器生态系统。 (True/False)

    False. 一家公司可能接受也可能不接受开发者建议的内容。因此,尽可能多地涵盖各方面是更安全的做法。

  8. 云转换器已成为主流。 (True/False)

    True.

  9. 转换器项目可以在笔记本电脑上运行。 (True/False)

    例如原型为 True。对于涉及成千上万用户的项目为 False。

  10. 工业 4.0 AI 专家将不得不更加灵活 (True/False)

    True.

第二章,开始学习转换器模型的架构

  1. NLP 转换可以对文本表示进行编码和解码。 (True/False)

    True. NLP 是将序列(书面或口头)转换为数字表示形式的转换,对其进行处理,并将结果解码回文本。

  2. 自然语言理解(NLU)是自然语言处理(NLP)的子集。 (True/False)

    True.

  3. 语言建模算法根据输入序列生成可能的单词序列。 (True/False)

    True.

  4. 转换器是带有 CNN 层的定制 LSTM。 (True/False)

    False. 转换器根本不包含 LSTM 或 CNN。

  5. 转换器不包含 LSTM 或 CNN 层。 (True/False)

    True.

  6. 注意检查序列中的所有标记,而不仅仅是最后一个。 (True/False)

    True.

  7. 转换器不使用位置编码。 (True/False)

    假的。一个Transformers使用位置编码。

  8. Transformers包含一个前馈网络。(真/假)

    真的。

  9. Transformers解码器的掩码多头注意力组件防止算法分析正在处理的序列的给定位置时看到其余序列的其余部分。(真/假)

    真的。

  10. Transformers可以更好地分析长距离依赖关系,优于 LSTMs。(真/假)

    真的。

第三章,《对 BERT 模型进行微调》

  1. BERT 代表双向编码器来自Transformers。(真/假)

    真的。

  2. BERT 是一个两步框架。第一步是预训练。第二步是微调。(真/假)

    真的。

  3. 对 BERT 模型进行微调意味着从头开始训练参数。(真/假)

    假的。BERT 微调是使用预训练的训练参数初始化的。

  4. BERT 只通过所有下游任务进行预训练。(真/假)

    假的。

  5. BERT 预训练基于掩码语言模型(MLM)。(真/假)

    真的。

  6. BERT 的预训练基于下一句预测(NSP)。(真/假)

    真的。

  7. BERT 预训练基于数学函数。(真/假)

    假的。

  8. 一个问题-答案任务是下游任务。(真/假)

    真的。

  9. BERT 预训练模型不需要标记化。(真/假)

    假的。

  10. 对 BERT 模型进行微调所需时间比预训练时间短。(真/假)

    真的。

第四章,《从头开始预训练 RoBERTa 模型》

  1. RoBERTa 使用字节级字节对编码分词器。(真/假)

    真的。

  2. 一个经过训练的 Hugging Face 分词器会产生 merges.txt 和 vocab.json。(真/假)

    真的。

  3. RoBERTa 不使用标记类型 ID。(真/假)

    真的。

  4. DistilBERT 有 6 层和 12 个头。(真/假)

    真的。

  5. 一个拥有 8000 万参数的Transformers模型是巨大的。(真/假)

    假的。8000 万参数是一个小型模型。

  6. 我们不能训练分词器。(真/假)

    假的。分词器可以被训练。

  7. 类似 BERT 的模型有六个解码器层。(真/假)

    假的。BERT 包含六个编码器层,而不是解码器层。

  8. MLM 预测句子中包含在掩码标记内的单词。(真/假)

    真的。

  9. 类似 BERT 的模型没有自注意力子层。(真/假)

    假的。BERT 有自注意力层。

  10. 数据收集器对于反向传播很有帮助。(真/假)

    真的。

第五章,《使用Transformers进行下游 NLP 任务》

  1. 机器智能使用与人类相同的数据来作出预测。(真/假)

    真的和假的。

    真的。在某些情况下,机器智能在处理海量数据以提取含义并执行一系列任务时超越人类,而这些任务人类需要花几个世纪的时间来完成。

    假的。对于 NLU,人类通过他们的感官可以获取更多信息。机器智能依赖于人类提供的各种媒体。

  2. SuperGLUE 对于 NLP 模型来说比 GLUE 更困难。(真/假)

    真的。

  3. BoolQ 期望一个二进制答案。(真/假)

    真的。

  4. WiC 代表的是上下文中的单词。(真/假)

    真的。

  5. Recognizing Textual Entailment(RTE)用于检测一个序列是否蕴涵另一个序列。(真/假)

    真的。

  6. 一个 Winograd 模式可以预测动词是否拼写正确。(真/假)

    假。Winograd 模式主要适用于代词消歧。

  7. Transformer 模型目前占据 GLUE 和 SuperGLUE 的前几名。(真/假)

    真。

  8. 人类基准标准并不是一成不变的。SuperGLUE 使其更加难以达到。(真/假)

    真。

  9. Transformer 模型永远不会超越 SuperGLUE 人类基准标准。(真/假)

    真和假。

    假。Transformer 模型击败了 GLUE 的人类基准,并将来也将击败 SuperGLUE。

    真。随着我们在 NLU 领域的进展,我们将继续设定更高的基准标准。

  10. 变种的 transformer 模型已经超越了 RNN 和 CNN 模型。(真/假)

    真。但你永远不知道在 AI 中将会发生什么!

第六章,《使用 Transformer 进行机器翻译》

  1. 机器翻译现在已经超过了人类基准。(真/假)

    假。机器翻译是最具挑战性的 NLP ML 任务之一。

  2. 机器翻译需要大型数据集。(真/假)

    真。

  3. 不需要使用相同的数据集比较 Transformer 模型。(真/假)

    假。比较不同模型的唯一方法是使用相同的数据集。

  4. BLEU 是法语单词,意思是蓝色,并且是 NLP 度量标准的首字母缩写。(真/假)

    真。BLEU代表双语评估辅助分数,这样很容易记住。

  5. 平滑技术增强了 BERT。(真/假)

    真。

  6. 对于机器翻译,德语-英语与英语-德语是相同的。(真/假)

    假。首先表示德语,然后翻译成其他语言并不同于表示英语再翻译为另一种语言。语言结构不同。

  7. 最初的 Transformer 多头注意力子层有两个头。(真/假)

    假。每个注意力子层有八个头。

  8. 最初的 Transformer 编码器有六层。(真/假)

    真。

  9. 最初的 Transformer 编码器有六层,但只有两个解码层。(真/假)

    假。有六个解码器层。

  10. 可以训练没有解码器的 transformer。(真/假)

    真。BERT 的结构只包含编码器。

第七章,《GPT-3 引擎的超人类Transformers崛起》

  1. 零-shot 方法只需一次训练参数。(真/假)

    假。没有训练参数。

  2. 在运行零-shot 模型时执行梯度更新。(真/假)

    假。

  3. GPT 模型只有一个解码器堆叠。(真/假)

    真。

  4. 在本地机器上训练 117M GPT 模型是不可能的。(真/假)

    假。我们在本章中训练了一个。

  5. 不可能使用特定数据集训练 GPT-2 模型。(真/假)

    假。我们在本章中训练了一个。

  6. 一个 GPT-2 模型不能被约束来生成文本。(真/假)

    假。我们在本章中实施了这一点。

  7. 一个 GPT-2 模型可以分析输入的上下文并生成完成的内容。(真/假)

    真。

  8. 我们不能在拥有少于八个 GPU 的机器上与一个 345M GTP 参数模型交互。 (True/False).

    假的。我们在本章中与这个尺寸的模型交互过。

  9. 拥有 285,000 个 CPU 的超级计算机不存在。 (True/False)

    假的。

  10. 拥有成千上万个 GPU 的超级计算机是 AI 中的游戏变革者。 (True/False)

    真的。由于这一点,我们将能够构建参数和连接数量逐渐增加的模型。

第八章,将转换器应用于法律和财务文件以进行 AI 文本摘要

  1. T5 模型只有像 BERT 模型一样的编码器栈。 (True/False)

    假的。

  2. T5 模型既有编码器栈,又有解码器栈。 (True/False)

    真的。

  3. T5 模型使用相对位置编码,而不是绝对位置编码。 (True/False)

    真的。

  4. 文本-文本模型只设计用于摘要。 (True/False)

    假的。

  5. 文本-文本模型将一个前缀应用到输入序列,用来确定 NLP 任务。 (True/False)

    真的。

  6. T5 模型对每个任务需要具体的超参数。 (True/False)

    假的。

  7. 文本-文本模型的优势之一是它们对所有 NLP 任务使用相同的超参数。 (True/False)

    真的。

  8. T5 转换器不包含前馈网络。 (True/False)

    假的。

  9. Hugging Face 是一个让转换器更容易实现的框架。 (True/False)

    真的。

  10. OpenAI 的转换器引擎是游戏变革者。 (True/False)

    真的。OpenAI 已经开发了一系列可供使用的引擎,如 Codex(从语言到代码)或 Davinci(通用引擎)。

第九章,匹配分词器和数据集

  1. 一个分词的词典包含了一种语言中存在的每个单词。 (True/False)

    假的。

  2. 预训练分词器可以对任何数据集进行编码。 (True/False)

    假的。

  3. 在使用数据库之前检查数据库是个好习惯。 (True/False)

    真的。

  4. 从数据集中消除淫秽数据是个好习惯。 (True/False)

    真的。

  5. 删除包含歧视性言论的数据是个好习惯。 (True/False)

    真的。

  6. 原始数据集有时可能会产生嘈杂内容和有用内容之间的关系。 (True/False)

    真的。

  7. 一个标准的预训练分词器包含了过去 700 年的英语词汇。 (True/False)

    假的。

  8. 古英语在使用现代英语训练的分词器对数据进行编码时可能会产生问题。 (True/False)

    真的。

  9. 医学和其他类型的行话在使用现代英语训练的分词器对数据进行编码时会产生问题。 (True/False)

    真的。

  10. 控制预训练分词器生成数据的输出是个好习惯。 (True/False)

    真的。

第十章,基于 BERT 的转换器进行语义角色标注

  1. 语义角色标注 (SRL) 是一个文本生成任务。 (True/False)

    假的。

  2. 谓语是一个名词。 (True/False)

    假的。

  3. 动词是谓语。 (True/False)

    真的。

  4. 论点可以描述谁和什么正在做某事。 (True/False)

    真的。

  5. 一个修饰语可以是一个副词。 (True/False)

    真的。

  6. 一个修饰语可以是一个地点。 (True/False)

    真的。

  7. 基于 BERT 的模型包含编码器和解码器堆栈。(真/假)

    假。

  8. 基于 BERT 的 SRL 模型具有标准的输入格式。(真/假)

    真。

  9. Transformers可以解决任何 SRL 任务。(真/假)

    假。

第十一章,让你的数据说话:故事,问题和答案

  1. 训练过的Transformers模型可以回答任何问题。(真/假)

    假。

  2. 问答不需要进一步的研究。它已经完美了。(真/假)

    假。

  3. 命名实体识别(NER)在寻找有意义的问题时可以提供有用的信息。(真/假)

    真。

  4. 语义角色标注(SRL)在准备问题时是无用的。(真/假)

    假。

  5. 问题生成器是产生问题的绝妙方法。(真/假)

    真。

  6. 实施问答需要谨慎的项目管理。(真/假)

    真。

  7. ELECTRA 模型与 GPT-2 具有相同的架构。(真/假)

    假。

  8. ELECTRA 模型与 BERT 具有相同的架构,但被训练为辨别器。(真/假)

    真。

  9. NER 可以识别地点并将其标记为 I-LOC。(真/假)

    真。

  10. NER 可以识别一个人并将该人标记为 I-PER。(真/假)

    真。

第十二章,检测客户情绪以做出预测

  1. 不需要为情感分析预训练Transformers。(真/假)

    假。

  2. 一个句子总是积极或消极的。它不能是中性的。(真/假)

    假。

  3. 合成性原则意味着Transformers必须理解句子的每个部分才能理解它。(真/假)

    真。

  4. RoBERTa-large 旨在改进Transformers模型的预训练过程。(真/假)

    真。

  5. 一个Transformers可以提供反馈,告诉我们客户是否满意。(真/假)

    真。

  6. 如果产品或服务的情感分析始终是负面的,它可以帮助我们做出改进我们提供的建议的适当决定。(真/假)

    真。

  7. 如果一个模型在某项任务上无法提供好的结果,那么在更换模型之前需要更多的训练或微调。(真/假)

    真。

第十三章,使用Transformers分析假新闻

  1. 标记为假新闻的新闻总是假的。.(真/假)

    假。

  2. 大家都同意的新闻总是准确的。(真/假)

    假。

  3. Transformers可以用于对推文进行情感分析。(真/假)

    真。

  4. 用 DistilBERT 模型运行 NER 可以从 Facebook 消息中提取关键实体。(真/假)

    真。

  5. 从运行 SRL 的基于 BERT 模型的 YouTube 聊天中可以识别关键动词。(真/假)

    真。

  6. 情感反应是对假新闻的自然第一反应。(真/假)

    真。

  7. 对假新闻的理性处理可以帮助澄清自己的立场。(真/假)

    真。

  8. 连接Transformers到可靠的网站可以帮助某人理解为什么一些新闻是假的。(真/假)

    真。

  9. Transformers可以对可靠网站进行摘要,帮助我们了解一些被标记为假新闻的主题。(真/假)

    真。

  10. 如果你为了我们所有人的利益使用人工智能,你可以改变世界。(真/假)

    真。

第十四章,解释黑匣子Transformers模型

  1. BERTViz 只显示了 BERT 模型的最后一层的输出。(真/假)

    假。 BERTViz 显示所有层的输出。

  2. BERTViz 显示了 BERT 模型每个层的注意力头。(真/假)

    真。

  3. BERTViz 显示令牌之间的关系。(真/假)

    真。

  4. LIT 显示了注意力头的内部工作,就像 BERTViz 一样。(真/假)

    假。然而,LIT 进行非探测性预测。

  5. 探测是一种算法预测语言表示的方法。(真/假)

    真。

  6. NER 是一个探测任务。(真/假)

    真。

  7. PCA 和 UMAP 是非探测任务。(真/假)

    真。

  8. LIME 是模型不可知的。(真/假)

    真。

  9. Transformers通过逐层加深令牌之间的关系。(真/假)

    真。

  10. 可视化Transformers模型解释为可解释的人工智能增加了一个新维度。(真/假)

    真。

第十五章,从自然语言处理到任务不可知的Transformers模型

  1. Reformer Transformers模型不包含编码器。(真/假)

    假。Reformer Transformers模型��含编码器。

  2. Reformer Transformers模型不包含解码器。(真/假)

    假。Reformer Transformers模型包含编码器和解码器。

  3. 在 Reformer 模型中,输入按层存储。(真/假)

    假。输入在每个级别重新计算,从而节省内存。

  4. DeBERTa Transformers模型解缠了内容和位置。(真/假)

    真。

  5. 在选择项目的预训练Transformers模型之前,有必要测试成百上千个模型。(真/假)

    真和假。你可以尝试所有的模型,或者你可以选择一个非常可靠的模型并实施它以适应你的需求。

  6. 最新的Transformers模型总是最好的。(真/假)

    真和假。关于Transformers有很多研究,但是一些实验模型寿命很短。然而,有时最新的模型超出了前期模型的性能。

  7. 每个自然语言处理任务最好有一个Transformers模型,而不是一个多任务Transformers模型。(真/假)

    真和假。这是你必须做出的个人决定。风险评估是项目的关键方面。

  8. Transformers模型总是需要进行微调。(真/假)

    假。GPT-3 引擎是零-shot 模型。

  9. OpenAI GPT-3 引擎可以执行各种自然语言处理任务,不需要进行微调。(真/假)

    真。

  10. 在本地服务器上实施 AI 算法总是更好的。(真/假)

    假。这取决于你的项目。这是你必须做出的风险评估。

第十六章,Transformers驱动副驾驶的出现

  1. 能够自动生成代码的 AI 副驾驶不存在。(真/假)

    假。比如,GitHub Copilot 现在正在使用中。

  2. AI 副驾驶永远不会取代人类。(真/假)

    真和假。人工智能将接管许多销售、支持、维护和其他领域的任务。然而,许多复杂的任务仍然需要人类干预。

  3. GPT-3 引擎只能执行一个任务。(True/False)

    False. GPT-3 引擎可以执行各种各样的任务。

  4. Transformers 可以被训练成推荐者。(True/False)

    True. Transformers 已经从语言序列转变为许多领域的序列。

  5. Transformers 只能处理语言。(True/False)

    False. 一旦 Transformer 被训练为处理语言序列,它们可以分析许多其他类型的序列。

  6. 一个 Transformer 序列只能包含单词。(True/False)

    False. 一旦语言序列被处理,Transformer 只能处理数字,而不是单词。

  7. 视觉 Transformer 不能与 CNN 相提并论。(True/False)

    False. Transformers 是深度神经网络,可以与 CNN 在计算机视觉上相媲美。

  8. 具有计算机视觉的 AI 机器人不存在。(True/False)

    False. 例如,具有计算机视觉的机器人已经开始在军事应用中出现。

  9. 自动产生 Python 源代码是不可能的。(True/False)

    False. 微软和 OpenAI 联合生产了一个可以与我们一起或为我们编写 Python 代码的副驾驶。

  10. 我们有一天可能会成为机器人的副驾驶员。(True/False)

    这可能是真的也可能是假的。这仍然是人类、机器人和不断发展的 AI 生态系统中的一个挑战。

加入我们书籍的 Discord 空间。

加入该书的 Discord 工作空间,每月与作者进行一次问答活动:

www.packt.link/Transformers

posted @ 2026-03-25 13:16  布客飞龙I  阅读(61)  评论(0)    收藏  举报