神经张量网络:探索文本实体之间的关系

Posted 腾讯云加社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了神经张量网络:探索文本实体之间的关系相关的知识,希望对你有一定的参考价值。

欢迎大家前往云加社区,获取更多腾讯海量技术实践干货哦~

译者:Waitingalone

本文翻译自Gaurav Bhatthttp://deeplearn-ai.com 发表的NEURAL TENSOR NETWORK: EXPLORING RELATIONS AMONG TEXT ENTITIES。文中版权、图像代码等数据均归作者所有。为了本土化,翻译内容略作修改。

在这篇文章中,我将介绍神经张量网络(NTN),如在用神经张量网络推理知识库的推理中所描述的那样 。我的NTN实现使用最新版本的Python 2.7,Keras 2.0和Theano 0.9。

用代码直接跳到GitHub仓库

什么是知识库完成?

在知识库完成中,任务是确定两个实体对之间的关系。例如,考虑两个实体对 -<cat, tail> 和<supervised learning, machine learning>。如果我们被要求确定给定的两对之间的关系 - <cat,R,tail>和<supervised learning, R, machine learning> - 那么第一个关系可以最好的归结为有型,而第二个关系可以被归结为实例。所以,我们可以将这两个对重新定义为 <cat,has,tail>和<supervised learning,instance of,machine learning>。神经张量网络(NTN)在实体 - 关系对的数据库上训练,用于探究实体之间的附加关系。这是通过将数据库中的每个实体(即每个对象或个体)表示为一个向量来实现的。这些载体可以捕获有关该实体的事实,以及它是如何可能是某种关系的一部分。每个关系都是通过一个新的神经张量网络的参数来定义的,这个神经张量网络可以明确地涉及两个实体向量

技术分享图片

使用NTN预测新的关系三元组。

关系推理的神经模型

能够认识到某些事实纯粹是由于其他现有的关系而存在的,是学习常识推理的模型的目标。NTN旨在发现实体<e1,e2>之间的关系,即对于<e1,e2>确定性地预测关系R. 例如,(e1,R,e2) = (Bengal tiger, has part, tail) 这个关系是否真实且具有确定性。神经张量网络(NTN)用一个双线性张量层代替一个标准的线性神经网络层,它直接关联了多个维度上的两个实体向量。该模型通过下列基于NTN的函数计算两个实体处于特定关系的可能性分数:

技术分享图片

其中技术分享图片是标准非线性的单元应用,技术分享图片技术分享图片是张量,双线性张量积技术分享图片产生向量技术分享图片技术分享图片,其中每个条目张量的一个切片技术分享图片计算:技术分享图片。其它参数为关系R是一个神经网络的标准形式:技术分享图片技术分享图片技术分享图片技术分享图片技术分享图片技术分享图片

可视化神经张量层

技术分享图片

NTN使用张量变量 技术分享图片对两个实体之间的关系进行乘法建模。如上所示,NTN是对简单神经层的扩展,增加了这些张量变量。所以,如果我们从上图中删除 技术分享图片,最后,目标函数被定义为

技术分享图片

这是一个简单的实体向量连接,以及偏向项。

培训目标

NTN采用对比式最大余量目标函数进行训练。给定训练样本中的三元组技术分享图片,则通过随机的将第二个实体替换为技术分享图片来创建负样本,其中j是随机索引。最后,目标函数被定义为

技术分享图片

其中,技术分享图片是正则化参数。

实施细节

现在,我们看到了NTN的工作,是时候深入实施了。这里要考虑的重要一点是,每个给定的关系都有其自己的一组张量参数。让我简单介绍一下在Keras的帮助下我们需要做些什么。

技术分享图片

每个关系都归因于一个单独的Keras模型,它也增加了张量参数。现在,假定张量层是在模型初始化和组合之间添加的。在后面的文章中,我将解释张量层的构造。从上图可以很容易得出结论,我们需要以某种方式处理训练数据,以便它可以同时传递到所有单独的模型。我们想要的只是更新与特定关系相对应的张量参数。然而,Keras 并没有让我们更新一个单独的模型,而剩下的。所以我们需要把数据分成不同的关系。每个训练样本将包含所有关系的一个实例,也就是每个关系的一对实体。

