GitHub項目地址:Mr.Miaow GitHub 如果對你有幫助歡迎
Star或者Fork。
機器學(xué)習(xí)深度學(xué)習(xí)面試題總結(jié)
項目介紹
本項目是優(yōu)達學(xué)城的其中一個納米學(xué)位畢業(yè)項目 -- 貓狗大戰(zhàn)。
項目要求使用深度學(xué)習(xí)方法識別一張圖片是貓還是狗
- 輸入:一張彩色圖片
- 輸出:是貓還是狗
注意:本項目代碼只供參考,嚴禁用于其他用途,如果使用請說明出處。
項目概述
本項目使用的卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network, CNN),卷積神經(jīng)網(wǎng)絡(luò)是深度學(xué)習(xí)技術(shù)中極具代表的網(wǎng)絡(luò)結(jié)構(gòu)之一,在圖像處理領(lǐng)域取得了很大的成功,在國際標準的 ImageNet 數(shù)據(jù)集上,許多成功的模型都是基于 CNN 的。CNN 相較于傳統(tǒng)的圖像處理算法的優(yōu)點之一在于,避免了對圖像復(fù)雜的前期預(yù)處理過程(提取人工特征等),可以直接輸入原始圖像。CNN 網(wǎng)絡(luò)對圖片進行多次卷基層和池化層處理,在輸出層給出兩個節(jié)點并進行 softmax 計算得到兩個類別各自的概率。
本項目最終需要訓(xùn)練基于 CNN 的機器學(xué)習(xí)模型,對測試樣本進行分類,并將最終結(jié)果上傳 kaggle 進行最終評判。
本項目同時也實現(xiàn)了使用 Keras 和 Flask 搭建部署一個簡單易用的深度學(xué)習(xí)圖像網(wǎng)頁應(yīng)用,可以通過網(wǎng)頁導(dǎo)入一張彩色貓或者狗的圖片預(yù)測是貓或者狗的概率。
問題稱述
數(shù)據(jù)集中大部分圖片是正常的,有少部分異常圖片和低分辨率圖片,對于訓(xùn)練集來說這些異常數(shù)據(jù)是要剔除掉的。
數(shù)據(jù)集中的文件名是以 type.num.jpg 方式命名的,比如 cat.0.jpg。使用 Keras 的 ImageDataGenerator 需要將不同種類的圖片分在不同的文件夾中。
數(shù)據(jù)集中的圖像大小是不固定的,但是神經(jīng)網(wǎng)絡(luò)輸入節(jié)點的個數(shù)是固定的。所以在將圖像的像素作為輸入之前,需要將圖像的大小進行 resize。
評價指標
對數(shù)損失(Log loss)亦被稱為邏輯回歸損失(Logistic regression loss)或交叉熵損失(Cross-entropy loss)。 交叉熵是常用的評價方式之一,它實際上刻畫的是兩個概率分布之間的距離,是分類問題中使用廣泛的一種損失函數(shù)。
本文實際上是二分類問題, 因此可以采用 logloss 損失函數(shù)作為評價指標, 計算公式如下:
其中:
n 是測試集中圖片數(shù)量
是圖片預(yù)測為狗的概率
如果圖像是狗,則為1,如果是貓,則為0
是自然(基數(shù)
)對數(shù)
采用交叉熵作為損失函數(shù)可以有效的解決梯度消失和梯度爆炸的問題。
交叉熵損失越小,代表模型的性能越好。上述評估指標可用于評估該項目的解決方案以及基準模型。
II. 分析
數(shù)據(jù)的探索
下載 kaggle 貓狗數(shù)據(jù)集解壓后分為 3 個文件 train.zip、 test.zip 和 sample_submission.csv。
train 訓(xùn)練集包含了 25000 張貓狗的圖片,貓狗各一半,每張圖片包含圖片本身和圖片名。命名規(guī)則根據(jù) “type.num.jpg” 方式命名。
test 測試集包含了 12500 張貓狗的圖片,沒有標定是貓還是狗,每張圖片命名規(guī)則根據(jù) “num.jpg”,需要注意的是測試集編號從 1 開始,而訓(xùn)練集的編號從 0 開始。
sample_submission.csv 需要將最終測試集的測試結(jié)果寫入.csv 文件中,上傳至 kaggle 進行打分。

從訓(xùn)練集中隨機提取圖片可視化如下:

訓(xùn)練集中圖片的尺寸散點分布圖:

