博客 / 詳情

返回

吳恩達深度學習課程二: 改善深層神經網絡 第三週:超參數調整,批量標準化和編程框架(二)batch歸一化

此分類用於記錄吳恩達深度學習課程的學習筆記。
課程相關信息鏈接如下:

  1. 原課程視頻鏈接:[雙語字幕]吳恩達深度學習deeplearning.ai
  2. github課程資料,含課件與筆記:吳恩達深度學習教學資料
  3. 課程配套練習(中英)與答案:吳恩達深度學習課後習題與答案

本篇為第二課的第三週內容,3.4到3.7的內容。


本週為第二課的第三週內容,你會發現這周的題目很長,實際上,作為第二課的最後一週內容,這一週是對基礎部分的最後補充。
在整個第一課和第二課部分,我們會了解到最基本的全連接神經網絡的基本結構和一個完整的模型訓練,驗證的各個部分。
之後幾課就會進行更多的實踐和進階內容介紹,從“通用”走向“特化”。
總的來説這周的難度不高,但也有需要理解的內容,我仍會在相對較難理解的部分增加更多基礎和例子,以及最後的“人話版”總結。
本篇的內容關於batch歸一化,是本週中相對較難的理解內容,為了保證完整,所以本篇的篇幅也較長,但更多是一些基礎,實例和與之前內容的聯繫。
同樣,我也在最後增加了總結部分。

1. 什麼是Batch 歸一化?

先上概念:

Batch Normalization(簡稱 BN)是深度學習中非常常用的一種技巧,它能加速模型訓練、穩定梯度、減少對初始化的依賴、提高網絡收斂速度

簡單概括一下它的核心思想: 把對輸入的歸一化邏輯應用在隱藏層,不讓每一層的輸入“亂七八糟”,讓它們始終保持在一個更穩定、可控的分佈中。

我們先從之前學過的“輸入歸一化”開始講起。

1.1 對輸入的歸一化

我們之前已經瞭解過,對於原始的數據集,我們常發現這樣一個問題:
不同維度的特徵常常有不同的數值範圍,導致訓練過程難以協調。

舉個例子——假設我們要訓練一個分類模型,有這樣一些輸入特徵:

特徵 數值範圍
年齡 0–100
收入 0–1,000,000
身高 150–190

而如果不歸一化,模型在訓練時梯度會被“收入”這種巨大數值主導,而“年齡、身高”被淹沒。
這時,歸一化讓所有特徵擺在一個“公平”的平台上訓練,讓模型更容易學習。
如果你有些忘了它的具體概念,可以在這裏回顧:歸一化

1.2 內部協變量偏移(Internal Covariate Shift)

現在我們已經解決了原始數據的量綱差距問題。
你可能會問: “用輸入歸一化解決了輸入的混亂後,那在傳播中不會出現任何問題了嗎?”

答案當然是否定的,我們在之前的RMSprop和權重初始化部分也提到過下面這種現象:
在傳播過程中隨着訓練進行:

  • 前一層的權重不斷更新
  • 這一層的輸出分佈不斷改變
  • 下一層看到的“輸入分佈”也在不斷漂移
    這次就來給這種現象專門下一個定義,這種現象被稱為:內部協變量偏移(Internal Covariate Shift,ICS)
    即:隨着訓練進行,每一層的輸入分佈不斷變化。

我們舉一個實例:
假設現在有一個兩層的神經網絡,它的傳播是這樣的:

輸入 → 第 1 層 → a¹ → 第 2 層

很明顯,第 2 層把 當作“輸入”。
現在,我們簡單設定一次訓練過程如下:

階段 第 1 層權重狀態 a¹(第 1 層輸出)的分佈變化 對第 2 層的影響
第一次迭代 權重較小 均值 ≈ 0 ; 方差 ≈ 1 ; ReLU 截斷部分為 0 輸入分佈正常、穩定
訓練若干輪後 權重變大 整體被放大 ; 均值從 0 → 3 ; 方差從 1 → 10 ; 分佈向右漂移 輸入突然變大,“味道變了”
再訓練一段時間 權重更新向反方向變化 a¹ 又變小 ; 均值回到 0 附近 ; 方差變窄 ; 更多值被 ReLU 截成 0 輸入再次變化,第二層需重新適應

