批量歸一化 Batch Normalization
設置合適的權重初始值,則各層的激活值分布會有適當的廣度,從而可以順利的進行學習。那么,更進一步,強制性的調整激活值的分布,是的各層擁有適當的廣度呢?批量歸一化(Batch Normalization)就是基于這個想法產生的。
算法介紹
有什么優點呢?
- 可以使學習快速進行(可以增大學習率)。
- 不那么依賴初始值(對于初始值不用那么神經質)。
- 抑制過擬合(降低Dropout等的必要性)
向神經網絡中插入對數據分布進行正規化的層,即Batch Normalization層。
式(6.7), μ B ← 1 m ∑ i = 1 m x i σ B 2 ← 1 m ∑ i = 1 m ( x i ? μ B ) 2 x ^ i ← x i ? μ B σ B 2 + ? \begin{aligned} \mu_B &\leftarrow \frac{1}{m}\sum^m_{i=1}x_i \\ \sigma_B^2 &\leftarrow \frac{1}{m}\sum^m_{i=1}(x_i-\mu_B)^2 \\ \hat{x}_i &\leftarrow \frac{x_i-\mu_B}{\sqrt{\sigma_B^2+\epsilon}} \end{aligned} μB?σB2?x^i??←m1?i=1∑m?xi?←m1?i=1∑m?(xi??μB?)2←σB2?+??xi??μB???
這里對mini-batch的 m m m個輸入數據的集合 B = { x 1 , x 2 , . . . , x m } B = \{x_1, x_2, ... , x_m\} B={x1?,x2?,...,xm?}求均值 μ B \mu_B μB?和方差 σ B 2 \sigma_B^2 σB2? 。然后,對輸入數據進行均值為0、方差為1(合適的分布)的正規化。式(6.7)中的 ? \epsilon ?是一個微小值(比如,10e-7等),它是為了防止出現除以0的情況。
式(6.7)所做的是將mini-batch的輸入數據 { x ^ 1 , x ^ 2 , . . . , x ^ m } \{\hat{x}_1, \hat{x}_2, ... , \hat{x}_m\} {x^1?,x^2?,...,x^m?}變換為均值為0、方差為1的數據。通過將這個處理插入到激活函數的前面(或者后面),可以減小數據分布的偏向。
接著,Batch Norm層會對正規化后的數據進行縮放和平移的變換,式(6.8), y i ← γ x i ^ + β y_i \leftarrow \gamma\hat{x_i} + \beta yi?←γxi?^?+β
這里, γ \gamma γ和 β \beta β是參數。一開始 γ = 1 , β = 0 \gamma = 1, \beta = 0 γ=1,β=0,然后再通過學習調整到合適的值。
幾乎所有的情況下都是使用Batch Norm時學習進行得更快。同時也可以發現,實際上,在不使用Batch Norm的情況下,如果不賦予一個尺度好的初始值,學習將完全無法進行。
通過使用批量歸一化,可以推動學習的進行。并且,對權重初始值變得健壯(“對初始值健壯”表示不那么依賴初始值)。
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 為了導入父目錄的文件而進行的設定
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.multi_layer_net_extend import MultiLayerNetExtend
from common.optimizer import SGD, Adam(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)# 減少學習數據
x_train = x_train[:1000]
t_train = t_train[:1000]max_epochs = 20
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.01def __train(weight_init_std):bn_network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10,weight_init_std=weight_init_std, use_batchnorm=True)network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100], output_size=10,weight_init_std=weight_init_std)optimizer = SGD(lr=learning_rate)train_acc_list = []bn_train_acc_list = []iter_per_epoch = max(train_size / batch_size, 1)epoch_cnt = 0for i in range(1000000000):batch_mask = np.random.choice(train_size, batch_size)x_batch = x_train[batch_mask]t_batch = t_train[batch_mask]for _network in (bn_network, network):grads = _network.gradient(x_batch, t_batch)optimizer.update(_network.params, grads)if i % iter_per_epoch == 0:train_acc = network.accuracy(x_train, t_train)bn_train_acc = bn_network.accuracy(x_train, t_train)train_acc_list.append(train_acc)bn_train_acc_list.append(bn_train_acc)print("epoch:" + str(epoch_cnt) + " | " + str(train_acc) + " - " + str(bn_train_acc))epoch_cnt += 1if epoch_cnt >= max_epochs:breakreturn train_acc_list, bn_train_acc_list# 3.繪制圖形==========
weight_scale_list = np.logspace(0, -4, num=16)
x = np.arange(max_epochs)for i, w in enumerate(weight_scale_list):print( "============== " + str(i+1) + "/16" + " ==============")train_acc_list, bn_train_acc_list = __train(w)plt.subplot(4,4,i+1)plt.title("W:" + str(w))if i == 15:plt.plot(x, bn_train_acc_list, label='Batch Normalization', markevery=2)plt.plot(x, train_acc_list, linestyle = "--", label='Normal(without BatchNorm)', markevery=2)else:plt.plot(x, bn_train_acc_list, markevery=2)plt.plot(x, train_acc_list, linestyle="--", markevery=2)plt.ylim(0, 1.0)if i % 4:plt.yticks([])else:plt.ylabel("accuracy")if i < 12:plt.xticks([])else:plt.xlabel("epochs")plt.legend(loc='lower right')
plt.show()
背景
批量歸一化(Batch Normalization)與層歸一化(Layer Normalization)深度解析
什么是歸一化 Normalization
在深度神經網絡的訓練過程中,隨著網絡深度的增加,模型的表征能力雖然有所提升,但也帶來了許多訓練上的難題。其中,梯度消失和梯度爆炸是最具代表性的兩個問題。早期的深層網絡中常使用Sigmoid或tanh等飽和激活函數,一旦輸入落入函數的飽和區(梯度接近0),梯度在層間傳播時會迅速衰減;另一方面,如果網絡層數較多或參數初始化不當,也有可能發生梯度的指數級增長,從而使參數更新呈現“發散”現象。
與此同時,隨著網絡在反向傳播中不斷更新,前幾層的參數變化會連帶影響后續層的輸入分布,導致高層特征分布發生非平穩性,這種現象被稱為內部協變量偏移(Internal Covariate Shift)。在網絡很深或數據分布復雜的情況下,這種效應會被放大,導致網絡難以收斂或需要極度細心地調整超參數。
歸一化(Normalization)技術正是在這樣的背景下逐漸興起的。它的核心思想是,無論網絡有多深,都希望每一層的輸入分布盡量穩定、可控。為此,通過對每一層的激活值進行某種形式的“標準化”處理,可以使每層輸入在訓練中保持較為穩定的分布,即均值和方差在較短的訓練迭代內不發生劇烈波動。這種操作一方面有助于緩解梯度消失和梯度爆炸;另一方面,網絡也不需要時時刻刻去適應快速變化的激活分布,從而提高了學習效率并縮短訓練收斂時間。
批量歸一化對批量大小的依賴
BN對批量大小較為敏感,如果批量太小(例如小于16甚至更小),當前批次的均值方差容易出現大幅波動,進而導致訓練不穩定或性能下降。在一些僅能使用小批量(如顯存受限或序列生成任務)的場景下,BN的效果往往不及設計專門的歸一化策略(例如LN、GN等)。
優缺點
優點:
- 大幅加速收斂,允許使用更高的初始學習率。
- 有一定正則化作用,降低對初始權重的敏感性,減少過擬合。
- 在主流圖像任務和大型批量訓練的場景下表現卓越。
缺點:
- 依賴足夠大的批量尺寸,否則會導致估計方差不穩定。
- 在序列模型(如RNN、Transformer等)或者小批量場景中表現不佳。
- 在分布式訓練時,計算全局均值與方差可能比較麻煩,需要額外同步開銷。