关系抽取:图卷积网络的学习(一)(附代码)

关系抽取:图卷积网络的学习(一)(附代码)

目录

  • 关系抽取:图卷积网络的学习(一)(附代码)
    • 一、 图卷积网络(GCN)【托马斯·基普夫】
      • 1.介绍
      • 2.Outline
      • 3.GCN到底有多强?
        • Recent literature相关文献
        • GCNs Part I: Definitions
        • GCNs Part II: A simple example
        • GCNs Part III: Embedding the karate club network 嵌入空手道俱乐部网络
        • GCNs Part IV: Semi-supervised learning 半监督学习
      • 4.结论
    • 二、关系图卷积网络(R-GCN)
      • 1.R-GCN的一个简单介绍
      • 2.R-GCN的关键点
      • 3.DGL中R-GCN的实现
        • 1)R-GCN层
        • 2)完整R-GCN模型定义
        • 3)数据集的处理
        • 4)创建图和模型
        • 5)训练
        • 4.任务二:链路预测
    • 三、基于 GCN 模型的关系抽取方法
    • 四、图卷积神经网络在关系抽取中的应用
    • 【参考文献】

一、 图卷积网络(GCN)【托马斯·基普夫】

关系抽取:图卷积网络的学习(一)(附代码)_第1张图片

图 多层一阶过滤器图卷积网络(GCN)

1.介绍

  现实世界里很多重要的数据集都以图表或网络的形式呈现,例如:社交网络、知识图谱、蛋白质相互作用网络、万维网等等。然而直到最近,神经网络模型对这些结构化数据集的泛化仍然很少得到关注。

  过去几年,很多研究重新思考了推广神经网络用于任意结构化图表的问题( Bruna et al., ICLR 2014;Henaff et al., 2015;Duvenaud et al., NIPS 2015;Li et al., ICLR 2016;Defferrard et al., NIPS 2016;Kipf & Welling, ICLR 2017 ),其中有些已经在某些领域取得了非常不错的结果,而这些领域过去使用基于核函数的方法、基于图的正则化技术或其他方法。

  在这篇文章里,我将对这个领域的最新进展作一个简要概述,并指出各种方法的强处和不足。这些讨论主要关注最近的两篇论文

  • Kipf & Welling (ICLR 2017), Semi-Supervised Classification with Graph Convolutional Networks (disclaimer: I’m the first author)
  • Defferrard et al. (NIPS 2016), Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering

  以及 Ferenc Huszar 的评论文章:How powerful are Graph Convolutions? ,这篇文章讨论了这些类型的模型的一些限制。

2.Outline

  • 简要介绍神经网络在图上的应用
  • 图谱卷积核图卷积网络(GCNs)
  • 实例:简单的1阶GCN模型的图嵌入
  • GCN视作Weisfeiler-Lehman算法一般化的可微分形式

3.GCN到底有多强?

Recent literature相关文献

  比较成熟的神经网络模型,如RNN、CNN在任意结构图上的应用是一个具有挑战性的问题。最近的一些论文引入了针对特定问题的特定结构(e.g.Duvenaud et al., NIPS 2015;Li et al., ICLR 2016;Jain et al., CVPR 2016),另外一些从图谱理论(Bruna et al., ICLR 2014;Henaff et al., 2015)中引入图卷积多层叠加的方式来解决问题,其中卷积的参数化的过滤器(filter)和经典CNN中的核(filter) 很相似。

  更近一点的研究主要集中在解决快速启发式和慢速启发式之间的问题,不过好像只有图谱理论这一个途径。Defferrard et al.(NIPS 2016) 在图谱理论中用切比雪夫多项式(Chebyshev polynomials)以神经网络的自由参数方式估算出平滑的过滤器。他们在常规领域(如MNIST)取得了令人信服的结果,非常接近简单的2D CNN模型

  在Kipf & Welling(ICLR 2017)这篇论文中,我采用了一些相似的方法,从图谱卷积框架开始,引入一些简化,在很多情况下可以成倍提高训练速度和取得更好的的预测精确度。在一些基准的图数据集中,我们已经达到了state-of-the-art的分类结果。

