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

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

译者: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深度学习的例子



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

时间: 2024-10-11 12:01:50

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

实体之间的关系(EF基础系列篇7)

EF实体之间的关系分为: 1.一对一: 2.一对多: 3.多对多: 一对一关系: Student和StudentAddress之间: public partial class Student { public int StudentID { get; set; } public string StudentName { get; set; } public Nullable<int> StandardID { get; set; } public string RowVersion { get

实体之间的关系

拿学生信息举例 查询所有学生记录,包含年级名称 Student表实体类 Grade表实体类 Dao层 测试类 实体之间的关系分为四种 1.一对一 2.一对多 3.多对一 4.多对多 原文地址:https://www.cnblogs.com/wangdayexinyue/p/10945123.html

Retrofit2 完全解析 探索与okhttp之间的关系

转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/51304204: 本文出自:[张鸿洋的博客] 之前写了个okhttputils的工具类,然后有很多同学询问这个工具类和retrofit什么区别,于是上了下官网,发现其底层对网络的访问默认也是基于okhttp,不过retrofit非常适合于restful url格式的请求,更多使用注解的方式提供功能. 既然这样,我们本篇博文首先研究其所提供的常用的用法: 一般的get.post请

实体与实体之间的联系

单张表的缺点: 表的结构不清晰 造成数据冗余 表的可扩展性差 一.外键 一个表的的主码的在另一张表中出现充当非主码字段(Foreign Key) 表与表之间用外码进行连接 外键虽然能够帮你强制建立表关系 但是也会给表之间增加数据相关的约束,通过cascade可以进行级联更新 外键约束 1.在创建表的时候 必须先创建被关联表 2.插入数据的时候 必须先插入被关联表的数据 二.实体与实体之间的关系 一对一关系 外键字段放在使用频率高的表上 一对多关系 外键字段放在多的一方 多对多关系 建在关系表中

带宽和网速之间的关系

先明白一下几个网络速度量词单位之间的关系: 1 Byte = 8 bits 1 Kb = 1024 bits 1 KB = 1024 bytes 1 Mb = 1024 Kb 1 MB = 1024 KB 1.Mbps是带宽单位,在“Mbps”单位中的“b”是指“Bit(位)”.带宽是按位来描述的. 2.MB/s为速度单位,在“MB/s”中的“B”是指“Byte(字节)”.因为数据是按字节传输的. 3.所谓 1M 宽带,其实是指 1Mbps (兆比特每秒),亦即 1 x 1024 / 8 = 1

使用JavaScript实现机器学习和神经学网络

欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 下载heaton-javascript-ml.zip - 45.1 KB 基本介绍 在本文中,你会对如何使用JavaScript实现机器学习这个话题有一些基本的了解.我会使用Encon(一个先进的神经网络和机器学习框架)这个框架,并向你们展示如何用这个框架来实现光学字符辨识,模拟退火法,遗传算法和神经网络.Encog同时包括了几个GUI窗体小部件,这些小部件可以更方便地显示出一般机器学习任务的输出. 运行环境 Encog是一个面向Java,

android 网络编程--socket tcp/ip udp http之间的关系

网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层,一般编程人员接触最多的就是应用层和运输层,再往下的就是所谓的媒体层了,不是我们研究的对象. 下面是应用层.运输层,网络层.链路层通信协议概图.我们经常接触到的一般是: http协议:应用层协议,并且http协议是基于tcp连接的,主要解决的是如何包装协议的 tcp协议:运输层协议,通常也叫做tcp/ip协议,主要解决数据如何在网络中传输 udp协议:运输层协议,用户数据报协议,不可靠的协议,只负责把应用层的协议的数

WinForm中回车键实现文本框之间的跳转

利用窗体的KeyPreView .设置KeyPreView = true 设置窗体的KeyPreView 属性为True后,那么窗体内的子控件响应KeyPress事件(或其他事件)之前,会先响应窗体的KeyPress事件.如下图,如果按下了Enter键, 则会先执行Form4_KeyPress,然后再执行textBox1_KeyPress. this.SelectNextControl(this.ActiveControl, true, true, false, false)意思是激活下一个控件

下拉框与文本框之间的转换

<html> <head> <meta charset="utf-8"> <title>下拉框与文本框之间的转换</title> <script language="JavaScript"> function demo(){ var sel=document.all["sel"]; var tx=document.all["txt"]; //alert(s