在Introduction中,将会包含以上四项内容的介绍。
在下边这些章节中,将会学习如下:
pipeline()
函数解决NLP任务,比如文本生成和文本分类encoder
、decoder
、encoder-decoder
架构及其使用案例介绍Transformer模型之前,先对NLP做一个简要概述。
简单来说,NLP任务就是要理解人类所表达的内容,包括语言、文字、语音等内容。常见的NLP任务如下:
NLP并不局限于文本领域,在语音识别和计算机视觉中也有其身影,比如:根据图像生成文本内容的描述。
计算机处理信息的方式不同于人类大脑。人类所说的语言可能有多种含义,我们可以轻松地排除,确定其所要表达的内涵,而对于机器学习模型来说,想要准确理解语言所表达的内容是很困难的,即语义理解极为困难,这也是当前NLP领域面临的一大难题。
Transformer
模型广泛应用于各种NLP任务当中,比如2.1节中提到的任务。
pipeline()
函数是Transformers library
最基础的对象,其将模型和必要的预处理和后处理步骤连接起来,允许我们直接输入文本得到清晰明确的结果。如下:
from transformers import pipeline
# 创建分类器对象
classifier=pipeline('sentiment-analysis')
classifier("I've been waiting for a HuggingFace course my whole life.")
[{‘label’: ‘POSITIVE’, ‘score’: 0.9598050713539124}]
也可以输入多个句子
classifier(
["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"]
)
[{‘label’: ‘POSITIVE’, ‘score’: 0.9598050713539124},
{‘label’: ‘NEGATIVE’, ‘score’: 0.9994558691978455}]
这里,选择已经预训练好的模型,并且在英语sentiment analysis(情感分析)
上进行了微调。创建分类器对象时下载并缓存模型,如果重新执行该语句,将使用缓存的模型,无需再次下载。
将输入文本传递到pipeline
时主要涉及如下三个步骤:
在这里可获得pipelines
如下:
这里从对尚未标记的样本进行分类任务开始,这是实际当中最常见的场景,因为标注不仅需要专业领域知识,而且时间、人力成本都很高。
在这个例子中,zero-shot-classification pipeline
非常强大,允许指定用于分类的标签,所以不必依赖于预训练模型的标签。在sentiment-analysis
中,可以把文本分类为positive 或negative
,而这里,可以使用任何喜欢的标签集对文本进行分类。
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]}
该pipeline
调用zero-shot
,无需根据数据微调模型,并且直接返回想要的任何标签列表的概率分数。
这里使用pipeline()
生成文本,主要思想就是提供一个prompt
,模型通过生成剩余的文本对其进行补全。文本生成涉及到随机性,所以生成的结果可能和如下不一致。
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 use the following technologies in a self defense weapon, to use their abilities effectively. We will be discussing the use of 3rd person perspective. We will have more examples of some of the concepts described above’}]
也可以使用参数num_return_sequences
控制生成多少个不同的序列以及使用参数max_length
控制输出文本的总长度。
上边的示例使用了默认模型,但也可以从Hub中选择特定模型用于pipeline,例如文本生成任务。到Model Hub中点击左侧对应标签会展示支持该任务的模型,如下图:
这里使用distilgpt2模型,下面是使用pipeline()
对distilgpt2
的加载。
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 make a better value system for you. Each lesson will be based on the interests of your clients’”},
{‘generated_text’: ‘In this course, we will teach you how to identify and identify the many common problems with your project. Please note, though, that we are not’}]
这里也可以通过点击language
标签来优化对模型的搜索,然后选择一个模型以用来生成另一种语言的文本。Model Hub
包含支持多种语言的多语言模型检查点。
unmasker=pipeline("fill-mask")
unmasker("This course will teach you all about models." ,top_k=2)
[{‘score’: 0.1961972862482071,
‘token’: 30412,
‘token_str’: ’ mathematical’,
‘sequence’: ‘This course will teach you all about mathematical models.’},
{‘score’: 0.04052707925438881,
‘token’: 38163,
‘token_str’: ’ computational’,
‘sequence’: ‘This course will teach you all about computational models.’}]
top_k
参数控制想要显示几种可能性结果。注意,这里对于空缺的位置填充了
,称之为掩码标记。其他的mask-filling
模型或许有不同的掩码标记,在探索其他模型时,验证正确的mask
词总是有益的。
NER(命名实体识别)是一项给定输入文本,找出其中对应的实体,比如人、位置或组织类别的实体。
from transformers import pipeline, AutoModelForTokenClassification, AutoTokenizer
model = AutoModelForTokenClassification.from_pretrained("dbmdz/bert-large-cased-finetuned-conll03-english")
tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
ner=pipeline("ner", model=model, tokenizer=tokenizer,grouped_entities=True)
ner("My name is Sylvain and I work at Hugging Face in Brooklyn.")
[{‘entity_group’: ‘PER’,
‘score’: 0.9981694,
‘word’: ‘Sylvain’,
‘start’: 11,
‘end’: 18},
{‘entity_group’: ‘ORG’,
‘score’: 0.9796019,
‘word’: ‘Hugging Face’,
‘start’: 33,
‘end’: 45},
{‘entity_group’: ‘LOC’,
‘score’: 0.9932106,
‘word’: ‘Brooklyn’,
‘start’: 49,
‘end’: 57}]
模型识别出Sylvain 是人(PER),Hugging Face是一个组织(ORG),Brooklyn是一个位置(LOC)。
通过在pipeline()
中添加grouped_entities=True
将句子中对应于同一实体的部分重新组合在一起,这里将"Hugging"和“Face”重组为一个组织。
事实上,后面小结中,预处理就可以将一些单词分为更小的部分。例如,Sylvain可以分为四部分:S,##yl,##va,和##in。后处理步骤中,pipeline
成功将这些pieces
(片)组合。
QA pipeline使用从上下文获取的信息来回答问题。
from transformers import pipeline
qa=pipeline("question-answering")
qa(
question="Where do I work?",
context="My name is Sylvain and I work at Hugging Face in Brooklyn"
)
{‘score’: 0.6949760913848877, ‘start’: 33, ‘end’: 45, ‘answer’: ‘Hugging Face’}
注意到,pipeline是从提供的上下文中提取信息的,并不生成答案。
Summarization将文本缩减为更短的文本,同时保留文本中重要内容信息。
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’: ’ China and India graduate six and eight times as many traditional engineers as the U.S. as does other industrial countries . America suffers an increasingly serious decline in the number of engineering graduates and a lack of well-educated engineers . There are declining offerings in engineering subjects dealing with infrastructure, infrastructure, the environment, and related issues .'}]
类似于text generation
,可以指定结果的max_length或min_length
。
这里使用Model Hub中的Helsinki-NLP/opus-mt-zh-en
模型来完成翻译任务。
from transformers import pipeline
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-zh-en")
translator("我叫舒城,我住在上海松江区。")
[{‘translation_text’: ‘My name is Shu City. I live in Songjiang District in Shanghai.’}]
类似于text generatio
和summarization
,也可以指定max_length
和min_length
。
pipeline()
的基本用法就如上述,下边将深入介绍pipeline()
功能。
这里,简要介绍Transformer
模型架构。
Transformer架构诞生于2017年,最初其被应用于翻译任务。以下是应用Transformer架构的一些模型:
以上模型并不是全部,广义上讲,可以将这些模型分为三个类别:
auto-regressive Transformer models
,自回归Transformer模型)auto-encoding Transformer models
,自编码Transformer模型)sequence-to-sequence Transformer models
,序列-to-序列Transformer模型)以上涉及到的所有Transformer模型均为语言模型。这意味着这些模型以self-supervised(自监督)方式在大量原始文本上进行了训练。所谓自监督就是一种训练类型,其目标是根据模型输入自动计算的,不需要人类对数据进行标注。这些类型的语言模型可以对其训练过的语言产生好的理解,但对于特定的实际任务并不是很有用,因此,一般预训练模型都会经过一个称之为迁移学习的过程,在此过程中,模型以监督方式在给定标签的特定数据集上进行微调,即预训练+微调范式。
一个任务的例子就是根据先前阅读的n个单词,预测下一个单词是什么。这称之为causal language modeling
,因为输出取决于过去和当前输入,而不是未来的输入。
另一个例子就是masked language modeling
(遮蔽语言建模),即预测一个句子中被掩盖的单词是什么。
除DistliBERT
之外,要使模型获得更好的性能一般性策略就是增加模型大小以及预训练使用的数据量。
不幸的是,训练一个大模型,需要大量数据,这在时间和计算资源上都很昂贵。这甚至可以转化为对环境的影响,如下图所示:
该图展示了一个一个由团队领导的大型模型项目,团队有意识地减少预训练对环境的影响,可以看到,运行大量实验以获得最佳超参数其二氧化碳排放量会更多。
可以想象,如果研究团队、学生组织或公司想要训练一个模型,都是从头开始的,这势必会导致巨大的、不必要的时间和计算成本的浪费。
这也是为什么共享语言模型如此重要:共享经过训练的权重,可以降低训练成本,减少对环境的影响。
预训练是从零开始训练一个模型:权重随机初始化、训练开始时没有任何先验知识。
另一方面,Fine-tuning
是在模型预训练之后的训练。首先需要获得一个预训练语言模型,然后使用特定任务的带有标签的数据集进行额外训练,即fine-tuning
。这里解释一下为什么要分两步进行,而不是一步到位直接训练达到目的。
例如,可以利用经过英语训练的预训练模型,在arXiv语料库上对齐进行fine-tuning,从而生成基于科学/研究的模型。fine-tuning只需要少量数据:预训练模型获得的知识是可以迁移的,因此称之为迁移学习。
因此,fine-tuning模型具有更少的时间、数据、钱和环境成本。迭代不同的fine-tuning方案也更快、更容易,于完整的预训练相比,训练的约束条件更少。
Transformer主要由两个blocks
组成:
encoder和decoder
都可以独立使用,具体取决于任务。
Transformer模型的一个关键特性就是由一个称之为attention layer
的特殊层所构建。详细内容可在其原始论文"Attention is All You Need!"查阅。现在,我们需要知道的是,在处理每个单词的表示时,该层会告诉模型特别注意传递给它的句子中的某些单词(或多或少的忽略其他单词)(类似于人的注意力,集中于感兴趣的地方)。
这里举一个例子,考虑文本从英语翻译成法语的任务。给定输入”You like this course",翻译模型需要关注相邻的词"You"来获得"like"这个词的正确翻译,因为在法语中,动词"like"的变位方式不同,具体取决于主题。然而,对于该词的翻译没有用处。同样,在翻译"this"时,模型还需要注意"course"这个词,因为"this"的翻译取决于相关连的名词是男性还是女性,同样,句子中的其他词对于"this"的翻译无关紧要。对于复杂的句子(复杂的语法规则),模型需要特别注意可能出现在句子中更远的单词,以正确翻译每个单词。
相同的概念适用于自然语言相关的其他任何任务:一个词本身具有含义,但也受到上下文影响,上下文可以是当前的词或之前/之后的任何其他词(或多个词)。
Transformer架构最初是为翻译任务而设计。训练期间,编码器接收某种语言的输入(句子),解码器接收目标语言的相同句子。在编码器中,注意力层可以使用句子中的所有单词(给定单词的翻译可能取决于句子中的前后内容)。然而,解码器是按顺序工作的,只能关注到已经翻译部分的单词。例如,当预测了翻译目标的前三个词时,将它们提供给解码器,然后解码器使用编码器的所有输入来尝试预测第四个词。
为加速训练过程(模型可以访问目标句子),将整个目标句子输入到decoder,但不允许使用未来的单词(如果在尝试预测位置2处的单词可以访问位置2处的单词,就相当于考试作弊)。例如,当尝试预测第四个单词时,注意力层只能访问位置1到3的单词。
原始Transformer架构如下,左侧为Encoder,右侧为Decoder。
注意到,解码器块中的第一个注意力层关注解码器过去所有输入,但第二个注意力层使用编码器的输出。因此,它可以访问整个句子以最好的预测当前单词。这非常有用,因为不同语言其语法规则不同,单词的顺序也不尽相同。有助于根据上下文确定单词的最佳翻译。
注意力掩码也在encoder/decoder中使用,以防止模型注意到某些特殊词。例如,在批处理句子时,特殊填充词用于使 所有输入句子具有相同的长度。
这里,对Architectures和checkpoints两个术语进行一下说明,
例如,BERT是一种架构,而Bert-base-cased(Google团队为BERT第一个版本训练的一组权重)是一个checkpoints
。但是,可以说"BERT模型"和"基于BERT的模型“。
Encoder模型仅使用Transformer模型的编码器。在每个阶段,attention layer
可以访问初始句子中的所有单词。这些模型通常被描述为具有“bi-directional”(双向)注意力,通常将其称为auto-encoding
(自编码器)模型。
Encoder模型的预训练通常围绕以某种方式破坏给定的句子(例如,随机掩盖句子中的单词)并让模型找到被掩盖的单词或重建原始句子。
编码器模型最适合于需要理解整个句子的任务,比如句子分类、命名实体识别以及抽取式问答等。典型的模型代表如下:
Decoder模型只包含Transformer模型中的decoder部分。在每个阶段,对于给定的单词,attention layer
只能访问句子中位于该次前边的单词,这些模型通常称之为auto-regressive
(自回归)模型。
Decoder模型的预训练通常围绕预测句子中的下一个单词进行。其最适合于文本生成类任务。Decoder模型的典型代表有如下:
Encoder-Decoder模型(也称作sequence-to-sequence模型)使用Transformer架构的两部分。每个阶段,编码器的注意力层可以访问初始句子的所有单词,而解码器的注意力层只能访问输入中给定单词之前的单词。
尽管预训练模型使用超大规模数据进行训练,参数规模也极大,所学习到的知识是极为丰富的,但不可避免的存在一定的局限性。
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’]
当填写这两个句子中的缺失词时,模型只给出了一个不区分性别的答案(waiter/waitress)。其他则是通常与一种特定性别相关的工作职业,prostitute
最终成为"women"和”work"相联系起来的一种可能性,这显然不是模型的想要的目标。即使经过预训练+微调之后,这种缺陷仍然不能避免。
在这里,了解了Transformers
中的pipeline()
函数的使用,可以用来处理不同的NLP任务。同时我们也讨论了迁移学习和微调的重要性,以及如何根据任务需要选择不同的模型架构,总结如下表:
Model | Example | Tasks |
---|---|---|
Encoder | ALBERT,BERT,DistilBERT,ELECTRA,RoBERTa | Sentence classification,NER,extractive question answering |
Decoder | CTRL,GPT,GPT-2,TransformerXL | Text generation |
Encoder-Decoder | BART,T5,Marian,mBART | Summarization,translation,generative question answering |