最后更新于
最后更新于
这篇文章提出了DIIN(DENSELY INTERACTIVE INFERENCE NETWORK)模型. 是解决NLI(NATURAL LANGUAGE INFERENCE)问题的很好的一种方法.
首先, 论文提出了IIN(Interactive Inference Network)网络结构的组成, 是一种五层的结构, 每层的结构有其固定的作用, 但是每层的实现可以使用任意能达到目的的子模型. 整体的结构如下图:
模型结构从上到下依次为:
Embedding Layer: 常见的对word
进行向量化的方法, 如word2vec
, GloVe
, fasttext
等方法. 此外文章中还使用了两种方法对char
进行编码, 对每个word
中的char
进行编码, 并拼接上char
的特征, 组合成一个向量, 拼接在word embedding vector
上. 这样就包含了更多的信息. 具体的方法在后文讲到.
Encoding Layer: 对句子进行编码, 可以用多种模型进行编码, 然后将他们编码的结果合并起来, 从而获得更多方面的关于句子的信息.
Interaction Layer: 在这一层将两个句子的信息进行交互. 可以采用对两个句子中的单词word-by-word
的相互作用的方法. 相互作用的方法也有很多选择.
Feature Extraction Layer: 从上层得到两个句子相互作用产生的Tensor
, 使用一些常见的CNN网络进行处理, 如AlexNet
, VGG
, Inception
, ResNet
, DenseNet
等. 注意这里使用的是处理图像的2-D
的卷积核, 而不是文本常用的1-D
卷积核. 使用方法见下文.
Output Layer: 将特征转换为最终结果的一层. 只需要设置好输出类的数量即可.
具体的解析DIIN模型每层的结构.
这里将三种生成word
的方法拼接起来: word embedding
, character feature
, syntactical features
.
word embedding
论文中使用的是通过GloVe
预训练好的向量. 而且, 论文中提到在训练时, 要打开word embedding
的训练, 跟随着任务一起训练.
character feature
这里指的是对一个word
中的char
进行自动的feature
.
首先使用char embedding
对每个char
进行向量化, 然后对char
向量进行1-D
的卷积, 最后使用MaxPool
得到这一个单词对应的char
特征向量.
使用keras
实现如下:
syntactical features
添加这种的目的是为OOV(out-of-vocabulary)的word
提供额外补充的信息. 论文中提到的方法有:
part-of-speech(POS
), 词性特征, 使用词性的One-Hot
特征.
binary exact match(EM
)特征, 指的是一个句字中的某个word
与另一个句子中对应的word
的词干stem
和辅助项lemma
相同, 则是1, 否则为0. 具体的实现和作用在论文中有另外详细的阐述.
对于对char
编码过程中使用到的Conv1D
, 两个句子共享同样的参数, 这是毋庸置疑的.
在这一层中, premise
和hypothesis
会经过一个两层的神经网络, 得到句子中的每一个word
将会用一种新的方式表示. 然后将转换过的表示方法传入到一个self-attention layer
中. 这种attenion
结构在解决NLI
问题的模型中经常出现, 目的是考虑word
的顺序和上下文信息. 以premise
为例:
在转换时, 我们需要考虑当前单词与它的上下文之间的关系, 文中使用的方法是self-attention layer
, 具体来说就是每个时间上经过编码后新的向量, 由整个句子中所有位置上的原向量考虑权重地加和产生. 而两个单词向量之间的权值就要借助attention weight
来得到了. 以premise
句子为例, 整个过程如下:
每个词的新向量都会考虑句子中其他所有的向量.
以上三步的代码类似于:
需要注意的是, 在这一层中, premise
和hypothesis
两个句子是不共享参数的, 但是为了让两个句子的参数相近, 两个句子在相同位置上的变量, 会对他们之间的差距做L2正则惩罚, 将这种惩罚计入总的loss
, 从而在训练过程中, 保证了参数的近似.
那么对于premise
和hypothesis
两个句子来源一个分布的情况, 是否可以共用一组参数呢? 需要进一步的实验.
再将得到的结果传入到一个三层结构中, 三层的结构完全相同. 每一层由一对Dense block
和transition block
组成. 两种block
是串联关系.
结果上面一层就使用2-d
的方法得到了两个句子交互的特征. 然后把他们展平, 拼接到输出层的Dense
上就可以. Dense
的输出维度为类别的数量.
通过这三种方法, 就得到了premise
句子和hypothesis
句子的表示方法, 其中和分别表示premise
句子和hypothesis
句子的长度, 表示最终每个单词向量的长度.
假设是经过转换后的premise
句子, 是时序位置上的word
新的向量. 同理, 是转换后的新的hypothesis
句子.
对于premise
句子的任意两个向量和, 通过的形式组成一个交互的向量. 原向量的长度为, 则新向量的长度为. 则长度为的句子经过此步, 就会得到.
使用共享的attention weight
与进行点乘. 的是长度为的向量. 所有的word
之间共享这一参数向量. 因此点乘的结果为一个形状为的矩阵, 用表示, 则是两个word
之间的关系值.
使用softmax
的方法计算权重, 即对于每一行, 对应的新的向量为:
然后将新得到的维向量和原本的维向量合并在一起组成向量, 再传入semantic composite fuse gate(fuse gate)
, 这种把encoding后的向量和原特征向量拼在一起在传入下一层模型的方法, 如同skip connection
(类比于ResNet). fuse gate
结构如下:
这里的, , 的形状为, , , 为长度为的向量. 都是可训练的参数. 为sigmoid
函数.
对两个句子的word
进行编码之后, 就要考虑两个句子相互作用的问题了. 对于长度为的premise
和长度为的hypothesis
, 对于他们的每个单词和, 将代表它们的向量逐元素点乘, 这样就得到了一个形状为的两个句子相互作用后的结果. 可以把他们认为是一个2-d
的图像, 有d
个通道.
由于两个句子相互作用产生了一个2-d
的结果, 因此我们可以通过使用那些平常用在图像上的CNN
方法结构, 来提取特征, 例如ResNet
效果就很好. 但考虑到模型的效率, 与参数的多少, 论文中使用了DenseNet
这种结构. 这种结构的具体论文参见. 这一层整体的过程如下:
上一步得到的结果我们记为, 形状为. 首先使用一个的卷积核, 按一定的缩小比例, 将现有的层通道缩小为.
DenseNet
本身是由n
层的的卷积层组成, 中间没有池化层. 每层的输出通道数量是一样的, 记为growth rate
. 且每层的输出, 都会并上这一层的输入, 作为下一层的输入. 这样也起到了类似于ResNet
的skip
效果. 代码如下:
transition block
这是一层简单的的卷积层, 目的是按照一定的比例压缩输出的通道. 这里的压缩比例跟上面的是不相关的, 记为. 之后再在后面接上一个MaxPool
, 考虑的范围是大小. 代码如下:
在github上有使用keras
实现的模型. 代码使用了自定义Model
, Layer
, Optimizer
的方式实现了这个模型, 形式非常灵活, 值得借鉴学习.