图解 2018 年领先的两大 NLP 模型:BERT 和 ELMo

转载来源

公众号:新智元

来源:jalammar.github.io

作者:Jay Alammar

编译:肖琴

阅读本文大概需要 11 分钟。

谷歌推出 BERT 模型被认为是 NLP 新时代的开始,NLP 终于找到了一种方法,可以像计算机视觉那样进行迁移学习。本文用图解的方式,生动易懂地讲解了 BERT 和 ELMo 等模型。

2018 年已经成为自然语言处理机器学习模型的转折点。我们对如何以最能捕捉潜在意义和关系的方式、最准确地表示单词和句子的理解正在迅速发展。

此外,NLP 社区开发了一些非常强大的组件,你可以免费下载并在自己的模型和 pipeline 中使用。

ULM-FiT 跟甜饼怪没有任何关系,但我想不出其它的了...

最新的一个里程碑是 BERT 的发布,这一事件被描述为 NLP 新时代的开始。BERT 是一个 NLP 模型,在几个语言处理任务中打破了记录。在描述模型的论文发布后不久,该团队还公开了模型的源代码,并提供了已经在大量数据集上预训练过的下载版本。

这是一个重大的进展,因为任何需要构建语言处理模型的人都可以将这个强大的预训练模型作为现成的组件使用,从而节省了从头开始训练模型所需的时间、精力、知识和资源。

图示的两个步骤显示了 BERT 是如何运作的。你可以下载步骤 1 中预训练的模型(在未经注释的数据上训练),然后只需在步骤 2 中对其进行微调。

BERT 建立在最近 NLP 领域涌现的许多聪明方法之上——包括但不限于半监督序列学习(作者是 Andrew Dai 和 Quoc Le)、ELMo (作者是 Matthew Peters 和来自 AI2 和 UW CSE 的研究人员)、ULMFiT (作者是fast.ai创始人Jeremy Howard和Sebastian Ruder),OpenAI transformer (作者是 OpenAI 研究员 Radford、Narasimhan、Salimans 和 Sutskever),以及 Transformer (作者是 Vaswani et al .)。

要正确理解 BERT 是什么,我们需要了解一些概念。让我们先看看如何使用 BERT,然后再看模型本身涉及的概念。

例子:句子分类

最直接的使用 BERT 的方法就是使用它来对单个文本进行分类。这个模型看起来是这样的:

要训练一个这样的模型,主要需要训练分类器,在训练阶段对 BERT 模型的更改非常小。这种训练过程称为微调 (Fine-Tuning),并且具有半监督序列学习 (Semi-supervised Sequence Learning) 和 ULMFiT 的根源。

具体来说,由于我们讨论的是分类器,这属于机器学习的监督学习范畴。这意味着我们需要一个标记数据集来训练模型。比如说,对于一个垃圾邮件分类器,标记数据集是一个电子邮件列表及其标签(将每封电子邮件标记为“垃圾邮件”或“非垃圾邮件”)。

模型架构

现在,你已经有了一个如何使用 BERT 的示例用例,接下来让我们进一步了解它是如何工作的。

论文中提供了两种尺寸的 BERT 模型:

  • BERT BASE - 大小与 OpenAI Transformer 相当
  • BERT LARGE - 一个非常庞大的模型,实现了最先进的结果

BERT 基本上是一个训练好的 Transformer Encoder 堆栈。Transformer模型是 BERT 的一个基本概念,我们将在下文中讨论。

这两种 BERT 模型都有大量的编码器层(论文中称之为 Transformer Blocks) —— Base 版本有 12 层,Large 版本有 24 层。它们也比初始论文里的 Transformer 的默认配置 (6 个编码器层,512 个隐藏单元,8 个 attention heads) 有更大的前馈网络(分别为 768 个和 1024 个隐藏单元), attention heads (分别为 12 个和 16 个)。

模型输入

第一个输入 token 是一个特殊的 [CLS]token,这里的 CLS 代表分类。

就像 transformer 的普通编码器一样,BERT 以一串单词作为输入。每一层应用 self-attention,并通过前馈网络传递其结果,然后将结果传递给下一个编码器。

在架构方面,到目前为止,这与 Transformer 完全相同(除了大小之外,不过大小是我们可以设置的配置)。在输出端,我们才开始看到两者的区别。

模型输出

每个位置输出大小为 hidden_size 的向量(BERT Base 中为 768)。对于上面看到的句子分类示例,我们只关注第一个位置的输出(我们将那个特殊的 [CLS] 标记传递给它)。

这个向量可以作为我们选择的分类器的输入。论文中利用单层神经网络作为分类器,取得了很好的分类效果。

如果你有更多的标签(例如,如果是电子邮件,你可以将邮件标记为“垃圾邮件”、“非垃圾邮件”、“社交”和“促销”),只需调整分类器网络,使其有更多的输出神经元,然后通过 softmax。

与卷积网络的相似之处

对于具有计算机视觉背景的人来说,这种向量传递的方式很容易让人联想到 VGGNet 之类的网络的卷积部分与网络末端完全连接的分类部分之间的事情。

嵌入的新时代

这些新进展带来了词汇编码方式的新变化。词汇嵌入一直是领先的 NLP 模型处理语言的主要能力。Word2Vec、Glove 等方法已广泛应用于此类任务。让我们先回顾一下如何使用它们。

词汇嵌入的回顾

对于要由机器学习模型处理的单词,它们需要以某种数字形式表示,以便模型可以在其计算中使用。Word2Vec 表明我们可以用一个向量(一个数字列表)以捕捉语义或意义关系(如判断单词的近义、反义关系)、以及语法或语法关系(例如, “had” 和 “has” 、“was” and “is”有同样的语法关系)的方式恰当地表示单词。

研究人员很快发现,使用经过大量文本数据进行预训练的嵌入 (embeddings) 是一个好主意,而不是与小数据集的模型一起训练。因此,通过使用 Word2Vec 或 GloVe 进行预训练,可以下载单词列表及其嵌入。如下图是单词 “stick” 的 GloVe 嵌入示例(嵌入向量大小为 200)

单词 “stick” 的 GloVe 嵌入

因为这些向量很大,并且数字很多,所以本文后面用下面这个基本图形来表示向量:

ELMo:上下文很重要

如果我们使用 GloVe 表示,那么不管上下文是什么,“stick” 这个词都会由这个向量表示。很多研究人员就发现不对劲了。“stick” 有多种含义,取决于它的上下文是什么。那么,为什么不根据它的上下文给它一个嵌入呢——既要捕捉该上下文中的单词含义,又要捕捉其他上下文信息?因此,语境化的词嵌入 (contextualized word-embeddings) 就出现了。

语境化词嵌入可以根据单词在句子的上下文中表示的不同含义,给它们不同的表征

ELMo 是对每个单词使用固定的嵌入,而是在为每个单词分配嵌入之前查看整个句子。它使用针对特定任务的双向 LSTM 来创建嵌入。

ELMo 为 NLP 中的预训练提供了重要的一步。ELMo LSTM 在大型数据集上进行训练,然后我们可以将其用作所处理语言的其他模型中的组件使用。

ELMo 的秘诀是什么?

ELMo 通过训练预测单词序列中的下一个单词来获得语言理解能力——这项任务被称为语言建模。这很方便,因为我们有大量的文本数据,这样的模型可以从这些数据中学习,不需要标签。

ELMo 预训练的一个步骤

我们可以看到每个展开的 LSTM 步骤的隐藏状态从 ELMo 的头部后面突出来。这些在预训练结束后的嵌入过程中会派上用场。

ELMo 实际上更进一步,训练了双向 LSTM——这样它的语言模型不仅考虑下一个单词,而且考虑前一个单词。

ELMo 通过将隐藏状态(和初始嵌入)以某种方式组合在一起(连接后加权求和),提出语境化词嵌入。

ULM-Fit:NLP 中的迁移学习

ULM-FiT 引入了一些方法来有效地利用模型在预训练期间学到的知识——不仅是嵌入,也不仅是语境化嵌入。ULM-FiT 提出了一个语言模型和一个流程 (process),以便针对各种任务有效地优化该语言模型。

NLP 终于找到了一种方法,可以像计算机视觉那样进行迁移学习。

Transformer:超越 LSTM

Transformer 的论文和代码的发布,以及它在机器翻译等任务上取得的成果,开始使一些业内人士认为 Transformers 是 LSTM 的替代品。而且,Transformer 在处理长期以来性方便比 LSTM 更好。

Transformer 的编码器-解码器结构使其非常适合于机器翻译。但是如何使用它来进行句子分类呢?如何使用它来预训练可以针对其他任务进行微调的语言模型(在 NLP 领域,使用预训练模型或组件的监督学习任务被称为下游任务)。

OpenAI Transformer:为语言建模预训练 Transformer 解码器

事实证明,我们不需要一个完整的 Transformer 来采用迁移学习,也不需要为 NLP 任务采用一个可微调的语言模型。我们只需要 Transformer 的解码器。解码器是一个很好的选择,因为它是语言建模(预测下一个单词)的首选,因为它是为屏蔽未来的 token 而构建的——在逐字生成翻译时,这是一个有用的特性。

OpenAI Transformer 由 Transformer 的解码器堆栈组成

