写在前面:本文主要参考了张俊林等大神的文章,这里对其相关文章进行了更精简的总结整理和扩充,更多内容请详见文末的参考文献,尊重原创。
——口天丶木乔

0. NLP简介

0.1 NLP任务特点

截屏2020-02-16下午12.05.03.png

  • NLP的输入往往是一句话或者一篇文章,所以它的输入是个一维线性序列;
  • 输入是不定长的,有的长有的短,而这点其实对于模型处理起来也会增加一些小麻烦;
  • 单词或者子句的相对位置关系很重要,两个单词位置互换可能导致完全不同的意思。

    0.2 NLP任务类别

    截屏2020-02-16下午12.07.02.png

  • 序列标注。这是最典型的NLP任务,比如中文分词,词性标注,命名实体识别,语义角色标注等都可以归入这一类问题,它的特点是句子中每个单词要求模型根据上下文都要给出一个分类类别;

  • 分类任务。比如我们常见的文本分类,情感计算等都可以归入这一类。它的特点是不管文章有多长,总体给出一个分类类别即可;
  • 句子关系判断,比如Entailment,QA,语义改写,自然语言推理等任务都是这个模式,它的特点是给定两个句子,模型判断出两个句子是否具备某种语义关系;
  • 生成式任务,比如机器翻译,文本摘要,写诗造句,看图说话等都属于这一类。它的特点是输入文本内容后,需要自主生成另外一段文字。

    1. RNN

    2014
    截屏2020-02-18上午9.53.05.png

    1.1 为何RNN能成为NLP中的主流特征处理器

    RNN的结构天然适配解决NLP的问题,NLP的输入往往是个不定长的线性序列句子,而RNN本身结构就是个可以接纳不定长输入的由前向后进行信息线性传导的网络结构,而在LSTM引入三个门后,对于捕获长距离特征也是非常有效的。所以RNN特别适合NLP这种线形序列应用场景,这是RNN为何在NLP界如此流行的根本原因。

    1.2 RNN在新时代面临的问题

  • 特殊改造的CNN模型,以及最近特别流行的Transformer,这些后起之秀尤其是Transformer的应用效果相比RNN来说,目前看具有明显的优势。

  • RNN本身的序列依赖结构对于大规模并行计算来说相当之不友好。通俗点说,就是RNN很难具备高效的并行计算能力。

    1.3 为何RNN并行计算能力比较差

    我们知道,RNN之所以是RNN,能将其和其它模型区分开的最典型标志是:T时刻隐层状态的计算,依赖两个输入,一个是T时刻的句子输入单词Xt,这个不算特点,所有模型都要接收这个原始输入;关键的是另外一个输入,T时刻的隐层状态St还依赖T-1时刻的隐层状态S(t-1)的输出,这是最能体现RNN本质特征的一点,RNN的历史信息是通过这个信息传输渠道往后传输的,示意参考上图。那么为什么RNN的并行计算能力不行呢?问题就出在这里。因为T时刻的计算依赖T-1时刻的隐层计算结果,而T-1时刻的计算依赖T-2时刻的隐层计算结果,这样就形成了所谓的序列依赖关系。就是说只能先把第1时间步的算完,才能算第2时间步的结果,这就造成了RNN在这个角度上是无法并行计算的,只能老老实实地按着时间步一个单词一个单词往后走。
    截屏2020-02-16上午11.45.26.png
    而CNN和Transformer就不存在这种序列依赖问题,所以对于这两者来说并行计算能力就不是问题,每个时间步的操作可以并行一起计算。

    1.4 RNN并行化改造思路拓展

    2. CNN

    2.1 CNN怀旧版

    最早将CNN引入NLP的是Kim在2014年做的工作(Convolutional neural networks for sentence classification):
    截屏2020-02-18上午9.44.05.png

  • 输入层。一般而言,输入的字或者词用Word Embedding的方式表达,这样本来一维的文本信息输入就转换成了二维的输入结构,假设输入X包含n个字符,而每个字符的Word Embedding的长度为d,那么输入就是d*n的二维向量。

  • 卷积层:抽取特征。卷积层本质上是个特征抽取层,可以设定超参数F来指定卷积层包含多少个卷积核(Filter)。对于某个Filter来说,可以想象有一个d*k大小的移动窗口从输入矩阵的第一个字开始不断往后移动,其中k是Filter指定的窗口大小,d是Word Embedding长度。对于某个时刻的窗口,通过神经网络的非线性变换,将这个窗口内的输入值转换为某个特征值,随着窗口不断往后移动,这个Filter对应的特征值不断产生,形成这个Filter的特征向量。这就是卷积核抽取特征的过程。卷积层内每个Filter都如此操作,就形成了不同的特征序列。
  • Pooling(池化)层:特征降维。选择卷积核中的最大值或取平均等操作进行特征降维,形成最终的特征。一般在Pooling层之后连接全联接层神经网络,形成最后的分类过程。

