图学习【参考资料2】-知识补充与node2vec代码注解

本项目参考:https://aistudio.baidu.com/aistudio/projectdetail/5012408?contributionType=1
*一、正题篇:DeepWalk、word2vec、node2vec其它相关项目:
关于图计算&图学习的基础知识概览:前置知识点学习(PGL)[系列一] https://aistudio.baidu.com/aistudio/projectdetail/4982973?contributionType=1
图机器学习(GML)&图神经网络(GNN)原理和代码实现(前置学习系列二):https://aistudio.baidu.com/aistudio/projectdetail/4990947?contributionType=1
1.1DeepWalk算法流程【图来源:网络,笔记由笔者添上】
算法流程:

图学习【参考资料2】-知识补充与node2vec代码注解

文章插图
【其中使用skip-gram模型是为了利用梯度的方法对参数进行更新训练】
1.2 Skip Gram算法流程【图来源:网络,笔记由笔者添上】
算法流程:
图学习【参考资料2】-知识补充与node2vec代码注解

文章插图
【其中使用skip-gram模型是为了利用梯度的方法对参数进行更新训练】
此外,关于以上两个算法的定义和概念就不一一展示说明了,后边等有空了补上 。下边说一下我学习的一些参考资料,希望对大家有帮助 。
参考资料1.【论文笔记】DeepWalk——陌上疏影凉1.【网络图模型综述1.【异构图神经网络简介--机器之心1.【Graph Embedding之metapath2vec--圈圈_Master1.【从Random Walk谈到Bacterial foraging optimization algorithm(BFOA),再谈到Ramdom Walk Graph Segmentation图分割算法
二 程序注解【注解展示,是为了方便自己理解,同时也希望能帮到和自己一样在学习这块知识的小伙伴】
1.0 DeepWalk随机游走的实现
图学习【参考资料2】-知识补充与node2vec代码注解

文章插图
实现Graph类的random_walk函数--可参考
1.1 实现的参考代码--DeepWalk的随机游走算法实现思路
  1. 理清successor,outdegree函数的输入输出
  2. 查看补全函数的返回类型--分析可能的结果--我最初的猜测:这walks应该是多个向量的集合,最后确实也是【[[],..]这样的结构多用于扩充,然后联想需要学习向量,所以想到向量递推的那种向量集合】
  3. 生成随机采样索引序列集 -- 这个需要匹配采样形状,以及索引阈值--我是参考一个示例修改的,感悟是: 利用随机数0~1,给rand传入指定shape , 再乘以一个相同shape的数据,可以得到一个>=0, <=最大出度-1的值 , 这样就可以用来索引采样了
  4. 理清上下文变量关系,进行zip打包遍历到一起,然后进行聚合操作即可 。
具体注解在代码中 , 可查阅,基本都是按照一行行注解的
from pgl.graph import Graphimport numpy as npclass UserDefGraph(Graph):def random_walk(self, nodes, walk_len):"""输入:nodes - 当前节点id list (batch_size,)walk_len - 最大路径长度 int输出:以当前节点为起点得到的路径 list (batch_size, walk_len)用到的函数1. self.successor(nodes)描述:获取当前节点的下一个相邻节点id列表输入:nodes - list (batch_size,)输出:succ_nodes - list of list ((num_successors_i,) for i in range(batch_size))2. self.outdegree(nodes)描述:获取当前节点的出度输入:nodes - list (batch_size,)输出:out_degrees - list (batch_size,)"""walks = [[node] for node in nodes]# 首先获得当前节点列表对应的一个向量walks_ids = np.arange(0, len(nodes))# 游走路径中节点对应id号cur_nodes = np.array(nodes)# 当前节点情况for l in range(walk_len):# 根据游走长度进行遍历--破出条件:1. range结束;2. outdegree==0【出度为零,没有可继续的节点】"""选取有下一个节点的路径继续采样 , 否则结束"""outdegree = self.outdegree(cur_nodes)# 计算当前节点的出度--也就是对应有哪些位置的邻近节点walk_mask = (outdegree != 0)# 根据出度来确定掩码--True,False--将出度为0的部分复制为False,反之Trueif not np.any(walk_mask):# 判断是否没有可继续的节点情况--出度为0breakcur_nodes = cur_nodes[walk_mask]# 根据掩码获取可继续前进的节点,作为后边讨论的当前可前行节点walks_ids = walks_ids[walk_mask]# 获取掩码下,原节点id,组成新的work_ids用于后边讨论,但本身还是作为一个节点的标记,对应这是第几个节点outdegree = outdegree[walk_mask]# 根据掩码获取相应的不为0的出度--用于后边计算前行的路径####################################### 请在此补充代码采样出下一个节点'''[注解有点多 , 所以放外边了]PS:1. successor 可获取当前节点的下一个相邻节点id列表 , 那么successor 计算出下一节点的集合后,我们需要从中随机取出一个节点--所以我们要创建随机采样的index_list(索引序列集)2. 创建index_list=>为了才到合适的index信息,采用np.floor与np.random,rand()实现:eg: np.floor(np.random.rand(outdegree.shape[0]) * outdegree).astype('int64')np.random.rand(outdegree.shape[0]): 根据出度集的形状来取得相应形状的随机数--这里体现游走的随机性np.random.rand(outdegree.shape[0]) * outdegree:利用生成的随机数与出度集对应元素相乘——这里得到一些列的随机数,随机数范围在0~最大出度值--保证路径有效np.floor(np.random.rand(outdegree.shape[0]) * outdegree)——实现向下取整,这样就得到了相应游走路径中接下来那个点的索引具体实例:np.floor(np.random.rand(20) * 3).astype('int64')result: array([0, 1, 2, 1, 0, 0, 0, 0, 1, 1, 1, 2, 0, 2, 2, 2, 2, 1, 2, 0])3. 既然知道了随机采样的序列集了,那么接下就是分配新的游走路径了next_nodes = []# 用于后边存放—— 装配有下一个节点的新路径# 参数说明:succ_nodes:相邻节点id列表sample_index:对应出度生成的随即索引集walks_ids:游走路径中节点对应id号# 接下来的循环指的是,将节点列表、随机采样序列、游走路径中节点对应id号一一对应进行填充--得到一个游走情况for s, ind, walk_id in zip(succ_nodes, sample_index, walks_ids):walks[walk_id].append(s[ind])# 注意: 从开始已经知道walks=>[[], [], []]是这种形式的,这样这里的append,就很容易理解成为相应节点添加可以继续前行的节点,形成一条路径next_nodes.append(s[ind])# 同时获取接下来要重新讨论游走时所需的新节点--即:如:从1走到了2,从3走到了7: [[1], [3]]=>[[1, 2], [3, 7]]# 接下来自然就该考虑把新的2, 7 作为下一次游走时讨论出度的节点啦'''succ_nodes = self.successor(cur_nodes)# 返回可继续的节点集合# next_nodes = ...sample_index = np.floor(np.random.rand(outdegree.shape[0]) * outdegree).astype('int64')next_nodes = []for s, ind, walk_id in zip(succ_nodes, sample_index, walks_ids):walks[walk_id].append(s[ind])next_nodes.append(s[ind])######################################cur_nodes = np.array(next_nodes)# 将节点转换为np类型,方便一些操作运算--同时保证前后数据类型# 遍历完游走长度的次数,就可以返回得到的随机游走路径啦return walks

推荐阅读