查看: 2260|回复: 0

详解谷歌最强NLP模型BERT(理论+实战)

[复制链接]

44

主题

139

帖子

382

积分

论坛管理

Rank: 4

积分
382
发表于 2019-1-18 19:09:29 | 显示全部楼层 |阅读模式
导语

Google BERT 模型最近横扫了各大评测任务,在多项任务中取得了最好的结果,而且很多任务比之前最好的系统都提高了非常多,可以说是深度学习最近几年在 NLP的一大突破。但它并不是凭空出现的,最近一年大家都非常关注的 UnsupervisedSentence Embedding 取得了很大的进展,包括 ELMo 和 OpenAI GPT 等模型都取得了很好的结果。而 BERT 在它们的基础上改进了语言模型单向信息流的问题,并且借助 Google 强大的工程能力和计算资源的优势,从而取得了巨大的突破。

本文从理论和编程实战角度详细的介绍 BERT 和它之前的相关的模型,包括
Transformer 模型。希望读者阅读本文之后既能理解模型的原理,同时又能很快的把模型用于解决实际问题。本文假设读者了解基本的深度学习知识包括 RNN/LSTM、Encoder-Decoder 和 Attention 等。

Sentence Embedding 简介

前面我们介绍了 Word Embedding,怎么把一个词表示成一个稠密的向量。Embedding几乎是在 NLP 任务使用深度学习的标准步骤。我们可以通过 Word2Vec、GloVe 等从未标注数据无监督的学习到词的 Embedding,然后把它用到不同的特定任务中。这种方法得到的 Embedding 叫作预训练的 (pretrained)Embedding。如果特定任务训练数据较多,那么我们可以用预训练的 Embedding 来初始化模型的 Embedding,然后用特定任务的监督数据来 fine-tuning。如果监督数据较少,我们可以固定 (fix)Embedding,只让模型学习其它的参数。这也可以看成一种 Transfer Learning。

但是 NLP 任务的输入通常是句子,比如情感分类,输入是一个句子,输出是正向或者负向的情感。我们需要一种机制表示一个句子,最常见的方法是使用 CNN 或者 RNN 对句子进行编码。用来编码的模块叫作编码器 (Encoder),编码的输出是一个向量。和词向量一样,我们期望这个向量能够很好的把一个句子映射到一个语义空间,相似的句子映射到相近的地方。编码句子比编码词更加复杂,因为词组成句子是有结构的 (我们之前的 Paring 其实就是寻找这种结构),两个句子即使词完全相同但是词的顺序不同,语义也可能相差很大。

传统的编码器都是用特定任务的监督数据训练出来的,它编码的目的是为了优化具体这个任务。因此它编码出的向量是适合这个任务的——如果这个任务很关注词序,那么它在编码的使用也会关注词序;如果这个任务关注构词法,那么学到的编码器也需要关注构词法。

但是监督数据总是很少的,获取的成本也极高。因此最近 (2018 年上半年),无监督的通用 (universal) 的句子编码器成为热点并且有了一些进展。无监督的意思是可以使用未标注的原始数据来学习编码器 (的参数),而通用的意思是学习到的编码器不需要 (太多的)fine-tuning 就可以直接用到所有 (只是是很多) 不同的任务中,并且能得到很好的效果。

评测工具

在介绍 Unsupervised Sentence Embedding 的具体算法之前我们先介绍两个评测工具(平台)。

SentEval

  • 简介


Sentence Embedding(包括 Word Embedding) 通常有两类评价方法:intrinsic 和 ex-trinsic。前者只评价 Embedding 本身,比如让人来主观评价。而后者通过下游 (Downstream) 的任务间接的来评价 Embedding 的好坏。前一种方法耗费人力,而且我们学习 Embedding 的目的也是为了解决后面的真实问题,因此 extrinsic 的评价更加重要。但是下游的任务通常很复杂,Embedding 只是其中的一个环节,因此很难说明最终效果的提高就是由于 Embedding 带来的,也许只是某个预处理或者超参数的调节带来的提高,但是却可能被作者认为是 Embedding 的功劳。另外下游任务很多,很多文章的结果也很难比较。

