はじめに

本書はCore ML Toolsの実践入門書です。KerasやTensorFlowを用いて構築した機械学習/ディープラーニングのモデルをiOSで利用するために必要な変換ツールである「Core ML Tools」(Pythonパッケージ名としてはcoremltools)の利用方法をさまざまなモデルをつくりながら学んでいきます。

最初はわずか2行のコードで変換することからはじめてCore ML Toolsに入門しつつ、もっと高度な変換方法や、モデルのサイズを縮小する方法、パイプラインを構築する歩法、オンデバイスで学習できるようにする方法等も解説していきます。

また巻末には「逆引きリファレンス」も収録しています。開発の現場で「どう書くんだっけ?」となったときに大いに役立つことでしょう。

対象読者

筆者はiOSエンジニアであり、基本的にその目線で書いてあります。したがって本書のiOSパートはXcodeやSwiftやUIKitについては習熟していることが前提になります。coremltoolsパートはiOSの知識は必要ないものの、やはりPythonの構文等については解説していません。また「機械学習とは」「ディープラーニングとは」といった内容や、ニューラルネットワークの各種レイヤーや関数の意味や効果についても、既に多くの良書があるため本書では解説していません。

iOSの基礎と機械学習の概念は理解しており、Core MLモデルを自作する方法について学びたい、という場合には本書は役立つでしょう。

動作環境

本書は以下の環境に準拠しています。

  • macOS Catalina 10.15
  • Python 3.7
  • TensorFlow 1.14.0
  • Keras 2.2.4
  • Core ML Tools 3.3
  • iOS 13(Core ML 3) / Swift 5 / Xcode 11

サンプルコード

本書のサンプルコードはhttps://github.com/shu223/iOSMLBookで公開しています。

目次

はじめに

対象読者
動作環境
サンプルコード

第1章 準備

1.1 Core ML Toolsとは
  • Core ML Tools? coremltools?
1.2 Core ML Toolsの環境構築
  • 1.2.1 Core ML Toolsのインストール
  • 1.2.2 TensorFlowのインストール
  • 1.2.3 Kerasのインストール
  • 1.2.4 動作確認
  • KerasとCore ML Tools

第2章 Core ML Toolsはじめの一歩

2.1 2行のコードで学習済みモデルをロードする
2.2 2行のコードでCore MLモデルに変換する
2.3 変換したモデルを.mlmodelファイルとして保存

第3章 Core MLモデル作成の基礎

3.1 HDF5ファイルを読み込む
3.2 Core MLモデルに変換する
  • 3.2.1 .mlmodelファイルとして保存する
  • 3.2.2 Core MLモデルの入力の型とVisionフレームワーク
3.3 Core MLモデルの入力の型を変更する
  • 3.3.1 Core MLモデルの入力形式を確認する
  • 3.3.2 入力の型をグレースケール画像に変更する
  • Core MLモデルから自動生成されるSwiftコード
3.4 iOSで推論を実行
  • 3.4.1 作成したCore MLモデルをプロジェクトに追加する
  • 3.4.2 VNCoreMLModelの初期化
  • 3.4.3 VNCoreMLRequestの作成
  • 3.4.4 VNImageRequestHandlerの作成/推論処理の開始
  • 3.4.5 推論結果の処理
  • Visionはどのように画像分類モデルを判定するか?

第4章 オンデバイス学習 - UpdatableなCore MLモデルの作成

4.1 モデルのパーソナライゼーション
4.2 ベースとなるモデルの作成
  • モデルの現状を確認
4.3 Updatableなモデルに変換する
4.4 損失関数をセットする
4.5 最適化アルゴリズムをセットする
4.6 エポック数をセットする
4.7 モデルを保存する

第5章 オンデバイス学習 - iOSで学習

5.1 MLUpdateTask
  • 5.1.1 mlmodelc
  • 5.1.2 MLBatchProvider, MLArrayBatchProvider
  • 5.1.3 MLTask
  • 5.1.4 オンデバイスモデル更新タスクの全体感
5.2 学習データの準備
  • 5.2.1 MNISTデータセットをプロジェクトに追加する
  • 5.2.2 学習データからMLArrayBatchProviderオブジェクトを作成する