GCNs Part I: Definitions

  当前,大部分图神经网络模型都有一些通用的架构。我将引用那些模型作为图卷积网络(GCNs)卷积,是因为过滤器参数在图的所有地方共享了卷积核参数(或者是一部分Duvenaud et al., NIPS 2015)。

  对于那些模型,目标是学习出一个信号/特征在图上的函数,G=(V,E),函数的输入是:

• 节点特征矩阵XN×D,N是节点数,D:输入的特征数。
• 图的邻接矩阵 ANxN。

  输出是节点层面的矩阵 ZNxF( F是每个节点的输出特征数)。图层面的输出可以引入一些池化操作。(e.g.Duvenaud et al., NIPS 2015

  每一个神经网络层可以写成下面非线性的函数

在这里插入图片描述

  这里 H(0)=X and H(L)=Z(或者Z是图层面的输出),L是神经网络的层数。这个模型主要依赖于函数f和参数化的选择

GCNs Part II: A simple example

  一个例子,让我们考虑下面一个简单层面的传播规则

在这里插入图片描述

  这里 W(l)是神经网第l层的参数矩阵,σ是非线性的激活函数,比如ReLU。尽管这个模型非常简单,但是已经很强了。

  在开始之前,我们给这个模型两个限制乘矩阵A是什么意思?对于每个节点,我把除自身(除了有自循环外)外相邻节点的特征全加起来。我们可以对邻接矩阵A加上一个单位矩阵I强制变成带自循环的邻接矩阵。
  第二个主要限制是A一般情况下是没有正规化的的,因此乘矩阵A会完全改变特征矩阵的规模(我们用A的特征值来想象一下)。正规化A使得A的每一行加起来等于1,比如 D−1A,这里D一个图的度的对角矩阵,这样我们来摆脱这个问题。乘D−1A结果会取相邻节点特征和的平均。在实际中,我们一般使用对称的形式 D−1/2AD−1/2(这样就不仅仅是简单的相邻节点的平均了)。综合这两个限制(trick),我们基本上获得了由Kipf & Welling (ICLR 2017)引入的神经网络传播规则

在这里插入图片描述

  A^=A+I, I是单位矩阵, D^是 邻接矩阵A^ 的节点度对角矩阵。

  下一节我们将会近距离观察这个模型在将图上的作用例子:Zachary空手道俱乐部网络(Zachary’s karate club network)。

GCNs Part III: Embedding the karate club network 嵌入空手道俱乐部网络

关系抽取:图卷积网络的学习(一)(附代码)_第2张图片

空手道俱乐部图,图中的颜色标记的是根据交流基于模块聚类方法的类别

  让我们看看我们简单的GCNs模型在著名的Zachary空手道俱乐部网络数据集上是如何工作的

  我们采用随机初始化的3层GCN网络。在开始训练之前,我们简单的把图的邻接矩阵A和特征矩阵X=I(用单位矩阵表示节点特征矩阵,因为我们不知道任何节点的信息)插入到模型中。这个3层GCN在前向传播中进行3次传播,并且非常有效的做3阶节点相邻的卷积(所有的节点最多跳3次)。这非常令人印象深刻,这个嵌入了所有节点的模型输出了和社交网络非常相似的图(如下图)。注意我们只是网络参数是随机初始化的,并且没有做训练更新

关系抽取:图卷积网络的学习(一)(附代码)_第3张图片

空手道俱乐部所有节点的GCN网络嵌入,随机初始化的参数

  这可能有点让人吃惊。最近的一篇关于模型的论文叫 DeepWalk (Perozzi et al., KDD 2014)展示了在复杂的非监督学习训练过程中,他们能学习出非常相似的嵌入。用我们简单的没有训练过的GCN模型去做图嵌入,这是如何可能的呢?

  我们可以用GCN更广泛的意义稍微解释一下,就是著名的Weisfeiler-Lehman算法在图上可微分的版本。下面的是1维Weisfeiler-Lehman算法工作的基本原理

遍历所有点 vi∈G:

  1. 获取所有相邻节点 {vj}的特征 {hvj}
  2. 更新节点的特征 hvi←hash(∑jhvj), 这里的hash是一个单射hash函数。

重复上述过程k次或者直到收敛。

  在实际应用中,Weisfeiler-Lehman 算法可以为大多数图赋予一组独特的特征。这意味着每个节点都被分配了一个独一无二的特征,该特征描述了该节点在图中的作用。但这对于像网格、链等高度规则的图是不适用的。对大多数不规则的图而言,特征分配可用于检查图的同构(即从节点排列,看两个图是否相同)。

  回看下图卷积层层传播的规则(向量形式):

在这里插入图片描述

  式中,j 表示 vi 的相邻节点。cij 是使用我们的 GCN 模型中的对称归一化邻接矩阵 D-1/2 A D-1/2 生成的边 (v_i,v_j) 的归一化常数。

  我们可以将该传播规则解释为在原始的 Weisfeiler-Lehman 算法中使用的 hash 函数的可微和参数化(对 W(l))变体。如果我们现在选择一个适当的、非线性的的矩阵,并且初始化其随机权重,使它是正交的,(或者使用 Glorot & Bengio, AISTATS 2010 提出的初始化)那么这个更新规则在实际应用中会变得稳定(这也归功于归一化中的 c_ij 的使用)。我们得出了很有见地的结论,即我们得到了一个很有意义的平滑嵌入,其中可以用距离远近表示局部图结构的相似性/不相似性

GCNs Part IV: Semi-supervised learning 半监督学习

  到目前为止,我们模型是可微分的和参数化的,我们可以添加一写标记,训练模型,观察嵌入后的反应。我们可以使用由Kipf & Welling (ICLR 2017)引入的半监督学习方法。对于每个类/群体,我们简单的标记一个节点。下面是训练的几个迭代。

  用 GCNs 进行半监督分类对每类仅仅标记一个标签,(突出显示标记节点)进行 300 次迭代训练得到隐空间的动态

关系抽取:图卷积网络的学习(一)(附代码)_第4张图片关系抽取:图卷积网络的学习(一)(附代码)_第5张图片关系抽取:图卷积网络的学习(一)(附代码)_第6张图片

GCN半监督分类

  隐式空间的动态模型,300个迭代训练,每个类一个标记的样本。高亮的是标记过的样本。

  注意模型的产生的是2维的隐式空间,我们可以直接视觉化。我们观察到3层GCN模型可以线性的分隔社交群体,只需一个类别标记一个样本。这是一个非常牛逼的结果(This is a somewhat remarkable result),我们并没有给出节点的任何特征。同时,节点初始化特征是可以被提供的,这和论文(Kipf & Welling, ICLR 2017)中的实验一样,在图数据集中的分类中取得了state-of-the-art的结果。

4.结论

  有关这个领域的研究才刚刚起步。在过去的几个月中,该领域已经获得了振奋人心的发展,但是迄今为止,我们可能只是抓住了这些模型的表象。而神经网络如何在图论上针对特定类型的问题进行研究,如在定向图或关系图上进行学习,以及如何使用学习的图嵌入来完成下一步的任务等问题,还有待进一步探索。本文涉及的内容绝非详尽无遗的,而我希望在不久的将来会有更多有趣的应用和扩展。

二、关系图卷积网络(R-GCN)

  这里,我们将会了解如何实现一个关系图卷积网络(R-GCN),这种类型的网络旨在泛化GCN来处理知识库中实体之间的不同关系。如果想要学习更多R-GCN背后的东西,可以看Modeling Relational Data with Graph Convolutional Networks 。

  简单的图卷积网络(GCN)和DGL探索一个数据集的结构信息(即,图的连通性)来改善节点表示的提取。图的边被保留为无类型。

  知识图由主题、关系、对象形式的三元组集合组成。 因此,边对重要信息进行编码,并具有自己有待学习的嵌入。 此外,在任何给定对之间可能存在多个边。

1.R-GCN的一个简单介绍

  在统计关系学习(statistical relational learning, SRL) 中,有两类基本任务:

  • 实体分类——需要指定实体的类型和分类属性
  • 链路预测——需要发现丢失的三元组

  上面两种情况中,我们都期望可以从图的邻居结构中发现丢失的信息。例如,有一篇R-GCN的文章提供了下面的例子。在知道Mikhail Baryshnikov曾经在Vaganova Academy受教育,可以推断出Mikhail Baryshnikov是有标签的,而且我们也可以知道三元组(Mikhail Baryshnikov, lived in, Russia)一定属于这个知识图。

  R-GCN通过一个常见的图卷积网络来解决上面两个问题。它使用多边编码进行扩展来计算实体的嵌入,但具有不同的下游处理。

  • 实体分类通过在实体(节点)嵌入的最后加一个softmax分类器来实现,训练是采用标准交叉熵的损失函数。
  • 链路预测通过一个自编码器结构来重新构建一条边,参数化score函数来实现,训练采用负采样。

  这里关注的是第一个任务,实体分类,并展示了如何去生成实体表示。

2.R-GCN的关键点

  回想一下GCN中,在(l+1)th每个节点i的隐层表示通过下面式子计算:

在这里插入图片描述

  其中,ci为正则化常数。

  R-GCN和GCN不同的关键之处在R-GCN中,边可以表示不同的关系。GCN中,上述等式中的W(1)是l层中所有的边共享的。相反,R-GCN中,不同类型的边使用不同的权重,只有相同关系类型r的边才使用相同的映射权重W(1)r

  因此在R-GCN中,(l+1)th层上实体隐藏层可以用下面的等式来表示:

在这里插入图片描述

  其中Nri表示在满足r∈R关系下,节点ii的邻居节点集合,ci,r是正则化常数。在实体分类中,R-GCN使用ci,r=∣Nri∣。

  直接使用上面的等式存在问题参数数目增长迅速,尤其对于高度多关系的数据而言。为了减少模型的参数规模和防止过拟合,原始的论文中提出使用基础分解

在这里插入图片描述

  因此,权重Wr(l)是基础转换Vb(l)和系数arb(l)的线性组合。base的数目B远远小于知识库的关系数目

3.DGL中R-GCN的实现

  一个R-GCN模型由多个R-GCN层构成。第一个R-GCN层作为输入层,输入与节点实体相关的特征,并映射到隐层空间(如:描述文本)。这里,我们只使用实体ID作为实体特征。

1)R-GCN层

  对于每个节点,一个R-GCN层执行下面的步骤

