數學 · 神經網路(四)· Normalize

我們在Python · 神經網路(三*)· 網路這裡曾經介紹過附加層(特殊層)SubLayer的概念,這一章我們則會較為詳細地介紹一下十分常用的 SubLayer 之一——Normalize(當然直接看原 paper 是最好的,因為我雖然一直在用這玩意兒但真的很難說有深刻的理解…… ( σω)σ)

Normalize 這個特殊層結構的學名叫 Batch Normalization、常簡稱為 BN,顧名思義,它用於對每個 Batch對應的數據進行規範化處理。這樣做的意義是直觀的:對於 NN、CNN 乃至任何機器學習分類器來說,其目的可以說都是從訓練樣本集中學出樣本在樣本空間中的分布、從而可以用這個分布來預測未知數據所屬的類別。如果不對每個 Batch 的數據進行任何操作的話,不難想像它們彼此對應的「極大似然分布(極大似然估計意義下的分布)」是各不相同的(因為訓練集只是樣本空間中的一個小抽樣、而 Batch 又只是訓練集的一個小抽樣);這樣的話,分類器在接受每個 Batch 時都要學習一個新的分布、然後最後還要嘗試從這些分布中總結出樣本空間的總分布,這無疑是相當困難的。如果存在一種規範化處理方法能夠使每個 Batch 的分布都貼近真實分布的話、對分類器的訓練來說無疑是至關重要的

傳統的做法是對輸入X進行第歸一化處理、亦即:

X=frac{X-bar X}{std(X)}

其中bar X表示X的均值、std(X)表示X的標準差(Standard Deviation)。這種做法雖然能保證輸入數據的質量、但是卻無法保證 NN 裡面中間層輸出數據的質量。試想 NN 中的第一個隱藏層L_2,它接收的輸入u^{(2)}是輸入層L_1的輸出v^{(1)}=phi_1left( u^{(1)}right)和權值矩陣w^{(1)}相乘後、加上偏置量b^{(1)}後的結果;在訓練過程中,雖然v^{(1)}的質量有保證,但由於w^{(1)}b^{(1)}在訓練過程中會不斷地被更新、所以u^{(2)}=v^{(1)}times w^{(1)}+b^{(1)}的分布其實仍然不斷在變。換句話說、u^{(2)}的質量其實就已經沒有保證了nn

BN 打算解決的正是隨著前向傳導演算法的推進、得到的數據的質量會不斷變差的問題,它能通過對中間層數據進行某種規範化處理以達到類似對輸入歸一化處理的效果。換句話說,Normalize 的核心思想正在於如何把父層的輸出進行某種「歸一化」處理,下面我們就簡單看看它具體是怎麼做到這一點的。

nn

首先需要指出的是,簡單地將每層得到的數據進行上述歸一化操作顯然是不可行的、因為這樣會破壞掉每層自身學到的數據特徵。設想如果某一層L_i學到了「數據基本都分布在樣本空間的邊緣」這一特徵,這時如果強行做歸一化處理並把數據都中心化的話、無疑就擯棄了L_i所學到的、可能是非常有價值的知識

nn為了使得中心化之後不破壞 Layer 本身學到的特徵、BN 採取了一個簡單卻十分有效的方法:引入兩個可以學習的「重構參數」以期望能夠從中心化的數據重構出 Layer 本身學到的特徵。具體而言:

  • 輸入:某一層L_i在當前 Batch 上的輸出v^{(i)}、增強數值穩定性所用的小值epsilon
  • 過程
    • 計算當前 Batch 的均值、方差:

      mu_i=bar{v^{(i)}},  sigma_i^2=[ text{std}left( v^{(i)}right)]^2

    • 歸一化:

      hat{v^{(i)}}=frac{v^{(i)}-mu_i}{sqrt{sigma_i^2+epsilon}}

    • 線性變換:

      y^{(i)}=gammahat{v^{(i)}}+beta

  • 輸出:規範化處理後的輸出y^{(i)}

BN 的核心即在於gammabeta這兩個參數的應用上。關於如何利用反向傳播演算法來更新這兩個參數的數學推導會稍顯繁複、我們就不展開敘述了,取而代之、我們會直接利用 Tensorflow 來進行相關的實現

nn需要指出的是、對於演算法中均值和方差的計算其實還有一個被廣泛使用的小技巧,該小技巧某種意義上可以說是用到了「動量」的思想:我們會分別維護兩個儲存「運行均值(Running Mean)」和「運行方差(Running Variance)」的變數。具體而言:

  • 輸入:某一層L_i在當前 Batch 上的輸出v^{(i)}、增強數值穩定性所用的小值epsilon,動量值m(一般取m=0.9
  • 過程

    首先要初始化 Running Mean、Running Variance 為 0 向量:

    mu_{run}=sigma_{run}^2=bold 0

    並初始化gammabeta為 1、0 向量:

    gamma = bold 1,  beta=bold 0

    然後進行如下操作:

    • 計算當前 Batch 的均值、方差:

      mu_i=bar{v^{(i)}},  sigma_i^2=[ text{std}left( v^{(i)}right)]^2

    • 利用mu_isigma_i^2和動量值m更新mu_{run}sigma_{run}^2

      mu_{run}leftarrow mcdotmu_{run}+(1-m)cdotmu_i

      sigma_{run}^2leftarrow mcdot sigma_{run}^2+(1-m)cdotsigma_i^2

    • 利用mu_{run}sigma_{run}^2規範化處理輸出:

      hat{v^{(i)}}=frac{v^{(i)}-mu_{run}}{sqrt{sigma_{run}^2+epsilon}}

    • 線性變換:

      y^{(i)}=gammahat{v^{(i)}}+beta

  • 輸出:規範化處理後的輸出y^{(i)}

最後提三點使用 Normalize 時需要注意的事項:

nn

  • 無論是哪種演算法、BN 的訓練過程和預測過程的表現都是不同的。具體而言,訓練過程和演算法中所敘述的一致、均值和方差都是根據當前 Batch 來計算的;但測試過程中的均值和方差不能根據當前 Batch 來計算、而應該根據訓練樣本集的某些特徵來進行計算。對於上面第二種演算法來說,mu_{run}sigma_{run}^2天然就是很好的、可以用來當測試過程中的均值和方差的變數,對於第一種演算法而言就需要額外的計算(別問我怎麼進行額外的計算,我不會……)
  • 對於 Normalize 這個特殊層結構來說、偏置量是一個冗餘的變數;這是因為規範化操作(去均值)本身會將偏置量的影響抹去、同時 BN 本身的beta參數可以說正是破壞對稱性的參數,它能比較好地完成原本偏置量所做的工作
  • Normalize 這個層結構是可以加在許多不同地方的(如下圖所示的 A、B 和 C 處),原論文將它加在了 A 處、但其實現在很多主流的深層 CNN 結構都將它加在了 C 處;相對而言、加在 B 處的做法則會少一些:

Normalize 的相關實現會在 CNN 系列的文章裡面進行說明(具體而言是這篇文章),敬請期待 ( σω)σ

希望觀眾老爺們能夠喜歡~


推薦閱讀:

神經網路與TensorFlow實踐-前言
C++實現神經網路之一 | Net類的設計和神經網路的初始化
Faster R-CNN
簡單易懂的自動編碼器
人工智慧vs人類智能小傳——再議阿爾法狗

TAG:数学 | 机器学习 | 神经网络 |