用Kaggle 經典案例教你用 CNN 做圖像分類!

2020-12-11 雷鋒網

雷鋒網按:本文原作者天雨粟,原文載於作者的知乎專欄——機器不學習,雷鋒網(公眾號:雷鋒網)經授權發布。

前言

在上一篇專欄中,我們利用卷積自編碼器對 MNIST 數據進行了實驗,這周我們來看一個 Kaggle 上比較經典的一個圖像分類的比賽 CIFAR( CIFAR-10 - Object Recognition in Images ),這個比賽現在已經關閉了,但不妨礙我們來去通過它學習一下卷積神經網絡做圖像識別的代碼結構。相信很多學過深度學習的同學都嘗試過這個比賽,如果對此比較熟悉的可以跳過本篇,如果沒有嘗試過的同學可以來學習一下哈。

整個代碼已經放在了我的 GitHub 上,建議可以把代碼 pull 下來,邊看文章邊看代碼。

GitHub 地址:NELSONZHAO/zhihu

如果覺得有幫助,麻煩點個 star 啦~

介紹

文章主要分為兩個部分,第一部分我們將通過一個簡單的 KNN 來實現圖像的分類,第二部分我們通過卷積神經網絡提升整個圖像分類的性能。

第一部分

提到圖像分類,我們可能會想到傳統機器學習中 KNN 算法,通過找到當前待分類圖像的 K 個近鄰,以近鄰的類別判斷當前圖像的類別。

由於我們的圖像實際上是由一個一個像素組成的,因此每一個圖像可以看做是一個向量,那麼我們此時就可以來計算向量(圖片)之間的距離。比如,我們的圖片如果是 32x32 像素的,那麼可以展開成一個 1x1024 的向量,就可以計算這些向量間的 L1 或者 L2 距離,找到它們的近鄰,從而根據近鄰的類別來判斷圖像的類別。

以下例子中 K=5。

下面我們就來用 scikit-learn 實現以下 KNN 對圖像的分類。

首先我們需要下載數據文件,網址為 https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 。我們數據包含了 60000 萬圖片,每張圖片的維度為 32 x 32 x 3,這些圖片都有各自的標註,一共分為了以下十類:

  • airplane

  • automobile

  • bird

  • cat

  • deer

  • dog

  • frog

  • horse

  • ship

  • truck

數據是被序列化以後存儲的,因此我們需要使用 Python 中的 pickle 包將它們讀進來。整個壓縮包解壓以後,會有 5 個 data_batch 和 1 個 test_batch。我們首先把數據加載進來:

我們定義了一個函數來獲取 batch 中的 features 和 labels,通過上面的步驟,我們就可以獲得 train 數據與 test 數據。

我們的每個圖片的維度是 32 x 32 x 3,其中 3 代表 RGB。我們先來看一些這些圖片長什麼樣子。

每張圖片的像素其實很低,縮小以後我們可以看到圖片中有汽車,馬,飛機等。

構造好了我們的 x_train, y_train, x_test 以及 y_test 以後,我們就可以開始建模過程。在將圖片扔進模型之前,我們首先要對數據進行預處理,包括重塑和歸一化兩步,首先將 32 x 32 x 3 轉化為一個 3072 維的向量,再對數據進行歸一化,歸一化的目的在於計算距離時保證各個維度的量綱一致。

到此為止,我們已經對數據進行了預處理,下面就可以調用 KNN 來進行訓練,我分別採用了 K=1,3,5 來看模型的效果。

從 KNN 的分類準確率來看,是要比我們隨機猜測類別提高了不少。我們隨機猜測圖片類別時,準確率大概是 10%,KNN 方式的圖片分類可以將準確率提高到 35% 左右。當然有興趣的小夥伴還可以去測試一下其他的 K 值,同時在上面的算法中,默認距離衡量方式是歐式距離,還可以嘗試其他度量距離來進行建模。

雖然 KNN 在 test 數據集上表現有所提升,但是這個準確率還是太低了。除此之外,KNN 有一個缺點,就是所有的計算時間都在 predict 階段,當一個新的圖來的時候,涉及到大量的距離計算,這就意味著一旦我們要拿它來進行圖像識別,那可能要等非常久才能拿到結果,而且還不是那麼的準。


第二部分

在上一部分,我們用了非常簡單的 KNN 思想實現了圖像分類。在這個部分,我們將通過卷積神經網絡來實現一個更加準確、高效的模型。

加載數據的過程與上一部分相同,不再贅述。當我們將數據加載完畢後,首先要做以下三件事:

  • 對輸入數據歸一化

  • 對標籤進行 one-hot 編碼

  • 構造訓練集,驗證集和測試集

