"src/git@developer.sourcefind.cn:renzhc/diffusers_dcu.git" did not exist on "2f7a417d1fb11bd242ad7f9098bb9fdf77c54422"
Unverified Commit 036084f6 authored by espylapiza's avatar espylapiza Committed by GitHub
Browse files

[Example] Update GCN on ogbn-arxiv dataset (#2153)



* [Example] GCN on ogbn-arxiv dataset

* Add README.md

* Update GCN implementation on ogbn-arxiv

* Update GCN on ogbn-arxiv

* Fix typo

* Use evaluator to get results
Co-authored-by: default avatarMufei Li <mufeili1996@gmail.com>
Co-authored-by: default avatarZihao Ye <expye@outlook.com>
parent 71629f49
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Requires DGL 0.5 or later versions. Requires DGL 0.5 or later versions.
Run `gcn.py` with `--use-linear` and `use-labels` enabled and you should directly see the result. Run `gcn.py` with `--use-linear` and `--use-labels` enabled and you should directly see the result.
```bash ```bash
python3 gcn.py --use-linear --use-labels python3 gcn.py --use-linear --use-labels
...@@ -17,12 +17,12 @@ usage: GCN on OGBN-Arxiv [-h] [--cpu] [--gpu GPU] [--n-runs N_RUNS] [--n-epochs ...@@ -17,12 +17,12 @@ usage: GCN on OGBN-Arxiv [-h] [--cpu] [--gpu GPU] [--n-runs N_RUNS] [--n-epochs
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
--cpu CPU mode. This option overrides --gpu. --cpu CPU mode. This option overrides --gpu. (default: False)
--gpu GPU GPU device ID. --gpu GPU GPU device ID. (default: 0)
--n-runs N_RUNS --n-runs N_RUNS
--n-epochs N_EPOCHS --n-epochs N_EPOCHS
--use-labels Use labels in the training set as input features. --use-labels Use labels in the training set as input features. (default: False)
--use-linear Use linear layers. --use-linear Use linear layer. (default: False)
--lr LR --lr LR
--n-layers N_LAYERS --n-layers N_LAYERS
--n-hidden N_HIDDEN --n-hidden N_HIDDEN
...@@ -41,3 +41,4 @@ Here are the results over 10 runs. ...@@ -41,3 +41,4 @@ Here are the results over 10 runs.
| Val acc | 0.7361 ± 0.0009 | 0.7397 ± 0.0010 | 0.7399 ± 0.0008 | 0.7442 ± 0.0012 | | Val acc | 0.7361 ± 0.0009 | 0.7397 ± 0.0010 | 0.7399 ± 0.0008 | 0.7442 ± 0.0012 |
| Test acc | 0.7246 ± 0.0021 | 0.7270 ± 0.0016 | 0.7259 ± 0.0006 | 0.7306 ± 0.0024 | | Test acc | 0.7246 ± 0.0021 | 0.7270 ± 0.0016 | 0.7259 ± 0.0006 | 0.7306 ± 0.0024 |
| Parameters | 109608 | 218152 | 119848 | 238632 | | Parameters | 109608 | 218152 | 119848 | 238632 |
...@@ -11,7 +11,7 @@ import torch.nn.functional as F ...@@ -11,7 +11,7 @@ import torch.nn.functional as F
import torch.optim as optim import torch.optim as optim
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
from matplotlib.ticker import AutoMinorLocator, MultipleLocator from matplotlib.ticker import AutoMinorLocator, MultipleLocator
from ogb.nodeproppred import DglNodePropPredDataset from ogb.nodeproppred import DglNodePropPredDataset, Evaluator
from models import GCN from models import GCN
...@@ -19,25 +19,38 @@ device = None ...@@ -19,25 +19,38 @@ device = None
in_feats, n_classes = None, None in_feats, n_classes = None, None
def compute_acc(pred, labels): def gen_model(args):
""" if args.use_labels:
Compute the accuracy of prediction given the labels. model = GCN(
""" in_feats + n_classes, args.n_hidden, n_classes, args.n_layers, F.relu, args.dropout, args.use_linear
return (th.argmax(pred, dim=1) == labels).float().sum() / len(pred) )
else:
model = GCN(in_feats, args.n_hidden, n_classes, args.n_layers, F.relu, args.dropout, args.use_linear)
return model
def cross_entropy(x, labels): def cross_entropy(x, labels):
y = F.cross_entropy(x, labels, reduction="none") y = F.cross_entropy(x, labels[:, 0], reduction="none")
y = th.log(0.5 + y) - math.log(0.5) y = th.log(0.5 + y) - math.log(0.5)
return th.mean(y) return th.mean(y)
def compute_acc(pred, labels, evaluator):
return evaluator.eval({"y_pred": pred.argmax(dim=-1, keepdim=True), "y_true": labels})["acc"]
def add_labels(feat, labels, idx): def add_labels(feat, labels, idx):
onehot = th.zeros([feat.shape[0], n_classes]).to(device) onehot = th.zeros([feat.shape[0], n_classes]).to(device)
onehot[idx, labels[idx]] = 1 onehot[idx, labels[idx, 0]] = 1
return th.cat([feat, onehot], dim=-1) return th.cat([feat, onehot], dim=-1)
def adjust_learning_rate(optimizer, lr, epoch):
if epoch <= 50:
for param_group in optimizer.param_groups:
param_group["lr"] = lr * epoch / 50
def train(model, graph, labels, train_idx, optimizer, use_labels): def train(model, graph, labels, train_idx, optimizer, use_labels):
model.train() model.train()
...@@ -54,6 +67,7 @@ def train(model, graph, labels, train_idx, optimizer, use_labels): ...@@ -54,6 +67,7 @@ def train(model, graph, labels, train_idx, optimizer, use_labels):
else: else:
mask_rate = 0.5 mask_rate = 0.5
mask = th.rand(train_idx.shape) < mask_rate mask = th.rand(train_idx.shape) < mask_rate
train_pred_idx = train_idx[mask] train_pred_idx = train_idx[mask]
optimizer.zero_grad() optimizer.zero_grad()
...@@ -66,7 +80,7 @@ def train(model, graph, labels, train_idx, optimizer, use_labels): ...@@ -66,7 +80,7 @@ def train(model, graph, labels, train_idx, optimizer, use_labels):
@th.no_grad() @th.no_grad()
def evaluate(model, graph, labels, train_idx, val_idx, test_idx, use_labels): def evaluate(model, graph, labels, train_idx, val_idx, test_idx, use_labels, evaluator):
model.eval() model.eval()
feat = graph.ndata["feat"] feat = graph.ndata["feat"]
...@@ -80,32 +94,16 @@ def evaluate(model, graph, labels, train_idx, val_idx, test_idx, use_labels): ...@@ -80,32 +94,16 @@ def evaluate(model, graph, labels, train_idx, val_idx, test_idx, use_labels):
test_loss = cross_entropy(pred[test_idx], labels[test_idx]) test_loss = cross_entropy(pred[test_idx], labels[test_idx])
return ( return (
compute_acc(pred[train_idx], labels[train_idx]), compute_acc(pred[train_idx], labels[train_idx], evaluator),
compute_acc(pred[val_idx], labels[val_idx]), compute_acc(pred[val_idx], labels[val_idx], evaluator),
compute_acc(pred[test_idx], labels[test_idx]), compute_acc(pred[test_idx], labels[test_idx], evaluator),
train_loss, train_loss,
val_loss, val_loss,
test_loss, test_loss,
) )
def adjust_learning_rate(optimizer, lr, epoch): def run(args, graph, labels, train_idx, val_idx, test_idx, evaluator, n_running):
if epoch <= 50:
for param_group in optimizer.param_groups:
param_group["lr"] = lr * epoch / 50
def gen_model(args):
if args.use_labels:
model = GCN(
in_feats + n_classes, args.n_hidden, n_classes, args.n_layers, F.relu, args.dropout, args.use_linear
)
else:
model = GCN(in_feats, args.n_hidden, n_classes, args.n_layers, F.relu, args.dropout, args.use_linear)
return model
def run(args, graph, labels, train_idx, val_idx, test_idx, n_running):
# define model and optimizer # define model and optimizer
model = gen_model(args) model = gen_model(args)
model = model.to(device) model = model.to(device)
...@@ -128,27 +126,28 @@ def run(args, graph, labels, train_idx, val_idx, test_idx, n_running): ...@@ -128,27 +126,28 @@ def run(args, graph, labels, train_idx, val_idx, test_idx, n_running):
adjust_learning_rate(optimizer, args.lr, epoch) adjust_learning_rate(optimizer, args.lr, epoch)
loss, pred = train(model, graph, labels, train_idx, optimizer, args.use_labels) loss, pred = train(model, graph, labels, train_idx, optimizer, args.use_labels)
acc = compute_acc(pred[train_idx], labels[train_idx]) acc = compute_acc(pred[train_idx], labels[train_idx], evaluator)
train_acc, val_acc, test_acc, train_loss, val_loss, test_loss = evaluate( train_acc, val_acc, test_acc, train_loss, val_loss, test_loss = evaluate(
model, graph, labels, train_idx, val_idx, test_idx, args.use_labels model, graph, labels, train_idx, val_idx, test_idx, args.use_labels, evaluator
) )
lr_scheduler.step(loss) lr_scheduler.step(loss)
toc = time.time() train_acc, val_acc, test_acc, train_loss, val_loss, test_loss = evaluate(
total_time += toc - tic model, graph, labels, train_idx, val_idx, test_idx, args.use_labels
)
# if val_acc > best_val_acc: # if val_acc > best_val_acc:
if val_loss < best_val_loss: if val_loss < best_val_loss:
best_val_loss = val_loss.item() best_val_loss = val_loss
best_val_acc = val_acc.item() best_val_acc = val_acc
best_test_acc = test_acc.item() best_test_acc = test_acc
if epoch % args.log_every == 0: if epoch % args.log_every == 0:
print(f"Epoch: {epoch}/{args.n_epochs}") print(f"Epoch: {epoch}/{args.n_epochs}")
print( print(
f"Loss: {loss.item():.4f}, Acc: {acc.item():.4f}\n" f"Loss: {loss.item():.4f}, Acc: {acc:.4f}\n"
f"Train/Val/Test loss: {train_loss:.4f}/{val_loss:.4f}/{test_loss:.4f}\n" f"Train/Val/Test loss: {train_loss:.4f}/{val_loss:.4f}/{test_loss:.4f}\n"
f"Train/Val/Test/Best val/Best test acc: {train_acc:.4f}/{val_acc:.4f}/{test_acc:.4f}/{best_val_acc:.4f}/{best_test_acc:.4f}" f"Train/Val/Test/Best val/Best test acc: {train_acc:.4f}/{val_acc:.4f}/{test_acc:.4f}/{best_val_acc:.4f}/{best_test_acc:.4f}"
) )
...@@ -234,10 +233,11 @@ def main(): ...@@ -234,10 +233,11 @@ def main():
# load data # load data
data = DglNodePropPredDataset(name="ogbn-arxiv") data = DglNodePropPredDataset(name="ogbn-arxiv")
evaluator = Evaluator(name="ogbn-arxiv")
splitted_idx = data.get_idx_split() splitted_idx = data.get_idx_split()
train_idx, val_idx, test_idx = splitted_idx["train"], splitted_idx["valid"], splitted_idx["test"] train_idx, val_idx, test_idx = splitted_idx["train"], splitted_idx["valid"], splitted_idx["test"]
graph, labels = data[0] graph, labels = data[0]
labels = labels[:, 0]
# add reverse edges # add reverse edges
srcs, dsts = graph.all_edges() srcs, dsts = graph.all_edges()
...@@ -263,7 +263,7 @@ def main(): ...@@ -263,7 +263,7 @@ def main():
test_accs = [] test_accs = []
for i in range(args.n_runs): for i in range(args.n_runs):
val_acc, test_acc = run(args, graph, labels, train_idx, val_idx, test_idx, i) val_acc, test_acc = run(args, graph, labels, train_idx, val_idx, test_idx, evaluator, i)
val_accs.append(val_acc) val_accs.append(val_acc)
test_accs.append(test_acc) test_accs.append(test_acc)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment