1. 程式人生 > >基於Google object detection API的貓臉識別器

基於Google object detection API的貓臉識別器

近期趁著閒下來整理一下之前做的各種東西。

首先是這麼一個貓臉識別器:基於Google提供、Tensorflow框架下的object detection API,只需準備幾百張自己的資料集,在Google提供的訓練好的模型上進一步訓練,可以在短時間內得到一個性能相對較好(準確率95%左右)、最終呼叫介面也十分方便的自定義識別器。基於已有模型、實現對新物體識別的訓練方法叫做Transfer Learning。

個人認為Google這個介面十分良心,直接方便了廣大工程師,可以快速地完成自己的特定應用,例如在攝像頭中監控特定目標是否出現等等。而且這個識別器既包含分類(Classification)的功能也包含了精確定位位置(Detection)的功能,下一步大概就是Segmentation了吧(笑)。

再說回貓臉識別。調查貓臉識別的時候,我們發現CSDN上倒是有基於opencv的程式碼,但是在Cats v.s. Dogs的資料集上跑了一下效果並不好,並且各種引數十分莫名根本不知道該怎麼調。該資料集本來是一個貓臉狗臉識別大賽的資料集,對於我們的應用剛好合適。Google的API有整隻貓的識別,但是沒有貓臉和貓眼睛的識別,於是就想到了在已有模型上進行Transfer Learning,可以快速達到目標。

主要參考了以下內容:

[1] Google自己github上的說明,此說明寫的非常詳細,只看這份說明就可以完成所有的操作。

[2] 英文不夠好導致不能清楚理解的朋友可以跟我一一樣參考一下這篇中文部落格~一篇講的還可以但不夠仔細的linux上的實現。

[3] 原博文找不到了,在原模型基礎上學習識別Racoon(小浣熊!),github上的程式碼架構十分清晰,但是README寫的十分簡略。

我自己的github程式碼裡有較為詳細的說明,如果使用的話需要修改路徑為自己的路徑:

那我們正式開始。

整體的實現可以分為幾個以下步驟:

一、環境搭建

安裝Tensorflow Object Detection API的環境,具體一步一步跟著[1]中Installation的安裝步驟走就沒問題。我遇到的問題主要有二:

1、Protobuf的版本要求3.0.0以上,如果直接使用pip install可能安裝較低版本,需要手動去官網上安裝新版本。

2、cocoapi(已有的模型如果是通過coco資料集訓練出來的,可能需要用到,我是這麼理解的,不知道對不對)的路徑需要加到環境變數中。使用如下語句可以把cocoapi的路徑新增到環境路徑中,我把這句加到了最終指令碼中,這樣就不用每次手動設定了。

export PATH=$PATH:/home/robot/cocoapi/PythonAPI

二、資料準備

由於是Transfer Learning,所以資料準備不需要太多,幾百張就足夠達到不錯的效果。資料標準使用LabelImg,具體就是無腦操作,用框框手動把目標框出來,打上標記。由於我比較懶,這一部分工作都是學弟做的,他給我的時候已經是.xml檔案。我們一共標記了300張圖片,其中240張用於訓練,60張用於測試。

完成了這一步之後,通過[1]中給出的xml_to_csv.py和generate_tfrecord.py將.xml轉成.csv最終轉成tfrecord檔案方便輸入Tensorflow搭建的框架。(突然有一個問題,為什麼一定是.xml格式,為什麼中間一定要有一個.csv格式過渡,為什麼一定要用tfrecord格式輸入Tensorflow?)這部分功能可以通過以下語句實現:

以上完成訓練資料準備。

三、訓練配置與訓練

訓練的一些設定,例如路徑的設定,訓練次數等基本引數,都需要手動修改一個.config檔案。這一部分在[1]中Configure the Object Training Pipeline也有詳細的說明。需要注意的是以下幾個引數:

1、train_config中的fine_tune_checkpoint:用於指出已有模型的路徑。Google提供的已有模型可以在model zoo裡找到並下載,部分model的效能列表如下。這裡我們選擇速度快、準確率相對偏低的ssd_mobilenet_v1_coco。之後的from_detection_checkpoint用於選擇是基於分類的模型還是識別的模型,一般都設為True,選擇效果更好的識別的模型。

2、train_config中的num_steps:訓練次數,本應用中發現20k次就足以,訓練20k次耗時4h30min。

3、train_input_reader和eval_input_reader中的input_path和label_map_path:準備好的資料的路徑和label map。所謂label map就是下面這麼個東西,反映從id到label的對映關係。

4、eval_config中的num_examples:測試集圖片的數量,改變資料量的時候一定記得要改!!

訓練的過程也十分簡單。並行執行訓練、測試、tensorboard三個程序即可,訓練和測試的程式碼都已寫好,只要呼叫就行。唯一需要注意的是需要設定一下訓練和測試佔用的GPU資源,如果不設定,官方程式碼就會直接佔用它能看到的所有GPU資源……

為了方便我把訓練的語句寫成了指令碼run.sh,這樣就不用每次敲巨長的命令來啟動訓練了。為了並行執行三個程序,每執行一個就放到後臺去,同時拿一個檔案記錄log(要不然怎麼掛了你都不知道)。然後檢測當訓練程序結束後就殺死檢測的程序。啟動訓練和測試的指令碼程式碼如下。

tensorboard上記錄的訓練曲線如下所示,橙色是訓練的曲線,藍色是測試的曲線。

最終的準確率在95%左右,看losses曲線有過擬合的現象,但是嘗試修改了l2 regularize的權重,並無明顯效果。這是未來改進的方向。

完成訓練和測試並沒有結束。還要把訓練的模型匯出,對接之後應用的介面,並進行簡單的測試。這就有了export_and_test.sh指令碼。本來想把這個指令碼和run.sh寫成一整個指令碼的,但後來發現,使用時往往需要通過訓練結果選取測試準確率最高的模型匯出,而這個模型在訓練結束前是不知道的。所以不得已將指令碼分成了兩部分,並且在呼叫export_and_test.sh前需要手動修改checkpoint到想要匯出的模型編號,如下圖。

四、呼叫

呼叫的方法可以參考[1]中object_detection_tutorial.ipynb,我的呼叫程式碼就是從jupyter下載.py程式碼後修改而成。(說起來剛學會用github還不會用jupyter呢,尷尬)使用CPU識別一次的時間大約為0.7s,使用GPU則為0.4s,調整圖片大小對耗時影響不大。

好的,說完了整個實現的步驟,我們來看一看實現的效果!

正常的效果是下面這個樣子的!

但是有一些不規則的較難情況就無法識別出來,比如側臉(如下圖),這需要增加訓練資料來改善,畢竟這才用了240張圖片來訓練。

最後,來總結一下整個過程中學到的小知識們~

1、改善過擬合的思路有四個:

  1. 在訓練中加入dropout
  2. 在訓練中加入batch normalization
  3. 在訓練中加入regularization
  4. 資料增強data augmentation,就是增加圖片的噪音

2、python中==和!=用來判斷值是否相等,這與c是一樣的。

同時python中還有一個表示式is和is not,這個是用來判斷兩者是否是同一個物件,並非兩者的值是否相等。

本來這兩種表達是毫不相干的,但有一種表達是if a is not None: ……導致不明白的話會有些混淆。

3、指令碼語言中對於空格的要求十分嚴格,例如賦值時等號兩邊不能有空格,同時if語句括號中諸多空格需要特別注意,如果多一個或者少一個都會報錯。