你會發現:前一層一更新,後一層的輸入分佈就跟着跳。
假如今天均值 0,明天均值 3,後天又掉回 0,那下一層永遠在“適應新分佈”,就會導致訓練不穩定、收斂變慢。
這就是內部協變量偏移現象。
我們再詳細展開區分一下。

1.3 輸入層的”混亂“和隱藏層的”混亂“

瞭解了內部協變量偏移後,你就會發現導致輸入層混亂和隱藏層混亂的原因並不一樣,我們總結如下:

位置 混亂的根本原因 產生機制 典型表現 解決方法
輸入層(原始數據) 量綱差距 不同特徵本身的單位、範圍差異過大,如 0.001 vs 1000 梯度被大尺度特徵主導,優化方向不準 輸入歸一化(標準化/MinMax)
隱藏層(傳播過程中) 內部協變量偏移 前一層權重每次更新 → 輸出分佈隨訓練不斷改變 輸入分佈一會兒大、一會兒小,下一層每輪都要重新適應 Batch Normalization(BN)

現在,我們希望:隱藏層也像輸入數據一樣保持穩定的分佈,不要每訓練一個 batch,分佈就偏移。
這就是 Batch Normalization 被提出的原因。

2. Batch 歸一化的步驟

既然我們已經知道隱藏層混亂的根源是 內部協變量偏移(ICS),那麼解決方式就非常自然了:
既然輸入層靠歸一化穩定了輸入特徵分佈,那隱藏層是否也能對自己的“輸入”——也就是 \(z\)——進行歸一化?
這就是BN 的核心思想:對每一層的 \(z\) 做歸一化,使分佈保持穩定
在一層網絡的前向傳播中,我們計算:

\[z = W·x + b \]

\[a = f(z) \]

而隱藏層真正的“輸入”是 \(z\),而不是原始輸入 \(x\)
因此 BN 會在激活函數 \(a\) 之前,對 \(z\) 進行“batch 內歸一化”。
流程如下:

z → 歸一化後的 ẑ → 激活函數 → a

現在,我相信你有一個小問題:

2.1 為什麼對 \(z\) 做歸一化而不是激活後的 \(a\) ?

你會發現,要是按照輸入層的邏輯,那經過激活函數後的 \(a\) 不才是下一層的輸入嗎?為什麼我們反而選擇了更靠前的 \(z\) 來進行歸一化?
實際上,激活函數(如 ReLU、sigmoid、tanh)會對分佈進行非線性變換:

  • ReLU 截斷負值
  • Sigmoid 壓縮到 0~1
  • tanh 壓縮到 -1~1
    如果在 \(a\) 上歸一化,分佈可能已經被截斷或拉伸,歸一化效果不穩定
    而對 \(z\) 歸一化,可以在激活函數之前就穩定每一層的輸入分佈。

這麼説不太清晰,我們來看下面這個實例:
假設某一層神經網絡的線性輸出 \(z\) 和激活輸出 \(a\) 如下:
對某個 batch,第一個神經元的 \(z\) 值範圍大致為:

樣本 \(z\)
1 -2
2 0.5
3 1.5
4 3

激活函數採用 ReLU,則 \(a = f(z) = \max(0, z)\)

樣本 \(a\)
1 0
2 0.5
3 1.5
4 3

現在考慮歸一化:

(1) 在 \(a\) 上歸一化

  • 均值 \(\mu_a = (0+0.5+1.5+3)/4 = 1.25\)
  • 方差 \(\sigma_a^2 = [(0-1.25)^2 + (0.5-1.25)^2 + (1.5-1.25)^2 + (3-1.25)^2]/4 = 1.4375\)

歸一化後:

