論文分享 -- >Graph Embedding -- >Structural Deep Network Embedding

博客內容將首發在微信公衆號"跟我一起讀論文啦啦",上面會定期分享機器學習、深度學習、數據挖掘、自然語言處理等高質量論文,歡迎關注!
在這裏插入圖片描述

本次要分享的論文是來自KDD2016的工作,論文鏈接Structural Deep Network Embedding,(簡稱SDNE)參考的代碼鏈接 CODE。本篇論文第一次利用深度學習知識做圖表示學習,其中也定義了與 LINE 中的一階相似性和二階相似性類似的概念,使其能夠捕捉到圖中高階的非線性網絡結構,同時能保留局部和全局結構信息,並且對稀疏網絡具有較好的魯棒性。與 LINE 論文方法相比,該論文方法在一些細節較容易讓人理解。其實驗部分證明了本方法與當時其他Graph Embedding方法相比,具有明顯的優越性。

論文動機和創新點

  • 現實世界中,圖網絡結構無處不在,例如在推薦系統,社羣團體挖掘等應用上,如何挖掘圖中的信息變得尤爲重要。其中一個重要的基礎問題就是,如何學習到有用的network embedding,通常的做法是將embedding空間映射到較低維的空間中進行節點的表示學習。

  • network embedding的學習面臨以下三個挑戰:
    1、如何學習到圖結構背後的高級非線性信息,是一個比較困難的事情。
    2、學習到的network embedding需要能保存 network structure信息,然而圖的結構信息是非常複雜的,如何學習到節點的局部和全局結構信息是比較困難的。
    3、現實世界中,大部分圖網絡是稀疏的,如果僅僅利用由有邊相連的部分進行學習,效果是很差的,所以學習到的network embedding能夠對稀疏網絡圖具有魯棒性。

  • 上面提到的三個挑戰,淺層模型很難有效解決,基於此,本文提出了 Structural Deep Network Embedding,即SDNE。更具體地說,
    1、利用深度神經網絡,將數據映射到一個高度非線性的潛在空間以保存網絡結構和捕捉高級的非線性特徵信息,並且對稀疏網絡具有魯棒性。
    2、提出了一個新的半監督結構的深度模型,同時優化了一階和二階相似度,使得所學習的表示保留了局部和全局網絡結構,並且對稀疏網絡具有魯棒性。

問題描述

圖結構定義

G=(V,E) G=(V,E)
上述公式中VV 表示 節點集合,EE 表示邊集合,對每天邊上的權重 e=(u,v)Ee=(u,v)\in E, ss 爲鄰接矩陣;對於有權重圖,si,js_{i,j} 表示節點ii 和節點jj關係強弱;若無連接,則si,j=0s_{i,j} = 0,反之 si,j>0s_{i,j} > 0,若爲無權重圖,si,j=1s_{i,j} = 1。如上所描述的圖G基本上可以囊括現實世界中的信息網絡。

一階相似度

對於圖中任意兩個節點i,ji, j 都可以由邊進行連接,如果在圖中兩節點有邊則 si,j>0s_{i,j}>0,否則等於0,這種定義也是符合現實邏輯的,在information network中,如果兩個用戶存在連接關係,則該兩個用戶的性格、興趣等可能存在相似性、如果兩個網頁存在連向彼此的鏈接,則該網頁內容可能存在相似性等等。本文中一階相似度用來保存全局圖結構信息。

二階相似度

顯然一階相似度有其侷限性,僅僅利用了有邊連接的部分進行學習,而現實世界中圖大部分是稀疏的;二階相似度指的是 圖中兩節點 相鄰節點的相似程度。本文中二階相似度用來保存局部圖結構信息。

SDNE模型

在這裏插入圖片描述

損失函數

二階相似度優化目標

可以查看上面SDNE網絡圖,圖中深度自編碼由多層神經網絡組成:
yi(1)=σ(W(1)xi+b(1)) y^{(1)}_{i} = \sigma (W^{(1)} x_i + b^{(1)})
yi(k)=σ(W(k)yi(k1)+b(k)),k=2,3,4,...,K y^{(k)}_{i} = \sigma (W^{(k)} y^{(k-1)}_{i}+ b^{(k)}), k=2, 3, 4,..., K

其中,自編碼輸入爲xi=six_i = s_i,即爲鄰接矩陣的第ii 行數據。

