深度學習基礎 - 基於Theano-MLP的字元識別實驗(MNIST)

Snoopy_Yuan發表於2017-05-10

深度學習基礎 - 基於Theano-MLP的手寫字元識別實驗


本文的完整程式碼託管在我的Github PY131/Practice-of-Machine-Learning,歡迎訪問。

基礎知識

深度學習回顧

深度學習的概念起源於人工神經網路,本文所採用的包含多隱層的多層感知機(MLP)就是其中的典型模型。長期以來,由模型複雜度所帶來的計算效率低下問題一直是抑制深度學習進一步發展的瓶頸。近年來,隨著大資料、雲端計算的興起以及進步的演算法設計,以“深度學習”為代表的大容量複雜模型開始突破其效率瓶頸,走向實用。深度學習正被愈發廣泛地應用於計算機視覺、語音識別、自然語言處理等領域,其所具備的強大學習能力已初現威力。

Theano簡介

Theano是一個基於python的科學計算框架,它在整合了numpy/scipy的基礎上,實現了對GPU的透明支援,theano常被用作深度學習的基礎框架。下面回顧theano的幾個基礎概念(核心概念):

- tensor variable(張量)
- theano function(theano函式)
- shared variable(共享變數)
- gradient(梯度)

基於MLP的字元識別模型

這裡我們採用簡單的單隱層MLP來實現,具體過程可參考:MNIST_Multilayer Perceptron

這裡列出一些建模過程中所要注意的內容:

  • 引數(連線權+偏置)的初始化區間需根據啟用函式而定;
  • 此處面向分類問題,輸出層可採用softmax來獲得最終預測結果;
  • 採用MSGD(塊隨機梯度下降)來加速尋優,注意mini-batch的size選取;
  • 採用L1/L2正則化提升模型泛化能力,注意正則化引數的調節;

實驗內容

檢視完整程式碼資料集

資料集分析

這裡我採用規約好的MNIST資料集,相關內容可參考:Getting Started - Datasets - MNIST Dataset,資料集(mnist.pkl.gz)相關統計內容如下:

- 維度屬性:
    資料集包含3個子資料集,對應train_set、valid_set、test_set,樣本規模分別為50000、10000、10000;
    每條樣本包含:
        輸入向量[1*784],對應輸入圖片灰度矩陣[28*28];
        輸出值,對應圖片類別標籤(數字0-9);
- 完整度:
    樣本完整;
- 平衡度:
    未知;
- 更多資訊:
    手寫字元所覆蓋的灰度已被人工調整到了圖片的中部。

根據上面的分析,在資料處理時需要對資料進行維度轉換。

下面是一些樣例圖片:

這裡寫圖片描述

網路模型實現

首先給出基於python-theano程式設計實現MLP的步驟如下:

  1. 編寫模型訓練、驗證、測試函式體;
  2. 基於theano.function及python函式實現相關函式(sigmoid、tanh、MSGD、train_model、valid_model、test_model、),;
  3. 基於theano.shared初始化引數(連線權+偏置);
  4. 設定其他引數(隱層節點數、學習率、塊大小、迭代次數、正則化係數、早停引數等);
  5. 完善模型訓練、驗證、測試函式體;

其中訓練函式體的流程概述如下:

1. 載入資料,生成訓練集、驗證集、測試集;
2. 根據資料維度,生成對應的MLP網路結構;
3. 訓練模型,更新引數,實時記錄訓練誤差、分時記錄驗證誤差和測試誤差(泛化誤差);
4. 達到訓練停止條件(迭代次數、耐心指數),輸出模型與相關記錄資訊;

簡化的模型訓練程式塊樣例如下:完整程式

