-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgae.py
More file actions
137 lines (116 loc) · 5.66 KB
/
Copy pathgae.py
File metadata and controls
137 lines (116 loc) · 5.66 KB
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
import argparse
from tqdm.auto import tqdm
import torch
import torch.nn as nn
import torch_geometric.transforms as T
# custom modules
from lrgae.dataset import load_dataset
from lrgae.decoders import EdgeDecoder
from lrgae.encoders import GNNEncoder
from lrgae.models import GAE
from lrgae.utils import set_seed
from lrgae.evaluators import NodeClasEvaluator
parser = argparse.ArgumentParser()
parser.add_argument("--dataset", default="Cora",
help="Datasets. (default: Cora)")
parser.add_argument('--seed', type=int, default=2024,
help='Random seed for model and dataset. (default: 2024)')
parser.add_argument("--layer", default="gcn",
help="GNN layer, (default: gcn)")
parser.add_argument("--encoder_activation", default="relu",
help="Activation function for GNN encoder, (default: relu)")
parser.add_argument('--encoder_channels', type=int, default=64,
help='Channels of hidden representation. (default: 64)')
parser.add_argument('--encoder_layers', type=int, default=2,
help='Number of layers for encoder. (default: 2)')
parser.add_argument('--encoder_dropout', type=float, default=0.5,
help='Dropout probability of encoder. (default: 0.5)')
parser.add_argument("--encoder_norm",
default="none", help="Normalization (default: none)")
parser.add_argument('--decoder_channels', type=int, default=32,
help='Channels of decoder layers. (default: 32)')
parser.add_argument('--decoder_layers', type=int, default=2,
help='Number of layers for decoders. (default: 2)')
parser.add_argument('--decoder_dropout', type=float, default=0.2,
help='Dropout probability of decoder. (default: 0.2)')
parser.add_argument("--decoder_norm",
default="none", help="Normalization (default: none)")
parser.add_argument('--lr', type=float, default=0.01,
help='Learning rate for training. (default: 0.01)')
parser.add_argument('--weight_decay', type=float, default=5e-5,
help='weight_decay for link prediction training. (default: 5e-5)')
parser.add_argument('--grad_norm', type=float, default=1.0,
help='grad_norm for training. (default: 1.0.)')
parser.add_argument('--l2_normalize', action='store_true',
help='Whether to use l2 normalize output embedding. (default: False)')
parser.add_argument('--nodeclas_lr', type=float, default=0.01,
help='Learning rate for training. (default: 0.01)')
parser.add_argument('--nodeclas_weight_decay', type=float, default=5e-5,
help='weight_decay for node classification training. (default: 5e-5)')
parser.add_argument("--mode", default="last",
help="Embedding mode `last` or `cat` (default: `last`)")
parser.add_argument('--epochs', type=int, default=500,
help='Number of training epochs. (default: 500)')
parser.add_argument('--runs', type=int, default=1,
help='Number of runs. (default: 1)')
parser.add_argument('--eval_steps', type=int, default=50, help='(default: 50)')
parser.add_argument("--device", type=int, default=0)
args = parser.parse_args()
set_seed(args.seed)
if args.device < 0:
device = "cpu"
else:
device = f"cuda:{args.device}" if torch.cuda.is_available() else "cpu"
# (!IMPORTANT) Specify the path to your dataset directory ##############
root = '~/public_data/pyg_data' # my root directory
# root = '../data/'
########################################################################
transform = T.Compose([
T.ToUndirected(),
T.ToDevice(device),
])
data = load_dataset(root, args.dataset, transform=transform)
evaluator = NodeClasEvaluator(lr=args.nodeclas_lr,
weight_decay=args.nodeclas_weight_decay,
mode=args.mode,
l2_normalize=args.l2_normalize,
device=device)
encoder = GNNEncoder(in_channels=data.num_features,
hidden_channels=args.encoder_channels,
out_channels=args.encoder_channels,
num_layers=args.encoder_layers,
dropout=args.encoder_dropout,
norm=args.encoder_norm,
layer=args.layer,
activation=args.encoder_activation)
decoder = EdgeDecoder(in_channels=args.encoder_channels,
hidden_channels=args.decoder_channels,
num_layers=args.decoder_layers,
dropout=args.decoder_dropout,
norm=args.decoder_norm)
model = GAE(encoder, decoder).to(device)
best_metric = None
optimizer = torch.optim.Adam(model.parameters(),
lr=args.lr,
weight_decay=args.weight_decay)
pbar = tqdm(range(1, 1 + args.epochs))
for epoch in pbar:
optimizer.zero_grad()
model.train()
loss = model.train_step(data)
loss.backward()
if args.grad_norm > 0:
nn.utils.clip_grad_norm_(model.parameters(), args.grad_norm)
optimizer.step()
pbar.set_description(f'Loss: {loss.item():.4f}')
if epoch % args.eval_steps == 0:
print(f'Evaluating on epoch {epoch}...')
results = evaluator.evaluate(model, data)
if best_metric is None:
best_metric = results
for metric, value in results.items():
print(f'- Averaged {metric}: {value:.2%}')
if best_metric[metric] < value:
best_metric = results
for metric, value in best_metric.items():
print(f'Best averaged {metric} on {args.dataset}: {value:.2%}')