はじめに
iOS11から登場した「CoreMLフレームワーク」。
そしてCoreMLフレームワークで 使用するための機械学習のモデルファイル「.mlmodel」。
当記事では、この「.mlmodel」ファイルのコンパイルについて取り上げていきます。
また、こちらの記事はAKIBA.swift 第11?回にて発表させていただいた内容になるので、下記スライド資料もご参考ください。
https://speakerdeck.com/tajitaji/mlmodel-falsekonpairu
「mlmodel」とは?
まず、mlmodelとは何かについてざっくり説明します。
- Keras, Caffe, scikit-learn といった機械学習フレームワークにて作成した学習済みモデルをCoreMLフレームワークで使用するフォーマットに変換したもの
- 対応している機械学習フレームワークはこちら
- ファイル拡張子として「.mlmodel」を使う
※画像は https://developer.apple.com/documentation/coreml より
このように、CoreMLフレームワークを使用してmlmodelを使うことによって、機械学習をアプリにintegrateできます。
mlmodelのコンパイル
それでは、本題のmlmodelのコンパイルについて述べていきます。
前述の通り、mlmodelは事前に作成した学習済みモデルをCoreMLフレームワークで使用できるフォーマットに変換したファイルですが、
実際にCoreMLフレームワークで使用する際には、「.mlmodel」ファイルをコンパイルしたものを使用します。
コンパイル方法を3種類紹介します。
1. Xcodeでコンパイル
Xcode9以降、mlmodelファイルを扱うことができるようになりました。
▼ コンパイル方法
Xcodeを使ってmlmodelファイルをコンパイルする方法は下記の通りになります。
- Xcodeのプロジェクトにmlmodelファイルを追加する
- 追加したmlmodelファイルをプロジェクトのターゲットに追加する
- 2の時点でXcodeが自動コンパイルしてくれる
この様子はWWDCの講演でもデモがされていましたね。
https://developer.apple.com/videos/play/wwdc2017/703/ (22分を過ぎたあたり)
さて、Xcodeにmlmodelを追加すると、Xcodeが自動でSwiftのコードを生成します。
自動生成されるコードは、mlmodelの学習済みモデルをSwiftで使うためのクラスなどが定義されています。
さて、ここで、Xcodeで自動作成されたSwiftコードの一部を掲載します。
/// Construct a model that automatically loads the model from the app's bundle
convenience init() {
let bundle = Bundle(for: fruits_classifier.self)
let assetPath = bundle.url(forResource: "fruits_classifier", withExtension:"mlmodelc")
try! self.init(contentsOf: assetPath!)
}
これは、機械学習モデルを使用するクラスのinitializerの部分になります。(fruits_classifier
という名前は、元の.mlmodelファイルに由来するところなので自分の環境で読み替えてください。)
▼ mlmodelc
さて、上記コードの中に**mlmodelc
**という拡張子のファイルが呼び出されていることが分かるかと思います。
let assetPath = bundle.url(forResource: "fruits_classifier", withExtension:"mlmodelc")
これは、mlmodelをコンパイルするとできるもので、Swiftのコードからはこのmlmodelcを使用します。
Xcodeでのコンパイルに関わらず、mlmodelをコンパイルすると、mlmodelcができ、Swiftのコードからはmlmodelcを呼びます。
さて、それでは、このmlmodelcはどこにあるのでしょうか?
▼ mlmodelc の場所
initializerのドキュメントコメントにConstruct a model that automatically loads the model from the app's bundle
とありますが、
前述の方法によってXcodeでmlmodelが自動コンパイルされた場合、アプリのバンドルの中にmlmodelcが作られます。
下のキャプチャが実際にアプリの中をみてみたものです。
(アプリを仮にMyAppとすると、MyApp.appの中身)
このように、mlmodelcがディレクトリとして作成されていることが分かります。
▼ Xcodeでmlmodelをコンパイルするデメリット
正確には、mlmodel, mlmodelcをアプリのバンドルに組み込むデメリットになりますが、
下記のようなことが考えられます。
- 機械学習のモデルを更新したいときにアプリごとアップデートを行う必要がある
- mlmodelのサイズに伴って、アプリの容量が大きくなる
上記のようなことを回避する案として、mlmodelを最初からアプリに入れておくのではなく、アプリの機能としてネットワークを通じてmlmodelをダウンロードして使用するという方法が考えられます。
そうなったときに必要なのが、Swiftコードでmlmodelをコンパイルする方法です。
2. Swiftコードでコンパイル
▼ コンパイル方法
まず、事前にアプリからmlmodelファイルをダウンロードしておきます。
そのmlmodelファイルのローカルファイルパスを指定してコンパイルを行います。
// mldeolUrlはダウンロードした.mlmodelファイルのパス
let compiledUrl = try MLModel.compileModel(at: modelUrl)
let model = try MLModel(contentsOf: compiledUrl)
CoreMLのMLModel
クラスのタイプメソッドとしてcompileModel(at:)
というものがあるので、それを使用します。
https://developer.apple.com/documentation/coreml/mlmodel/2921516-compilemodel
返り値としてコンパイルされたmlmodelcのパスが返ってくるので、それを使用してモデルクラスをインスタンス化することができます。
▼ 注意点
- メインスレッドでは行なわない
- コンパイル処理が重い処理になりがちなのでメインスレッドは避ける
- コンパイルされた
mlmodelc
はtemporaryなディレクトリに保存される- 返り値として返ってくる
mlmodelc
のパスも当然temporaryなディレクトリ - 永続的に使用する場合はapplicationSupportDirectoryなどにコピーする
- 返り値として返ってくる
機械学習モデルファイルの更新などを考えると、このようにSwiftでのコンパイルを実行する機能をアプリに実装しておいたほうがいいかもしれません。
3. コマンドラインでコンパイル(おまけ)
使いどころが不明なのですが、こういう方法もありますというのをご紹介します。
情報お持ちの方、ご教授いただければ幸いです。
▼ 方法
下記のコマンドを使用してmlmodelファイルをコンパイルすることができます。
$ /Applications/Xcode.app/Contents/Developer/usr/bin/coremlc compile [path to mlmodel] [output path]
※/Applications/Xcode.app/Contents/Developer
の部分はxcode-select -p
にて出力されるパスです
まとめ
- mlmodelをコンパイルするとmlmodelcというディレクトリが作成される
- CoreMLからはmlmodelcを呼ぶ
- Xcodeでの自動コンパイルはアプリのバンドルにmlmodelcが作成される
- Swiftコードでのコンパイルには
MLModel.compileModel(at:)
を使用する - Xcodeのツールの中に
coremlc
というコマンドがあり、そのコマンドでコンパイルすることも可能
おわりに
以上、mlmodelのコンパイル方法をいくつか紹介しました。
まだ情報が少ないので、今回紹介した内容は公式ドキュメントに書いてあることも多いですが、間違いなどあればご指摘いただければ幸いです。
また、mlmodelについて調べていると、Protocol buffersが関連していることがわかってきたので、そのあたりも深掘りしていきたいと思います。