\[\hat{a}_i = \frac{a_i - \mu_a}{\sqrt{\sigma_a^2 + \epsilon}} \]

結果:

樣本 \(\hat{a}_i\)
1 -1.04
2 -0.63
3 0.21
4 1.46

好像沒什麼不對,但是注意:樣本 1 的負值對應原本被 ReLU 截斷的 0
這樣歸一化會產生負數,實際上 破壞了 ReLU 的非負性特性,而且分佈已經被截斷過,歸一化效果不穩定。

(2) 在 \(z\) 上歸一化

  • 均值 \(\mu_z = (-2+0.5+1.5+3)/4 = 0.75\)
  • 方差 \(\sigma_z^2 = [(-2-0.75)^2 + (0.5-0.75)^2 + (1.5-0.75)^2 + (3-0.75)^2]/4 = 3.1875\)
    歸一化後:
樣本 \(\hat{z}_i\)
1 -1.57
2 -0.14
3 0.42
4 1.28

然後再經過 ReLU 激活:

樣本 \(a_i = \max(0, \hat{z}_i)\)
1 0
2 0
3 0.42
4 1.28

這次,歸一化是在 未被截斷的原始分佈 z 上進行,保持了統計特性,激活函數再作用不會破壞歸一化效果,從而穩定下一層輸入分佈。
這就是 BN 選擇對 \(z\) 而非 \(a\) 歸一化的直觀原因。
現在就來看看它的具體步驟。

2.2 步驟一:對當前 batch 的 \(z\) 做均值與方差歸一化

對一個 batch 中每一維特徵 \(j\),BN 首先計算 均值方差

\[\mu_j = \frac{1}{m} \sum_{i=1}^{m} z_{i,j} \]

其中,\(z_{i,j}\) 就是\(i\) 個樣本在第 \(j\) 個神經元的線性輸出

\[\sigma_j^2 = \frac{1}{m} \sum_{i=1}^{m} (z_{i,j} - \mu_j)^2 \]

這些公式我們都不陌生,現在我們進行歸一化:

\[\hat{z}_{i,j} = \frac{z_{i,j} - \mu_j}{\sqrt{\sigma_j^2 + \epsilon}} \]

同樣這裏的 \(\epsilon\) 是一個很小的數,用於防止分母為 0。

  • 經過這一步,每一層輸入 \(z\) 的分佈被強制變為 均值 0,方差 1
  • 下一層就不必再每天適應漂移的輸入分佈

可是這時又會出現一些新的問題:
我們把每層輸出都變成均值 0、方差 1 了,那原來大的還是大、小的還是小的這種差別不就沒了?
比如我房價模型前一層算出來的結果本來是幾百萬,現在突然全變成 0.x、1.x 這種小數字——這不把信息壓扁了嗎?
BN 的標準化就像把所有輸入“洗白”一遍,讓它們都變成整整齊齊的統一格式。
可麻煩就在這:有些重要的特徵確實需要保留原本的大數值尺度。
為了不讓網絡被限制住,設計者在 BN 之後又貼心地加了兩個調節旋鈕:

  • 一個讓它可以重新把輸出“放大或縮小”(γ)
  • 一個讓它可以把分佈“往上或往下挪動”(β)

這樣網絡就能在“被清洗乾淨”後重新找回它想要的表達方式。
這就是下一步——γ 和 β 的由來。

2.3 步驟二:引入可學習的縮放和平移(γ, β)

你可能會想:BN 把每一層的輸出都強制歸一化,難道不是把數值壓扁了嗎?比如預測房價,原本幾百萬的輸出可能被縮到 -1~1。

為了避免這種情況,BN 引入了 γ(scale)β(shift) 這兩個“調節閥”:

  • γ(scale):負責把歸一化後的值按需要放大或縮小
    • 默認值 1,初始不放大也不縮小
  • β(shift):負責把均值移動到合適的位置
    • 默認值 0,初始不平移
      公式如下:

\[z_{i,j}^\text{BN} = \gamma_j \hat{z}_{i,j} + \beta_j \]

