AutoML Vision Edgeがどのようなニューラルネットワークを作るのかが気になったので調べてみました。
Kaggleの犬猫分類(画像による2クラス分類)をAutoML Vision EdgeでTensoflow Liteのモデルを作り、ネットワーク構造を読み出して分析しました。まだ、完全に理解したわけではないので間違っている所もありそうでうが、雰囲気がつかめたのでまとめてみます。
準備
データを用意する。
ここから、犬と猫の画像をそれぞれ2000枚選びました。
https://www.kaggle.com/c/dogs-vs-cats
データをAutoMLで扱えるようにする。
この2つを見ればだいたいわかります。
ディレクトリに分けた画像をzipにして4000枚アップロードしたところ、ディレクトリ構造は認識してくれず、結局手で4000枚ラベル付けしました。ラベル付けのUIはあまり使いやすくなかったです。まずは500枚くらいアップロードして、作戦を考えた方が良いでしょう。今回であれば、先に犬の画像を2000枚アップロードし全てにdogのラベルをつけた後、猫の画像を2000枚アップロードして未分類の物を全てcatにすれば楽でした。自力でラベル付けした時点で少なくとも10枚は間違っていたのですが、今回は精度はあまり興味が無いのでこのまま進みました。
モデルをトレーニングする。
トレーニングの方法はここの通りに進めればOKです。
https://qiita.com/shinkoizumi0033/items/4ae75e0bebb2848cbd54
上で準備した同じデータセットに対して、Lowest latency、Best Trade-off、Higher accuracyの設定でそれぞれトレーニングしました。トレーニングは1時間半程度(1時間では終わらなかった)で終わり、メールが届くのでそのリンク先を開くと結果がみれます。
精度が悪いのは、上に書いたようにデータセットがすでに間違っているからだと思います。
モデルをダウンロードする。
訓練が終わった後、、AutoML Visionの画面からモデルを選択し、PREDICTのタブをクリックします。
この画面でEXPORTをクリックすると、GCP上にデータがエクスポートされます。gsutilを使ってローカルへ持ってきましょう。
TFLiteのモデルをJSONへ変換する。
TFLiteモデルの中身は、flatbufferです。
github.com
flatbuffersをインストールして、flatc コマンドを使えるようにします。
フォーマットの定義ファイルは、wgetで持ってきましょう。
wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/lite/schema/schema.fbs
flatcコマンドが動けばJsonファイルができるはずです。
flatc --json --defaults-json --strict-json schema.fbs -- XXXX.tflite
JSONファイルを読み込んでdotファイルを作る。
ここは自作ツールでやりました。ONNXで同じようなことをしていれば簡単にできると思います。そんなに難しくないです。需要があれば公開します。
dotファイルができれば、pngやPDFに変換して完了です。
オプションによるモデルの比較
モデルの大きさ比較
|
Lowest latency |
Best Trade-off |
Higher accuracy |
TFliteファイルのサイズ(Kb) |
548 |
3,179 |
5,851 |
推論速度の見積もり(ms) |
22 |
65 |
105 |
計算のサイズ |
UINT8 |
UINT8 |
UINT8 |
層数 |
65 |
64 |
64 |
TFliteの中身を見てみましたが特に圧縮されている様子も無く、ファイルサイズがほぼパラメータのデータサイズと思って良さそうです。データの持ち方は全モデルでUINT8でした。意外にもレイヤ数はほぼ同じでした。
可視化したニューラルネットワーク
とりあえず3つ並べてみました。
ニューラルネットワークの基本構造
3つのモデルの構造を見てみました。基本的な構造は3つとも同じのようにみえます。
ResNetに似た構造が、10~11個シーケンシャルにつなげています。これだけで5層あるので5×10で50層、最初、真ん中、最後に少し違う構造が入っていて、合計で64層のニューラルネットワークを構成しています。
Lowest latency が11個、残りの2つが10層で全体のニューラルネットワークを構成しているので、微妙なところではモデルに違いがありそうです。これが、速度、精度との問題なのか、AutoMLで使われているであろう乱数の結果による違いなのかは分かりません。もう少し、いろんなデータで試す必要がありそうです。
入力層直後を除き、2DConvが全て1x1のみで、5x5等はDepthwiseConv2Dでのみ出てくるところが面白いです。
データ数の比較
3つのモデルについて、先頭と最後のデータ数(重みの数)を比べてみました。Best Trade-offとHigher accuracyは構造が同じで、パラメータの数だけの違いに見えます。Lowest latencyはネットワーク構成が違い、パラメータを大きく減らしています。Best Trade-offの半分以下です。
layer |
Lowest latency |
Best Trade-off |
Higher accuracy |
0 |
Conv2D 3x3 16 |
Conv2D 3x3 32 |
Conv2D 3x3 48 |
1 |
DConv2D 3x3 16 |
DConv2D 3x3 32 |
DConv2D 3x3 48 |
2 |
Conv2D 8 |
Conv2D 16 |
Conv2D 24 |
3 |
Conv2D 24 |
Conv2D 48 |
Conv2D 72 |
4 |
DConv2D 3x3 24 |
DConv2D 3x3 48 |
DConv2D 3x3 72 |
5 |
Conv2D 8 |
Conv2D 24 |
Conv2D 24 |
6 |
Conv2D 24 |
Conv2D 72 |
Conv2D 72 |
7 |
DConv2D 3x3 24 |
DConv2D 3x3 72 |
DConv2D 3x3 72 |
8 |
Conv2D 8 |
Conv2D 24 |
Conv2D 24 |
9 |
Add |
Add |
Add |
10 |
Conv2D 24 |
Conv2D 72 |
Conv2D 72 |
|
|
|
|
50 |
Add |
Conv2D 1152 |
Conv2D 1632 |
51 |
Conv2D 384 |
DConv2D 5x5 1152 |
DConv2D 5x5 1632 |
52 |
DConv2D 5x5 384 |
Conv2D 192 |
Conv2D 272 |
53 |
Conv2D 64 |
Add |
Add |
54 |
Add |
Conv2D 1152 |
Conv2D 1632 |
55 |
Conv2D 384 |
DConv2D 5x5 1152 |
DConv2D 5x5 1632 |
56 |
DConv2D 5x5 384 |
Conv2D 192 |
Conv2D 272 |
57 |
Conv2D 64 |
Add |
Add |
58 |
Add |
Conv2D 1152 |
Conv2D 1632 |
59 |
Conv2D 384 |
DConv2D 3x3 1152 |
DConv2D 3x3 1632 |
60 |
DConv2D 3x3 384 |
Conv2D 320 |
Conv2D 448 |
61 |
Conv2D 112 |
Conv2D 1280 |
Conv2D 1280 |
62 |
Conv2D 1280 |
Reducer |
Reducer |
63 |
Reducer |
FC |
FC |
64 |
FC |
SoftMax |
SoftMax |
65 |
SoftMax |
|
|
こうやって並べてみると、データ数が8の倍数になっているのは分かります。例えば24個のUINT8(8bit)のデータを22個にしても、速度への影響はあまりないのだと思います。ギリギリで削るというよりは、いくつかの組み合わせを試しているように見えます。おそらく、エッジ動作での速度を確保するために、クラウドで使用するAutoMLよりは制約がきつくなっていると感じます。4x4みたいなカーネルの方が精度が高かったとしても、エッジ側のライブラリが3x3と5x5にしか対応していなければ、速度がでないとかの事情はありそうです。
上には書いていないですが、アクティベーション層が全て計算が少ないReLUになっているのもエッジ動作を想定してのことだと思います。
量子化
ちゃんと調査したわけでは無いのであくまで予想ですが、量子化は2種類のフォーマットを組み合わせています。
ここに詳しく説明されていますが、まだ全部みれてません。
heartbeat.fritz.ai
A typical quantized layer
一般的なTF Liteで使われる量子化フォーマット
"quantization": {
"min": [
-22.376556
],
"max": [
23.63975
],
"scale": [
0.180456
],
"zero_point": [
124
],
Fake Quantization
おそらく、単純にかけ算をするだけのフォーマット。
"quantization": {
"scale": [
0.011161
],
"zero_point": [
0
],
他に気になったこと
定番のMaxpoolingやBatchNormalizationが入っていないのも気になりました。Maxpoolingに関してはResNetの構造を上手く使っているので必要なさそうですが、BatchNormalizationはあまり効果がないのかConvの計算に組み込まれて(Fuse)いるのかは良く分かりません。
まとめ
- AutoML Vision Edgeで作ったモデルは、JSONに変換して構成を見ることができる。
- 今回のケースでは、ResNetっぽいNNを生成している。いくつかの組み合わせから選んでいる様子。
- エッジでの計算早くなりそうなレイヤーを組み合わせている。
- Lowest latencyは層数こそ変わらないが、かなり重みの数を減らしている。
次は物体検出が、どのようなネットワークで構成されているかをやってみたいです。