存在问题:

  • 卷积层问题。只有一个卷积层,表面看上去好像是深度不够的问题是吧?我会反问你说:为什么要把CNN作深呢?其实把深度做起来是手段,不是目的。只有一个卷积层带来的问题是:对于远距离特征,单层CNN是无法捕获到的,如果滑动窗口k最大为2,而如果有个远距离特征距离是5,那么无论上多少个卷积核,都无法覆盖到长度为5的距离的输入,所以它是无法捕获长距离特征的,为解决这一问题,后来出现了多个改进CNN模型,下面会提到。

截屏2020-02-18上午10.02.18.png

  • Max Pooling层问题。前面提到过,NLP任务最大的特点之一就是输入特征之间的相对位置信息很重要,CNN的卷积核是能保留特征之间的相对位置的,道理很简单,滑动窗口从左到右滑动,捕获到的特征也是如此顺序排列,所以它在结构上已经记录了相对位置信息了。但是如果卷积层后面立即接上Pooling层的话,Max Pooling的操作逻辑是:从一个卷积核获得的特征向量里只选中并保留最强的那一个特征,所以到了Pooling层,位置信息就被扔掉了,这在NLP里其实是有信息损失的。所以在NLP领域里,目前CNN的一个发展趋势是抛弃Pooling层,靠全卷积层来叠加网络深度,这背后是有原因的(当然图像领域也是这个趋势)。

    2.2 CNN改进版

    为解决怀旧版CNN无法捕获远距离特征的问题,最典型的两个改进版模型:

  • Dilated CNN。仍然用单个卷积层,滑动窗口大小k假设为3,就是只接收三个输入单词,但是我们想捕获距离为5的特征,怎么做才行?显然,可以跳着覆盖,这就是Dilated 卷积的基本思想。

截屏2020-02-18上午10.09.50.png

  • Deep CNN。把深度做起来。第一层卷积层,假设滑动窗口大小k是3,如果再往上叠一层卷积层,假设滑动窗口大小也是3,但是第二层窗口覆盖的是第一层窗口的输出特征,所以它其实能覆盖输入的距离达到了5。如果继续往上叠加卷积层,可以继续增大卷积核覆盖输入的长度。

截屏2020-02-18上午10.11.01.png

  • Dilated CNN偏技巧一些,而且叠加卷积层时超参如何设置有些学问,因为连续跳接可能会错过一些特征组合,所以需要精心调节参数搭配,保证所有可能组合都被覆盖到,相对而言,把CNN作深是主流发展方向。自从CNN一出现,人们就想各种办法试图把CNN的深度做起来,但做到2到3层卷积层就做不上去了,网络更深对任务效果没什么帮助(请不要拿CharCNN来做反例,后来研究表明使用单词的2层CNN效果超过CharCNN)。目前看来,还是深层网络参数优化手段不足导致的这个问题,而不是层深没有用。后来Resnet等图像领域的新技术出现后,很自然地,人们会考虑把Skip Connection及各种Norm等参数优化技术引入,这才能慢慢把CNN的网络深度做起来。