這裏 \(\hat{z}_{i,j}\) 是歸一化後、零均值單位方差的值,γ、β 會把它調整到網絡需要的尺度。
要強調一點,我們可以手動設置 γ 和 β 的初始值。
但在實際運行中,每一層的γ 和 β 會和權重,偏置一樣在反向傳播中更新,通過梯度下降不斷調整,讓網絡學會最合適的縮放和偏移。
最終:

  • γ 學會放大或縮小歸一化後的 z,使輸出幅度適合網絡
  • β 學會平移分佈,使輸出均值符合任務需求

好像有些模糊,我們通過一個實例來演示一下。

2.4 加入 BN 後的一次傳播實例

為了更直觀地理解 BN 的實際作用,我們用一個例子來展示一次完整的前向傳播。
假設現在有一層神經網絡,它的線性輸出 \(z = Wx + b\) 對某個 batch 的 4 個樣本分別是:

樣本 \(z\)
1 -2
2 0
3 2
4 6

下面我們逐步演示加入BN後的一次傳播中每一環節。

(1) 計算 batch 內的均值與方差

先算均值:

\[\mu = (-2 + 0 + 2 + 6)/4 = 1.5 \]

再算方差:

\[\sigma^2 = \frac{(-2-1.5)^2 + (0-1.5)^2 + (2-1.5)^2 + (6-1.5)^2}{4} \]

計算過程如下:

樣本 \(z_i\) \(z_i - \mu\) \((z_i - \mu)^2\)
1 -2 -3.5 12.25
2 0 -1.5 2.25
3 2 0.5 0.25
4 6 4.5 20.25

方差:

\[\sigma^2 = \frac{12.25+2.25+0.25+20.25}{4}=8.25 \]

(1)對 z 做歸一化

再看一下歸一化公式:

\[\hat{z}_i = \frac{z_i - \mu}{\sqrt{\sigma^2 + \epsilon}} \]

為了演示,我們暫時忽略 \(\epsilon\),一來它只是為了防止除0而存在,二來它的量級過小,幾乎不會有影響。

\[\sqrt{8.25} \approx 2.872 \]

於是:

樣本 歸一化後 \(\hat{z}_i\)
1 -3.5 / 2.872 ≈ -1.22
2 -1.5 / 2.872 ≈ -0.52
3 0.5 / 2.872 ≈ 0.17
4 4.5 / 2.872 ≈ 1.57

到這裏,已經符合 BN 的目標:

  • 均值 = 0
  • 方差 = 1
    但如此一來,不同神經元之間的差異是否被壓扁了?
    這就是 γ 和 β 的作用要登場了。

(3)用 γ、β 調整回網絡想要的尺度

再次更新BN的輸出公式 :

\[z_i^\text{BN} = \gamma \hat{z}_i + \beta \]

現在假設當前這一層的初始參數為:

  • \(\gamma = 2\)
  • \(\beta = 1\)

再次強調,我們我們可以手動設置 γ 和 β 的初始值,這裏是為了展示效果。
但在實際訓練中,我們通常會用默認的1和0,因為它們會在訓練中自動更新成更合適的數值,我們很難提前探知這個“合適的值”,這也是深度學習模型解釋性弱的體現之一。

繼續計算:

樣本 \(\hat{z}_i\) \(z^\text{BN}_i = 2\hat{z}_i + 1\)
1 -1.22 2×(-1.22)+1 = -1.44
2 -0.52 2×(-0.52)+1 = -0.04
3 0.17 2×0.17 + 1 = 1.34
4 1.57 2×1.57 + 1 = 4.14

現在你就會看到:

  • BN 讓分佈穩定
  • γ=2 把幅度又放大回去了
  • β=1 把整體分佈抬高了

網絡依然可以學習到它想要的 z 大小,信息沒有丟失。

(4) 通過激活函數(例:ReLU)

激活函數:

\[a_i = \max(0, z_i^\text{BN}) \]

得到最終輸出:

