2022年3月29日 星期二

機器學習筆記 : 深度學習的 16 堂課 (五)

本篇繼續整理 "深度學習的16堂課" 這本書的讀後筆記, 本系列之前的文章參考 : 


以下是我讀第五章 "先動手實作! 5 行程式體驗神經網路模型" 的摘要筆記與測試紀錄 (此書第一篇前四章是 ML 知識介紹, 本章開始才有程式碼實作, 第二篇 5~8 章介紹深度學習核心概念) :
  1. Tensorflow 2 開始將原本獨立的高階 API Keras 套件納入 Tensorflow 中, 成為 tf.Keras 子套件, 使建構神經網路的程式碼更加簡潔. 
  2. MNIST 是由 Yann LeCun, Corinna Cortes, 與微軟 AI 研究員 Burges 整理的手寫數字資料集, 含有 70000 張 28x28 解析度的手寫數字圖片, 其中 60000 張是訓練資料集 (training datatset), 10000 張是測試資料集 (test dataset). 
  3. 基本的淺層神經網路由輸入層, 隱藏層, 與輸出層構成, 以 MNIST 來訓練手寫數字圖片辨識模型來說, 輸入層需有 28x28=784 個神經元 (用來接收每張圖的 784 個像素), 輸出層需有 10 個神經元 (表示 0~9 數字的機率, 最高者為其預測結果), 隱藏層用來學習輸入資料的特徵, 其神經元數目是超參數, 可任意指定, 一般使用 2 的次方數字 (例如 64). 由於 MNIST 資料集是以 2D 陣列表示, 因此在饋入神經網路之前須將其拉平為 1D 陣列. 
  4. 在 Google 雲端硬碟中的 Colab 運算平台執行機器學習運算非常方便, 用法參考 :
    方便好用的 Google Colab 運算平台
    如果要在 Colab 上用 matplotlib 繪圖, 需先執行下列程式碼 :
    %matplotlib inline    
  5. 在 Colab 平台進行 MNIST 資料集訓練 : 
    (1). 匯入模組 :
    from tensorflow.keras.datasets import mnist          # 匯入 MNIST 資料集
    from tensorflow.keras.models import Sequential   # 匯入堆疊模型
    from tensorflow.keras.layers import Dense             # 匯入密集層
    from tensorflow.keras import optimizers                # 匯入優化器
    from tensorflow.keras.utils import plot_model       # 匯入繪圖模型
    from tensorflow.keras.utils import to_categorical   # 匯入分類器
    import matplotlib.pyplot as plt                                  # 匯入繪圖模組 pyplot
    import numpy as np                                                    # 匯入 Numpy

    (2). 載入 MNIST 資料集 : 

    (X_train, y_train), (X_test, y_test)=mnist.load_data()    
    這會傳回兩組 tuple第一組是 6 萬筆的訓練集, X_train 是訓練集的圖片資料, y_train 是訓練集的標籤 (答案); 第二組是 1 萬筆的測試集, X_test 是測試集的圖片資料, y_test 是測試集的標籤 (答案), 結果如下 : 


    大寫 X 表示這是 2D 以上的向量; 而小寫 y 表示這是 1D 的向量或純量.

    (3). 查看資料集內容 :

    X_train.shape    
    (60000, 28, 28)   
    表示訓練集有 6 萬筆資料, 每筆圖片解析度是 28x28.
    然後用 Numpy 的 set_printoptions() 設定列印寬度為無限大, 這樣才不會因為過長而跳行, 接著列印訓練集的第一筆資料圖片內容 :
    np.set_printoptions(linewidth=np.inf)      
    X_train[0]    




    看起來是數字 5. 接著查看訓練集標籤內容 :
    y_train[0:12]   
    array([5, 0, 4, 1, 9, 2, 1, 3, 1, 4, 3, 5], dtype=uint8)


    可見訓練集第一張圖片確實是 5.

    (4). 用 Matplotlib 繪製 MNIST 資料圖片 :
     
    plt.figure(figsize=(5, 5))     # 設定 5吋*5吋畫布
    for k in range(12):              # 繪製前 12 張圖片
        plt.subplot(3, 4, k+1)      # 指定 3*4 網格中第 k+1 個子圖繪圖區
        plt.imshow(X_train[k], cmap='gray')     # 在第 k+1 個子圖繪製第 k 張圖片
    plt.tight_layout()    
    plt.show()    

    上面程式碼用來繪製 MNIST 測試集的前 12 張圖片, 這裡要注意, plt.subplot() 的子圖網格系統編號是 1 起始的, 但 MNIST 的資料編號則是 0 起始的. 關於 Mplotlib 用法參考 :

    Python 學習筆記 : Matplotlib 資料視覺化 (一) 基本篇
    Python 學習筆記 : Matplotlib 資料視覺化 (二) 統計圖
    Python 學習筆記 : Matplotlib 資料視覺化 (三) 進階篇

    結果如下 :



    (5). 資料預處理 : 
    資料預處理主要有兩項, 首先要將全部資料集的圖片資料從 28*28 的 2D 陣列型態拉平為 1*784 的 1D 陣列, 這樣才能與神經網路的輸入層結構匹配 (同時也將原本 0~255 的整數像素由 uint8 改為 float32 浮點數), 這主要是依賴 Numpy 的 reshape() 與 astype() 達成. 其次是要將資料正規化, 將所有資料轉成 0~1 之間的數值, 這樣模型的訓練成效較好. 最簡單的正規化就是除以最大值 (255) :

    X_train=X_train.reshape(60000, 784).astype('float32')    # 2D 資料展平為 1D
    X_test=X_test.reshape(10000, 784).astype('float32')         # 2D 資料展平為 1D
    X_train /= 255              # 正規化
    X_test /= 255                # 正規化
    X_train[0]                    # 顯示第一張圖片




    (6). 標籤預處理 : 

    除了資料需要預處理外, 輸出標籤 (即 y_train 與 y_test) 也需要預處理, 將原本的 0~9 用 one-hot 編碼為 10 維的 1D 陣列, 這要用到 Keras 的 to_categorical() 函式 :

    y_train=to_categorical(y_train, 10)     # 訓練集標籤 one-hot 編碼
    y_test=to_categorical(y_test, 10)          # 測試集標籤 one-hot 編碼
    y_train[0]            # 顯示訓練集第一張圖的標籤


    可見第一張圖 5 只有在 [5] 位置是 1, 其餘為 0. 

    (7). 建立, 編譯, 與訓練神經網路模型 :

    使用 Sequential 模型建立三層神經網路 :


    model=Sequential()     # 建立序列式模型
    model.add(Dense(64, activation='sigmoid', input_shape=(784,)))   # 輸入+隱藏層
    model.add(Dense(10, activation='softmax'))    # 輸出層
    model.compile(loss='mean_squared_error',    
                             optimizer=optimizers.SGD(learning_rate=0.01),    
                             metrics='accuracy')                    # 編譯模型
    model.fit(X_train, y_train, batch_size=128, epochs=200, verbose=1,      
                    validation_data=(X_test, y_test))       # 訓練模型

    此處 model 只呼叫 add() 兩次就建立了三層模型, 因為第一次呼叫 add() 時同時建立了輸入層 (用 input_shape 參數指定 784 個神經元) 與隱藏層 (64 個神經元), 因為在 tf.Keras 中第一層是輸入層間隱藏層, 第二次呼叫 add() 建立輸出層時不需指定 input_shape, 模型會自動連結上一層的 64 個神經元. 呼叫 Dense() 函式是要建立全連接的密集層, 該層的每個神經元都會與上一層的每個神經元連接. 參數 activation 指定激活函數 (activation function), 用來增加神經元對非線性規則的學習能力. 激活函數 softmax 可將輸出層神經元的輸出限制在 0~1 之間, 而這 10 個值加起來是 1, 故 softmax 有輸出機率值的效果. 
    呼叫 fit() 編譯模型時傳入 loss 參數指定損失函數類型來計算模型預測值與正確答案之誤差, optimizer 參數指定優化器, 用來調整權重使誤差值能降到最低. metrics 參數則指定如何評估模型的學習成效, 'accuracy' 表示以準確度來評估. 
    呼叫 fit() 訓練時傳入參數 batch_size=128 表示訓練時每次從 6 萬筆資料集中取 128 筆資料進行訓練 (考量到記憶體容量, 並不是把訓練集一次全部饋入神經網路, 而是分批饋入), 依序跑完 6 萬筆稱為一個 epoch (一輪), 參數 epochs=200 表示這 6 萬筆要跑 200 輪. 參數 verbose=1 表示顯示完整的訓練過程 (包含進度條). 


    跑 200 個 epoch (輪) 花了 6 分鐘, 最後達到 86.4% 精確度 :


  6. 儲存 ipynb 檔副本於 GitHub :
    Colab 的執行過程除了會儲存在 Google 雲端硬碟裡, 還可以儲存副本到自己的 GitHub 儲存庫裡, 上面的程式碼 ipynb 檔的 GitHub 網址如下 :
    https://github.com/tony1966/colab/blob/main/deep_learning_illustrated_ch5_mnist.ipynb



     

沒有留言 :