#!/usr/bin/env python3 """H33: 20-seed extension of L=20 hero on 4 real-world datasets × {BP, DFA, DFA-GNN, GRAFT}. Paper setup (5%/class, hidden=64, lr=0.01, no scheduler, 200 epochs, GCN backbone, no dropout/BN/res). Tightens DBLP std (0.121 at 10-seed bimodal) for paper-grade stats. Run as: python run_realworld_hero_L20.py [SEED_START SEED_END] default: 10..19 (extending prior seeds 0..9). """ import sys, time import numpy as np import torch import torch.nn as nn import torch.nn.functional as F from torch_geometric.datasets import CitationFull, Coauthor from torch_geometric.nn import GCNConv from torch_geometric.utils import add_self_loops, degree sys.path.insert(0, '/home/yurenh2/graph-grape') from src.trainers import GraphGrAPETrainer device = torch.device('cuda:2') def build_A_hat(edge_index, N): edge_index, _ = add_self_loops(edge_index, num_nodes=N) row, col = edge_index deg = degree(row, num_nodes=N, dtype=torch.float) dis = deg.pow(-0.5); dis[dis == float('inf')] = 0 return torch.sparse_coo_tensor(edge_index, dis[row]*dis[col], (N, N)).coalesce() def build_row_norm(edge_index, N): ei, _ = add_self_loops(edge_index, num_nodes=N) row, col = ei deg = degree(row, num_nodes=N, dtype=torch.float).clamp(min=1) A_row = torch.sparse_coo_tensor(ei, 1.0/deg[row], (N,N)).coalesce() A_row_T = torch.sparse_coo_tensor(ei.flip(0), 1.0/deg[col], (N,N)).coalesce() return A_row, A_row_T def paper_split(N, y, seed, train_frac=0.05, n_val=500): g = torch.Generator().manual_seed(seed) train_mask = torch.zeros(N, dtype=torch.bool) val_mask = torch.zeros(N, dtype=torch.bool) test_mask = torch.zeros(N, dtype=torch.bool) C = int(y.max()) + 1 for c in range(C): idx = (y == c).nonzero().flatten() idx = idx[torch.randperm(idx.size(0), generator=g)] n_tr = max(1, int(round(train_frac * idx.size(0)))) train_mask[idx[:n_tr]] = True remaining = (~train_mask).nonzero().flatten() remaining = remaining[torch.randperm(remaining.size(0), generator=g)] val_mask[remaining[:n_val]] = True test_mask[remaining[n_val:]] = True return train_mask, val_mask, test_mask class GCN(nn.Module): def __init__(self, in_dim, hidden, out_dim, L): super().__init__() self.convs = nn.ModuleList([GCNConv(in_dim if i==0 else hidden, hidden if i