Galapagos Blog

株式会社ガラパゴスのメンバーによるブログです。

Create MLでMNISTの分類器を作ってみた

こんにちは。iOSチームの高橋です。好きな拡張子は.xhtmlです。

今回はWWDC 2018で発表されたCreate MLについて、セッションの内容を踏まえつつ、簡単なデモ(みんな大好きMNIST)で評価をしてみました。

注意:この記事はベータ版の内容をもとに書かれています。実際に公開されるバージョンでは事情が異なっている可能性がありますのでご注意ください。

Create MLとは

昨年のWWDCでは、Kerasなどの機械学習フレームワークで学習させたモデルを読み込んで推論を行うCore MLが発表されました。 このblogでも、以前に一度Core MLを使ったスタイル変換について紹介しています。

gtech.hatenablog.com

しかし、Core MLでできるのは学習済みモデルを使った推論のみで、学習自体は別のフレームワークを使って行う必要がありました。 それはKerasであったりTensorFlowであったり、あるいはLIBSVMであったり様々ですが、いずれも多かれ少なかれ機械学習に関する専門的知識を必要としたり、 データの整備やモデルの評価などの煩雑な(しかし重要な)作業を必要とするものでした。

Create MLを使えば、基本的なワークフローを理解するだけで、以下のようなタスクに対応する機械学習モデルを簡単に作ることができます。

  • 画像分類
  • テキスト分類
  • 表データからの回帰・分類

以下では画像分類モデルの作りかたを見ていきます。

ワークフロー

機械学習モデルの構築は、次のようなステップで行われます。

  1. データの収集・整備
  2. 学習
  3. 評価

Create MLは、このそれぞれのステップをものすごく簡略化するためのAPIを提供しています。

データの整備

学習させるデータは、モデルに与えられる前に十分に整備されている必要があります。 たとえば画像ならばサイズを揃えたりする必要がありますし、文字列ならば適切なトークン化(文字単位、あるいは形態素単位)と符号化が必要になるでしょう。

Create MLはこれを全部肩代わりしてくれます。開発者がすべきことは単にディレクトリに画像やテキストを放り込むだけです。 ラベルはサブディレクトリの名前として与えられます。たとえばMNISTならばこんな風になります:

train_data/
├ 0/
| ├ 00007.png
| ├ 00010.png
| └ ...
├ 1/
| └ ...
└ ...

また、(今回は使いませんでしたが)画像データのオーグメンテーション1にも対応しており、 学習時にオプションを与えることで自動的に処理してくれます。

学習

画像分類モデルの学習は二通りのやりかたが用意されています。Create ML UIを使う方法と使わない方法です。まずは前者から説明します。

macOS用のPlaygroundを作成し、Assistant editorを開いた状態で以下のようなコードを実行します。

import CreateMLUI

let builder = MLImageClassifierBuilder()
builder.showInLiveView()

すると下図のようなUIが出現します(画像は公式のリファレンスから引用しています)。 f:id:glpgsinc:20180611214817p:plain

あとは"Drop Images To Begin Training"のところに上で用意したフォルダをドロップするだけで学習が開始します。 今回はMNISTを1000枚に絞った小さなデータセット2(学習用800枚とテスト用200枚)を作成し、それを学習させてみたところ、Training精度が86%、Validation精度が82%となりました。 Validationが表示されるということは何らかのハイパーパラメータを振っているのだと思いますが、そのあたりの詳細はよくわかりません。

ところで、もちろんコードで書く方法も提供されています。MLImageClassifier構造体のイニシャライザに学習データディレクトリのURLを与えるだけで学習がスタートします。

import CreateML
let trainDirectory = URL(string: "file:///path/to/train/data")!
let classifier = try! MLImageClassifier(trainingData: .labeledDirectories(at: trainDirectory))

このイニシャライザには他にparametersという引数をとり、学習する最大ステップ数やデータオーグメンテーションの種類などを渡すことができます。 筆者はFeatureExtractorTypeという列挙体が気になるのですが、今のところ1種類しか定義されていないようです。いずれは他のものも使えるようになるのかしら。

評価

学習が終わったら、評価をせねばなりません。Create ML UIを使った場合は、学習が終了すると精度表示の下に"Drop Images To Begin Testing"というボックスが表示されるので、 テストデータをそこにドロップすれば評価が実行されます。今回のデータセットでは85%の精度が出ました3

800枚で85%というのがどのくらいなのか、比較のためにTensorFlowで簡単なモデル4を書いて実験してみたところ、81.5%の精度を得ました。 どうやら同等以上の性能が出るようです。これは転移学習5がうまくいっているためと思われます。 しかもコードはたったの3行で。これはうれしいですね。

モデルの書き出し

十分に精度の高いモデルが得られたら、それをmlmodelファイルに書き出します。 Create ML UIを使った場合はライブビュー上のメニューを展開するとモデルのメタデータを設定して保存するボタンが出てくるので、それだけでOKです(下の画像も公式のリファレンスから引用しています)。 f:id:glpgsinc:20180614153543p:plain

コードで書いた場合は、MLImageClassifierwrite(to:metadata:)メソッドを呼ぶことで、指定したURLにモデルファイルが書き出されます。

let outputURL = URL(string: "file:///path/to/output")!
try! classifier.write(to: outputURL)

書き出されたモデルのサイズはなんとたったの152KBでした。これも転移学習のおかげでパラメータの大部分をOS側に載せることに成功しているためです6

まとめと感想

ということで、Create MLを使って簡単な手書き数字識別モデルを作成することができました。 たった3行のコーディングで、機械学習の専門知識なしにそれなりの精度のモデルが作れてしまうのは便利だな、と思います。 モデルサイズが小さく抑えられるのも実用面で魅力的ですね。

一方で、せっかく転移学習をしているわりには精度がTensorFlowと同程度だったのが気懸かりではありますが、 これは元の学習データとMNISTが大きく異なるデータセットだったからではないかと考えています。 (そう考えると、CIFAR-10などで比較したら違う結果になっていたかもしれません)

また、今回はデータセットの準備が面倒だったので試さなかったテキスト分類や回帰モデルなども、 同じように非常にシンプルなコードで簡単にモデルを作成できるようなので、次の機会があれば試してみたいと思います。

ところで(いつもの)

弊社ではエンジニアを募集しています。ご興味をお持ちのかたはぜひ弊社採用ページをご覧ください。

www.glpgs.com

以上です。


  1. 画像のフリップや回転などの加工でデータ量を水増しすること

  2. 大きなデータセットが用意できない/するのがめんどくさいようなケースを想定しています。

  3. ただし、何度か実験すると精度はけっこうばらつくようです。これは学習時のTraining/Validationデータの分割がランダムであることなどに起因するのだと思われます(実際何をやっているのかはわかりませんが)。

  4. アーキテクチャは畳み込み+プーリング3層+全結合2層。Weight decayあり。ステップ数はCreate MLにあわせて10としました。ちなみに、両者のステップ数を100にしたときは、Create MLが87%、TensorFlowが84.5%でした。

  5. すでに大量のデータで学習されたモデルの一部だけを少量の新しいデータで学習し直すことで、少量のデータから高精度なモデルを作成する手法です。

  6. ちなみにTensorFlowからのmlmodel書き出しは試していませんが、チェックポイントのサイズが80MBほどあったので、まあその程度でしょう。