對輸入數據歸一化

在這裡我們使用 sklearn 中的 minmax 歸一化。

首先將訓練數據集重塑為 [50000, 3072] 的形狀,利用 minmax 來進行歸一化。最後再將圖像重塑回原來的形狀。

對標籤進行 one-hot 編碼

同樣我們在這裡使用 sklearn 中的 LabelBinarizer 來進行 one-hot 編碼。

構造 train 和 val

目前我們已經有了 train 和 test 數據集,接下來我們要將加載進來的 train 分成訓練集和驗證集。從而在訓練過程中觀察驗證集的結果。

我們將訓練數據集按照 8:2 分為 train 和 validation。

卷積網絡

完成了數據的預處理,我們接下來就要開始進行建模。

首先我們把一些重要的參數設置好,並且將輸入和標籤 tensor 構造好。

img_shape 是整個訓練集的形狀,為 [40000, 32, 32, 3],同時我們的輸入形狀是 [batch_size, 32, 32, 3],由於前面我們已經對標籤進行了 one-hot 編碼,因此標籤是一個 [batch_size, 10] 的 tensor。

接下來我們先來看一下整個卷積網絡的結構:

在這裡我設置了兩層卷積 + 兩層全連接層的結構,大家也可以嘗試其他不同的結構和參數。

conv2d 中我自己定義了初始化權重為 truncated_normal,事實證明權重初始化對於卷積結果有一定的影響。

在這裡,我們來說一下 conv2d 的參數:

  • 輸入 tensor:inputs_

  • 濾波器的數量:64

  • 濾波器的 size:height=2, width=2, depth 默認與 inputs_的 depth 相同

  • strides:strides 默認為 1x1,因此在這裡我沒有重新設置 strides

  • padding:padding 我選了 same,在 strides 是 1 的情況下,經過卷積以後 height 和 width 與原圖保持一致

  • kernel_initializer:濾波器的初始化權重

在這裡講一下卷積函數中的兩種常見 padding 方式,分別是 valid,same。假設我們輸入圖片長和寬均為 h,filter 的 size 為 k x k,strides 為 s x s,padding 大小 = p。當 padding=valid 時,經過卷積以後的圖片新的長(或寬)為 ;當 padding=same 時,經過卷積以後 。但在 TensorFlow 中的實現與這裡有所區別,在 TensorFlow 中,當 padding=valid 時, ;當 padding=same 時,

其餘參數類似,這裡不再贅述,如果還不是很清楚的小夥伴可以去查看官方文檔。

在第一個全連接層中我加入了 dropout 正則化防止過擬合,同時加快訓練速度。

訓練模型

完成了模型的構建,下面我們就來開始訓練整個模型。

在訓練過程中,每 100 輪列印一次日誌,顯示出當前 train loss 和 validation 上的準確率。

我們來看一下最終的訓練結果:

上圖是我之前跑的一次結果,這次跑出來可能有所出入,但準確率大概會在 65%-70% 之間。

最後在 validation 上的準確率大約穩定在了 70% 左右,我們接下來看一下在 test 數據上的準確率。下面的代碼是在 test 測試準確率的代碼。

我們把訓練結果加載進來,設置 test 的 batchs_size 為 100,來測試我們的訓練結果。最終我們的測試準確率也基本在 70% 左右。

總結