樣本 \(z_i^\text{BN}\) 激活後 \(a_i\)
1 -1.44 0
2 -0.04 0
3 1.34 1.34
4 4.14 4.14

這便是一個完整流程,把BN加入了線性組合後,通過激活函數之間,來實現批次間的歸一化。

2.5 γ 與 β ,權重與偏置

再補充一個小問題,我們剛剛説通過γ 和 β,網絡依然可以學習到它想要的 z 大小,信息沒有丟失。
可是權重和偏置不也能實現這樣的效果嗎?一個是“幅度”,一個是“平移”,在下一層的線性組合部分不也能進行控制嗎?
所以,真的有必要在反向傳播中增加兩個需要更新的新參數嗎?

答案當然是有必要,我們先説結論:γ 與 β是為了解決權重調整和歸一化調整的衝突性。
現在開始展開:
假設沒有γ和β, BN 每次都會把上一層輸出 \(z\) 強制洗白成:

  • 均值 = 0
  • 方差 = 1
    無論 W 和 b 怎麼把 \(z\) 拉大、壓小、平移、拉偏,
    只要經過 BN,這些尺度和偏移統統都會壓扁。
    因此:
    想只通過 W 和 b 表達“幅度”和“偏移”是不可能的,因為 BN 下一秒就洗掉;
    只有 γ β 能在 BN 之後重新加回來,不會被覆蓋。

繼續展開:如果網絡沒有 γ β,它為了恢復想要的幅度/偏移,只能瘋狂調 W 和 b:

  • W 變大 → BN 歸一化沖掉
  • W 再變更大 → BN 再衝掉
  • …無限循環……
    這會導致:
  • 訓練更慢、更亂
  • 參數量級越變越大卻完全沒意義

這就是兩個參數存在的意義:
BN 會把每層輸出強行標準化(均值 0、方差 1),所以想表達“幅度”和“偏移”的權利不能放在 W 和 b 上(會被洗掉),必須交給 γ 和 β,它們是 BN 後唯一真正能保留這種表達能力的參數。

我們還是用做菜打個比方:
W,b 決定特徵的組合結構———“做什麼菜”;
BN 歸一化————“菜量,調味料量統一”;
γ,β ————“統一大份還是小份,重口味還是清口味” ;
在一次次迭代中,γ,β 就會訓練成讓菜最美味的規格。
Pasted image 20251117110728

簡單來説,結構歸 W,b,量級歸 γ,β,各司其職,不衝突也不重複。

3. BN 的作用和使用中的注意事項

3.1 BN 的作用

(1)加速訓練

BN 會把每層的輸入都“洗白”成 均值 0、方差 1
這會讓網絡的每一層都在比較“乾淨、統一”的數值範圍裏工作:

  • 梯度不會忽大忽小
  • 不容易梯度爆炸 / 消失
  • 學習率可以設得更大膽
  • 收斂更快
    一句話: BN = 把數據洗乾淨 → 每層都更好訓練

(2)一定程度的正則化效果

BN 的 mini-batch 統計量每次都來自當前 batch,因此帶有輕微隨機性:

  • 每個 batch 的均值和方差略有不同
  • 相當於給網絡輸出加了一點噪聲
    這種噪聲會讓網絡不再過度依賴某個固定模式,從而降低過擬合風險

好像不太清晰,再來看一個示例:
假設你訓練一個圖片分類網絡,每次輸入 batch 大小為 32 張圖片:

  1. BN 會計算 32 張圖的平均值和方差,歸一化每個特徵
  2. 下一層看到的特徵略有變化,因為 batch 內的統計量不同, 比如上一批 \(\mu_\text{batch}=120\),下一批 \(\mu_\text{batch}=118\)同一個像素歸一化後的值會變化。差值雖小,但對網絡來説是一種輕微的“擾動”。
  3. 因此,網絡不會只記住某個固定數值,而是學會適應“小幅波動”
  4. 訓練過程中,相當於每次都給網絡做了微小擾動 → 起到正則化效果

