iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
2
AI & Data

輕鬆掌握 Keras 及相關應用系列 第 3

Day 03:撰寫第一支完整的 Keras 程式

前言

上一篇,我們完成了一個神經元的計算,如果要完成整個神經網路的計算,一個一個神經元撰寫,程式碼可能要很多迴圈,才能完成多層式的神經網路,因此,深度學習套件又導入【神經層】(Layer)的函數,直接作一層層的串連,就方便許多了。

這次我們就利用神經層串連一個神經網路,辨識手寫阿拉伯數字,終極目標我們要撰寫一個視窗介面親自實驗模型的準確性。

2017年我使用 Keras 獨立套件撰寫辨識手寫阿拉伯數字的程式,請參閱【Day 02:撰寫第一支 Neural Network 程式 -- 阿拉伯數字辨識】,現在,我們改用TensorFlow Keras 寫類似的程式,讀者可比較其差異,其實,大部份的程式是相同的,只是命名空間不同罷了。

Tensorflow 的反攻

Tensorflow 1.x 版使用會話(Session)及運算圖(Computational Grahp)的概念,撰寫一支簡單的程式就要花費好大的功夫,被 Facebook PyTorch 批評的體無完膚,包括:

  1. 程式觀念複雜難懂:Tensorflow把簡單的事情複雜化,Keras 則把複雜的事情過於簡化。
  2. 除錯不易:須等到運算圖(Computational Grahp)執行完畢,才可以查看過程中的變數值。
  3. 與 Python 整合度差,無法在模型中直接使用 Python 的 if/else。

因此,Tensorflow 2.x 大改版,作了以下的改變:

  1. 把運算圖(Computational Grahp)隱藏起來,預設模式改為 Eager Mode,隨時可列印(print)變數值。
  2. 不用 Session,直接呼叫自動微分(GradientTape)。
  3. 重新開發 Keras,並與其他模組整合。

並且在官網直接放上一支超短程式,示範如何辨識手寫阿拉伯數字,要證明Tensorflow超好用,現在我們就來看看這支程式,以下我逐行加了一些註解。

import tensorflow as tf
mnist = tf.keras.datasets.mnist

# 匯入 MNIST 手寫阿拉伯數字 訓練資料
(x_train, y_train),(x_test, y_test) = mnist.load_data()
# 特徵縮放,使用常態化(Normalization),公式 = (x - min) / (max - min)
# 顏色範圍:0~255,所以,公式簡化為 x / 255
x_train, x_test = x_train / 255.0, x_test / 255.0

# 建立模型
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='softmax')
])

# 設定優化器(optimizer)、損失函數(loss)、效能衡量指標(metrics)的類別
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 模型訓練
model.fit(x_train, y_train, epochs=5)
# 模型評估,打分數
model.evaluate(x_test, y_test)

模型結構如下:
https://ithelp.ithome.com.tw/upload/images/20200902/20001976GKQxHxVSHQ.png

各神經層處理程序如下(tf.keras.models.Sequential那一段):

  1. Flatten Layer:將寬、高各28個像素的圖轉成一維陣列 28 x 28 = 784個特徵。
  2. Dense Layer:input為784個特徵,output 為128個神經元,即128條迴歸線。
  3. Dropout Layer:在訓練週期隨機丟棄20%的神經元,藉以矯正過度擬合的現象。
    https://ithelp.ithome.com.tw/upload/images/20200902/200019762LSVXn3CUG.png
  4. 最後一個 Dense Layer:輸出10個神經元,透過 softmax activation function,轉成機率,即0~9的預測機率,選擇最大機率者為預測值。

上述的程式扣除註解,不到10行,辨識的準確率高達97~98%,真是厲害 !!

強化

要徹底了解上述程式,建議在不清楚的指令行後面,加一些除錯訊息,例如 03_01_MNIST.ipynb。

  1. 顯示圖片資料。
# 將非0的數字轉為1,顯示第1張圖片
data = x_train[0].copy()
data[data>0]=1

# 將轉換後二維內容顯示出來,隱約可以看出數字為 5
text_image=[]
for i in range(data.shape[0]):
    text_image.append(''.join(str(data[i])))
text_image

https://ithelp.ithome.com.tw/upload/images/20200903/20001976n9jZPH2iKm.png
圖一. 將非0的數字轉為1,隱約可以看出數字為 5

  1. 訓練資料切成兩份,驗證資料占兩成。