5.3 学習タスクの実行
5.4 オンデバイスで学習したモデルを保存する / MLUpdateContext, MLWritable
5.5 推論処理の実行

第6章 TensorFlowモデルの変換 - 基礎編

6.1 tfcoreml
6.2 tfcoremlを用いたCore MLモデルへの変換(最小実装)
  • 6.2.1 学習済みモデル(.pbファイル)を読み込む
  • 6.2.2 TensorFlowのグラフ定義を読み込む
  • 6.2.3 出力テンソルの名前を取得する
  • 6.2.4 tfcoremlを用いて変換する
6.3 より扱いやすいCore MLモデルに変換する
  • 6.3.1 クラスラベルを指定する
  • 6.3.2 入力の型を画像に変更する
6.4 iOSで推論を実行
6.5 入力画像の前処理を指定する

第7章 TensorFlowモデルの変換 - 画風変換モデル

7.1 学習済みモデルからグラフ定義を読み込む
7.2 変換に必要なグラフの情報を取得する
  • 7.2.1 入力テンソルの名前を取得する
  • 7.2.2 出力テンソルの名前を取得する
7.3 tfcoremlを用いて変換する
  • 7.3.1 入力テンソルのshapeを指定する
7.4 Core MLモデルの出力の型を変更する
7.5 iOSで画風変換を実行
  • 7.5.1 複数の入力を持つCore MLモデルをVisionで使う
  • 7.5.2 出力画像を取得する

第8章 Flexible Shape - 超解像モデル

8.1 Flexible Shapeとは/使いどころ
8.2 超解像モデルをCore MLモデルに変換する
  • 8.2.1 利用する超解像モデル
  • 8.2.2 カスタム損失関数を使用しているKerasモデルの読み込み
  • 8.2.3 Core MLモデルに変換する
  • 8.2.4 Core MLモデルの出力の型を変更する
8.3 Flexible Shapeを適用する
  • 8.3.1 Flexible Shapeの適用可否を確認する
  • 8.3.2 入力・出力の画像サイズを範囲で指定する
  • 8.3.3 Flexible Shapeを適用したモデルのSpecification Version
8.4 iOS側での推論処理の実行

第9章 Core MLモデルのサイズを小さくする

9.1 本章で利用する感情認識モデルについて
9.2 重みを16ビット化する
  • 9.2.1 16ビット化が推論結果の精度に与える影響
  • 9.2.2 Core MLモデルを16ビット化する手順
9.3 クォンタイズ
  • 9.3.1 クォンタイズ実行手順
9.4 iOSでの推論結果の比較
9.5 さらなるモデルサイズ削減
  • 9.5.1 ルックアップテーブルを利用した量子化
  • 9.5.2 モデルの一部を共通化

第10章 パイプラインモデルとリンクモデル(Linked Model)

10.1 パイプラインの構築
  • 10.1.1 coremltools.models.pipelineモジュール
  • 10.1.2 PipelineClassifierオブジェクトの生成
  • 10.1.3 パイプラインにモデルを追加
  • 10.1.4 MLModelオブジェクト生成
10.2 リンクモデル(Linked Model)
  • 10.2.1 リンクモデルとは/リンクモデルを使用するメリット
  • 10.2.2 パイプラインとリンクモデル
  • 10.2.3 リンクモデルの作成方法
Create MLのモデルはなぜ小さいのか
  • 10.2.4 Create MLとパイプライン
  • 10.2.5 Vision FeaturePrint

第11章 モデルの可視化

11.1 Netron
  • 11.1.1 インストール方法
  • 11.1.2 使用方法
11.2 coremltoolsのvisualize_spec
11.3 TensorBoard
  • 11.3.1 TensorFlowモデルのグラフを可視化
  • 11.3.2 Kerasでの学習状況を可視化
11.4 Kerasのplot_model

第12章 mlmodelファイルフォーマット

12.1 mlmodelファイルフォーマットを理解するメリット
12.2 .protoファイルの読み方
12.3 coremltoolsとprotobuf
  • 12.3.1 *_pb2
  • 12.3.2 .protoファイルのコンパイル
  • 12.3.3 _pb2.pyと.protoの比較
  • 12.3.4 mlmodelファイルのデシリアライズ
