本篇繼續來整理我讀布留川英一寫的 "強化式學習-打造最強通用演算法 AlphaZero" 這本書的摘要筆記, 本系列之前的筆記參考 :
以下是我讀完第三章 "深度學習" 的第 一部分 MNIST 資料集之摘要筆記 :
- 深度學習最核心的工作就是根據大量資料建構出最佳的神經網路.
- 深度學習常用的損失函數, 優化器, 與評估指標 :
常用的損失函數 說明 mse 均方誤差, 用於評估連續值的迴歸模型 binary_crossentropy 二元交叉熵, 用於二元分類的預測 categorical_crossentropy 多元交叉熵, 用於多元分類的預測 常用的優化器 說明 SGD stochastic gradient decent (隨機梯度下降), 最傳統的優化器 adagrad adaptive gradient, 動態學習率 (梯度小 -> 學習率大) adam adagrad + momentum (方向改變時學習率變慢), 性能優異 常用的評估指標 說明 acc accuracy (準確率), 用於分類, 越接近 1 越好 mae 平均絕對誤差, 用於迴歸, 越接近 0 越好 - 監督式學習的訓練流程 :
損失函數計算預測值與標籤的誤差; 優化器是一個演算法, 透過計算損失值的梯度 (偏微分) 來修改權重參數使損失值能逐批次降低至最小. - 資料集載入與預處理 (以 MNIST 為例) :
將資料集切割成訓練集與測試集兩部分, 先用訓練集訓練網路模型, 再用測試集來評估訓練過的模型對新資料的普適能力 (generalization ability). 訓練集裡面又會分出一部分 (通常是 20%) 當作驗證集 (validation set), 它會被用來當作訓練過程中的先期測試, 目的是在批次訓練的同時可以知道有沒有發生過度適配 (overfitting) 現象. 這些資料切割 tf.keras 會自動進行, 不須手動分割. - 此章第一部分是用 MLP 多層感知器來辨識 MNIST 手寫數字資料集, 此處使用三層密集層與一個丟棄層, 結構如下 :
(1). 輸入層 :
tf.keras 的輸入層是包含第一個隱藏的, 其參數包括 :
第一隱藏層神經元數目 units (整數, 第一參數可以不寫)
輸入層神經元數目 input_shape (元組) 或 input_dim (整數)
激活函數 activation (字串), 可用 'sigmoid', 'relu' 等
(2). 隱藏層 :
隱藏層與每層神經元數目是建構者自行指定設計的, 增加神經元與層數可捕捉到更複雜特徵, 但參數 (w 與 b) 也會增加, 若訓練資料不足容易出現過度配適問題 (overfitting), 這時網路會過度學習訓練資料 (形成固定路徑), 而非學習到通用規則, 於是無法順利辨識新資料, 即對訓練資料預測能力很好, 對新資料卻很爛 (好比是當圖庫不大時, 偷懶的學生就不求甚解, 直接把題庫背下來, 若老師出考古題可得高分, 但若稍做變化就會死得很慘).
(3). 激活函數 :
將神經元輸出進行非線性運算, 以便能從資料中學到複雜的非線性規則.
(4). 丟棄層 :
丟棄層是為了抑制過度適配而設的, 在每批次訓練中會隨機丟棄上一層神經元輸出 (設為 0) 以減少神經元之間的依賴性, 可提升模型之普適能力, 通常加在密集層後面, 常用丟棄率 50%.
(5). 輸出層 :
輸出層為密集層, 對於分類問題, 其神經元數目取決於分類類別之數量, 例如 MNIST 資料集要辨識 0~9 手寫數字, 輸出層要設 10 個神經元, 其激活函數通常使用 Softmax, 它會讓每個分類輸出之機率總和為 1, 機率最高者即為預測值.
Jupyter 內嵌繪圖結果 :%matplotlib inline
載入套件模組 :from tensorflow.keras.datasets import mnistfrom tensorflow.keras.models import Sequentialfrom tensorflow.keras.layers import Dense, Activation, Dropoutfrom tensorflow.keras.optimizers import SGDfrom tensorflow.keras.utils import plot_modelfrom tensorflow.keras.utils import to_categoricalimport matplotlib.pyplot as pltimport numpy as np
下載資料集 :(train_images, train_labels), (test_images, test_labels)= mnist.load_data()
檢視資料集 :print(type(train_images)) # <class 'numpy.ndarray'>print(type(train_labels)) # <class 'numpy.ndarray'>print(type(test_images)) # <class 'numpy.ndarray'>print(type(test_labels)) # <class 'numpy.ndarray'>print(train_images.shape) # (60000, 28, 28)print(train_labels.shape) # (60000,)print(test_images.shape) # (10000, 28, 28)print(test_labels.shape) # (10000,)
注意這裡標籤都是純量, 訓練集有 60000 個 (60000,), 測試集有 10000 個 (10000,), 都是 0~9 的單一整數, 例如 train_labels 的前十筆答案如下 :
print(train_labels[0:10]) # [5 0 4 1 9 2 1 3 1 4]
繪製前 10 筆圖片 (前面須用 %matplotlib inline 指令內嵌圖片於網頁中) :for i in range(10):plt.subplot(1, 10, i+1)plt.imshow(train_images[i], 'gray')
注意, Jupyter 中 plt.show() 可有可無, 結果如下 :
可見與上面印出的 train_labels[0:10] 結果一致.
檢視訓練集第一個圖片 :print(train_images[0])
圖片預處理 (將 2D 矩陣序列化為 1D 向量) :train_images=train_images.reshape((train_images.shape[0], 784))test_images=test_images.reshape((test_images.shape[0], 784))print(train_images.shape) # (60000, 784)print(test_images.shape) # (10000, 784)
可見訓練集與測試集的圖片形狀 (shape) 都從 (28, 28) 變成 (784,) 了. 注意, 此處之預處理並未對訓練圖片的值做正規化 (normalization) 處理, 即除以 255 將值限縮至 0~1 之間, 而是以原來的 0~255 值進行訓練, 參考 :
# 機器學習筆記 : 深度學習的 16 堂課 (八)
標籤預處理 (轉成 one-hot 編碼) :# 檢視第 0 張圖片之原標籤print(train_labels[0])print(test_labels[0])# 將全部標籤轉成 one-hot 編碼train_labels=to_categorical(train_labels) # 5test_labels=to_categorical(test_labels) # 7# 檢視轉換後的第 0 張圖片之新標籤print(train_labels[0]) # [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]print(test_labels[0]) # [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]# 檢視轉換後的標籤形狀print(train_labels.shape) # (60000, 10)print(test_labels.shape) # (10000, 10)
建構神經網路 :# 建構神經網路模型model=Sequential()model.add(Dense(256, activation='sigmoid', input_shape=(784,))) # 輸入層+隱藏層1model.add(Dense(128, activation='sigmoid')) # 隱藏層2model.add(Dropout(rate=0.5)) # Dropoutmodel.add(Dense(10, activation='softmax')) # 輸出層
編譯模型 :model.compile(loss='categorical_crossentropy', optimizer=SGD(learning_rate=0.1),metrics=['acc'])
注意, 書上學習率設定使用 lr, 但此用法已被廢棄, 新參數名為 learning_rate.
訓練模型 :history=model.fit(train_images, train_labels, batch_size=500,epochs=5, validation_split=0.2, verbose=1)
結果如下 :
只跑五個周期就達到 91.42% 了.
顯示訓練歷史 :print(history.history)
{'loss': [1.7062885761260986, 0.9367091655731201, 0.6744827628135681, 0.5535663366317749, 0.47903767228126526], 'acc': [0.4466041624546051, 0.7388125061988831, 0.8157291412353516, 0.8494583368301392, 0.867229163646698], 'val_loss': [0.9893402457237244, 0.5934872031211853, 0.44598323106765747, 0.3705187141895294, 0.3295259475708008], 'val_acc': [0.8325833082199097, 0.8818333148956299, 0.8964166641235352, 0.9075833559036255, 0.9141666889190674]}
繪製訓練過程 :plt.plot(history.history['acc'], label='acc')plt.plot(history.history['val_acc'], label='val_acc')plt.ylabel('accuracy')plt.xlabel('epoch')plt.legend(loc='best')plt.show()
用測試集評估 :test_loss, test_acc=model.evaluate(test_images, test_labels)print('loss: {:.3f}\nacc: {:.3f}'.format(test_loss, test_acc ))
準確率達到 91.4%.
預測測試集第 0 張圖片 :test_predictions=model.predict(test_images[0:1])print([round(i,4) for i in test_predictions[0].tolist()])# 顯示預測結果的標籤test_predictions=np.argmax(test_predictions, axis=1)print(test_predictions[0])
結果為 7, 機率為 0.9827 :
[0.0008, 0.0005, 0.0014, 0.0038, 0.0002, 0.0006, 0.0, 0.9827, 0.0003, 0.0097]
7
繪製測試集前 10 張圖片 :for i in range(10): plt.subplot(1, 10, i+1) plt.imshow(test_images[i].reshape((28, 28)), 'gray') plt.show()
預測測試集前 10 張圖片 :test_predictions=model.predict(test_images[0:10])test_predictions=np.argmax(test_predictions, axis=1)print(test_predictions)結果完全正確除第 9 個錯誤外 (正確是 5 但預測為 6) 其餘都正確 :
[7 2 1 0 4 1 4 9 6 9]
以上演練筆記本參考 :
# https://github.com/tony1966/colab/blob/main/reinforcement_learning_ch3_mnist.ipynb
沒有留言:
張貼留言