# 訓練
history = model.fit(x_train_norm, y_train, epochs=5, validation_split=0.2)
  1. 對訓練過程的準確度/損失函數繪圖。
# 對訓練過程的準確度繪圖
import matplotlib.pyplot as plt
plt.plot(history.history['accuracy'], 'r')
plt.plot(history.history['val_accuracy'], 'g')

# 對訓練過程的損失函數繪圖
plt.plot(history.history['loss'], 'r')
plt.plot(history.history['val_loss'], 'g')
  1. 實際預測 N 筆,觀察結果,發現第9筆錯誤,顯示錯誤的圖片。
# 實際預測 20 筆
predictions = model.predict_classes(x_test_norm)
# get prediction result
print('prediction:', predictions[0:20])
print('actual    :', y_test[0:20])

# 顯示錯誤的資料圖像
X2 = x_test[8,:,:]
plt.imshow(X2.reshape(28,28))
plt.show() 

https://ithelp.ithome.com.tw/upload/images/20200903/200019760htyM3a2Tv.png
圖二. 實際為5,辨識為6的圖像

  1. 使用小畫家,寫0~9,實際測試看看,注意,顏色0為白色,與RGB顏色不同,(0,0,0) 為黑色。
# 使用小畫家,寫0~9,實際測試看看
from skimage import io
from skimage.transform import resize
import numpy as np

uploaded_file = './myDigits/8.png'
image1 = io.imread(uploaded_file, as_gray=True)
#image1 = Image.open(uploaded_file).convert('LA')
image_resized = resize(image1, (28, 28), anti_aliasing=True)    
X1 = image_resized.reshape(1,28, 28) #/ 255
# 反轉顏色
# 顏色0為白色,與RGB顏色不同,(0,0,0) 為黑色。
X1 = np.abs(1-X1)
predictions = model.predict_classes(X1)
print(predictions)
  1. 其他功能:顯示模型的彙總資訊、模型存檔/載入、模型繪圖。
# 顯示模型的彙總資訊
model.summary()

# 模型存檔
model.save('model.h5')

# 模型載入
model = tf.keras.models.load_model('model.h5')

# 繪製模型
# 需安裝 graphviz (https://www.graphviz.org/download/)
# 將安裝路徑 C:\Program Files (x86)\Graphviz2.38\bin 新增至環境變數 path 中
# pip install graphviz
# pip install pydotplus
tf.keras.utils.plot_model(model, to_file='model.png')

檔案名稱為 03_01_MNIST.ipynb。

結論

讀到這裡,讀者對神經網路應該有些心得,但是,應該也會有更多的疑問。
我的心得如下:

  1. 神經網路並不是真的認識圖片中的數字,它只是將圖片中的像素當作特徵,將訓練資料作歸納,找出0~9的區別。
  2. 機器學習並不是規則引擎(Rule Engine),而是演算法藉由資料,歸納出模型或公式。
  3. 機器學習的標準處理流程如下圖,後續再詳加說明。
    https://ithelp.ithome.com.tw/upload/images/20200903/20001976UxH8Uf9GdY.png

讀完上文,初次接觸深度學習的讀者應該還是會有許多疑問:

  1. 為什麼模型要設成兩層完全連接層(Dense)?
  2. 為什麼第一層完全連接層(Dense)要設為 128?
  3. activation function、優化器(optimizer)、損失函數(loss)、效能衡量指標(metrics) 要如何選擇?
  4. 為什麼使用小畫家,寫0~9實際測試,準確率好像不如測試資料那麼高? 我寫9,永遠辨識錯誤,唉 !
  5. 使用像素辨識,好像不是很高明,應該用輪廓或線條比較好吧。
  6. 如果要辨識多個數字,例如車牌,要怎麼作?
  7. 如果要辨識其他事物,怎麼作?

後續我們就來一一探討這些問題,下一篇我們先來說明如何作效能調校(Performance Tuning)。

本篇範例包括 03_01_MNIST.ipynb,可自【這裡】下載。


上一篇
Day 02:梯度下降與自動微分
下一篇
Day 04:神經網路的效能調校(Performance Tuning)
系列文
輕鬆掌握 Keras 及相關應用30

尚未有邦友留言

立即登入留言