MotoJapan's Tech-Memo

技術めも

【iOS11 / CoreML】自作した回帰予測モデル(.mlmodel)の結果を得る実装方法 (Regression, VNCoreMLRequest)

iOS11がリリースされて3日経過したが、本家が提供するモデルはMobileNet、SqueezeNet、Places205-GoogLeNet、ResNet50、Inception v3と分類モデルが多く、サンプルコードも分類しか見つけられない。
なので、今回は回帰予測モデル(具体的には、1次元配列 : 3次元ベクトル回帰)について説明。(世間で回帰関連の記事もないので)

説明すること:回帰の場合の実装方法(比較として分類の場合も記載)
説明しないこと:CoreMLの基本的な使い方、実行方法(巷に溢れているので割愛)

参考資料

本家で提供される学習済みモデル一覧
Machine Learning - Apple Developer

CoreMLの分類サンプルコード
Classifying Images with Vision and Core ML | Apple Developer Documentation

回帰モデルの説明

自作したモデルは、1次元配列(3次元ベクトル)を求めるようなモデル。
(まぁ多次元配列でもスカラーでも、話は同じだったので割愛)
Kerasで学習させた回帰モデルをCoreMLToolsを用いて変換する。

変換イメージ

  • Keras model (.h5) → [CoreMLTools] → CoreML model (.mlmodel)

生成されたモデル (例えば、MyRegression.mlmodel) はXcodeでプロジェクトにドラック&ドロップすることで見える。

モデルの確認方法

  • プロジェクト上にドラック&ドロップした自作モデルをクリック -> [Model Evaluation Parameters] -> [outputs]

モデル情報は次の通り。

Name Type Description
output1 MultiArray<Double, 3> (未記入)

MultiArrayとして、3要素のDouble型1次元配列を回帰するモデルとなっていると確認できる。

[分類/回帰]モデルをロード

なんてことはない、分類も回帰も同じ手順

//学習済みmodelをロード (分類)
let model = try! VNCoreMLModel(for: MyClassification().model) # 提供される学習済みであればMobileNet()とか

//学習済みmodelをロード (回帰)
let model = try! VNCoreMLModel(for: MyRegression().model)

[分類/回帰]モデルと結果を受け取るコールバックを設定

ここも特に差はない、分類も回帰も同じ手順

//分類
let coremlRequest = VNCoreMLRequest(model: model, completionHandler: { (request, error) in
self?.processClassification(for: request, error: error)
})

//回帰
let coremlRequest = VNCoreMLRequest(model: model, completionHandler: { (request, error) in
self?.processRegression(for: request, error: error)
})

[分類/回帰]コールバック関数 / 結果の読み取り【最重要】

ポイントは下記で、分類と回帰でクラスを使い分ける

分類の場合 回帰の場合
VNClassificationObservation VNCoreMLFeatureValueObservation
//分類(VNClassificationObservation)
func processClassification(for request: VNRequest, error: Error?) {
    guard let observations = request.results as? [VNClassificationObservation] else { fatalError() }
    guard let best = observations.first else { fatalError() }
  //best.identifier : best時のクラス情報
    //best.confidence : best時の信頼度
}

//回帰(VNCoreMLFeatureValueObservation)
func processClassification(for request: VNRequest, error: Error?) {
    guard let observations = request.results as? [VNCoreMLFeatureValueObservation] else { fatalError() }
    guard let values = observations[0].featureValue.multiArrayValue!
    //valuesはここでArrayになっているので
    //あとはランダムアクセスすればスカラー値が取得できる
    //values[0], values[1], values[2]
}

ちなみに、回帰でbservations[0]の0は、学習時のバッチサイズの問題だと思っている。(確か)

感想

  • 単純な回帰だけでなく生成モデルとかやる場合は使いそう。
  • 17/09/23時点では、 Webで調べても全く記事が無く、世間はあまり回帰に興味が無いのか?
  • もっといい方法があれば教えてください。