12.4 protobuf API
  • 12.4.1 WhichOneof()
  • 12.4.2 HasField()
  • 12.4.3 ClearField()
  • 12.4.4 add(), append(), extend()
  • 12.4.5 CopyFrom()
  • 12.4.6 ByteSize()

付録A coremltools逆引きリファレンス

A.1 MLModelオブジェクトを生成する
  • .mlmodelファイルから生成する
  • spec(Model_pb2.Model)から生成する
A.2 モデルのspec(Model_pb2.Model)を取得する
  • .mlmodelファイルから取得する
  • MLModelオブジェクトから取得する
A.3 .mlmodelファイルの保存・読み込み
  • .mlmodelファイルを読み込む
  • .mlmodelファイルとして保存する
A.4 NeuralNetworkBuilderを生成する
A.5 モデルの中身を調べる
  • モデルを可視化(ビジュアライズ)する
  • モデルのバージョン(Specification Version)を確認する
  • モデルのdescriptionをログに出力する
  • ネットワークの情報をログに出力する
  • NeuralNetworkBuilderでモデルの入力・出力形式を確認する
  • モデルのレイヤー一覧を出力する
  • モデルの中間層の入出力形式を調べる
A.6 Core MLモデルにクラスラベルを与える
  • ラベル文字列の配列を渡す
  • クラスラベルファイルのパスを渡す
A.7 モデルの入力・出力をカスタマイズする
  • 入力・出力名を指定する
  • 変換時に入力の型を画像型にする
  • 変換済みモデルの入力・出力の型を画像型にする
  • 入力テンソルのshapeを指定する
  • 入力画像の前処理を指定する
A.8 モデルサイズを圧縮する
  • 重みを16ビット(半精度)化する
  • 重みをクォンタイズする
A.9 オンデバイス学習関連
  • モデルがUpdatableかどうかを調べる
  • Updatableなレイヤー一覧を出力
  • Updatableなモデルに変換する
  • 学習で使用する損失関数をセットする
  • 損失関数のサマリを確認する
  • 学習で使用する最適化アルゴリズム(オプティマイザ)をセットする
  • 最適化アルゴリズムを確認する
  • エポック数をセットする
A.10 Flexible Shape関連
  • Flexible Shapeの適用可否を確認する
  • 入力・出力の画像サイズを範囲で指定する
  • 入力・出力に複数の画像サイズを指定する
A.11 misc.
  • 利用中のcoremltoolsのバージョンを確認する

付録B Keras入門

B.1 Kerasとは
  • B.1.1 tf.kerasとスタンドアロン版Keras
B.2 Kerasでカスタムモデル作成
  • B.2.1 モデルのネットワークを定義する
  • B.2.2 モデルのコンパイル
  • B.2.3 モデルの学習
  • B.2.4 モデルの評価
  • B.2.5 モデルの保存

参考文献

第1章 準備

本章ではまず、Core ML Toolsとは何か、といった前提知識の説明や、本書で利用する環境の構築手順について解説します。

1.1 Core ML Toolsとは

Core ML Toolsは、さまざまな機械学習フレームワークで作成されたモデルをCore MLモデルフォーマット(.mlmodel)に変換するツールです。

図1.1:

GitHubのAppleアカウント配下でオープンソースとして運用されています。

2020年3月現在、coremltoolsの最新リリースバージョンは3.3で、以下のフォーマットをサポートしています*1

  • Caffe V1 (.prototxt, .caffemodel format)
  • Keras API (2.2+) (.h5 format)
  • TensorFlow 1 (1.13+) (.pb frozen graph def format)
  • TensorFlow 2 (.h5 and SavedModel formats)

Core ML Tools? coremltools?

