使用 Turi Create 製作圖案辨識的 App - Core ML and Vision
Turi Create是一個拿來做 machine learning model 的 Python 模組,在 WWDC18 上,有多個 Session 直接在現場使用這個模組直接 Demo。他可以讓 iOS 開發者在使用 Core ML 模組時,更專注在 APIs 的行為上。除些之外,你如果有些初步的想法,你不用去找一個 ML 專家或是把自己變成 ML 專家,也能做出一個初步的 ML Model,讓這個 model 先做 prototype 再發揚光大。
在 WWDC18 Session 712 中,整個 session 都在介紹 Turi Create,如果對那個 Session 有興趣,你可以看下面這一篇 Medium。
讓我們開始 Demo Turi Create 裡面會用到的 API,以及他怎麼實作吧。我們要實作的是判斷這張圖裡面是不是金城武。範例影片放在這個 Youtube 上,除了判斷是不是金城武以外,還加上了信心指數。
信心指數的意思,你的 model 對這個結果有多少的信心,這個數字會在 0~ 1.0 之間。如果他判斷這張圖不是金城武,然後信心指數是 0.97。就表示這個 data 對這個 model來說,「不是金城武」這結果有 0.97 的信心指數。
要做 image classification 前,你需要有 image data,然後針對該分類建立資料夾,並把對應的圖片放到資料夾內。當然資料是愈多愈好,但至少該放多少呢?蘋果的投影片中有提到,建議至少放個 40 張當做 data。
如下圖所示,我在網路上搜尋了 40 張金城武的照片,然後放進 kaneshiro 這個資料夾。不過比較困難的地方,是「非金城武」這邊的 data 應該放什麼呢? 就邏輯來說,就是放所有非金城武的照片,但這些照片到底該放哪些呢? 因為是範例,所以我這裡就先放數十張非金城武的人像照當做 demo ,真正在做這種專案的時候,還是建議詢問資料科學領域的人,你想處理的資料該怎麼訓練模型。
當你的資料放好了,你就可以用下面這些程式碼進行 model 的訓練和 Core ML 的輸出。程式碼的數量相當的低,這邊只用了 12 行而已 (註解不算)。你可以在 (Ref-1) 上直接下載 Jupyter Notebook 的檔案
Turi Create 在讀取檔案的時候非常聰明,如果他讀的案是他不支援的,他會吐出 error message,但程式會繼續執行。下圖示範了這個結果,.DS_Store 是 mac 系統裡面存放空間資料用途,這是給 Mac OS 的 finder 程式使用的。
如果你的 Jupyter Notebook 是第一次跑,程序會連到 Apple 的 model 網站去下載相關資料。
下面就是模型訓練時, Turi Create 會吐出來的資訊
Analyzing and extracting image features.+------------------+--------------+------------------+| Images Processed | Elapsed Time | Percent Complete |+------------------+--------------+------------------+| 64 | 3.16s | 50% || 74 | 11.34s | 100% |+------------------+--------------+------------------+Logistic regression:--------------------------------------------------------Number of examples : 74Number of classes : 2Number of feature columns : 1Number of unpacked features : 2048Number of coefficients : 2049Starting L-BFGS--------------------------------------------------------+-----------+----------+-----------+--------------+-------------------+| Iteration | Passes | Step size | Elapsed Time | Training Accuracy |+-----------+----------+-----------+--------------+-------------------| 0 | 1 | NaN | 0.017910 | 0.540541 | 1 | 7 | 0.000083 | 0.125282 | 0.540541 | 2 | 10 | 5.000000 | 0.181402 | 0.918919 | 3 | 11 | 5.000000 | 0.207410 | 0.945946 | 4 | 12 | 5.000000 | 0.242203 | 0.459459 | 5 | 14 | 1.000000 | 0.280374 | 0.864865 | 10 | 20 | 1.000000 | 0.409511 | 1.000000 +-----------+----------+-----------+--------------+-------------------+Completed (Iteration limit reached).This model may not be optimal. To improve it, consider increasing `max_iterations`.Analyzing and extracting image features.+------------------+--------------+------------------+| Images Processed | Elapsed Time | Percent Complete |+------------------+--------------+------------------+| 13 | 2.53s | 100% |+------------------+--------------+------------------+1.0
我個人覺得這個模組很棒的地方,是他會提示你這個模型是不是需要再修正。像上面的 message 中可以看到一行: This model may not be optimal. To improve it, consider increasing `max_iterations`. 這是因為我 max_iterations 只給預設值,結果他跑出來後覺得這個模型準確率太低,並直接建議你調高 max_iterations。
跑完後你就可以拿到 mlmodel 這個檔案,而且你還可以看到 model 細項。以本文為例,你可以看到他有說明這個是 mlmodel 是用於 image clasifier,而且是從 Resnet-50 訓練出來的, Turi Create 版本是 5.0 beta 3。
底下則是 input 和 output 訊息,你要輸入的是彩色 224 x 224 的圖片。然後他輸出有兩個,如果是 kaneshiroOrNot,則是這個 model 判出來的結果。因為當初我們只設定兩個 label,一個是 Kaneshiro,另一個是 Unknown。所以這一項一定是這兩個其一。
另一個輸出是 kaneshiroOrNotProbability 他是個 dictionary,key 是每個 label,value 是該 label 的信心指數,雖然這個範例只有兩個 label ,但實際上你能訓練出能辨試多種水果的 model,這時候你可能會想知道每個 label 的信心指數,去看有沒有可能有近似的結果,再去做處理。
接下來,我們開始寫圖像辨識的專案吧。因為這個專案極有可能用到照相機和相簿功能,請記得在 info.plist 裡面做 Privacy 請求。
在這裡,我先使用 App Coda 的方法 (Ref-2)讓 ML Model 去讀取 UIImage 檔案。我也試用過 Vision 模組的 VNRequest,但辨識的結果差很多,而且該檔案和模組都是直接從 Apple 上下載下來的。我想,可能還有些參數我應該要調整才能讓辨識率提高。目前 App Coda 的這個方法,辨識率還不錯,就先用這種方式。
在 UIImage 裡面 extension buffer 這個 method。讓原來的 image data 專換成 VCPixelBuffer 格式, Core ML 模組才能辨識。
接下來就是辨識的核心 method。因為我們的 MLModel 是基於 Resnet 所訓練出來的,所以他吃的是 224 x 224 的 image,這個資訊你可以在 MLModel file detail 看到。
接下來,只要在取得 image 物件後,去呼叫 judgeKaneshiro(:),就完成了。舉例來說,像是鏡頭取得 image 後。
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
實際跑一遍,你會發現,這個範例並沒有那麼準,比如說,有幾張金城武的照片,因為髮型或者背景不一樣,他就認為這不是金城武。然後,我也試著把古天樂放進去判斷看看,結果他認為這個是金城武。這樣的問題並沒有辦法在這裡用程式碼解決,因為這是 mlmodel 判斷的結果。要處理的話,要從訓練 model 那邊開始下手。建議你可以試著換換 model,或是調整 dataset,或是調一下 max_iterations 參數試試看。
整個專案都放在下面這個 GitHub ,你可以在 Project_KaneshiroOrNot 中找到 XCode 的檔案。Turi Create 的程式碼則可以在 Jupyter Notebook 的 folder 中找到。
Ref-1: GitHub位址
Ref-2: App Coda 的範例, 分辨照片是湯或是飯