有关语义匹配和推理

描述

先把论文放出来:Enhanced LSTM for Natural Language Inference,说实话这篇论文不算新了,但是在语义相似度方至今仍流传着他的传说,因此我还是把这篇论文拿着读了起来。近期也是看了很多文章,但是终究不如读论文来的过瘾,大部分博客对这篇论文的模型核心做了很多介绍,但各个操作的出发点和一些独到的见解却写的不多,这次我会在介绍ESIM的过程中讨论一下。

当然,还是建议大家好好品读原论文,更有味道。

另外给点代码,看论文不清楚的看看论文也挺好:

https://blog.csdn.net/wcy23580/article/details/84990923。

https://github.com/weekcup/ESIM。

有关语义匹配和推理

一般地,向量召回主要用的表征模型,但是表征模型没有用到交互特征,因此匹配的准确率上肯定比不过交互模型,所以一般工程上用表征模型召回,然后用交互模型来做精排,这样能保证整个搜索系统的效果更加稳定可靠(看到没,准召分离的思路又来了),而交互模型这块,比较可靠的基线,应该就要数ESIM了。

ESIM里,我比较欣赏的是这几点:

LSTM抽取上下文信息。Tree-LSTM的尝试也为信息抽取带来启发。

把Decomposable attention作为交互特征的思路有机组合起来了。

多种交互形式的特征concat起来。

当然具体阅读后,我还提炼了一些新的idea,在文末。有了这些思路,先让我们来看看具体的模型,其实论文的行文里讨论了很多思路,我们先来看整体论文思路,然后再来提炼里面的独到之处。

模型整体

论文的模型其实没有想象中的困难,在很早就把整篇论文给到了:

输入层是embedding+LSTM的组合。

Local Inference Modeling层,用的Decomposable Attention来体现两者的交互型。

Inference composition层则把上面一层的结果进行多种组合计算,得到多种特征,说白了就是比较。

输出层就不多说了,大家都懂的。

输入层

一般的输入层只会是简单的word2vector,但这里其实加了一个LSTM,还是双向的,就是用来获取各路信息。来看看代码,这个还是比较清晰的:

i1 = Input(shape=(SentenceLen,), dtype='float32') i2 = Input(shape=(SentenceLen,), dtype='float32') x1 = Embedding([CONFIG])(i1) x2 = Embedding([CONFIG])(i2) x1 = Bidirectional(LSTM(300, return_sequences=True))(x1) x2 = Bidirectional(LSTM(300, return_sequences=True))(x2)

Local Inference Modeling

中文翻译应该是局部推理层,我的理解这一层是用于抽取局部信息的,作者用的方法应该来源于这篇论文:A Decomposable Attention Model for Natural Language Inference,这里其实是一个计算交互特征的过程,即一一分析两个句子之间每个位置的相似度,最简单的方式就是点乘,而这篇论文就是使用的这个最简单的方式:

然后再把权重分散到各个位置,其实形态就很像softmax了:

这个其实就是做了一个交叉,计算整个句子的权重,然后用类似softmax的形式整上,非常讨巧,相信ESIM的成功很大程度上就和这个有关。

而这并没结束,作者进行了进一步的强化,对比Decomposable Attention前后的变化,进行了组合。

Inference Composition

推理层应该是进入最终预测之前的最后一层了。这一层的操作同样没那么简单,大部分人可能flatten、maxpool、avgpool之类的就直接全连接了,但是这里并不是,而是做了一系列的再提取和再处理,最终才完成预测向量的:

作者是真的把信息抽取和特征的组合做到了极致,对上面构造的两个组合特征再进行了一次特征提取,用的依旧是熟悉的Bilstm,值得注意的是他操作的维度,来看一个ESIM的开源代码吧:

class InferenceCompositionLayer(object):     """     Layer to compose the local inference information.     """     def __init__(self, hidden_units, max_length=100, dropout=0.5,                  activation='tanh', sequences=True):         self.hidden_units = hidden_units         self.max_length = max_length         self.dropout = dropout         self.activation = activation         self.sequences = sequences     def __call__(self, input):         composition = Bidirectional(LSTM(self.hidden_units,                                          activation=self.activation,                                          return_sequences=self.sequences,                                          recurrent_dropout=self.dropout,                                          dropout=self.dropout))(input)         reduction = TimeDistributed(Dense(self.hidden_units,                                           kernel_initializer='he_normal',                                           activation='relu'))(composition)         return Dropout(self.dropout)(reduction)

这里用到另一个我没见过的keras层,即TimeDistributed,有兴趣可以了解下。

此后,非常精髓的使用avg-pool和max-pool的组合,有关池化,max和avg一直打得火热,没有人能给出非常稳定的结论,因此作者就用了两者的组合:

启示

整篇文章其实没有构造出非常高端的结构,只是一些非常朴素的操作,但是综合起来成了现在也非常推荐用的基线,是有很多有借鉴意义的东西的,我这里一一列举,大家可以直接在里面选择需要的来用。

BiLSTM似乎还挺好用的。当然私以为CNN其实也可以尝试的。

花式concat,多种信息抽取方式进行组合,小孩子才做选择,大人全都要。

attention的使用,其实有出处A Decomposable Attention Model for Natural Language Inference,思想其实是两者一一对比得到交互矩阵,利用该交互矩阵构造类似softmax的权重,为各自的关键信息进行加权,重点提取。

信息的对比来自于可以来自减和乘,减直接计算两者的差距,类似欧氏距离,乘的使用则来源于余弦距离,既然要对比特征,那就把这两个用到极致。

avg和max哪个好,别争了,都用,哪个比较重要交给后面的全连接层来决定吧。

我的这篇文章里面没有讲tree-lstm,主要是因为我们平时比较难用到,原因是这个树不好构建,需要依赖依存句法,但是的确是一个挺有意思的思想,只有真的去读论文的人才能知道。

参考资料

论文原文:Enhanced LSTM for Natural Language Inference

论文解读:https://blog.csdn.net/wcy23580/article/details/84990923

keras版本代码:https://github.com/weekcup/ESIM/blob/master/src/model.py

依旧推荐大家直接去读论文,文章对他为什么做这些操作有很明确的思想,其实在我看来这些思想比操作本身还要重要,毕竟思想是需要启发的,在这些思想的指导下,我在思考解决方案的时候就能有参考,方案可以借鉴,但是这个思想的实现并不局限在一个方法上。

责任编辑:lq

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分