实施NTN层

让我们从实施神经张量层开始。这部分的先决条件是在Keras编写自定义图层。如果您不确定这意味着什么,那么请查看Keras文档的 编写你自己的keras图层。

我们首先用参数inp_size,out_size和activation来初始化NTN类。该inp_size是输入变量的形状,在我们的例子中的实体; 所述out_size是张量参数(K),和激活是要使用的激活函数(默认为tanh)。

from ntn_input import *
from keras import activations

class ntn_layer(Layer):
     def __init__(self, inp_size, out_size, activation=tanh, **kwargs):
          super(ntn_layer, self).__init__(**kwargs)
          self.k = out_size
          self.d = inp_size
          self.activation = activations.get(activation)
          self.test_out = 0

 

维的命名保持不变,即k对应于每个关系的张量参数个数,d是实体的形状。

现在,我们需要初始化张量图层参数。为了更好的理解我们在这里做什么,看一下张量网络的下图。

技术分享图片

我们初始化四个张量参数,即W,V,b和U如下:

def build(self,input_shape):
     self.W = self.add_weight(name=w,shape=(self.d, self.d, self.k), initializer=glorot_uniform, trainable=True)

     self.V = self.add_weight(name=v, shape=(self.k, self.d*2), initializer=glorot_uniform, trainable=True)

     self.b = self.add_weight(name=b, shape=(self.k,), initializer=zeros, trainable=True)

     self.U = self.add_weight(name=u, shape=(self.k,), initializer=glorot_uniform,trainable=True)

     super(ntn_layer, self).build(input_shape)

在这里,我们用glorot_uniform 采样初始化参数 。在实践中,这种初始化比其他初始化导致更好的性能。add_weight 函数的另一个参数是可训练的,如果我们不想更新特定的可调参数,可以设置为false。例如,我们可以将W参数设置为不可训练的,如前所述,NTN模型将表现得像一个简单的神经网络。

一旦参数被初始化,那么是时候实现下面的等式了:

技术分享图片

上面的等式给出了每个实体对的分数。正如你所看到的,我们必须迭代k个张量参数(张量模型的切片)。这是通过计算每个迭代的中间产品来完成的,最后,汇总所有这些产品。下面的代码片段为你做这个。请不要更改函数的名称,因为它们与Keras API一致。

def call(self ,x ,mask=None):
     e1=x[0] # 实体 1
     e2=x[1] # 实体 2
     batch_size = K.shape(e1)[0]
     V_out, h, mid_pro = [],[],[]
     for i in range(self.k): # 计算内部产品
          V_out = K.dot(self.V[i],K.concatenate([e1,e2]).T)
          temp = K.dot(e1,self.W[:,:,i])
          h = K.sum(temp*e2,axis=1)
          mid_pro.append(V_out+h+self.b[i])

    tensor_bi_product = K.concatenate(mid_pro,axis=0)
    tensor_bi_product = self.U*self.activation(K.reshape(tensor_bi_product,(self.k,batch_size))).T

    self.test_out = K.shape(tensor_bi_product)
    return tensor_bi_product

 

最后,要完成NTN层的实现,我们必须添加以下功能。这与NTN无关; Keras使用以下函数进行内部处理。

def compute_output_shape(self, input_shape):
     return (input_shape[0][0],self.k)

 

我们已经建立了可以像Keras中的任何其他神经层一样调用的NTN层。让我们看看如何在真实的数据集上使用NTN层。

数据集

我将使用文中提到的Wordbase和Freebase数据集。我已经准备好了数据集(预处理的一部分从GitHub存储库中获取),并且可以进行如下处理。

import ntn_input

