為了解決
Internal Covariate Shift
問題引入,該問題具體表現為:
- 中間層輸入分布總是變化,增加了模型拟合的難度。
- 中間層輸入分布會使輸出逐漸靠近激活函數梯度較小的地方,導緻梯度消失
BatchNorm就是在深度神經網絡訓練過程中使得每一層神經網絡的輸入保持相同分布的,在輸入到激活函數之前,對每個mini-batch輸入,做如下處理:
整個的過程如下圖所示,訓練過程為第1-6行,這裡需要注意BN層引入了可訓練參數的 β \beta β和 γ \gamma γ。
假設有K個激活函數,每個
mini-batch
在傳入每個激活函數之前,需要經過一個BN層
inference
的過程為第7-11行,
inference
過程輸出應該完全由輸入決定,使用固定的均值和方差(對于隻有一個測試集,也無法統計均值和方差)。
這裡固定的均值和方差,通過使用對應位置的(某個激活函數之前)所有mini-batch的均值的期望作為均值,所有mini-batch的方差的無偏估計作為方差(第10行)
圖檔來自論文Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
pytorch中包含多種計算BatchNorm方法,下面将一一介紹
BatchNorm1d
y = x − E [ x ] Var [ x ] + ϵ ∗ γ + β y=\frac{x-\mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}} * \gamma+\beta y=Var[x]+ϵ
x−E[x]∗γ+β
β \beta β和 γ \gamma γ的初始值為0,1。
傳入BatchNorm1d的參數如下:
-
需要進行Normalization的那個次元大小 C C C,輸入的次元可以是 ( N , C ) (N,C) (N,C)和 ( N , C , L ) (N,C,L) (N,C,L)num_features
-
上述公式中的 ϵ \epsilon ϵ,防止分母為 ,預設為eps
1e-5
-
用于計算momentum
過程的均值和方差(滑動平均),預設為inference
0.1
-
是否使用可訓練參數的 β \beta β和 γ \gamma γ,預設為affine
True
-
是否記錄上一個track_running_stats
的均值mini-batch
和方差running_mean
。如果是,通過滑動平均的方式得到running_var
時的均值和方差;如果不是,則需要在inference
時重新計算。inference
當
track_running_stats=True
時,
momentum
使用如下:
running_mean = momentum * running_mean + (1 - momentum) * x_mean
running_var = momentum * running_var + (1 - momentum) * x_var
inference
直接使用最後的
running_mean
和
running_var
作為固定的均值和方差
import torch
import torch.nn as nn
import numpy as np
import math
def validation(x):
"""
驗證函數
:param x:
:return:
"""
x = np.array(x)
avg = np.mean(x, axis=0)
std2 = np.var(x, axis=0)
x_avg = [[item for item in avg] for _ in range(x.shape[0])]
x_std = [[math.pow(item, 1 / 2) for item in std2] for _ in range(x.shape[0])]
x_ = (x - np.array(x_avg)) / np.array(x_std)
return x_
# With Learnable Parameters
# m = nn.BatchNorm1d(4)
# Without Learnable Parameters
m = nn.BatchNorm1d(4, affine=False)
x = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]
input = torch.tensor(x, dtype=torch.float)
output = m(input)
print(output)
res = validation(x)
print("valiadation:\n", res)
輸出:
tensor([[-1.2247, -1.2247, -1.2247, -1.2247],
[ 0.0000, 0.0000, 0.0000, 0.0000],
[ 1.2247, 1.2247, 1.2247, 1.2247]])
valiadation:
[[-1.22474487 -1.22474487 -1.22474487 -1.22474487]
[ 0. 0. 0. 0. ]
[ 1.22474487 1.22474487 1.22474487 1.22474487]]
也可以輸入三維張量:
m = nn.BatchNorm1d(4, affine=False)
x = [[[1, 1], [2, 2], [3, 3], [4, 4]], [[2, 2], [3, 3], [4, 4], [5, 5]], [[3, 3], [4, 4], [5, 5], [6, 6]]]
input = torch.tensor(x, dtype=torch.float)
print(input.size())
output = m(input)
print(output)
輸出:
torch.Size([3, 4, 2])
tensor([[[-1.2247, -1.2247],
[-1.2247, -1.2247],
[-1.2247, -1.2247],
[-1.2247, -1.2247]],
[[ 0.0000, 0.0000],
[ 0.0000, 0.0000],
[ 0.0000, 0.0000],
[ 0.0000, 0.0000]],
[[ 1.2247, 1.2247],
[ 1.2247, 1.2247],
[ 1.2247, 1.2247],
[ 1.2247, 1.2247]]])
BatchNorm2d
同上BatchNorm1d
y = x − E [ x ] Var [ x ] + ϵ ∗ γ + β y=\frac{x-\mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}} * \gamma+\beta y=Var[x]+ϵ
x−E[x]∗γ+β
β \beta β和 γ \gamma γ的初始值為0,1。
-
需要進行Normalization的那個次元大小 C C C,輸入的次元可以是 ( N , C , H , W ) (N, C, H, W) (N,C,H,W)num_features
BatchNorm3d
同上BatchNorm1d
y = x − E [ x ] Var [ x ] + ϵ ∗ γ + β y=\frac{x-\mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}} * \gamma+\beta y=Var[x]+ϵ
x−E[x]∗γ+β
β \beta β和 γ \gamma γ的初始值為0,1。
-
需要進行Normalization的那個次元大小 C C C,輸入的次元可以是 ( N , C , D , H , W ) (N, C, D, H, W) (N,C,D,H,W)num_features