Hugging Face主页课程第二篇《 Using Transformers》
Hugging Face主页课程第三篇《Fine-tuning a pretrained model》
Hugging Face 主页课程部分解析
本文翻译自Hugging Face主页Resources下的课程。
本课程将使用 Hugging Face 生态系统中的库—— Transformers、 Datasets、 Tokenizers 和 Accelerate——以及 Hugging Face Hub ,来教你自然语言处理 (NLP)。
这个课程:
关于作者:
Matthew Carrigan 是 Hugging Face 的机器学习工程师。他住在爱尔兰都柏林,之前在 Parse.ly 担任 ML 工程师,在此之前,他在都柏林三一学院担任博士后研究员。他不相信我们会通过扩展现有架构来实现 AGI,但无论如何都对机器人的不朽寄予厚望。
Lysandre Debut 是 Hugging Face 的机器学习工程师,从早期的开发阶段就一直致力于 Transformers 库。他的目标是通过使用非常简单的 API 开发工具,让每个人都可以使用 NLP。
Sylvain Gugger 是 Hugging Face 的一名研究工程师,也是 变形金刚库的核心维护者之一。此前,他是 fast.ai 的一名研究科学家,他与 fastai 和 PyTorch 与 Jeremy Howard 共同编写了面向程序员的深度学习。他的主要研究重点是通过设计和改进允许模型在有限资源上快速训练的技术,使深度学习更容易获得。
你准备好了吗? 在本章中,您将学习:
在进入 Transformer 模型之前,让我们快速了解一下自然语言处理是什么以及我们为什么关心它。
什么是自然语言处理?
NLP 是语言学和机器学习领域,专注于理解与人类语言相关的一切。 NLP 任务的目标不仅是单独理解单个单词,而且是能够理解这些单词的上下文。
以下是常见 NLP 任务的列表,每个任务都有一些示例:
计算机处理信息的方式与人类不同。 例如,当我们读到“我饿了”这句话时,我们很容易理解它的意思。 同样,给定两个句子,例如“我很饿”和“我很伤心”,我们可以轻松确定它们的相似程度。 对于机器学习 (ML) 模型,此类任务更加困难。 文本需要以一种使模型能够从中学习的方式进行处理。 而且由于语言很复杂,我们需要仔细考虑必须如何进行这种处理。 关于如何表示文本已经做了很多研究,我们将在下一章中介绍一些方法。
在本节中,我们将看看 Transformer 模型可以做什么,并使用 Transformers 库中的第一个工具:管道pipeline。
单击Open in Colab以打开包含本节所有代码示例的 Google Colab 笔记本。 此按钮将出现在包含代码示例的任何部分中。
如果您想在本地运行示例,我们建议您查看设置。
Transformer 模型用于解决各种 NLP 任务,就像上一节中提到的那样。 以下是一些使用 Hugging Face 和 Transformer 模型的公司和组织,他们也通过分享他们的模型回馈社区:
Transformers 库提供了创建和使用这些共享模型的功能. Model Hub包含数千个所有人都可以下载和使用的预训练模型。 您也可以将自己的模型上传到 Hub!
⚠️ Hugging Face Hub 不限于 Transformer 模型。 任何人都可以分享他们想要的任何类型的模型或数据集! 创建一个huggingface.co 帐户将会从所有可用功能中受益!
在深入研究 Transformer 模型的底层工作原理之前,让我们先看几个示例,看看它们如何用于解决一些有趣的 NLP 问题。
Transformers 库中最基本的对象是pipeline。 它将模型与其必要的预处理和后处理步骤连接起来,使我们能够直接输入任何文本并获得可理解的答案:
from transformers import pipeline
classifier = pipeline("sentiment-analysis")
classifier("I've been waiting for a HuggingFace course my whole life.")
[{'label': 'POSITIVE', 'score': 0.9598047137260437}]
我们甚至可以传入几个句子!
classifier([
"I've been waiting for a HuggingFace course my whole life.",
"I hate this so much!"
])
[{'label': 'POSITIVE', 'score': 0.9598047137260437},
{'label': 'NEGATIVE', 'score': 0.9994558095932007}]
默认情况下,此管道选择一个特定的预训练模型,该模型已针对英语情感分析进行了微调。 创建分类器对象时,将下载并缓存模型。 如果您重新运行该命令,则将使用缓存的模型,无需再次下载模型。
将一些文本传递到管道时涉及三个主要步骤:
目前可用的一些管道是:
让我们来看一看这些管道。
零样本分类, 这是实际项目中的常见场景,因为注释文本通常很耗时,并且需要领域专业知识。
对于这个用例,零样本分类管道非常强大:它允许您指定用于分类的标签,因此您不必依赖预训练模型的标签。 您已经看到模型如何使用这两个标签将句子分类为正面或负面——但它也可以使用您喜欢的任何其他标签集对文本进行分类。
from transformers import pipeline
classifier = pipeline("zero-shot-classification")
classifier(
"This is a course about the Transformers library",
candidate_labels=["education", "politics", "business"],
)
{'sequence': 'This is a course about the Transformers library',
'labels': ['education', 'business', 'politics'],
'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]}
此管道称为零样本,因为您无需在您的数据集上微调模型。 它可以直接返回您想要的任何标签列表的概率分数!
✏️ 试试看! 使用您自己的序列和标签,看看模型的如何运行。
现在让我们看看如何使用管道来生成一些文本。 这里的主要思想是您提供一个提示,模型将通过生成剩余的文本来自动完成它。 这类似于许多手机上的预测文本功能。 文本生成涉及随机性,因此如果您没有得到如下所示的相同结果,是正常的。
from transformers import pipeline
generator = pipeline("text-generation")
generator("In this course, we will teach you how to")
[{'generated_text': 'In this course, we will teach you how to understand and use '
'data flow and data interchange when handling user data. We '
'will be working with one or more of the most commonly used '
'data flows — data flows of various types, as seen by the '
'HTTP'}]
✏️快来试试吧! 使用 num_return_sequences 和 max_length 参数生成两个句子,每个句子 15 个单词。
前面的示例针对简单任务使用了默认模型,但您也可以从 Hub 中针对特定任务来选择特定模型的管道 例如,文本生成。转到 Model Hub并单击左侧的相应标签,页面将会仅显示文本生成任务支持的模型。 您应该进入这个页面。
让我们试试 distilgpt2 模型吧! 以下是如何在与以前相同的管道中加载它:
from transformers import pipeline
generator = pipeline("text-generation", model="distilgpt2")
generator(
"In this course, we will teach you how to",
max_length=30,
num_return_sequences=2,
)
[{'generated_text': 'In this course, we will teach you how to manipulate the world and '
'move your mental and physical capabilities to your advantage.'},
{'generated_text': 'In this course, we will teach you how to become an expert and '
'practice realtime, and with a hands on experience on both real '
'time and real'}]
模型中心包含多语言模型的checkpoints。您可以通过单击语言标签来优化对模型的搜索,然后选择生成另一种语言文本的模型。
通过单击选择模型后,您会看到有一个小部件,可让您直接在线试用。 通过这种方式,您可以在下载模型之前快速测试模型的功能。
✏️快来试试吧! 使用filters查找另一种语言的文本生成模型。 随意使用小部件并在管道中使用它!
Hugging Face 网站上的Inference API,可以对所有模型直接进行测试。即您可以直接在此页面上使用各种模型,通过输入自定义文本就可以看到模型处理输入数据后的结果。
支持小部件的推理Inference API 也可作为付费产品使用。 有关更多详细信息,请参阅定价页面。
您将尝试的下一个管道是 fill-mask。 此任务的想法是填充给定文本中的空白(完形填空):
from transformers import pipeline
unmasker = pipeline("fill-mask")
unmasker("This course will teach you all about models." , top_k=2)
[{'sequence': 'This course will teach you all about mathematical models.',
'score': 0.19619831442832947,
'token': 30412,
'token_str': ' mathematical'},
{'sequence': 'This course will teach you all about computational models.',
'score': 0.04052725434303284,
'token': 38163,
'token_str': ' computational'}]
top_k 参数控制要显示多少可能的结果。
请注意,这里模型填充了特殊的 词,它通常被称为掩码标记。 其他掩码填充模型可能具有不同的掩码标记,因此在使用其它模型时要先进行确认。比如是查看右侧Hosted inference API中使用的掩码。
✏️快来试试吧! 在 Hub 上搜索 bert-base-cased 模型并在Hosted inference API中识别其掩码。 这个模型对上面管道示例中的句子预测了什么?
命名实体识别 (NER) 任务中,模型必须找到输入文本各部分分别对应哪些实体(例如人员、位置或组织)。 让我们看一个例子:
from transformers import pipeline
ner = pipeline("ner", grouped_entities=True)
ner("My name is Sylvain and I work at Hugging Face in Brooklyn.")
[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18},
{'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45},
{'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57}
]
在这里,模型正确地识别出 Sylvain 是一个人 (PER),Hugging Face 是一个组织 (ORG),而Brooklyn是一个位置 (LOC)。
设定参数 grouped_entities=True ,这样管道会将对应于同一实体的句子部分重新组合在一起。这里模型正确地将“Hugging”和“Face”分组为一个组织,即使该名称由多个单词组成。
事实上,正如我们将在下一章看到的,预处理甚至将一些单词分成更小的部分。 例如,Sylvain 被分成四部分:S、##yl、##va 和 ##in。 在后处理步骤中,管道会将这些部分重新组合。
✏️快来试试吧! 在Model Hub搜索能够用英语进行词性标注(通常缩写为 POS)的模型。 这个模型对上面例子中的句子预测了什么?
问答管道使用给定的上下文信息来回答问题:
from transformers import pipeline
question_answerer = pipeline("question-answering")
question_answerer(
question="Where do I work?",
context="My name is Sylvain and I work at Hugging Face in Brooklyn"
)
{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'}
请注意,此管道是抽取式问答;它不会生成答案。
摘要是将文本缩减为较短文本的任务,同时保留文本中引用的所有(或大部分)重要方面。 下面是一个例子:
from transformers import pipeline
summarizer = pipeline("summarization")
summarizer("""
America has changed dramatically during recent years. Not only has the number of
graduates in traditional engineering disciplines such as mechanical, civil,
electrical, chemical, and aeronautical engineering declined, but in most of
the premier American universities engineering curricula now concentrate on
and encourage largely the study of engineering science. As a result, there
are declining offerings in engineering subjects dealing with infrastructure,
the environment, and related issues, and greater concentration on high
technology subjects, largely supporting increasingly complex scientific
developments. While the latter is important, it should not be at the expense
of more traditional engineering.
Rapidly developing economies such as China and India, as well as other
industrial countries in Europe and Asia, continue to encourage and advance
the teaching of engineering. Both China and India, respectively, graduate
six and eight times as many traditional engineers as does the United States.
Other industrial countries at minimum maintain their output, while America
suffers an increasingly serious decline in the number of engineering graduates
and a lack of well-educated engineers.
""")
[{'summary_text': ' America has changed dramatically during recent years . The '
'number of engineering graduates in the U.S. has declined in '
'traditional engineering disciplines such as mechanical, civil '
', electrical, chemical, and aeronautical engineering . Rapidly '
'developing economies such as China and India, as well as other '
'industrial countries in Europe and Asia, continue to encourage '
'and advance engineering .'}]
与文本生成一样,您可以为结果指定 max_length 或 min_length。
对于翻译,如果您在任务名称中提供语言对(例如“translation_en_to_fr”),则可以使用默认模型,但最简单的方法是在 Model Hub选择要使用的模型。 在这里,我们将尝试将法语翻译成英语:
rom transformers import pipeline
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en")
translator("Ce cours est produit par Hugging Face.")
[{'translation_text': 'This course is produced by Hugging Face.'}]
与文本生成和摘要一样,您可以为结果指定 max_length 或 min_length。
✏️快来试试吧! 搜索其他语言的翻译模型,并尝试将前一句翻译成几种不同的语言。
到目前为止显示的pipeline主要用于演示目的。 它们是为特定任务编程的,不能执行它们的变体。 在下一章中,您将了解管道内部的内容以及如何自定义其行为。
在本节中,我们将深入了解 Transformer 模型的架构。
以下是 Transformer 模型(简短)历史中的一些参考点:
Transformer 架构于 2017 年 6 月推出。原始研究的重点是翻译任务。随后推出了几个有影响力的模型,包括:
这个列表并不全,只是为了突出一些不同类型的 Transformer 模型。大体上,它们可以分为三类:
稍后我们将更深入地探讨这些类别。
上面提到的所有 Transformer 模型(GPT、BERT、BART、T5 等)都是作为语言模型来训练。这意味着他们已经以自我监督的方式接受了大量原始文本的训练。
自监督模型可以对其所训练的语言进行统计理解,但对于特定的实际任务并不是很有用。因此,通用的预训练模型会经历一个称为迁移学习的过程。在此过程中,模型在给定任务上以监督方式进行微调——即使用人工标注的标签。
任务的一个例子是预测一个句子中已经阅读了 n 个前一个单词的下一个单词。这被称为因果语言建模causal language modeling,因为输出取决于过去和现在的输入,而不是未来的输入。
另一个例子是掩码语言建模,其中模型预测句子中的掩码词。
除了一些例外情况(如 DistilBERT)外,实现更好性能的一般策略是增加模型的大小以及预训练的数据量。
不幸的是,训练模型,尤其是大型模型,需要大量数据。 这在时间和计算资源方面变得非常昂贵。 它甚至会转化为环境影响 environmental impact,如下图所示。
这展示了一个团队领导的(非常大的)模型项目,有意识地试图减少预训练对环境的影响。 运行大量试验以获得最佳超参数的足迹会更高。
想象一下,如果每次研究团队、学生组织或公司想要训练一个模型,它都会从头开始。 这将导致巨大的、不必要的全球成本!
这就是共享语言模型至关重要的原因:共享已训练的权重并在已训练权重的基础上进行构建可降低社区的整体计算成本和carbon footprint。
预训练是从头开始训练模型的行为:权重随机初始化,训练在没有任何先验知识的情况下开始。
这种预训练通常是在非常大量的数据上完成的。因此,它需要非常大的数据语料库,并且训练可能需要长达数周的时间。
另一方面,微调是在模型经过预训练后进行的训练。要进行微调,您首先需要获得一个预训练的语言模型,然后使用特定于您的任务的数据集进行额外的训练。等等——为什么不直接为最终任务训练呢?有几个原因:
因此,微调模型具有更低的时间、数据、财务和环境成本。 迭代不同的微调方案也更快、更容易,因为训练比完全预训练的约束更少。
这个过程也会比从头开始训练获得更好的结果(除非你有大量数据),这就是为什么你应该总是尝试利用预训练模型——一个尽可能接近你手头任务的模型——并进行微调 它。
在本节中,我们将介绍 Transformer 模型的一般架构。 如果您不了解某些概念,请不要担心; 后面有详细的部分介绍了每个组件。
该模型主要由两个块组成:
这些部分中的每一个都可以独立使用,具体取决于任务:
我们将在后面的部分中独立深入研究这些架构。
Transformer 模型的一个关键特征是它们由称为注意力层的特殊层构建而成。事实上,介绍 Transformer 架构的论文的标题是《Attention Is All You Need》!该层将告诉模型在处理每个单词的表示时,特别注意您传递给它的句子中的某些单词(并或多或少忽略其他单词)。
考虑将文本从英语翻译成法语的任务。输入“You like this course”,翻译模型还需要注意相邻的单词“you”以获得单词“like”的正确翻译,因为在法语中动词“like”随主语的不同而变化。而句子的其余部分对于该词的翻译没有用处。同样,在翻译“this”时,模型还需要注意“course”这个词,因为“this”的翻译取决于相关名词是阳性masculine还是阴性feminine。同样,句子中的其他单词对于“this”的翻译无关紧要。对于更复杂的句子(和更复杂的语法规则),模型需要特别注意可能出现在句子中较远的单词以正确翻译每个单词。
相同的概念适用于与自然语言相关的任何任务:一个词本身就具有含义,但该含义深受上下文的影响,上下文可以是正在研究的单词之前或之后的任何其他单词(或多个单词)。
现在您已经了解了注意力层的全部内容,让我们仔细看看 Transformer 架构。
Transformer 架构最初是为翻译而设计的。在训练期间,编码器接收某种语言的输入(句子),而解码器接收所需目标语言的相同句子。在编码器中,注意力层可以使用句子中的所有单词(因为,正如我们刚刚看到的,给定单词的翻译可以依赖于句子中在它之后和之前的内容)。然而,解码器是按顺序工作的,并且只能关注它已经翻译的句子中的单词(因此,只有当前生成的单词之前的单词)。例如,当我们预测了翻译目标的前三个单词时,我们将它们提供给解码器,然后解码器使用编码器的所有输入来尝试预测第四个单词。
为了在训练过程中加快速度(当模型可以访问目标句子时),解码器被输入了整个目标,但不允许使用未来的词(如果它在尝试预测时可以访问位置 2 的词)位置 2 的词,问题不会很难!)。例如,当尝试预测第四个单词时,注意力层只能访问位置 1 到 3 中的单词。
最初的 Transformer 架构是这样的,左边是编码器,右边是解码器:
请注意,解码器块中的第一个注意力层关注解码器的所有(过去)输入,但第二个注意力层使用编码器的输出。 因此,它可以访问整个输入句子以最好地预测当前单词。 因为不同的语言语法规则不同,会将单词按不同的顺序排列,或者句子后面提供的某些上下文可能有助于确定给定单词的最佳翻译。
注意力掩码也可以用在编码器/解码器中,以防止模型注意一些特殊的词——例如,特殊的填充词用于在将句子批处理时使所有输入具有相同的长度。
当我们在本课程中深入研究 Transformer 模型时,您会看到架构和检查点以及模型的提及。 这些术语的含义略有不同:
Architectures:这是模型的骨架——每一层的定义和模型中发生的每个操作。
checkpoints:这些是将在给定架构中加载的权重。
Model:这是一个总称,不像“架构”或“检查点”那样精确:它可以同时表示两者。 当需要减少歧义时,本课程将指定架构或检查点。
例如,BERT 是一种 Architectures,而 bert-base-cased(谷歌团队为 BERT 的第一个版本训练的一组权重)是一个checkpoints。 但是,可以说“the BERT model”和“the bert-base-cased model”。
编码器模型仅使用 Transformer 模型的编码器。 在每个阶段,注意力层都可以访问初始句子中的所有单词。 这些模型通常被描述为具有“双向”注意力,并且通常被称为自动编码模型。
这些模型的预训练通常围绕着以某种方式破坏给定的句子(例如,通过屏蔽其中的随机单词)并让模型找到或重建初始句子。
编码器模型最适合需要理解完整句子的任务,例如句子分类、命名实体识别(以及更一般的单词分类)和提取式问答。
该系列模型的代表包括:
ALBERT
BERT
DistilBERT
ELECTRA
RoBERTa
解码器模型仅使用 Transformer 模型的解码器。 在每个阶段,对于给定的单词,注意力层只能访问句子中位于它之前的单词。 这些模型通常称为自回归模型。
解码器模型的预训练通常围绕预测句子中的下一个单词,最适合涉及文本生成的任务。
该系列模型的代表包括:
CTRL
GPT
GPT-2
Transformer XL
编码器-解码器模型(也称为序列到序列模型)使用 Transformer 架构的两个部分。 在每个阶段,编码器的注意力层可以访问初始句子中的所有单词,而解码器的注意力层只能访问位于输入中给定单词之前的单词。
这些模型的预训练可以使用编码器或解码器模型的目标来完成,但通常涉及更复杂的事情。 例如,T5 是通过用单个掩码特殊词替换随机文本跨度(可以包含多个单词)来预训练的,然后目标是预测该掩码替换的文本。
序列到序列模型最适合根据给定输入生成新句子的任务,例如摘要、翻译或生成式问答。
该系列模型的代表包括:
BART
mBART
Marian
T5
如果您打算在工作中使用预训练模型或微调版本,请注意,虽然这些模型是强大的工具,但它们也有局限性。 其中最重要的是,为了能够对大量数据进行预训练,研究人员通常会抓取他们能找到的所有内容,从互联网上可用的内容中选取最好的和最坏的。
为了快速说明,让我们回到带有 BERT 模型的填充掩码管道的示例:
from transformers import pipeline
unmasker = pipeline("fill-mask", model="bert-base-uncased")
result = unmasker("This man works as a [MASK].")
print([r["token_str"] for r in result])
result = unmasker("This woman works as a [MASK].")
print([r["token_str"] for r in result])
['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic']
['nurse', 'waitress', 'teacher', 'maid', 'prostitute']
当要求填写这两句话中缺失的单词时,模型只给出了一个不分性别的答案(服务员/女服务员)。 其他的是通常与一种特定性别相关的工作职业——是的,妓女最终出现在模型与“女人”和“工作”相关联的前 5 种可能性中。 尽管 BERT 是罕见的 Transformer 模型之一,但不是通过从互联网上抓取数据构建的,而是使用明显中性的数据(它在英语维基百科和 BookCorpus 数据集上训练),这种情况也会发生。
因此,当您使用这些工具时,您需要牢记您所使用的原始模型很容易产生性别歧视、种族主义或恐同内容。 根据您的数据对模型进行微调不会使这种内在偏差消失。
在本章中,您看到了如何使用 Transformers pipeline API 来处理不同的 NLP 任务。 您还了解了如何在 Hub 中搜索和使用模型,以及如何使用Inference API 直接在浏览器中测试模型。
我们讨论了 Transformer 模型如何高水平地工作,并讨论了迁移学习和微调的重要性。 您可以使用完整架构,也可以仅使用编码器或解码器,具体取决于您要解决的任务类型。 下表总结了这一点:
模型 | 例子 | 任务 |
---|---|---|
Encoder | ALBERT, BERT, DistilBERT, ELECTRA, RoBERTa | 句子分类、命名实体识别、抽取式问答 |
Decoder | CTRL, GPT, GPT-2, Transformer XL | 文本生成 |
Encoder-decoder | BART, T5, Marian, mBART | 摘要生成、翻译、生成式问答 |
第一节是本章目标和作者简介:
第二节介绍了transformer库不同任务的pipeline处理,以及Hosted inference API在线测试功能
第三节介绍了Transformers的历史(三种语言模型)、迁移学习的重要性以及Transformers基本结构、Architectures 和 checkpoints的概念。Attention layers关注某些单词(比如影响单词时态语态单复数等等)(并或多或少忽略其他单词)。
4.5.6.8节都是总结三种语言模型的代表模型及适用任务。第7 节介绍了此类模型预训练的限制和偏置,如性别歧视、种族主义或恐同内容等。
章节测试