- 边索引
- 异构图
- 采样器
- with g.local_scope()
- add_reverse_edges
- copy_u以及copy_e
- 常用api
本文先讲解一些基础概念与机制,然后有了这些理解之后,我再直接列出常用api。
import dgl
边索引
src=[1,2,3]
dst=[3,4,1]
g=dgl.graph((src,dst))
注意上述,默认就是(1,3)的边索引为0,其他依次类推。
异构图异构图就是节点有不同类型,边有不同类型的图。举个例子如下:
data_dict = {
('user', 'follows', 'user'): (torch.tensor([0, 1]), torch.tensor([1, 2])),
('user', 'follows', 'topic'): (torch.tensor([1, 1]), torch.tensor([1, 2])),
('user', 'plays', 'game'): (torch.tensor([0, 3]), torch.tensor([3, 4]))
}
g = dgl.heterograph(data_dict)
g
上面可能就有人懵逼了,啥跟啥啊。其实上面表示说节点有
user,topic,game
3种类型,边有:
follows,plays
2种类型。以第一个为例:
('user', 'follows', 'user'): (torch.tensor([0, 1]), torch.tensor([1, 2]))
其表示就是说有两条边,(0,1)(1,2),然后这两条边的头实体都是user,尾实体也是user,边类型是follows。
注意:不同节点类型,编码是不同的,例如上述
('user', 'follows', 'user'): (torch.tensor([0, 1]), torch.tensor([1, 2])),
('user', 'follows', 'topic'): (torch.tensor([1, 1]), torch.tensor([1, 2])),
可以看到,在第一行中,0,1,2都是user。
但是在第二行中,1是user,1,2是topic。也就是说,这个topic的1,2是在该节点类型下的独立编码。从这里我们可以推断,topic至少有3个,因为还有0!
下面是我们之前定义异构图返回的结果。
Graph(num_nodes={‘game’: 5, ‘topic’: 3, ‘user’: 4},
num_edges={(‘user’, ‘follows’, ‘topic’): 2, (‘user’, ‘follows’, ‘user’): 2, (‘user’, ‘plays’, ‘game’): 2},
metagraph=[(‘user’, ‘topic’, ‘follows’), (‘user’, ‘user’, ‘follows’), (‘user’, ‘game’, ‘plays’)])
我们来分析一下,这个节点数量就是推断的结果,指各个节点类型的节点数量,其实就是索引的max然后加1。至于边数量就很好理解了,一目了然。元图则表示一共有几种类型的边。
这个节点数量推断的结果,我们也可以显示指定,如下:
data_dict = {
('user', 'follows', 'user'): (torch.tensor([0, 1]), torch.tensor([1, 2])),
('user', 'follows', 'topic'): (torch.tensor([1, 1]), torch.tensor([1, 2])),
('user', 'plays', 'game'): (torch.tensor([0, 3]), torch.tensor([3, 4]))
}
nodes_num={'user': 20, 'game': 10,"topic":10}#有20个user节点
g = dgl.heterograph(data_dict,nodes_num)
g
结果如下:
采样器Graph(num_nodes={‘game’: 10, ‘topic’: 10, ‘user’: 20},
num_edges={(‘user’, ‘follows’, ‘topic’): 2, (‘user’, ‘follows’, ‘user’): 2, (‘user’, ‘plays’, ‘game’): 2},
metagraph=[(‘user’, ‘topic’, ‘follows’), (‘user’, ‘user’, ‘follows’), (‘user’, ‘game’, ‘plays’)])
比如,对于一个图,给定一个源节点1,我们希望采样一些假的目标节点,从而构成一些假边。这个官方也是有api的,不过,这个东西其实不用官方api,我们自己也可以实现。这里由于是介绍,所以还是介绍一下api。
g = dgl.graph(([0, 1, 2], [1, 2, 3]))
neg_sampler = dgl.dataloading.negative_sampler.Uniform(2)#2表示每一个节点采样两个假目标节点。
neg_sampler(g, torch.tensor([0, 1]))
结果如下:
(tensor([0, 0, 1, 1]), tensor([1, 0, 2, 3]))
可以看到,对于源节点0,采样了1,0两个假目标节点。那么有人就会说了,不是采样假目标节点吗?这里怎么采样了1这个真节点?注意,他这个官方api是从所有节点里面均匀分布抽取的,而不是去掉0的邻居之后再均匀分布。
with g.local_scope()这个玩意可以使得除了In-place *** 作之外的 *** 作不会对原图进行修改。(inplace *** 作就是例如a=[1],a[0]=1(inplace),a=[2]不是)
def foo(g):
with g.local_scope():
g.edata['h'] = torch.ones((g.num_edges(), 3))
g.edata['h2'] = torch.ones((g.num_edges(), 3))
return g.edata['h']
g = dgl.graph((torch.tensor([0, 1, 1]), torch.tensor([0, 0, 2])))
g.edata['h'] = torch.zeros((g.num_edges(), 3))
newh = foo(g)
print(g.edata['h']) # still get tensor of all zeros
'h2' in g.edata # new feature set in the function scope is not found
add_reverse_edges
给一个图复制一倍(边反向),其特征之类的也会被复制。注意一个问题,(0,1)复制后变成(1,0),但是他们的边id是相同的,因为边id并不是索引。
copy_u以及copy_e这两个东西分别对节点和边进行 *** 作。例如:
fn.copy_e('timestamp', 'times')
就是将edata的一个属性'timestamp'
复制一遍,再生成一个属性'times'
。
用途 | 代码 |
---|---|
给定边的id,找到边 | g.find_edges([0,2]) |
给定一个或者多个图,进行压缩并且重新编码,例如对于一个图,可能节点索引不是从0开始的,对于多个图,我们要将其合并,并重新编码 | dgl.compact_graphs(g)/dgl.compact_graphs([g1,g2]) |
给定边的id以及是否重新编码,得到子图 | dgl.edge_subgraph(g, [0, 2]) |
图有什么边的类型 | g.etypes |
图有什么(节点,边,节点)的类型组合 | g.canonical_etypes |
图有什么类型的节点 | g.ntypes |
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)