关系分类泛读系列(三)—— Relation Classific

2019-05-21  本文已影响0人  DataArk

一、写在前面的话

这篇论文发表于ACL2016,在SemEval 2010 Task 8 数据集上达到了88%的F1-Score,为目前最高,不过貌似还未有人可以复现。论文使用两层的Attention尽可能应用关系分类任务所特有的信息,损失函数在原有的基础上提出了新的margin function,另外在输入中加入了trigram信息。不过,引入两层Attention导致训练似乎非常困难,加上没有人复现,所以后面文章的对比基本上忽略了这篇文章。

二、论文笔记

1. 论文整体架构

该模型结构主要包含了输入的Attention、卷积层、池化的Attention以及最后的margin function。

2. 输入部分

输入主要分为3部分:

  1. word embedding
  2. position embedding
  3. trigram信息

前两个没什么好说的,就是前两篇笔记里提到的操作,trigram信息是指设置一个滑动窗口k,以每个word 为中心,左右k/2个词作为上下文,将它们拼接起来(这里拼接的不止是词向量,也包括位置向量)。简单来说,其实就是在输入加入了lexical level features,只是一般lexical level features是等深度学习这边操作完成输出句子特征之后拼接这些特征,就像《Relation Classification via Convolutional Deep Neural Network》中的操作一样。

简单来说,现在原来一个词的向量维度变成了:一个词上下文的数量k * (词向量维度 + 位置向量维度*2)

3. 输入的Attention

输入的Attention主要是衡量我们的词与两个实体直接的关系,论文中是引入了两个对角矩阵来分别记录每个词和两个实体之间的attention(不知道这个对角矩阵的意义是什么,其实直接用向量计算似乎就可以了,后面有待研究),计算公式如下,其中A_{i,i}^{j}= f(e_j, w_i)e_j是实体向量,w_i是词向量:

每个词都有对两个entity的权重,论文中提出了如下三种方式融合:

substract concat average

4. 卷积层

与其他文章的卷积大致相同:

5. 池化的Attention

这一层Attention其实就是求卷积的输出和relation labels的关系,首先这需要将relation labels也做一个嵌入 W^L,然后使用如下公式获得Attention:

在这个基础上我们再去做pooling:

6. 损失函数

这个损失函数其实建立在relation labels嵌入的基础上,可以看到,这个损失使用了网络最后的输出和relation labels嵌入做distance,最后加上了一个margin,下图中设置margin为1:

7. 实验结果

基本上目前是最优秀的结果,哪怕当前加入了bert之后的最新论文也就达到87%多,但基本没人复现是坑。另外,文章中也详细地做了消去实验,实验也算完备。

三、总结

尽管这篇论文存在不能完整复现的问题,但文章中多层Attention的想法其实是很值得考虑得,从几个维度考虑Attention或者在不同阶段加入Attention都是不错的一个技巧,另外关于损失函数,该论文使用了embedding的逼近来作为距离函数,也有较好地提升,能否在其他任务里加入这样的技巧,也是值得思考的。整体来说,虽然坑很多,但思路很好,值得阅读和尝试复现。

四、代码

运行了https://github.com/FrankWork/acnn,在运行代码上没什么坑,但是效果并不怎么样,下次会重新改到自己的代码上:

输入的Attention实现:

  def _input_attention(self, x, e1, e2, initializer=None):
    bz = self.config.batch_size
    n = self.config.max_len

    with tf.name_scope('input_attention'):
      A1 = tf.matmul(x, tf.expand_dims(e1, -1))# bz, n, 1
      A2 = tf.matmul(x, tf.expand_dims(e2, -1))
      A1 = tf.reshape(A1, [bz, n])
      A2 = tf.reshape(A2, [bz, n])
      alpha1 = tf.nn.softmax(A1)# bz, n
      alpha2 = tf.nn.softmax(A2)# bz, n

      alpha = (alpha1 + alpha2)/2
      
      return alpha

配置如下:

import tensorflow as tf


# Basics
# tf.app.flags.DEFINE_boolean("debug", True,
#                             "run in the debug mode.")
tf.app.flags.DEFINE_boolean("test_only", False,
                            "no need to run training process.")

# Data files
tf.app.flags.DEFINE_string("data_path", "data/", "Data directory")
tf.app.flags.DEFINE_string("embedding_file", "embedding/senna/embeddings.txt", 
                           "embedding file")
tf.app.flags.DEFINE_string("embedding_vocab", "embedding/senna/words.lst", 
                           "embedding vocab file")
tf.app.flags.DEFINE_string("train_file", "train.txt", "training file")
tf.app.flags.DEFINE_string("test_file", "test.txt", "Test file")
# tf.app.flags.DEFINE_string("log_file", 'run/log.txt', "Log file") 
# tf.app.flags.DEFINE_string("save_path", 'run/', "save model here")
tf.app.flags.DEFINE_string("log_file", None, "Log file") 
tf.app.flags.DEFINE_string("save_path", None, "save model here")

tf.app.flags.DEFINE_string("embedding_size",'50' , "pad word")
tf.app.flags.DEFINE_string("max_len",'30' , "pad word")



# Model details
tf.app.flags.DEFINE_integer("pos_embed_num", 123, "position embedding number")
tf.app.flags.DEFINE_integer("pos_embed_size", 5, "position embedding size")
tf.app.flags.DEFINE_integer("slide_window", 3, "Slide window size")
tf.app.flags.DEFINE_integer("num_filters", 100,
                            "How many features a convolution op have to output")
tf.app.flags.DEFINE_integer("classnum", 19, "Number of relations")

# Optimization details
tf.app.flags.DEFINE_integer("batch_size", 100, "Batch size")
tf.app.flags.DEFINE_integer("num_epoches", 100, "Number of epoches")
tf.app.flags.DEFINE_float("keep_prob", 1.0, "Dropout keep prob.")
tf.app.flags.DEFINE_float("learning_rate", 1e-3, "Learning rate.")
tf.app.flags.DEFINE_float("l2_reg_lambda", 1, "regularization parameter")
# tf.app.flags.DEFINE_float("learning_rate2", 1e-3, "learning_rate for regularization")
tf.app.flags.DEFINE_float("margin", 1, "margin based loss function")
tf.app.flags.DEFINE_float("grad_clipping", 10., "Gradient clipping.")


FLAGS = tf.app.flags.FLAGS
上一篇 下一篇

猜你喜欢

热点阅读