動機
Edge TPU Compilerには複数のモデルを同時にコンパイルすることができる。同時にコンパイルすることで、複数のモデルを1つのEdge TPUで同時に実行するときにパフォーマンスが向上することができるとある。なのでどの程度パフォーマンスが向上するのか計測してみた。
"Co-compiling multiple models"
https://coral.withgoogle.com/docs/edgetpu/compiler/
まとめとかいろいろ
(USB AcceleratorでかつUSB2.0の場合)
- 複数モデルを連続して使用する(複数回の推論を行う)場合は、Edge TPU Compilerの同時コンパイルは有効。
- 複数のモデルがEdge TPUのメモリに収まるかが重要。
Edge TPUのメモリに収まらなかったモデルの推論の処理時間が遅くなってしまう。どちらのモデルを優先で使うかを考えてコンパイルする順序をかえる。このため、コンパイルする順序を変える(小さいモデルを先にする)と改善する(場合がある)。
- ただし、Edge TPUのメモリに収まらなかった場合でも、同時コンパイルしない場合と比べ、トータルの処理時間は早くなる。
- Dev Board(PCIe)やUSB3.0と接続した場合、推論の時間がどの程度変わってくるか不明(どちらの環境も持っていないので...)。
環境
- Raspberry Pi 3 B+
- Edge TPU USB Accelerator(接続は"最大動作周波数")
- Edge TPU API Release1.9.2 (Apr 2019)
- Edge TPU Compiler (Offline compiler) Version 1.0.249710469
- 使用モデルはPre-trained model
複数モデルのコンパイル
使用モデル
Pre-trained modelのTF-Lite modelを使用。
項番の順にコンパイルに指定及び、推論を行う。
- Model1 : mobilenet_v2_1.0_224_inat_bird_quant.tflite
- Model2 : mobilenet_v2_1.0_224_inat_plant_quant.tflite
コンパイル
コンパイルはoff-line compilerのみ。コマンドライン引数で複数のモデルを指定する。コンパイル後、Edge TPU モデルが生成される。1つのモデルにまとめられるわけではなく、指定したTF-Liteモデルの分、生成される(最初は1つにまとめられると思っていた)。
edgetpu_compiler Model1 Model2
コマンドライン引数とコンパイル時の結果は以下の通り。
# edgetpu_compiler -o output/ -s mobilenet_v2_1.0_224_inat_bird_quant.tflite mobilenet_v2_1.0_224_inat_plant_quant.tflite
Edge TPU Compiler version 1.0.249710469
INFO: Initialized TensorFlow Lite runtime.
Models compiled successfully in 1390 ms.
Input model: mobilenet_v2_1.0_224_inat_bird_quant.tflite
Input size: 3.37MiB
Output model: output/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.tflite
Output size: 3.89MiB
On-chip memory available for caching model parameters: 6.91MiB
On-chip memory used for caching model parameters: 3.75MiB
Off-chip memory used for streaming uncached model parameters: 0.00B
Number of Edge TPU subgraphs: 1
Total number of operations: 65
Operation log: output/mobilenet_v2_1.0_224_inat_bird_quant_edgetpu.log
Operator Count Status
FULLY_CONNECTED 1 Mapped to Edge TPU
SOFTMAX 1 Mapped to Edge TPU
ADD 10 Mapped to Edge TPU
AVERAGE_POOL_2D 1 Mapped to Edge TPU
CONV_2D 35 Mapped to Edge TPU
DEPTHWISE_CONV_2D 17 Mapped to Edge TPU
Input model: mobilenet_v2_1.0_224_inat_plant_quant.tflite
Input size: 4.76MiB
Output model: output/mobilenet_v2_1.0_224_inat_plant_quant_edgetpu.tflite
Output size: 5.22MiB
On-chip memory available for caching model parameters: 3.16MiB
On-chip memory used for caching model parameters: 2.49MiB
Off-chip memory used for streaming uncached model parameters: 2.59MiB
Number of Edge TPU subgraphs: 1
Total number of operations: 65
Operation log: output/mobilenet_v2_1.0_224_inat_plant_quant_edgetpu.log
Operator Count Status
ADD 10 Mapped to Edge TPU
AVERAGE_POOL_2D 1 Mapped to Edge TPU
CONV_2D 35 Mapped to Edge TPU
DEPTHWISE_CONV_2D 17 Mapped to Edge TPU
SOFTMAX 1 Mapped to Edge TPU
FULLY_CONNECTED 1 Mapped to Edge TPU
Edge TPUのメモリのサイズ(On-chip memory)に注目すると、2つのモデルがEdge TPUのメモリに割り当てられている。そして、2つのモデルをコンパイルした場合、Edge TPUのメモリに収まり切らないため、2つ目のモデルのはみ出す分が、"Off-chip memory"(外部メモリ)割り当てられている。
1つ目のモデルのコンパイル
- 1つ目のモデルがすべて、Edge TPUのメモリに割り当てられている(3.75Mib)。
- Edge TPUのメモリの空きは3.16MiB(6.19 - 3.75Mib)。
On-chip memory available for caching model parameters: 6.91MiB
On-chip memory used for caching model parameters: 3.75MiB
Off-chip memory used for streaming uncached model parameters: 0.00B
2つ目のモデルのコンパイル
- 2つ目のモデルのうち2.49Mib分が、Edge TPUの空きメモリから割り当てられる。
このとき、Edge TPUの空きメモリは3.16Mibなので0.67Mib分の余白あり。
- 外部メモリに2.59Mibが割り当てられた。
On-chip memory available for caching model parameters: 3.16MiB
On-chip memory used for caching model parameters: 2.49MiB
Off-chip memory used for streaming uncached model parameters: 2.59MiB
(ご指摘いただいて気づいたのだが)
Edge TPU Compilerはコンパイル時にモデルを識別するための"caching token"を付与する。推論の実行時にEdge TPUのメモリに展開されたモデルと、推論を行うモデルの"caching token"を比べて、異なれば推論を行うモデルをEdge TPUのメモリに展開する。このため、毎回異なるモデルでの推論を行った場合は、都度Edge TPUのメモリへの展開が行われるため、推論時間が遅くなってしまう。
複数モデルをコンパイルしたときは"caching token"が同一なのでEdge TPUのメモリが書き換わらないため、推論の処理時間が早くなる。
※より正確には
Parameter data cachingを参照。
モデルの可視化
visualize.pyでコンパイルしたEdge TPU モデルを可視化すると、Tensorsが通常と異なることが分かる。
下の図は、通常のコンパイル(マルチモデルでない)した場合。
MoblieNetV2の各Tensorsが分かる。
 |
