CoolFace
Modelpublic

rk-random/PACT-Net

sourceHugging Facemitupdated 9mo agoView on Hugging Face
1likes
polyatomic.py140 linesDownload Raw Back to models
1import torch2import torch_geometric3import torch.nn as nn4import torch.nn.functional as F5from torch_geometric.nn import (6    PNAConv,7    global_mean_pool,8    global_max_pool,9    global_add_pool,10)11from torch_geometric.utils import degree12 13 14class PolyatomicNet(nn.Module):15    def __init__(16        self,17        node_feat_dim,18        edge_feat_dim,19        graph_feat_dim,20        deg,21        hidden_dim=128,22        num_layers=5,23        dropout=0.1,24    ):25        super().__init__()26        self.graph_feat_dim = graph_feat_dim27        self.node_emb = nn.Linear(node_feat_dim, hidden_dim)28        self.deg = deg29        self.virtualnode_emb = nn.Embedding(1, hidden_dim)30        self.vn_mlp = nn.Sequential(31            nn.Linear(hidden_dim, hidden_dim),32            nn.ReLU(),33            nn.Linear(hidden_dim, hidden_dim),34        )35 36        # For graph-level feature projection37        self.graph_proj = nn.Sequential(38            nn.Linear(graph_feat_dim, hidden_dim),39            nn.ReLU(),40            nn.Linear(hidden_dim, hidden_dim),41        )42 43        # PNAConv requires degree preprocessing44        self.deg_emb = nn.Embedding(20, hidden_dim)  # cap degree buckets45 46        aggregators = ["mean", "min", "max", "std"]47        scalers = ["identity", "amplification", "attenuation"]48 49        self.convs = nn.ModuleList()50        self.bns = nn.ModuleList()51 52        for _ in range(num_layers):53            conv = PNAConv(54                in_channels=hidden_dim,55                out_channels=hidden_dim,56                aggregators=aggregators,57                scalers=scalers,58                edge_dim=edge_feat_dim,59                towers=4,60                pre_layers=1,61                post_layers=1,62                divide_input=True,63                deg=deg,64            )65            self.convs.append(conv)66            self.bns.append(nn.BatchNorm1d(hidden_dim))67 68        self.dropout = nn.Dropout(dropout)69 70        # Final readout71        self.readout = nn.Sequential(72            nn.Linear(hidden_dim * 3, hidden_dim),73            nn.ReLU(),74            nn.Dropout(dropout),75            nn.Linear(hidden_dim, hidden_dim // 2),76            nn.ReLU(),77            nn.Linear(hidden_dim // 2, 1),78        )79 80    def forward(self, data):81        x, edge_index, edge_attr, batch = (82            data.x,83            data.edge_index,84            data.edge_attr,85            data.batch,86        )87 88        deg = degree(edge_index[0], x.size(0), dtype=torch.long).clamp(max=19)89        h = self.node_emb(x) + self.deg_emb(deg)90 91        vn = self.virtualnode_emb(92            torch.zeros(batch.max().item() + 1, dtype=torch.long, device=x.device)93        )94 95        for conv, bn in zip(self.convs, self.bns):96            h = h + vn[batch]97            h = conv(h, edge_index, edge_attr)98            h = bn(h)99            h = F.relu(h)100            h = self.dropout(h)101            vn = vn + self.vn_mlp(global_mean_pool(h, batch))102 103        mean_pool = global_mean_pool(h, batch)104        max_pool = global_max_pool(h, batch)105        # add_pool = global_add_pool(h, batch)106 107        max_feat_dim = self.graph_feat_dim108 109        if hasattr(data, "graph_feats") and isinstance(110            data, torch_geometric.data.Batch  # type: ignore111        ):112            g_proj_list = []113            for g in data.to_data_list():114                g_feat = g.graph_feats.to(x.device)115 116                if g_feat.size(0) < max_feat_dim:117                    padded = torch.zeros(max_feat_dim, device=g_feat.device)118                    padded[: g_feat.size(0)] = g_feat119                    g_feat = padded120                elif g_feat.size(0) > max_feat_dim:121                    g_feat = g_feat[:max_feat_dim]122                g_feat = torch.nan_to_num(g_feat, nan=0.0, posinf=1e5, neginf=-1e5)123                g_proj_list.append(self.graph_proj(g_feat))124 125            g_proj = torch.stack(g_proj_list, dim=0)126 127        else:128            g_feat = data.graph_feats.to(x.device)129            if g_feat.size(0) < max_feat_dim:130                padded = torch.zeros(max_feat_dim, device=g_feat.device)131                padded[: g_feat.size(0)] = g_feat132                g_feat = padded133            elif g_feat.size(0) > max_feat_dim:134                g_feat = g_feat[:max_feat_dim]135            g_feat = torch.nan_to_num(g_feat, nan=0.0, posinf=1e5, neginf=-1e5)136            g_proj = self.graph_proj(g_feat).unsqueeze(0)137 138        final_input = torch.cat([mean_pool, max_pool, g_proj], dim=1)139        return self.readout(final_input).view(-1)140