• 使用节点表示和与边类型(消息函数)相关的权重矩阵计算输出信息。
• 聚合输入的信息并生成新的节点表示(reduce和apply函数)。

  下面定义R-GCN隐藏层的代码

  每种关系类型对应于不同的权重,因此,整个权重矩阵维度为3关系,输入特征,输出特征

import torch
import torch.nn.functional as F
from dgl import DGLGraph
import dgl.function as fn
from functools import partial

class RGCNLayer(nn.Module):
	def __init__(self, in_feat, out_feat, num_rels, num_bases=-1, bias=None, activation=None, is_input_layer=False):
		super(RGCNLayer, self).__init__()
		self.in_feat = in_fear
		self.out_feat = out_feat
		self.num_rels = num_rels
		self.num_bases = num_bases
		self.bias =bias
		self.activation = activation
		self.is_input_layer = is_input_layer
		
		# sanity check(完整性检查)
		if self.num_bases <= 0 or self.num_bases > self.num_rels:
			self.num_bases = self.num_rels

		# weight bases in equation (3)
		self.weight = nn.Parameter(torch.Tensor(self.num_bases, self.in_feat, self.out_feat))

		if self.num_bases < self.num_rels:
		# linear combination coefficients in equation (3)
		self.w_comp = nn.Parameter(torch.Tensor(self.num_rels, self.num_bases))

		# add bias
		if self.bias:
			self.bias = nn.Parameter(torch.Tensor(out_feat))

		# init trainable parameters
		nn.init.xavier_uniform_(self.weight, gain=nn.init.calculate_gain('relu'))
		
		if self.num_bases < self.num_rels:
			nn.init.xavier_uniform_(self.w_comp, gain=nn.init.calculate_gain('relu'))
		
		if self.bias:
			nn.init.xavier_uniform_(self.bias, gain=nn.init.calculate_gain('relu'))

	def forward(self, g):
		if self.num_bases < self.num_rels:
			# generate all weights from bases (equation (3))
			weight = self.weight.view(self.in_feat, self.num_bases, self.out_feat)
			weight = torch.matmul(self.w_comp, weight).view(self.num_rels, self.in_feat, self.out_feat)
		else:
			weight = self.weight

		if self.is_input_layer:
			def meaasge_func(edges):
				# for input layer, matrix multiply can be converted to be an embedding lookup using source node id
				embed = weight.view(-1, self.out_feat)
				index = edges.data['rel_type'] * self.in_feat + edges.src['id']
				return {'msg': embed[index] * edges.data['norm']}
		else:
			def message_func(edges):
				w = weight[deges.data['rel_type']]
				msg = torch.bmm(edges.src['h'].unsqueeze(1), w).squeeze()
				msg = msg * edges.data['norm']
				return {'msg': msg}

		def apply_func(nodes):
			h = nodes.data['h']
			if self.bias:
				h = h + self.bias
			if self.activation:
				h = self.activation(h)
			return {'h': h}
		g.update_all(message_func, fn.sum(msg='msg', out='h', apply_func)

2)完整R-GCN模型定义

