关系抽取远程监督PCNN:Distant Supervision for Relation Extraction via Piecewise Convolutional Neural Networks
Distant Supervision for Relation Extraction via Piecewise Convolutional Neural Networks
- 0 前言
- 1 多示例学习
- 2 数据集
- 3 模型架构
- 3.1 向量表示
- 3.2 卷积、分段最大池化与分类
- 3.3 样本选择与损失
- 5 结语
- 6 参考资料
0 前言
远程监督(distant supervision)利用知识图谱的实体以及对应的关系对未标注文本进行回标,如果未标注文本中包含了一个知识图谱中具有某种关系的实体对,那么就假定这个文本也描述了相同的关系。通过这种标注策略虽然可以获得大量数据,但同时也会因为假设性太强而一如很多噪声数据(因为包含一个实体对的文本不一定描述了对应的关系)。
文章通过将PCNN模型与 多示例学习 Multi-instanceLearning 结合,有效降低了标注带来的噪声,是远程监督领域一篇非常经典的论文。这篇博客将结合论文与pytorch源码(非官方实现),对PCNN模型以及采用的多示例学习方法进行解读。
1 多示例学习
在解读模型之前,我们先来了解一下什么是多实例学习;
多示例学习可以被描述为:假设训练数据集中的每个数据是一个包(Bag),每个包都是一个示例(instance)的集合,每个包都有一个训练标记,而包中的示例是没有标记的;如果包中至少存在一个正标记的示例,则包被赋予正标记;而对于一个有负标记的包,其中所有的示例均为负标记。(这里说包中的示例没有标记,而后面又说包中至少存在一个正标记的示例时包为正标记包,是相对训练而言的,也就是说训练的时候是没有给示例标记的,只是给了包的标记,但是示例的标记是确实存在的,存在正负示例来判断正负类别)。通过定义可以看出,与监督学习相比,多示例学习数据集中的样本示例的标记是未知的,而监督学习的训练样本集中,每个示例都有一个一已知的标记;与非监督学习相比,多示例学习仅仅只有包的标记是已知的,而非监督学习样本所有示例均没有标记。但是多示例学习有个特点就是它广泛存在真实的世界中,潜在的应用前景非常大。
文章使用的多实例学习给予一个假设:在一个bag中,至少有一个句子是被标注正确的。因此,每个bag都有至少有一个标注正确的句子,这样就可以从每个bag中找一个得分最高的句子来表示整个bag。
2 数据集
作者将 NYT+FreeBase 数据集进行过滤以及打包,形成如下数据集:
27类关系,对数据集做了一些过滤,如删除了两个实体之间距离大于40个词的句子,以及去掉了实例少的关系,详细数据如下所示:
训练数据集:
实体对: 65726; 句子数: 112941;
测试数据集:
实体对: 93574; 句子数: 152416;
具体的,在数据集中,第一行是两个实体ID: ent1id ent2id;第二行: bag标签和bag内句子个数,其中由于少数bag有多个label(不会超过4个),因此句子label用4个整数表示,-1表示为空,如: 2 4 -1 -1 3 表示该bag的标签为2和4,然后包含3个句子;后续几行表示该bag内的句子。
3 模型架构
PCNN模型在功能上与其他非远程监督的普通模型并没有太大区别,通过向量表示,卷积,最大池化,分类四个部分获得关系的向量表示,模型结构如下所示:
3.1 向量表示
对于文本的向量表示,文章采用了词向量加位置嵌入的形式。对于位置嵌入,模型通过文本中每一个词与两个实体 e1e2e_1 e_2e1e2 的相对位置来获取。示例如下:
首先要注意的是,与一般的模型不同,PCNN每次计算一个包的数据,而不是一个batch,一般模型中第一维度的大小是batch_size,而在这里几乎都是bag_size。实现时获得形状为(bag_size, sequence_len, dwd_wdw)的词向量以及(bag_size, sequence_len, dpd_pdp)的位置嵌入,并在hidden_size维度也就是第二维度连接,即可获得 d=dw+dp∗2d=d_w+d_p * 2d=dw+dp∗2 的文本向量表示,源码如下:
self.word_embs = nn.Embedding(self.opt.vocab_size, self.opt.word_dim)self.pos1_embs = nn.Embedding(self.opt.pos_size, self.opt.pos_dim)self.pos2_embs = nn.Embedding(self.opt.pos_size, self.opt.pos_dim)word_emb = self.word_embs(insX)pf1_emb = self.pos1_embs(insPF1)pf2_emb = self.pos2_embs(insPF2)x = torch.cat([word_emb, pf1_emb, pf2_emb], 2)
3.2 卷积、分段最大池化与分类
在卷积的过程中,文章选择了大小为(3, kernel_size = ddd)的卷积核,并设置了 nnn 个输出通道。在上图中,输出通道为3,而在具体实现的时候为230。对于每个输出通道的输出的卷积向量 cic_ici ,模型根据两个实体的位置将其分为3个 piece ,在最大池化时分别对其进行池化,因此 nnn 个卷积向量进行池化后即可得到长度为 3∗n3*n3∗n 最终向量表示,经过一个全连接后即可得到分类结果。主体部分源码如下:
feature_dim = self.opt.word_dim + self.opt.pos_dim * 2self.convs = nn.ModuleList([nn.Conv2d(1, self.opt.filters_num, (k, feature_dim), padding=(int(k / 2), 0)) for k in self.opt.filters])all_filter_num = self.opt.filters_num * len(self.opt.filters)if self.opt.use_pcnn:all_filter_num = all_filter_num * 3masks = torch.FloatTensor(([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]]))if self.opt.use_gpu:masks = masks.cuda()self.mask_embedding = nn.Embedding(4, 3)self.mask_embedding.weight.data.copy_(masks)self.mask_embedding.weight.requires_grad = Falseself.linear = nn.Linear(all_filter_num, self.opt.rel_num)self.dropout = nn.Dropout(self.opt.drop_out)///////////////////////////////////////////////////////////////////////////////x = x.unsqueeze(1)x = self.dropout(x)x = [conv(x).squeeze(3) for conv in self.convs]if self.opt.use_pcnn:x = [self.mask_piece_pooling(i, insMasks) for i in x]else:x = [F.max_pool1d(i, i.size(2)).squeeze(2) for i in x]x = torch.cat(x, 1).tanh()x = self.dropout(x)x = self.linear(x)return x
在PCNN主体部分的代码中,模型首先将 3.1 小节中获得的向量表示增加一个维度,再经dropout后过了一个卷积,得到了一个shape为(bag_size, out_channel=230, sequence_len)的卷积向量。之后对得到的卷积向量进行分段最大池化,激活后过全连接即可。
下面我们将着重看一下用 mask 实现分段最大池化(Piecewise Max Pooling)的策略。如果对于实现细节不是很感兴趣,可直接跳转到第 3.3 小节。
在获得一个包中一个instance的mask时,模型根据两个实体 e1e2e_1 e_2e1e2 将文本进行分割,源码如下:
mask = [1] * (epos[0] + 1)mask += [2] * (epos[1] - epos[0])mask += [3] * (len(sent[2:-1]) - epos[1])
通过两个实体,一个句子的mask被分成1,2,3三个 piece 。为了保证每个包中句子长度的一致性,还会适当补0,后来补充的这部分mask为0。有了mask后,我们来看一下最大池化部分的代码,其实现使用了很巧妙的技巧,源码如下:
def mask_piece_pooling(self, x, mask):'''refer: https://github.com/thunlp/OpenNREA fast piecewise pooling using mask'''x = x.unsqueeze(-1).permute(0, 2, 1, -1)masks = self.mask_embedding(mask).unsqueeze(-2) * 100x = masks.float() + xx = torch.max(x, 1)[0] - torch.FloatTensor([100]).cuda()x = x.view(-1, x.size(1) * x.size(2))return x
其中mask的shape为(bag_size, sequnce_len)经过 x = x.unsqueeze(-1).permute(0, 2, 1, -1)
后,x的shape为(bag_size, sequence_len, out_channel, 1)。通过mask_embedding,mask中文本的位置0,1,2,3分别被映射成[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1],因此masks的shape为(bag_size, sequence_len, 1, 3)。
当masks与x相加时,效果如下:
>>> a=torch.tensor(range(3)).reshape(1,3)
>>> b=torch.tensor(range(3)).reshape(3,1)
>>> print(a)
tensor([[0, 1, 2]])
>>> print(b)
tensor([[0],[1],[2]])
>>> print(a+b)
tensor([[0, 1, 2],[1, 2, 3],[2, 3, 4]])
也就是说,一个元素如果在第一个实体 e1e_1e1 之前,那么其对应的mask是1,对应的masks是 [100, 0, 0] ,其余两个位置亦然,如果是0填充,对应的masks是 [0, 0, 0] ,不会被计算。在masks与x相加时,卷积向量中的每个元素都被复制了三份,并且如果这个元素处于第 i 个piece,那么这个元素会在最后一个维度的第 i 个位置上被加上100,这样在求最大值时,一个句子会被重复求三次,第一个 piece 上的最大元素会被保留在最后一个维度第一个位置上,第二个 piece 最大元素在第二个位置上,第三个亦然。最后改变一下矩阵的形状,我们就可以得到最大池化的结果。确实是个很有意思的加速计算技巧。
3.3 样本选择与损失
在本文开头我们提到,PCNN模型基于一个假设,在一个bag中,至少有一个句子是被标注正确的。bag 中每个实例经过全连接后,都会得到关于每个关系类别的概率。假设训练集中某个 bag 标签为 label,我们选择每个包中预测关系为 label 概率最高的那个值作为 bag 描述关系为 label 的概率。源码如下:
model.eval()for idx, bag in enumerate(batch_data):insNum = bag[1]label = labels[idx]max_ins_id = 0if insNum > 1:model.batch_size = insNumif opt.use_gpu:data = map(lambda x: torch.LongTensor(x).cuda(), bag)else:data = map(lambda x: torch.LongTensor(x), bag)out = model(data)# max_ins_id = torch.max(torch.max(out, 1)[0], 0)[1]max_ins_id = torch.max(out[:, label], 0)[1]
比较特别的地方在于,这里首先要将模型调为eval模式,然后预测bag中所有实力表示目标关系的概率,再选取最高者作为包的表示。在选出所有batch中所有bag的表示后,把模型调成train模式,再进行预测与计算损失。
ps:这样确实带来了很多重复运算,其实选择出一个 bag 的表示之后无需再用model预测,直接使用即可,可以在后续需要的时候加以改进。
out = model(data, train=True)loss = criterion(out, label)
data就是刚刚获得的所有bag都用所选示例表示的一个batch的数据。损失函数采用了交叉熵,这里就不过多赘述,更多实现细节可以阅读源码实现。
5 结语
PCNN模型通过分段最大池化和多示例学习,降低了错误标签带来的噪声,提高了模型的准确率,是远程监督领域一个非常经典的模型。
6 参考资料
论文地址:
https://www.aclweb.org/anthology/D15-1203.pdf
pytorch源码:
https://github.com/ShomyLiu/pytorch-relation-extraction
mask策略参考:
https://github.com/thunlp/OpenNRE
参考博客:
http://shomy.top/2018/02/28/relation-extraction/
http://shomy.top/2018/07/05/pytorch-relation-extraction/
https://www.jianshu.com/p/c8d08e92744c
关系抽取远程监督PCNN:Distant Supervision for Relation Extraction via Piecewise Convolutional Neural Networks相关推荐
- PCNN模型解读:《Distant Supervision for Relation Extraction via Piecewise Convolutional Neural Networks》
PCNN模型解读 本文是对Daojian Zeng, Kang Liu, Yubo Chen and Jun Zhao的论文<Distant Supervision for Relation E ...
- 知识图谱—关系抽取—远程监督—OpenNRE(一)
一.远程监督简介 远程监督的英文名称Distant Supervision,是目前关系抽取中比较常见的一类做法.该方法由 M Mintz 大佬于ACL2009上首次提出,它既不是单纯的传统意义上的监督 ...
- 论文浅尝 | Distant Supervision for Relation Extraction
Citation: Ji,G., Liu, K., He, S., & Zhao, J. (2017). Distant Supervision for RelationExtraction ...
- 文档级关系抽取:QIUXP:DORE: Document Ordered Relation Extraction based on Generative Framework
DORE: Document Ordered Relation Extraction based on Generative Framework 文档级关系抽取是从整篇文档中抽取出三元组.更难,但也很 ...
- 论文学习17-Global Normalization of Convolutional Neural Networks(联合实体关系抽取CNN+CRF)2017
文章目录 abstract 1.Introduction 2.相关工作 3.Model 全局归一化层(使用线性链CRF) 4.实验和分析 4.3实验结果 总结 Adel, H. and H. Schü ...
- 【转】自然语言系列学习之表示学习与知识获取(八)利用远程监督多实例的关系抽取
下面介绍下如何利用远程监督多实例进行关系抽取.前文有提到到当利用文本进行关系抽取,基本思想是利用知识图谱中,如(下图)任意两个实体同时在句子中出现: 我们把句子当成是两个实体关系训练得样例,这样就可以 ...
- 关系抽取(二)远程监督方法总结
目录 前言 1. 远程监督关系抽取开山之作 1.1 介绍 1.2 训练过程 1.2.1 数据标注方法 1.2.2 训练方法 1.3 测试过程 1.4 思考 1.5 总结 2. PCNN 2.1 介绍 ...
- [论文阅读笔记51]关系抽取【DNN】综述(监督与远程监督)
题目 Deep Neural Network Based Relation Extraction: An Overview 单位:University of Electronic Science an ...
- 文献阅读课14-DIAG-NRE: A Neural Pattern Diagnosis Framework for远程监督关系抽取,模式标注去噪自动化,FN,FP,RL
文章目录 abstract 1. Introduction 2.相关工作 3.方法 3.1 NRE Models 3.2 Pattern Extraction 3.3 Pattern Refinemen ...
最新文章
- 麒麟芯片AI首席科学家,解读AI芯片如何让手机更智能
- 江西理工大学计算机管理技术期末复习(wangzhendong)网络管理与维护
- nginx strip模块优化页面
- 华为荣耀8青春版计算机在哪里,华为荣耀8青春版
- Tomcat9+eclipse如何发布网站
- java泛型的作用和实现原理_java泛型的作用及实现原理
- 张正友标定法 【计算机视觉学习笔记--双目视觉几何框架系列】
- 关于JVM和JIT的一点点
- php变量函数,回调函数
- mysql更新写入数据_七、MySQL插入、更新与删除数据
- oracle清空回收站
- jsonobject json对象里面_「jsonobject」用JSONObject解析和处理json数据 - seo实验室
- Win10 Anaconda下TensorFlow-GPU环境搭建详细教程(包含CUDA+cuDNN安装过程)
- Loadrunner11安装
- IT技术入门基础知识分享贴
- 三段式状态机理解浅析
- 抢购器 抢拍器 秒杀器 秒杀软件 抢购软件 设计思路(未实现)
- 华硕 Asus TUF B360M+INTEL i5+Sapphire AMD VEGA56黑苹果EFI引导文件
- EPLAN导入EDZ文件
- 知识库管理-运维管理
热门文章
- C语言知识点总结 -思维导图
- socket加入组播
- OneNote添加Markdown插件的方法 #OneNote#工具篇
- qt for android开发百度地图(一步步带图详解)
- Oracle-数据库对象的使用
- 大势所趋,RIA已成为主流应用程序!
- 拿下它的心-车联网(二)
- python matplotlib pyplot方法_Matplotlib.pyplot 常用方法
- 低代码内参:低代码平台 Airtable 再获 7.35 亿美元的融资,一年内估值翻倍达117亿美元
- CUDA:工作负载遵循CPU预处理->GPU处理->CPU后处理的形式的实例