-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlayers.py
98 lines (88 loc) · 3.44 KB
/
layers.py
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import torch
from torch import nn
import torch.nn.functional as F
def _norm_no_nan(x, axis=-1, keepdims=False, eps=1e-8, sqrt=True):
'''
This class implementation is taken from
https://github.com/drorlab/gvp-pytorch/blob/main/gvp/__init__.py
L2 norm of tensor clamped above a minimum value `eps`.
:param sqrt: if `False`, returns the square of the L2 norm
'''
out = torch.clamp(torch.sum(torch.square(x), axis, keepdims), min=eps)
return torch.sqrt(out) if sqrt else out
class GVP(nn.Module):
'''
This class implementation is taken from
https://github.com/drorlab/gvp-pytorch/blob/main/gvp/__init__.py
'''
def __init__(self, in_dims, out_dims, h_dim=None,
activations=(F.relu, torch.sigmoid), vector_gate=False):
super(GVP, self).__init__()
self.si, self.vi = in_dims
self.so, self.vo = out_dims
self.vector_gate = vector_gate
if self.vi:
self.h_dim = h_dim or max(self.vi, self.vo)
self.wh = nn.Linear(self.vi, self.h_dim, bias=False)
self.ws = nn.Linear(self.h_dim + self.si, self.so)
if self.vo:
self.wv = nn.Linear(self.h_dim, self.vo, bias=False)
if self.vector_gate: self.wsv = nn.Linear(self.so, self.vo)
else:
self.ws = nn.Linear(self.si, self.so)
self.scalar_act, self.vector_act = activations
self.dummy_param = nn.Parameter(torch.empty(0))
def forward(self, x):
'''
:param x: tuple (s, V) of `torch.Tensor`,
or (if vectors_in is 0), a single `torch.Tensor`
:return: tuple (s, V) of `torch.Tensor`,
or (if vectors_out is 0), a single `torch.Tensor`
'''
if self.vi:
s, v = x
v = torch.transpose(v, -1, -2)
vh = self.wh(v)
vn = _norm_no_nan(vh, axis=-2)
s = self.ws(torch.cat([s, vn], -1))
if self.vo:
v = self.wv(vh)
v = torch.transpose(v, -1, -2)
if self.vector_gate:
if self.vector_act:
gate = self.wsv(self.vector_act(s))
else:
gate = self.wsv(s)
v = v * torch.sigmoid(gate).unsqueeze(-1)
elif self.vector_act:
v = v * self.vector_act(
_norm_no_nan(v, axis=-1, keepdims=True))
else:
s = self.ws(x)
if self.vo:
v = torch.zeros(s.shape[0], self.vo, 3,
device=self.dummy_param.device)
if self.scalar_act:
s = self.scalar_act(s)
return (s, v) if self.vo else s
class _VDropout(nn.Module):
'''
Vector channel dropout where the elements of each
vector channel are dropped together.
'''
def __init__(self, drop_rate):
super(_VDropout, self).__init__()
self.drop_rate = drop_rate
self.dummy_param = nn.Parameter(torch.empty(0))
def forward(self, x):
'''
:param x: `torch.Tensor` corresponding to vector channels
'''
device = self.dummy_param.device
if not self.training:
return x
mask = torch.bernoulli(
(1 - self.drop_rate) * torch.ones(x.shape[:-1], device=device)
).unsqueeze(-1)
x = mask * x / (1 - self.drop_rate)
return x