爲何要零均值化?python
人們對圖像信息的攝取一般不是來自於像素色值的高低,而是來自於像素之間的相對色差。零均值化並無消除像素之間的相對差別(交流信息),僅僅是去掉了直流信息的影響。web
數據有過大的均值也可能致使參數的梯度過大。網絡
若是有後續的處理,可能要求數據零均值,好比PCA。dom
假設數據存放在一個矩陣 X 中,X 的形狀爲(N,D),N 是樣本個數,D 是樣本維度,零均值化操做可用 python 的 numpy 來實現:
函數
X -= numpy.mean(X, axis=0)
即 X 的每一列都減去該列的均值。學習
對於灰度圖像,也能夠減去整張圖片的均值:
優化
X -= numpy.mean(X)
對於彩色圖像,將以上操做在3個顏色通道內分別進行便可。spa
爲何要歸一化?code
歸一化是爲了讓不一樣緯度的數據具備相同的分佈規模。orm
假如二維數據數據(x1,x2)兩個維度都服從均值爲零的正態分佈,可是x1方差爲100,x2方差爲1。能夠想像對(x1,x2)進行隨機採樣並在而爲座標系中標記後的圖像,應該是一個很是狹長的橢圓形。
對這些數據作特徵提取會用到如下形式的表達式:
S = w1*x1 + w2*x2 + b
那麼:
dS / dw1 = x1
dS / dw2 = x2
因爲x1與x2在分佈規模上的巨大差別,w1與w2的導數也會差別巨大。此時繪製目標函數(不是S)的曲面圖,就像一個深邃的峽谷,沿着峽谷方向變化的是w2,坡度很小;在峽谷垂直方向變化的是w1,坡度很是陡峭。
由於咱們指望的目標函數是這樣的:
而如今的目標函數多是這樣的:
咱們知道這樣的目標函數是很是難以優化的。由於w1與w2的梯度差別太大,在兩個維度上須要不一樣的迭代方案。可是在實際操做中,爲了簡便,咱們一般爲全部維度設置相同的步長,隨着迭代的進行,步長的縮減在不一樣維度間也是同步的。這就要求W不一樣維度的分佈規模大體相同,而這一切都始於數據的歸一化。
一個典型的歸一化實現:
X /= numpy.std(X, axis = 0)
在天然圖像上進行訓練時,能夠不進行歸一化操做,由於(理論上)圖像任一部分的統計性質都應該和其它部分相同,圖像的這種特性被稱做平穩性(stationarity)。(注意是同分布,不是獨立同分布)
白化至關於在零均值化與歸一化操做之間插入一個旋轉操做,將數據投影在主軸上。一張圖片在通過白化後,能夠認爲各個像素之間是統計獨立的。
然而白化不多在卷積神經網絡中使用。我猜想是由於圖像信息原本就是依靠像素之間的相對差別來體現的,白化讓像素間去相關,讓這種差別變得不肯定,抹掉了不少信息。
大型模型每每須要大量數據來訓練。一些數據擴充方法所以被髮明出來,以天然圖像爲例:
能夠對圖片作水平翻轉、進行必定程度的位移或者剪裁,還能夠對它的顏色作必定程度的調整。在不改變圖像類別的狀況下,增長數據量,還能提升模型的泛化能力。
不要將參數所有初始化爲零。
幾乎全部的CNN網絡都是對稱結構,將參數零初始化會致使流過網絡的數據也是對稱的(都是零),而且沒有辦法在不受擾動的狀況下打破這種數據對稱,從而致使網絡沒法學習。
打破對稱性的思路很簡單,給每一個參數隨機賦予一個接近零的值就行了:
W = 0.01* numpy.random.randn(D,H)
randn 方法生成一個均值爲零,方差爲1的服從正態分佈的隨機數。
把 W 應用到以前的表達式 S ,S 就是多個隨機變量的加權和。獨立隨機變量和的方差爲:
Var(A+B+C) = Var(A)+Var(B)+Var(C)
假設 W 各元素之間相互獨立,隨着數據維度的增加,S 的方差將會線性累積。根據任務的不一樣,數據的維度從小到大跨度很是大,是不可控的,因此咱們但願將 S 的方差作歸一化,這隻須要對 W 動動手腳就能夠了:
W = numpy.random.randn(n) / sqrt(n)
其中 n 就是數據的維度。
推導過程以下:
令 n*Var(W) = 1,就獲得 std(W) = 1 / sqrt(n)。
在實際使用中,若是結合 ReLU,這篇文章推薦:
w = numpy.random.randn(n) * sqrt(2.0/n)
激活函數用於在模型中引入非線性。
sigmoid 與 tanh 曾經很流行,但如今不多用於視覺模型了,主要緣由在於當輸入的絕對值較大時,其導數接近於零,梯度的反向傳播過程將被中斷,出現梯度消散的現象。
ReLU 是一個很好的替代:
相比於 sigmoid 與 tanh,它有兩個優點:
沒有飽和問題,大大緩解了梯度消散的現象,加快了收斂速度。
實現起來很是簡單,加速了計算過程。
ReLU 有一個缺陷,就是它可能會永遠「死」掉:
假若有一組二維數據 X(x1, x2)分佈在 x1:[0,1], x2:[0,1] 的區域內,有一組參數 W(w1, w2)對 X 作線性變換,並將結果輸入到 ReLU。
F = w1*x1 + w2*x2
若是 w1 = w2 = -1,那麼不管 X 如何取值,F 必然小於等於零。那麼 ReLU 函數對 F 的導數將永遠爲零。這個 ReLU 節點將永遠不參與整個模型的學習過程。
形成上述現象的緣由是 ReLU 在負區間的導數爲零,爲了解決這一問題,人們發明了 Leaky ReLU, Parametric ReLU, Randomized ReLU 等變體。他們的中心思想都是爲 ReLU 函數在負區間賦予必定的斜率,從而讓其導數不爲零(這裏設斜率爲 alpha)。
Leaky ReLU 就是直接給 alpha 指定一個值,整個模型都用這個斜率:
Parametric ReLU 將 alpha 做爲一個參數,經過學習獲取它的最優值。Randomized ReLU 爲 alpha 規定一個區間,而後在區間內隨機選取 alpha 的值。
在實踐中, Parametric ReLU 和 Randomized ReLU 都是可取的。
僅僅理解 CNN 的結構是不夠的,在實踐中,特別是訓練大規模網絡的時候,有不少技巧性或經驗性的細節。不只要會用它們,更要理解這些技巧背後的規律。我認爲合理的學習過程是:
實踐-》總結-》再實踐 循環往復
一開始看不懂論文,能夠利用一些公開課或者教程,理解基本概念,並跟隨教程完整的實現一些簡單模型,找到最初始也是最重要的感受。
而後總結在該領域內的一些最佳實踐,並理解爲何這麼作,漸漸對該領域造成體系化的認識。
在有了體系化的理解以後,你發現你有了觸類旁通的能力,能夠嘗試實現更復雜的模型,以印證本身的想法。還能夠去閱讀專業人士的論文,鞏固和完善本身的認知體系。
此時你已經熬過了最痛苦的積累期,具備了創造的能力。關於CNN的細節,我還會再作補充討論。