【coremltools4】新しいconvertメソッドの使い方【Core ML】

 coremltoolsが4.0になって、Unified Conversion APIが追加されました。本記事では、新しく追加されたconvert()メソッドの使い方について解説します。

Unified Conversion APIとは

4.0でUnified Conversion APIが追加され、どのフレームワークでも統合されたconvert()メソッドでモデルを変換することができるようになりました。3.x系まではTensorFlowなどのフレームワークごとにconvert()メソッドが用意されていて、それを使っていました。

新しいconvert()メソッドがサポートしているフォーマットは下表の通りです。

フレームワークフォーマット
TensorFlow 1.xFrozen tf.Graph
Frozen (.pb)ファイル
tf.keras.Model
(.h5)ファイル
SavedModelディレクトリ
TensorFlow 2.xtf.keras.Model
(.h5)ファイル
SavedModelディレクトリ
concrete function
PyTorchTorchScriptオブジェクト
TorchScriptオブジェクトの(.pt)ファイル

Kerasは、tf.keras.Modelか、(.h5)ファイルが使用できます。

変換のサンプル

実際に私が使った変換コードをサンプルとして置いておきます。モデルはどれもKerasで作成した(.h5)ファイルです。

回帰問題

XORを実装したモデルを変換してみました。入力は2つ、出力は1つです。

model = ct.convert('xor.h5')

model.save('xor.mlmodel')

引数で(.h5)ファイルへのパスを指定するだけで変換できます。

変換したモデルをCore MLで使う場合は、次のようなコードになります。

let array = try! MLMultiArray(shape: [1, 2], dataType: .float32)
array[0] = 1.0
array[1] = 0.0
let input = xorInput(dense_1_input: array)
        
let output = try! model.prediction(input: input)
print("\(output.Identity[0].floatValue)")

MLMlutiArrayのshapeで入力行列の形状を指定しますが、[2]ではなくて[1, 2]と指定しなければならないようです。

出力結果はoutput.Identityに配列として格納されています。今回は出力は1つなので、Identity[0].floatValueで取り出しています。

クラス分類

モーションセンサーの値を入力してデバイスの姿勢を推論するモデルを変換してみました。3個 (X, Y, Z)×100個の入力に対して、4個(上、左、右、下)の出力です。

model = ct.convert('attitude.h5')

model.save('attitude.mlmodel')

このモデルを使ったSwiftコードは次のようになります。

    let array: MLMultiArray?

    let motionManager = CMMotionManager()

    init() {
        array = try! MLMultiArray(shape: [1, 100, 3], dataType: .float32)
        
        motionManager.accelerometerUpdateInterval = 0.1
        motionManager.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: {(motion:CMAccelerometerData?, error:Error?) in
            self.getAccelerometerData(data: motion!)
        })
    }

    func getAccelerometerData(data:CMAccelerometerData) {
        array![index + 0] = data.acceleration.x as NSNumber
        array![index + 1] = data.acceleration.y as NSNumber
        array![index + 2] = data.acceleration.z as NSNumber
        index += 3
        
        if index >= 300 {
            predict()
            index = 0
        }
    }
    
    func predict() {
        let input = attitudeInput(conv1d_1_input: array!)

        let output = try! model.prediction(input: input)
        
        for i in 0..<output.Identity.count {
            print("\(output.Identity[i].floatValue")
        }
    }

入力が多次元配列なので少し注意が必要です。Core MLでは入力は1次元配列に並べ替える必要があります。それをしているのが下記のコードです。

    func getAccelerometerData(data:CMAccelerometerData) {
        array![index + 0] = data.acceleration.x as NSNumber
        array![index + 1] = data.acceleration.y as NSNumber
        array![index + 2] = data.acceleration.z as NSNumber
        index += 3

出力は、各クラスの推定値を表示しています。

        let output = try! model.prediction(input: input)
        
        for i in 0..<output.Identity.count {
            print("\(output.Identity[i].floatValue")
        }

実行すると下記のような表示がされます。

0.99999
0.00000
0.00000
0.00000

これだけでも十分ですが、モデル変換時にクラスのラベル付けをしておくと、Swiftのコードが楽になります。

import coremltools as ct

model = ct.convert('attitude.h5', classifier_config=ct.ClassifierConfig(['UP', 'RIGHT', 'DOWN', 'LEFT'], predicted_feature_name='attitudeLabel'))

model.save('attitude.mlmodel')

ClassifierConfigの第1引数でラベルの文字列配列、第2引数のpredicted_feature_nameでラベルを保持する変数名を指定します。

こうするとSwift側のコードが次のように書けます。

        let output = try! model.prediction(input: input)

        print("\(output.attitudeLabel) : \(output.Identity[output.attitudeLabel])")

先ほど指定したattitudeLabelに、クラス分類した結果のラベル名が入るようになります。また、Identityの値は辞書型で格納されるので、そのラベル名をキーにすれば取得できます。

実行すると、次のような表示がされます。

UP : 0.9999879

クラス分類の場合は、こちらの方が使いやすいかと思います。


以降は、APIを日本語訳したものです。ご参考までに。

定義

coremltools.converters.convert(model, source=’auto’, inputs=None, outputs=None, classifier_config=None, minimum_deployment_target=None, **kwargs)

引数

model(必須)

ネットワークのモデルを指定します。

source(オプション)

モデルの元となったフレームワークを文字列で指定します。指定しなければautoになります。

  • auto(自動検出)
  • tensorflow
  • pytorch

ほとんどのケースで自動検出できます。自動検出で失敗したらValueErrorが発生します。

input(Pytorch:必須、TensorFlow:オプション)

モデルへの入力を、TensorTypeかImageTypeのリストで指定します。

PyTorchの場合

PyTorchモデルの場合は、ネストされたリストかタプルかもしれません。

TensorFlow 1.x, 2.xの場合

TensorFlowモデルの場合は、フラットなリストでなければなりません。

Noneを指定した場合、モデルがFrozenなtf.GraphであればPlaceholderノードとなり、モデルがtf関数であれば関数の入力となります。

Noneを指定しなかった場合、モデルの全てのPlaceholderのサブセットだけを含むかもしれません。

outputs(PyTorch:指定不可、TensorFlow:オプション)

モデルの出力を文字列のリストで指定します。

TensorFlowの場合

指定しなかった場合は、適当に名前を付けます。

classifier_config(オプション)

このモデルがクラス分類だった時に使用します。ClassifierConfigクラスを指定します。

minimum_deployment_target(オプション)

(調査中)列挙型coremltools.targetの1つを指定します。

参考URL

Unified Conversion API

convert API Reference