data_name = wordbase # wordbase or freebase
data_path = data+data_name
raw_training_data = ntn_input.load_training_data(ntn_input.data_path)
raw_dev_data = ntn_input.load_dev_data(ntn_input.data_path)
entities_list = ntn_input.load_entities(ntn_input.data_path)
relations_list = ntn_input.load_relations(ntn_input.data_path)
indexed_training_data = data_to_indexed(raw_training_data, entities_list, relations_list)
indexed_dev_data = data_to_indexed(raw_dev_data, entities_list, relations_list)
(init_word_embeds, entity_to_wordvec) = ntn_input.load_init_embeds(ntn_input.data_path)

num_entities = len(entities_list)
num_relations = len(relations_list)

 

此时您可以打印并查看实体及其对应的关系。现在,我们需要根据关系来划分数据集,以便所有Keras模型都可以同时更新。我已经包括一个预处理功能,为您执行此步骤。此步骤中还添加了否定样本。负样本作为损坏的样本传递给prepare_data函数。如果corrupt_samples = 1,则对应于每个训练样本添加一个负样本。这意味着,整个训练数据集将会翻倍。

import ntn_input
e1,e2,labels_train,t1,t2,labels_dev,num_relations = prepare_data(corrupt_samples)

NTN的定义存储在一个名为ntn的文件中,很容易导入使用。

建立模型

为了训练模型,我们需要定义对比最大边缘损失函数。

def contrastive_loss(y_true, y_pred):
     margin = 1
     return K.mean(y_true * K.square(y_pred) + (1 - y_true) * K.square(K.maximum(margin - y_pred, 0)))

 

我们应该可以从Keras编译函数中调用这个自定义的丢失函数。

from ntn import *

def build_model(num_relations):
     Input_x, Input_y = [], []
     for i in range(num_relations):
          Input_x.append(Input(shape=(dimx,)))
          Input_y.append(Input(shape=(dimy,)))

     ntn, score = [], [] # 存储单独的张量参数
     for i in range(num_relations): # 通过每个切片迭代 k
          ntn.append(ntn_layer(inp_size=dimx, out_size=4)([Input_x[i],Input_y[i]]))
          score.append(Dense(1,activation=sigmoid)(ntn[i]))

     all_inputs = [Input_x[i]for i in range(num_relations)]
     all_inputs.extend([Input_y[i]for i in range(num_relations)]) # 聚合所有模型

     model = Model(all_inputs,score)
     model.compile(loss=contrastive_loss,optimizer=adam)
     return model

 

最后,我们需要汇总数据以训练模型

e, t, labels_train, labels_dev = aggregate(e1, e2, labels_train, t1, t2, labels_dev, num_relations)
model.fit(e, labels_train, nb_epoch=10, batch_size=100, verbose=2)

 

在这一点上,你可以看到模型开始训练,每个个体模型的损失逐渐减少。此外,为了计算NTN在知识库数据集上的准确性,我们需要计算所有关系的成本,并选择最大分数的成本。正如本文所述,所达到的准确度接近88%(平均)。

下一步是什么?

在这篇文章中,我们看到了建立知识库完成的神经张量网络。在下一篇文章中,我们将看到NTN如何用于解决其他NLP问题,例如基于非事实问题的回答。。

原文链接:http://deeplearn-ai.com/2017/11/21/neural-tensor-network-exploring-relations-among-text-entities/

原文作者:Gaurav Bhatt

相关阅读

推荐算法之协同过滤

实习生的监控算法: 利用时间序列模型进行曲线预测

用R和Keras深度学习的例子


 

此文已由作者授权云加社区发布,转载请注明原文出处

 


以上是关于神经张量网络:探索文本实体之间的关系的主要内容,如果未能解决你的问题,请参考以下文章

使用神经网络执行文本分类时,准确性和损失之间是不是存在直接关系?

特定领域知识图谱知识融合方案(实体对齐):基于图神经网络的商品异构实体表征探索

论文泛读177使用递归神经张量网络从自然语言需求中提取细粒度因果关系

论文泛读177使用递归神经张量网络从自然语言需求中提取细粒度因果关系

标量向量矩阵张量之间的区别和联系

讲坛实录知识图谱的探索与应用