1. 程式人生 > >從0到1:神經網路實現影象識別(中)

從0到1:神經網路實現影象識別(中)

”. . .  we may have knowledge of the past and cannot control it; we may control the future but have no knowledge of it.” — Claude Shannon 1959

往者可知然不可諫,來者可追或未可知

 

上篇介紹了神經網路的理論基石 - 感知機(perceptron)模型;感知機模型是一個簡潔的二類分類模型,在中篇裡,我們把它推廣到多類分類問題,不借助計算框架,構建一個全連線神經網路,再應用於MNIST資料集手寫數字識別場景。

 

MNIST資料集

能正確的提出問題,你已經解決了問題的一半。

這裡“正確的問題”是MNIST,一個手寫數字圖片集資料的識別問題。

你可以在 Yann LeCun的官網下載這套資料集,共四個檔案包:

train-images-idx3-ubyte.gz:  訓練圖片集 (9912422 bytes)  

train-labels-idx1-ubyte.gz: 訓練圖片集的正確標籤 (28881 bytes) 

t10k-images-idx3-ubyte.gz:   測試圖片 (1648877 

bytes) t10k-labels-idx1-ubyte.gz:   測試圖片的正確標籤  (4542 bytes)

每張圖片包含一個手寫數字。

資料集包含6萬張圖片用於訓練,1萬張用於測試驗證。

 

影象資料格式和圖向量

每張圖片表達了[0,9]這是10個數字中的一個,有28X28=784個畫素,每個畫素根據灰度取整數值[0,255];把每張圖片看作具有784個特徵的圖向量,問題就變成:根據D個特徵維度,對影象做K分類的問題,這裡D=784,K=10。

 

從二分類到多分類問題

一種思路是把 K 類分類問題,視為 K 個二類分類問題:第一次,把樣本資料集的某一個類別,和餘下的K-1類(合併成一個大類)做二類分類劃分,識別出某一類;第 i 次,劃分第i類和餘下的K-i類;經過 K 次 二類分類迭代,最終完成 K 類分類。

 

這裡,我們選用一種更直接的思路,回憶感知機二類分類模型,只包含了一個輸出節點;現在把輸出節點擴充套件為K個 ;權值向量w擴充套件為 D x K的權值矩陣W,偏置(bias) b擴充套件為長度為K的陣列;這樣一來,一個樣本點經過模型處理,會得到這個樣本點在所有K個類別上的歸類可能性得分 z。

\displaystyle p_j = softmax ( z_j ) = \frac {e^{z_j}}{\sum _{k=1}^Ke^{z_k}}

z同樣是長度為K的陣列,某一個元素z [j]的數值越大,輸入樣本點屬於對應分類類別j的可能性也越高。

 

Softmax

Softmax方法,用於把輸出z進一步標準化(normalize),得到某個樣本點,歸屬於各個類別的概率分佈;

 

例如,歸屬於類別 j 的概率為:

\displaystyle H( p_{ \hat y},p ) = - \sum _{j=1}^{K} p_{\hat y_j} log(p_j)

這個結果滿足了概率分佈的標準化要求:在所有類別上的輸出概率都不小0,且所有類別上的輸出概率和等於1。

 

就得到了模型預測輸出結果的標準概率分佈。

 

對應的,目標問題MNIST資料集的正確標籤,也可以視為一個概率分佈;一張手寫數字圖片,在正確類別上的概率分佈視為1,其它類別上為0;數字9的圖片,所對應的正確標籤為(0,0,0,0,0,0,0,0,0,1),可視為放平之後的分類期望向量\({\hat {y}}\)。

 

有了預測輸出和正確答案的概率分佈,就可以刻畫兩者之間相似度,簡便地度量模型預測的損失。

 

損失函式-交叉熵

經過 Softmax 轉換為標準概率分佈的預測輸出p,與正確類別標籤\({\hat {y}}\)之間的損失,可以用兩個概率分佈的 交叉熵(cross entropy)來度量:

\displaystyle H( p_{ \hat y},p ) = - \sum _{j=1}^{K} p_{\hat y_j} log(p_j)

所以,某一樣本點使用模型預測的損失函式,可以寫為

\begin{split} Loss (\hat y) =& - \sum _{j=1}^{K} p_{\hat y_j} log(p_j) \\=& -log \ e^{z_j} + log\sum _{k=1}^Ke^{z_k} \end{split}\begin{split} Loss (\hat y) =& - \sum _{j=1}^{K} p_{\hat y_j} log(p_j) \\=& -log \ e^{z_j} + log\sum _{k=1}^Ke^{z_k} \end{split}

