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

158 lines
4.0 KiB
Python
Executable File

import dgl.function as fn
import numpy as np
import torch as th
import torch.nn as nn
import torch.nn.functional as F
def drop_node(feats, drop_rate, training):
n = feats.shape[0]
drop_rates = th.FloatTensor(np.ones(n) * drop_rate)
if training:
masks = th.bernoulli(1.0 - drop_rates).unsqueeze(1)
feats = masks.to(feats.device) * feats
else:
feats = feats * (1.0 - drop_rate)
return feats
class MLP(nn.Module):
def __init__(
self, nfeat, nhid, nclass, input_droprate, hidden_droprate, use_bn=False
):
super(MLP, self).__init__()
self.layer1 = nn.Linear(nfeat, nhid, bias=True)
self.layer2 = nn.Linear(nhid, nclass, bias=True)
self.input_dropout = nn.Dropout(input_droprate)
self.hidden_dropout = nn.Dropout(hidden_droprate)
self.bn1 = nn.BatchNorm1d(nfeat)
self.bn2 = nn.BatchNorm1d(nhid)
self.use_bn = use_bn
def reset_parameters(self):
self.layer1.reset_parameters()
self.layer2.reset_parameters()
def forward(self, x):
if self.use_bn:
x = self.bn1(x)
x = self.input_dropout(x)
x = F.relu(self.layer1(x))
if self.use_bn:
x = self.bn2(x)
x = self.hidden_dropout(x)
x = self.layer2(x)
return x
def GRANDConv(graph, feats, order):
"""
Parameters
-----------
graph: dgl.Graph
The input graph
feats: Tensor (n_nodes * feat_dim)
Node features
order: int
Propagation Steps
"""
with graph.local_scope():
"""Calculate Symmetric normalized adjacency matrix \hat{A}"""
degs = graph.in_degrees().float().clamp(min=1)
norm = th.pow(degs, -0.5).to(feats.device).unsqueeze(1)
graph.ndata["norm"] = norm
graph.apply_edges(fn.u_mul_v("norm", "norm", "weight"))
""" Graph Conv """
x = feats
y = 0 + feats
for i in range(order):
graph.ndata["h"] = x
graph.update_all(fn.u_mul_e("h", "weight", "m"), fn.sum("m", "h"))
x = graph.ndata.pop("h")
y.add_(x)
return y / (order + 1)
class GRAND(nn.Module):
r"""
Parameters
-----------
in_dim: int
Input feature size. i.e, the number of dimensions of: math: `H^{(i)}`.
hid_dim: int
Hidden feature size.
n_class: int
Number of classes.
S: int
Number of Augmentation samples
K: int
Number of Propagation Steps
node_dropout: float
Dropout rate on node features.
input_dropout: float
Dropout rate of the input layer of a MLP
hidden_dropout: float
Dropout rate of the hidden layer of a MLPx
batchnorm: bool, optional
If True, use batch normalization.
"""
def __init__(
self,
in_dim,
hid_dim,
n_class,
S=1,
K=3,
node_dropout=0.0,
input_droprate=0.0,
hidden_droprate=0.0,
batchnorm=False,
):
super(GRAND, self).__init__()
self.in_dim = in_dim
self.hid_dim = hid_dim
self.S = S
self.K = K
self.n_class = n_class
self.mlp = MLP(
in_dim, hid_dim, n_class, input_droprate, hidden_droprate, batchnorm
)
self.dropout = node_dropout
self.node_dropout = nn.Dropout(node_dropout)
def forward(self, graph, feats, training=True):
X = feats
S = self.S
if training: # Training Mode
output_list = []
for s in range(S):
drop_feat = drop_node(X, self.dropout, True) # Drop node
feat = GRANDConv(graph, drop_feat, self.K) # Graph Convolution
output_list.append(
th.log_softmax(self.mlp(feat), dim=-1)
) # Prediction
return output_list
else: # Inference Mode
drop_feat = drop_node(X, self.dropout, False)
X = GRANDConv(graph, drop_feat, self.K)
return th.log_softmax(self.mlp(X), dim=-1)