-
-
Notifications
You must be signed in to change notification settings - Fork 129
Expand file tree
/
Copy pathnormalization.py
More file actions
58 lines (48 loc) · 2.14 KB
/
Copy pathnormalization.py
File metadata and controls
58 lines (48 loc) · 2.14 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
50
51
52
53
54
55
56
57
58
import torch
from .base import Flow
from .affine_coupling import AffineConstFlow
class ActNorm(AffineConstFlow):
"""
An AffineConstFlow but with a data-dependent initialization,
where on the very first batch we clever initialize the s,t so that the output
is unit gaussian. As described in Glow paper.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# self.data_dep_init_done_cpu = torch.tensor(0.)
self.register_buffer('data_dep_init_done', torch.tensor(0.))
def forward(self, z):
# first batch is used for initialization, c.f. batchnorm
if not self.data_dep_init_done > 0.:
assert self.s is not None and self.t is not None
s_init = -torch.log(z.std(dim=self.batch_dims, keepdim=True) + 1e-6)
self.s.data = s_init.data
self.t.data = (-z.mean(dim=self.batch_dims, keepdim=True) * torch.exp(self.s)).data
self.data_dep_init_done[...] = 1.
return super().forward(z)
def inverse(self, z):
# first batch is used for initialization, c.f. batchnorm
if not self.data_dep_init_done:
assert self.s is not None and self.t is not None
s_init = torch.log(z.std(dim=self.batch_dims, keepdim=True) + 1e-6)
self.s.data = s_init.data
self.t.data = z.mean(dim=self.batch_dims, keepdim=True).data
self.data_dep_init_done[...] = 1.
return super().inverse(z)
class BatchNorm(Flow):
"""
Batch Normalization with out considering the derivatives of the batch statistics, see arXiv: 1605.08803
"""
def __init__(self, eps=1.e-10):
super().__init__()
self.eps_cpu = torch.tensor(eps)
self.register_buffer('eps', self.eps_cpu)
def forward(self, z):
"""
Do batch norm over batch and sample dimension
"""
mean = torch.mean(z, dim=0, keepdims=True)
std = torch.std(z, dim=0, keepdims=True)
z_ = (z - mean) / torch.sqrt(std ** 2 + self.eps)
log_det = torch.log(1 / torch.prod(torch.sqrt(std ** 2 + self.eps))).repeat(z.size()[0])
return z_, log_det