【AutoKeras 自動化機器學習:隨手解 Dogs vs. Cats 影像辨識】
![](https://i.imgur.com/Kbo26EB.png)
上回我們看到 AutoKeras 的 ImageClassifier 類別如何對 MNIST 手寫數字資料集和 CIFAR-10 影像資料集產生高準確率的預測模型,這些也是我們書上實際展示的範例。不過這兩個資料集有個缺點:圖片實在太小了。美編之前還跟小編說,這圖是不是截得不夠清楚哇?(笑)
所以今天我們來看另一個範例:資料科學競賽網站 Kaggle 上的 Dogs vs. Cats Redux (https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/overview),是練習性質的競賽,當中的訓練集包含貓和狗的照片總共25,000 張,測試集則有無標籤的貓狗照片 12,500 張,每張圖的長寬至少有 100 像素以上,也不太需要做太多的預處理,相當適合今天的展示目的。
![](https://i.imgur.com/KTbeXic.png)
這資料集其實出自微軟和寵物領養網站 Petfinder.com 在 2007 年合作的 Asirra (https://www.microsoft.com/en-us/download/details.aspx?id=54765),也就是一個要求使用者分辨貓狗圖片來證明自己是真人的 CAPTCHA 工具,因為當時對機器來說,區分貓狗比解讀數字難多了。不過,如今你能否用神經網路『破解』它呢?
當然可以,不過目前 Kaggle 上多數的最佳解法都牽涉到模型調校、使用額外資料集或結合多重模型的技巧。在此我們要來看看,若你完全只使用 ak. ImageClassifier 的懶人訓練法能做到怎樣的程度。
以下的訓練是在小編自己的電腦進行,配有 GTX 1660 Ti 加速卡 (6G 記憶體),訓練時間約為半天。只要在電腦上安裝 NVIDIA 驅動程式和 CUDA 函式庫,AutoKeras 在訓練時就會自動使用 GPU。
(得注意的是,假如資料集非常龐大,那麼有可能訓練到某個模型時會因顯卡記憶體不足而當掉。通常用顯卡工具程式清一下記憶體、再重跑一次訓練,AutoKeras 會讀取硬碟中的記錄,從之前中斷的地方繼續。一般 AutoKeras 會根據記憶體自動調整訓練批量 (batch size),但你也可以自行指定,好預防記憶體不足問題。)
====================
1. 首先下載 Kaggle 提供的資料集,訓練集在 train 目錄下,測試集在 test 目錄下。
由於訓練集的貓狗圖片剛好一半一半,為了後面讀取方便,我們在 train 底下建 cat 和 dog 子目錄,然後把對應的圖片拖進去:
```
\train
\cat
\dog
```
至於測試集,Kaggle 上沒有給答案,所以我們通通把圖片丟進 test 子目錄:
```
\test
\test
````
2. 匯入套件:
```
import autokeras as ak
import tensorflow as tf
```
```
train = ak.image_dataset_from_directory('./train', image_size=(200, 200))
test = ak.image_dataset_from_directory('./test', image_size=(200, 200))
```
```
``
clf = ak.ImageClassifier(max_trials=3)
clf.fit(train, callbacks=[tf.keras.callbacks.EarlyStopping(patience=3)])
```
```
Trial 3 Complete [04h 36m 47s]
val_loss: 0.02502167783677578
Best val_loss So Far: 0.02502167783677578
Total elapsed time: 06h 51m 16s
INFO:tensorflow:Oracle triggered exit
Epoch 1/6
Not enough memory, reduce batch size to 16.
Epoch 1/6
Not enough memory, reduce batch size to 8.
Epoch 1/6
Not enough memory, reduce batch size to 4.
Epoch 1/6
6250/6250 [==============================] - 2113s 338ms/step - loss: 0.1483 - accuracy: 0.9423
Epoch 2/6
6250/6250 [==============================] - 2100s 336ms/step - loss: 0.0230 - accuracy: 0.9924
Epoch 3/6
6250/6250 [==============================] - 2101s 336ms/step - loss: 0.0111 - accuracy: 0.9966
Epoch 4/6
6250/6250 [==============================] - 2090s 334ms/step - loss: 0.0088 - accuracy: 0.9972
Epoch 5/6
6250/6250 [==============================] - 2241s 359ms/step - loss: 0.0068 - accuracy: 0.9978
Epoch 6/6
6250/6250 [==============================] - 2087s 334ms/step - loss: 0.0067 - accuracy: 0.9978
INFO:tensorflow:Assets written to: .\image_classifier\best_model\assets
```
```
第一個預設模型 (雙層 CNN) 的最佳損失值約為 0.4,第二個預設模型 (ResNet50) 約為 0.16,而第三個 EfficientNet B7 則是 0.025。三個模型訓練完畢後,AutoKeras 自動選擇表現最佳的三號模型,並合併訓練集和驗證集來訓練最後一次。
以往在 Keras 中,我們可能得使用 ModelCheckpoint 回呼函式來記錄最佳模型,並在訓練結束後重新載入其權重。不過在 AutoKeras 就不須這麼做了,因為它會記得候選模型在訓練幾周期時表現最好。
由上可見,模型對訓練集的準確率達到 99.78%,損失值為 0.0067。
5. 將模型匯出為 Keras 模型並檢視摘要:
```
model = clf.export_model()
model.summary()
```
這會印出
Model: "model"
![](https://i.imgur.com/D03Vtr8.jpg)
6. 由於測試集沒有解答,我們來對其圖片產生預測結果,以便稍後跟圖片比對:
```
predicted = clf.predict(test)
predicted
```
產生結果如下:
```
array([['cat'],
['dog'],
['dog'],
...,
['dog'],
['dog'],
['dog']], dtype='<U3')
```
可見模型產生的預測結果不是 0 或 1,而是字串 ‘cat’ 與 ‘dog’。
7. 下面我們便用 matplotlib 將前 40 張測試集圖片跟其預測標籤畫出來 (由於 test 是 tf.data.Dataset 物件,走訪上比較麻煩一點):
```
import matplotlib.pyplot as plt
count = 40
i = 0
fig = plt.figure(figsize=(10, 16))
for batch in test.as_numpy_iterator():
for img in batch[0]:
ax = fig.add_subplot(8, 5, i + 1)
ax.set_title(f'Predicted: {predicted[i][0]}')
ax.set_axis_off()
plt.imshow(img / 255)
i += 1
if i >= count:
break
else:
continue
break
plt.tight_layout()
plt.show()
```
![](https://i.imgur.com/LySAJsK.jpg)
這個結果取決於tf.data.Dataset 物件的讀取順序,你看到的可能會略有不同。
8. 那麼,模型拿來預測其他圖片的成效如何呢?由於 Dogs vs. Cats Redux 競賽以及網路上許多範例都會顯示貓與狗的預測機率,而不是單獨的預測分類,所以我們要改用前面匯出的 Keras 模型,它的預測結果就是機率而不是特定標籤:
```
import cv2
import numpy as np
img_original = []
img = []
for i in range(4):
new_image = cv2.cvtColor(cv2.imread(f'./test{i+1}.jpg'), cv2.COLOR_BGR2RGB)
img_original.append(new_image)
img.append(cv2.resize(new_image, (200, 200)))
new_test = np.array(img)
new_predicted = model.predict(new_test).flatten()
new_predicted
```
我們在同目錄下放了四張測試圖片,test1.jpg~test4.jpg。我們使用 OpenCV 讀取它、保留一份原始圖檔,並產生大小調整為 200 x 200 的新圖檔 (匯出的 Keras 模型會需要你提供相符大小的圖片),以此產生預測值:
`array([0.00111161, 0.99979526, 0.09952653, 0.8113645 ], dtype=float32)`
由於貓狗資料集等於只有分類 0 (貓) 和 1 (狗),這種二元分類相當於正負,因此 Keras 模型傳回的是『分類為正 (1=狗) 的機率』。例如,第一筆預測值是 0.0011,這表示模型認為它是狗的機率為 0.11%,貓的機率就是 1 - 0.0011 = 0.9989 (99.89%)。
9. 下面我們將這四張圖片和其兩個分類的預測機率都畫出來:
```
fig = plt.figure(figsize=(10, 8))
for i in range(4):
ax = fig.add_subplot(2, 2, i+1)
plt.imshow(img_original[i])
ax.set_title(f'Dog: {new_predicted[i]*100:.3f}%\nCat: {(1-new_predicted[i])*100:.3f}%')
ax.set_axis_off()
plt.tight_layout()
plt.show()
```
![](https://i.imgur.com/wYdOagl.png)
最上面兩張是小編在路邊拍的。
至於下面兩張…所以《貓》的主角真的是貓無誤,而熊吉是狗嗎?XD
10. 最後,雖然這篇的目的不是在比賽,不過我們還是可以產生一份符合競賽要求的輸出結果:
```
import pandas as pd
img = []
for i in range(12500):
new_image = cv2.cvtColor(cv2.imread(f'./test/test/{i+1}.jpg'), cv2.COLOR_BGR2RGB)
img.append(cv2.resize(new_image, (200, 200)))
test = np.array(img)
predicted = model.predict(test).flatten()
submission = pd.DataFrame({'id': np.arange(predicted.size)+1, 'label': predicted})
submission
```
為了確保圖片能按正確順序預測 (前面的 tf.data.Dataset 物件不保證這種順序),我們再次用 OpenCV 讀一讀取檔案,丟給模型產生預測值,然後把圖片 id 和預測結果 (分類 1 的機率) 轉成 pandas.DataFrame:
```
id label
0 1 0.999999
1 2 0.999980
2 3 1.000000
3 4 1.000000
4 5 0.000031
... ... ...
12495 12496 0.000001
12496 12497 0.000763
12497 12498 1.000000
12498 12499 1.000000
12499 12500 0.001510
12500 rows × 2 columns
```
11. 最後將 DataFrame 輸出為 CSV 檔並上傳 Kaggle:
`submission.to_csv('./submission.csv', index=False)`
![](https://i.imgur.com/1IBkhpr.png)
此競賽的計分方式是拿你的結果跟正確結果比對,並算出 log loss,值越低越好。(log loss 必須透過機率計算,所以若你的預測值四捨五入為整數 0 或 1,那麼 log loss 就會暴增)。我們得到 0.078,在五年前的排行榜 (1,314 組參賽者) 大概能排到 200 多名。
雖然看起來好像還好,但請記得:在完全沒有做額外預處理 (訓練集中其實有 52 張標錯分類的圖,而且還有不是貓或狗的圖)、沒有提供額外資料、模型微調或跟使用集成式學習,而且還用 EarlyStopping 縮短訓練時間的前提下,這模型的預測準確率已經相當高了,建模部分則一樣只用了 3 行程式而已。若你擁有足夠的運算資源 (例如 NVIDIA P100/V100 加速卡) 和時間,你就能讓 AutoKeras 繼續搜尋模型來試著改良它。
在書中的第 8 章,也會提到如何在同一個 AutoKeras 中建立多重模型。你可以拿同一份資料產生多個預測結果,或者讓多重模型預測同一個結果。這些都有機會讓你進一步提高那百分之零點幾的預測率。
![https://pse.is/3yhe9q](https://i.imgur.com/wcduRnr.jpg)
想了解更多《AutoML 自動化機器學習:用 AutoKeras 超輕鬆打造高效能 AI 模型》
博客來 → https://pse.is/3yhe9q