目前主流CNN框架:
image.png
通常由卷积层来叠加深度,使用Skip Connection(残差连接)来辅助优化,也可以引入Dilated CNN等手段。比如ConvS2S主体就是上图所示结构,Encoder包含 15个卷积层,卷积核kernel size=3,覆盖输入长度为25。当然对于ConvS2S来说,卷积核里引入GLU门控非线性函数也有重要帮助,限于篇幅,这里不展开说了,GLU貌似是NLP里CNN模型必备的构件,值得掌握。再比如TCN(论文:An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence Modeling),集成了几项技术:利用Dilated CNN拓展单层卷积层的输入覆盖长度,利用全卷积层堆叠层深,使用Skip Connection辅助优化,引入Casual CNN让网络结构看不到T时间步后的数据。不过TCN的实验做得有两个明显问题:一个问题是任务除了语言模型外都不是典型的NLP任务,而是合成数据任务,所以论文结论很难直接说就适合NLP领域;另外一点,它用来进行效果比较的对比方法,没有用当时效果很好的模型来对比,比较基准低。所以TCN的模型效果说服力不太够。其实它该引入的元素也基本引入了,实验说服力不够,我觉得可能是它命中缺GLU吧。

2.3 CNN位置编码及并行计算

  • CNN的卷积层其实是保留了相对位置信息的,只要你在设计模型中间层不要随手瞎插入Pooling层,问题就不大,不专门在输入部分对position进行编码也行。但是也可以类似ConvS2S那样,专门在输入部分给每个单词增加一个position embedding,将单词的position embedding和词向量embedding叠加起来形成单词输入,这样也可以,也是常规做法。
  • 至于CNN的并行计算能力,那是非常强的,这其实很好理解。我们考虑单层卷积层,首先对于某个卷积核来说,每个滑动窗口位置之间没有依赖关系,所以完全可以并行计算;另外,不同的卷积核之间也没什么相互影响,所以也可以并行计算。CNN的并行度是非常自由也非常高的,这是CNN的一个非常好的优点。

    3. Transformer

    请参考我的另一篇博文,其中对transformer进行了详细讲解,这里就不再细述了。

    4. 三者性能比较

  • RNN无法实现并行能力,RNN本身的根本特质是:T时刻隐层节点对前向输入及中间计算结果的序列依赖,因为它要线形序列收集前面的信息,这是RNN之所以是RNN的最主要特点。但也因此RNN可以捕获长距离信息。

  • CNN和transformer都可以较好的并行化,早期的CNN做不好NLP的一个很大原因是网络深度做不起来,随着不断借鉴图像处理的新型CNN模型的构造经验,以及一些深度网络的优化trick,CNN在NLP领域里的深度逐步能做起来了。而既然深度能做起来,那么本来CNN做NLP天然的一个缺陷:无法有效捕获长距离特征的问题,就得到了极大缓解。目前看可以靠堆深度或者结合dilated CNN来一定程度上解决这个问题,虽然还不够好,但是仍然是那句话,希望还在。
  • Transformer在并行能力、长距离信息捕获都有较大优势。不过存在较为明显的缺点,对于长输入的任务,典型的比如篇章级别的任务(例如文本摘要),因为任务的输入太长,Transformer会有巨大的计算复杂度,导致速度会急剧变慢。Transforme-XL最新论文一定程度解决了这部分问题。Transformer复杂结构为什么有效果还没有坚实的理论依据,这在经验大于理论的AI领域也算是极为常见了。Transformer进一步发展空间:结构较为复杂,如何简化?为何对于距离远与13的长距离特征,Transformer性能弱于RNN?Bert对Transformer的优化。

    参考文献

  1. 放弃幻想,全面拥抱Transformer:自然语言处理三大特征抽取器(CNN/RNN/TF)比较
  2. Convolutional neural networks for sentence classification