日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【Graph Embedding】node2vec:算法原理,实现和应用

發布時間:2023/12/31 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Graph Embedding】node2vec:算法原理,实现和应用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前面介紹過基于DFS鄰域的DeepWalk和基于BFS鄰域的LINE。

DeepWalk:算法原理,實現和應用
LINE:算法原理,實現和應用

node2vec是一種綜合考慮DFS鄰域和BFS鄰域的graph embedding方法。簡單來說,可以看作是eepwalk的一種擴展,可以看作是結合了DFS和BFS隨機游走的deepwalk。

nodo2vec 算法原理

優化目標

f(u)f(u)f(u)是將頂點uuu映射為embedding向量的映射函數,對于圖中每個頂點uuu,定義NS(u)N_S(u)NS?(u)為通過采樣策略SSS采樣出的頂點uuu的近鄰頂點集合。

node2vec優化的目標是給定每個頂點條件下,令其近鄰頂點出現的概率最大。

maxf∑u∈Vlog?Pr(NS(U)∣f(u))max_f {\sum_{u\in V}\log{Pr(N_S(U)|f(u))}}maxf?uV?logPr(NS?(U)f(u))

為了將上述最優化問題可解,文章提出兩個假設:

  • 條件獨立性假設
    假設給定源頂點下,其近鄰頂點出現的概率與近鄰集合中其余頂點無關。
    Pr(Ns(u)∣f(u))=∏ni∈Ns(u)Pr(ni∣f(u))Pr(N_s(u)|f(u))=\prod_{n_i\in N_s(u)} Pr(n_i|f(u))Pr(Ns?(u)f(u))=ni?Ns?(u)?Pr(ni?f(u))
  • 特征空間對稱性假設
    這里是說一個頂點作為源頂點和作為近鄰頂點的時候共享同一套embedding向量。(對比LINE中的2階相似度,一個頂點作為源點和近鄰點的時候是擁有不同的embedding向量的)
    在這個假設下,上述條件概率公式可表示為Pr(ni∣f(u))=exp?f(ni)?f(u)∑v∈Vexp?f(v)?f(u)Pr(n_i|f(u))=\frac{\exp{f(n_i)\cdot f(u)}}{\sum_{v\in V}{\exp{f(v)\cdot f(u)}}}Pr(ni?f(u))=vV?expf(v)?f(u)expf(ni?)?f(u)?

根據以上兩個假設條件,最終的目標函數表示為
maxf∑u∈V[?log?Zu+∑ni∈Ns(u)f(ni)?f(u)]max_f{\sum_{u\in V}[-\log{Z_u}+\sum_{n_i\in N_s(u)}{f(n_i)\cdot f(u)}]}maxf?uV?[?logZu?+ni?Ns?(u)?f(ni?)?f(u)]

由于歸一化因子Zu=∑ni∈Ns(u)exp?(f(ni)?f(u))Z_u=\sum_{n_i\in N_s(u)}{\exp(f(n_i)\cdot f(u))}Zu?=ni?Ns?(u)?exp(f(ni?)?f(u))的計算代價高,所以采用負采樣技術優化。

采樣策略

node2vec依然采用隨機游走的方式獲取頂點的近鄰序列,不同的是node2vec采用的是一種有偏的隨機游走。

