1. 程式人生 > >使用卷積神經網路進行圖片分類 3

使用卷積神經網路進行圖片分類 3

控制caffe模型的訓練過程

一、實驗介紹

1.1 實驗內容

上次實驗,我們已經構建好了卷積神經網路,我們的模型已經蓄勢待發,準備接受訓練了。為了控制訓練程序,記錄訓練過程中的各種資料,caffe還需要定義另一個solver.prototxt檔案,這次實驗我們就來完成它,並開始激動人心的訓練過程。

1.2 實驗知識點

  • 可變的學習速率
  • 正則化

1.3 實驗環境

  • caffe 1.0.0

二、實驗步驟

2.1 指定網路定義檔案

solver.prototxt中,我們需要先指定網路定義檔案的位置,我們通過下面的語句指定:

net: "network.prototxt"

2.2 可變的學習速率

在課程814中,有這麼一張圖:

此處輸入圖片的描述當學習速率固定時,每次引數更新的“步長”會慢慢變短。我將為什麼步長會變短作為一個選做課後作業留在了那裡,其實不難思考,因為學習速率固定,而損失函式圖形的“傾斜”程度一直在變小,即損失函式對引數的梯度的數值一直在變小,所以最後更新的“步長”會越來越短。

這個特性有利於我們的模型訓練過程,因為越接近損失函式最低點我們希望更新的步長越小,這樣才能使引數更逼近最低點。但為了保證每次更新的步長越來越小,也可以在訓練的過程中減小學習速率的數值,在solver.prototxt中可以像下面這樣定義:

base_lr: 0.001lr_policy: "step"stepsize: 4000gamma: 0.1max_iter: 10000

其中base_lr指定在開始訓練時的學習速率,這裡設定為0.001, lr_policy設定為stepstep_size設定為4000就指定了學習速率每隔4000次訓練週期(epoch)就自動減小。而gamma的數值就是每次減小學習速率時乘以的數值,這裡設定為0.1就代表每次將學習速率減小到原來的十分之一。

max_iter指定訓練的最大迭代週期數,這裡設定成10000次。

2.3 測試周期

在前一次實驗中,我們的測試資料層(phase設定為TEST的資料層)中的batch_size被設定成了100,而我們的測試資料總共有10000張圖片,為了每次測試將所有圖片都測試一次,這裡需要如下設定:

test_iter: 100test_interval:500

test_iter為100即測試的迭代次數為100次,這樣100x100等於10000,剛好把所有圖片都測試一次。

同時,這裡設定test_interval為500表明每訓練500個週期執行一次測試。

2.4 正則化

其實早在課程814中,我就非常想講解正則化,但是一直擔心一次性介紹太多內容會讓人難以消化,這裡我終於迎來了必須講解正則化的機會。為了理解正則化在深度學習中的作用,我們以迴歸問題為例講解。

此處輸入圖片的描述

如圖,假設我們現在要根據圖中的六個點擬合出資料的分佈曲線,用於預測其他x座標對應的y值,我們使用如下的多項式進行擬合:y=a0+a1*x+a2*x^2+a3*x^3+...

假如一開始,只有a0和a1不為0,其他係數a都為0,擬合函式就變成了:y=a0+a1*x, 擬合曲線如下:

此處輸入圖片的描述由於此時的係數比較少,曲線不夠靈活,所以此時擬合的誤差較大,損失函式較大。

如果我們再增加一個不為0的係數a2, 擬合函式變成了:y=a0+a1*x+a2*x^2, 擬合曲線如下:

此處輸入圖片的描述

這時的擬合效果已經非常好了,但注意仍然有一些資料點的中心不在擬合曲線上,即損失函式值大於0。假如此時再增加一個不為0的係數a3, 擬合函式變成了:y=a0+a1*x+a2*x^2+a3*x^3, 注意每次增加一個不為0的係數,相當於是擬合函式變得更加的靈活。這時擬合曲線可能如下:

此處輸入圖片的描述此時擬合函式經過每一個數據點的中心,損失函式為0。但擬合函式的形狀已經有些奇怪了。如果我們繼續增加更多的不為0的係數,擬合函式曲線甚至可能變成這樣:

此處輸入圖片的描述擬合函式非常精確的經過了每一個數據點且此時的損失函式值為0,但使用這個擬合函式來預測新的x點對應的y的值可能不會取得非常好的結果。聯想之前我們學過的泛化效能,這裡的泛化效能會非常差。或者說,這裡出現了過擬合(overfitting)

