YOLO with CoreML

Run object detection YOLO neural network with CoreML on iOS

前一篇介紹了一些影像辨識 (Object detection) 的深度學習模型,其中 YOLO — You Only Look Once是目前最好、最快、最強大的影像辨識模型,既然這麼好,我就想說那麼實際應用上是否可行呢?剛好拿 iOS CoreML 來練練手。

這邊的程式改自 YOLO: Core ML vs MPSNNGraph,該篇部落格文章的作者也是 Machine Learning iOS framework Forge 的作者,如果要使用該程式,直接從 github repo pull 下來用 xcode 打開就可以了。

我的程式碼做了一些變動:

  1. 從原本的 Tiny YOLO 模型改成 YOLO2 模型。Tiny YOLO 是 YOLO2 的簡化版,只能偵測 20 種物體類別,準確率也比較差,但是速度快!我用 iPhoneX 實測,Tiny YOLO 的偵測速度可以到 20–30 FPS 沒問題。但是我好奇,如果是 YOLO2 呢? YOLO2 可以偵測 80 種物體,準確率也比較高,速度比較慢是可預期的,但是會慢多少?
  2. 原本作者使用 yad2k script 將 darknet 格式的預先訓練模型轉成 Keras 1.2.2,再轉成 CoreML 格式。不過我不想 downgrade Keras,我使用 yad2k 時也一直不順利,所以在我的程式裡改使用其他方式來轉格式。
  3. 簡化部分程式碼,拿掉 NNGraph 的相關程式。主要原因是我只對 CoreML 有興趣。
  4. 修改程式碼中一些 YOLO2 相關的 Hyperparameters 。

在轉成 YOLO2 模型後,執行出來的結果在 iPhoneX 上約略在 2–3 FPS 左右,效能比 TinyYOLO 大概慢了 10 倍,但是可偵測的物體種類變多了。

我修改過的程式:

syshen/YOLO-CoreML

YOLO: You Only Look Once

關於 YOLO 可以看我前一篇文章,針對不同影像辨識深度模型的介紹。但簡單來說,YOLO 的作法在於將一張圖片切割成 SxS 個方格,以每個方格為中心取 k 個 bounding box 用同一組 CNN 模型來辨識物體種類的機率,以及可能的 bounding box 位置。

關於影像辨識,所有你應該知道的深度學習模型

YOLO2 在 YOLO 上加了很多改進方式,不僅提升辨識速度、辨識準確率,也增加可辨識種類。提升輸入圖檔的解析度也是其中一個改良,原有 YOLO 的 input shape 是 448x448x3,YOLO2 可以依所需的辨識率不同,用不同的 input shape size ,TinyYOLO 是 416x416x3,我所使用的模型是 608x608x3 。

CoreML & Vision Framework

Apple 在 iOS11 後推出 Vision Framework,提供一個圖像處理的 pipeline 架構,讓開發者可以很簡單的開發一些影像的相關處理,如: Rectangle detection、Face detection、Face landmark detection、Object tracking 等。它跟過去 CIDetector 比較不同的是,Vision Framework 可以串連 CoreML,使用深度學習來作影像處理,所以在臉部辨識上,CIDetector 難以處理側臉或者不完整的臉部,但是這些對深度學習來說都是小菜一疊。

左邊是透過 CIDetector 辨識人臉,辨識能力有限。右邊是透過 Vision Framework 做的臉部辨識,使用深度學習,不僅可以得到較好的結果,還可以偵測出人臉的 landmark 特徵

使用 Vision 一開始你需要建立一個 Request,然後再跟他講你想要怎麼處理圖像,最後觀察結果就好。Vision 是一個 pipeline 的處理流程,也幫開發者處理一些瑣碎的事情,像是改變圖像尺寸 (例如在我使用的 YOLO2 模型中,Input shape 需為 608×608,所以可以把 resize 工作交給 Vision Framework 處理即可)、修正圖檔的方向。

Vision 也支援 CoreML,CoreML 是 Apple 設計的 Machine Learning 框架,但是目前為止,你還不能使用 CoreML 來訓練你的模型,你只能在 iOS 或者 Mac 上使用 CoreML 模型,所以目前所有的 CoreML 模型都是由其他工具如 Caffe 、Tensorflow、Keras 訓練好,再轉檔成 .mlmodel 格式。而使用 CoreML 的好處是他底層與 Apple 的 Metal framework 整合,可以提供較好的效能,而且其他 framework 有些不是不支援 iOS 要不就是過於龐大。

Core ML 等層整合 Metal 支援不同 OS 的 GPU 功能

轉檔

重新訓練 YOLO 模型太花時間了,幸好 YOLO2 作者有提供預先訓練好的模型可供下載,但由於是 darknet 格式,我們要轉檔成 mlmodel 才能在 iOS 中使用,轉檔流程如下:

  1. YOLO/Darknet 官網下載 YOLO 模型
% curl https://pjreddie.com/media/files/yolo.weights > yolo.weights
% curl https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolo.cfg > yolo.cfg

