Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 952830b

Browse files
authored
[Dataset] Add PPI and PPI-large dataset (THUDM#175)
* Add PPI and PPI-Large * Fix bugs in PPRGo trainer * Fix bugs in subgraph sampling * Simplify node_classification test * Add tests for graphsage
1 parent 282ac1f commit 952830b

15 files changed

Lines changed: 102 additions & 46 deletions

cogdl/data/data.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
import re
2+
import numba
23

34
import torch
45
import numpy as np
56
import scipy.sparse as sparse
67

78

9+
@numba.njit
10+
def reindex(node_idx, col):
11+
node_dict = dict()
12+
cnt = 0
13+
for i in node_idx:
14+
node_dict[i] = cnt
15+
cnt += 1
16+
new_col = [node_dict[i] for i in col]
17+
return np.array(new_col)
18+
19+
820
class Data(object):
921
r"""A plain old python object modeling a single graph with various
1022
(optional) attributes:
@@ -184,6 +196,12 @@ def _build_adj_(self):
184196
if self.__adj is not None:
185197
return
186198
num_edges = self.edge_index.shape[1]
199+
200+
self.edge_row, col = self.edge_index.cpu()
201+
self.edge_col = col.numpy()
202+
203+
self.node_idx = torch.unique(self.edge_index).cpu().numpy()
204+
187205
edge_index_np = self.edge_index.cpu().numpy()
188206
num_nodes = self.x.shape[0]
189207
edge_attr_np = np.ones(num_edges)
@@ -205,7 +223,9 @@ def subgraph(self, node_idx):
205223
edge_attr = torch.from_numpy(adj_coo.data).to(self.x.device)
206224
edge_index = torch.from_numpy(np.stack([row, col], axis=0)).to(self.x.device).long()
207225
keys = self.keys
208-
attrs = {key: self[key][node_idx] for key in keys if "edge" not in key}
226+
227+
print(keys)
228+
attrs = {key: self[key][node_idx] for key in keys if "edge" not in key and "node_idx" not in key}
209229
attrs["edge_index"] = edge_index
210230
if edge_attr is not None:
211231
attrs["edge_attr"] = edge_attr
@@ -243,37 +263,32 @@ def sample_adj(self, batch, size=-1, replace=True):
243263
adj = self.__adj[batch].tocsr()
244264
batch_size = len(batch)
245265
if size == -1:
246-
adj = adj.tocoo()
247-
row, col = torch.from_numpy(adj.row), torch.from_numpy(adj.col)
248-
node_idx = torch.unique(col)
266+
row, col = self.edge_row, self.edge_col
267+
_node_idx = self.node_idx
249268
else:
250269
indices = torch.from_numpy(adj.indices)
251270
indptr = torch.from_numpy(adj.indptr)
252271
node_idx, (row, col) = self._sample_adj(batch_size, indices, indptr, size)
253-
col = col.numpy()
254-
_node_idx = node_idx.numpy()
272+
col = col.numpy()
273+
_node_idx = node_idx.numpy()
255274

256275
# Reindexing: target nodes are always put at the front
257-
_node_idx = list(batch) + list(set(_node_idx).difference(set(batch)))
258-
node_dict = {val: key for key, val in enumerate(_node_idx)}
259-
new_col = torch.LongTensor([node_dict[i] for i in col])
276+
_node_idx = np.concatenate((batch, np.setdiff1d(_node_idx, batch)))
277+
278+
new_col = torch.as_tensor(reindex(_node_idx, col), dtype=torch.long)
260279
edge_index = torch.stack([row.long(), new_col])
261280

262-
node_idx = torch.Tensor(_node_idx).long().to(self.x.device)
281+
node_idx = torch.as_tensor(_node_idx, dtype=torch.long).to(self.x.device)
263282
edge_index = edge_index.long().to(self.x.device)
264283
return node_idx, edge_index
265284

266285
def _sample_adj(self, batch_size, indices, indptr, size):
267-
indptr = indptr
268-
row_counts = torch.Tensor([indptr[i] - indptr[i - 1] for i in range(1, len(indptr))])
286+
row_counts = torch.as_tensor([indptr[i] - indptr[i - 1] for i in range(1, len(indptr))]).long()
269287

270-
# if not replace:
271-
# edge_cols = [col[indptr[i]: indptr[i+1]] for i in range(len(indptr)-1)]
272-
# edge_cols = [np.random.choice(x, min(size, len(x)), replace=False) for x in edge_cols]
273-
# else:
274288
rand = torch.rand(batch_size, size)
275289
rand = rand * row_counts.view(-1, 1)
276290
rand = rand.long()
291+
277292
rand = rand + indptr[:-1].view(-1, 1)
278293
edge_cols = indices[rand].view(-1)
279294
row = torch.arange(0, batch_size).view(-1, 1).repeat(1, size).view(-1)

cogdl/datasets/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def build_dataset_from_path(data_path, task):
109109
"blogcatalog": "cogdl.datasets.matlab_matrix",
110110
"flickr-ne": "cogdl.datasets.matlab_matrix",
111111
"wikipedia": "cogdl.datasets.matlab_matrix",
112-
"ppi": "cogdl.datasets.matlab_matrix",
112+
"ppi-ne": "cogdl.datasets.matlab_matrix",
113113
"han-acm": "cogdl.datasets.han_data",
114114
"han-dblp": "cogdl.datasets.han_data",
115115
"han-imdb": "cogdl.datasets.han_data",
@@ -129,6 +129,8 @@ def build_dataset_from_path(data_path, task):
129129
"amazon-s": "cogdl.datasets.saint_data",
130130
"flickr": "cogdl.datasets.saint_data",
131131
"reddit": "cogdl.datasets.saint_data",
132+
"ppi": "cogdl.datasets.saint_data",
133+
"ppi-large": "cogdl.datasets.saint_data",
132134
"test_bio": "cogdl.datasets.pyg_strategies_data",
133135
"test_chem": "cogdl.datasets.pyg_strategies_data",
134136
"bio": "cogdl.datasets.strategies_data",

cogdl/datasets/matlab_matrix.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def __init__(self):
9393
super(WikipediaDataset, self).__init__(path, filename, url)
9494

9595

96-
@register_dataset("ppi")
96+
@register_dataset("ppi-ne")
9797
class PPIDataset(MatlabMatrix):
9898
def __init__(self):
9999
dataset, filename = "ppi", "Homo_sapiens"

cogdl/datasets/saint_data.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,33 @@ def __init__(self):
167167

168168
def get_evaluator(self):
169169
return multiclass_evaluator()
170+
171+
172+
@register_dataset("ppi")
173+
class PPIDataset(SAINTDataset):
174+
def __init__(self):
175+
dataset = "PPI"
176+
url = "https://cloud.tsinghua.edu.cn/d/2c6e94ec9dad4972b58e/files/?p=%2F{}&dl=1"
177+
path = osp.join("data", dataset)
178+
if not osp.exists(path):
179+
SAINTDataset(path, dataset, url)
180+
super(PPIDataset, self).__init__(path, dataset, url)
181+
self.data = scale_feats(self.data)
182+
183+
def get_evaluator(self):
184+
return multilabel_evaluator()
185+
186+
187+
@register_dataset("ppi-large")
188+
class PPILargeDataset(SAINTDataset):
189+
def __init__(self):
190+
dataset = "PPI_Large"
191+
url = "https://cloud.tsinghua.edu.cn/d/469ef38a520640bba267/files/?p=%2F{}&dl=1"
192+
path = osp.join("data", dataset)
193+
if not osp.exists(path):
194+
SAINTDataset(path, dataset, url)
195+
super(PPILargeDataset, self).__init__(path, dataset, url)
196+
self.data = scale_feats(self.data)
197+
198+
def get_evaluator(self):
199+
return multilabel_evaluator()

cogdl/match.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ node_classification:
3333
- ogbn-products
3434
- ogbn-papers100M
3535
- flickr
36-
- amazon
36+
- amazon-s
3737
- yelp
38+
- ppi
3839
- reddit
3940
unsupervised_node_classification:
4041
- model:
@@ -51,7 +52,7 @@ unsupervised_node_classification:
5152
- spectral
5253
- gcc
5354
dataset:
54-
- ppi
55+
- ppi-ne
5556
- blogcatalog
5657
- wikipedia
5758
- usa-airport

cogdl/models/nn/graphsage.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ def inference(self, x_all, data_loader):
159159
def get_trainer(task: Any, args: Any):
160160
if args.dataset not in ["cora", "citeseer"]:
161161
return NeighborSamplingTrainer
162+
if hasattr(args, "use_trainer"):
163+
return NeighborSamplingTrainer
162164

163165
def set_data_device(self, device):
164166
self.device = device

cogdl/models/nn/pyg_graph_unet.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ def __init__(
182182
self.act = get_activation(activation)
183183
assert pooling_layer <= len(pooling_rates)
184184
pooling_rates = pooling_rates[:pooling_layer]
185+
pooling_rates = [float(x) for x in pooling_rates]
185186
self.unet = GraphUnetLayer(hidden_size, pooling_layer, pooling_rates, activation, n_dropout, aug_adj)
186187

187188
self.in_gcn = GraphConvolution(in_feats, hidden_size)

cogdl/trainers/ppr_trainer.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ def ppr_run(self, dataset, mode="train"):
5050
else:
5151
edge_index = data.edge_index
5252

53-
if not os.path.exists("./saved"):
54-
os.mkdir("saved")
55-
path = f"./saved/{self.dataset_name}_{self.topk}_{self.alpha}_{self.normalization}.{mode}.npz"
53+
if not os.path.exists("./pprgo_saved"):
54+
os.mkdir("pprgo_saved")
55+
path = f"./pprgo_saved/{self.dataset_name}_{self.topk}_{self.alpha}_{self.normalization}.{mode}.npz"
5656

5757
if os.path.exists(path):
5858
print(f"Load {mode} from cached")
@@ -103,7 +103,6 @@ def fit(self, model, dataset):
103103
epoch_iter.set_description(
104104
f"Epoch: {epoch}, TrainLoss: {train_loss: .4f}, ValLoss: {val_loss: .4f}, ValAcc: {best_acc: .4f}"
105105
)
106-
print()
107106
self.model = best_model
108107

109108
del train_loader

cogdl/trainers/sampled_trainer.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
import torch.nn.functional as F
88
from tqdm import tqdm
99

10-
from cogdl.data import Dataset, Data
10+
from cogdl.data import Dataset
1111
from cogdl.data.sampler import NodeSampler, EdgeSampler, RWSampler, MRWSampler, LayerSampler, NeighborSampler
1212
from cogdl.models.supervised_model import SupervisedModel
1313
from cogdl.trainers.base_trainer import BaseTrainer
14+
from cogdl.utils import add_remaining_self_loops
1415

1516

1617
class SampledTrainer(BaseTrainer):
@@ -149,9 +150,14 @@ def __init__(self, args):
149150
self.patience = self.patience // self.eval_per_epoch
150151

151152
self.device = "cpu" if not torch.cuda.is_available() or args.cpu else args.device_id[0]
153+
self.loss_fn, self.evaluator = None, None
152154

153155
def fit(self, model, dataset):
154-
self.data = Data.from_pyg_data(dataset[0])
156+
self.data = dataset[0]
157+
self.data.edge_index, _ = add_remaining_self_loops(self.data.edge_index)
158+
if hasattr(self.data, "edge_index_train"):
159+
self.data.edge_index_train, _ = add_remaining_self_loops(self.data.edge_index_train)
160+
self.loss_fn, self.evaluator = dataset.get_evaluator()
155161
self.train_loader = NeighborSampler(
156162
data=self.data,
157163
mask=self.data.train_mask,

scripts/train.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
parser = options.get_training_parser()
66
args, _ = parser.parse_known_args()
77
args = options.parse_args_and_arch(parser, args)
8-
print(args)
98
assert len(args.device_id) == 1
109

1110
experiment(task=args.task, dataset=args.dataset, model=args.model, args=args)

0 commit comments

Comments
 (0)