class Model(nn.Module):
	def __init__(self, num_nodes, h_dim, out_dim, num_rels, num_bases=-1, num_hidden_layers=1):
		super(Model, self).__init__()
		self.num_nodes = num_nodes
		self.h_dim = h_dim
		self.out_dim = out_dim
		self.num_rels = num_rels
		self.num_bases = num_bases
		self.num_hidden_layers = num_hidden_layers

		# create rgcn layers
		self.features = self.create_features()

	def build_model(self):
		self.layers = nn.ModuleList()
		# input to hidden
		i2h = self.build_input_layer()
		self.layers.append(i2h)
		# hidden to hidden
		for _ in range(self.num_hidden_layers):
			h2h = self.build_hidden_layer()
			self.layers.append(h2h)
		# hidden to output
		h2o = self.build_output_layer()
		self.layers.append(h2o)

	# initialize feature for each node
	def create_features(self):
		features = torch.arange(self.num_nodes)
		return features

	def build_input_layer(self):
		return RGCNLayer(self.num_nodes, self.h_dim, self.num_rels, self.num_bases, activation=F.relu, is_input_layer=True)

	def build_hidden_layer(self):
		return RGCNLayer(self.h_dim, self.h_dim, self.num_rels, self.num_bases, activation=F.relu)

	def build_output_layer(self):
		return RGCNLayer(self.h_dim, self.out_dim, self.num_rels, self.num_bases, activation=partial(F.softmax, dim=1))

	def forward(self, g):
		if self.features is not None:
			g.ndata['id'] = self.features
		for layer in self.layers:
			layer(g)
		return g.ndata.pop('h')

