編者按: 選自Medium 機器之心編譯 參與:蔣思源、黃小天、吳攀
項目地址:https://github.com/Fdevmsy/Image_Classification_with_5_methods 圖像分類,顧名思義,就是為輸入圖像打上固定類別的標簽。這是計算機視覺領(lǐng)域的核心問題之一。盡管聽起來很簡單,但圖像分類有大量不同的實際應用。 傳統(tǒng)方式:特征描述和檢測 也許對一些樣本任務有好處,但實際情況要復雜得多。 因此,我們并沒有通過代碼的形式直接指出每一類型的外觀(visual appearance),而是使用機器學習——為計算機提供每一類的諸多實例,接著開發(fā)學習算法觀察這些實例,并學習每一類的外觀。 然而,圖像分類如此復雜,以至于其處理經(jīng)常用到深度學習模型,比如 CNN(卷積神經(jīng)網(wǎng)絡)。我們已經(jīng)知道,我們在課堂上學習的不少算法(如 KNN、SVM)通常很擅長數(shù)據(jù)挖掘;但是對于圖像分類,它們卻不是最佳選擇。 因此,我們將對課堂中學到的以及 CNN 和遷移學習等算法做一個對比。 目標 我們的目標是: 1. 把 KNN、SVM、BP 神經(jīng)網(wǎng)絡與業(yè)界處理圖像識別問題的算法——CNN 和遷移學習——進行對比。 2. 獲得深度學習經(jīng)驗。 3. 通過 TensorFlow 探索機器學習框架。 系統(tǒng)設(shè)計 & 實現(xiàn)細節(jié) 算法與工具 本項目使用的 5 個方法是 KNN、SVM、BP 神經(jīng)網(wǎng)絡、CNN 和遷移學習。 全項目可分為 3 類方法:
實現(xiàn) 第一類方法:預處理數(shù)據(jù)集,并使用 sklearn 實現(xiàn) KNN、SVM、BP 神經(jīng)網(wǎng)絡。 首先,我們使用 OpenCV 包定義了 2 個不同的預處理函數(shù):第一個是圖像到特征向量,它可以重調(diào)圖像大小,并把圖像轉(zhuǎn)化為行像素列表;第二個是提取顏色直方圖,即使用 cv2.normalize 從 HSV 顏色空間提取 3D 顏色直方圖,并平化(flatten)結(jié)果。 接著,建構(gòu)若干個我們需要解析的參數(shù)。由于想要同時測試整個數(shù)據(jù)集和帶不同數(shù)量標簽的子數(shù)據(jù)集的精確度,我們構(gòu)建了一個作為參數(shù)的數(shù)據(jù)集并解析進我們的程序。我們同樣構(gòu)建了用于 k-NN 方法的鄰元素數(shù)作為解析參數(shù)。 之后,我們開始提取數(shù)據(jù)集中的每一圖像特征,并將其放入數(shù)組。我們使用 cv2.imread 讀取每一圖像,通過從圖像名稱中提取字符串來拆分標簽。在我們的數(shù)據(jù)集中,我們使用相同格式——類別標簽. 圖像序號.jpg——設(shè)置名稱,因此我們可以輕易提取每張圖像的分類標簽。接著我們使用這兩個函數(shù)提取 2 種特征并附加到數(shù)組 rawImages,而之前提取的標簽附加到數(shù)組標簽。 下一步是使用從 sklearn 包導入的函數(shù) train_test_split 拆分數(shù)據(jù)集。這個集具有后綴 RI,RL 是 rawImages 和標簽對的拆分結(jié)果,另一個是特征和標簽對的拆分結(jié)果。我們使用 85% 的數(shù)據(jù)集作為訓練集,余下的 15% 作為測試集。 最后,我們應用 KNN、SVM、BP 神經(jīng)網(wǎng)絡函數(shù)評估數(shù)據(jù)。對于 KNN 我們使用 KNeighborsClassifier,對于 SVM 我們使用 SVC,對于 BP 神經(jīng)網(wǎng)絡我們使用 MLPClassifier。 第二類方法:使用 TensorFlow 構(gòu)建 CNN。TensorFlow 的全部目的在于使你打造一張計算圖(使用 Python 等語言),接著在 C++ 中執(zhí)行該圖(在相同計算量的情況下,C++比 Python 更高效)。 TensorFlow 也可自動計算優(yōu)化圖變量所需的梯度,從而使模型表現(xiàn)更好。這是由于該圖由簡單的數(shù)學表達式組合而成,因此可通過導數(shù)鏈式法則計算全圖的梯度。 一張 TensorFlow 圖包含以下幾個部分,每一部分將在下文詳述:
因此,在我們的實現(xiàn)中,第一層是保存圖像,接著我們使用 2 x 2 最大池化和修正線性單元(ReLU)的構(gòu)建 3 個卷積層。輸入是 4 維張量:
輸出是另一個 4 維張量:
接著,我們我們在網(wǎng)絡末端構(gòu)建了 2 個全連接層。輸入是一個 2 維的形狀張量 [num_images、num_inputs]。輸出也是一個 2 維的形狀張量 [num_images、num_outputs] 然而,為了連接卷積層和全連接層,我們需要一個平層(Flatten Layer)以把 4 維向量減少至可輸入到全連接層的 2 維。 CNN 末端通常是一個 softmax 層,它可歸一化來自全連接層的輸出,因此每一元素被限制在 0 與 1 之間,并且所有元素總和為 1。 為了優(yōu)化訓練結(jié)果,我們需要一個成本衡量標準并在每次迭代中將成本降至最少。這里我們使用的成本函數(shù)是交叉熵(tf.nn.oftmax_cross_entropy_with_logits()),并在所有的圖像分類中取交叉熵的平均值。優(yōu)化方法是 tf.train.AdamOptimizer(),它是梯度下降的高級形式。這是一個可被調(diào)節(jié)的參數(shù)學習率。 第三種方法:再訓練 Inception V3?,F(xiàn)代目標識別模型有數(shù)以百萬計的參數(shù),并可能需要花費數(shù)周的時間才能完全訓練一個模型。遷移學習是一種采用在分類數(shù)據(jù)集(如 ImageNet)中已訓練的模型而快速完成這一工作的方法,因為其只需要重新訓練新類別的權(quán)重就行。雖然這樣的模型并沒有完全訓練的模型表現(xiàn)好,但對于許多應用來說,這是非常高效的,因為其不需要 GPU 并可以在筆記本上花半個小時就完成訓練。 讀者可以點擊一下鏈接進一步了解遷移學習的訓練過程:https://www./tutorials/image_retraining 首先我們需要獲取預訓練模型,并移除舊的頂層神經(jīng)網(wǎng)絡,然后再基于我們的數(shù)據(jù)集重新訓練一個輸出層。雖然貓的所有品種并沒有在原始 ImageNet 數(shù)據(jù)集和全訓練的模型中體現(xiàn),但遷移學習的神奇之處就在于其可以利用已訓練模型用來識別某些目標的底層特征,因為底層特征可以在很多不更改的情況下應用于很多識別任務。然后我們分析本地的所有圖片并計算每張的瓶頸值(bottleneck values)。因為每張圖片在訓練過程中重復使用了多次,所以計算每個瓶頸值需要花費大量時間,但我們可以加快緩存這些瓶頸值,也就可以省去重復的計算。 該腳本將運行 4000 次訓練步。每一步從訓練集中隨機選擇 10 張圖片,并從緩存中搜索其瓶頸值,然后再將它們訓練最后一層以得到預測。這些預測會通過對比真實標注值而通過反向傳播過程更新最后一層的權(quán)重。 實驗 數(shù)據(jù)集 Oxford-IIIT Pet 數(shù)據(jù)集:http://www.robots./~vgg/data/pets/ 該數(shù)據(jù)集有 25 種狗和 12 種貓。每一種類別有 200 張相片。我們在該項目中只會使用 10 種貓。 在該項目中我們用的類別為 [斯芬克斯貓、暹羅貓、布偶貓、波斯貓、緬因貓、英國短毛貓、孟買貓、伯曼貓、孟加拉豹貓、阿比西尼亞貓]。 因此在數(shù)據(jù)集中我們總共有 2000 張圖片。雖然圖片的尺寸是不同的,但我們可以調(diào)整為固定的大小如 64x64 或 128x128。 預處理 在該項目中,我們主要使用 OpenCV 對圖片進行預處理,如讀取圖片放入陣列或調(diào)整為我們需要的大小等。 提升圖像訓練結(jié)果的一個常用方法就是對訓練輸入隨機進行變形、裁剪或亮度調(diào)整處理。由于采用了同一圖片所有可能的變體,該方法不僅具有擴展有效訓練數(shù)據(jù)大小的優(yōu)點,同時還傾向幫助網(wǎng)絡使用分類器學習處理所有在現(xiàn)實生活中可能出現(xiàn)的畸變。 具體請查看:https://github.com/aleju/imgaug. 評估 第一個方法:第一部分為預處理數(shù)據(jù)集和使用 sklearn 應用 KNN、SVM 和 BP 神經(jīng)網(wǎng)絡。 在程序中有很多參數(shù)可以調(diào)整:在 image_to_feature_vector 函數(shù)中,我們設(shè)置的圖片尺寸為 128x128,我們之前也嘗試過使用其他尺寸(如 8x8、 64x64、256x256)進行訓練。我們發(fā)現(xiàn)雖然圖片的尺寸越大效果越好,但大尺寸的圖片同樣也增加了執(zhí)行時間和內(nèi)存需求。因此我們最后決定使用 128x128 的圖片尺寸,因為其并不太大,同時還保證了準確度。 在 extract_color_histogram 函數(shù)中,我們將每個通道的二進制值設(shè)置為 32,32,32。在先前的函數(shù)中,我們還嘗試了 8, 8, 8 和 64, 64, 64。雖然更高的數(shù)值能有更優(yōu)的結(jié)果,但同時也要求更長的執(zhí)行時間,因此我們認為 32,32,32 是比較合適的。 對于數(shù)據(jù)集,我們訓練了 3 種。第一種是有 400 張圖片、2 種標注的子數(shù)據(jù)集。第二種是有 1000 張圖片、5 種標注的子數(shù)據(jù)集。最后一種是有 1997 張圖片、10 種標注的全數(shù)據(jù)集。我們將不同的數(shù)據(jù)集解析為程序中的參數(shù)。 在 KNeighborsClassifier 中,我們只改變近鄰的數(shù)量并儲存每一種數(shù)據(jù)集最優(yōu) K 值的分類結(jié)果。其他所有參數(shù)都設(shè)為默認。 在 MLPClassifier 中,我們設(shè)置每一個隱藏層有 50 個神經(jīng)元。我們確實測試了多個隱藏層,但好像對最后的結(jié)果沒有明顯的變化。最大的迭代次數(shù)設(shè)置為 1000,并且為了確保模型能夠收斂,我們?nèi)萑滩钤O(shè)置為 1e-4。同時還需要設(shè)置 L2 罰項的參數(shù) alpha 為默認值,隨機狀態(tài)為 1,求解器設(shè)置為學習速率為 0.1 的「sgd」。 在 SVC 中,最大迭代次數(shù)為 1000,類別權(quán)重設(shè)置為「balanced」。 我們程序的運行時間并不會太久,對于我們的三種數(shù)據(jù)集大概分別花 3 到 5 分鐘左右。 第二種方法:使用 TensorFlow 構(gòu)建 CNN 使用整個大數(shù)據(jù)集會需要很長的時間計算模型的梯度,因此我們在優(yōu)化器每一次迭代中都只使用小批量的圖片更新權(quán)重,批量大小一般是 32 或 64。該數(shù)據(jù)集分為包含 1600 張圖片的訓練集、包含 400 張圖片的驗證集和包含 300 張圖片的測試集。 該模型同樣有許多參數(shù)需要調(diào)整。 首先是學習率。優(yōu)良的學習率因為其足夠小而很容易令模型收斂,同時又足夠大令模型的收斂速度不至于太慢。所以我們選擇了 1 x 10^-4。 第二個需要調(diào)整的參數(shù)是投入到網(wǎng)絡的圖片尺寸。我們訓練了 64x64 和 128x128 兩種圖片尺寸,結(jié)果表明尺寸越大模型精度就越高,但代價是運行時間會更長。 然后是神經(jīng)網(wǎng)絡層級數(shù)和它的形狀。然而實際上由于這一方面有太多的參數(shù)可以調(diào)整,所以很難在所有的參數(shù)間找到一個最優(yōu)值。 根據(jù)網(wǎng)上的很多資源,我們發(fā)現(xiàn)對于構(gòu)建神經(jīng)網(wǎng)絡,參數(shù)的選擇很大一部分都是根據(jù)已有的經(jīng)驗。 最開始,我們希望構(gòu)建相當復雜的神經(jīng)網(wǎng)絡,其所采用的參數(shù)如下:
我們采用 3 個卷積層和 2 個全連接層,它們的結(jié)構(gòu)都比較復雜。 然而,我們的結(jié)果是:過擬合。對于這樣的復雜網(wǎng)絡,訓練精度在迭代一千次后就達到了 100%,但測試精度僅僅只有 30%。最開始,我們十分疑惑為什么模型會過擬合,然后開始隨機調(diào)整參數(shù),但這時候模型的表現(xiàn)卻又變好了。幸好幾天后我碰巧讀到了 Google 在討論深度學習的一篇文章:https:///@blaisea/physiognomys-new-clothes-f2d4b59fdd6a 該文章指出他們所主導的項目是有問題的:「一個技術(shù)性的問題是如果少于 2000 個樣本,那么其是不足以訓練和測試如同 AlexNet 那樣的卷積神經(jīng)網(wǎng)絡而不出現(xiàn)過擬合情況。」所以我才意識到我們的數(shù)據(jù)集實在是太小了,而網(wǎng)絡構(gòu)架又太復雜,這才產(chǎn)生了過擬合現(xiàn)象。 我們的數(shù)據(jù)集正好包含 2000 張圖片 因此,我開始減少神經(jīng)網(wǎng)絡的層級數(shù)和核函數(shù)的大小。我嘗試調(diào)整了很多參數(shù),以下是我們最后使用的神經(jīng)網(wǎng)絡架構(gòu)參數(shù):
我們僅僅使用 2 個小型的卷積層和 2 個全連接層。訓練結(jié)果并不好,在迭代 4000 次后同樣出現(xiàn)了過擬合現(xiàn)象,但測試精度還是要比前面的模型高 10%。 我們?nèi)匀辉趯ふ医鉀Q的辦法,然而一個顯然易見的原因是我們的數(shù)據(jù)集實在是太小了,我們也沒有足夠的時間做更多的改進。 作為最后的結(jié)果,我們在 5000 次迭代后大概實現(xiàn)了 43% 的精度,該訓練花了一個半小時。實際上,我們對這一結(jié)果比較沮喪,因此我們準備使用另一標準數(shù)據(jù)集 CIFAR-10。 CIFAR-10 數(shù)據(jù)集由 60000 張 32x32 10 類彩色圖片,每一個類別都有 6000 張圖片。該數(shù)據(jù)集包含了 50000 張訓練集和 10000 張測試集。 我們使用了和上面相同的神經(jīng)網(wǎng)絡架構(gòu),在 10 小時的訓練后,我們在測試集上實現(xiàn)了 78% 的準確度。 第三種方法:再訓練 Inception V3,我們隨機選取一些圖片進行訓練,而另一批圖片用于驗證。 該模型同樣有許多參數(shù)需要調(diào)整。 首先是訓練步,默認值是 4000 步。我們也可以根據(jù)情況增加或減少以盡快獲得一個可接受的結(jié)果。 隨后是學習率,該參數(shù)控制了在訓練期間更新至最后一層的量級。直觀地說,如果學習速率小,那么需要更多的時間進行學習,但最終其可能收斂到更優(yōu)的全局精度。訓練批量大小控制了在一個訓練步中檢查圖片的多少,又因為學習率應用于每一個批量,如果能以更大的批量獲得相似的全局效果,我們需要減少它。 因為深度學習任務所需要的運行時間通常很長,所以我們并不希望模型在訓練幾小時后實際上表現(xiàn)很糟糕。所以我們需要經(jīng)常獲得驗證精度的報告。這樣我們同樣可以避免過擬合。數(shù)據(jù)集的分割是將 80% 的圖片投入到主要的訓練中,10% 的圖片作為訓練期間經(jīng)常進行的驗證集,而剩下 10% 的圖片作為最終的測試集以預測分類器在現(xiàn)實世界中的表現(xiàn)。 結(jié)果 第一類方法:預處理數(shù)據(jù)集并使用 sklearn 實現(xiàn) KNN、SVM 和 BP 神經(jīng)網(wǎng)絡。 結(jié)果在下表中。由于 SVM 結(jié)果非常差,甚至低于隨機猜測,我們不再展示其結(jié)果。 從結(jié)果中我們看到:
基于以上結(jié)果,我們發(fā)現(xiàn)為了提升精確度,使用一些深度學習方法很必要。 第二類方法:使用 TensorFlow 構(gòu)建 CNN。如上所述,由于過擬合我們不能獲取好的結(jié)果。 正常情況下訓練需要半個小時,然而由于結(jié)果過擬合,我們認為這一運行時間并不重要。通過和第一類方法的比較,我們看到:盡管 CNN 過擬合訓練數(shù)據(jù),我依然得到了更好的結(jié)果。 量化投資實戰(zhàn)課程——全明星六大海龜豪華陣容傾囊相授 上課地點:上海 培訓時間:2017年6月16日—18日 吳帆· AIMA中國區(qū)總經(jīng)理 聶軍· 凱思博香港總經(jīng)理 毛煜春· 安誠數(shù)盈董事長 張弘· 深圳盈富總經(jīng)理 林健武·量化總監(jiān) 章赟· 量化總監(jiān) |
|
|