Graph Embedding:Node2Vec
參考文章:Alias Method離散分布隨機取樣 | 天空的城在圖的隨機游走中,有一塊需要隨機取樣, 比如當(dāng)前到達v節(jié)點,那么下一次隨機會到達哪個節(jié)點。這種問題其實就是離散分布的隨機變量的取樣問題。 查了一些資料, 發(fā)現(xiàn)Alias Method 是一種很高效的方式。https://shomy.top/2017/05/09/alias-method-sampling/
【Graph Embedding】node2vec:算法原理,實現(xiàn)和應(yīng)用_淺夢的學(xué)習(xí)筆記-CSDN博客_node2vec前面介紹過基于DFS鄰域的DeepWalk和基于BFS鄰域的LINE。node2vec則是一種綜合考慮dfs鄰域和bfs鄰域的graph embedding方法。DeepWalk:算法原理,實現(xiàn)和應(yīng)用LINE:算法原理,實現(xiàn)和應(yīng)用簡單來說,node2vec是deepwalk的一種擴展,可以看作是結(jié)合了dfs和bfs隨機游走的deepwalk。nodo2vec 算法原理優(yōu)化目標(biāo)設(shè)f(u)...https://blog.csdn.net/u012151283/article/details/87081272?spm=1001.2014.3001.5502
參考視頻:【圖神經(jīng)網(wǎng)絡(luò)】GNN從入門到精通_嗶哩嗶哩_bilibili課程已經(jīng)更新完畢,PPT,論文,代碼在置頂評論下載。結(jié)合論文和源碼,才能到達最好效果https://www.bilibili.com/video/BV1K5411H7EQ?p=5
Code:
論文鏈接:
DeepWalk可以認為是random walk + skip_gram的模型
random walk本質(zhì)上是一個DFS(深度優(yōu)先探索)的過程,丟失了BFS(廣度優(yōu)先探索)的鄰居結(jié)構(gòu)信息;而node2vec可以簡單的解釋為對deepwalk的隨機過程優(yōu)化,綜合考慮了DFS和BFS的游走方式,提出了一個biased random walk,訓(xùn)練仍然是skip_gram
node2vec 使用了一個變量a來控制節(jié)點的走向,而a是由參數(shù)p,q控制的
?在上圖中,我們已經(jīng)從 t 節(jié)點走到了 V節(jié)點。然后我們要,求下一次游走到其他節(jié)點的概率,我們定義V節(jié)點到下一個節(jié)點的概率為,從公式里我們可以看出節(jié)點v到節(jié)點x的概率? π vx= 上一個節(jié)點 t?游走到節(jié)點 x?的概率? *? Wvx。Wvx表示節(jié)點V到節(jié)點x的邊的權(quán)重大小,這里我著重看一下αpq(t,x)
?我們可以看到α(pq)總共分為三種情況(說明一下,下面的x和上面圖中的x1,2,3節(jié)點沒什么關(guān)系,下面的x表示一個未知節(jié)點):
(1)如果距離d(tx) = 0:我們從上面圖中可以看到,距離t節(jié)點距離為0的節(jié)點只有 t 節(jié)點本身,或者我們從t節(jié)點出發(fā)到 x節(jié)點 然后再返回到t節(jié)點,即(t? - x - t),那么我們αpq(t,x)的概率此時為為 1/ p,那我們 節(jié)點 v 到 節(jié)點 t 的概率π vx就為
?(2)如果距離d(tx) = 1:我們從上圖中可以看到? ,距離t節(jié)點距離為1的節(jié)點有z節(jié)點和x1節(jié)點,也就是說我們t節(jié)點游走到v節(jié)點之后在走到z和x1節(jié)點的概率αpq(t,x)是等于1的,那么我們 節(jié)點v到節(jié)點x1的概率π vx =?,但是節(jié)點v到節(jié)點z的概率 = 0,因為節(jié)點v和節(jié)點z之間沒有節(jié)點相連接,即Wvz = 0
?(3)如果距離d(tx) = 2:我們從上圖中可以看到? ,距離 t節(jié)點距離為2的節(jié)點有x2節(jié)點和x3節(jié)點,也就是說我們 t節(jié)點 游走到 v節(jié)點 之后在走到x2和x3節(jié)點的概率αpq(t,x)是等于1 / q 的,那么我們 節(jié)點v到節(jié)點x2,x3的概率 π vx =
?上面我們說了,α是由參數(shù)p和q來控制的
-
參數(shù)??:表示節(jié)點之間的最短路徑,取值為0,1,2
-
參數(shù) p :返回參數(shù),控制重新采樣上一步已訪問節(jié)點的概率。
參數(shù)p并不直接控制整個游走過程時DFS還是BFS,只控制游走的區(qū)域是一直接近起點還是逐漸遠離起點 - q:出入?yún)?shù),控制采樣的方向。
-
當(dāng)參數(shù) q > 1 時,接下來采樣的節(jié)點傾向于向? t 靠近,偏向于bfs;
-
當(dāng)參數(shù)? q < 1時,接下來采樣的節(jié)點傾向于向? t 遠離,偏向于dfs;
-
?可以發(fā)現(xiàn),當(dāng) p = q = 1? 時,node2vec就是一個deepwalk模型了
?學(xué)習(xí)算法
采樣完頂點序列后,剩下的步驟就和deepwalk一樣了,用word2vec去學(xué)習(xí)頂點的embedding向量。
值得注意的是node2vecWalk中不再是隨機抽取鄰接點,而是按概率抽取,node2vec采用了Alias算法進行頂點采樣。下面這個鏈接對Alias的講解非常通俗易懂
Alias Method離散分布隨機取樣 | 天空的城在圖的隨機游走中,有一塊需要隨機取樣, 比如當(dāng)前到達v節(jié)點,那么下一次隨機會到達哪個節(jié)點。這種問題其實就是離散分布的隨機變量的取樣問題。 查了一些資料, 發(fā)現(xiàn)Alias Method 是一種很高效的方式。https://shomy.top/2017/05/09/alias-method-sampling/
node2vecWalk
通過上面的偽代碼可以看到,node2vec和deepwalk非常類似,主要區(qū)別在于頂點序列的采樣策略不同,所以這里我們主要關(guān)注node2vecWalk的實現(xiàn)。
由于采樣時需要考慮前面2步訪問過的頂點,所以當(dāng)訪問序列中只有1個頂點時,直接使用當(dāng)前頂點和鄰居頂點之間的邊權(quán)作為采樣依據(jù)。 當(dāng)序列多余2個頂點時,使用文章提到的有偏采樣。
def node2vec_walk(self, walk_length, start_node):G = self.G alias_nodes = self.alias_nodes alias_edges = self.alias_edgeswalk = [start_node]while len(walk) < walk_length: cur = walk[-1] cur_nbrs = list(G.neighbors(cur)) if len(cur_nbrs) > 0: if len(walk) == 1: walk.append(cur_nbrs[alias_sample(alias_nodes[cur][0], alias_nodes[cur][1])]) else: prev = walk[-2] edge = (prev, cur) next_node = cur_nbrs[alias_sample(alias_edges[edge][0],alias_edges[edge][1])] walk.append(next_node) else: breakreturn walk構(gòu)造采樣表
preprocess_transition_probs分別生成alias_nodes和alias_edges,alias_nodes存儲著在每個頂點時決定下一次訪問其鄰接點時需要的alias表(不考慮當(dāng)前頂點之前訪問的頂點)。alias_edges存儲著在前一個訪問頂點為 t??,當(dāng)前頂點為??V時決定下一次訪問哪個鄰接點時需要的alias表。
get_alias_edge方法返回的是在上一次訪問頂點 t??,當(dāng)前訪問頂點為 v?時到下一個頂點 x?的未歸一化轉(zhuǎn)移概率?
def get_alias_edge(self, t, v):G = self.G p = self.p q = self.qunnormalized_probs = [] for x in G.neighbors(v): weight = G[v][x].get('weight', 1.0)# w_vx if x == t:# d_tx == 0 unnormalized_probs.append(weight/p) elif G.has_edge(x, t):# d_tx == 1 unnormalized_probs.append(weight) else:# d_tx == 2 unnormalized_probs.append(weight/q) norm_const = sum(unnormalized_probs) normalized_probs = [float(u_prob)/norm_const for u_prob in unnormalized_probs]return create_alias_table(normalized_probs)def preprocess_transition_probs(self):G = self.Galias_nodes = {} for node in G.nodes(): unnormalized_probs = [G[node][nbr].get('weight', 1.0) for nbr in G.neighbors(node)] norm_const = sum(unnormalized_probs) normalized_probs = [float(u_prob)/norm_const for u_prob in unnormalized_probs] alias_nodes[node] = create_alias_table(normalized_probs)alias_edges = {}for edge in G.edges(): alias_edges[edge] = self.get_alias_edge(edge[0], edge[1])self.alias_nodes = alias_nodes self.alias_edges = alias_edgesreturnnode2vec應(yīng)用
使用node2vec在wiki數(shù)據(jù)集上進行節(jié)點分類任務(wù)和可視化任務(wù)。 wiki數(shù)據(jù)集包含 2,405 個網(wǎng)頁和17,981條網(wǎng)頁之間的鏈接關(guān)系,以及每個網(wǎng)頁的所屬類別。 通過簡單的超參搜索,這里使用p=0.25,q=4的設(shè)置。
本例中的訓(xùn)練,評測和可視化的完整代碼在下面的git倉庫中,
G = nx.read_edgelist('../data/wiki/Wiki_edgelist.txt',create_using=nx.DiGraph(),nodetype=None,data=[('weight',int)])model = Node2Vec(G,walk_length=10,num_walks=80,p=0.25,q=4,workers=1) model.train(window_size=5,iter=3) embeddings = model.get_embeddings()evaluate_embeddings(embeddings) plot_embeddings(embeddings)總結(jié)
以上是生活随笔為你收集整理的Graph Embedding:Node2Vec的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javaWeb框架开发
- 下一篇: c语言怎么写注释,C语言如何注释一段代码