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

153 lines
4.6 KiB
Python

import argparse
import warnings
import dgl
import torch as th
from dataset import load
from dgl.dataloading import GraphDataLoader
warnings.filterwarnings("ignore")
from model import MVGRL
from utils import linearsvc
parser = argparse.ArgumentParser(description="mvgrl")
parser.add_argument(
"--dataname", type=str, default="MUTAG", help="Name of dataset."
)
parser.add_argument(
"--gpu", type=int, default=-1, help="GPU index. Default: -1, using cpu."
)
parser.add_argument(
"--epochs", type=int, default=200, help=" Number of training periods."
)
parser.add_argument(
"--patience", type=int, default=20, help="Early stopping steps."
)
parser.add_argument(
"--lr", type=float, default=0.001, help="Learning rate of mvgrl."
)
parser.add_argument(
"--wd", type=float, default=0.0, help="Weight decay of mvgrl."
)
parser.add_argument("--batch_size", type=int, default=64, help="Batch size.")
parser.add_argument(
"--n_layers", type=int, default=4, help="Number of GNN layers."
)
parser.add_argument("--hid_dim", type=int, default=32, help="Hidden layer dim.")
args = parser.parse_args()
# check cuda
if args.gpu != -1 and th.cuda.is_available():
args.device = "cuda:{}".format(args.gpu)
else:
args.device = "cpu"
def collate(samples):
"""collate function for building the graph dataloader"""
graphs, diff_graphs, labels = map(list, zip(*samples))
# generate batched graphs and labels
batched_graph = dgl.batch(graphs)
batched_labels = th.tensor(labels)
batched_diff_graph = dgl.batch(diff_graphs)
n_graphs = len(graphs)
graph_id = th.arange(n_graphs)
graph_id = dgl.broadcast_nodes(batched_graph, graph_id)
batched_graph.ndata["graph_id"] = graph_id
return batched_graph, batched_diff_graph, batched_labels
if __name__ == "__main__":
# Step 1: Prepare data =================================================================== #
dataset = load(args.dataname)
graphs, diff_graphs, labels = map(list, zip(*dataset))
print("Number of graphs:", len(graphs))
# generate a full-graph with all examples for evaluation
wholegraph = dgl.batch(graphs)
whole_dg = dgl.batch(diff_graphs)
# create dataloader for batch training
dataloader = GraphDataLoader(
dataset,
batch_size=args.batch_size,
collate_fn=collate,
drop_last=False,
shuffle=True,
)
in_dim = wholegraph.ndata["feat"].shape[1]
# Step 2: Create model =================================================================== #
model = MVGRL(in_dim, args.hid_dim, args.n_layers)
model = model.to(args.device)
# Step 3: Create training components ===================================================== #
optimizer = th.optim.Adam(model.parameters(), lr=args.lr)
print("===== Before training ======")
wholegraph = wholegraph.to(args.device)
whole_dg = whole_dg.to(args.device)
wholefeat = wholegraph.ndata.pop("feat")
whole_weight = whole_dg.edata.pop("edge_weight")
embs = model.get_embedding(wholegraph, whole_dg, wholefeat, whole_weight)
lbls = th.LongTensor(labels)
acc_mean, acc_std = linearsvc(embs, lbls)
print("accuracy_mean, {:.4f}".format(acc_mean))
best = float("inf")
cnt_wait = 0
# Step 4: Training epochs =============================================================== #
for epoch in range(args.epochs):
loss_all = 0
model.train()
for graph, diff_graph, label in dataloader:
graph = graph.to(args.device)
diff_graph = diff_graph.to(args.device)
feat = graph.ndata["feat"]
graph_id = graph.ndata["graph_id"]
edge_weight = diff_graph.edata["edge_weight"]
n_graph = label.shape[0]
optimizer.zero_grad()
loss = model(graph, diff_graph, feat, edge_weight, graph_id)
loss_all += loss.item()
loss.backward()
optimizer.step()
print("Epoch {}, Loss {:.4f}".format(epoch, loss_all))
if loss_all < best:
best = loss_all
best_t = epoch
cnt_wait = 0
th.save(model.state_dict(), f"{args.dataname}.pkl")
else:
cnt_wait += 1
if cnt_wait == args.patience:
print("Early stopping")
break
print("Training End")
# Step 5: Linear evaluation ========================================================== #
model.load_state_dict(th.load(f"{args.dataname}.pkl"))
embs = model.get_embedding(wholegraph, whole_dg, wholefeat, whole_weight)
acc_mean, acc_std = linearsvc(embs, lbls)
print("accuracy_mean, {:.4f}".format(acc_mean))