測試集中圖片的尺寸散點分布圖:

通過對圖片中的色彩-像素比進行 IQR 分析,可以發(fā)現(xiàn)很多分辨率低、無關(guān)的圖片,下面是其中一些不合格的圖片:

經(jīng)過觀察數(shù)據(jù),數(shù)據(jù)集中大部分圖片是正常的,有少部分異常圖片,對于訓(xùn)練集來說這些異常數(shù)據(jù)是要剔除掉的。
算法和技術(shù)
問題分析
在給定一張圖片,系統(tǒng)需要預(yù)測出圖像屬于預(yù)先定義類別中的哪一類。在計算機視覺領(lǐng)域,目前解決這類問題的核心技術(shù)框架是深度學(xué)習(xí)(Deep Learning),特別地,針對圖像類型的數(shù)據(jù),是深度學(xué)習(xí)中的卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Networks, ConvNets)架構(gòu)。常見的卷積神經(jīng)網(wǎng)絡(luò)架構(gòu)如下:

卷積神經(jīng)網(wǎng)絡(luò)中卷積層和池化層主要是對圖片的幾何特征進行抽取,比如淺層的卷積池化層可以抽取出一些直線,角點等簡單的抽象信息,深層的卷積池化層可以抽取人臉等復(fù)雜的抽象信息,最后的全連接層才是對圖片分類的關(guān)鍵處理。
因此可以利用已經(jīng)訓(xùn)練好的卷積神經(jīng)網(wǎng)絡(luò)提取圖片中復(fù)雜的幾何特征,即將原始圖片用已經(jīng)訓(xùn)練好的卷積神經(jīng)網(wǎng)絡(luò)處理之后的輸出,作為新的輸入,然后加上自己的全連接層,去進行分類。在模型訓(xùn)練的過程中,只改變新加的全連接層的權(quán)重。
總的來說,卷積神經(jīng)網(wǎng)絡(luò)是一種特殊的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),即通過卷積操作可以實現(xiàn)對圖像特征的自動學(xué)習(xí),選取那些有用的視覺特征以最大化圖像分類的準確率。

上圖給出了一個簡單的貓狗識別的卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),在最底下(同時也是最大的)的點塊表示的是網(wǎng)絡(luò)的輸入層(Input Layer),通常這一層作用是讀入圖像作為網(wǎng)絡(luò)的數(shù)據(jù)輸入。在最上面的點塊是網(wǎng)絡(luò)的輸出層(Output Layer),其作用是預(yù)測并輸出讀入圖像的類別,在這里由于只需要區(qū)分貓和狗,因此輸出層只有 2 個神經(jīng)計算單元。而位于輸入和輸出層的,都稱之為隱含層(Hidden Layer),圖中有 3 個隱含層,圖像分類的隱含層都是由卷積操作完成的,因此這樣的隱含層也成為卷積層(Convolutional Layer)。因此,輸入層、卷積層、輸出層的結(jié)構(gòu)及其對應(yīng)的參數(shù)就構(gòu)成了一個典型的卷積神經(jīng)網(wǎng)絡(luò)。
當(dāng)然,在實際中使用的卷積神經(jīng)網(wǎng)絡(luò)要比這個示例的結(jié)構(gòu)更加復(fù)雜,自 2012 年的 ImageNet 比賽起,幾乎每一年都會有新的網(wǎng)絡(luò)結(jié)構(gòu)誕生,已經(jīng)被大家認可的常見網(wǎng)絡(luò)有 AlexNet, VGG-Net, GoogLeNet, Inception V2-V4, ResNet 等等。這些卷積神經(jīng)網(wǎng)絡(luò)都是在 ImageNet 數(shù)據(jù)集上表現(xiàn)非常優(yōu)異的神經(jīng)網(wǎng)絡(luò),具體準確率和模型大小如下圖所示。

模型選擇及技術(shù)
由于每一種神經(jīng)網(wǎng)絡(luò)提取的特征都不一樣,因此本項目將多個神經(jīng)網(wǎng)絡(luò)處理的結(jié)果拼接,作為最后一層全連接層的輸入,這樣做可以有效地降低方差。
本項目遷移學(xué)習(xí)部分使用 Keras 實現(xiàn),而 Keras 中可以導(dǎo)入的模型有 Xception,VGG16,VGG19,ResNet50,InceptionV3,InceptionResNet -V2,MobileNet. 綜合考慮模型的分類準確率和大小,選用遷移學(xué)習(xí)的基礎(chǔ)模型為 ResNet50,InceptionV3 和 Xception。
卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)演化圖:

ResNet:
ResNet引入了殘差網(wǎng)絡(luò)結(jié)構(gòu)(residual network),通過這種殘差網(wǎng)絡(luò)結(jié)構(gòu),可以把網(wǎng)絡(luò)層弄的很深(據(jù)說目前可以達到 1000 多層),并且最終的分類效果也非常好,殘差網(wǎng)絡(luò)的基本結(jié)構(gòu)如下圖所示,很明顯,該圖是帶有跳躍結(jié)構(gòu)的:

殘差網(wǎng)絡(luò)借鑒了高速網(wǎng)絡(luò)(Highway Network)的跨層鏈接思想,但對其進行改進(殘差項原本是帶權(quán)值的,但 ResNet 用恒等映射代替之)。
假定某段神經(jīng)網(wǎng)絡(luò)的輸入是 ,期望輸出是
,即
是期望的復(fù)雜潛在映射,如果是要學(xué)習(xí)這樣的模型,則訓(xùn)練難度會比較大;回想前面的假設(shè),如果已經(jīng)學(xué)習(xí)到較飽和的準確率(或者當(dāng)發(fā)現(xiàn)下層的誤差變大時),那么接下來的學(xué)習(xí)目標就轉(zhuǎn)變?yōu)楹愕扔成涞膶W(xué)習(xí),也就是使輸入
近似于輸出
,以保持在后面的層次中不會造成精度下降。
在上圖的殘差網(wǎng)絡(luò)結(jié)構(gòu)圖中,通過“shortcut connections(捷徑連接)”的方式,直接把輸入傳到輸出作為初始結(jié)果,輸出結(jié)果為
,當(dāng)
時,那么
,也就是上面所提到的恒等映射。于是,ResNet 相當(dāng)于將學(xué)習(xí)目標改變了,不再是學(xué)習(xí)一個完整的輸出,而是目標值
和
的差值,也就是所謂的殘差
,因此,后面的訓(xùn)練目標就是要將殘差結(jié)果逼近于
,使到隨著網(wǎng)絡(luò)加深,準確率不下降。
這種殘差跳躍式的結(jié)構(gòu),打破了傳統(tǒng)的神經(jīng)網(wǎng)絡(luò) 層的輸出只能給
層作為輸入的慣例,使某一層的輸出可以直接跨過幾層作為后面某一層的輸入,其意義在于為疊加多層網(wǎng)絡(luò)而使得整個學(xué)習(xí)模型的錯誤率不降反升的難題提供了新的方向。
在此之前,深度神經(jīng)網(wǎng)絡(luò)常常會有梯度消失問題的困擾,即來自誤差函數(shù)的梯度信號會在反向傳播回更早的層時指數(shù)級地下降。本質(zhì)上講,在誤差信號反向回到更早的層時,它們會變得非常小以至于網(wǎng)絡(luò)無法學(xué)習(xí)。但是,因為 ResNet 的梯度信號可以直接通過捷徑連接回到更早的層,所以一下子就可以構(gòu)建 50 層、101 層、152 層甚至 1000 層以上的網(wǎng)絡(luò)了,而且它們的表現(xiàn)依然良好。那時候,這在當(dāng)時最佳的基礎(chǔ)上實現(xiàn)了巨大的飛躍——這個 22 層的網(wǎng)絡(luò)贏得了 ILSVRC 2014 挑戰(zhàn)賽。
Inception V3:
Inception 模塊之間特征圖的縮小,主要有下面兩種方式:

右圖是先進行 Inception 操作,再進行池化來下采樣,但是這樣參數(shù)量明顯多于左圖(比較方式同前文的降維后 Inception 模塊),因此 v2 采用的是左圖的方式,即在不同的 Inception 之間(35/17/8 的梯度)采用池化來進行下采樣。
但是,左圖這種操作會造成表達瓶頸問題,也就是說特征圖的大小不應(yīng)該出現(xiàn)急劇的衰減(只經(jīng)過一層就驟降)。如果出現(xiàn)急劇縮減,將會丟失大量的信息,對模型的訓(xùn)練造成困難。
因此,在2015年12月提出的 Inception V3結(jié)構(gòu)借鑒 Inception 的結(jié)構(gòu)設(shè)計了采用一種并行的降維結(jié)構(gòu),如下圖:

經(jīng)過優(yōu)化后的inception v3網(wǎng)絡(luò)與其他網(wǎng)絡(luò)識別誤差率對比如表所示:

Inception V3 一個最重要的改進是分解(Factorization),將 7x7 分解成兩個一維的卷積(1x7,7x1),3x3 也是一樣(1x3,3x1),這樣的好處,既可以加速計算,又可以將 1 個卷積拆成 2 個卷積,使得網(wǎng)絡(luò)深度進一步增加,增加了網(wǎng)絡(luò)的非線性(每增加一層都要進行 ReLU)。
另外,網(wǎng)絡(luò)輸入從 224*224 變?yōu)榱?299*299。
Xception:
Xception 實際上采用了類似于 ResNet 的網(wǎng)絡(luò)結(jié)構(gòu),主體部分采用了模塊化設(shè)計。如下圖所示:

Xception 是 google 繼 Inception 后提出的對 Inception v3 的另一種改進,主要是采用 depthwise separable convolution 來替換原來Inception v3中的卷積操作。
Xception 取名的由來是 "Extreme Inception",Inception V3 的演進過程:

"極端形式"同 SeparableConv 的區(qū)別主要有兩點:
3x3卷積和1x1卷積的先后順序。 原來的 Inception 結(jié)構(gòu)是先1x1卷積,后3x3卷積。作者認為這里的區(qū)別并不重要。兩個卷積層之間是否有激活函數(shù)。 原來的 Inception 中間是有 ReLU 激活的。 但實驗結(jié)果證明不加激活效果更好。
基準模型
本項目的最低要求是 kaggle Public Leaderboard 前 10%。在 kaggle 上,總共有 1314 只隊伍參加了比賽,所以需要最終的結(jié)果排在 131 位之前,131 位的得分是 0.06127,所以目標是模型預(yù)測結(jié)果要小于 0.06127。
III. 方法
數(shù)據(jù)預(yù)處理
對于異常數(shù)據(jù)的清理采用 優(yōu)達學(xué)習(xí)筆記 提供的“預(yù)處理模型”方法實現(xiàn)異常數(shù)據(jù)清洗。
評價 ImageNet 有指標 Top-1 和 Top-5:

本項目使用 InceptionV3 top-10 訓(xùn)練train訓(xùn)練集。訓(xùn)練過程中將圖片的名稱和預(yù)測 top-10 的結(jié)果保存到字典里,訓(xùn)練結(jié)束后保存字典為 train_decode_predictions.csv。將模型預(yù)測結(jié)果與 ImageNetClasses.csv 進行異常數(shù)據(jù)排查。具體實現(xiàn)代碼參考 outlier_detection.ipynb 。
使用 InceptionV3 模型排查出的異常圖片總數(shù)為:131張,其中有些圖片是正常的,經(jīng)過篩選后選出 43 張異常圖片作為本試驗要清理的異常圖片。這些異常圖片如下圖:

去除異常數(shù)據(jù)后數(shù)據(jù)分布如下:

數(shù)據(jù)集清洗后,貓的數(shù)量:12482,狗的數(shù)量:12475,測試集圖片數(shù)量:12500。
由于我們的數(shù)據(jù)集的文件名是以 type.num.jpg 這樣的方式命名的,比如 cat.0.jpg,但是使用 Keras 的 ImageDataGenerator 需要將不同種類的圖片分在不同的文件夾中,因此我們需要對數(shù)據(jù)集進行預(yù)處理。這里我們采取的思路是創(chuàng)建符號鏈接(symbol link),這樣的好處是不用復(fù)制一遍圖片,占用不必要的空間。
文件目錄結(jié)構(gòu)如下:
image/
├── test
├── img_test
│ ├── test -> ../test/
├── train
├── img_train
│ ├── cat
│ └── dog
執(zhí)行過程
生成遷移學(xué)習(xí)特征向量
Xception,InceptionV3 和 ResNet50 這三個模型對于輸入數(shù)據(jù)都有各自的默認值,比如在輸入圖片大小維度上,Xception 和 InceptionV3 默認輸入圖片大小是 299*299,ResNet50 默認輸入圖片大小是 224*224;在輸入數(shù)值維度上,Xception 和 InceptionV3 默認輸入數(shù)值在 (-1, 1) 范圍內(nèi)。當(dāng)要輸入與默認圖片大小不同的圖片時,只需傳入當(dāng)前圖片大小即可。ResNet50 需要對圖片進行中心化處理,由于載入的 ResNet50 模型是在 ImageNet 數(shù)據(jù)上訓(xùn)練出來的,所以在預(yù)處理中每個像素點都要減去 ImageNet 均值。當(dāng)要輸入與默認圖片大小不同的圖片時,只需傳入當(dāng)前圖片大小即可。當(dāng)輸入數(shù)值不符合默認要求時,使用每個模型的預(yù)處理函數(shù) preprocess_input 即可將輸入圖片處理成該模型的標準輸入。
常見的卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)在前面的若干層都是卷積池化層及其各種變種,后面幾層都是全連接層,這些全連接層之前的網(wǎng)絡(luò)層被稱為瓶頸層 (bottleneck). 將新的圖片通過訓(xùn)練好的卷積神經(jīng)網(wǎng)絡(luò)直到瓶頸層的過程可以看做是對圖像進行特征提取的過程。一般情況下,為了減少內(nèi)存的消耗, 加快計算的過程,再將瓶頸層的結(jié)果輸入全連接層之前,做一次全局平均 池化,比如 ResNet50 瓶頸層輸出結(jié)果是 7*7*2048,如果直接輸入到全連接層,參數(shù)會非常多,所以進行一次全局平均池化,將輸出矩陣調(diào)整為 1*1*2048,這么做還有一個好處,那就是可以降低過擬合的程度。
在 Keras 中載入模型并進行全局平均池化,只需要在載入模型的時候,設(shè)置 include_top=False, pooling='avg'. 每個模型都將圖片處理成一個 1*2048 的行向量,將這三個行向量進行拼接,得到一個 1*6144 的行向量,作為數(shù)據(jù)預(yù)處理的結(jié)果。
def write_gap(MODEL, image_size, lambda_func=None):
width = image_size[0]
height = image_size[1]
input_tensor = Input((height, width, 3))
x = input_tensor
if lambda_func:
x = Lambda(lambda_func)(x)
base_model = MODEL(input_tensor=x, weights='imagenet', include_top=False, pooling='avg')
model = Model(base_model.input, GlobalAveragePooling2D()(base_model.output))
gen = ImageDataGenerator()
train_generator = gen.flow_from_directory("img_train", image_size, shuffle=False,
batch_size=16)
test_generator = gen.flow_from_directory("img_test", image_size, shuffle=False,
batch_size=16, class_mode=None)
train = model.predict_generator(train_generator, train_generator.nb_sample)
test = model.predict_generator(test_generator, test_generator.nb_sample)
with h5py.File("gap_%s.h5"%MODEL.__name__) as h:
h.create_dataset("train", data=train)
h.create_dataset("test", data=test)
h.create_dataset("label", data=train_generator.classes)
載入特征向量
經(jīng)過上面的代碼以后,我們獲得了三個特征向量文件,分別是:
- gap_ResNet50.h5
- gap_InceptionV3.h5
- gap_Xception.h5
這里需要載入這些特征向量,并且將它們合成一條特征向量,然后記得把 X 和 y 打亂,不然之后設(shè)置 validation_split 的時候會出問題。這里設(shè)置了 numpy 的隨機數(shù)種子為 2018。
np.random.seed(2018)
X_train = []
X_test = []
for filename in ["gap_ResNet50.h5", "gap_Xception.h5", "gap_InceptionV3.h5"]:
with h5py.File(filename, 'r') as h:
X_train.append(np.array(h['train']))
X_test.append(np.array(h['test']))
y_train = np.array(h['label'])
X_train = np.concatenate(X_train, axis=1)
X_test = np.concatenate(X_test, axis=1)
X_train, y_train = shuffle(X_train, y_train)
構(gòu)建模型
載入預(yù)處理的數(shù)據(jù)之后,先進行一次概率為 0.5 的 dropout,然后直接連接輸出層,激活函數(shù)為 Sigmoid,優(yōu)化器為 Adadelta,輸出一個零維張量,表示某張圖片中有狗的概率。
input_tensor = Input(X_train.shape[1:])
x = input_tensor
x = Dropout(0.5)(x)
x = Dense(1, activation='sigmoid')(x)
model = Model(input_tensor, x)
model.compile(optimizer='adadelta',
loss='binary_crossentropy',
metrics=['accuracy'])
整個遷移學(xué)習(xí)的神經(jīng)網(wǎng)格結(jié)構(gòu)如下所示:

訓(xùn)練模型
模型構(gòu)件好了以后,我們就可以進行訓(xùn)練了,這里我們設(shè)置驗證集大小為 20% ,也就是說訓(xùn)練集是 19964 張圖,驗證集是 4991 張圖。
model_history = model.fit(X_train,
y_train,
batch_size=128,
nb_epoch=8,
verbose=1,
validation_split=0.2,
callbacks = [TensorBoard(log_dir='./Graph')])
model.save('model.h5')
保存模型為:model.h5
完善
本項目通過對圖片中的色彩-像素比進行 IQR 分析,經(jīng)人工篩選后剔除了分辨率低、無關(guān)的圖片,這種方法并不能把所有的異常圖片都剔除掉。比如還有一些圖片被別的物體遮擋,對訓(xùn)練造成干擾等等。后期可以考慮多方面對圖片做篩選處理
圖片中貓狗的拍攝角度不盡相同,而且貓狗占整張圖片的比例也有所差別。為了讓模型盡量不受這些因素的干擾,增強模型的泛化能力,需要對原始圖片進行一些隨機操作,比如旋轉(zhuǎn)、剪切變換、縮放、水平翻轉(zhuǎn)等。Keras 提供的圖片生成器
ImageDataGenerator可以很方便地對圖片進行提升對模型參數(shù)的優(yōu)化,通過不同的優(yōu)化器的嘗試得到更好的優(yōu)化結(jié)果
IV. 結(jié)果
模型的評價與驗證

我們可以看到,訓(xùn)練的過程很快,十秒以內(nèi)就能訓(xùn)練完,準確率也很高,在驗證集上最高達到了99.4%的準確率,這相當(dāng)于一千張圖只錯了6張,可以說比我還厲害。
訓(xùn)練過中的 loss 和 accuracy 如下:

將測試集的處理結(jié)果提交到kaggle上,loss為0.04150,和驗證集的loss近似。

合理性分析
單個 ResNet50 模型 5 次迭代訓(xùn)練結(jié)果:
- 訓(xùn)練集loss:0.0755,驗證集loss:0.0419。
使用 Xception,InceptionV3 和 ResNet50 這三個模型進行遷移學(xué)習(xí) 5 次迭代訓(xùn)練結(jié)果:
- 訓(xùn)練集loss:0.0152,驗證集loss:0.0170。
原始的 Xception 有 126 層,原始的 InceptionV3 有 159 層,原始的 ResNet50 有 168 層,更多的層數(shù),不同的卷積核各種各樣的的組合,可以更好的抽取圖片中的泛化特征,這樣既可以提高分類的準確率,又可以降低模型的過擬合風(fēng)險,所以現(xiàn)在在各種比賽中斬頭露角的神經(jīng)網(wǎng)絡(luò)層數(shù)都非常的多,深度很深,這也是類似的神經(jīng)網(wǎng)絡(luò)被稱為深度學(xué)習(xí)的一個主要原因。
Xception,InceptionV3 和 ResNet50 這三個模型進行組合遷移學(xué)習(xí),效果比先單個神經(jīng)網(wǎng)絡(luò)模型效果好。這里利用了 bagging 的思想,通過多個模型處理數(shù)據(jù)并進行組合,可以有效降低模型的方差,減少過擬合程度,提高分類準確率。
V. 項目結(jié)論
結(jié)果可視化
下圖是使用優(yōu)化之前的 ResNet50 模型進行預(yù)測的結(jié)果展示,可以看到都是正確的結(jié)果,只是精度達不到項目要求。使用了知乎上優(yōu)達學(xué)城官方方法進行了實現(xiàn),完全能達到項目的要求。

