對DL初學者而言,最常用來測試的大概就是MNIST跟CIFAR-10這兩個數據集了。或許對大神們來說不過都是些玩具,但我認為CIFAR-10不只是個toy dataset,相較於MNIST那樣使用MLP就能輕易達到近乎99%辨識準確率的灰階影像,CIFAR-10不像"Hello World!"這麼容易吧?🤨
關於CIFAR-10數據集,像我這樣略懂略懂的人就不贅言了,網路上介紹CIFAR-10的文章很多。不過,當我爬了許多文章之後,大致上都是介紹數據集和使用簡單的CNN來測試而已(準確率約70%),如何對現有模型結構優化並提升CIFAR-10準確率還是沒頭緒,雖然可以直接載入Keras內建的預訓練模型,例如VGG-16、ResNet-50,但我認為那樣做沒啥意思,根本上還是沒搞懂,也像是大砲打小鳥。
Keras Sample Code
看一下Keras的範例程式,根據頁面說明,該範例於訓練50 epochs後達到79%的驗證準確率。實際訓練了100 epochs也差不多。
Model Summary
Train History
More Optimization
就Keras範例來說,我嘗試以相同結構增加其網路深度,驗證準確率有得到些微提升(約82%),但持續盲目地加深網路卻會造成反效果。後來我找到了Jason Brownlee博士的教學,那是一個很棒的tutorial,嘗試對模型結構進行優化後,訓練結果在測試數據集取得89%的準確率(Train / Test : 94.60% / 89.35%)。
Model Summary
Train History
Fractional Max-Pooling
在優化了模型結構後,測試準確率依然無法突破90%,因此我搜尋了state-of-the-art on CIFAR-10,看看大神們超脫凡俗的思路究竟是如何突破問題。於是我仔細閱讀了Fractional Max-Pooling這篇論文,並實際應用到我的模型訓練,儘管我沒有使用和原始論文實驗中同樣深的網路結構,依然在測試數據集的準確率達到了93%(Train / Test : 97.94% / 93.55%)。順帶一提,該模型在我的GTX 1660 Super訓練600 epochs需耗費30個小時左右。
關於Fractional Max-Pooling的實現,TensorFlow已有內建,而Keras可以利用Lambda來引入模型中使用:
def frac_max_pool(x):
return tf.nn.fractional_max_pool(x, [1.0, 1.41, 1.41, 1.0], pseudo_random=True, overlapping=True)[0]
model.add(Lambda(frac_max_pool))
Model Summary
Train History
Comparison
對參數量和模型大小做個比較:
VGG-16/VGG-19 | VGG-like + FMP | |
---|---|---|
total params | 10M+ | 1.5M |
model size | 200+ MB | 12.4 MB |
Source Code
https://github.com/laplacetw/vgg-like-cifar10
*2020/12/07 發現被PapersWithCode社群收錄了。