dmlc--dgl
44089c8b4d
* Merge * [Graph][CUDA] Graph on GPU and many refactoring (#1791) * change edge_ids behavior and C++ impl * fix unittests; remove utils.Index in edge_id * pass mx and th tests * pass tf test * add aten::Scatter_ * Add nonzero; impl CSRGetDataAndIndices/CSRSliceMatrix * CSRGetData and CSRGetDataAndIndices passed tests * CSRSliceMatrix basic tests * fix bug in empty slice * CUDA CSRHasDuplicate * has_node; has_edge_between * predecessors, successors * deprecate send/recv; fix send_and_recv * deprecate send/recv; fix send_and_recv * in_edges; out_edges; all_edges; apply_edges * in deg/out deg * subgraph/edge_subgraph * adj * in_subgraph/out_subgraph * sample neighbors * set/get_n/e_repr * wip: working on refactoring all idtypes * pass ndata/edata tests on gpu * fix * stash * workaround nonzero issue * stash * nx conversion * test_hetero_basics except update routines * test_update_routines * test_hetero_basics for pytorch * more fixes * WIP: flatten graph * wip: flatten * test_flatten * test_to_device * fix bug in to_homo * fix bug in CSRSliceMatrix * pass subgraph test * fix send_and_recv * fix filter * test_heterograph * passed all pytorch tests * fix mx unittest * fix pytorch test_nn * fix all unittests for PyTorch * passed all mxnet tests * lint * fix tf nn test * pass all tf tests * lint * lint * change deprecation * try fix compile * lint * update METIDS * fix utest * fix * fix utests * try debug * revert * small fix * fix utests * upd * upd * upd * fix * upd * upd * upd * upd * upd * trigger * +1s * [kernel] Use heterograph index instead of unitgraph index (#1813) * upd * upd * upd * fix * upd * upd * upd * upd * upd * trigger * +1s * [Graph] Mutation for Heterograph (#1818) * mutation add_nodes and add_edges * Add support for remove_edges, remove_nodes, add_selfloop, remove_selfloop * Fix Co-authored-by: Ubuntu <ubuntu@ip-172-31-51-214.ec2.internal> * upd * upd * upd * fix * [Transfom] Mutable transform (#1833) * add nodesy * All three * Fix * lint * Add some test case * Fix * Fix * Fix * Fix * Fix * Fix * fix * triger * Fix * fix Co-authored-by: Ubuntu <ubuntu@ip-172-31-51-214.ec2.internal> * [Graph] Migrate Batch & Readout module to heterograph (#1836) * dgl.batch * unbatch * fix to device * reduce readout; segment reduce * change batch_num_nodes|edges to function * reduce readout/ softmax * broadcast * topk * fix * fix tf and mx * fix some ci * fix batch but unbatch differently * new checkk * upd * upd * upd * idtype behavior; code reorg * idtype behavior; code reorg * wip: test_basics * pass test_basics * WIP: from nx/ to nx * missing files * upd * pass test_basics:test_nx_conversion * Fix test * Fix inplace update * WIP: fixing tests * upd * pass test_transform cpu * pass gpu test_transform * pass test_batched_graph * GPU graph auto cast to int32 * missing file * stash * WIP: rgcn-hetero * Fix two datasety * upd * weird * Fix capsuley * fuck you * fuck matthias * Fix dgmg * fix bug in block degrees; pass rgcn-hetero * rgcn * gat and diffpool fix also fix ppi and tu dataset * Tree LSTM * pointcloud * rrn; wip: sgc * resolve conflicts * upd * sgc and reddit dataset * upd * Fix deepwalk, gindt and gcn * fix datasets and sign * optimization * optimization * upd * upd * Fix GIN * fix bug in add_nodes add_edges; tagcn * adaptive sampling and gcmc * upd * upd * fix geometric * fix * metapath2vec * fix agnn * fix pickling problem of block * fix utests * miss file * linegraph * upd * upd * upd * graphsage * stgcn_wave * fix hgt * on unittests * Fix transformer * Fix HAN * passed pytorch unittests * lint * fix * Fix cluster gcn * cluster-gcn is ready * on fixing block related codes * 2nd order derivative * Revert "2nd order derivative" This reverts commit 523bf6c249bee61b51b1ad1babf42aad4167f206. * passed torch utests again * fix all mxnet unittests * delete some useless tests * pass all tf cpu tests * disable * disable distributed unittest * fix * fix * lint * fix * fix * fix script * fix tutorial * fix apply edges bug * fix 2 basics * fix tutorial Co-authored-by: yzh119 <expye@outlook.com> Co-authored-by: xiang song(charlie.song) <classicxsong@gmail.com> Co-authored-by: Ubuntu <ubuntu@ip-172-31-51-214.ec2.internal> Co-authored-by: Ubuntu <ubuntu@ip-172-31-7-42.us-west-2.compute.internal> Co-authored-by: Ubuntu <ubuntu@ip-172-31-1-5.us-west-2.compute.internal> Co-authored-by: Ubuntu <ubuntu@ip-172-31-68-185.ec2.internal>
186 行
7.9 KiB
Python
186 行
7.9 KiB
Python
import dgl
|
|
import math
|
|
import torch
|
|
import torch.nn as nn
|
|
import torch.nn.functional as F
|
|
import dgl.function as fn
|
|
|
|
class HGTLayer(nn.Module):
|
|
def __init__(self,
|
|
in_dim,
|
|
out_dim,
|
|
node_dict,
|
|
edge_dict,
|
|
n_heads,
|
|
dropout = 0.2,
|
|
use_norm = False):
|
|
super(HGTLayer, self).__init__()
|
|
|
|
self.in_dim = in_dim
|
|
self.out_dim = out_dim
|
|
self.node_dict = node_dict
|
|
self.edge_dict = edge_dict
|
|
self.num_types = len(node_dict)
|
|
self.num_relations = len(edge_dict)
|
|
self.total_rel = self.num_types * self.num_relations * self.num_types
|
|
self.n_heads = n_heads
|
|
self.d_k = out_dim // n_heads
|
|
self.sqrt_dk = math.sqrt(self.d_k)
|
|
self.att = None
|
|
|
|
self.k_linears = nn.ModuleList()
|
|
self.q_linears = nn.ModuleList()
|
|
self.v_linears = nn.ModuleList()
|
|
self.a_linears = nn.ModuleList()
|
|
self.norms = nn.ModuleList()
|
|
self.use_norm = use_norm
|
|
|
|
for t in range(self.num_types):
|
|
self.k_linears.append(nn.Linear(in_dim, out_dim))
|
|
self.q_linears.append(nn.Linear(in_dim, out_dim))
|
|
self.v_linears.append(nn.Linear(in_dim, out_dim))
|
|
self.a_linears.append(nn.Linear(out_dim, out_dim))
|
|
if use_norm:
|
|
self.norms.append(nn.LayerNorm(out_dim))
|
|
|
|
self.relation_pri = nn.Parameter(torch.ones(self.num_relations, self.n_heads))
|
|
self.relation_att = nn.Parameter(torch.Tensor(self.num_relations, n_heads, self.d_k, self.d_k))
|
|
self.relation_msg = nn.Parameter(torch.Tensor(self.num_relations, n_heads, self.d_k, self.d_k))
|
|
self.skip = nn.Parameter(torch.ones(self.num_types))
|
|
self.drop = nn.Dropout(dropout)
|
|
|
|
nn.init.xavier_uniform_(self.relation_att)
|
|
nn.init.xavier_uniform_(self.relation_msg)
|
|
|
|
def edge_attention(self, edges):
|
|
etype = edges.data['id'][0]
|
|
|
|
'''
|
|
Step 1: Heterogeneous Mutual Attention
|
|
'''
|
|
relation_att = self.relation_att[etype]
|
|
relation_pri = self.relation_pri[etype]
|
|
key = torch.bmm(edges.src['k'].transpose(1,0), relation_att).transpose(1,0)
|
|
att = (edges.dst['q'] * key).sum(dim=-1) * relation_pri / self.sqrt_dk
|
|
|
|
'''
|
|
Step 2: Heterogeneous Message Passing
|
|
'''
|
|
relation_msg = self.relation_msg[etype]
|
|
val = torch.bmm(edges.src['v'].transpose(1,0), relation_msg).transpose(1,0)
|
|
return {'a': att, 'v': val}
|
|
|
|
def message_func(self, edges):
|
|
return {'v': edges.data['v'], 'a': edges.data['a']}
|
|
|
|
def reduce_func(self, nodes):
|
|
'''
|
|
Softmax based on target node's id (edge_index_i).
|
|
NOTE: Using DGL's API, there is a minor difference with this softmax with the original one.
|
|
This implementation will do softmax only on edges belong to the same relation type, instead of for all of the edges.
|
|
'''
|
|
att = F.softmax(nodes.mailbox['a'], dim=1)
|
|
h = torch.sum(att.unsqueeze(dim = -1) * nodes.mailbox['v'], dim=1)
|
|
return {'t': h.view(-1, self.out_dim)}
|
|
|
|
def forward(self, G, h):
|
|
with G.local_scope():
|
|
node_dict, edge_dict = self.node_dict, self.edge_dict
|
|
for srctype, etype, dsttype in G.canonical_etypes:
|
|
k_linear = self.k_linears[node_dict[srctype]]
|
|
v_linear = self.v_linears[node_dict[srctype]]
|
|
q_linear = self.q_linears[node_dict[dsttype]]
|
|
|
|
G.nodes[srctype].data['k'] = k_linear(h[srctype]).view(-1, self.n_heads, self.d_k)
|
|
G.nodes[srctype].data['v'] = v_linear(h[srctype]).view(-1, self.n_heads, self.d_k)
|
|
G.nodes[dsttype].data['q'] = q_linear(h[dsttype]).view(-1, self.n_heads, self.d_k)
|
|
|
|
G.apply_edges(func=self.edge_attention, etype=etype)
|
|
G.multi_update_all({etype : (self.message_func, self.reduce_func) \
|
|
for etype in edge_dict}, cross_reducer = 'mean')
|
|
new_h = {}
|
|
for ntype in G.ntypes:
|
|
'''
|
|
Step 3: Target-specific Aggregation
|
|
x = norm( W[node_type] * gelu( Agg(x) ) + x )
|
|
'''
|
|
n_id = node_dict[ntype]
|
|
alpha = torch.sigmoid(self.skip[n_id])
|
|
trans_out = self.drop(self.a_linears[n_id](G.nodes[ntype].data['t']))
|
|
trans_out = trans_out * alpha + h[ntype] * (1-alpha)
|
|
if self.use_norm:
|
|
new_h[ntype] = self.norms[n_id](trans_out)
|
|
else:
|
|
new_h[ntype] = trans_out
|
|
return new_h
|
|
|
|
class HGT(nn.Module):
|
|
def __init__(self, G, node_dict, edge_dict, n_inp, n_hid, n_out, n_layers, n_heads, use_norm = True):
|
|
super(HGT, self).__init__()
|
|
self.node_dict = node_dict
|
|
self.edge_dict = edge_dict
|
|
self.gcs = nn.ModuleList()
|
|
self.n_inp = n_inp
|
|
self.n_hid = n_hid
|
|
self.n_out = n_out
|
|
self.n_layers = n_layers
|
|
self.adapt_ws = nn.ModuleList()
|
|
for t in range(len(node_dict)):
|
|
self.adapt_ws.append(nn.Linear(n_inp, n_hid))
|
|
for _ in range(n_layers):
|
|
self.gcs.append(HGTLayer(n_hid, n_hid, node_dict, edge_dict, n_heads, use_norm = use_norm))
|
|
self.out = nn.Linear(n_hid, n_out)
|
|
|
|
def forward(self, G, out_key):
|
|
h = {}
|
|
for ntype in G.ntypes:
|
|
n_id = self.node_dict[ntype]
|
|
h[ntype] = F.gelu(self.adapt_ws[n_id](G.nodes[ntype].data['inp']))
|
|
for i in range(self.n_layers):
|
|
h = self.gcs[i](G, h)
|
|
return self.out(h[out_key])
|
|
|
|
class HeteroRGCNLayer(nn.Module):
|
|
def __init__(self, in_size, out_size, etypes):
|
|
super(HeteroRGCNLayer, self).__init__()
|
|
# W_r for each relation
|
|
self.weight = nn.ModuleDict({
|
|
name : nn.Linear(in_size, out_size) for name in etypes
|
|
})
|
|
|
|
def forward(self, G, feat_dict):
|
|
# The input is a dictionary of node features for each type
|
|
funcs = {}
|
|
for srctype, etype, dsttype in G.canonical_etypes:
|
|
# Compute W_r * h
|
|
Wh = self.weight[etype](feat_dict[srctype])
|
|
# Save it in graph for message passing
|
|
G.nodes[srctype].data['Wh_%s' % etype] = Wh
|
|
# Specify per-relation message passing functions: (message_func, reduce_func).
|
|
# Note that the results are saved to the same destination feature 'h', which
|
|
# hints the type wise reducer for aggregation.
|
|
funcs[etype] = (fn.copy_u('Wh_%s' % etype, 'm'), fn.mean('m', 'h'))
|
|
# Trigger message passing of multiple types.
|
|
# The first argument is the message passing functions for each relation.
|
|
# The second one is the type wise reducer, could be "sum", "max",
|
|
# "min", "mean", "stack"
|
|
G.multi_update_all(funcs, 'sum')
|
|
# return the updated node feature dictionary
|
|
return {ntype : G.nodes[ntype].data['h'] for ntype in G.ntypes}
|
|
|
|
|
|
class HeteroRGCN(nn.Module):
|
|
def __init__(self, G, in_size, hidden_size, out_size):
|
|
super(HeteroRGCN, self).__init__()
|
|
# create layers
|
|
self.layer1 = HeteroRGCNLayer(in_size, hidden_size, G.etypes)
|
|
self.layer2 = HeteroRGCNLayer(hidden_size, out_size, G.etypes)
|
|
|
|
def forward(self, G, out_key):
|
|
input_dict = {ntype : G.nodes[ntype].data['inp'] for ntype in G.ntypes}
|
|
h_dict = self.layer1(G, input_dict)
|
|
h_dict = {k : F.leaky_relu(h) for k, h in h_dict.items()}
|
|
h_dict = self.layer2(G, h_dict)
|
|
# get paper logits
|
|
return h_dict[out_key]
|