我們的深度神經網路模型就可能會出現這個問題,雖然在訓練集上的損失函式值已經非常低,甚至為0,但可能仍然無法在驗證/測試集上獲得很好的泛化效能。

為了避免過擬合,就需要我們這裡的正則化(regularization), 在solver.prototxt裡像下面這樣設定正則化引數:

regularization_type: "L2"weight_decay:0.0001

那麼具體正則化是如何防止過擬合發生的呢?實際上,這裡的正則化,是通過在前向計算的過程中,將網路中所有的引數的平方與weight_decay相乘,再加到損失函式值上;而反向傳遞梯度時,則仍然根據鏈式法則對引數進行更新。比如這裡的weight_decay為0.0001,假設只有一個引數a=3,則損失函式值計算時就變成了:L=L0+0.0001*3^2=L0+0.0009,這裡的L0是不新增正則化時的損失函式值。反向傳遞梯度時,對引數的更新就變成了a=a-lr*(d0+2*0.0001*3), 其中d0是不新增正則化時的梯度值,而2*0.0001*3是誤差函式中的正則化項對引數求導(梯度)的結果。實際上,由於這裡的a值就是3,之前的式子可以直接改成:a=(1-lr*2*0.0001)*a-lr*d0。合理的設定學習速率lr和正則化引數weight_decay的值,可以使(1-lr*2*weight_decay)的值小於1,這樣的效果實際上是使得引數a值每次都以一定的比例縮小, 防止引數變得過大。這樣可以在一定程度上使高次項的係數變小,從而防止高次項對整個模型的影響過大。從而最終達到防止過擬合的目的。

正則化在這裡屬於稍難的內容,如果你不需要非常深刻的理解深度學習而只是想能夠實際上手,可以暫時不去深究正則化的原理,只需要記住caffe裡的這兩個引數是用來進行正則化,從而提高模型效果就行了。

regularization_type設定為L2就是代表對損失函式加上引數的平方項,還可以將其設定為L1,這樣加上的就是引數的絕對值。(實際上,這裡的L2代表的是2-範數,而L1代表的是1-範數)

2.5 其他設定

我們的solver.prototxt還剩下下面這些設定項:

display: 100snapshot: 2000snapshot_prefix: "snapshot/alpha"solver_mode: CPU

其中display: 100代表訓練是每隔100隔訓練週期顯示一次損失函式值snapshlt: 2000代表每隔2000個訓練週期將當前模型的引數caffemodel和訓練過程中的其他資料solverstate存入快照,快照存入的位置由snapshot_prefix指定solver_mode指定訓練是在CPU還是GPU上進行,這裡是CPU

2.6 開始訓練

終於,我們的solver.prototxt也寫好了,可以開始我們的訓練了。訓練前,你先要確保存放快照檔案的資料夾存在,由於這裡snapshot_prefixsnapshot/alpha,所以我們的快照最終後儲存在snapshot目錄中,我們執行以下命令建立這個目錄:

mkdir snapshot

通過以下命令執行訓練過程:

caffe train -solver solver.prototxt

train代表了現在我們是要進行訓練,-solver solver.prototxt指定了我們的solver.prototxt檔案的位置。

如果沒有出錯的話,你會先看到很長的一串輸出(caffe建立模型時的日誌輸出),接著就是類似這樣的損失函式值輸出:

此處輸入圖片的描述

可以看到,每隔100個訓練週期,會有損失函式值的輸出,損失函式值大致是呈遞減的趨勢。每隔500個訓練週期,會有測試準確率輸出,準確率大致呈遞增的趨勢。

整個訓練過程10000次迭代大致需要三分鐘,訓練結束後,差不多能夠達到0.994的準確率。

就這樣,我們使用caffe訓練出了第一個卷積神經網路模型(鼓掌)。在snapshot資料夾下面,你可以找到訓練完畢的模型引數檔案。

此處輸入圖片的描述

三、實驗總結

至此,模型的構建和訓練過程已經全部完成了,我們擁有了一個準確率超過0.99的卷積神經網路模型。下次實驗,我們會利用這個模型去開發一個圖片字母識別程式,讓我們的模型真正的能夠發揮作用。

本次實驗,我們學習了:

  • 讓學習速率隨著訓練的過程逐漸變小可以使最終的引數更接近理想點。
  • 正則化是保證模型獲得較高的泛化效能的重要手段之一。

四、課後作業

  1. solver.prototxt中的超引數我已經提前設定好了,請你自己嘗試不同的超引數設定,觀察超引數的變化對模型訓練過程的影響。