---
# System prepended metadata

title: Untitled

---

【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