yolo.cfg 記載了很多 Hyperparameter 設定,程式碼必須跟著這些 Hyperparameter 作更改。

2. 安裝 darkflow

% git clone https://github.com/thtrieu/darkflow.git
% cd darkflow
% python3 setup.py build_ext --inplace
% pip install -e .

3. 使用 darkflow 轉將 yolo.weights 轉成 tensorflow pb 格式

flow --model yolo.cfg --load yolo.weights --savepb

4. 也可以用 darkflow 測試一下轉檔後的結果

% flow --pbLoad ../yolo.pb --metaLoad ../yolo.meta --imgdir sample_img

執行後的結果會放在 sample_img/out 目錄下

5. 安裝 tf-coreml。tf-coreml 是 Apple 與 Google 合作開發的小工具,用來將 tensorflow 的檔案轉成 coreml 格式。

% pip install -U tfcoreml

6. Clone 我的 github repo,然後使用 Converter 目錄下的 Convert_pb_coreml.ipynb script 來轉檔 (使用 Jupyter notebook 來開啟檔案)

轉檔後就會得到 yolo.mlmodel ,你可以拿來直接加入到 Xcode project 中。

事實上,你也可以不用轉檔,在我的 github repo 中都幫你轉好了,只是 model 檔案太大,github 不給放,在 clone 我的 repo 後,請執行 download.sh 下載 model 檔。

關於 Jupyter notebook 的用法,可以參考我另外一篇深度學習入門的簡單教學。

入門深度學習 — 1

使用 Vision Framework 與 CoreML

詳細程式碼可以參考我 repo YOLO-CoreML 目錄下的檔案,程式是改自於 YOLO: Core ML vs MPSNNGraph

程式碼大概由幾個部分構成:

  1. Video capture,這邊是用 AVFoundation 來開啟相機抓取畫面,並將 CMSampleBuffer 轉成 CVPixelBuffer 。
  2. 當把 mlmodel 檔拉進 xcode project 時,xcode 會自動生成 Model class 程式碼,class 名稱就是 yolo,在這裡的程式,又在 yolo class 外再包一層 YOLO class,這一層其實沒有一定需要,只是將一些相關的 Hyperparameter 以及產生 bounding box 的函式一併包到裡頭去。
xcode 中 yolo.mlmodel 的內容,可以看到 Input node 名稱為 input__0,input 需要一個 608x608x3 的圖檔,Output node 名稱為 output__0,shape 大小為 19x19x425

初始 Vision 的方式如下:

建立 VNCoreMLModel 物件,再建立 VNCoreMLRequest,並且設定 visionRequestDidComplete 為 completion handler,並且指定 imageCropAndSacleOption 為 .scaleFill ,這裡是讓 Vision Framework 自動幫我們 Crop 跟 resize ,而 Vision Framework 會自動從 CoreML 的 input node 的 shape size 去判斷要 resize 成多大,所以前面 tf-coreml converter script 中有段參數要指定 image input node ,就是要指名轉出來的 CoreML 的 input node 為 image 。

當開啟相機取得 CVPixelBuffer 後,每個 pixel buffer 我們都建立一個 VNImageRequestHandler 物件,並執行前面的 request。

這裡的 startTimes 主要是來計算 FPS 用的。

每個 pixel buffer 處理完會呼叫 visionRequestDidComplete,在這裡我們可以把偵測的結果取出來並計算 bounding box。

這個版本的 YOLO 輸出是 19x19x425,也就是說他切割成 19×19 個方格,每個方格取 5 個 anchor boxes,每個 anchor box 會包含 80 種類別機率,以及 box 的 x,y,w,h 跟 confidence score 五個數值,所以 (80 + 5) * 5 = 425

上述的數字都是 Hyperparameter 需要從原有 training 設定中找出來,可以直接參考 yolo.cfg

在 YOLO.swift 中,取 bounding box 的方法就是先過濾 confidence score 過低的 box,然後在用 non-maximum suppression 來去掉彼此 overlap 太多的 box 。

取得 bounding box 後就是將這些方框畫到畫面上。

結語

YOLO 還有一個 YOLO9000 的版本,可以偵測 9000 多種不同的類別,有興趣的人也可以試試看 port 到 iOS CoreML 上去執行。

YOLO 雖然很強大,但是當要偵測到 80 種不同類別時,在 iPhoneX 上也只有 2–3 FPS ,還不到 real-time object detection,如果要放到一些更低階的裝置如監視系統或者 Camera 上的話,都還需要作更多的優化,甚至重新訓練,減少類別數,減少 layer 數應該都可以增加辨識速度。

此外,去年 Apple 也默默推出一個 Machine Learning 的訓練框架 — Turi Create,可以透過這個框架產生一些模型如 object detection、image classification、text classifier 等,不過似乎是以教學為目的開發的框架,細節我就沒詳加研究了。

最後

覺得我寫的還可以
請幫我拍手三下 ???

如果想要給我更多鼓勵
可以給我更多的拍手 ????????

感恩 ??

Source: Deep Learning on Medium