3)数据集的处理

  这里使用R-GCN论文中的应用信息学和形式描述方法研究所(AIFB)数据集

# load graph data
from dgl.contrib.data import load_data
import numpy as np
data = load_data(dataset='aifb')
num_nodes = data.num_nodes
num_rels = data.num_rels
num_classes = data.num_classes
labels = data.labels
train_idx = data.train_idx
# split training and validation set
val_idx = train_idx[:len(train_idx) // 5]
train_idx = train_idx[len(train_idx) // 5:]

# edge type and normalization factor
edge_type = torch.form_numpy(data.edge_type)
edge_norm = torch.form_numpy(data.edge_norm).unsqueeze(1)

labels = torch.from_numpy(labels).view(-1)
Out:
Loading dataset aifb
Number of nodes:  8285
Number of edges:  66371
Number of relations:  91
Number of classes:  4
removing nodes that are more than 3 hops away

4)创建图和模型

# configurations
n_hidden = 16 # number of hidden units
n_bases = -1 # use number of relations as number of bases
n_hidden_layers = 0 # use 1 input layer, 1 output layer, no hidden layer
n_epochs = 25 # epochs to train
lr = 0.01 # learning rate
l2norm = 0 # L2 norm coefficient

# create graph
g = DGLGraph()
g.add_nodes(num_nodes)
g.add_edges(data.edge_src, data.edge_dst)
g.edata.update({'rel_type': edge_type, 'norm': edge_norm})

# create model
model = Model(len(g), n_hidden, num_classes, num_rels, num_bases=n_bases, num_hidden_layers=n_hidden_layers)

5)训练

