Files
2026-07-13 13:35:51 +08:00

127 lines
3.6 KiB
Python

import argparse
import time
import dgl.sparse as dglsp
import torch.nn.functional as F
import torch.optim as optim
from dgl import AddSelfLoop
from dgl.data import CiteseerGraphDataset, CoraGraphDataset, PubmedGraphDataset
from ogc import OGC
from utils import model_test, symmetric_normalize_adjacency
def train(model, embeds, lazy_adj, args):
patience = 0
_, _, last_acc, last_output = model_test(model, embeds)
tv_mask = model.tv_mask
optimizer = optim.SGD(model.parameters(), lr=args.lr_clf)
for i in range(64):
model.train()
output = model(embeds)
loss_tv = F.mse_loss(
output[tv_mask], model.label_one_hot[tv_mask], reduction="sum"
)
optimizer.zero_grad()
loss_tv.backward()
optimizer.step()
# Updating node embeds by LGC and SEB jointly.
embeds = model.update_embeds(embeds, lazy_adj, args)
loss_tv, acc_tv, acc_test, pred = model_test(model, embeds)
print(
"epoch {} loss_tv {:.4f} acc_tv {:.4f} acc_test {:.4f}".format(
i + 1, loss_tv, acc_tv, acc_test
)
)
sim_rate = float(int((pred == last_output).sum()) / int(pred.shape[0]))
if sim_rate > args.max_sim_rate:
patience += 1
if patience > args.max_patience:
break
last_acc = acc_test
last_output = pred
return last_acc
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--dataset",
type=str,
default="citeseer",
choices=["cora", "citeseer", "pubmed"],
help="dataset to use",
)
parser.add_argument(
"--decline", type=float, default=0.9, help="decline rate"
)
parser.add_argument(
"--lr_sup",
type=float,
default=0.001,
help="learning rate for supervised loss",
)
parser.add_argument(
"--lr_clf",
type=float,
default=0.5,
help="learning rate for the used linear classifier",
)
parser.add_argument(
"--beta",
type=float,
default=0.1,
help="moving probability that a node moves to its neighbors",
)
parser.add_argument(
"--max_sim_rate",
type=float,
default=0.995,
help="max label prediction similarity between iterations",
)
parser.add_argument(
"--max_patience",
type=int,
default=2,
help="tolerance for consecutively similar test predictions",
)
parser.add_argument(
"--device",
type=str,
default="cpu",
choices=["cpu", "cuda"],
help="device to use",
)
args, _ = parser.parse_known_args()
# Load and preprocess dataset.
transform = AddSelfLoop()
if args.dataset == "cora":
data = CoraGraphDataset(transform=transform)
elif args.dataset == "citeseer":
data = CiteseerGraphDataset(transform=transform)
elif args.dataset == "pubmed":
data = PubmedGraphDataset(transform=transform)
else:
raise ValueError("Unknown dataset: {}".format(args.dataset))
graph = data[0].to(args.device)
features = graph.ndata["feat"]
adj = symmetric_normalize_adjacency(graph)
I_N = dglsp.identity((features.shape[0], features.shape[0]))
# Lazy random walk (also known as lazy graph convolution).
lazy_adj = dglsp.add((1 - args.beta) * I_N, args.beta * adj).to(args.device)
model = OGC(graph).to(args.device)
start_time = time.time()
res = train(model, features, lazy_adj, args)
time_tot = time.time() - start_time
print(f"Test Acc:{res:.4f}")
print(f"Total Time:{time_tot:.4f}")