給定當前頂點vvv,訪問下一個頂點xxx的概率為
P(ci=x∣ci?1=v)={πvxZif?(v,x)∈E0otherwiseP(c_i=x|c_{i-1}=v)=\left\{ \begin{aligned} \frac{\pi_ {vx}}{Z} & & \text{if }(v,x)\in E \\ 0 & & \text{otherwise} \\ \end{aligned} \right. P(ci?=xci?1?=v)=????Zπvx??0??if?(v,x)Eotherwise?
πvx\pi_{vx}πvx?是頂點vvv和頂點xxx之間的未歸一化轉移概率,ZZZ是歸一化常數。

node2vec引入兩個超參數pppqqq來控制隨機游走的策略,假設當前隨機游走經過邊(t,v)(t,v)(t,v)到達頂點vvv
πvx=αpq(t,x)?wvx\pi_{vx}=\alpha_{pq}(t,x)\cdot w_{vx}πvx?=αpq?(t,x)?wvx?wvxw_{vx}wvx?是頂點vvvxxx之間的邊權,

αpq(t,x)={1p=if?dtx=01=if?dtx=11q=if?dtx=2\alpha_{pq}(t,x)=\left\{ \begin{aligned} \frac{1}{p} & = & \text{if }d_{tx}=0\\ 1 & = & \text{if }d_{tx}=1\\ \frac{1}{q} & = & \text{if }d_{tx}=2\\ \end{aligned} \right. αpq?(t,x)=??????????????p1?1q1??===?if?dtx?=0if?dtx?=1if?dtx?=2?
dtxd_{tx}dtx?為頂點ttt和頂點xxx之間的最短路徑距離。

下面討論超參數pppqqq對游走策略的影響

  • Return parameter,p
    參數ppp控制重復訪問剛剛訪問過的頂點的概率。
    注意到ppp僅作用于dtx=0d_{tx}=0dtx?=0的情況,而dtx=0d_{tx}=0dtx?=0表示頂點xxx就是訪問當前頂點vvv之前剛剛訪問過的頂點。
    那么若ppp較高,則訪問剛剛訪問過的頂點的概率會變低,反之變高。
  • In-out papameter,q
    qqq控制著游走是向外還是向內,若q>1,隨機游走傾向于訪問和ttt接近的頂點(偏向BFS)。若q<1q<1q<1,傾向于訪問遠離ttt的頂點(偏向DFS)。

下面的圖描述的是當從t訪問到v時,決定下一個訪問頂點時每個頂點對應的α\alphaα

學習算法

采樣完頂點序列后,剩下的步驟就和deepwalk一樣了,用word2vec去學習頂點的embedding向量。
值得注意的是node2vecWalk中不再是隨機抽取鄰接點,而是按概率抽取,node2vec采用了Alias算法進行頂點采樣。
Alias Method:時間復雜度O(1)的離散采樣方法

node2vec核心代碼

node2vecWalk

通過上面的偽代碼可以看到,node2vec和deepwalk非常類似,主要區別在于頂點序列的采樣策略不同,所以這里我們主要關注node2vecWalk的實現。

由于采樣時需要考慮前面2步訪問過的頂點,所以當訪問序列中只有1個頂點時,直接使用當前頂點和鄰居頂點之間的邊權作為采樣依據。
當序列多余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

構造采樣表

preprocess_transition_probs分別生成alias_nodes和alias_edges,alias_nodes存儲著在每個頂點時決定下一次訪問其鄰接點時需要的alias表(不考慮當前頂點之前訪問的頂點)。alias_edges存儲著在前一個訪問頂點為ttt,當前頂點為vvv時決定下一次訪問哪個鄰接點時需要的alias表。

get_alias_edge方法返回的是在上一次訪問頂點ttt,當前訪問頂點為vvv時到下一個頂點xxx的未歸一化轉移概率πvx=αpq(t,x)?wvx\pi_{vx}=\alpha_{pq}(t,x)\cdot w_{vx}πvx?=αpq?(t,x)?wvx?

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_edgesreturn

node2vec應用

使用node2vec在wiki數據集上進行節點分類任務和可視化任務。 wiki數據集包含 2,405 個網頁和17,981條網頁之間的鏈接關系,以及每個網頁的所屬類別。 通過簡單的超參搜索,這里使用p=0.25,q=4的設置。

本例中的訓練,評測和可視化的完整代碼在下面的git倉庫中,

https://github.com/shenweichen/GraphEmbedding

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)

分類任務

micro-F1: 0.6757
macro-F1: 0.5917

這個結果相比于DeepWalk和LINE是有提升的。

可視化

這個結果相比于DeepWalk和LINE可以看到不同類別的分布更加分散了。

參考資料

  • Grover A, Leskovec J. node2vec: Scalable Feature Learning for Networks[C]// Acm Sigkdd International Conference on Knowledge Discovery & Data Mining. 2016.

圖算法干貨匯總

我把近年來主流的圖表示學習方法的paper和對應的代碼實現進行了匯總整理,掃碼關注公眾號【淺夢的學習筆記】,后臺回復【圖算法】即可打包下載。


歡迎加入星球群,一個由1300+小伙伴共建的交流平臺,專注于前沿graph embedding算法技術與實踐經驗的分享學習。

總結

以上是生活随笔為你收集整理的【Graph Embedding】node2vec:算法原理,实现和应用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。