iOS 使用coreML — yolo model

convert pretrained-yoloModel.h5 to coreML

Big N
碼農勤耕田
10 min readApr 2, 2020

--

最近有人問怎麼在iOS上使用訓練好的模型,雖然網路上已經有sampleCode了,不過可能coreMlTools更新過的關係,有點小小的不同,所以記錄一下踩坑的過程QQ。

大致上分為三步:

step1: 訓練模型(yolov3, keras),取得h5

這個我就不記錄怎麼train了,google滿多詳細的教學,可以照著做

這裡使用的是keras,如果是用pytorch或其它工具的話,本篇不適用。

step2: convert h5 file -> coreML

這邊的重點是用apple的coremltools去轉,網路上的sampleCode轉出來,跟實際結果有小小的不同,所以這邊是小小的重點。

還有一個就是trained好的模型,有些小地方還要改QQ,不能直接貼Code QQ,否則會遇到yolo_head is not defined

那為什麼要把h5轉成coreMl呢?因為iOS吃coreML,不會吃h5,而蘋果也寫了一個工具,讓我們可以把h5轉成coreML。

step3: XCode — load coreML

這裡就不多加介紹,直接放別人的網誌了XD

step1: 訓練模型(yolov3, keras),取得h5

基本上模型不會由手機端訓練,一般應該是用電腦先跑個一段時間,訓練出來的模型是一個h5的檔案。

如果只是想要練習怎麼把h5轉coreML的話,可以看下面這篇,參照quickStart取得h5檔案

基本上就是整包clone下來後,依序複製貼上下面兩程程式碼就可以取得h5了,轉出來的h5就在model_data這個資料夾裡頭。

wget https://pjreddie.com/media/files/yolov3.weights
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5

這樣就有已經trained好的h5了

如果要自己訓練資料的話,再google看看,滿多詳細的教學可以依序完成。

step2: convert h5 file -> coreML

本文重點記錄,大概再分成2小部份:

1: how to convert h5->coreML

用的是蘋果官方的小工具,可以看到github下方有寫如何使用,基本上也是直接照著做,用virtualenv去建置環境,我一開始偷懶,不管什麼虛擬環境,直接inistall,結果各種錯誤,(像是 coreml object has no attribute ‘convert’ ),踩一堆奇怪的坑,所以建議直接依照蘋果的作法,打開終端機,依序貼指令上去。

# 安裝virtualenv
pip install virtualenv
# 會建一個"mlvirtualenv"名稱的資料夾
mkdir mlvirtualenv
# 路徑進入至資料夾"mlvirtualenv"
cd mlvirtualenv
# 建一個虛擬環境,名稱叫作"pythonenv"
virtualenv pythonenv
# 啟動叫作"pythonenv"的虛擬環境
source pythonenv/bin/activate

# 這時候你的終端機前方應該就變成(pythonenv)了
# 再貼上下指令去安裝coreMlTools
pip install -U coremltools

好了,這樣coreMlTools就裝好了

之後因為是虛擬環境,所以要再裝一次tensorflow, keras

pip install keras==2.2.4
pip install tensorflow==1.14.0

2: how to implement h5 -> coreML by coremltools

這裡分兩段記錄,一個是已經上述qqwwee已經訓練好的model;另一個則是自己訓練的要怎麼做。

字面上看起來可能有點奇怪,明明都是h5,為什麼要分成「qqwwee的」跟「自己訓練的」,不都一樣嗎?

呃,其實我也不知道…..囧>||||||

如果是自己train的,轉coreML的時候會遇到一些怪事,要額外再多寫一點code

這是qqwwee的h5,用以下python程式碼,看是要貼到記錄本,存成py檔,還是直接在終端機輸入python,再依序貼上程式碼。

# import 蘋果的小工具
import coremltools
# 利用coremltools,把同層資料中,名稱為為"yolo.h5"的檔案轉型為mlModel
# 可以看到這裡用的是keras,如果你是用別的架構訓練的話,這裡不會work
model = coremltools.converters.keras.convert("./yolo.h5",
input_names='image',
image_input_names='image',
input_name_shape_dict={'image':
[None, 416, 416, 3]
},
image_scale=1/255.)
# 把剛剛的model存到同層資料夾,名稱命名為"yolo.mlmodel"
model.save("./yolo.mlmodel")

如果是自己trained的模型,依照上述的作法,可能會噴出’yolo_head’ is not defined這個錯誤,所以要稍作修改,我猜應該是因為qqwwee裡頭train完是寫save_weight,而不是save_model吧(?)

# 這裡的yolo3,是qqwwee內的yolo,所以要特別注意這時候你的路徑在哪裡
from yolo3.model import yolo_eval, yolo_body, tiny_yolo_body
from keras.layers import Input
import coremltools
# 最後一個參數YOUR_CLASS_NUM,是你辨識幾類,如果有80類,就是打80
model = yolo_body(Input(shape=(None, None, 3)), 3, YOUR_CLASS_NUM)
# 去讀你同層資料夾中,名為"customData.h5"的檔案
model.load_weights("./customData.h5")
# 這裡基本上就同剛剛的寫法了, 只是變成讀model,而不是讀路徑
mlModel = coremltools.converters.keras.convert(model,
input_names='image',
image_input_names='image',
input_name_shape_dict={'image': [None, 416, 416, 3]},
image_scale=1/255.)
# 把剛剛的mlModel存到同層資料夾,名稱命名為"customData.mlmodel"
mlModel.save("./customData.mlmodel")

好了,走到這裡就完成h5 -> mlModel了

step3: XCode — load coreML

這時候把模型直接拉到Xcode裡頭,應該就會發現「蛤蛤蛤???我的output的size根本不一樣啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊(大崩潰)」

左圖輸出有3維(255x13x13),是網上sampleCode的model;

而右圖輸出有1維(255),則是用上述方法轉出來的model。

所以用網上sampleCode直接執行就會GG

還好,原sampleCode的作者,也有針對這個issue回答,只要在Yolo.swift中

原本的
let channelStride = features.strides[0].intValue
let yStride = features.strides[1].intValue
let xStride = features.strides[2].intValue
改為
let channelStride = features.strides[2].intValue
let yStride = features.strides[3].intValue
let xStride = features.strides[4].intValue

也就是改index而已,因為原本的模型是拿到3維,但我們現在會拿到5維,前兩維都是1,所以往後取資料而已。

原sampleCode model
我們現在轉出來的model

走到這裡,如果一開始用的是qqwwee的模型,現在就已經結束了,只要替換model就可以順利執行了。

那如果是自己trained的模型,還要改什麼呢?

1- 模型的分類數量

在yolo.swift中
let numClasses = 80 // 這裡改成你自己分幾類

2-對應的label

在Helpers.swift中
let labels = ["1", "2", "3", ......]
labels的元素改為你要顯示的名稱

至於他整篇sampleCode是怎麼做的呢

可以參考原文

或是這位網友有介紹原本的sampleCode大概是怎樣的作法

--

--

Big N
碼農勤耕田

(1.01)³⁶⁵ = 37.8; (0.99)³⁶⁵ = 0.03; 每天多踩一個坑, 一年之後就變成坑王了!!! ;但是每天少踩一個坑…身體就會很變乾淨哦A口A(咦?)