自編碼損失函數:
在這裏插入圖片描述
爲了避免稀疏問題(sis_i 中可能存在大量0),這裏加上一個懲罰項BB ,對非0元素給予更大的懲罰:
bi={bi,j}j=1nb_i = \{{b_{i,j}}\}_{j=1}^n
bi,j={1si,j=0β>1 si,j>0b_{i,j} = \left\{\begin{matrix} 1 & s_{i,j} =0\\ \beta >1 & \ s_{i,j} >0 \end{matrix}\right.

顯然以上這種重構過程,將使具有相似鄰域結構的頂點具有相似的潛在表示,可以保存全局的網絡結構信息。

一階相似度優化目標

除了捕捉和保存圖的全局結構信息,還需要捕捉保存圖的局部結構信息。
在這裏插入圖片描述
其中si,js_{i,j} 表示節點ii和節點jj 的權重,yi(k)y_i^{(k)} 表示節點ii 在自編碼的第kk 層的降維輸出,上式借鑑了 Laplacian Eigenmaps的思想,目的讓相似的頂點在降維後的低維空間裏仍舊儘量接近。

通過線性代數的知識,可將上式轉化爲如下:
在這裏插入圖片描述
其中 L=DSL = D−S 爲圖的拉普拉斯矩陣,D爲圖的度矩陣,S爲鄰接矩陣。

SDNE損失函數

在這裏插入圖片描述

其中:
在這裏插入圖片描述

整體算法流程

在這裏插入圖片描述

實驗

本論文實驗部分,利用了五個公開的數據集,在三類任務上進行了實驗,與其baseline model相比,sdne方法無論在泛化能力上、對稀疏網絡的魯棒性上,可視化上等都有較大的優越性。

代碼

代碼參考自:keras-sdne

一階、二階損失函數

def l_2nd(beta):
    def loss_2nd(y_true, y_pred):
        b_ = np.ones_like(y_true)
        b_[y_true != 0] = beta
        x = K.square((y_true - y_pred) * b_)
        t = K.sum(x, axis=-1, )
        return K.mean(t)

    return loss_2nd


def l_1st(alpha):
    def loss_1st(y_true, y_pred):
        L = y_true
        Y = y_pred
        batch_size = tf.to_float(K.shape(L)[0])
        return alpha * 2 * tf.linalg.trace(tf.matmul(tf.matmul(Y, L, transpose_a=True), Y)) / batch_size

    return loss_1st

創建模型

def create_model(node_size, hidden_size=[256, 128], l1=1e-5, l2=1e-4):
    A = Input(shape=(node_size,))
    L = Input(shape=(None,))
    fc = A
    for i in range(len(hidden_size)):
        if i == len(hidden_size) - 1:
            fc = Dense(hidden_size[i], activation='relu',
                       kernel_regularizer=l1_l2(l1, l2), name='1st')(fc)
        else:
            fc = Dense(hidden_size[i], activation='relu',
                       kernel_regularizer=l1_l2(l1, l2))(fc)
    Y = fc
    for i in reversed(range(len(hidden_size) - 1)):
        fc = Dense(hidden_size[i], activation='relu',
                   kernel_regularizer=l1_l2(l1, l2))(fc)

    A_ = Dense(node_size, 'relu', name='2nd')(fc)
    ## A->A_ 自編碼
   	## L->y  Laplacian Eigenmaps
    model = Model(inputs=[A, L], outputs=[A_, Y]) 
    emb = Model(inputs=A, outputs=Y)
    return model, emb

模型訓練

 def train(self, batch_size=1024, epochs=1, initial_epoch=0, verbose=1):
        if batch_size >= self.node_size:
            if batch_size > self.node_size:
                print('batch_size({0}) > node_size({1}),set batch_size = {1}'.format(
                    batch_size, self.node_size))
                batch_size = self.node_size
            return self.model.fit([self.A.todense(), self.L.todense()], [self.A.todense(), self.L.todense()],
                                  batch_size=batch_size, epochs=epochs, initial_epoch=initial_epoch, verbose=verbose,
                                  shuffle=False, )
        else:
            steps_per_epoch = (self.node_size - 1) // batch_size + 1
            hist = History()
            hist.on_train_begin()
            logs = {}
            for epoch in range(initial_epoch, epochs):
                start_time = time.time()
                losses = np.zeros(3)
                for i in range(steps_per_epoch):
                    index = np.arange(
                        i * batch_size, min((i + 1) * batch_size, self.node_size))
                    A_train = self.A[index, :].todense()
                    L_mat_train = self.L[index][:, index].todense()
                    inp = [A_train, L_mat_train]
                    ## inp 作爲模型的輸入;同時又做模型的y_true
                    batch_losses = self.model.train_on_batch(inp, inp)
                    losses += batch_losses
                losses = losses / steps_per_epoch

個人總結

  • 本論文方法中的 一階二階相似度的計算方式,比起LINE來說,直觀上較好理解。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章