developer.apple.comでは主に"Core ML Tools"と表記され、GitHubのリポジトリやAPIドキュメント(https://apple.github.io/coremltools/)では主に"coremltools"と表記されており正式な表記に迷いますが、本書ではツール名称としては前者、Pythonパッケージとしての文脈では後者の表記を用いることにします。

1.2 Core ML Toolsの環境構築

環境構築手順を解説します。本書ではCore ML Toolsの入門として、Keras, TensorFlowで作成したモデルの変換を行うので、それらもインストールします*2。なお前提として、筆者はAnacondaでPython 3.7の仮想環境を用意しました*3

1.2.1 Core ML Toolsのインストール

まずはcoremltoolsをインストールします。

$ pip install -U coremltools

手順としてはこれだけです。次のようにPythonコードを実行すると、利用中のCore ML Toolsのバージョンが確認できます。

$ python
>>> import coremltools
>>> print(coremltools.__version__)    # 3.3

最新リリース版にアップデートする際にはまた同様に-U/--upgradeオプションをつけてpip installを実行してください。

$ pip install -U coremltools

1.2.2 TensorFlowのインストール

インストールしたCore ML Toolsバージョンに合うTensorFlowバージョンの番号を指定してインストールを実行します。

$ pip install tensorflow==1.14.0

こちらも次のようにバージョン確認できます。

$ python
>>> import tensorflow
>>> print(tensorflow.__version__)     # 1.14.0

1.2.3 Kerasのインストール

こちらも利用するCore ML Toolsバージョンに合わせてバージョン番号を指定してインストールします。

$ pip install keras==2.2.4

1.2.4 動作確認

サンプルコード: coremltools/keras_helloworld.ipynb

Kerasが利用可能となっているはずなので、確認としてバージョンを出力してみましょう。

import keras
print('Hello, Keras. version:', keras.__version__)

上記のコードをJupyter Notebookに打ち込んで、実行してください。以下のような出力が得られます。

Hello, Keras. version: 2.2.4

Kerasが利用可能となっていることがわかります。またバージョンとしてもCore ML Toolsがサポートしているものとなっていることが確認できます。

なお、本書では使用しませんが、TensorFlow同梱版のKerasを利用する場合はtensorflow.kerasをインポートします。

import tensorflow as tf
import tensorflow.keras as keras
print(keras.__version__)          # 2.2.4-tf

KerasとCore ML Tools

前述のcoremltools 3.3のサポート一覧から、Kerasをサポートしていることがわかります。つまり、Kerasで構築・学習し、.h5形式で書き出したモデルは、Core ML Toolsを用いて.mlmodelファイルに変換し、iOSアプリに組み込んで用いることができます。

  • TensorFlowをそのまま使うよりも簡単にカスタムモデルを作成できる
  • Core ML Toolsが正式サポートしており、Core MLモデルに変換してiOSで用いることができる

以上2点が、本書の冒頭でKerasを採用している理由となります。

[*2] Kerasについては付録B「Keras入門」で基礎から解説しています。

[*3] 本書ではサンプル実行にJupyter Notebookを利用するため、仮想環境にはJupyterもインストールしています。Anaconda環境であれば、conda install jupyterでインストールできます。

第2章 Core ML Toolsはじめの一歩

まずはKerasに用意されている学習済みモデルをCore MLモデルに変換してみるところから始めてみましょう。モデルを構築するところが省けるので非常にシンプルなコードでKerasやCore ML Toolsがどういうものかを学べますし、また既存モデルの取り扱いは今後ファインチューニングや転移学習を行う際にも必要となってきます。

サンプルコード: coremltools/keras_firststep.ipynb

2.1 2行のコードで学習済みモデルをロードする

Jupyter Notebookで新規ノートブックを作成し、次のコードを書いてください。

# VGG16をインポート
from keras.applications.vgg16 import VGG16

# VGG16オブジェクトを生成
model = VGG16()

たったこれだけのコードで、Kerasが持っている学習済みモデルのひとつVGG16を使用する準備ができました。確認のため、summary()メソッドを用いてモデルのサマリを出力してみましょう。

model.summary()

実行すると以下のような出力が得られます。

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         (None, 224, 224, 3)       0
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 224, 224, 64)      1792
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 224, 224, 64)      36928
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 112, 112, 64)      0
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 112, 112, 128)     73856
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 112, 112, 128)     147584
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 56, 56, 128)       0
_________________________________________________________________
(中略)
_________________________________________________________________
flatten (Flatten)            (None, 25088)             0
_________________________________________________________________
fc1 (Dense)                  (None, 4096)              102764544
_________________________________________________________________
fc2 (Dense)                  (None, 4096)              16781312
_________________________________________________________________
predictions (Dense)          (None, 1000)              4097000
=================================================================
Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0
_________________________________________________________________

