1. 程式人生 > >神經張量網絡:探索文本實體之間的關系

神經張量網絡:探索文本實體之間的關系

訓練樣本 新版本 rom 自己的 最新版本 時間序列 mbed 培訓 社區

歡迎大家前往雲加社區,獲取更多騰訊海量技術實踐幹貨哦~

譯者:Waitingalone

本文翻譯自Gaurav Bhatt在 http://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深度學習的例子


此文已由作者授權雲加社區發布,轉載請註明原文出處

神經張量網絡:探索文本實體之間的關系