BERT and It's family

大名鼎鼎的芝麻街

预训练语言模型的缩写大可能是芝麻街的人物。这显然是起名艺术大师们的有意为之。他们甚至均可以抛弃用首字母缩写的原则去硬凑出芝麻街人名php

上图所示的模型(除了Big Bird,由于没有这个模型)他们之间都有一些共同点,就是能经过一个句子的上下文来给一个词进行Embedding,而能达到这种目的的网络架构有不少,例如LSTM,Self-attention layers,Tree-based model(注重文法,通常表现不佳,只有在文法结构很是严谨的状况下表现好)等等html

Smaller Model

预训练语言模型比来比去,变得愈来愈巨大,愈来愈臃肿,愈来愈玩不起。然而,让模型变小,就比如咱们去到非洲,可让人民币在一线城市的购买力变得更多。这就是穷人用的 BERT。例如Distill BERTTiny BERTMobile BERTQ8BERTALBERTgit

授人以鱼不如授人以渔,究竟有哪些方法可使Model变小呢?能够参考李宏毅老师模型压缩的视频讲解,以及All The Ways You Can Compress BERT这篇文章。常见的方法有如下几种github

  • Network Pruning 剪枝
  • Knowledge Distillation 知识蒸馏
  • Parameter Quantization 参数量化
  • Architecture Design 结构设计

Network Architecture Improvements

除了模型压缩之外,近年来比较火的尝试还有模型架构的设计。比方说Transfomer-XL经过理解跨片断的内容,能够处理很是长的序列;ReformerLongformer可使得自注意力的复杂度变小,从 O ( N 2 ) O(N^2) O ( N l o g N ) O(NlogN) 甚至更低markdown

How to Fine-tune

这一部分李宏毅老师讲了很是多,但我我的感受有不少都是比较简单的内容。比方说输入一个句子如何进行分类,这个你们其实作的都比较多了,常见的作法就是利用[CLS]的输出后面跟一个线性分类层,又或者是将全部token的输出求一个Average,再送入线性分类层。上述两种方法的目的都是要作分类,可是它们的本质区别在于究竟用什么东西来表明一个句子的Embedding比较好,关于这个能够看一下Sentence-BERT的论文,或者是Sentence-BERT详解这篇文章,里面有一些实验证实了用哪些东西表明一个句子的向量比较好网络

Extraction-based QA

可能你们见的很少的是如何利用预训练模型作Extraction-based QA (Question Answering)任务架构

比方说如今将一篇文档和一个问题丢入QA Model,模型会输出两个整数 s s e e ,这两个整数表明这个问题的答案就是文档中第 s s 个词到第 e e 个词,即 { d s , . . . , d e } \{d_s,...,d_e\} app

获得这两个整数的方式也颇有意思。首先咱们生成两个向量(上图中橙色和蓝色),用其中一个(橙色)向量去和document全部位置的输出作一个dot product,以后再通过一个Softmax获得一系列几率值,咱们取最大几率值所在的下标(其实就是argmax)就获得了答案的开始位置 s = 2 s=2 ide

答案的结束位置 e e 获得的方式也差很少,就是用另外一个(蓝色)向量去和document全部位置的输出作一个dot product,一样通过Softmax以后获得几率最大值所在的下标。那么最终答案就是 [ s , e ] [s,e] 这个区间内的单词oop

回到主题,预训练语言模型要如何进行微调呢?一种方法是固定预训练的模型,让它做为一个特征提取器,训练的时候,只更新后面接的Task-specific模型的参数;另外一种方法是不固定预训练语言模型的参数,全部参数在训练过程当中都进行更新。不过就我本人作过的不少实验来看,后者效果是比前者好的,可是问题在于,不少预训练模型特别大,常常11G的显存都不够,因此不得不采用前一种方法

Combination of Features

咱们知道BERT有不少Encoder Layer,你们常规的作法都是提取最后一层的输出来作下游任务,但实际上这是最优解吗?其实就有人在NER任务上作过一个实验,将不一样层的输出进行各类组合,获得的效果以下

肖涵在 Github 上建立了一个名为 bert-as-service 的开源项目,该项目旨在使用 BERT 为您的文本建立单词嵌入。他尝试了各类方法来组合这些嵌入,并在项目的 FAQ 页面上分享了一些结论和基本原理

肖涵的观点认为:

  1. 第一层是嵌入层,因为它没有上下文信息,所以同一个词在不一样语境下的向量是相同的
  2. 随着进入网络的更深层次,单词嵌入从每一层中得到了愈来愈多的上下文信息
  3. 可是,当您接近最后一层时,词嵌入将开始获取 BERT 特定预训练任务的信息(MLM 和 NSP)
  4. 使用倒数第二层比较合理

Why Pre-train Models?

为何咱们要使用这些预训练的模型?一个很明显的道理是,咱们没那么多钱去从头训练一个比较大的模型,因此直接拿别人训练好的来用就好了

固然,EMNLP 2019的一篇文章Visualizing and Understanding the Effectiveness of BERT从学术角度仔细分析了为何要使用预训练模型,文章代表,预训练模型能够大大加速损失的收敛,而不使用预训练模型,损失比较难降低。能够理解为,预训练模型提供了一种比随机初始化更好的初始化

另外一个结论是,预训练模型能够大大增长模型的泛化能力。上图表示给模型不一样参数时,模型训练后结束点的损失会抵达一个local minima的位置。这个local minima的位置越陡峭,则泛化能力越差,由于输入稍微变化,它的损失就会有很大的变更;反之,这个local minima越平缓,则泛化能力越强

ELMo

ELMo是目前来讲比较知名的双向网络。传统的LSTM只是从左往右过一遍句子,那预测下一个token所依赖的信息就只能取决于它左边的内容,为了能真正利用这个token的上下文,咱们能够从右到左再过一遍句子,即BiLSTM。但实际上还不够,由于当模型在encode w 1 , w 2 , w 3 , w 4 w_1,w_2,w_3,w_4 的时候,它没看到句子后面的部分;而在encode w 5 , w 6 , w 7 w_5,w_6,w_7 的时候,也没考虑到句子前面的部分,因此ELMo在底层进行编码的时候并非真正的双向。而在上层,因为两边的embedding进行了concat,此时它才同时看到了双向的信息

BERT

对于Transformer类模型(典型表明就是BERT),自注意力机制使得它可以同时看到上下文,每个token两两之间都能交互,惟一要作的只是随机地把某个token用[MASK]遮住就能够了

若是你回溯历史,回到Word2vec刚刚掀起NLP革命的时候,你会发现CBOW的训练方式和BERT几乎同样,它们的主要区别在于,BERT能关注的范围长度是可变的,而CBOW的范围是固定的

Whole Word Masking (WWM)

随机地mask掉某个token效果是否真的好呢?对于中文来讲,词是由多个字组成的,一个字就是一个token。若是咱们随机mask掉某个token,模型可能不须要学到不少语义依赖,就能够很容易地经过前面的字或后面的字来预测这个token。为此咱们须要把难度提高一点,盖住的不是某个token,而是某个词(span),模型须要学到更多语义去把遮住的span预测出来,这即是BERT-wwm。同理,咱们能够把词的span再延长一些,拓展成短语级别、实体级别(ERNIE)

SpanBERT

还有一种BERT的改进叫SpanBERT。它每次会盖住 n n 个token,其中 n n 是根据上图所示的几率获得的。实验结果发现,这种基于几率选择盖住多少个token的方式在某些任务上要更好一些

SpanBERT还提出了一种名为Span Boundary Objective (SBO)的训练方法。通常咱们训练只是把masked的tokens给训练出来。而SBO但愿经过被盖住范围的左右两边的输出,去预测被盖住的范围内有什么样的东西。如上图所示,将 w 3 w_3 w 8 w_8 的输出以及一个索引送入后续的网络中,其中这个索引表示咱们但愿预测的是span中哪一个位置的词

XLNet

关于XLNet更详细的讲解能够看这篇博客。简单来讲,XLNet认为BERT类模型训练和测试阶段不统一(训练阶段有[MASK]token,测试阶段没有),所以可能会存在某些问题。若是从Autoregressive的角度去看XLNet,其实就是将输入打乱顺序做为输入,而后从左往右预测下一个token。若是以AutoEncoder (BERT)的角度去看XLNet,咱们但愿根据[MASK]左边或者右边的信息去预测[MASK]位置的词。与BERT不一样的地方在于,XLNet的输入没有[MASK]的存在

MASS / BART

BERT类模型缺少生成句子的能力,因此它不太适合作Seq2Seq的任务,而MASS和BART这两个模型就解决了BERT不擅长生成的问题。咱们首先把一个句子输入到Encoder,咱们但愿Decoder的output就是Encoder的input,但有一点要注意的是,咱们必须将Encoder的input作必定程度的破坏,由于若是没有任何破坏,Decoder直接将Encoder的输入copy过来就好了,它可能学不到什么有用的东西

MASS的作法是,把输入的一些部分随机用[MASK]token遮住。输出不必定要还原完整的句子序列,只要能把[MASK]的部分预测正确就能够了

在BART的论文中,它又提出了各式各样的方法,除了给输入序列随机mask之外,还能够直接删除某个token,或者随机排列组合等。关于BART更详细的讲解能够看这篇文章

UniLM

还有一个模型叫UniLM,它既能够是编码器,也能够是解码器,还能够是Seq2Seq。UniLM由不少Transformer堆叠,它同时进行三种训练,包括BERT那样做为编码器的方式、GPT那样做为解码器的方式、MASS/BART那样做为Seq2Seq的方式。它做为Seq2Seq使用时,输入被分为两个片断,输入第一个片断的时候,该片断上的token之间能够互相注意,但第二个片断,都只能看左边token

ELECTRA

预测一个东西须要的训练强度是很大的,ELECTRA想要简化这件事情,转为二分类问题,判断输入的某个词是否被随机替换了

但问题来了,怎样把一些词进行替换,同时保证文法没错,语义也不是那么奇怪的句子呢?由于若是token被替换成了一些奇怪的东西,模型很容易就能发现,ELECTRA就学不到什么厉害的东西了。论文用了另外一个比较小的BERT去输出被mask的单词,这里不须要用很好的BERT,由于若是BERT效果太好,直接就输出了和原来一摸同样的单词,这也不是咱们指望的。这个架构看上去有点像GAN,但实际上它并非GAN,由于GAN的Generator在训练的时候,要骗过Discriminator。而这里的small BERT是本身训练本身的,只要把被mask的位置预测出来就行了,至于后面的模型预测的对不对和它没有关系

ELECTRA训练效果很惊人,在相同的预训练量下,GLUE上的分数比BERT要好不少,并且它只须要1/4的运算量就能够达到XLNet的效果

T5

预训练语言模型须要的资源太多,不是普通人随便就能够作的。谷歌有篇论文叫T5,它展示了谷歌庞大的财力和运算资源,这篇文论把各式各样的预训练方法都尝试了一次,而后获得了一些结论,让别人没有研究可作

Reference

相关文章
相关标签/搜索