你可以跳過關於交叉熵的展開介紹,從學習演算法處繼續閱讀,不影響方法使用。

 

再深一點:關於交叉熵

1948年,Claude E Shannon首次提出資訊熵(Entropy)概念。

 

交叉熵(Cross Entropy)的概念來自資訊理論 :若離散事件以真實概率p(xi)分佈,則以隱概率q(xi)分佈對一系列隨機事件xi做最短編碼,所需要的平均位元(bits)長度。其中,定義q(xi)=1/2li,顯然,較短的編碼長度li,應當被用於出現頻度q(xi)較高的編碼片段,以提高傳輸效率。

直觀理解,如果有H(p,q')<H(p,q)   ,  則相對於qi,  概率分佈qi'同真實概率pi分佈 更相似。

 

交叉熵對兩個概率分佈的度量結果,不具對稱性,所以交叉熵並不是嚴格意義上的距離。

交叉熵概念的源頭,用位元(bits)資訊為單位,以2為底做對數計算,那麼用作損失函式Loss時,對數計算是否必須以2為底呢?

不是必須的。

機器學習領域,交叉熵被用來衡量兩個概率分佈的相似度,交叉熵越小,兩個概率分佈越相似。工程實踐中,出於簡化公式推導,或優化數值計算效率的考慮,對數的底可以做出其它選擇。

例舉以e為底的情況,由換底公式:

可知,對數的底由2換成e,對Loss的影響是,縮小了常數倍 log2e;上一次,我們提到,優化損失函式使損失極小的場景下,函式取值的數值縮放正倍數不影響優化方法。

所以損失函式也可以寫為:

學習演算法

用上一次介紹的方法,你可以先為 W, b 設定初始值,W隨機初始化為很小的值,b初始化為0;然後用梯度下降法( gradient descent),讓引數不斷更新梯度▽W 和▽b,來極小化損失函式。

對包含D維輸入特徵的K類分類樣例點,根據損失函式計算引數更新的梯度:

得到引數更新的梯度:

 

反向傳播(back propagation)

反向傳播(back propagation)是相對前向推斷(inference)過程而言的。

 

抽取訓練資料,得到預測分類結果,再使用訓練資料的正確標註,計算樣本預測損失,然後根據損失更新神經網路模型引數,這個迭代過程就是反向傳播方法。

 

工程實踐中,往往從訓練樣本集中,抽取一批(batch)訓練樣本,通過整批資料的矩陣運算,得到這批樣本損失的均值,減少更新梯度的次數提高訓練效率;每輪訓練後,使用該批次的梯度均值更新引數,較快得到接近梯度下降的收斂結果。

 

實現-第一個神經網路

上述演算法的python實現,不需要安裝Tensorflow計算框架,你可以從演算法實現層面,瞭解一個基礎的全連線神經網路的基本結構,跟蹤訓練過程:

在一千五百次引數更新迭代後,模型引數在驗證集上準確率超過90%,五千次迭代後,驗證資料集上預測損失(Loss)趨於穩定。

預測準確率(acc)也在驗證資料集上穩定在92%附近。

上述演算法,可以進一步通過正則化處理,來緩解過擬合風險,降低泛化誤差。

 

過擬合與正則化

在訓練資料集上,訓練迭代次數不足,模型沒有學到訓練樣本的一般特徵,稱為欠擬合(under-fitting);

 

反之,有大量引數的複雜模型,經過多輪訓練,會將訓練資料中,不具一般性的噪聲,也學習到模型引數裡,結果在訓練資料上得到很好的擬合表現,在未知資料上預測效果卻不好,這種情況稱為過擬合(Over-fitting)。

 

通過大量引數,在訓練資料上擬合複雜模型,可能很好地反映出訓練資料集上的細微特徵,也會包括不具一般性的樣本噪聲,過擬合為模型引入“偏見”,增加了模型的泛化誤差。

 

過擬合的緩解方法,是根據模型的複雜程度,增加罰項(penalty term),使模型的結構風險最小化。

總損失中增加的罰項部分,也稱為L2正則化項(regularizer),其中,入是根據模型複雜度設定的罰項係數;乘數0.5用於簡化計算;||w||是權值引數w的L2範數,計算方法參見上篇,學習策略部分的介紹。

 

你可以進一步瞭解正則化處理,也可以跳到”隱藏層“部分繼續閱讀,不影響正則化方法的使用。

 

再深一點:關於正則項

L2正則化的直觀效果是:含有相對大分量的權值引數 w,其罰項項也越大;各分量相對小而分散權值w,罰項也較小。

例如:

 

輸入向量 x = [1,1,1,1],和兩個權值向量  w1=[1,0,0,0], w2=[0.25,0.25,0.25,0.25]。

 

做內積運算後結果均為1;然而 W1的L2 罰項為1,W2由於各分量相對小而分散,罰項只有0.25。

L2正則化後的模型,傾向於均衡評估輸入樣本點上全部各個維度的特徵,而不是少數大分量值特徵對分類結果的影響,來提高模型在測試資料集上的泛化(generalization)能力,緩解過擬合風險。

 

偏置項 b 是否也需要做正則化處理呢?

 

不需要。

 

上面的例子可以看到:輸入樣本點各個維度特徵分量的數值特徵,影響了內積計算結果;而偏置 b, 既不參與內積計算,也不對特徵分量的數值特徵做倍數放大。所以實踐中通常只對權值引數 w 做正則化處理。

 

隱藏層(Hidden Layer)

感知機線性模型能很好的處理線性可分樣本點的類別劃分,卻無法處理如下非線性可分問題:

通過引入隱藏層,將模型去線性化,可使模型能處理非線性可分樣本的分類識別;

 

原始輸入,先經過隱藏層處理,再傳遞到輸出層;隱藏層中的節點,代表了從輸入特徵中抽取得到的更高層特徵。

 

把新增隱藏層中的節點看作神經元,這些神經元通過自身的啟用函式產生神經元輸出。

 

啟用函式

這裡使用ReLU(Rectified Linear Units)作為啟用函式,形式簡潔,有如下效果:

 

單側抑制,僅啟用輸出大於閾值0的訊號

寬闊的啟用邊界

稀疏的啟用性

 

隨著神經網路深度(隱藏層數)的增加,ReLU降低訊號的啟用率的作用愈加顯著,有助於重要特徵的高效提取。

 

從影象可以看到,ReLU函式不是處處可導的,但是反向傳播梯度仍然可以計算,接下來的演算法部分會介紹。

以上是ReLU和另一個常用啟用函式tanh的影象對比。

 

下面是不再常用的S型啟用函式和softplus啟用函式的影象。

 

演算法

由於總損失增加了正則化損失部分:

反向傳播時,權值矩陣W的也相應增加了正則化部分梯度:

增加了隱藏層之後,隱藏層的M個節點和輸入層節點之間,有了新的權值矩陣 W1和偏置b1;

隱藏層原始輸出Zh,啟用後表達程為h,作為下一層的輸入。

 

隱藏層到輸出層的引數仍然保留,名稱改為W2,b2,以方便對應。

隱藏層到輸出層引數梯度計算方法不變,以隱藏層輸出的M個元素陣列h,轉置為列向量後,作為輸入,

仍然採用交叉熵度量預測損失,W2, b2 反向傳播梯度,正則化後,成為:

對 W1, b1 仍然可以設定初始值,然後用梯度下降法( gradient descent),讓引數不斷更新梯度▽W1 和▽b1,來極小化損失函式。

 

首先,誤差損失 δ 反向傳播到隱藏層:

再看啟用函式 ReLU(x) =max(0,x),不是處處可導的,但是觀察函式性質,當輸出為負數時,經過ReLU之後被抑制,其梯度降為0;如果輸出為非負數,則導數為1,即誤差傳遞到此處是自變數x本身。

所以實際反向梯度▽h為

得到正則化後,引數更新的梯度:

得到反向傳播的全部引數更新梯度。

 

實現-加入隱藏層

上述演算法的python實現,不借助計算框架,在上一次全連線神經網路的基本結構上,增加了正則化處理,緩解過擬合問題,並添加了一個隱藏層,使模型能處理非線性可分特徵,進一步提高識別效果。

 

以下是設定單隱藏層500個隱藏層節點的訓練過程:

驗證集上識別正確率穩定在98以上%。

以上,介紹了具有一個隱藏層的全連線神經網路,隨著深度(隱藏層)增加,神經網路能在複雜的輸入樣本上提取更多的特徵,得以在一些資料集上,超過了人工識別準確率。

 

增加深度也帶來了新挑戰:連線節點和引數過多,導致反向傳播訓練效率降低,且增加了過擬合風險;下一次,將在目前網路結構的基礎上,引入卷積核(Convolutional kernel)處理,使之成為一個卷積神經網路(CNN), 通過進一步實踐,瞭解這一挑戰的應對方法。

 

(中篇完)

 

參考

[1]  斯坦福大學 class CS231n:The Stanford CS class CS231n

[2] de Boer, PT., Kroese, D.P., Mannor, S. et al. A Tutorial on the Cross-Entropy Method. Ann Oper Res (2005) 134: 19.