| MoblieNet V2 のPre-trained modelを可視化 |
下の図は、マルチモデルでコンパイルした場合。
Inputと中間のTensorsがすべて、map/TensorArrayStack/TensorArrayGatherV3となっている。
 |
| MoblieNet V2のマルチモデルのコンパイルした結果を可視化 |
ベンチマーク
方法
Pythonスクリプトを自作して計測。コードは
ここ。
単純に2つのモデルの推論を繰り返し行う。推論の処理時間はEdge TPUのAPI(
get_inference_time)を使用。
計測の概要は以下。
- モデルはImage Classificationのモデル。
- 推論の処理時間を計測。比較用に
モデルが1つの推論
モデルが2つの推論・別々にコンパイルしたモデルを使用
モデルが2つの推論・同じモデルを使用
モデルが2つの推論・同時にコンパイルしたモデルを使用
- 推論の初回と2回目以降は処理時間が異なる(初回はモデルを転送している)ので、別々に計測。
初回の推論 : 10回計測した平均
2回目以降の推論 : 100回計測した平均
初回の推論時は、ClassificationEngineクラスの生成でかなり時間がかかるので回数を落としている。
初回の推論
[モデルが1つの場合]
[モデルが2つの場合]
| 同時コンパイル | 平均推論時間[ms] |
なし
| Model1 | 119.99 |
| Model2 | 159.26 |
なし
Model1, 2とも
同一モデル
| Model1 | 120.04 |
| Model2 | 119.96 |
あり
| Model1 | 120.14 |
| Model2 | 158.23 |
2回め以降の推論
[モデルが1つの場合]
[モデルが2つの場合]
| 同時コンパイル | 平均推論時間[ms] |
なし
| Model1 | 123.00 |
| Model2 | 163.27 |
なし
Model1, 2とも
同一モデル
| Model1 | 10.33 |
| Model2 | 10.34 |
あり
| Model1 | 10.61 |
| Model2 | 86.31 |
結果
初回の推論時
- 同時コンパイルの有無に関係なく、Model1、2ともほぼ同じ処理時間がかかっている。
- ただ、2つ目のモデルの処理時間が若干遅い(約40msほど遅い)。
- Model1, 2に同一のモデルを指定した場合は、推論時間に差はない。
Model2の推論時には、すでにモデルがEdge TPUのメモリに展開されているので処理時間は少なくなるはず?なぜか処理時間が変わらない結果となった。
2回目以降の推論時
- 同時コンパイルしない場合は、初回の推論とほぼ同じぐらいの処理時間がかかっている。
これは、推論ごとにEdge TPUのメモリの入れ替えが発生しているためと推測。
- 同時コンパイルした場合は、効果が確認できる。
1つ目のモデルは、モデルが1つの場合と同じ処理時間。
2つ目のモデルは若干遅い(約70ms)これは、外部メモリからモデルをロードするためと推測。同時コンパイルしない場合と比べ、約190msの短縮。
- Model1, 2に同一のモデルを指定した場合は、推論時間に差はない。
Edge TPUのメモリの切り替えが発生しないためと推測。
その他
1つ目のモデルで大半のEdge TPUのメモリを使用してしまう場合の組み合わせを確認。
指定したTF-Liteモデルは以下。
Model1 : inception_v3_299_quant.tflite
Model2 : mobilenet_v2_1.0_224_inat_plant_quant.tflite
コンパイルした結果。
(1つ目のinception_v3でほぼすべてのEdge TPUのメモリが専有されてしまう)
# edgetpu_compiler -o output/ -s inception_v1_224_quant.tflite mobilenet_v2_1.0_224_inat_plant_quant.tflite
Edge TPU Compiler version 1.0.249710469
INFO: Initialized TensorFlow Lite runtime.
Models compiled successfully in 2590 ms.
Input model: inception_v1_224_quant.tflite
Input size: 6.38MiB
Output model: output/inception_v1_224_quant_edgetpu.tflite
Output size: 6.93MiB
On-chip memory available for caching model parameters: 6.53MiB
On-chip memory used for caching model parameters: 6.53MiB
Off-chip memory used for streaming uncached model parameters: 182.19KiB
Number of Edge TPU subgraphs: 1
Total number of operations: 83
Operation log: output/inception_v1_224_quant_edgetpu.log
Operator Count Status
CONCATENATION 9 Mapped to Edge TPU
CONV_2D 58 Mapped to Edge TPU
RESHAPE 1 Mapped to Edge TPU
SOFTMAX 1 Mapped to Edge TPU
AVERAGE_POOL_2D 1 Mapped to Edge TPU
MAX_POOL_2D 13 Mapped to Edge TPU
Input model: mobilenet_v2_1.0_224_inat_plant_quant.tflite
Input size: 4.76MiB
Output model: output/mobilenet_v2_1.0_224_inat_plant_quant_edgetpu.tflite
Output size: 6.04MiB
On-chip memory available for caching model parameters: 1.50KiB
On-chip memory used for caching model parameters: 1.25KiB
Off-chip memory used for streaming uncached model parameters: 5.86MiB
Number of Edge TPU subgraphs: 1
Total number of operations: 65
Operation log: output/mobilenet_v2_1.0_224_inat_plant_quant_edgetpu.log
Operator Count Status
DEPTHWISE_CONV_2D 17 Mapped to Edge TPU
SOFTMAX 1 Mapped to Edge TPU
FULLY_CONNECTED 1 Mapped to Edge TPU
ADD 10 Mapped to Edge TPU
AVERAGE_POOL_2D 1 Mapped to Edge TPU
CONV_2D 35 Mapped to Edge TPU
推論結果(2回目以降の推論)
同時コンパイルした場合は、しない場合と比べ、約170msの短縮。
ただし、Model2(MoblieNet V2)の処理時間はかなり遅い(1つだけのモデルで推論した場合は約10ms程度)。
| 同時コンパイル | 平均推論時間[ms] |
なし
|
Model1 | 212.19 |
Model2 | 162.95 |
する
|
Model1 | 18.91 |
Model2 | 183.4 |
1つ目と2つ目のモデルを入れ替えた場合
Model1 : mobilenet_v2_1.0_224_inat_plant_quant.tflite
Model2 : inception_v1_244_quant.tflite
コンパイルした結果。
1つ目のMobileNetV2のモデルサイズは小さいため、2つ目のInception V3にもEdge TPUのメモリが割り当てられる(1.45MiB)。
# edgetpu_compiler -o output/ -s mobilenet_v2_1.0_224_inat_plant_quant.tflite inception_v1_224_quant.tflite
Edge TPU Compiler version 1.0.249710469
INFO: Initialized TensorFlow Lite runtime.
Models compiled successfully in 2534 ms.
Input model: mobilenet_v2_1.0_224_inat_plant_quant.tflite
Input size: 4.76MiB
Output model: output/mobilenet_v2_1.0_224_inat_plant_quant_edgetpu.tflite
Output size: 5.22MiB
On-chip memory available for caching model parameters: 6.53MiB
On-chip memory used for caching model parameters: 5.08MiB
Off-chip memory used for streaming uncached model parameters: 0.00B
Number of Edge TPU subgraphs: 1
Total number of operations: 65
Operation log: output/mobilenet_v2_1.0_224_inat_plant_quant_edgetpu.log
Operator Count Status
ADD 10 Mapped to Edge TPU
AVERAGE_POOL_2D 1 Mapped to Edge TPU
CONV_2D 35 Mapped to Edge TPU
DEPTHWISE_CONV_2D 17 Mapped to Edge TPU
FULLY_CONNECTED 1 Mapped to Edge TPU
SOFTMAX 1 Mapped to Edge TPU
Input model: inception_v1_224_quant.tflite
Input size: 6.38MiB
Output model: output/inception_v1_224_quant_edgetpu.tflite
Output size: 6.93MiB
On-chip memory available for caching model parameters: 1.45MiB
On-chip memory used for caching model parameters: 1.45MiB
Off-chip memory used for streaming uncached model parameters: 5.16MiB
Number of Edge TPU subgraphs: 1
Total number of operations: 83
Operation log: output/inception_v1_224_quant_edgetpu.log
Operator Count Status
RESHAPE 1 Mapped to Edge TPU
SOFTMAX 1 Mapped to Edge TPU
AVERAGE_POOL_2D 1 Mapped to Edge TPU
MAX_POOL_2D 13 Mapped to Edge TPU
CONCATENATION 9 Mapped to Edge TPU
CONV_2D 58 Mapped to Edge TPU
推論結果(2回目以降の推論)
1つ目と2つ目のモデルを入れ替える前と比べて、約20msの短縮。
Model1(MobileNet V2)は、1つだけのモデルで推論した結果とほぼ変わらない。
Model2(Inception V1)の処理時間が遅くなっているがトータルとしてMoblieNet V2が早くなった分、改善している。
[2019/6/25 指摘を頂いて追記]
モデルを入れ替えることによって推論時間のトータルが改善することは意味がない。
(今回のケースではたまたま処理時間が改善しているように見えるだけであると推測)
モデルを入れ替える場合はどちらのモデルが使用頻度が高いか(Model1のほうが使用頻度が高ければ順序を先にする)を考慮したほうがメリットがある。
| 同時コンパイル | 平均推論時間[ms] |
あり
|
Model1 | 11.18 |
Model2 | 169.28 |