Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

About GraphSAGE sampling on weighted graph #1961

Open
jindeok opened this issue Jan 2, 2021 · 19 comments
Open

About GraphSAGE sampling on weighted graph #1961

jindeok opened this issue Jan 2, 2021 · 19 comments

Comments

@jindeok
Copy link

jindeok commented Jan 2, 2021

❓ Questions & Help

Hello.
I really appreciate for you to share such a implementation examples of GNN, However, I have a 1 short question.

I'm wondering what happens when I put weighted graph into GraphSAGE example.
Does NeighborhoodSampling consider It as unweighted(binary edge) graph?
or weight of edges affect the sampling process?

@rusty1s
Copy link
Member

rusty1s commented Jan 2, 2021

Currently, SAGEConv does not support weighted graphs, but GraphConv does (which is quite similar). Note that you need to pas both edge_index and edge_weight to the GNN op.

@1byxero
Copy link

1byxero commented Jan 3, 2021

Can we use sparse matrix for the edge weights?

@rusty1s
Copy link
Member

rusty1s commented Jan 3, 2021

Do you mean using the SparseTensor class? That is possible by passing edge weights to the value argument:

adj_t = SparseTensor(row=row, col=col, value=edge_weight, sparse_sizes=(N, N))

@1byxero
Copy link

1byxero commented Jan 4, 2021

This means we need one dense tensor storing edge weights initially. Right?

I don't want to do that as that dense tensor is taking up too much GPU memory.
Is there any workaround?

@jindeok
Copy link
Author

jindeok commented Jan 4, 2021

Thank you for your reply.!! It was very helpful.

Can I ask one more question?
I'm also wonder whether I can apply NeighborSampler function on weighted graph if I want to construct training set from sampling.

@rusty1s
Copy link
Member

rusty1s commented Jan 4, 2021

NeighborSampler returns a e_id tensor, which can be used to index the original edge weights:

loader = NeighborSampler(edge_index, ...)
for batch_size, n_id, adjs:
    for edge_index, e_id, size in adjs:
        sampled_edge_weight = edge_weight[e_id]

@jindeok

This comment has been minimized.

@rusty1s
Copy link
Member

rusty1s commented Jan 7, 2021

Can you give me a short example to illustrate this issue?

@jindeok
Copy link
Author

jindeok commented Jan 7, 2021

Im sorry I found that from_networkx()method also convert edge weight.
anyway,

my work example]

  • I want to aggregate information from sampled neighbor batch on weighted graph *

(In graphsage_unsupervised example code, I just replaced SAGEConv into GraphConv here)

class myGNN(nn.Module):
    def __init__(self, in_channels, hidden_channels, num_layers):
        super(myGNN, self).__init__()
        self.num_layers = num_layers
        self.convs = nn.ModuleList()
        for i in range(num_layers):
            in_channels = in_channels if i == 0 else hidden_channels
            self.convs.append(**GraphConv**(in_channels, hidden_channels, aggr = 'mean'))

    def forward(self, x, adjs):
        for i, (edge_index, _, size) in enumerate(adjs):
            x_target = x[:size[1]]  # Target nodes are always placed first.
            x = self.convs[i]((x, x_target), edge_index) 
            if i != self.num_layers - 1:
                x = x.relu()
                x = F.dropout(x, p=0.5, training=self.training)
        return x

    def full_forward(self, x, edge_index):
        for i, conv in enumerate(self.convs):
            x = conv(x, edge_index) 
            if i != self.num_layers - 1:
                x = x.relu()
                x = F.dropout(x, p=0.5, training=self.training)
        return x


data = from_networkx(G)  # G: Weighted Graph that constructed in networkx
train_loader = NeighborSampler(data.edge_index, sizes=[10, 10], batch_size=256,
                               shuffle=True, num_nodes=data.num_nodes)

model.train()

total_loss = 0
for batch_size, n_id, adjs in train_loader:
      for edge_index, e_id, size in adjs:
        sampled_edge_weight = edge_weight[e_id]   # I stuck in this part(this code does not work)
        adjs = [adj.to(device) for adj in adjs]
        optimizer.zero_grad()
        out = model(....)
        ...

  1. How to design GNN forward method that I can input weighted graph?
  2. As for training phase, how can I get weight information from train_loader?

@rusty1s
Copy link
Member

rusty1s commented Jan 7, 2021

You need to index select the edge weights coming from data.edge_weight. The correct example would look similar to:

def forward(self, x, adjs, edge_weight):
        for i, (edge_index, e_id, size) in enumerate(adjs):
            x_target = x[:size[1]]  # Target nodes are always placed first.
            x = self.convs[i]((x, x_target), edge_index, edge_weight[e_id]) 
            if i != self.num_layers - 1:
                x = x.relu()
                x = F.dropout(x, p=0.5, training=self.training)

for batch_size, n_id, adjs in train_loader:
    ...
    model(x[n_id], adjs, data.edge_weight)

@pintonos
Copy link

Currently, SAGEConv does not support weightes graphs, but GraphConv does (which is quite similar). Note that you need to pas both edge_index and edge_weight to the GNN op.

For the inductive case it seems SAGEConv performs better than GraphConv. Is there any possibility to extend the SAGEConv with edge weights? And after reading the paper of GraphConv I am not sure why it should be similar to SAGEConv?

@rusty1s
Copy link
Member

rusty1s commented Jan 11, 2022

GraphConv is the same as SAGEConv in case you specify aggr="mean". Let me know if that works for you.

@pintonos
Copy link

GraphConv is the same as SAGEConv in case you specify aggr="mean". Let me know if that works for you.

Works fine now, thanks! The documentation of GraphConv only defines its node-wise formulation. What would be the definition for the whole graph as in GCNConv for instance?

@rusty1s
Copy link
Member

rusty1s commented Jan 18, 2022

X @ W_1 + D^{-1} A X W_2

@Kang9779
Copy link

Kang9779 commented Apr 25, 2022

You need to index select the edge weights coming from data.edge_weight. The correct example would look similar to:

def forward(self, x, adjs, edge_weight):
        for i, (edge_index, e_id, size) in enumerate(adjs):
            x_target = x[:size[1]]  # Target nodes are always placed first.
            x = self.convs[i]((x, x_target), edge_index, edge_weight[e_id]) 
            if i != self.num_layers - 1:
                x = x.relu()
                x = F.dropout(x, p=0.5, training=self.training)

for batch_size, n_id, adjs in train_loader:
    ...
    model(x[n_id], adjs, data.edge_weight)

I have a question about,How to generate positive and negative samples by using NeighborSampler Sampling on weighted graph?

in this code pos_batch = random_walk(row, col, batch, walk_length=1,coalesced=True)[:, 1],how to randow walk according to the edge weight?

@rusty1s
Copy link
Member

rusty1s commented Apr 26, 2022

We do not have support for biased/weighted sampling of random walks yet, I am sorry.

@ZRH0308
Copy link

ZRH0308 commented Nov 18, 2022

You need to index select the edge weights coming from data.edge_weight. The correct example would look similar to:

def forward(self, x, adjs, edge_weight):
        for i, (edge_index, e_id, size) in enumerate(adjs):
            x_target = x[:size[1]]  # Target nodes are always placed first.
            x = self.convs[i]((x, x_target), edge_index, edge_weight[e_id]) 
            if i != self.num_layers - 1:
                x = x.relu()
                x = F.dropout(x, p=0.5, training=self.training)

for batch_size, n_id, adjs in train_loader:
    ...
    model(x[n_id], adjs, data.edge_weight)

I have a question about,How to generate positive and negative samples by using NeighborSampler Sampling on weighted graph?

in this code pos_batch = random_walk(row, col, batch, walk_length=1,coalesced=True)[:, 1],how to randow walk according to the edge weight?

Hi,
I have the same need as you, how did you solve it in the end?

@ZRH0308
Copy link

ZRH0308 commented Nov 19, 2022

We do not have support for biased/weighted sampling of random walks yet, I am sorry.

Hi, @rusty1s
Now is it possible to do weighted sampling of random walks? I need to sample positive neighbors based on the edge_weight.

If I just need to take an one step neighbor, can I directly select the TOP neighbor with the largest edge_weight in the current batch for each node as a positive sample? Do you think it will work?

@rusty1s
Copy link
Member

rusty1s commented Nov 21, 2022

There is an open PR for this out, see rusty1s/pytorch_cluster#140. Maybe you can check it out to see if it fits your need.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants