forked from Danial-sb/Diffpool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdiffpool.py
219 lines (168 loc) · 38.7 KB
/
diffpool.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# -*- coding: utf-8 -*-
"""DiffPool.ipynb
Automatically generated by Colaboratory.
Original file is located at
https://colab.research.google.com/drive/18x0slqSIdZJTMzcyZS69PKc9uqfBnB5a
**First, we look at the concept of DiffPool**
"""
import torch
from math import ceil
"""For doing the computation for the first hierarchical step, we need the node feature matrix and adjacency matrix of the graph.
For instance, imagine out initial graph would be like:
**X_0 = 200 * 32**
**A_0 = 200 * 200**
"""
X_0 = torch.rand(200, 32)
A_0 = torch.rand(200, 200).round().long()
identity = torch.eye(200)
A_0 = A_0 + identity
"""At first step, we have **100** clusters (nodes). For the next step, we want to have these nodes into **10** clusters"""
n_clusters_0 = 200
n_clusters_1 = 10
"""Initialize GNN_weights and GNN_pool"""
w_gnn_weights = torch.rand(32, 16)
w_gnn_pool = torch.rand(32, n_clusters_1)
"""![Capture.PNG](data:image/png;base64,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)
![Capture1.PNG](data:image/png;base64,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)
"""
Z_0 = torch.relu(A_0 @ X_0 @ w_gnn_weights)
S_0 = torch.softmax((A_0 @ X_0 @ w_gnn_pool), dim = 1)
print(f"shape of Z_0: {Z_0.shape}\nshape of S_0: {S_0.shape}")
"""![Capture.PNG](data:image/png;base64,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)"""
X_1 = S_0.t() @ Z_0
A_1 = S_0.t() @ A_0 @ S_0
print(f"shape of Z_0: {X_1.shape}\nshape of S_0: {A_1.shape}")
!pip install -q torch-scatter -f https://data.pyg.org/whl/torch-1.12.1+cu113.html
!pip install -q torch-sparse -f https://data.pyg.org/whl/torch-1.12.1+cu113.html
!pip install -q git+https://github.com/pyg-team/pytorch_geometric.git
import torch.nn.functional as F
from torch_geometric.datasets import TUDataset
import torch_geometric.transforms as T
from torch_geometric.data import DenseDataLoader
from torch_geometric.data import DataLoader
from torch.nn import Linear
from torch_geometric.nn import global_mean_pool
from torch_geometric.nn import DenseGCNConv as GCNConv, dense_diff_pool
#from torch_geometric.nn import GCNConv
max_nodes = 300
class Filter(object):
def __call__(self, data):
return data.num_nodes <= max_nodes
dataset = TUDataset('/content', 'PROTEINS', transform = T.ToDense(max_nodes), pre_filter=Filter())
#dataset = TUDataset('/content', 'PROTEINS', transform = T.ToDense(max_nodes), pre_filter=Filter())
print(f"Number of graphs in the dataset: {len(dataset)}")
print(f"Number of features: {dataset.num_features}")
print(f"Number of classes: {dataset.num_classes}")
dataset.shuffle()
n = (len(dataset)) // 10
test_data = dataset[:2*n]
val_data = dataset[n:2*n]
train_data = dataset[2*n:]
print(f'length of train data: {len(train_data)}')
print(f'length of test data: {len(test_data)}')
print("========================")
test_loader = DenseDataLoader(test_data, batch_size = 32)
val_loader = DenseDataLoader(val_data, batch_size = 32)
train_loader = DenseDataLoader(train_data, batch_size = 32)
for step, data in enumerate(train_loader):
print(f'Step {step + 1}:')
print('=======')
#print(f'Number of graphs in the current batch: {data.num_graphs}')
print(data)
print()
class GNN(torch.nn.Module):
def __init__(self, in_channels, hidden_channels, out_channels,
normalize=True, lin=True):
super(GNN, self).__init__()
self.convs = torch.nn.ModuleList()
self.convs.append(GCNConv(in_channels, hidden_channels, normalize))
self.convs.append(GCNConv(hidden_channels, hidden_channels, normalize))
self.convs.append(GCNConv(hidden_channels, out_channels, normalize))
def forward(self, x, adj, mask=None):
batch_size, num_nodes, in_channels = x.size()
for i in range(len(self.convs)):
x = F.relu(self.convs[i](x, adj, mask))
return x
class DiffPool(torch.nn.Module):
def __init__(self):
super(DiffPool, self).__init__()
num_nodes = ceil(0.25 * max_nodes)
self.gnn1_pool = GNN(dataset.num_features, 64, num_nodes)
self.gnn1_embed = GNN(dataset.num_features, 64, 64)
num_nodes = ceil(0.25 * num_nodes)
self.gnn2_pool = GNN(64, 64, num_nodes)
self.gnn2_embed = GNN(64, 64, 64, lin=False)
self.gnn3_embed = GNN(64, 64, 64, lin=False)
self.lin1 = torch.nn.Linear(64, 64)
self.lin2 = torch.nn.Linear(64, dataset.num_classes)
def forward(self, x, adj, mask=None):
s = self.gnn1_pool(x, adj, mask)
x = self.gnn1_embed(x, adj, mask)
x, adj, l1, e1 = dense_diff_pool(x, adj, s)
s = self.gnn2_pool(x, adj)
x = self.gnn2_embed(x, adj)
x, adj, l2, e2 = dense_diff_pool(x, adj, s)
x = self.gnn3_embed(x, adj)
x = x.mean(dim=1)
x = F.relu(self.lin1(x))
x = self.lin2(x)
return F.log_softmax(x, dim=-1), l1 + l2, e1 + e2
model = DiffPool()
print(model)
for data in train_loader:
print(data.y.size(0))
break
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = DiffPool().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=5e-4)
n_total_steps = len(train_loader)
num_epochs = 10
def train():
loss_all = 0
correct = 0
model.train()
for data in train_loader:
data = data.to(device)
optimizer.zero_grad()
output, _, _ = model(data.x, data.adj, data.mask)
loss = F.nll_loss(output, data.y.view(-1))
loss.backward()
loss_all += data.y.size(0) * loss.item()
optimizer.step()
pred = output.argmax(dim = 1)
correct += int((pred == data.y).sum())
return (loss_all / len(train_data)), (correct / len(train_data))
@torch.no_grad()
def test(loader):
model.eval()
correct = 0
for data in loader:
data = data.to(device)
pred = model(data.x, data.adj, data.mask)[0].max(dim=1)[1]
correct += pred.eq(data.y.view(-1)).sum().item()
return correct / len(loader.dataset)
train_loss = []
train_acc = []
for epoch in range(1, 10):
loss, acc = train()
train_loss.append(loss)
train_acc.append(acc)
#if epoch % 10 == 0:
print(f'epoch: {epoch}, Train loss: {loss:.4f}, Train acc: {acc:.4f}')
train_loss = []
train_acc = []
val_loss = []
val_acc = []
best_val_acc = test_acc = 0
for epoch in range(1, 151):
loss, acc = train()
train_loss.append(loss)
train_acc.append(acc)
v_acc = test(val_loader)
if v_acc > best_val_acc:
test_acc = test(test_loader)
best_val_acc = v_acc
#val_loss.append(v_loss)
val_acc.appened(v_acc)
if epoch % 10 == 0:
print(f'epoch: {epoch}, Train loss: {loss:.4f}, Train acc: {acc:.4f}, Val acc: {v_acc:.4f}, Test acc: {test_acc:.4f}')