模型堆叠了 12 个解码器层。由于在这种设置中没有编码器,这些解码器层将不会有普通 transformer 解码器层所具有的编码器-解码器注意力子层。但是,它仍具有自注意层。

通过这个结构,我们可以继续在相同的语言建模任务上训练模型:使用大量(未标记的)数据集预测下一个单词。只是,我们可以把足足 7000 本书的文本扔给它,让它学习!书籍非常适合这类任务,因为它允许模型学习相关信息,即使它们被大量文本分隔——假如使用推特或文章进行训练,就无法获得这些信息。

OpenAI Transformer 用由 7000 本书组成的数据集进行训练,以预测下一个单词。

将学习转移到下游任务

既然 OpenAI transformer 已经经过了预训练,并且它的层已经被调优以合理地处理语言,那么我们就可以开始将其用于下游任务。让我们先来看看句子分类(将邮件分为“垃圾邮件”或“非垃圾邮件”):

如何使用预训练的 OpenAI transformer 来进行句子分割

OpenAI 论文中概述了一些用于处理不同类型任务输入的输入转换。下图描绘了模型的结构和执行不同任务的输入转换。

这是不很是聪明?

BERT:从解码器到编码器

OpenAI transformer 为我们提供了一个基于 Transformer 的可微调预训练模型。但是在从 LSTM 到 Transformer 的转换过程中缺少了一些东西。ELMo 的语言模型是双向的,而 OpenAI Transformer只 训练一个正向语言模型。我们能否建立一个基于 transformer 的模型,它的语言模型既考虑前向又考虑后向(用技术术语来说,“同时受左右上下文的制约”)?

BERT 聪明的语言建模任务遮盖了输入中 15% 的单词,并要求模型预测丢失的单词。

找到合适的任务来训练 Transformer 的编码器堆栈不容易,BERT 采用了 “masked language model” 的概念(文献中也成为完形填空任务)来解决这个问题。

除了遮盖 15% 的输入,BERT 还混入了一些东西,以改进模型后来的微调方式。有时它会随机地将一个单词替换成另一个单词,并要求模型预测该位置的正确单词。

两句话任务

如果你回顾 OpenAI transformer 处理不同任务时所做的输入转换,你会注意到一些任务需要模型说出关于两个句子的一些信息(例如,它们是否只是同件事情的相互转述?假设一个维基百科条目作为输入,一个关于这个条目的问题作为另一个输入,我们能回答这个问题吗?)

为了让 BERT 更好的处理多个句子之间的关系,预训练过程增加了一个额外的任务:给定两个句子 (A 和 B), B 可能是 A 后面的句子,还是 A 前面的句子?

BERT 预训练的第二个任务是一个两句话分类任务。

特定任务的模型

BERT 的论文展示了在不同的任务中使用 BERT 的多种方法。

BERT 用于特征提取

fine-tuning 方法并不是使用 BERT 的唯一方法。就像 ELMo 一样,你可以使用经过预训练的 BERT 来创建语境化的单词嵌入。然后,你可以将这些嵌入提供给现有的模型——论文中证明了,在诸如名称-实体识别之类的任务上,这个过程产生的结果与对 BERT 进行微调的结果相差不远。

哪个向量最适合作为语境化化嵌入?我认为这取决于任务。论文考察了 6 个选项(与得分 96.4 的 fine-tuned 模型相比):

结语

试用 BERT 的最佳方式是通过使用托管在谷歌 Colab 上的 Cloud TPUs notebook 的 BERT FineTuning。如果你以前从未使用过云 TPU,那么这也是一个很好的起点,可以尝试使用它们。BERT代码也适用于 TPU、CPU 和 GPU。

下一步是查看 BERT repo 中的代码:

  • 该模型是在 modeling.py(BertModel类)中构建的,与原始 Transformer 编码器完全相同。
  • run_classifier.py 是 fine-tuning 过程的一个示例。它还构建了监督模型的分类层。如果要构建自己的分类器,请查看文件中的 create_model() 方法。
  • 有几个预训练模型可供下载。包括 BERT Base 和 BERT Large,以及英语,中文等语言的单语言模型,以及涵盖 102 种语言的多语言模型,这些语言在维基百科上训练。
  • BERT 不是将单词看作 token。相反,它关注的是词块 (WordPieces)。tokennization.py 是将单词转换成适合 BERT 的 WordPieces 的工具。

BERT 也有 PyTorch 实现。AllenNLP library 使用这个实现,允许在任何模型中使用 BERT 嵌入。

原文:https://jalammar.github.io/illustrated-bert/

原文发布于微信公众号 - 进击的Coder(FightingCoder)

原文发表时间:2018-12-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券