论文: Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton. Layer Normalization. arXiv:1607.06450
Batch normalization
对每个channel或者hidden unit,求输入(mini-)batch上所有样本在这个channel上的均值和标准差。之后根据每个channel上的均值和标准差对这些样本进行归一化处理。
然后对归一化后的样本的每个channel进行放射变换: y i c = g a i n c × x i c + b i a s c y_{ic}= gain_c \times x_{ic} + bias_c yic=gainc×xic+biasc,一个mini-batch上不同样本的同一channel上处理方式相同。
每个channel需要且仅需要学习两个参数: g a i n c gain_c gainc和 b i a s c bias_c biasc。
Layer normalization
对于输入的每个样本求一个均值和方差,然后根据每个样本的均值和方差对该样本进行归一化处理。
pytorch 中默认参数 elementwise_affine=True
这时需要学习 C
×
\times
× W
×
\times
×H个gain和bias。
但是归一化仍然是对每个样本CWH归一化 (归一化可指定)
如果将elementwise_affine设置为=False,则不需要学习仿射变换(不学习任何参数)。
pytorch实现与LayerNorm原文的意思不相符合。
MUNIT中自己实现的Layer Normalization:
可以看出参数数量和batchrnom相同,即为channel数的两倍。
原文中似乎并没有说仿射变换的事情,只提到了归一化方式与batchnorm的异同: Layer Normalization 对于每个样本进行归一化,学习过程中不需要限制minibatch中的样本数>=2
class LayerNorm(nn.Module):
def __init__(self, num_features, eps=1e-5, affine=True):
super(LayerNorm, self).__init__()
self.num_features = num_features
self.affine = affine
self.eps = eps
if self.affine:
self.gamma = nn.Parameter(torch.Tensor(num_features).uniform_())
self.beta = nn.Parameter(torch.zeros(num_features))
def forward(self, x):
shape = [-1] + [1] * (x.dim() - 1)
# print(x.size())
if x.size(0) == 1:
# These two lines run much faster in pytorch 0.4 than the two lines listed below.
mean = x.view(-1).mean().view(*shape)
std = x.view(-1).std().view(*shape)
else:
mean = x.view(x.size(0), -1).mean(1).view(*shape)
std = x.view(x.size(0), -1).std(1).view(*shape)
x = (x - mean) / (std + self.eps)
if self.affine:
shape = [1, -1] + [1] * (x.dim() - 2)
x = x * self.gamma.view(*shape) + self.beta.view(*shape)
Instance normalization
对于输入的每个样本:求每个channel的均值和方差(HW)。之后根据这个样本不同channel的均值和方差逐channel对该样本进行归一化处理。
这之后每个channel进行一个相同的仿射变换: y i c = g a i n c × x i c + b i a s c y_{ic}= gain_{c}\times x_{ic}+bias_{c} yic=gainc×xic+biasc。
每个通道需要且仅需要学习两个参数: g a i n c gain_c gainc和 b i a s c bias_c biasc。