为了解决这些问题,Facebook 做了 SentEval 这个工具。这是一个用于评估Universal Sentence Representation 的工具,所谓的 Universal Sentence Representation是指与特定任务无关的通用的句子表示 (Embedding) 方法。为了保证公平公正,这个工具只评价句子的 Embedding,对于具体的任务,大家都使用相同的预处理,网络结构和后处理,从而能够保证比较公平的评测。

SentEval 任务分类

SentEval 任务分为如下类别:

  • 分类问题 (包括二分类和多分类)
  • Natural Language Inference
  • 语义相似度计算
  • 图像检索 (Image Retrieval)




分类很简单,输入是一个字符串 (一个句子或者文章),输出是一个分类标签。所以任务如图17.1所示。包括情感分类、句子类型分类等等任务。

Natural Language Inference(NLI) 任务也叫 recognizing textual entailment(RTE),它的输入是两个句子,需要机器判断第一个句子和第二个句子的关系。它们的关系通常有 3 种:矛盾 (contradiction)、无关 (neutral) 和蕴含 (entailment)。

SNLI(https://nlp.stanford.edu/projects/snli/) 是很常用的 NLI 数据集,示例是来自这个数据集的例子。比如下面的两个句子是矛盾的:

A man inspects the uniform of a figure in some East Asian country.
The man is sleeping.

一个人不能同时在观察和睡觉。而下面两个句子的关系是无关的:

A smiling costumed woman is holding an umbrella.
A happy woman in a fairy costume holds an umbrella.

而下面两个的第一个句子蕴含了第二个句子:
A soccer game with multiple males playing.
Some men are playing a sport.

语义相似度计算的输入是两个句子,输出是它们的相似度,一般相似度会分为几个程度,所以输出也是标签。当然最简单的是分成两类——相似与不相似,比如MRPC 就是这样的任务,这个任务又叫 Paraphrase Detection,判断两个句子是否同义复写。

Image Retrieval 的输入是一幅图片和一段文字,如果文字能很好的描述图片的内容,那么输出一个高的分值,否则输出低分。

SentEval 包括的 NLI 和图像检索任务如图17.2所示。


图 17.2: SentEval 的 NLI 和 Image Retrieval 任务

SentEval 的用法

SentEval 依赖 NumPy/SciPy、PyTorch(>=0.4.0) 和 scikit-learn(>=0.18.0)。

然后从https://github.com/facebookresearch/SentEval.git clone 代码。SentEval 提供了一些baseline 系统,包括 bow、infersent 和 skipthought 等等。读者如果实现了一种新的Sentence Embedding 算法,那么可以参考 baseline 的代码用 SentEval 来评价算法的好坏。

我们这里只介绍最简单的 bow 的用法,它就是把 Pretraining 的 Word Embedding加起来得到 Sentence Embedding。

我们首先下载 fasttext 的 Embedding:



然后运行:



main 函数代码为:




首先构造 senteval.engine.SE,然后列举需要跑的 task,最后调用 se.eval 得到结果。

构造 senteval.engine.SE 需要传入 3 个参数,params_senteval, batcher 和 prepare。params_senteval 是控制 SentEval 模型训练的一些超参数。比如 bow.py 里的:



而后两个参数是函数,我们先看 prepare:



这个函数相当于初始化的回调函数,参数会传入 params 和 samples,samples 就是所有的句子,我们需要根据这些句子来做一些初始化的工作,结果存在 params 里,后面会用到。这里我们用 samples 构造 word2id——word 到 id 的映射,另外根据word2id,从预训练的词向量里提取需要的词向量 (因为预训练的词向量有很多词,但是在某个具体任务中用到的词是有限的,我们只需要提取需要的部分),另外把词向量的维度保持到 params 里。

batcher 函数的输入参数是前面的 params 和 batch,batch 就是句子列表,我们需要对它做 Sentence Embedding,这里的实现很简单,就是把词向量加起来求平均值得到句子向量。





回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表