euler icon indicating copy to clipboard operation
euler copied to clipboard

Deepwalk/Node2vec 随机游走图算法的实现

Open ykwd opened this issue 6 years ago • 11 comments

非常感谢贵司提供这个开源项目!

我对于代码实现有两点疑问,还请不吝赐教:

  1. 欧拉自带的几个算法中,deepwalk和node2vec的随机游走的图算法的实现是不是直接调用的TensorFlow的随机游走,而没有用到欧拉自己的c++的库?

  2. 有没有一个完整的图算法的实现来展示欧拉c++的库的使用的整个流程呢?wiki里面的代码只有简单的遍历之类的,但是感觉欧拉的c++的执行流程和模型都和传统的图计算系统(例如powergraph)不太一样,不是那种定义好算子后就一遍执行到底的,而是需要用户不断调用欧拉的接口来进行交互,不知道我的理解是否正确?

预祝新年快乐!

ykwd avatar Feb 02 '19 04:02 ykwd

1.node2vec,deepwalk使用的是Euler内部的邻居采样接口实现的,从一批根结点出发采样一批邻居,然后重复这个过程得到游走序列。 2.你的理解是对的,Euler提供一些cpp接口对图进行查询采样,用户不断调用这些接口来完成计算过程。我们在Euler的cpp接口之上封装了tf的op,然后基于这些op封装了图学习的一系列算法。

| | 计算机院 魏源 邮箱:[email protected] |

签名由 网易邮箱大师 定制

在2019年02月02日 12:20,ykwd 写道:

非常感谢贵司提供这个开源项目!

我对于代码实现有两点疑问,还请不吝赐教:

欧拉自带的几个算法中,deepwalk和node2vec的随机游走的图算法的实现是不是直接调用的TensorFlow的随机游走,而没有用到欧拉自己的c++的库?

有没有一个完整的图算法的实现来展示欧拉c++的库的使用的整个流程呢?wiki里面的代码只有简单的遍历之类的,但是感觉欧拉的c++的执行流程和模型都和传统的图计算系统(例如powergraph)不太一样,不是那种定义好算子后就一遍执行到底的,而是需要用户不断调用欧拉的接口来进行交互,不知道我的理解是否正确?

预祝新年快乐!

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

zakheav avatar Feb 02 '19 04:02 zakheav

非常抱歉问一个可能比较低级的问题:我发现Python代码里deepwalk和node2vec都调用的是c++编译好的库libtf_euler.so里的random_walk函数,而在c++中,我看了所有的cc文件,都没有找到node2vec的实现,包括在random_walk_op.cc或者walks_ops.cc等。

能否麻烦您指示一下node2vec的实现在哪里呢?

ykwd avatar Feb 02 '19 05:02 ykwd

实际上random walk就是用node2vec实现的,random walk可以看作是node2vec的特殊情况,Euler部分的代码在euler/euler/client/graph.h下面,叫BiasedSampleNeighbor函数

| | 计算机院 魏源 邮箱:[email protected] |

签名由 网易邮箱大师 定制

在2019年02月02日 13:04,ykwd 写道:

非常抱歉问一个可能比较低级的问题:我发现Python代码里deepwalk和node2vec都调用的是c++编译好的库libtf_euler.so里的random_walk函数,而在c++中,我看了所有的cc文件,都没有找到node2vec的实现,包括在random_walk_op.cc或者walks_ops.cc等。

能否麻烦您指示一下node2vec的实现在哪里呢?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

zakheav avatar Feb 02 '19 05:02 zakheav

明白啦,谢谢~

ykwd avatar Feb 02 '19 16:02 ykwd

你好,https://cs.stanford.edu/people/jure/pubs/node2vec-kdd16.pdf 原始论文中, 权重指的是边的权重,而不是当前节点neighbor的权重,我认为这里实现的有误。

实现在,GetSortedFullNeighbor里的neighbors_weight_在graphBuilder构建的时候读的是neighbor的顶点权重而不是边的权重,这里是否实现有误? 虽然可以trick一下不需要改代码,把邻居点的权重设置成边的权重,但是这样不太好。

同样如果lshne 也修改了p q超参数的话,也会走这个逻辑,导致出错。

lixusign avatar May 18 '20 04:05 lixusign

node2vec实现的时候会根据当前节点周围的结构信息生成一个a向量,然后乘以neighbor权重。具体可以看euler/euler/client/graph.cc

| | 魏源 邮箱:[email protected] |

签名由 网易邮箱大师 定制

在2020年05月18日 12:39,lixusign 写道:

你好,https://cs.stanford.edu/people/jure/pubs/node2vec-kdd16.pdf 原始论文中, 权重指的是边的权重,而不是当前节点neighbor的权重,因为neighbor的权重是一个绝对值,无法站在从当前顶点出发的视角进行游走,我认为这里实现的有误。

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

zakheav avatar May 18 '20 12:05 zakheav

我的意思是,用于控制结构性和同质性的P、Q参数 在条件下需要和节点之间的边的权重相乘作为游走的概率依据。而euler的实现是P、Q参数在条件下和”以自身节点看待neighbor权重“的信息做了相乘作为游走概率依据,和原始论文不一致。

lixusign avatar May 19 '20 03:05 lixusign

neighbor的权重是指的邻居边权重,不是邻居节点的权重

zakheav avatar May 19 '20 11:05 zakheav

{ "node_id": "顶点编号,int", "node_type": "顶点类型,int", "node_weight": "顶点权重,float", "neighbor": {"边类型": {"邻居id": "权重", "...": "..."}, "...": "..."}, "uint64_feature": {"属性编号": ["int", "..."], "...": "..."}, "float_feature": {"属性编号": ["float", "..."], "...": "..."}, "binary_feature": {"属性编号": "string", "...": "..."}, "edge":[{ "src_id": "起点id, int", "dst_id": "终点id, int", "edge_type": "边类型, int", "weight": "边权重, float", "uint64_feature": {"属性编号": ["int", "..."], "...": ["int", "..."]}, "float_feature": {"属性编号": ["float", "..."], "...": ["float", "..."]}, "binary_feature": {"属性编号": "string", "...": "..."} }, "..."] }

那edge里的weight也是这条边的权重了,这两个有啥区别?

lixusign avatar May 19 '20 11:05 lixusign

其实是没区别的

| | 魏源 邮箱:[email protected] |

签名由 网易邮箱大师 定制

在2020年05月19日 19:13,lixusign 写道:

{ "node_id": "顶点编号,int", "node_type": "顶点类型,int", "node_weight": "顶点权重,float", "neighbor": {"边类型": {"邻居id": "权重", "...": "..."}, "...": "..."}, "uint64_feature": {"属性编号": ["int", "..."], "...": "..."}, "float_feature": {"属性编号": ["float", "..."], "...": "..."}, "binary_feature": {"属性编号": "string", "...": "..."}, "edge":[{ "src_id": "起点id, int", "dst_id": "终点id, int", "edge_type": "边类型, int", "weight": "边权重, float", "uint64_feature": {"属性编号": ["int", "..."], "...": ["int", "..."]}, "float_feature": {"属性编号": ["float", "..."], "...": ["float", "..."]}, "binary_feature": {"属性编号": "string", "...": "..."} }, "..."] }

那edge里的weight也是这条边的权重了,这两个有啥区别?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

zakheav avatar May 19 '20 11:05 zakheav

明白了,多谢

lixusign avatar May 19 '20 11:05 lixusign