# 函式引數包括相關引數設定
def test_mlp(learning_rate=0.01,          # 學習率 (等號右邊為預設值) 
             L1_reg=0.00, L2_reg=0.0001,  # 正則化係數
             n_epochs=1000,               # 迭代次數
             batch_size=20,               # mini-batch大小
             n_hidden=500,                # 隱層節點數
             dataset='mnist.pkl.gz'       # 資料集
            ):  

    # 載入資料、獲取訓練集、驗證集、測試集
    datasets = load_data(dataset)   
    train_set_x, train_set_y = datasets[0]
    valid_set_x, valid_set_y = datasets[1]
    test_set_x,   test_set_y = datasets[2]

    ...

    # 初始化MLP網路結構和引數
    classifier = MLP(
        rng=rng,
        input=x,
        n_in=28 * 28,
        n_hidden=n_hidden,
        n_out=10
    )

    # 生成“似然+正則化”損失函式體
    cost = (
        classifier.negative_log_likelihood(y) 
        + L1_reg * classifier.L1 
        + + L2_reg * classifier.L2_sqr
    )

    # “模型測試”函式體
    test_model = theano.function(...)

    # “模型驗證”函式體
    validate_model = theano.function(...)

    # “梯度計算”函式體
    gparams = [T.grad(cost, param) for param in classifier.params]

    # “引數更新”機制
    updates = [
        (param, param - learning_rate * gparam)
        for param, gparam in zip(classifier.params, gparams)
    ]

    # 訓練函式體
    train_model = theano.function(...)

    ###############
    # 模型訓練主體 #
    ###############

    # 早停機制設計
    ...

    # 迭代主體
    while (epoch < n_epochs) and (not done_looping):
        epoch = epoch + 1

        # 一個塊的迭代訓練
        for minibatch_index in range(n_train_batches):

            # 一條樣本迭代訓練(前向計算、基於梯度的引數更新)
            train_outputs = train_model(minibatch_index)  

            # 訓練損失計算
            minibatch_avg_cost = train_outputs[0]    

            # 驗證塊
            # 達到驗證所要求迭代次數 - 進行驗證
               validation_losses = [validate_model(i) for i in range(n_valid_batches)]  # 計算0-1損失
               this_validation_loss = numpy.mean(validation_losses)  # 平均驗證誤差計算

               # 記錄最優資訊
            ...

            # 是否達到測試所要求條件 - 進行測試
               test_losses = [test_model(i) for i in range(n_test_batches)] # 計算0-1損失
               test_score = numpy.mean(test_losses)  # 測試誤差計算
               ...

            # 早停判斷               
            ...      
    ...

    # 過程資訊反回
    return err_train, err_valid, err_test   

實驗結果分析

通過合適的引數設定,記錄訓練過程中的訓練誤差(每iteration記錄一次),驗證誤差(每epoch記錄一次),測試誤差(當驗證精度提高時計算一次),得出三種誤差的收斂曲線如下圖示:

這裡寫圖片描述

最終的分類結果如下:

Optimization complete. Best validation score of 1.880000 % (驗證誤差結果)
obtained at iteration 2077500, with test performance 1.840000 % (測試誤差結果)

而整個程式執行時間為:

The code for file MLP.py ran for 68.32m (分鐘)

我們可以對結果作如下分析:

  • 這裡的MLP模型在當前引數和軟硬體條件下下,採用了一個多小時(略長)的引數訓練,得到了小於2%的誤差精度,一方面說明了神經網路模型的龐大計算量,另一方面說明了該模型的出色效果。
  • 誤差曲線在較早時就已經趨向於穩定,說明當前結構和引數下模型精度已經難再提升。
  • 神經網路模型的引數設定,有時會對訓練過程和最終效果產生重要影響,比如這裡的學習率、L1/L2正則化係數、隱層規模、mini-batch規模等。

總結

這裡採用python-theano實現了一個簡單的多層感知機網路,並基於MNIST手寫字元資料集實現了分類實驗

在這個過程中,我們回顧了神經網路的基礎知識,練習了theano計算框架的使用,採用了相關輔助方法來優化訓練,為後面開展“深度學習”研究積累了經驗。

通過實驗我們看到,一方面,神經網路模型訓練往往伴隨著巨大的計算量,相關引數設定也需要謹慎考慮並結合實驗結果科學調整;另一方面,通過大量訓練所得到的神經網路模型能夠表現出優異的效能

參考資料

相關重要參考列出如下:

核心參考:

其他參考:

相關文章