VGG16*1のネットワークが得られていることが確認できます。

2.2 2行のコードでCore MLモデルに変換する

この学習済みモデルをCore ML ToolsでCore MLモデルに変換してみましょう。

KerasのモデルをCore ML形式に変換するには、coremltools.converters.kerasconvertメソッドを使用します。第1引数にはKerasモデルのオブジェクトを渡します*2

import coremltools

mlmodel = coremltools.converters.keras.convert(model)

上記コードを実行すると次のようなログが出力されます。

0 : input_1, <keras.engine.input_layer.InputLayer object at ...>
1 : block1_conv1, <keras.layers.convolutional.Conv2D object at ...>
2 : block1_conv1__activation__, <keras.layers.core.Activation object at ...>
3 : block1_conv2, <keras.layers.convolutional.Conv2D object at ...>
4 : block1_conv2__activation__, <keras.layers.core.Activation object at ...>
5 : block1_pool, <keras.layers.pooling.MaxPooling2D object at ...>
(中略)
32 : flatten, <keras.layers.core.Flatten object at ...>
33 : fc1, <keras.layers.core.Dense object at ...>
34 : fc1__activation__, <keras.layers.core.Activation object at ...>
35 : fc2, <keras.layers.core.Dense object at ...>
36 : fc2__activation__, <keras.layers.core.Activation object at ...>
37 : predictions, <keras.layers.core.Dense object at ...>
38 : predictions__activation__, <keras.layers.core.Activation object at ...>

2.3 変換したモデルを.mlmodelファイルとして保存

前項で使用したconvertメソッドでは、返り値としてMLModelクラスのオブジェクトが得られます。同クラスが持つsaveメソッドを用いてCore MLモデルを.mlmodelファイルとして保存することができます。

mlmodel.save('./VGG16.mlmodel')

作成した.mlmodelファイルがちゃんとCore MLモデルファイルになっているか確認してみましょう。.mlmodelファイルをXcodeで開いてください。

図2.1:

しっかりCore MLモデルとして生成できていることがわかります。

さて、ここまで正味のコードはimportを入れてもわずか5行です。たったこれだけのコードでKerasからモデルを読み込み、Core ML Toolsで変換し、iOSで使えるCore MLモデルファイルを出力できたことになります。

# VGG16モデルをロード
from keras.applications.vgg16 import VGG16
model = VGG16()

# Core MLモデル形式に変換
import coremltools
mlmodel = coremltools.converters.keras.convert(model)

# 変換したモデルを.mlmodelファイルとして保存
mlmodel.save('./VGG16.mlmodel')

[*2] coremltools.converters.keras.convertには他にも多くの引数がありますが、第1引数以外はすべてoptionalです。そのうちいくつかの引数については以降の章で使用します。

第3章 Core MLモデル作成の基礎

本章では前章からは一歩進んで、Core MLモデルにクラスラベルの情報を持たせたり、入出力の型を変更する方法について解説していきます。いずれもCore MLモデル作成において必須の知識となります。

サンプルコード: coremltools/mnist_cnn_convert.ipynb

なお、本章で用いる学習済みモデルは筆者がKerasで独自に構築・学習したモデルです。Kerasを用いたカスタムモデルの作成方法の基礎については付録B「Keras入門」で解説しています。

3.1 HDF5ファイルを読み込む

Kerasで作成したHDF5形式(.h5)のモデルファイルを読み込むには、keras.models.load_model(filepath)メソッドを使用します。

from keras.models import load_model

keras_model = load_model('./KerasMnist.h5')

3.2 Core MLモデルに変換する

coremltools.converters.keras.convertメソッドを用いて変換を行います。

from coremltools.converters import keras as converter

class_labels = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

mlmodel = converter.convert(keras_model,
                            input_names=['image'],
                            output_names=['digitProbabilities'],
                            class_labels=class_labels,
                            predicted_feature_name='digit')