# optimizer
optimizer = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=l2norm)

print("strat training...")
model.train()
for epoch in range(n_epochs):
	optimizer.zero_grad()
	logits = model.forward(g)
	loss = F.cross_entropy(logits[train_idx], labels[train_idx])
	loss.backward()

	train_acc = torch.sum(logits[train_idx].argmax(dim=1) == labels[train_idx])
	train_acc = train_acc.item() / len(train_idx)
	val_loss = F.cross_entropy(logits[val_idx], labels[val_idx])
	val_acc = torch.sum(logits[val_idx].argmax(dim=1) == labels[val_idx])
	val_acc = val_acc.item() / len(val_idx)
	print("Epoch {:05d} | ".format(epoch) + "Train Accuracy: {:.4f} | Train Loss: {:.4f} | ".format(train_acc, loss.item()) + "Validation Accuracy: {:.4f} | Validation loss: {:.4f}".format(val_acc, val_loss.item()))

  Out:

start training...
Epoch 00000 | Train Accuracy: 0.1786 | Train Loss: 1.3866 | Validation Accuracy: 0.1786 | Validation loss: 1.3862
Epoch 00001 | Train Accuracy: 0.9821 | Train Loss: 1.3487 | Validation Accuracy: 0.9643 | Validation loss: 1.3620
Epoch 00002 | Train Accuracy: 0.9821 | Train Loss: 1.2905 | Validation Accuracy: 1.0000 | Validation loss: 1.3259
Epoch 00003 | Train Accuracy: 0.9821 | Train Loss: 1.2137 | Validation Accuracy: 1.0000 | Validation loss: 1.2773
Epoch 00004 | Train Accuracy: 0.9821 | Train Loss: 1.1291 | Validation Accuracy: 1.0000 | Validation loss: 1.2188
Epoch 00005 | Train Accuracy: 0.9821 | Train Loss: 1.0506 | Validation Accuracy: 1.0000 | Validation loss: 1.1536
Epoch 00006 | Train Accuracy: 0.9821 | Train Loss: 0.9850 | Validation Accuracy: 1.0000 | Validation loss: 1.0862
Epoch 00007 | Train Accuracy: 0.9821 | Train Loss: 0.9324 | Validation Accuracy: 1.0000 | Validation loss: 1.0220
Epoch 00008 | Train Accuracy: 0.9821 | Train Loss: 0.8910 | Validation Accuracy: 1.0000 | Validation loss: 0.9659
Epoch 00009 | Train Accuracy: 0.9821 | Train Loss: 0.8588 | Validation Accuracy: 1.0000 | Validation loss: 0.9202
Epoch 00010 | Train Accuracy: 0.9821 | Train Loss: 0.8339 | Validation Accuracy: 1.0000 | Validation loss: 0.8847
Epoch 00011 | Train Accuracy: 0.9821 | Train Loss: 0.8147 | Validation Accuracy: 1.0000 | Validation loss: 0.8571
Epoch 00012 | Train Accuracy: 0.9821 | Train Loss: 0.8001 | Validation Accuracy: 1.0000 | Validation loss: 0.8358
Epoch 00013 | Train Accuracy: 0.9821 | Train Loss: 0.7892 | Validation Accuracy: 1.0000 | Validation loss: 0.8194
Epoch 00014 | Train Accuracy: 0.9821 | Train Loss: 0.7812 | Validation Accuracy: 1.0000 | Validation loss: 0.8071
Epoch 00015 | Train Accuracy: 0.9821 | Train Loss: 0.7752 | Validation Accuracy: 1.0000 | Validation loss: 0.7979
Epoch 00016 | Train Accuracy: 0.9821 | Train Loss: 0.7708 | Validation Accuracy: 0.9643 | Validation loss: 0.7912
Epoch 00017 | Train Accuracy: 0.9821 | Train Loss: 0.7675 | Validation Accuracy: 0.9643 | Validation loss: 0.7864
Epoch 00018 | Train Accuracy: 0.9821 | Train Loss: 0.7650 | Validation Accuracy: 0.9643 | Validation loss: 0.7830
Epoch 00019 | Train Accuracy: 0.9821 | Train Loss: 0.7631 | Validation Accuracy: 0.9643 | Validation loss: 0.7805
Epoch 00020 | Train Accuracy: 0.9821 | Train Loss: 0.7616 | Validation Accuracy: 0.9643 | Validation loss: 0.7787
Epoch 00021 | Train Accuracy: 0.9821 | Train Loss: 0.7603 | Validation Accuracy: 0.9643 | Validation loss: 0.7775
Epoch 00022 | Train Accuracy: 0.9821 | Train Loss: 0.7592 | Validation Accuracy: 0.9643 | Validation loss: 0.7767
Epoch 00023 | Train Accuracy: 0.9821 | Train Loss: 0.7581 | Validation Accuracy: 0.9643 | Validation loss: 0.7762
Epoch 00024 | Train Accuracy: 0.9821 | Train Loss: 0.7570 | Validation Accuracy: 0.9643 | Validation loss: 0.7760

