Hello everyone,
When training a model with GatedGraphConv for some reason DGLError: Invalid edge
rises.
Model:
class GatedGNNModel(torch.nn.Module):
def __init__(self, in_dim, hidden_dim, n_steps, n_etypes, n_classes):
super(GatedGNNModel, self).__init__()
self.in_dim = in_dim
self.out_dim = hidden_dim
self.n_steps = n_steps
self.n_etypes = n_etypes
self.n_classes = n_classes
# Define topology and functions
# GatedGraphConv Layer
self.g_conv = dgl.nn.pytorch.GatedGraphConv(self.in_dim, self.out_dim, self.n_steps, n_etypes)
# Linear (Classification Layer)
self.output_layer = torch.nn.Linear(self.out_dim, self.n_classes)
# Functions and properties
self.activation = torch.nn.LeakyReLU()
self.dropout = torch.nn.Dropout(0.2)
def forward(self, g, h, e_list, labels):
labels = labels.cuda()
g = g.to(torch.device("cuda"))
_h = h.cuda()
_e_list = etypes.cuda()
h = torch.nn.functional.leaky_relu(self.g_conv(g, _h, _e_list))
h = self.dropout(h)
g.ndata['h'] = _h
readout_features = dgl.max_nodes(g, 'h')
logits = torch.nn.functional.leaky_relu(self.output_layer(readout_features))
preds = torch.argmax(logits, -1)
_labels = labels.cuda()
loss = torch.nn.functional.cross_entropy(logits, _labels)
return loss, preds
Training loop:
for epoch in range(50):
model.train()
for batched_graph, labels in train_dataloader:
feats = batched_graph.ndata['node_feat']
etypes = batched_graph.edata['edge_type']
opt.zero_grad()
loss, preds = model(batched_graph, feats, etypes, labels)
loss.backward()
opt.step()
with torch.no_grad():
y_preds = []
y_trues = []
model.eval()
for v_graph, v_label in test_dataloader:
v_feats = v_graph.ndata['node_feat']
v_etypes = v_graph.edata['edge_type']
v_loss, v_preds = model(v_graph, v_feats, v_etypes, v_label)
y_pred = preds.cpu().tolist()
y_preds.append(y_pred[0])
y_trues.append(v_label[0])
f1 = f1_score(y_trues, y_preds, average='macro')
acc = accuracy_score(y_trues, y_preds)
print("="*100)
print(f"Epoch {epoch}")
print("Dev F1 %.2f" % f1 * 100)
print("Dev Acc %.2f" % acc * 100)
print("="*100)
As for the dataset, it consists of networkx graphs (where some are multigraphs). I have converted each raw graph as follows (then save the whole set in a .bin using dgl.save_graphs
):
dgl.from_networkx(nx_graph, node_attrs=['node_feat'], edge_attrs=['edge_type'], edge_id_attr_name='eid')
Where node_feat
is a 769-dim tensor and edge_type
is a tensor that contains the types of edges (values between 0 and 9)
Error:
---------------------------------------------------------------------------
DGLError Traceback (most recent call last)
Input In [58], in <cell line: 1>()
19 v_feats = v_graph.ndata['node_feat']
20 v_etypes = v_graph.edata['edge_type']
---> 21 v_loss, v_preds = model(v_graph, v_feats, v_etypes, v_label)
22 y_pred = preds.cpu().tolist()
24 y_preds.append(y_pred[0])
File /usr/local/lib/python3.9/dist-packages/torch/nn/modules/module.py:1130, in Module._call_impl(self, *input, **kwargs)
1126 # If we don't have any hooks, we want to skip the rest of the logic in
1127 # this function, and just call forward.
1128 if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
1129 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1130 return forward_call(*input, **kwargs)
1131 # Do not call functions when jit is used
1132 full_backward_hooks, non_full_backward_hooks = [], []
Input In [54], in GatedGNNModel.forward(self, g, h, e_list, labels)
25 _h = h.cuda()
26 _e_list = etypes.cuda()
---> 27 h = torch.nn.functional.leaky_relu(self.g_conv(g, _h, _e_list))
28 h = self.dropout(h)
29 g.ndata['h'] = _h
File /usr/local/lib/python3.9/dist-packages/torch/nn/modules/module.py:1130, in Module._call_impl(self, *input, **kwargs)
1126 # If we don't have any hooks, we want to skip the rest of the logic in
1127 # this function, and just call forward.
1128 if not (self._backward_hooks or self._forward_hooks or self._forward_pre_hooks or _global_backward_hooks
1129 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1130 return forward_call(*input, **kwargs)
1131 # Do not call functions when jit is used
1132 full_backward_hooks, non_full_backward_hooks = [], []
File /usr/local/lib/python3.9/dist-packages/dgl/nn/pytorch/conv/gatedgraphconv.py:161, in GatedGraphConv.forward(self, graph, feat, etypes)
158 eids = th.nonzero(
159 etypes == i, as_tuple=False).view(-1).type(graph.idtype)
160 if len(eids) > 0:
--> 161 graph.apply_edges(
162 lambda edges: {
163 'W_e*h': self.linears[i](edges.src['h'])},
164 eids
165 )
166 graph.update_all(fn.copy_e('W_e*h', 'm'), fn.sum('m', 'a'))
167 a = graph.ndata.pop('a') # (N, D)
File /usr/local/lib/python3.9/dist-packages/dgl/heterograph.py:4460, in DGLHeteroGraph.apply_edges(self, func, edges, etype, inplace)
4458 edata = core.invoke_gsddmm(g, func)
4459 else:
-> 4460 edata = core.invoke_edge_udf(g, eid, etype, func)
4462 if self._graph.number_of_etypes() == 1 or etype is not None:
4463 self._set_e_repr(etid, eid, edata)
File /usr/local/lib/python3.9/dist-packages/dgl/core.py:76, in invoke_edge_udf(graph, eid, etype, func, orig_eid)
74 edata = graph._edge_frames[etid]
75 else:
---> 76 u, v = graph.find_edges(eid)
77 edata = graph._edge_frames[etid].subframe(eid)
78 if len(u) == 0:
File /usr/local/lib/python3.9/dist-packages/dgl/heterograph.py:3168, in DGLHeteroGraph.find_edges(self, eid, etype)
3166 max_eid = F.as_scalar(F.max(eid, 0))
3167 if max_eid >= self.num_edges(etype):
-> 3168 raise DGLError('Invalid edge ID {:d}'.format(max_eid))
3170 if len(eid) == 0:
3171 empty = F.copy_to(F.tensor([], self.idtype), self.device)
DGLError: Invalid edge ID 9
Thank you