在閱讀源碼的過程中,BN代碼部分出現了一些之前沒見過的參數,在這裏總結一下(用小寫字母代表,具體出現在各個程序的源碼中可能有區別,但是大致應該相同)。
-
epsilon:防止normalization過程中分母出現爲0的情況,一般設置爲很小的值(例如1e-5),如下是batch norm的算法描述過程,在算法第四步中分母部分出現了epsilon
-
momentum:batch norm需要計算加權移動平均數(EMA),momentum就是移動平均值的權重,如下是代碼例子,在代碼的21行和22行就是momentum(權重)的使用。
def Batchnorm_simple_for_train(x, gamma, beta, bn_param):
"""
param:x : 輸入數據,設shape(B,L)
param:gama : 縮放因子 γ
param:beta : 平移因子 β
param:bn_param : batchnorm所需要的一些參數
eps : 接近0的數,防止分母出現0
momentum : 動量參數,一般爲0.9, 0.99, 0.999
running_mean :滑動平均的方式計算新的均值,訓練時計算,爲測試數據做準備
running_var : 滑動平均的方式計算新的方差,訓練時計算,爲測試數據做準備
"""
running_mean = bn_param['running_mean'] #shape = [B]
running_var = bn_param['running_var'] #shape = [B]
results = 0. # 建立一個新的變量
x_mean=x.mean(axis=0) # 計算x的均值
x_var=x.var(axis=0) # 計算方差
x_normalized=(x-x_mean)/np.sqrt(x_var+eps) # 歸一化
results = gamma * x_normalized + beta # 縮放平移
running_mean = momentum * running_mean + (1 - momentum) * x_mean
running_var = momentum * running_var + (1 - momentum) * x_var
#記錄新的值
bn_param['running_mean'] = running_mean
bn_param['running_var'] = running_var
return results , bn_param
-
use_precise_stats:在使用batch norm的時候,訓練的時候有batch的概念,但是測試的時候並沒有batch,所以在測試的時候需要找到一個適當的值來進行normalization,這個值就是EMA(上述的滑動平均數),但是EMA僅僅是一個估計值,當訓練的時候計算的EMA不能很好的估計到測試的時候的均值和方差的時候(EMA的計算方式有問題或者batch和model不穩定),batch norm就會失效。
在EMA的計算過程中,如果lamda過小,那麼最近的均值對EMA貢獻過大,就會產生很大的偏差,如果lamda過大,那麼需要大量的迭代才能得到結果(通常的lamda取值範圍是0.9~0.99)
將模型固定住,取一定數量的batch,計算真正的均值和方差(不是EMA),這就是precise batch norm,batch的數量也是一個超參數。
注意precise batch norm不是一個主流的方法,因爲EMA通常是有效的(lamda足夠大,模型會迭代訓練很多輪,選取的模型在經過一定的迭代後會穩定下來)。 -
num_batches_precise:在precise batchnorm中計算平均數使用的batch數量。
參考:
https://blog.csdn.net/shuzfan/article/details/50723877
https://blog.csdn.net/qq_25737169/article/details/79048516
https://www.bilibili.com/video/av60805995