4.任务二:链路预测

  到目前为止,我们已经了解了如何使用DGL通过R-GCN模型实现实体分类。 在知识库设置中,R-GCN生成的表示可用于发现节点之间的潜在关系。 在R-GCN论文中,作者将R-GCN生成的实体表示提供给DistMult预测模型,以预测可能的关系

  该实现与此处介绍的实现类似,但在R-GCN层之上堆叠了一个额外的DistMult层。
代码地址 【https://github.com/dmlc/dgl/blob/master/examples/pytorch/rgcn/link_predict.py】

三、基于 GCN 模型的关系抽取方法

  句法依存树包含句子中各词语间的依存关系,将其引入关系抽取任务可以挖掘更深层的语义信息。图卷积神经网络的提出实现了非欧式数据上的卷积操作,也为处理图结构数据提供了新思路。

  Zhang 等人提出一种基于修剪依存树的图卷积神经网络并用于实体关系抽取问题,仅保留两个实体的最小公共祖先子树上 K 距离内的结点,并将修剪后的句法依存树引入图卷积网络进行实体关系抽取任务。实验表明,这种修剪方式过滤依存树中无关数据的同时,保留了对关系抽取任务有用的信息。但基于规则的硬性修剪策略却很容易产生过剪枝或欠剪枝,为了解决这个问题,Guo 等人提出了注意力引导的图卷积网络 AGGCN,可以理解为一种对句法依存树的软修剪策略,模型将完整依存树作为输入并结合注意力机制,在迭代训练中自动学习保留对关系抽取任务有用的子结构。AGGCN 模型由个相同模块组成,每个块包含注意力引导层、密集连接层和线性组合层,其中注意力引导层使用多头注意力机制构造个注意力引导邻接矩阵,将输入依存树转换为个不同的全连接边加权图,即每个注意力引导邻接矩阵对应一个全连接图。

  Sun 等人认为 AGGCN 模型使用的全连接图破坏了依存树原始结构,基于这个问题提出了可学习的句法传输注意力图卷积网络( LST-AGCN),通过引入连接节点的依存关系类型将树转换为加权图即句法传输图。通过词嵌入、依存关系嵌入和节点嵌入来建模可学习的传输矩阵 A,并结合注意力机制学习合适权重来聚合所有图层输出的特征向量,得到最终句子表示再进行关系抽取,其中涉及的注意力机制主要用于整合每层 GCN 的输出。

  下表将注意力机制按其结构分为单层自注意力、多层注意力和多头注意力机制。无论是基于 CNN、RNN 还是 GCN 衍生出的关系抽取模型,均可以通过引入不同 Attention 或其组合来提高性能。注意力机制良好的软性选择能力也可以有效缓解远程监督中的噪声问题,许多研究将其引入远程监督来过滤错误标记的样本。