注意:BN 不是 dropout 或 weight decay 的替代,它只是順帶有一點正則化效果。

3.2 注意事項:訓練和測試中的 BN

不同於我們之前介紹的其他方法,BN 在訓練和測試階段的行為略有不同。

(1)訓練階段

我們已經知道, 在訓練中,BN會使用當前 batch 的均值和方差來進行歸一化。
但實際上,BN 還會同時維護一個通過EMA更新 全局均值(moving mean)和全局方差(moving variance)

\[\mu_\text{moving} = \alpha \cdot \mu_\text{moving} + (1-\alpha) \cdot \mu_\text{batch} \]

\[ \sigma^2_\text{moving} = \alpha \cdot \sigma^2_\text{moving} + (1-\alpha) \cdot \sigma^2_\text{batch} \]

這裏 \(\alpha\) 一般接近 0.9–0.99。
為什麼這兩個量之前都沒有出現過?他們又是幹什麼的?
因為這兩個全局統計量用於測試階段的歸一化。

(2)測試階段

測試時,一般 一次只輸入一個樣本,或者 batch 太小,無法可靠統計均值方差,這就會導致BN反而可能降低最終的測試指標。
於是就出現了一個問題:測試時樣本可能和訓練 batch 分佈不同,就像我們之前説的小批次帶來波動性,這時在測試中應用BN反而阻礙擬合,但我們希望保持穩定輸出。
因此 BN 不再使用當前 batch 統計量,而是使用訓練階段維護的移動平均,這裏就用到了我們在訓練階段維護的全局均值和全局方差 :

\[\hat{z}_i = \frac{z_i - \mu_\text{moving}}{\sqrt{\sigma^2_\text{moving} + \epsilon}} \]

\[z_i^\text{BN} = \gamma \hat{z}_i + \beta \]

就像直接把訓練數據的模板套到測試中,不再用測試的數據進行歸一化。這樣,使用全局統計量可以確保預測一致性和穩定性。
總的來説,就是訓練階段用 batch 統計量保證穩定和輕微正則化,測試階段用全局均值方差保證預測一致性。

4.“人話版”總結

概念 原理 比喻
輸入歸一化 對原始特徵做標準化(均值0,方差1或縮放到0~1),防止不同特徵尺度差異過大影響訓練 給不同食材“統一切成小塊”,保證每樣菜量可控,不搶味道
內部協變量偏移 (ICS) 隨着前一層權重更新,每層輸入分佈不斷漂移,導致訓練不穩定 菜做一半調味料改變,下一步廚師得重新適應味道,效率變慢
Batch Normalization (BN) 對每層線性輸出 (z = Wx+b) 在 batch 內做歸一化,保持均值0、方差1,減小 ICS 影響 廚師在每次下鍋前,把食材量和調味量統一標準化,保證每道菜味道穩定
歸一化前選擇 (z) 而非 (a) 激活函數會非線性截斷或壓縮分佈,歸一化在 (z) 上更穩定 把食材原料量統一,而不是煮熟後的菜,煮熟後可能大小不一
γ(scale)和 β(shift) BN 後可學習的縮放和平移參數,恢復輸出幅度和均值 “統一菜量後,再決定大份小份、重口味還是清口味”
訓練階段 BN 使用當前 batch 的均值和方差歸一化,同時更新全局移動平均統計量 廚師嘗試每鍋菜略有不同,但記錄總體平均味道
測試階段 BN 使用訓練階段的全局均值和方差歸一化,不用當前 batch 統計量,保證輸出穩定 按照訓練時記錄的標準味道做菜,不因單鍋差異影響味道
作用 1. 加速訓練(梯度穩定,可用更大學習率)2. 提供輕微正則化(batch 內統計波動) 把廚房每個步驟標準化,菜做得快又穩;偶爾小變動讓廚師不死板
注意事項 BN 不是 Dropout 替代,γ/β 必須單獨更新,訓練與測試策略不同 廚師要同時管理食材量標準化和調味偏好,訓練時可微調,測試時按固定標準
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.