前章とは違い、第1引数にKerasモデルオブジェクトを渡しているだけではなく、他のさまざまな引数を用いている点に注目してください。

引数class_labelsにはその名の通りクラスラベルを渡します。上のコード例のように文字列の配列で渡すか、クラスラベルファイル*1のパスを文字列で渡します。

引数input_namesには、Core MLモデルの入力の名前のリストを渡します。何も指定しなければ名前は[input1, input2, …, inputN]となります。引数output_namesは同様にCore MLモデルの出力の名前を与えるもので、指定しなければ[output1, output2, …, outputN]となります。第2章でconvertを実行した際にはこれらを指定しなかったため、デフォルトの名前が付いていました。

図3.1:

引数predicted_feature_nameには、Core MLモデルのクラスラベル出力の名前を与えます。デフォルトではclassLabelとなります。

戻り値の型はMLModelです。Core ML形式のモデルを表すクラスです。

ではconvertメソッドを実行してみましょう。次のようなログが出力されます。

0 : conv2d_1_input, <keras.engine.input_layer.InputLayer object at ...>
1 : conv2d_1, <keras.layers.convolutional.Conv2D object at ...>
2 : conv2d_1__activation__, <keras.layers.core.Activation object at ...>
...

3.2.1 .mlmodelファイルとして保存する

変換したCore MLモデルを.mlmodelファイルとして保存します。第2章と同様にsaveメソッドを使用します。

coreml_model_path = './MNISTDigitClassifier.mlmodel'
mlmodel.save(coreml_model_path)

保存した.mlmodelファイルをXcodeで開いてプレビューしてみましょう。

図3.2:

Core ML Toolsでの変換時に指定した各名前がきちんと反映されていますね。

3.2.2 Core MLモデルの入力の型とVisionフレームワーク

しかし、入力の型が"MultiArray (Double 1x28x28)"となっている点に注目してください。このCore MLモデルを用いてiOSで推論処理を実装しようとすると、VNCoreMLModelを初期化しようとするところで、

let model =  try! VNCoreMLModel(for: MNISTDigitClassifier().model)

次のような実行時エラーになってしまいます。

Error Domain=com.apple.vis Code=15 "The model does not have a valid input feature of type image"

Visionを用いてCore MLモデルを利用する実装を行う場合は、入力の型がMultiArray(MLMultiArray)ではなくCVPixelBuffer等の画像型である必要があります。

3.3 Core MLモデルの入力の型を変更する

画像を入力とするCore MLモデルをiOSで使用する場合は、上位レイヤーであるVisionフレームワークを用いて実装したほうが(Core MLフレームワーク単体で実装するよりも)簡単になります。Visionを使用できるよう、Core MLモデルの入力の型をMultiArrayからImageにCore ML Toolsで変更します。

3.3.1 Core MLモデルの入力形式を確認する

まず、作成したモデルの入力形式をcoremltoolsを用いて確認してみましょう。

coremltools.models.utilsload_specメソッドを用いてモデルの仕様を表すModel_pb2.Modelオブジェクト(以下specオブジェクト)を取得します。引数にはファイルパスを渡します。

import coremltools

spec = coremltools.utils.load_spec(coreml_model_path)

次にcoremltools.models.neural_network.builder.NeuralNetworkBuilderクラスを初期化します。spec引数には取得したspecオブジェクトを渡します。

builder = coremltools.models.neural_network.NeuralNetworkBuilder(spec=spec)

NeuralNetworkBuilderはCore MLモデルを構築するためのクラスです。inspect_input_featuresメソッドでモデルの入力に関する情報を出力できます。

builder.inspect_input_features()

(出力)

[Id: 0] Name: image
          Type: multiArrayType {
  shape: 1
  shape: 28
  shape: 28
  dataType: DOUBLE
}

MNISTDigitClassifier.mlmodelをXcodeでプレビューした際に入力形式が"MultiArray (Double 1x28x28)"となっていたことと一致します。

3.3.2 入力の型をグレースケール画像に変更する

NeuralNetworkBuilderを用いて入力の型を28x28のグレースケール画像に変更します。モデルの入力を表すオブジェクトへはbuilder.spec.description.input[{インデックス番号}]のようにアクセスできます*2

