使用Keras實現多輸出分類:用單個模型同時執行兩個獨立分類任務
選自pyimagesearch,作者:Adrian Rosebrock,機器之心編譯,參與:Panda。
如何讓一個網路同時分類一張圖像的兩個獨立標籤?多輸出分類可能是你的答案。已經推出了兩個圖像搜索引擎(ID My Pill 和 Chic Engine)的 Adrian Rosebrock 近日發布了一份教程,介紹了使用 Keras 和 TensorFlow 實現「服裝種類+顏色」多輸出分類的詳細過程。機器之心編譯介紹了該教程。
之前我們介紹了使用 Keras 和深度學習的多標籤分類(multi-label classification),參閱 https://goo.gl/e8RXtV。今天我們將討論一種更為先進的技術——多輸出分類(multi-output classification)。
所以,這兩者之間有何不同?你怎樣才能跟得上這各項技術?
儘管這兩者有些混淆不清(尤其是當你剛入門深度學習時),但下面的解釋能幫你區分它們:
- 在多標籤分類中,你的網路僅有一組全連接層(即「頭」),它們位於網路末端,負責分類。
- 但在多輸出分類中,你的網路至少會分支兩次(有時候會更多),從而在網路末端創建出多組全連接頭——然後你的網路的每個頭都會預測一組類別標籤,使其有可能學習到不相交的標籤組合。
你甚至可以將多標籤分類和多輸出分類結合起來,這樣每個全連接頭都能預測多個輸出了!
如果這開始讓你感到頭暈了,不要擔心——這篇教程將引導你通過 Keras 透徹了解多輸出分類。實際做起來會比預想的更輕鬆。
話雖如此,這項深度學習技術還是比之前介紹的多標籤分類技術更先進。如果你還沒有閱讀那篇文章,一定要先看看。
讀完那篇文章之後,你應該就已經能使用多個損失函數訓練你的網路並從該網路獲取多個輸出了。接下來我們介紹如何通過 Keras 使用多個輸出和多個損失。
圖 1:我們可以使用 Keras 執行多輸出分類,其中多組全連接頭使其有可能學習到不相交的標籤組合。該動畫展示了幾個多輸出分類的結果。
在這篇文章中,我們將了解如何通過 Keras 深度學習庫使用:
- 多個損失函數
- 多個輸出
正如前面提到的,多標籤預測和多輸出預測之間存在區別。
使用多標籤分類時,我們使用一個全連接頭來預測多個類別標籤。
但使用多輸出分類時,我們至少有兩個全連接頭——每個頭都負責執行一項特定的分類任務。
我們甚至可以將多輸出分類與多標籤分類結合起來——在這種情況下,每個多輸出頭也會負責計算多個標籤!
你可能已經開始覺得有些難以理解了,所以我們不再繼續討論多輸出分類和多標籤分類的差異。接下來走進項目里看看吧!我相信本文中所給出的代碼能幫你理清這兩個概念。
首先我們將介紹數據集的情況,我們將使用這個數據集來構建我們的多輸出 Keras 分類器。
然後,我們將實現並訓練我們的 Keras 架構 FashionNet,其可使用該架構中兩個獨立的分支來分類服裝/時裝:
- 一個分支用於分類給定輸入圖像的服裝種類(比如襯衫、裙子、牛仔褲、鞋子等);
- 另一個分支負責分類該服裝的顏色(黑色、紅色、藍色等)。
最後,我們將使用訓練後的網路來分類示例圖像,得到多輸出分類結果。
下面就開始吧!
多輸出深度學習數據集
圖 2:我們的多輸出分類數據集是使用這篇文章所討論的技術創建的:https://goo.gl/3C8xyK。注意我們的數據集中不包含紅色/藍色鞋子或黑色裙子/襯衫,但本文所介紹的 Keras 多輸出分類方法依然能正確預測這些組合。
在本 Keras 多輸出分類教程中,我們將使用的數據集基於之前的多標籤分類文章的數據集,但也有一個例外——我增加了一個包含 358 張「黑色鞋子」圖像的文件夾。
總體而言,我們的數據集由 2525 張圖像構成,分為 7 種「顏色+類別」組合,包括:
- 黑色牛仔褲(344 張圖像)
- 黑色鞋子(358 張圖像)
- 藍色裙子(386 張圖像)
- 藍色牛仔褲(356 張圖像)
- 藍色襯衫(369 張圖像)
- 紅色裙子(380 張圖像)
- 紅色襯衫(332 張圖像)
我使用我之前寫的教程《如何(快速)創建一個深度學習圖像數據集》中描述的方法創建了該數據集,參閱:https://goo.gl/3C8xyK。
下載圖像和人工移除 7 個組合中的無關圖像的整個過程大約耗時 30 分鐘。在構建你自己的深度學習圖像數據集時,要確保你遵循了上述鏈接的教程——這能為你開始構建自己的數據集提供很大幫助。
我們的目標是能夠同時預測顏色和服裝種類,這和上次一樣;但不同之處是我們這一次的網路要能夠預測之前未訓練過的「服裝種類+顏色」組合。
比如,給定下列「黑色裙子」圖像(我們的網路沒使用過這樣的訓練數據):
圖 3:儘管我們的數據集不包含「黑色裙子」圖像,但我們仍然可以通過 Keras 和深度學習使用多輸出分類來得到正確的分類結果。
我們的目標是正確預測出該圖像的「黑色」+「裙子」。
我們的 Keras + 深度學習項目結構
如果你想在你自己的圖像上操作這些代碼,可以訪問原文結尾處的下載板塊,下載與本文關聯的 .zip 文件。
然後,unzip 這個文件並按下列方式修改目錄(cd)。然後使用 tree 命令,你就可以看到組織好的文件和文件夾。
上面你可以看到我們的項目結構,但在我們繼續之前,首先讓我們概覽一下其中的內容。
其中有 3 個值得關注的 Python 文件:
- pyimagesearch/fashionnet.py:我們的多輸出分類網路文件包含由三種方法組成的 FashionNet 架構類:build_category_branch、build_color_branch 和 build。我們將在下一節詳細介紹這些方法。
- train.py:這個腳本會訓練 FashionNet 模型,並在這一過程中在輸出文件夾生成所有文件。
- classify.py:這個腳本會載入訓練後的網路,然後使用多輸出分類來分類示例圖像。
我們還有 4 個頂級目錄:
- dataset/:我們的時裝數據集,這是使用 Bing 圖片搜索的 API 收集到的。我們在前一節中介紹了這個數據集。你可以參考前面提到的教程來創建自己的數據集。
- examples/:我們有一些示例圖像,我們將在本文最後一節與我們的 classify.py 腳本一起使用。
- output/:我們的 train.py 腳本會生成一些輸出文件:
- fashion.model:我們的序列化的 Keras 模型
- category_lb.pickle:由 scikit-learn 生成的服裝類別的序列化 LabelBinarizer 對象。這個文件可被我們的 classify.py 腳本載入(而且標籤會被調用)
- color_lb.pickle:顏色的 LabelBinarizer 對象
- output_accs.png:準確度的訓練圖表
- output_losses.png:損失的訓練圖表
- pyimageseach/:這是一個包含 FashionNet 類的 Python 模塊
快速概覽我們的多輸出 Keras 架構
要使用 Keras 執行多輸出預測,我們要實現一種特殊的網路架構(這是我專為這篇文章創造的),我稱之為 FashionNet。
FashionNet 架構包含兩個特殊組件,包括:
- 一個網路的早期分支,之後會分成兩個「子網路」——一個負責服裝種類分類,另一個負責顏色分類。
- 在網路末端的兩個(不相交的)全連接頭,每一個都負責各自的分類任務。
在我們開始實現 FashionNet 之前,我們先可視化地看看每個組分,首先是分支:
圖 4:我們的多輸出分類網路的頂層是用 Keras 編碼的。可以看到,左邊是服裝種類分支,右邊是顏色分支。每個分支都有一個全連接頭。
在這個網路架構圖中可以看到,我們的網路接收的輸入圖像是 96x96x3 大小。
接下來我們就創建兩個分支:
- 左邊的分支負責分類服裝種類。
- 右邊的分支負責分類顏色。
每個分支都執行各自的卷積、激活、批歸一化、池化和 dropout 操作組合,直到我們得到最終輸出:
圖 5:我們的深度學習 Keras 多輸出分類網路有可能學習到不相交的標籤組合。
注意這些全連接(FC)頭組合看起來就像是本博客介紹過的其它架構的全連接層——但現在這裡有兩個全連接頭了,其中每一個都負責一個給定的分類任務。
可以看到,該網路的右邊分支比左邊分支要淺很多,這是因為預測顏色比預測服裝類別容易多了。
下一節我們將介紹如何實現這樣的架構。
實現我們的 FashionNet 架構
圖 6:Keras 深度學習庫擁有執行多輸出分類所需的所有功能。
因為使用多個損失函數訓練帶有多個輸出的網路是一項相當先進的技術,所以我假定你已經知道 CNN 的基礎知識,我們將主要關注實現多輸出/多損失訓練的元素。
如果你還是深度學習和圖像分類領域的新手,你可以考慮看看我的書《Deep Learning for Computer Vision with Python》,這能幫你快速趕上來。
我相信你已經照前文說的方法下載好了那些文件和數據。現在讓我們打開 fashionnet.py 看一看:
我們先從 Keras 庫導入模塊並導入 TensorFlow 本身。
因為我們的網路由兩個子網路構成,所以我們將定義兩個函數,分別負責構建每個分支。
第一個分支 build_category_branch 負責分類服裝種類,定義如下:
第 16 和 17 行定義了 build_category_branch,它具有三個值得提及的參數:
- inputs:輸入類別分支子網路的輸入量
- numCategories:裙子、鞋子、牛仔褲、襯衫等類別的數量
- finalAct:最後的激活層的類型,默認是一個 softmax 分類器。如果你要既要執行多輸出分類,也要執行多標籤分類,你應該將這個激活換成 sigmoid。
看一下第 20 行,這裡我們使用了一個 lambda 層將我們的圖像從 RGB 轉換成了灰度圖像。
為什麼要這樣做?
因為不管是紅、藍、綠還是紫,裙子始終都是裙子。所以我們決定丟棄顏色信息,僅關注圖像中的實際結構成分,以確保我們的網路沒有在學習中將特定的顏色與服裝種類關聯起來。
註:lambda 在 Python 3.5 和 Python 3.6 中的工作方式不一樣。我訓練這個模型使用的是 Python 3.5,所以如果你想用 Python 3.6 運行這個 classify.py 腳本來進行測試,你可能會遇到麻煩。如果你在 lambda 層遇到了報錯,我建議你 (a) 嘗試 Python 3.5 或 (b) 在 Python 3.6 上訓練然後分類。不需要修改代碼。
第 23-27 行,我們繼續構建帶有 dropout 的 CONV => RELU => POOL 代碼塊。
我們的第一個 CONV 層有 32 個帶有 3x3 卷積核和 RELU(修正線性單元)激活的過濾器。我們應用了批歸一化、最大池化和 25% 的 dropout。
dropout 是一種隨機斷開當前層節點與下一層節點之間的連接的過程。這一隨機斷開連接過程本質上有助於減少過擬合,因為該層中不會有什麼單獨的節點負責預測一個特定的類別、物體、邊緣或角。
接下來是兩組 (CONV => RELU) * 2 => POOL 代碼塊:
在這個代碼塊中對過濾器、卷積核和池化大小的修改是聯合進行的,以在逐步降低空間尺寸的同時增加深度。
讓我們再使用一個 FC => RELU 層將其歸總到一處:
最後一個激活層是全連接的,並且有與我們的 numCategories 同樣數量的神經元/輸出。
要注意,我們在第 57 行將我們最後的激活層命名為了 category_output。這很重要,因為我們之後將在 train.py 中通過名字引用這一層。
讓我們定義第二個用於構建我們的多輸出分類網路的函數。我們將其命名為 build_color_branch,顧名思義,其負責分類圖像中的顏色。
build_color_branch 的參數與 build_category_branch 的參數基本一樣。我們使用 numColors 作為其最後一層激活的數量(不同於 numCategories)。
這時候我們不再使用 lambda 灰度轉換層,因為網路這個部分實際上關心的就是顏色。如果轉換成灰度圖像,我們就會丟失所有的顏色信息!
網路的這個分支比分類服裝種類的分支淺很多,很多分類顏色的任務要簡單很多。這個子網路需要做的只是分類顏色,不需要太深。
類似於服裝種類分支,我們也有一個全連接頭。讓我們構建 FC =>RELU 代碼塊來完成:
為了區分顏色分支的最終激活層,我在第 94 行提供了 name="color_output" 關鍵詞參數。我們將在訓練腳本中引用它。
構建 FashionNet 的最後一步是將我們的兩個分支合併到一起,build 最終架構:
我們的 build 函數是在第 100 行定義的,其有 5 個一看就懂的參數。
這個 build 函數假設我們正在使用 TensorFlow 和通道最後排序(channels last ordering)。這使得第 105 行中的 inputShape 元組有清晰明確的排序 (height, width, 3),其中 3 是指 RGB 這 3 個通道。
如果你更願意使用不同於 TensorFlow 的後端,你需要對代碼進行修改:(1)你的後端應該有適當的通道排序,(2)實現一個定製層來處理 RGB 到灰度的轉換。
之後,我們定義該網路的兩個分支(第 110-113 行),然後將它們組合到一個 model 中(第 118-121 行)。
其中的關鍵思想是我們的分支有一個共有輸入,但有兩個不同的輸出(服裝種類和顏色分類結果)。
實現多輸出和多損失訓練腳本
現在我們已經實現了我們的 FashionNet 架構,開始訓練它吧!
準備好了嗎?讓我們打開 train.py 繼續深入:
我們首先導入該腳本必需的軟體包。
然後我們解析我們的命令行參數:
我們很快就會看到如何運行訓練腳本了。目前,只需要知道 --dataset 是我們的數據集的輸入文件路徑,--model、--categorybin、--colorbin 是三個輸出文件的路徑。
還有個可選操作。你可以使用 --plot 參數指定一個用於生成的準確度/損失圖表的基本文件名。我會在腳本中遇到它們時指出這些命令行參數。如果第 21-32 行對你而言有些難以理解,請參閱這篇文章:https://goo.gl/uG5mo9。
現在,讓我們確定 4 個重要的訓練變數:
我們在第 36-39 行設置了以下變數:
- EPOCHS:epoch 數量設置為 50。我通過實驗發現 50 epoch 能得到低損失同時又不會過擬合訓練集(或者盡我們所能不過擬合)的模型。
- INIT_LR:我們的初始學習率設置為 0.001。學習率控制著我們沿梯度前進的「步伐」。值越小說明步伐越小,值越大說明步伐越大。我們很快就將看到我們會使用 Adam 優化演算法,隨時間逐步降低學習率。。
- BS:我們將以 32 的批大小訓練我們的網路。
- IMAGE_DIMS:所有輸入圖像的尺寸都會調整為 96x96,外加 3 個通道(RGB)。我們使用這樣的維度進行訓練,我們的網路架構輸入維度也反映了這一點。當我們在之後一節使用示例圖像測試我們的網路時,測試圖像的維度也必須調整得和訓練圖像一樣。
接下來是抓取我們的圖像路徑並隨機打亂順序。我們還將初始化分別用於保存圖像本身以及服裝種類和顏色的列表。
接下來,我們將在 imagePaths 上循環,預處理圖像並填充 data、categoryLabels 和 colorLabels 列表。
這個在 imagePaths 上的循環是從第 54 行開始的。
在該循環內部,我們載入圖像並將其尺寸調整為 IMAGE_DIMS。我們也將圖像顏色通道的順序從 BGR 轉換成 RGB。為什麼要做這樣的轉換?回想一下 build_category_branch 函數中的 FashionNet 類,其中我們在 lambda 函數/層中使用了 TensorFlow 的 rgb_to_grayscale 轉換。因此,我們首先在第 58 行將圖像轉換成 RGB,最後將預處理後的圖像加到 data 列表裡。
接下來,依然在循環內,我們從當前圖像所在的目錄名稱中提取顏色和類別標籤(第 64 行)。
如果你想實際看看操作情況,只需要在你的終端啟動 Python,然後按如下方式提供了一個樣本 imagePath 來實驗即可:
當然,你可以按照你想要的任何方式組織你的目錄結構(但你必須相應地修改代碼)。我最喜歡的兩種方法包括:(1)為每個標籤使用子目錄,(2)將所有圖像存儲在同一個目錄中,然後創建一個 CSV 或 JSON 文件將圖像文件名映射到它們的標籤。
然後將這三個列錶轉換成 NumPy 數組,將標籤二值化,並將數據分成訓練部分和測試部分。
我們的最後一個預處理步驟(轉換成一個 NumPy 數組並將原始像素強度調整到 [0, 1] 區間)可以一步完成,見第 70 行。
我們也將 categoryLabels 和 colorLabels 轉換成 NumPy 數組(第 75-76 行)。這很有必要,因為接下來我們將使用 scikit-learn 的 LabelBinarizer 來將這些標籤二值化(第 80-83 行),這是我們之前導入的工具。因為我們的網路有兩個獨立的分支,所以我們可以使用兩個獨立的標籤 LabelBinarizer——這不同於多標籤分類的情況,其中我們使用了 MultiLabelBinarizer(這同樣來自於 scikit-learn)。
接下來,我們對我們的數據集執行一次典型的分割:80% 訓練數據和 20% 的測試數據(第 87-96 行)。
接下來構建網路,定義獨立的損失,並編譯我們的模型:
在第 93-96 行,我們實例化了我們的多輸出 FashionNet 模型。我們在創建 FashionNet 類和其中的 build 函數時解釋過這些參數,但你還是要看看這裡我們實際提供的值。
接下來,我們需要為每個全連接頭定義兩個 losses(第 101-104 行)。
定義多個損失是使用一個詞典完成的,其使用了每個分支激活層的名稱——這就是我們在 FashionNet 實現中給我們的輸出層命名的原因!每個損失都使用類別交叉熵,這是分類類別大於 2 時訓練網路使用的標準損失方法。
在第 105 行,我們還在另一個詞典中定義了一個等值的 lossWeights(同樣的名稱鍵值具有相同的值)。在你的特定應用中,你可能希望某些損失的權重大於其它損失。
現在我們已經實例化了我們的模型並創建了我們的 losses + lossWeights 詞典,接下來我們用學習率延遲實例化 Adam 優化器並 compile 我們的 model(第 110-111 行)。
接下來的代碼就是啟動訓練過程:
回想一下第 87-90 行,我們將我們的數據分成了訓練部分(trainX)和測試部分(testX)。在第 114-119 行,我們在提供數據的同時啟動了訓練過程。注意第 115 行我們以詞典的形式傳遞標籤。第 116 行和 117 行也是一樣,我們為驗證數據傳遞了一個二元組。以這種方式傳遞訓練和驗證標籤是使用 Keras 執行多輸出分類的要求。我們需要指示 Keras 明白哪些目標標籤集合對應於網路的哪些輸出分支。
使用我們的命名行參數(args["model"]),我們可以將序列化的模型保存到磁碟以備之後調用。
我們也能通過同樣的操作將我們的標籤二值化器保存為序列化的 pickle 文件:
使用命令行參數路徑(args["categorybin"] 和 args["colorbin"]),我們將兩個標籤二值化器(categoryLB 和 colorLB)都以序列化 pickle 文件形式保存到了磁碟。
然後就是使用這個腳本繪製結果圖表:
上面的代碼塊負責繪製每個損失函數的損失歷史圖表,它們是分別繪製的,但疊放在一起,包括:
- 總體損失
- 類別輸出的損失
- 顏色輸出的損失
類似地,我們將準確度繪製成另一個圖像文件:
我們的類別準確度和顏色準確度圖最好分開看,所以它們是分開的,但放在同一個圖片中。
訓練多輸出/多損失 Keras 模型
請確保你下載了本文附帶的代碼和數據集。
不要忘了:在本教程給出的下載內容中,我使用的是 Python 3.5 訓練該網路。只要你保持一致(一直都用 Python 3.5 或 Python 3.6),你應該不會遇到 lambda 實現不一致的問題。你甚至可以運行 Python 2.7(尚未測試)。
打開終端。然後將下列命令粘貼進去,開始訓練過程(如果你沒有 GPU,你可能就得等一段時間,也許抽空喝杯啤酒?):
對於我們的類別輸出,我們得到:
- 在訓練集上準確度為 99.31%
- 在測試集上準確度為 93.47%
對於顏色輸出,結果為:
- 在訓練集上準確度為 99.31%
- 在測試集上準確度為 97.82%
下面是每個損失的圖表:
圖 7:使用 matplotlib 繪製的我們的 Keras 深度學習多輸出分類訓練損失圖。為了便於分析,我們的總損失(上圖)、服裝類別損失(中圖)和顏色損失(下圖)是分開繪製的。
還有我們的準確度圖表:
圖 8:FashionNet 是一個用 Keras 訓練的多輸出分類網路。為了分析訓練情況,最好是分開呈現準確度圖表。上圖為服裝種類訓練準確度圖,下圖為顏色訓練準確度圖。
應用數據增強可以實現更高的準確度。
實現多輸出分類腳本
現在我們已經訓練好了我們的網路,接下來看一下如何將其應用於不屬於我們的訓練集的輸入圖像。
打開 classify.py,插入以下代碼:
首先,我們導入所需的軟體包,然後解析命令行參數:
我們有 4 個命令行參數,你需要這些參數來在你的終端上運行這個腳本:
- --model:我們剛剛訓練好的序列化模型文件的路徑(我們之前腳本的一個輸出)
- --categorybin:種類標籤二值化器的路徑(之前腳本的一個輸出)
- --colorbin:顏色標籤二值化器的路徑(之前腳本的一個輸出)
- --image:測試圖像文件的路徑——這個圖像來自我們的 examples/ 目錄
然後我們載入圖像並對其進行預處理:
在運行推理前,我們需要預處理圖像。在上面的代碼塊中,我們載入了圖像,為輸出調整了圖像大小,然後轉換了顏色通道(第 24-26 行),這樣我們就可以在 FashionNet 的 lambda 層中使用 TensorFlow 的 RGB 轉灰度函數了。然後我們重新調整 RGB 圖像的大小(再次調用我們訓練腳本中的 IMAGE_DIMS),將其範圍調整到 [0,1],將其轉換成一個 NumPy 數組,並為該批增加一個維度(第 29-32 行)。
這裡的預處理步驟應該遵照訓練腳本的預處理步驟,這是很重要的。
接下來,載入我們的序列化模型和兩個標籤二值化器:
在第 37-39 行,我們使用了 4 個命令行參數中的 3 個,載入了 model、categoryLB 和 colorLB。
現在(1)多輸出 Keras 模型和(2)標籤二值化器都已經放入了內存,我們可以分類圖像了:
我們在第 43 行執行多輸出分類,得到服裝種類和顏色的概率(分別為 categoryProba 和 colorProba)。
注意:我沒有把 include 代碼包含進來,因為這樣會顯得很冗長,但你可以通過檢查輸出張量的名稱來確定你的 TensorFlow + Keras 模型返回多個輸出的順序。參閱 StackOverflow 上的這個討論了解更多詳情:https://goo.gl/F2KChX。
然後,我們會為類別和顏色提取最高概率的索引(第 48-49 行)。
使用這些高概率索引,我們可以提取出類別名稱(第 50-51 行)。
看起來有點太簡單了,對不對?但應用使用 Keras 的多輸出分類到新圖像上就這麼簡單!
讓我們給出結果來證明這一點:
我們在輸出圖像上顯示結果(第 54-61 行)。結果在圖像左上角以綠色文本顯示。如果我們遇到了「紅色裙子」,結果可能是:
- category: dress (89.04%)
- color: red (95.07%)
第 64-65 行也會將結果信息顯示在終端上,之後輸出圖像顯示在屏幕上(第 68 行)。
執行使用 Keras 的多輸出分類
有趣的部分來了!
在這一節,我們將為我們的網路提供 5 張不屬於訓練集樣本目錄的圖像。
按道理,我們的網路應該只能識別其中 2 張(黑色牛仔褲和紅色襯衫)。我們的網路應該能輕鬆處理這樣的種類和顏色搭配。
其餘三張圖像則是我們的模型從未見過的搭配——我們沒使用紅色鞋子、藍色鞋子或黑色裙子訓練過;但我們將試試多輸出分類的效果。
首先從「黑色牛仔褲」開始——這個應該很簡單,因為訓練數據集中有很多類似圖像。請確保以這樣的方式使用 4 個命令行參數:
圖 9:深度學習多輸出分類可以識別不相交標籤的組合,比如服裝種類和服裝顏色。我們的網路正確分類了這張圖像:牛仔褲+黑色。
和預計一樣,我們的網路正確分類了這張圖像:牛仔褲+黑色。
再來試試「紅色襯衫」:
圖 10:這張「紅色襯衫」圖像是一張不在我們的深度學習圖像數據集中的測試圖像。但我們的 Keras 多輸出網路見過其它紅色襯衫。它能輕鬆以 100% 的置信度分類這兩個標籤。
結果在這兩個類別標籤上都達到了 100% 的置信度,我們的圖像確實包含一件「紅色襯衫」。請記住,我們的網路在訓練過程中見過其它「紅色襯衫」。
現在讓我們回頭想想。我們的數據集中原來沒有「紅色鞋子」,但卻有「紅色」的「裙子」和「襯衫」,還有「黑色」的「鞋子」。
那麼我們的模型能不能看懂之前從未見過的同時包含「鞋子」和「紅色」的圖像呢?
來看結果:
圖 11:我們的深度學習多輸出分類網路之前從未見過「紅色」與「鞋子」的組合。在訓練過程中,模型確實看到過鞋子(但是黑色的);也看到過紅色(但是襯衫和裙子)。讓人驚喜的是,我們的網路能得到正確的多輸出標籤,將這張圖像分類為「紅色鞋子」。成功!
正確!
看看圖像中的結果,我們成功了。
我們已經有一個好開始了,雖然這個多輸出組合是之前從未出現過的。我們的網路設計+訓練是有效的,我們可以以很高的準確度識別「紅色鞋子」。
接下來看看我們的網路能正確分類「黑色裙子」嗎?記得嗎,在之前的多標籤分類教程中,當時的網路並沒有得到正確的結果。
我認為這一次我們很可能成功,將以下代碼輸入終端:
圖 12:儘管「黑色裙子」圖像並不包含在今天的數據集中,但我們仍然可以通過 Keras 和深度學習使用多輸出分類來正確分類它們。
看看這張圖左上角的標籤類別!
我們在種類和顏色上都得到了超過 98% 準確度的正確分類。我們已經實現了目標!
不要激動,讓我們再試試另一個未見過的組合:「藍色鞋子」。在終端輸入同樣的命令,只是將 --image 參數改為 examples/blue_shoes.jpg:
圖 13:儘管多標籤分類可能無法分類不熟悉的標籤組合,但多輸出分類能很好地應對這樣的任務。
結果同樣很好——我們的網路沒在「藍色鞋子」圖像上訓練過,但還是能使用多輸出和多損失分類的兩個子網路正確分類它們。
總結
在這篇文章中,我們學習了如何使用 Keras 深度學習庫中的多輸出和多損失函數。
為了完成我們的任務,我們定義了一個用於時裝/服裝分類的 Keras 架構 FashionNet。
FashionNet 架構包含兩個分支:
- 一個分支負責分類給定輸入圖像的服裝種類(比如襯衫、裙子、牛仔褲、鞋子等)
- 另一個分支負責分類該服裝的顏色(黑色、紅色、藍色等)
分支在網路早期產生,實際上在同一個網路中創造了兩個「子網路」,它們分別負責各自的分類任務。
最值得一提的是,多輸出分類讓我們可以解決之前的多標籤分類的遺留問題,即:我們在 6 種類別(黑色牛仔褲、藍色裙子、藍色牛仔褲、藍色襯衫、紅色裙子、紅色襯衫)上訓練了我們的網路,但得到的網路卻無法分類「黑色裙子」,因為該網路之前從未見過這樣的數據組合!
通過創建兩個全連接頭和相關的子網路(如有必要),我們可以訓練一個頭分類服裝種類,另一個頭負責識別顏色——最終得到的網路可以分類「黑色裙子」,即使它之前從未在這樣的數據上訓練過!
但還是要記住,你應該儘力提供你想要識別的每個類別的樣本訓練數據——深度神經網路雖然很強大,但可不是「魔法」!
你應該儘力保證適當的訓練方式,其中首先應該收集合適的訓練數據。
這就是我們的多輸出分類文章,希望你喜歡!
代碼下載鏈接:https://www.getdrip.com/forms/749437062/submissions
TAG:機器之心 |