對項目的思考
深度學(xué)習(xí)毫無疑問是處理圖像問題最佳的機器模型,近年來各大賽的前幾名均是通過深度學(xué)習(xí)獲取了前幾名的好成績。但是相比于傳統(tǒng)的機器學(xué)習(xí)模型,深度學(xué)習(xí)需要更多的數(shù)據(jù),更強大的算力和資源。本項目在訓(xùn)練遷移學(xué)習(xí)模型使用的是自己的 Mac,足足跑了三天訓(xùn)練完,淚崩。建議在使用的時候用云計算平臺去訓(xùn)練。
kaggle 上貓狗大戰(zhàn)前幾名的 loss 達到了 0.0330,相比于本文中的 0.0415,絕對值減少了 0.0085,說明還是有較大的改進空間。本文只是使用的 Xception,InceptionV3 和 ResNet50 這三個模型進行了提取特征向量,然后將特征向量直接拼接,忽略了特征之間的位置關(guān)系。除了這三個模型,還可以增加更多新的模型,或者使用stacking的方法進行模型融合,進一步降低方差,提高分類的準確率。還可以從原始樣本上入手,有些圖片的分類概率正確,但是不夠確定,可以先做一部分處理,然后讓模型更加確定。
需要作出的改進
相比 Keras,TensorFlow 真的真的太麻煩了,但是 Google 為什么要把 TensorFlow 做的這么麻煩呢?個人認為是為了運行的高效率和極大的靈活性做出了讓步。TensorFlow 是經(jīng)過工業(yè)界實際產(chǎn)品考驗過的框架,生態(tài)及其豐富,想實現(xiàn)一個功能,有多種寫法,學(xué)起來有一種 C++ 的感覺,Keras 更像是為了快速出活的框架,如果想做一些改動十分的麻煩,Keras 的默認 backend 就是 TensorFlow,所以 Keras 的執(zhí)行效率是比 TensorFlow 慢很多的。TensorFlow1.4 里面已經(jīng)把 tf.contrib.keras 更改為核心模塊 tf.keras,所以 TensorFlow 以后用起來應(yīng)該也會方便很多。最后還想說的是 PyTorch,好多人都推薦,說不僅僅有 TensorFlow 的高效率,而且很 pythonic,可以在任意層和 numpy 數(shù)組進行轉(zhuǎn)化。
項目部署
項目使用 Keras 和 Flask 搭建部署一個簡單易用的深度學(xué)習(xí)圖像網(wǎng)頁應(yīng)用,可以通過網(wǎng)頁導(dǎo)入一張彩色貓或者狗的圖片預(yù)測是貓或者狗的概率。
項目目錄結(jié)構(gòu):
.
├── README.md
├── ResNet50_image_predict.ipynb
├── app.py
├── environmert.yml
├── static
│ ├── css
│ │ └── main.css
│ └── js
│ └── main.js
├── templates
│ ├── base.html
│ └── index.html
├── models
│ └── ResNet50_catdog_model.h5
├── uploads
│ ├── test01.jpg
│ └── test02.jpg
└── webapp_image_predict.ipynb
環(huán)境搭建
$ conda env create -f environmert.yml
運行
$ python app.py
這時候用瀏覽器打開 http://localhost:5000/ 就可以進行網(wǎng)頁導(dǎo)入圖片預(yù)測圖片是狗的概率了。
如果不想搭建環(huán)境復(fù)現(xiàn)實驗結(jié)果,可以按照以下操作分分鐘復(fù)現(xiàn)實驗結(jié)果:
$ docker pull miaowmiaow/webapp:1.1.0
$ docker run -p 5000:5000 miaowmiaow/webapp:1.1.0
到此就可以在瀏覽器中輸入 http://localhost:5000 就可以使用網(wǎng)頁對導(dǎo)入的貓狗圖片做預(yù)測了。
下圖為預(yù)測的效果圖:

VI. 參考文獻
[1] K. He, X. Zhang, S. Ren, and J. Sun. Deep residual learning for image recognition. arXiv preprint arXiv:1512.03385, 2015.
[2] Christian Szegedy, Wei Liu, Yangqing Jia. Going Deeper with Convolutions arXiv:1409.4842, 2014
[3] Fran?ois Chollet. Xception: Deep Learning with Depthwise Separable Convolutions arXiv:1610.02357, 2016
[4]手把手教你如何在Kaggle貓狗大戰(zhàn)沖到Top2%
[5] Karen Simonyan and Andrew Zisserman. VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE- SCALE IMAGE RECOGNITION. At ICLR,2015.
[6] K. Simonyan and A. Zisserman. Very deep convolutional networks for large-scale image recognition. In ICLR, 2015.
[7] Building powerful image classification models using very little data.
[8] Dogs vs. Cats: Image Classification with Deep Learning using TensorFlow in Python.
[9] ImageNet: VGGNet, ResNet, Inception, and Xception with Keras.
[10] The residual module in ResNet as originally proposed by He et al. in 2015.
[11] An Analysis of Deep Neural Network Models for Practical Applications. arXiv:1605.07678, 2017.