from coremltools.proto import FeatureTypes_pb2 as ft
grayscale = ft.ImageFeatureType.ColorSpace.Value('GRAYSCALE')
input_image_type = builder.spec.description.input[0].type.imageType
input_image_type.width = 28
input_image_type.height = 28
input_image_type.colorSpace = grayscale

変更されたか確認してみましょう。

builder.inspect_input_features()

(出力)

[Id: 0] Name: image
          Type: imageType {
  width: 28
  height: 28
  colorSpace: GRAYSCALE
}

"Type: imageType"となり、以前は"dataType: DOUBLE"だったところが"colorSpace: GRAYSCALE"となりました。

specからMLModelオブジェクトを改めて生成し、saveメソッドで保存します。

mlmodel_modified = coremltools.models.MLModel(spec)
mlmodel_modified.save('./ModifiedMNISTDigitClassifier.mlmodel')

保存した.mlmodelをXcodeでプレビューしてみましょう。

図3.3:

入力の型が"Image (Grayscale 28x28)"となっていることが確認できます。

Core MLモデルから自動生成されるSwiftコード

.mlmodelファイルをXcodeプロジェクトに追加すると、Swiftコードが自動生成されます。自動生成されたSwiftコードは、プロジェクト内で.mlmodelファイルを選択したときに表示されるプレビュー内の、[Model Class]欄にある矢印ボタンを押すと見ることができます。

図3.4:

これらを見ると、coremltoolsconvertメソッドの各種引数に渡した値がどうCore MLモデルに影響したかをより具体的に知ることができます。

たとえば本書で作成したModifiedMNISTDigitClassifier.mlmodelからは次のようなクラスの実装が自動生成されます(いずれも一部を抜粋)。

- モデルを表すクラス。MLModel型のmodelプロパティを持つ。

class ModifiedMNISTDigitClassifier {
    var model: MLModel

    ...
}

- モデルへの入力を表すクラス。coremltoolsで与えた入力の名前や型が反映されている。

class ModifiedMNISTDigitClassifierInput : MLFeatureProvider {

    var image: CVPixelBuffer

    var featureNames: Set<String> {
        get {
            return ["image"]
        }
    }

    ...

    init(image: CVPixelBuffer) {
        self.image = image
    }
}

- モデルの出力を表すクラス。coremltoolsで与えた名前がインターフェースに反映されている。

class ModifiedMNISTDigitClassifierOutput : MLFeatureProvider {

    lazy var digitProbabilities: [String : Double] = ...

    lazy var digit: String = ...

    ...

    init(digitProbabilities: [String : Double], digit: String) {
        ...
    }

    ...
}

3.4 iOSで推論を実行

前節までに作成した手書き数字認識のCore MLモデルファイルを用いて、iOSで推論を行います。Visionフレームワークを使用します。

サンプルコード: iOS/MNISTSample

3.4.1 作成したCore MLモデルをプロジェクトに追加する

.mlmodelファイルをXcodeプロジェクトに追加します。モデルが正しく生成されていれば、Xcodeが必要なSwiftコードを自動生成してくれます。

3.4.2 VNCoreMLModelの初期化

まず、VNCoreMLModelオブジェクトを生成します。引数にはCore MLから生成されたクラスのmodelプロパティからMLModelオブジェクトを渡します。

private let model: VNCoreMLModel
model =  try! VNCoreMLModel(for: ModifiedMNISTDigitClassifier().model)

3.4.3 VNCoreMLRequestの作成

次に、VNCoreMLRequestオブジェクトを生成します。イニシャライザの引数にはVNCoreMLModelオブジェクトと、推論処理完了時に実行するクロージャを渡します。

let request =
    VNCoreMLRequest(model: model, completionHandler: { request, error in
        // 推論処理完了後に行う処理
        ...
    })

3.4.4 VNImageRequestHandlerの作成/推論処理の開始

VNImageRequestHandlerオブジェクトを生成します。イニシャライザの引数には入力画像データをCGImage型やCVPixelBuffer型で渡せませす。

let handler = VNImageRequestHandler(cgImage: inputImage)

