node2vec的一些理解
node2vec
node2vec也是一種網絡嵌入的表示方法,它是基于DeepWalk的基礎上進行改進的。主要改進的地方在于它在隨機游走的過程中加入了一個權重,使得游走可以采用深度優先和廣度優先的策略進行游走。
Search bias α
使得隨機游走產生片偏差的最簡單的方法是根據靜態邊緣權重WvxW_vxWv?x進行采樣,在未加權圖的情況下Wvx=1W_{vx}=1Wvx?=1,但是這并不能解釋我們的網絡結構,并且指導我們探索不同的網絡鄰居。此外,與BFS和DFS不同,BFS和DFS是分別適用于結構等價性和同質性的極端抽樣范式,我們的隨機游動應該適應這樣一個事實:這些等價性的概念不是競爭的或排他的,而現實世界的網絡通常表現出兩者的混合。
所以我們定義了一個2階隨機游走,并且定義了兩個參數分別是p和q用來指導我們進行隨機游走。
假設我們有一個隨機游走已經穿過了(t,v)節點并且現在暫時居住在如圖所示的V節點。我們現在要考慮下一步怎么走,那么我們可以使用邊(v,x)的轉移概率ΠvxΠ_{vx}Πvx?用來引導我們從v的下一步怎么走。我們假定了一個轉移概率Πvx=αpq(t,x)?WvxΠ_vx=α_{pq}(t,x)*W_{vx}Πv?x=αpq?(t,x)?Wvx? 其中αpq(t,x)α_{pq}(t,x)αpq?(t,x)定義如下:
其中dtxd_{tx}dtx?表示t和x之間的最短路徑,注意的是dtxd_{tx}dtx?的取值一定是{0,1,2}的其中一個,所以p,q兩個參數能夠很好的指導游走。
例如當終點為t時,我們相當于往回走了,不為t時我們則是向外游走或是向深游走。
返回參數 p:p代表我們游走時重復游走的可能性,如果我們把p設置為一個很高的值(> max(q,1))則可以用來確保我們有極小的可能性重復游走一個節點(除非下一個節點沒有其他鄰居)。這個策略鼓勵我們適度探索,而不是產生冗余。另一方面,如果我們把p的值設為很小(< min(q,1)),則他會使得walk接近我們的起始位置。
In-Out參數 q:他更傾向于訪問距離節點t更遠的節點,這種行為反映了鼓勵向外探索的DFS。然而,這里的一個本質區別是,我們在隨機行走框架中實現了類似DFS的探索。
node2vec 算法流程
如上圖所示,我們一開始主要是要進行我們的靜態權重的賦值,用它來引導我們繼續隨機游走得到隨機游走序列,然后我們將得到的序列利用skip-gram模型進行嵌入,最后得到嵌入矩陣。
具體代碼實現如圖所示,我們首先進入函數利用d_graph生成一個字典,在其中加入概率標簽,然后我們通過循環節點以及節點的鄰居對權重進行賦值,同時對我們的p,q進行策略的更改。最后的d_graph則是我們修改之后的帶有我們設置的權重的重要參數,然后我們將d_graph帶入到我們的游走序列生成的函數當中去。
def parallel_generate_walks(d_graph: dict, global_walk_length: int, num_walks: int, cpu_num: int,sampling_strategy: dict = None, num_walks_key: str = None, walk_length_key: str = None,neighbors_key: str = None, probabilities_key: str = None, first_travel_key: str = None,quiet: bool = False) -> list:"""Generates the random walks which will be used as the skip-gram input.:return: List of walks. Each walk is a list of nodes."""walks = list()if not quiet:pbar = tqdm(total=num_walks, desc='Generating walks (CPU: {})'.format(cpu_num))for n_walk in range(num_walks):# Update progress barif not quiet:pbar.update(1)# Shuffle the nodesshuffled_nodes = list(d_graph.keys())random.shuffle(shuffled_nodes)# Start a random walk from every nodefor source in shuffled_nodes:# Skip nodes with specific num_walksif source in sampling_strategy and \num_walks_key in sampling_strategy[source] and \sampling_strategy[source][num_walks_key] <= n_walk:continue# Start walkwalk = [source]# Calculate walk lengthif source in sampling_strategy:walk_length = sampling_strategy[source].get(walk_length_key, global_walk_length)else:walk_length = global_walk_length# Perform walkwhile len(walk) < walk_length:walk_options = d_graph[walk[-1]].get(neighbors_key, None)# Skip dead end nodesif not walk_options:breakif len(walk) == 1: # For the first stepprobabilities = d_graph[walk[-1]][first_travel_key]walk_to = np.random.choice(walk_options, size=1, p=probabilities)[0]else:probabilities = d_graph[walk[-1]][probabilities_key][walk[-2]]walk_to = np.random.choice(walk_options, size=1, p=probabilities)[0]walk.append(walk_to)walk = list(map(str, walk)) # Convert all to stringswalks.append(walk)if not quiet:pbar.close()return walks生成游走的序列的代碼如上圖所示,我們可以看出將d_graph當中的概率取出,然后帶入到np.random.choice這個函數當中去,這樣我們就是按照一定的概率進行隨機游走,而游走的概率是可以通過修改p,q兩個參數進而進行修改的。最后我們則將我們得到的游走序列walks帶入skip-gram模型進行訓練,得到我們想要的嵌入矩陣。
def fit(self, **skip_gram_params):"""Creates the embeddings using gensim's Word2Vec.:param skip_gram_params: Parameteres for gensim.models.Word2Vec - do not supply 'size' it is taken from the Node2Vec 'dimensions' parameter:type skip_gram_params: dict:return: A gensim word2vec model"""if 'workers' not in skip_gram_params:skip_gram_params['workers'] = self.workersif 'size' not in skip_gram_params:skip_gram_params['size'] = self.dimensionsreturn gensim.models.Word2Vec(self.walks, **skip_gram_params)總結
以上是生活随笔為你收集整理的node2vec的一些理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SM3算法对大文件做摘要
- 下一篇: SOAOffice和iWebOffice