至此,我們實現了兩種圖像分類的算法。第一種是 KNN,它的思想非常好理解,但缺點在於計算量都集中在測試階段,訓練階段的計算量幾乎為 0,另外,它的準確性也非常差。第二種我們利用 CNN 實現了分類,最終的測試結果大約在 70% 左右,相比 KNN 的 30% 準確率,它的分類效果表現的相當好。當然,如果想要繼續提升模型的準確率,就需要採用其他的一些手段,如果感興趣的小夥伴可以去看一下相關連結(http://rodrigob.github.io/are_we_there_yet/build/classification_datasets_results.html#43494641522d3130) 裡的技巧,Kaggle 上的第一名準確率已經超過了 95%。

如果覺得有用,請記得給 GitHub 打一個 Star,非常感謝!

雷鋒網版權文章,未經授權禁止轉載。詳情見轉載須知。

相關焦點

  • 圖像分類:13個Kaggle項目的經驗總結
    機器學習和圖像分類也不例外,工程師們可以通過參加像Kaggle這樣的競賽來展示最佳實踐。在這篇文章中,我將給你很多資源來學習,聚焦於從13個Kaggle比賽中挑選出的最好的Kaggle kernel。第二步是圖像預處理,目的是對原始圖像提高圖像數據(也稱為圖像特徵)的質量,通過抑制不必要的扭曲,縮放,增強重要的特徵,使數據更適合模型並提高性能。
  • 獨家 | kaggle季軍新手筆記:利用fast.ai對油棕人工林圖像進行快速分類(附代碼)
    這個權重從一個已經訓練好的圖像分類的resnet模型中直接獲得,無須擔心這種方法的細節。目前為止,我們正在構建一個以衛星圖像為輸入並輸出這兩種分類的預測概率模型。後續,會用它們來監控模型的改進。在第四個循環,得到了最佳的模型。
  • 圖像分類比賽中,你可以用如下方案舉一反三
    雷鋒網 AI 研習社按,在本文中,作者將向大家介紹其在 Kaggle 植物幼苗分類大賽(https://www.kaggle.com/c/plant-seedlings-classification)中所使用的解決方案。本文作者曾經位列該項賽事排行榜榜首達數月之久,並最終斬獲第五名。作者使用的方法普適性非常強,可以用於其它的圖像識別任務。
  • 手把手系列 | 教你用Python構建多標籤圖像分類模型(附案例)
    我們可以使用計算機視覺算法來做很多事情:對象檢測圖像分割圖像翻譯對象跟蹤(實時),還有更多……這讓我思考——如果一個圖像中有多個對象類別,我們該怎麼辦?製作一個圖像分類模型是一個很好的開始,但我想擴展我的視野以承擔一個更具挑戰性的任務—構建一個多標籤圖像分類模型!
  • 手把手教你用Python構建你的第一個多標籤圖像分類模型(附案例)
    本文明確了多標籤圖像分類的概念,並講解了如何構建多標籤圖像分類模型。介紹你正在處理圖像數據嗎?我們可以使用計算機視覺算法來做很多事情:對象檢測圖像分割圖像翻譯對象跟蹤(實時),還有更多……這讓我思考——如果一個圖像中有多個對象類別,我們該怎麼辦?
  • 有關藝術畫作分類的 Kaggle 比賽經驗分享
    在這個項目中,我將使用遷移學習和深度學習框架Keras對kaggle數據集中的不同藝術作品圖像進行分類。你將學到什麼!#3按類別將訓練圖像進行可視化。,以查看模型做得有多好!Python高級技巧:用一行代碼減少一半內存佔用等你來譯:雷鋒網預訓練模型及其應用 一文帶你讀懂線性分類器 (
  • 全面拆解Kaggle經典案例,100%實戰
    你可能會想,為什麼每次都找不到讓自己滿意的工作?而別人卻可以。因為你在面試的時候,需要有一段優秀的項目實戰經驗放在簡歷裡,更需要用一個完善的項目經驗,來歸納總結那些零零散散學到的內容,實打實地感受到自己掌握的技能。更重要的是,擁有一個完善的項目實戰的經驗能幫你更深層次的加深理解,並在求職過程中,取得一個「質的飛躍」。
  • 獨家 | 手把手教你用Python構建你的第一個多標籤圖像分類模型(附案例)
    本文明確了多標籤圖像分類的概念,並講解了如何構建多標籤圖像分類模型。介紹你正在處理圖像數據嗎?我們可以使用計算機視覺算法來做很多事情:對象檢測圖像分割圖像翻譯對象跟蹤(實時),還有更多……這讓我思考——如果一個圖像中有多個對象類別,我們該怎麼辦?
  • 手把手教你用PyTorch實現圖像分類器(第一部分)
    經過幾個月富有挑戰性但是受益良多的學習,我最近從Udacity的Python Nanodegree program AI編程專業畢業。最後一個項目是用PyTorch創建一個102種不同類型的花的圖像分類器。
  • Kaggle創始人Goldbloom:我們是這樣做數據科學競賽的
    以下Anthony Goldbloom的最新演講,文摘菌做了有刪改的整理~Kaggle聚集了大量的機器學習的專家以及大數據的專家最,截止到目前為止,差不多是有250萬人了,在演講的最開始,首先介紹一下我們在kaggle的工作。然後給大家說一下我們在kaggle學到的一些經驗。
  • 競賽實戰|kaggle圖像分類Doodle Recognition Challenge總結
    作者:SMON連結:https://zhuanlan.zhihu.com/p/54172633來源:知乎,已通過作者授權,未經允許不得二次轉載「該比賽大多數人的做法是採用圖像分類方法,本文也是基於此。簡單來說,梯度累積就是累積多個batch的梯度然後一次更新參數,而不是常用的一個batch更新一次,親測在小數據集上是有效果提升的(本次比賽數據集size很大,但我也用了這個trick,沒有和不用這個trick做比較)。
  • 簡單到出人意料的CNN圖像分類策略
    ,對自然圖像進行分類。 在深度學習出現之前,自然圖像中的對象識別過程相當粗暴簡單:定義一組關鍵視覺特徵(「單詞」),識別每個視覺特徵在圖像中的存在頻率(「包」),然後根據這些數字對圖像進行分類。BagNets的分類策略:對於每個補丁,我們使用DNN提取類證據(logits)並總結所有補丁的總類證據為了以最簡單和最有效的方式實現這一策略,我們採用標準的ResNet-50架構,用1x1卷積替換大多數(但不是全部)3x3卷積。
  • 手把手教你在小數據集下使用Keras進行圖像分類
    AI 前線導讀:這是一篇實戰類的文章,旨在向讀者介紹計算機視覺的外圍應用:圖像分類問題。現在我們翻譯了 Rising Odegua 這篇基於 keras 進行圖像分類的文章。在本文,作者介紹了如何在數據集較小的情況下,如何使用 keras 進行圖像分類。
  • 圖像分類入門,輕鬆拿下90%準確率|教你用Keras搞Fashion-MNIST
    原作 Margaret Maynard-Reid王小新 編譯自 TensorFlow的Medium量子位 出品 | 公眾號 QbitAI這篇教程會介紹如何用TensorFlow裡的tf.keras函數,對Fashion-MNIST數據集進行圖像分類
  • 海康威視提出:無監督圖像分類的深度表徵學習
    文章首先講了下deep clustering 相比self-supervised learning而言是一個比較有前途的方向,但是做cluster的時候需要對embedding(feature map)做clustering對於數據集很大的情況下是非常消耗資源的(因為你需要把所有dataset對應的embedding都存起來),所以這篇文章主要就是提供了一個更加簡單和優雅的框架來做這個事情
  • OpenCV入門及應用案例:手把手教你做DNN圖像分類
    近些年添加的opencv/open_model_zoo倉庫也增加了很多預訓練好的深度學習模型,這些模型大多做過性能和速度上的調優。OpenCV是一個自包含庫,可以不依賴於任何第三方庫而運行,這個特性給開發調試帶來了很大的便利。另外,OpenCV還提供了硬體加速功能,使得算法能夠在各種平臺高效地執行。下面以一個識別性別和年齡的深度學習應用為例,展現OpenCV深度學習應用的典型流程。
  • CNN圖像分類:從LeNet5到EfficientNet
    Author:louwillFrom:深度學習筆記在對卷積的含義有了一定的理解之後,我們便可以對CNN在最簡單的計算機視覺任務圖像分類中的經典網絡進行探索CNN在近幾年的發展歷程中,從經典的LeNet5網絡到最近號稱最好的圖像分類網絡EfficientNet,大量學者不斷的做出了努力和創新。本講我們就來梳理經典的圖像分類網絡。自從神經網絡和深度學習方法引入到圖像領域,經過近些年來的發展,從一開始的圖像分類逐漸延伸到目標檢測和圖像分割領域,深度學習也逐漸在計算機視覺領域佔據絕對的主導地位。
  • 用於圖像分割的卷積神經網絡:從R-CNN到Mask R-CNN
    雖然這些結果令人印象深刻,但與真實的人類視覺理解的多樣性和複雜性相比,圖像分類還是簡單得多。分類挑戰賽使用的圖像實例。注意圖像的構圖以及對象的唯一性。在分類中,圖像的焦點通常是一個單一目標,任務即是對圖像進行簡單描述(見上文)。但是當我們在觀察周遭世界時,我們處理的任務相對複雜的多。
  • 參加了39場Kaggle比賽之後,有人總結了圖像分割煉丹的奇技淫巧
    Derrick Mwiti 就帶頭做了這麼一件事,他和他所在的團隊將過去 39 場 Kaggle 比賽中討論過的圖像分割技巧、資料都匯總到了一起,希望可以幫到在圖像分割任務中遇到困難的同學。這份列表分為十大板塊,包括外部數據、預處理、數據增強、建模、硬體配置、損失函數、訓練技巧、評估和交叉驗證、集成方法以及後處理。
  • 圖像分類入門,輕鬆拿下90%準確率 | 教你用Keras搞定Fashion-MNIST
    裡的tf.keras函數,對Fashion-MNIST數據集進行圖像分類。只需幾行代碼,就可以定義和訓練模型,甚至不需要太多優化,在該數據集上的分類準確率能輕鬆超過90%。進入正題,教你用tf.keras完成Fashion-MNIST數據集的圖像分類~運行環境無需設置,只要使用Colab直接打開這個Jupyter Notebook連結,就能找到所有代碼。