iOSの機械学習フレームワークの比較 - Core ML / Metal Performance Shaders (MPSCNN) / BNNS

iOS 11 で追加された Core ML と、iOS 10 の頃からある Metal Performance Shaders の CNN、Accelerate の BNNS について、2017年7月に勉強会で話した際のスライドです。

- [Core ML vs MPSCNN vs BNNS #fincwwdc // Speaker Deck](https://speakerdeck.com/shu223/core-ml-vs-mpscnn-vs-bnns-number-fincwwdc)

<a href="https://speakerdeck.com/shu223/core-ml-vs-mpscnn-vs-bnns-number-fincwwdc"><img width="600" alt="Screen Shot 2017-07-27 at 0.38.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/c460db17-72e7-3731-dd91-66ace3f219a3.png"></a>



## 発表の概要

iOS 11で追加されたCore MLが非常に注目を集めていますが、「既存の機械学習ツールを使って学習させたモデル（のパラメータ）をiOS側に持ってきて推論を実行する」ということ自体は<b>iOS 10から</b>ありました。

<img width="600" alt="Screen Shot 2017-07-27 at 0.28.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/b3f0ba33-0570-c4af-f71c-e39669b833d0.png">

<img width="600" alt="Screen Shot 2017-07-27 at 0.29.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/4bd16c52-1f89-9fbc-d785-fccb731e8519.png">

そして、そこに**不便さがあったので広まらず、Core MLで改善されたことにより使われるようになった**、という側面はもちろんありつつも、いややはりそれでも単にそういうことがiOS 10できるようになったということ自体が**知られていなかっただけなのでは**、と Core ML と Metal Performance Shaders の注目度のあまりの違いから考えていました。


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">それにしてもCoreMLはこんなに話題になるのに、なぜMPSCNNはあんまり盛り上がらなかったのか。「iOS側でのネットワーク実装とかモデル持ってくるのとか色々面倒」というCoreMLで改善された部分がネックになる以前に、そもそも</p>&mdash; Shuichi Tsutsumi (@shu223) <a href="https://twitter.com/shu223/status/886440238859431937">2017年7月16日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">（つづき）そもそも「他ツールで学習させたモデルを利用してiOS側で推論を実行できるようになったよ」っていうこと自体もあまり知られてなかった気がする。（そしてCore MLでそれができるようになった！って言ってる記事も見かける。。） <a href="https://t.co/SA23gU4WII">https://t.co/SA23gU4WII</a></p>&mdash; Shuichi Tsutsumi (@shu223) <a href="https://twitter.com/shu223/status/886440614459580417">2017年7月16日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


確かに自分も Metal Performance Shaders のCNN APIを用いた機能を実装しようとしたときに、**情報があまりに少なく、何ができて何ができないのか、どうやるのかがよくわからなかった**、ということがありました。


で、そのへんをシンプルに説明したら、もっと興味をもつ人も出てくるんじゃないかなと思い、<b>実装手順を3ステップ</b>で解説してみました。


## MPSCNNを用いた機械学習機能の実装手順3ステップ

### Step 1: モデルをつくる

<img width="600" alt="Screen Shot 2017-07-25 at 6.25.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/eb0670d2-9345-e9b0-f0ee-a854518073a0.png">

Core ML は **Keral, Caffe, scikit-learn, etc.** といったメジャーな機械学習ツールで学習させたモデルからのコンバートをサポートしていることが大きなポイントですが、それらの学習結果を「使える」という点ではMPSCNNも同様です。

- [iOSのMPSCNNに渡すモデルパラメータのフォーマット / TensorFlowからの書き出し - Qiita](http://qiita.com/shu223/items/c735ab888a83f214f89a) 


### Step 2: ネットワークを実装する

<img width="600" alt="Screen Shot 2017-07-25 at 6.25.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/83d39724-85e8-6fcf-0692-552c77c878f9.png">

<img width="600" alt="Screen Shot 2017-07-25 at 6.25.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/5f368f37-db28-83ae-1bf3-239365834277.png">

- [iOSのMetalで畳み込みニューラルネットワーク - MPSCNNを用いた手書き数字認識の実装 - Qiita](http://qiita.com/shu223/items/bdd537f38872a5af4e4c)

### Step 3: 推論の実行処理を書く

<img width="600" alt="Screen Shot 2017-07-25 at 6.26.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/2df27687-b806-54d6-e57b-f2595cc5311f.png">

- [iOSのMPSCNNによる手書き数字認識のサンプルを読む - 前編 - Qiita](http://qiita.com/shu223/items/28122f5668cf1547e8fe)


## MPSCNN のつらみと Core ML & Vision

上記のMPSCNNを用いた実装手順、<b>意外と簡単そう/使えそう</b> と思っていただけたのではないでしょうか？


ところが・・・


<img width="600" alt="Screen Shot 2017-07-25 at 6.26.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/9f15e33c-84a2-6b8a-a033-5ce519ec03b8.png">

<img width="600" alt="Screen Shot 2017-07-25 at 6.27.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/9970a332-de33-3112-8c2c-30deb18d791c.png">


っていうつらさがあり、他にも色々と面倒な点があり、やっぱり<b>Core ML & Visionのおかげで各段に便利になった</b>、という話を[スライドに書いています](https://speakerdeck.com/shu223/core-ml-vs-mpscnn-vs-bnns-number-fincwwdc?slide=46)。


## BNNS　の使いどころ、MPSCNN との使い分け

最後に<b>**AccelerateフレームワークのBNNSの使いどころについてWWDC17のMetal Labで聞いた話**</b>が出てきます。

<a href="https://speakerdeck.com/shu223/core-ml-vs-mpscnn-vs-bnns-number-fincwwdc?slide=59"><img width="600" alt="Screen Shot 2017-07-25 at 7.29.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/41e26790-33ca-60bc-a19f-45d5fec55897.png"></a>

（[スライドの該当ページ](https://speakerdeck.com/shu223/core-ml-vs-mpscnn-vs-bnns-number-fincwwdc?slide=59)）


### BNNSについていただいたコメント

この点について、スライドを読んだ[sonsonさん](https://twitter.com/sonson_twit)からFacebookでコメントいただきました。

<img width="400" alt="Screen Shot 2017-07-25 at 12.38.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/3180/6a46c807-b747-652d-30e1-952ef8414049.png">

> BNNSとMPSCNNの使い分けは，難しいけど，電力と計算スピードのバランスかなぁと思います．

> あと，GPUのメモリとCPUのメモリ間の転送に時間がかかるので，オーバーヘッドをカバーできるくらい，データや計算量大きくないと，GPUは意味ないでしょう．
BNNSは，SIMDなので，これも当然CPUのコンテキストスイッチのためのオーバーヘッド（ノーマルモードとSIMDモードの切り替え）があるのですが，GPUほどではないので，小さいネットワークだとGPUよりBNNSの方が速いというのはありそうです．

> まぁ，なんで，電力と速度の限界に挑戦する場合は，ベンチマークとって極限を目指そうって感じですかねｗ


なるほど、単に「CNNの計算はGPUが向いてるでしょ」とか「Appleの人も言ってた」とかってだけでBNNSのことは忘れようとか言ってちゃいけない、と反省しました。

確かに **GPU <-> CPU間の転送速度のボトルネックとGPUによる高速化がどれぐらい見込まれるかのバランスによる** というのは非常に納得です。また「SIMDモードへの切り替えのオーバーヘッド」（はあるがGPUとの転送ほどではない）というあたりもまったく考慮できてなかったところです。

CPU、GPUの負荷がそれぞれどれぐらいか、というのはXcodeで簡単に見れますが、GPU <-> CPU間の転送状況を見る方法もあるのでしょうか？GPUまわりの計測・デバッグ手法はもうちょっと勉強したいところです。