そしてVNImageRequestHandlerperformメソッドを呼ぶと推論処理が開始します。

try! handler.perform([request])

引数にはVNRequestオブジェクトの配列を渡します。VNCoreMLRequestクラスはVNRequestクラスを継承しています。

3.4.5 推論結果の処理

推論処理が完了すると、VNCoreMLRequestのイニシャライザで第2引数に渡したクロージャが実行されます。クロージャの型はVNRequestCompletionHandlerで、次のように定義されています。

public typealias VNRequestCompletionHandler = (VNRequest, Error?) -> Void

この定義の通り、引数には実行したVNRequestのオブジェクトが入ってくるので、そのresultsプロパティから推論処理の結果が取り出せます。ただし、次のようにその型はAnyの配列となっています。VNRequest自体はVisionフレームワークにおけるさまざまなリクエストの基底クラスとなるもので、そのリクエストの種類に応じて結果の型も変わるためです。

var results: [Any]?

今回のモデルは画像の分類(classification)を行うものなので、このresultsVNClassificationObservation型の配列となります。

let request =
VNCoreMLRequest(model: model, completionHandler: { request, error in
    let observations = request.results as! [VNClassificationObservation]
    ...
})

VNClassificationObservationidentifierプロパティからはクラスラベルがString型で取得でき、

var identifier: String

また当該クラスの信頼度がconfidenceプロパティよりVNConfidence型で取得できます*3

var confidence: VNConfidence { get }

次の画像は作成したCore MLモデルを使って実装した手書き数字認識デモアプリです。

図3.5:

手書きビューの下にあるラベルが認識結果を示しています。実際に正しく手書き数字を認識できていることがわかります。

Visionはどのように画像分類モデルを判定するか?

Visionは次の場合、VNCoreMLRequestに渡されたMLModelが画像分類モデルであると判断します*4

  • モデルは単一の特徴を予測する(たとえば本章のモデルでいえばクラスラベルを示す数字が該当する)
  • MLModelmodelDescriptionプロパティから得られるMLModelDescriptionオブジェクトのpredictedFeatureNamenilではない値を持つこと。
// MLModelのプロパティ
var modelDescription: MLModelDescription { get }
// MLModelDescriptionのプロパティ
var predictedFeatureName: String? { get }

[*1] 1行ごとに各クラスラベルの文字列が入ったファイル。

[*2] 具体的には、{NeuralNetworkBuilderオブジェクト}.specModel_pb2.Modelオブジェクトを取得しており、*.protoの定義に従ってその内容をカスタマイズしています。詳しくは第12章「mlmodelファイルフォーマット」を参照してください。

[*3] confidenceプロパティはVNClassificationObservationの親クラスであるVNObservationクラスで定義されています。

第4章 オンデバイス学習 - UpdatableなCore MLモデルの作成

4.1 モデルのパーソナライゼーション

Core ML 3で追加された待望の新機能が、iOSデバイス側(エッジ側)で追加のデータを与えて学習を行い、モデルを更新できるというものです。

ユーザー毎にモデルをパーソナライズ可能に(画像は[1;より)

図4.1: ユーザー毎にモデルをパーソナライズ可能に(画像は[1]より)

True-Depthカメラを利用したFace IDでは以前からこのオンデバイス学習によるモデルのパーソナライゼーションを行っていたと考えられていますが、ついにこの機能をサードパーティのiOSデベロッパも利用できるようになったわけです。最初から汎用的なモデルを作成することは困難なケースもあるため、この機能はCore MLのユースケースを大きく広げるでしょう。

本章ではそのUpdatableなCore MLモデルの作成方法を解説します。具体的には、付録B「Keras入門」および第3章「Core MLモデル作成の基礎」で作成した手書き数字認識と同様のモデルを、UpdatableなCore MLモデルに変換します。

サンプルコード: coremltools/mnist_cnn_make_updatable.ipynb

なお、UpdatableなCore MLモデルの作成にはCore ML Tools 3.0以上が必要で、モデルの利用(推論処理の実行)にはCore ML 3以上(iOS 13以上)が必要です。

試し読みはここまでです。
この続きは、製品版でお楽しみください。