-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathlayer.py
More file actions
49 lines (39 loc) · 1.61 KB
/
Copy pathlayer.py
File metadata and controls
49 lines (39 loc) · 1.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import torch
import torch.nn as nn
from torch_sparse import spmm
import numpy as np
class PairNorm(nn.Module):
def __init__(self, mode='PN', scale=1):
"""
mode:
'None' : No normalization
'PN' : Original version
'PN-SI' : Scale-Individually version
'PN-SCS' : Scale-and-Center-Simultaneously version
('SCS'-mode is not in the paper but we found it works well in practice,
especially for GCN and GAT.)
PairNorm is typically used after each graph convolution operation.
"""
assert mode in ['None', 'PN', 'PN-SI', 'PN-SCS']
super(PairNorm, self).__init__()
self.mode = mode
self.scale = scale
# Scale can be set based on origina data, and also the current feature lengths.
# We leave the experiments to future. A good pool we used for choosing scale:
# [0.1, 1, 10, 50, 100]
def forward(self, x):
if self.mode == 'None':
return x
col_mean = x.mean(dim=0)
if self.mode == 'PN':
x = x - col_mean
rownorm_mean = (1e-6 + x.pow(2).sum(dim=1).mean()).sqrt()
x = self.scale * x / rownorm_mean
if self.mode == 'PN-SI':
x = x - col_mean
rownorm_individual = (1e-6 + x.pow(2).sum(dim=1, keepdim=True)).sqrt()
x = self.scale * x / rownorm_individual
if self.mode == 'PN-SCS':
rownorm_individual = (1e-6 + x.pow(2).sum(dim=1, keepdim=True)).sqrt()
x = self.scale * x / rownorm_individual - col_mean
return x