表 注意力机制相关方法统计

关系抽取:图卷积网络的学习(一)(附代码)_第7张图片

四、图卷积神经网络在关系抽取中的应用

  这是一个用于图中节点进行(半监督)分类的图卷积网络的TensorFlow实现,如本文所述:

  Thomas N. Kipf, Max Welling, Semi-Supervised Classification with Graph Convolutional Networks (ICLR 2017)

  有关更多的解释,请查看我们的博客文章:
  Thomas Kipf, Graph Convolutional Networks (2016)

  图卷积神经网络直接使用图卷积神经网络作者提供的源代码:https://github.com/squirrel1982/gcn

  你可以在以下模型之间进行选择:

  • gcn:图卷积网络(Thomas N. Kipf,Max Welling, Semi-Supervised Classification with Graph Convolutional Networks,2016年)
  • gcn_cheby:图卷积网络的Chebyshev多项式版本,如(Michaël Defferrard,Xavier Bresson,Pierre Vandergheynst, Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering,NIPS 2016)
  • dense:支持稀疏输入的基本多层感知器

  我们的框架还支持对每个具有邻接矩阵的多个图实例(可能具有不同的大小)进行批量分类。最好将各个特征矩阵连接起来,并建立一个(稀疏的)块对角矩阵,其中每个块对应一个图实例的邻接矩阵。对于池化(对于图级输出而不是节点级输出),最好指定一个简单的池化矩阵,该矩阵从各自的图实例中收集要素,如下所示:

关系抽取:图卷积网络的学习(一)(附代码)_第8张图片

  代码结构

├── init
├── data // 图数据
├── inits // 初始化的一些公用函数
├── layers // GCN层的定义
├── metrics // 评测指标的计算
├── models // 模型结构定义
├── train // 训练
└── utils // 工具函数的定义

  结果:

关系抽取:图卷积网络的学习(一)(附代码)_第9张图片

  结论:GCN虽然是一个思路,但使用关系三元组中前项、后项的词汇信息和实体类型信息以及关联关系信息,想在严重不平衡数据集(正负样本比例是88:12)中对正样本进行15种类型的分类,不太可行,信息量不够

【参考文献】

  1. http://tkipf.github.io/graph-convolutional-networks/
  2. Vashishth S , Sanyal S , Nitin V , et al. Composition-based Multi-Relational Graph Convolutional Networks[J]. 2019.
  3. Kipf, Thomas N, Welling, Max. Semi-Supervised Classification with Graph Convolutional Networks[J].
  4. Michael Schlichtkrull, Thomas N Kipf, Peter Bloem, Rianne van den Berg, Ivan Titov, and Max Welling. Modeling relational data with graph convolutional networks. arXiv preprint arXiv:1703.06103, 2017
  5. David K. Hammond, Pierre Vandergheynst, and R´emi Gribonval. Wavelets on graphs via spectral graph theory. Applied and Computational Harmonic Analysis, 30(2):129–150, 2011

你可能感兴趣的:(Information,extraction,神经网络,自然语言处理,深度学习,tensorflow)