Pytorch_geometric: Fixed, static graph with varying Node samples

Created on 21 Nov 2019  路  10Comments  路  Source: rusty1s/pytorch_geometric

I'm trying to get started on using this package for an experiment I'm running and I'd like to use the ChebConv class.

My problem uses a fixed, static graph of shape:

A: _N_ x _N_ (Nodes x Nodes)

and an input of shape:

X: _S_ x _N_ x _F_ (Samples x Nodes x Features)

where what "changes" here is different instances/samples of the same graph (same number of Nodes & Features) for each sample.

How can I use the Data functions from utils library here?

I don't want to use a Data object for each Sample because every sample has the same edges and edge features, where the number of nodes is ~= 600k. If I use a Data object for every sample I'd be replicating the same graph _S_-times (one for each sample of _X_)

I just want one object that has my adjacency matrix (2D) and another for my input tensor (3D) and batch over the _Samples_ dimension of the input tensor

feature

Most helpful comment

This is now supported with the latest commit via the node_dim attribute of MessagePassing [1, 2]. If you have batched node features x with shape [B, N, F] and a sparse single adjacency matrix edge_index with shape [2, E], all you need to do is:

conv = GCNConv(in_channels, out_channels, node_dim=1)
out = conv(x, edge_index)

[1] https://github.com/rusty1s/pytorch_geometric/blob/master/torch_geometric/nn/conv/message_passing.py#L17-L40
[2] https://github.com/rusty1s/pytorch_geometric/blob/master/test/nn/conv/test_static_graph.py

All 10 comments

I'm not sure if I'm answering my own question here, but:

Should I just create a single Data object of dimensions: _Nodes_ x _Samples_ x _Features_ ?

How would I batch over a single Data object where my batch dimension is in the middle though..I'm very confused

close was an accident

This is now supported with the latest commit via the node_dim attribute of MessagePassing [1, 2]. If you have batched node features x with shape [B, N, F] and a sparse single adjacency matrix edge_index with shape [2, E], all you need to do is:

conv = GCNConv(in_channels, out_channels, node_dim=1)
out = conv(x, edge_index)

[1] https://github.com/rusty1s/pytorch_geometric/blob/master/torch_geometric/nn/conv/message_passing.py#L17-L40
[2] https://github.com/rusty1s/pytorch_geometric/blob/master/test/nn/conv/test_static_graph.py

All you need to test is to pull PyG from GitHub and run python setup.py install. If you encounter any issues with this, please let me know.

This is now supported with the latest commit via the node_dim attribute of MessagePassing [1, 2]. If you have batched node features x with shape [B, N, F] and a sparse single adjacency matrix edge_index with shape [2, E], all you need to do is:

conv = GCNConv(in_channels, out_channels, node_dim=1)
out = conv(x, edge_index)

[1] https://github.com/rusty1s/pytorch_geometric/blob/master/torch_geometric/nn/conv/message_passing.py#L17-L40
[2] https://github.com/rusty1s/pytorch_geometric/blob/master/test/nn/conv/test_static_graph.py

This didn't fix the issue. As it stands, the code works regardless of whether

node_dim = 0 or node_dim=1 .

By using the Batch operation, my data, x, of dimensions B x N x F, is now just converted to B*N x F

Screen Shot 2019-12-01 at 2 50 29 PM

Screen Shot 2019-12-01 at 2 50 39 PM

Screen Shot 2019-12-01 at 2 50 52 PM

`---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in
13 out = conv_layer(x = batch2.x,
14 edge_index = A_test.edge_index,
---> 15 edge_weight = A_test.edge_attr)

/usr/local/lib/python3.6/dist-packages/torch/nn/modules/module.py in __call__(self, input, *kwargs)
539 result = self._slow_forward(input, *kwargs)
540 else:
--> 541 result = self.forward(input, *kwargs)
542 for hook in self._forward_hooks.values():
543 hook_result = hook(self, input, result)

/usr/local/lib/python3.6/dist-packages/torch_geometric/nn/conv/cheb_conv.py in forward(self, x, edge_index, edge_weight, batch, lambda_max)
113 edge_index, norm = self.norm(edge_index, x.size(0), edge_weight,
114 self.normalization, lambda_max,
--> 115 dtype=x.dtype, batch=batch)
116
117 Tx_0 = x

/usr/local/lib/python3.6/dist-packages/torch_geometric/nn/conv/cheb_conv.py in norm(edge_index, num_nodes, edge_weight, normalization, lambda_max, dtype, batch)
90
91 edge_index, edge_weight = get_laplacian(
---> 92 edge_index, edge_weight, normalization, dtype, num_nodes)
93
94 if batch is not None and torch.is_tensor(lambda_max):

/usr/local/lib/python3.6/dist-packages/torch_geometric/utils/get_laplacian.py in get_laplacian(edge_index, edge_weight, normalization, dtype, num_nodes)
42
43 row, col = edge_index
---> 44 deg = scatter_add(edge_weight, row, dim=0, dim_size=num_nodes)
45
46 if normalization is None:

/usr/local/lib/python3.6/dist-packages/torch_scatter/add.py in scatter_add(src, index, dim, out, dim_size, fill_value)
73 """
74 src, out, index, dim = gen(src, index, dim, out, dim_size, fill_value)
---> 75 return out.scatter_add_(dim, index, src)

RuntimeError: Invalid index in scatterAdd at /pytorch/aten/src/TH/generic/THTensorEvenMoreMath.cpp:721`

This appears to be the same issue as #611

Are you sure you are working on PyTorch Geometric master? What happens if you run the following test code?

import torch
from torch_geometric.data import Data, Batch
from torch_geometric.nn import MessagePassing, GCNConv, ChebConv


class MyConv(MessagePassing):
    def forward(self, x, edge_index):
        return self.propagate(edge_index, x=x)


def test_static_graph():
    edge_index = torch.tensor([[0, 1, 1, 2], [1, 0, 2, 1]])
    x1, x2 = torch.randn(3, 8), torch.randn(3, 8)

    data1 = Data(edge_index=edge_index, x=x1)
    data2 = Data(edge_index=edge_index, x=x2)
    batch = Batch.from_data_list([data1, data2])

    x = torch.stack([x1, x2], dim=0)
    for conv in [MyConv(), GCNConv(8, 16), ChebConv(8, 16, K=2)]:
        out1 = conv(batch.x, batch.edge_index)
        assert out1.size(0) == 6
        conv.node_dim = 1
        out2 = conv(x, edge_index)
        assert out2.size()[:2] == (2, 3)
        assert torch.allclose(out1, out2.view(-1, out2.size(-1)))

test_static_graph()

**On another note, I'm now getting an error after reinstalling PyTorch Geometric (to ensure it's from master even though I'm sure it is).

I'll open this as a new issue and keep the batch-question issue here.

Once this is remedied I'll re-test the batch test you suggested.

**

see #843

Was this page helpful?
0 / 5 - 0 ratings