Edge Classification with one node type

I followed the instructions from the error:

AssertionError: The HeteroNodeDataView has only one node type. please pass a tensor directly

Therefore, I changed

node_features = graph.nodes[node_type].data['feature']
labels = graph.edges[target_edge].data['label']
train_mask = graph.edges[target_edge].data['train_mask']
feats = {'node': node_features}
opt = torch.optim.Adam(model.parameters())
for epoch in range(100):
    model.train()
    pred = model(graph, feats, target_edge)
    # pred = model(graph, node_features, target_edge)
    loss = ((pred[train_mask] - labels[train_mask]) ** 2).mean()
    opt.zero_grad()
    loss.backward()
    opt.step()
    print(loss.item())

to

node_features = graph.nodes[node_type].data['feature']
labels = graph.edges[target_edge].data['label']
train_mask = graph.edges[target_edge].data['train_mask']
opt = torch.optim.Adam(model.parameters())
for epoch in range(100):
    model.train()
    pred = model(graph, node_features, target_edge)
    loss = ((pred[train_mask] - labels[train_mask]) ** 2).mean()
    opt.zero_grad()
    loss.backward()
    opt.step()
    print(loss.item())

But now I get the following error

RuntimeError: Tensor.__contains__ only supports Tensor or scalar, but you passed in a <class 'str'>.

This is caused by

    def __contains__(self, element):
        r"""Check if `element` is present in tensor

        Args:
            element (Tensor or scalar): element to be checked
                for presence in current tensor"
        """
        if has_torch_function_unary(self):
            return handle_torch_function(Tensor.__contains__, (self,), self, element)
        if isinstance(element, (torch.Tensor, Number)):
            # type hint doesn't understand the __contains__ result array
            return (element == self).any().item()  # type: ignore[union-attr]

        raise RuntimeError(
            "Tensor.__contains__ only supports Tensor or scalar, but you passed in a %s." %
            type(element)
        )

where element is ‘node’
This is triggered by the fact that the code executes the second part of the if.

 if isinstance(inputs, tuple) or g.is_block:
            if isinstance(inputs, tuple):
                src_inputs, dst_inputs = inputs
            else:
                src_inputs = inputs
                dst_inputs = {k: v[:g.number_of_dst_nodes(k)] for k, v in inputs.items()}

            for stype, etype, dtype in g.canonical_etypes:
                rel_graph = g[stype, etype, dtype]
                if rel_graph.number_of_edges() == 0:
                    continue
                if stype not in src_inputs or dtype not in dst_inputs:
                    continue
                dstdata = self.mods[etype](
                    rel_graph,
                    (src_inputs[stype], dst_inputs[dtype]),
                    *mod_args.get(etype, ()),
                    **mod_kwargs.get(etype, {}))
                outputs[dtype].append(dstdata)
        else:
            for stype, etype, dtype in g.canonical_etypes:
                rel_graph = g[stype, etype, dtype]
                if rel_graph.number_of_edges() == 0:
                    continue
                if stype not in inputs: # <--- error from the stacktrace
                    continue
                dstdata = self.mods[etype](
                    rel_graph,
                    (inputs[stype], inputs[dtype]),
                    *mod_args.get(etype, ()),
                    **mod_kwargs.get(etype, {}))
                outputs[dtype].append(dstdata)

How should I format my input, which is a Tensor of shape(no_nodes, no_features) to be a tuple?

This is the stack trace

Using backend: pytorch
Traceback (most recent call last):
 File "/home/tudor/projects/xtailab/task2_graph_attention/test_scripts/hetero-edge_classif.py", line 159, in <module>
   pred = model(graph, node_features, target_edge)
 File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
   result = self.forward(*input, **kwargs)
 File "/home/tudor/projects/xtailab/task2_graph_attention/test_scripts/hetero-edge_classif.py", line 144, in forward
   h = self.sage(g, x)
 File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
   result = self.forward(*input, **kwargs)
 File "/home/tudor/projects/xtailab/task2_graph_attention/test_scripts/hetero-edge_classif.py", line 129, in forward
   h = self.conv1(graph, inputs)
 File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
   result = self.forward(*input, **kwargs)
 File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/dgl/nn/pytorch/hetero.py", line 187, in forward
   if stype not in inputs:
 File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/torch/tensor.py", line 648, in __contains__
   raise RuntimeError(
RuntimeError: Tensor.__contains__ only supports Tensor or scalar, but you passed in a <class 'str'>.

Process finished with exit code 1

Seems that your conv1 is a HeteroGraphConv instance. The input feature to that module must be a dictionary. I can see that you have changed the dictionary to a tensor due to the AssertionError above. Could you also show the stack trace of that error?

Traceback (most recent call last):
  File "/home/tudor/projects/xtailab/task2_graph_attention/test_scripts/hetero-edge_classif.py", line 160, in <module>
    pred = model(graph, node_feats, target_edge)
  File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
    result = self.forward(*input, **kwargs)
  File "/home/tudor/projects/xtailab/task2_graph_attention/test_scripts/hetero-edge_classif.py", line 145, in forward
    return self.pred(g, h, etype)
  File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
    result = self.forward(*input, **kwargs)
  File "/home/tudor/projects/xtailab/task2_graph_attention/test_scripts/hetero-edge_classif.py", line 90, in forward
    graph.ndata['h'] = h  # assigns 'h' of all node types in one shot
  File "/home/tudor/.miniconda3/envs/xtailab/lib/python3.9/site-packages/dgl/view.py", line 78, in __setitem__
    assert isinstance(val, dict) is False, \
AssertionError: The HeteroNodeDataView has only one node type. please pass a tensor directly

Process finished with exit code 1

So I guess your graph is heterogeneous but only has one node type? In that case you will need to change

graph.ndata['h'] = h

to

graph.ndata['h'] = h[your_node_type]
1 Like

Yes, I had one node type and multiple edge types.

It worked!
Thank you very much!