一、关系抽取简介
信息抽取的主要目的是将非结构化或半结构化描述的自然语言文本转化成结构化数据(Structuring),关系抽取是其重要的子任务,主要负责从文本中识别出实体(Entities),抽取实体之间的语义关系。
如:句子“Bill Gates is the founder of MicrosoftInc.”中包含一个实体对(Bill Gates, Microsoft Inc.),这两个实体对之间的关系为Founder。
Freebase中的关系类型
现有主流的关系抽取技术分为有监督的学习方法、半监督的学习方法和无监督的学习方法三种:
1、有监督的学习方法将关系抽取任务当做分类问题,根据训练数据设计有效的特征,从而学习各种分类模型,然后使用训练好的分类器预测关系。该方法的问题在于需要大量的人工标注训练语料,而语料标注工作通常非常耗时耗力。
2、半监督的学习方法主要采用Bootstrapping进行关系抽取。对于要抽取的关系,该方法首先手工设定若干种子实例,然后迭代地从数据从抽取关系对应的关系模板和更多的实例。
3、无监督的学习方法假设拥有相同语义关系的实体对拥有相似的上下文信息。因此可以利用每个实体对对应上下文信息来代表该实体对的语义关系,并对所有实体对的语义关系进行聚类。
与其他两种方法相比,有监督的学习方法能够抽取更有效的特征,其准确率和召回率都更高。因此有监督的学习方法受到了越来越多学者的关注。
因为NLP中的句子长度是不同的,所以CNN的输入矩阵大小是不确定的,这取决于m的大小是多少。卷积层本质上是个特征抽取层,可以设定超参数F来指定设立多少个特征抽取器(Filter),对于某个Filter来说,可以想象有一个k*d大小的移动窗口从输入矩阵的第一个字开始不断往后移动,其中k是Filter指定的窗口大小,d是Word Embedding长度。对于某个时刻的窗口,通过神经网络的非线性变换,将这个窗口内的输入值转换为某个特征值,随着窗口不断往后移动,这个Filter对应的特征值不断产生,形成这个Filter的特征向量。这就是卷积层抽取特征的过程。每个Filter都如此操作,形成了不同的特征抽取器。Pooling 层则对Filter的特征进行降维操作,形成最终的特征。一般在Pooling层之后连接全联接层神经网络,形成最后的分类过程。
二、论文研读
论文1:Distant Supervision for Relation Extraction via Piecewise Convolutional Neural Networks
假如现在有一语料集,要判断Bill Gates is the founder of Microsoft这句话中Bill Gates 和Microsoft这两者之间的关系,首先要找出包含这两个单词的句子集{,, … ,}。现在要判断这些句子中两者众多关系中关系r的概率。考虑句子集中每个包含m个单词的句子x。,为了表达这个句子的意思,将每个单词转化为对应的word embedding (维度)。同时找出每个单词相对于两个实体之间距离的position embeddings (维度)。讲两者联结起来,构成新向量集,(维度)位置向量
接下来则要进行卷积运算了,设d=|w|, l为滑动窗口长度,可以就看出图一的例子中d=6 , l=2 。现在假设为w中第i-l+1到i行构成的。其中,超出边界(i<1或i>m)的值为0。
因此,卷积层的第i个滑动窗口由下式计算得到。
接着最大池化得到一数。
这篇论文在池化层时将通过两个实体位置将 feature map 分为三段进行池化,其目的是为了更好的捕获两个实体间的结构化信息。最后,通过 softmax 层进行分类。如果将句子通过两个实体的位置将其分为三段,这样,就被分成了三段
然后再对每一段最大池化,
接着将 首尾连接起来得到
最后,通过非线性层tanh得到向量
最后一层全连接层
(n1是最后的关系分类数)
原始句子经过CNN的处理后,就成为了一个具有多个特征的向量,之后就可以用不同的方法去处理了。 这篇论文使用了多示例学习(multi-instance learning)的方法。7. 假设网络所有参数为θ,训练集有T个包,
第i个包有qi个示例:
算法流程如下:
目标函数:
最大化目标函数以学习参数。
论文2:Neural Relation Extraction with Selective Attention over Instances (2016)
论文在前半部分的处理与前一篇论文一样,不多做阐述。 如上图所示,主要区别在于全连接层本篇论文使用了选择性关注机制。 考虑包含两个实体的句子集合,将这些矢量加权求和: 论文中选择了两种求权值的方法,如下:(1)取平均(AVE): (2)选择性关注(ATT):
该方法主要是为了减少错误标签的影响。
加入attention之后的s,再通过一层网络:这一层网络的参数M是现存所有实体关系的向量所组成的矩阵,这样的处理在数学上的意义也是很直观的,最后将该层网络的输出经过一个softmax层,那么所要最大化的的就是的就是在网络参数下某实体关系的概率:
选取交叉熵函数并利用随机梯度下降进行优化最后便可以学得网络的所有参数:论文3:Attention-Based Bidirectional Long Short-Term Memory Networks for RelationClassification
该论文在前面也做了类似的词向量和位置向量处理。后面使用了LSTM的方法。 主要流程图如下: 这里只简要各层的功能:输入层:将原始句子输入该层;
向量层:将每个单词映射到一个低维向量;
LSTM层:利用BLSTM从输入的向量得到该句子的强特征
关注层:产生一个权重向量,将LSTM中的每一个时间节点通过这个权重向量联结起来;
输出层:将上面得到的向量运用到关系分类任务上。
三、实验过程与验证:
1、前两篇论文实验:
代码使用的语言是C++,在Ubuntu环境下测试
代码:https://github.com/thunlp/NRE
下载完代码后,编译,进入文件夹要测试的文件夹包括CNN+ONE, PCNN+ONE,CNN+ATT, PCNN+ATT打开终端输入make
其中:PCNN+ONE对应第一篇论文,PCNN+ATT对应第二篇论文。
训练数据: ./train
测试数据: ./test
p.s.作者已经训练好数据并且已保存好模型,可以直接test,所以没有必要每个都运行train。
(1)CNN+ONE结果
(2)CNN+ATT结果
(3)PCNN+ONE结果
(4)PCNN+ATT结果
效果上PCNN > CNN
ATT>ONE
2、第三篇论文实验:
第三篇论文实验使用的python3语言,在Ubuntu环境下测试
首先下载代码:https://github.com/thunlp/TensorFlow-NRE
作者使用的python版本是python2,同时tensorflow的版本是r0.11
而我电脑上的python版本是python3,tensorflow 的版本是1.1.0
又不想重新安装,所以只能改动源代码。
首先,ubuntu中默认安装的python2中有个2to3工具,可以直接将python2的代码转换为python3的代码。
终端输入 2to3 –w example.py就能将example.py转换为python3,同时产生example.oy.bak的备份文件。
这样就可以将所有的相关代码转换为对应的python3语言,非常方便,省的一个一个改。
接着就要改tensorflow了,由于tensorflow版本的变动比较大,所以要改的地方还挺多的,针对我改动过程中遇到的问题,整理如下,当然一些没遇到的就没有整理了。
Tensorflow 新旧版本的改动
一、AttributeError:module 'tensorflow.python.ops.nn' has no attribute 'rnn_cell'
tf.nn.rnn_cell ===》
tf.contrib.rnn
二、TypeError:Expected int32, got list containing Tensors of type '_Message' instead.
tf.concat参数调换下位置,数字放在后面
三、AttributeError:module 'tensorflow' has no attribute 'batch_matmul'
batch_matmul ===》
matmul
四、AttributeError:module 'tensorflow' has no attribute 'mul'
mul ===>
multiply
五、ValueError:Only call `softmax_cross_entropy_with_logits` with named arguments (labels=...,logits=..., …)
注明哪个是labels,哪个是logits
六、AttributeError:module 'tensorflow' has no attribute 'scalar_summary'
tf.audio_summary ===》 tf.summary.audio
tf.contrib.deprecated.histogram_summary===》 tf.summary.histogram
tf.contrib.deprecated.scalar_summary===》 tf.summary.scalar
tf.histogram_summary===》 tf.summary.histogram
tf.image_summary===》 tf.summary.image
tf.merge_all_summaries===》 tf.summary.merge_all
tf.merge_summary===》 tf.summary.merge
tf.scalar_summary===》 tf.summary.scalar
tf.train.SummaryWriter===》 to tf.summary.FileWriter
七、WARNING:initialize_all_variables(from tensorflow.python.ops.variables) is deprecated and will be removed after2017-03-02.
Instructions forupdating:
Use`tf.global_variables_initializer` instead.
代码改完后,就可以运行了。
Python3 train_GRU.py
根据保存的模型修改test.py中的testlist:
修改完后运行
Python3test_GRU.py
在众多评测结果中我找到的比较好的结果是iter16000,结果如下
Evaluating P@Nfor iter 16000
Evaluating P@Nfor one
P@100:
0.71
P@200:
0.65
P@300:
0.5866666666666667
Evaluating P@Nfor two
P@100:
0.72
P@200:
0.64
P@300:
0.62
Evaluating P@Nfor all
P@100:
0.74
P@200:
0.705
P@300:
0.6533333333333333
2017-05-15T16:12:42.613068
Evaluating alltest data and save data for PR curve
saving all testresult...
PR curvearea:0.309841978919
2017-05-15T16:15:40.915434
P@N for all testdata:
P@100:
0.7
P@200:
0.665
P@300:
0.65
而作者找到的较好的结果是iter10900,PR曲线 ,可见其效果是最好的。
而我得到的PR曲线如下,效果跟CNN+ATT差不多
参考资料:
论文1
论文2
论文3