前言
语义匹配是NLP领域的基础任务之一,直接目标就是判断两句话是否表达了相同或相似意思。其模型框架十分简洁,通常包含文本表示和匹配策略两个模块,因而很容易扩展到相关应用场景,如搜索、推荐、QA系统等。此类模型通常依赖数据驱动,即模型的效果需要高质量的数据作为基础,而在医疗领域,文本数据的质量不光依赖语法,还要求相对严谨的实体描述,因而对数据的要求更为严格,也为模型训练调整增添了困难。
联系到丁香园团队的在线问诊、病症查询、医疗推荐等业务场景,我们希望能构建更高质量的语义表征模型,一方面对于文本中的疾病症状等实体词足够敏感,另一方面能够捕获长距离的组合信息。通过在语义匹配任务上的尝试,积累语义模型的特点,从而在各个具体应用场景下,针对性地构建模型结构。本文介绍了丁香园大数据团队在医疗文本数据上,对语义匹配这一基础任务的实践。首先简单介绍早期的文本特征表示方法,然后列举几种Representation-Based和Interaction-Based的模型,最后介绍实践中的一些细节。
传统文本表示
经典的匹配模型普遍采用某种基于bow的统计文本表示,例如tf-idf和bm25,这类方法普遍存在两个问题,一是维数太高,二是丢失了context的特征。2013年的Word2Vec的出现改变了文本表示的方式,利用文本的context token训练每个token的低维度向量表示,使向量本身包含语义信息,此后成为文本类任务的主流预训练手段。
在对比传统方式和word2vec的效果后,丁香园也逐渐用词向量作为各个业务场景中的文本表示,并在此基础上,不断挖掘更深层的文本表示学习,语义匹配模型则是重要的探索方向。
模型介绍
常见的语义匹配模型有两种设计的思路:基于表示(Representation-Based)和基于交互(Interaction-Based)
Representation-Based Model
基于表示的模型很直接,就是用一个Encoder模块提取本文的特征信息,以可计算的数值向量输出,最后一层计算两个向量的匹配程度,可接一层MLP,也可直接算余弦相似。很明显这类模型的关键是中间Encoder模块的设计,目标是设计强大的特征提取器,在Encoder部分获得文本的语义表示。
Interaction-Based Model
基于交互的模型认为,只用孤立的Encoder模块是不够的,而两个文本交互匹配本身就会产生有关匹配程度的信息,利用好这个信息可以提升模型的匹配能力。基于这个设想,再加上attention机制的流行,语义模型就开始变得复杂了。下面将列举几个有代表性的网络结构。
DSSM
DSSM是非常经典的语义模型,是标准的Representation-Based的结构模版,模型本身效果很好,且极易修改或扩展,因而广泛应用在相关业务场景中。Encoder部分,DSSM采用了MLP,在此基础上的扩展通常也是将MLP换成CNN或RNN结构,顶层直接计算cos,各部分都相对容易实现。不过,原文选用了BOW模型作为文本的表示方式,虽然也加入了trigrams等策略,但仍不可避免会失去词的context信息。此外,原文采用了point-wise的loss,我们团队在搜索精排序阶段尝试改进了DSSM,用RNN替换了MLP,并采用triplet loss训练模型,并与多种Encoder+point-wise-loss对比,结构显示了triplet loss在排序任务上有更大的优势。
SiameseRNN
孪生网络(Siamese network)是一类网络结构,其特点是Encoder共享权重。Encoder可根据需要替换。这里以RNN为例,是因为RNN结构的特性。DSSM结尾处提到了词的context信息,虽然词向量是利用context训练得到,但文本序列的词序信息仍需要Encoder捕捉,而RNN类结构本身就具有捕捉序列信息的能力,因此在语义匹配任务中,RNN常常会比CNN有更好的效果。这也是很多文本任务的模型会在Embedding层上加Bi-RNN的原因。
不过RNN类模型训练耗时长,并行困难,这对科研调试和产业应用都不友好,特别对于应用落地,时间开销太大,再好的模型也没法上线。当然关于RNN并行也有很多相关研究,SRU和Sliced RNN应该是两种代表性的改进方式,不过仍然难以比拟天生就适合并行的CNN和Transformer。
TextCNN
上面提到了RNN具备提取词序信息的能力,其实就是说每个词和其前后的内容并不独立出现,但CNN是一个个窗口,窗口间的计算并不关联,如何用CNN抽取词序信息呢?本文是Kim在2014年发表的,代表性的CNN做文本特征提取的工作。原文模型用于句子分类任务,基本思路就是,让一个窗口的大小刚好装下k个词,对这种窗口的卷积操作就相当于抽取了k个词共同表达的信息,也起到了抽取词序信息的作用。不过这种CNN结构存在两个明显的问题,一是k的取值通常很小,意味着文中采用的单层CNN无法提取长序列的信息;二是文中的CNN包含max pooling操作,对于k个词对应的向量,池化操作只保留一个最大的值,这势必会丢掉一些信息,因此目前也有许多针对性的CNN改进策略,下一节将介绍CNN的改进以及与RNN,Transformer的对比。
Transformer
Transformer的出现应该是NLP界的大新闻,除了在机器翻译任务上超越了Seq2seq外,霸气的文章标题也令人记忆犹新。正如该题目所述,Transformer给了人们CNN和RNN外的其他选择。这里针对语义匹配,我们只关注其中的Encoder部分。全文的重点是self-attention,通过这种attention计算,让文本序列中的每个词都和序列本身建立联系,计算过程非常简单。其中Q,K,V都是文本序列本身,分母上的sqrt(dk)作用是缓解Q和K的dot计算出现过大的值。不难想象,分子上的dot(Q,K)操作计算了序列中每个词与其他词之间的相似度,softmax对这一结果做归一化,得到的就是序列对自身的权重。此外,文中提到了多次计算self-attention对特征提取是有帮助的,因此Encoder采用了Multi-Head Attention机制,多个self-attention独立的计算,原文采用了base和big两种结构,分别对应12和24个self-attention块,更宽更深的模型在文中的实验里取得了更好的效果,并且,由于self-attention本身计算不慢,又相互独立,这使得Multi-Head机制很容易并行操作。
当然,整个Encoder不光包含Multi-Head Attention,Transformer如此有效,或许跟Block结构本身也有很大关系,完全可以尝试将Multi-Head Attention替换成CNN或RNN结构,针对不同应用场景很可能会有奇效。
ESIM
上述的结构都是完全关注Encoder的Representation-Based Model,而事实上Interaction-Based Model早已成为此类任务的主流设计思路。一方面对比融合不同输入的信息符合人们的常识,另一方面诸如attention等融合机制所提供的改进的确在很多任务中表现出色。下面将介绍两个在文本分类,文本匹配等比赛中频频夺魁的模型,首先是ESIM。
该模型专门为自然语言推理而设计,结构上并不复杂,重点是在两层Bi-LSTM间加入了interaction计算,文中称作 local inference modeling ,其实就是利用了 soft attention 计算两个文本的匹配矩阵,可以认为这个矩阵中包含了两个文本的交互信息。之后这个矩阵和两个Embedding后的输入文本做差和点基,再做concat,就得到增强后的文本特征向量。
当然,本文还有其他创新点,例如在句法分析类问题上可以用Tree-LSTM替换Bi-LSTM,不过这里重点关注提取interaction信息的结构设计。类似 soft attention 的结构已经是众多Interaction-Based Model的标配,计算量不大,实现简单,对模型的效果提升也很客观,是个性价比很高的trick。相比之下,两个Bi-LSTM层的计算耗时要显著的长。
BiMPM
BiMPM是和ESIM类似的Interaction-Based Model,interaction计算上下均有一层Bi-LSTM,不过作者在interaction计算上花了很多心思,并非简单采用 soft attention ,而是同时用4种匹配策略。此模型在quora question pairs数据集上测试accuracy达到88,比当时最好的[L.D.C.]模型高3个点,比Siamese-LSTM高6个点。在类似文本匹配的比赛中,BiMPM和ESIM的表现也非常突出,也能一定程度上说明不同的interaction计算策略对匹配效果有不小的帮助。
不过,这两个模型都有一个明显的缺点————慢,而小数据集又无法发挥它们的效果,所以训练调参的过程会很耗时。像是quora question pairs数据集提供了40W对训练样本,不平衡程度也不大(正负比 3:5),这时两个模型效果都不错,这也印证了数据驱动的重要性。
实践体会
TextCNN的局限和改进
上节提到,TextCNN通过调整卷积窗口来提取序列context信息,但是卷积窗口一次毕竟只能提取k个词的组合信息,这样仍然无法处理长序列。为了在长序列问题上比肩RNN,一个直接的应对方式就是堆叠层数,也是目前相对主流的方法,反正CNN计算比RNN快得多,多加几层也没什么问题。
话虽如此,但直接堆叠TextCNN的效果并不理想,业界也衍生出了不少对TextCNN结构的改进,这里笔者将介绍Facebook AI Research提出的ConvS2S结构。本文对应着Transformer,二者都是Seq2seq结构的改进,因此ConvS2S的Encoder完全可以用于文本匹配等任务。就Encoder模块而言,ConvS2S为了有效堆叠CNN做出了两处改进,GLU(Gated Linear Units)和残差连接(Residual Connections),使用glu作为非线性运算可以优化梯度传播,后者residual结构则为了保留了输入序列的信息。这样的修改可以帮助增加卷积层的深度,一定程度上提升CNN在序列任务上的特征提取能力,同时相比于RNN类模型,模型耗时和并行能力的优势依旧存在。笔者尝试用ConvS2S替换TextCNN,叠加5层后模型效果有明显提升,仅从Encoder模块对比,可以与LSTM效果持平,当然这样的对比无法证明CNN可以通过叠加取代RNN,毕竟实验结果与本文数据的关系更大,不过至少说明CNN仍然有改进的潜力。
Positional Embedding
CNN除了面对长序列乏力外,还存在一个问题,就是编码序列时会丢掉position信息。由于RNN是按时序处理序列的,所以序列的位置信息自然会被编码进状态变量中,但CNN做不到,尤其是卷积过后用pooling操作降维会损失的更严重,相同的问题transformer中也存在,看self-attention的公式很容易理解,每个词的地位是完全相同的,计算出的权重只和当前参与计算的两个词有关。因此,在ConvS2S和Transformer的文章中都提出了额外补充位置信息的策略,被称作 position embedding 。
ConvS2S提出的编码策略很简单,就是加一个类似词向量的位置向量参与训练,在模型训练过程中把位置向量也学出来;transformer则提出一种傅立叶变换生成词的位置编码,作者表示这种计算得到的结果与训练出的位置向量基本一致,但生成过程是一个确定的公式,不必训练生成。
对于这两种 position embedding 方法,笔者的实践结果并不好。学习位置向量相当于加了一层网络,完全寄希望与网络学习能力,可能在数据量充足的情况下会有效果(BERT也用了这种学习策略),但小数据集的条件下想要学习出这组参数其实难度很大。至于Transformer配合使用的生成公式,也有不少人从信号系统角度出发给出相应解释,不过笔者认为说服力并不足够,这种生成方式本身是不是合理,以及是否与语言语法相关都值得商榷,不过好在计算很快,训练时加一组对比实验开销也不大。
总而言之,笔者认为,序列数据中存在位置信息这个设想是有道理的,对于非RNN类的提取器,如何更好的抽取这类信息,也是值得关注的方向,这里link一篇包含相关工作的(https://arxiv.org/pdf/1803.02155.pdf)供大家学习参考。
Encoder组合
其实对于语义匹配这个任务,不同领域的数据源,不同的任务需求才是影响模型的关键因素,寄希望于sota得到的结果往往令人失望,原因也很好理解,大部分sota的成果都是针对一两个数据集做优化,其目的也是验证某些结构或trick的可行性,并不意味着sota等价于万能。因此在尝试过包括LDC,ESIM,BiMPM在内的十余种模型后,我们专门尝试了简单的编码器以及编码器组合的对比实验。
首先是用Representation-Based的结构,对比CNN,RNN,Transformer的效果。实验结果仍然是RNN最好,CNN用了ConvS2S的Encoder并堆叠层数后可以逼近RNN的结果,Transformer的效果则不理想。笔者认为,CNN虽然可以靠层数增强长序列捕捉能力,但毕竟增强有限,这篇文章(https://arxiv.org/pdf/1808.08946v1.pdf)中对三种编码器的长序列特征捕捉能力做了比较,实验结果说明了CNN在此方面仍然有所不足。不过该文章中Transformer的能力应该是强于RNN的,这与笔者的实验结果不符,其原因在于笔者这里实验所用的数据量不足,以及Transformer的模型不够"重"。其实Transformer的强力早已在OpenAI-GPT一文中被展现,去年10月的BERT更是再次证明这一模型的强大,只是由于header的数量会极大影响Transformer的性能,所以在小数据集上单纯靠Transformer可能会让人失望。
对比这三类编码器后,我们也尝试了组合RNN和CNN,或在Encoder间加入attention提升模型,根据组合实验,我们认为Embedding层后首先用RNN的效果通常比较好,在RNN之上加CNN是有帮助的,不过用attention计算匹配矩阵的提升似乎更大。这里的组合方式都是最简单的拼接,或是向量线性运算,实现很容易,并且在数据集不大的条件下,结果也能逼近甚至超越ESIM,BiMPM这种强力模型。
BERT
最后介绍一下BERT,相信入坑超过半年的NLPer一定都知道BERT的威名,2018年10月一经问世立刻刷新了各个榜单,现如今搭载BERT的模型已经成为了榜单上的标配。网上关于模型本身的解读非常多,因此这里重点介绍下在小数据集上的语义匹配的实验过程。模型本身的结构非常简单,就是秉承深度模型理念的,做深做宽的巨型Transformer,即便是Base版,原始的模型尺寸也是显存无法接受的存在,笔者尝试过精简模型参数后自己做模型预训练,效果比直接用官方完成预训练的中文模型差很多,所以如果不是既有海量语料又有足够资源,还是不建议自己预训练的。看模型结构在文中的占比就能感受到,巨型Transformer甚至都不是文章的重点,全文最着重描述的其实是BERT的pre-training思路,下面将尽量详细的介绍两个任务的训练过程。
预训练有两个任务:第一个是预测句子中的词,也就是训练文中的 MLM(Masked LM) ,如上图所示,模型的输入包含3种embedding,token,segment和position,其中的token和position好理解,与ConvS2S中的word embedding + position embedding是一回事,segment是和token中的[SEP]是为第二个任务服务的,我们稍后在介绍。首先为什么要用双向Transformer训练MLM呢,作者的解释大概可以总结成"为了训练足够深的双向模型",这里对比的就是OpenAI-GPT的单向模型以及ELMo的两个单向的concat。那训练MLM到底是如何做呢,说白了就是随机的遮挡住句子中的某些词(用[MASK]替换),让模型去预测这些词,不过作者也提到了,fine-tuning时文本中是没有[MASK]的,这和预训练时模型遇到的输入不同,为了缓解这种差异带来的影响,作者仅取15%的token,且以0.8的概率遮挡,0.1的概率保持不变,0.1的概率随便换一个词,原文提到,模型不知道那个词是被mask的还是被replace的,所以能force to学习每个输入的context信息,并且由于被replace的词仅有1.5%,因此不会降低模型的效果。
第二个任务是预测下一个句子,先解释segment是和token中的[SEP],BERT中每行input都是由两句话拼成的,两句话间用[SEP]分割,第一句开头是[CLS],第二句结尾是[SEP],segment就是input每个位置属于第一句还是第二句,第一句的位置index都是0,第二句都是1。源码中,两个句子分别对应变量token_a和token_b,其中token_b的构造也有trick,每句都以50%的概率替换成随机某一篇文档中的随机某句话。这个任务其实是为了让模型学习到句间关系,文中的实验结果对比显示了此任务对模型的提升(在QNLI数据集上accuracy提高4个点)
以上就是两个关键的预训练的设计,完成后,BERT提供了一个输出层,针对不同任务,只需要对该层稍作修改即可,可以参考文中给出的结构图。这里不得不说,BERT不仅效果好,源码也很友好,想迁移到自己的任务上,只需要实现对应的数据处理类,调整模型输出层即可,即便是想在bert后接自己的模型,也只需要取到transformer最后一层作为自己模型的输入。这里需要注意,对于中文任务,官方的预训练是在字向量基础上做的,字典也必须用官方提供的,需要按词分的话就不得不重新预训练了,不过修改成分词的数据生成代码也只需要简单做几行改动,不过通常字典的size只是万级(BERT中文语料来自维基百科,字典大小21128),而常用的语料中词典的大小至少有几十倍大,恐怕BERT这种预训练方式也难以收敛。
从ELMo到BERT,语言理解模型可能是2018年NLP领域最耀眼的成果。2013年的Word2Vec之于NLP可谓功勋卓著,它本身就有预训练的思路,但word embedding层面的trick还不够满足任务需求,并且一直以来NLP领域的模型总是做不深,即便是ELMo尝试堆叠Bi-LSTM,也只有3层,而且3层的时间开销已经让大部分团队难以接受,直到Transformer被OpenAI-GPT验证了有堆叠提升的潜力,紧接着BERT再次证明了Transformer的能力,同时也证明了深度模型的潜能。从工程角度出发,NLP的标注数据通常不易得,而这种利用大规模无标注数据做预训练的方法无疑大大降低成本,小团队或个人也有机会利用少量数据和计算资源fine-tuning出满足需求的模型。
总结
作为nlp领域的基础任务,语义匹配模型可以根据应用场景灵活调整,但核心都是挖掘文本序列特征的表示学习。为此,我们希望能把握不同结构中细节的作用,以便在不同任务场景中移植。同时,丁香园也在逐渐适应深度学习模型应用落地,在搜索的精排序阶段,大数据团队尝试接入改进后的LSTM-DSSM,利用Bi-LSTM的长序列捕捉能力,并采用triplet-loss训练模型,同时在召回阶段,我们也在探索改进CNN和Transformer以提高召回质量。此外,BERT源码易读,fine-tuning成本低,模型迁移性好,我们目前的实践结果也证明其在业务中的潜力,因此,我们未来也会跟进BERT工程化的工作。
另一方面,这次BERT的成功很大程度上是依靠新颖的预训练策略,以及对无标注语料的探索,近期OpenAI-GPT2.0的成功似乎也证明了高质量数据驱动的能量巨大。然而对于医疗场景而言,准确性和严谨性是重中之重,依靠数据驱动是远远不够的,这更需要基于图谱的知识表示和推理的复杂技术,结合数据驱动和专业信息来共同实现知识表示和语言理解,从而提供安全准确的医疗智能服务。
本文原创首发于【丁香园自然语言处理】,团队专注于互联网医疗领域的自然语言处理,利用NLP(自然语言处理)、Knowledge Graph(知识图谱)、Deep Learning(深度学习)等技术,处理丁香园海量医学文本数据,打通电商、在线问诊、健康知识、社区讨论等各个场景数据,构建医学知识图谱,搭建通用NLP服务。团队会总结整理近期阅读的NLP相关论文并应用于实际的业务场景中,提供满满的干货!关注公众号【丁香园大数据】了解更多,每月月初,干货满满,不见不散~
【丁香园大数据】近期文章????
搜索中的Query扩展技术
初探GNN-文本表示学习
如何为实体抽取描述性短语
多知识图谱的融合算法探究
医疗健康领域的短文本解析探索(2)
如何扩充知识图谱中的同义词
夕小瑶的卖萌屋
关注&星标小夕,带你解锁AI秘籍
订阅号主页下方「撩一下」有惊喜哦