Armadilloフォーラム

NPU の使いこなしについて

tetsuo.yamashita

2022年3月28日 16時42分

お世話になっております。
下記の Armadillo-Base-OS サンプルアプリケーションを一通り実行し、実機にて USB Cam → DNN → OpenCV → HDMI までを確認できました。
https://manual.atmark-techno.com/armadillo-iot-g4/armadillo-base-os-dev…

このサンプルで利用したモデルの処理時間を調べてみたところ、公称 NPU 性能である 2.3TOPS よりも大幅に性能が低く測定されました。

・モデルの計算量 : 0.6GFLOPs/frame 程度
  ・ckpt と提供のサンプルモデルを元に tensorflow の model_analyzer, option_builder を使って計測
  ・tensorflow lite 化前のモデルになる
・invoke() (推論実行部) の実機処理時間 : 19msec/frame
  ・python time ライブラリで計測
  ・100 frame 平均を複数回計測し、ほぼ 19msec で固定
・0.6 [GFLOPs/frame] x 1/19 [frame/msec] ≒ 30[GFLOPs/sec]

これについて、

・性能低下の原因について何か知見があれば、教えていただけませんでしょうか?
・そもそも正常に NPU を動作させることができているのかを調べるために NPU の使用率などプロファイルを取る方法があれば、教えていただけまでんでしょうか?

以上、よろしくお願いいたします。

コメント

at_shiita.ishigaki

2022年3月29日 10時50分

石垣です。

> ・モデルの計算量 : 0.6GFLOPs/frame 程度
>   ・ckpt と提供のサンプルモデルを元に tensorflow の model_analyzer, option_builder を使って計測

よろしければ、モデルの計算量を0.6GFLOPs/frame程度と求めた方法について詳しく教えて頂けないでしょうか。

> ・性能低下の原因について何か知見があれば、教えていただけませんでしょうか?

性能低下の原因としていくつか考えられます。
・今回使用したモデルはNPU delegateが対応していない演算が含まれており、その演算はCPUで行う必要があること
・invoke()が呼び出される前に時間を計測し始めて、invoke()の処理が終わった後に計測を終了としているとした場合は、CPUがPythonのコードを処理する時間・CPUとNPU間でデータを渡す時間・NPUがキャッシュを読み込む時間等、演算性能を測定する以外の箇所の時間を測定していること
・NPUには3つのExecution Engineが入っており、どの演算のときにどの箇所が使用されるかは、下記URLのAppendix Dに記載されております。
https://www.nxp.com/docs/en/user-guide/IMX-MACHINE-LEARNING-UG.pdf
Batch NormalizationやAdd等で使用されるPPUは、他のExecution Engineからデータを受け取る時に、遅くなる傾向があります。恐らくこれはPPUが並列処理を行うため、データが溜まるまで待っているものだと思われます。

> ・そもそも正常に NPU を動作させることができているのかを調べるために NPU の使用率などプロファイルを取る方法があれば、教えていただけまでんでしょうか?

以下のコマンドを実行することで、NPUのデバッグを有効にすることができます。
デバッグを有効にすると、ログが出力され、各演算の実行時間や演算に使用されるExecution Engine等を確認することができます。

[container~ ]# export CNN_PERF=1 VIV_VX_DEBUG_LEVEL=1

tetsuo.yamashita

2022年3月29日 18時31分

返信ありがとうございます。

> よろしければ、モデルの計算量を0.6GFLOPs/frame程度と求めた方法について詳しく教えて頂けないでしょうか。
以下の二通りの方法で計算量を求めました。ほぼ結果は一致しています。

・サンプルアプリのモデルから concrete_function を取り出し、profile にかける(ckpt は不要でした)
  ・添付 zip 内の .ipynb を参照のこと
・netron model.tflite でモデルのグラフ構造を画像化し、手作業で演算ブロック (Conv2D など) を抽出し、手作業で MUL 回数を計算する
  ・添付 zip 内の png, excel ファイルを参照のこと

計算量の求め方について何か間違いがありましたら、教えていただければありがたいです。

> 性能低下の原因としていくつか考えられます。
> ・今回使用したモデルはNPU delegateが対応していない演算が含まれており、その演算はCPUで行う必要があること
> ・invoke()が呼び出される前に時間を計測し始めて、invoke()の処理が終わった後に計測を終了としているとした場合は、CPUがPythonのコードを処理する時間・CPUとNPU間でデータを渡す時間・NPUがキャッシュを読み込む時間等、演算性能を測定する以外の箇所の時間を測定していること
> ・NPUには3つのExecution Engineが入っており、どの演算のときにどの箇所が使用されるかは、下記URLのAppendix Dに記載されております。
> https://www.nxp.com/docs/en/user-guide/IMX-MACHINE-LEARNING-UG.pdf
> Batch NormalizationやAdd等で使用されるPPUは、他のExecution Engineからデータを受け取る時に、遅くなる傾向があります。恐らくこれはPPUが並列処理を行うため、データが溜まるまで待っているものだと思われます。

ありがとうございます。頂いた情報を元にもう少し調べてみます。

> 以下のコマンドを実行することで、NPUのデバッグを有効にすることができます。
> デバッグを有効にすると、ログが出力され、各演算の実行時間や演算に使用されるExecution Engine等を確認することができます。

[container~ ]# export CNN_PERF=1 VIV_VX_DEBUG_LEVEL=1

ありがとうございます。こちらも頂いた情報を元にもう少し調べてみます。

ファイル ファイルの説明
calc_flops.zip

at_shiita.ishigaki

2022年3月30日 15時19分

石垣です。

> 計算量の求め方について何か間違いがありましたら、教えていただければありがたいです。

tfliteモデルのFLOPsを求めるgitリポジトリを見つけました。
https://github.com/lisosia/tflite-flops
こちらのgitリポジトリとcalc_flops.xlsxで求められている、tfliteの計算量を比べてみたのですが、
calc_flops.xlsx行っている計算方法で求められるものは、MAC(Multiply-Accumulate)であって、
これをFLOPsに変換するためには、2倍する必要があるようです。
https://github.com/sovrasov/flops-counter.pytorch/issues/16
実際に上記のgitリポジトリにあるスクリプトを実行して、model.tfliteのFLOPsを計算したところ、1.2GFLOPsが得られました。

実際にモデルを呼び出して、TOPSを求めるという方法についてですが、
前述の方法では、計算量の算出対象はConvのみですが、
モデルの中では、Convレイヤー以外にも他のレイヤーであるReluやReshape等の演算も行われるため、
計算量の算出対象以外でも処理を行っていると考えられます。
また、NPU内でExecution Engine間で通信を行うことを考えると、これも計算量の算出対象以外の処理になります。
そのため、実際にモデルを実行して、TOPSを求めることは難しいのではないかと思います。

試しに、Conv2Dを1回のみ行うモデルを作成し、NPUのデバッグログで時間を計測してみたのですが、
42.6[MFLOPs]の計算量に対して362[us]かかったと表示されましたので、0.1[TOPS]と
NPUの演算性能公称値には及びませんでした。
ソフトウェア的な計測だとこれ以上の計測は難しいかと思われます。

ご参考になりましたら幸いです。

tetsuo.yamashita

2022年3月30日 15時40分

返信ありがとうございます。

> tfliteモデルのFLOPsを求めるgitリポジトリを見つけました。
> https://github.com/lisosia/tflite-flops
> こちらのgitリポジトリとcalc_flops.xlsxで求められている、tfliteの計算量を比べてみたのですが、
> calc_flops.xlsx行っている計算方法で求められるものは、MAC(Multiply-Accumulate)であって、
> これをFLOPsに変換するためには、2倍する必要があるようです。
> https://github.com/sovrasov/flops-counter.pytorch/issues/16
> 実際に上記のgitリポジトリにあるスクリプトを実行して、model.tfliteのFLOPsを計算したところ、1.2GFLOPsが得られました。
情報をありがとうございます。
x2 して 1.2GFLOPs であることに関して、その通りですね。
先の添付ファイルでは、
・calc_flops.xlsx の手計算のほうは MUL のみを計算しました
・ipynb のほうでは profile で求めた OPs 数を // 2 することで 0.6GOPs としていました

> 実際にモデルを呼び出して、TOPSを求めるという方法についてですが、
> 前述の方法では、計算量の算出対象はConvのみですが、
> モデルの中では、Convレイヤー以外にも他のレイヤーであるReluやReshape等の演算も行われるため、
> 計算量の算出対象以外でも処理を行っていると考えられます。
> また、NPU内でExecution Engine間で通信を行うことを考えると、これも計算量の算出対象以外の処理になります。
> そのため、実際にモデルを実行して、TOPSを求めることは難しいのではないかと思います。
なるほど、ありがとうございます。
事前に DNN モデル設計を行う際に、「ある程度で良いのでモデル計算量から実行性能見積もりができると DNN モデルの軽量化にフィードバックできる」
ということを狙えないかと考えて、調査しておりました。
Armadillo-Base-OS 上のコンテナで python コードを実際に動かして実行速度を見るほうが早そうですね。

> 試しに、Conv2Dを1回のみ行うモデルを作成し、NPUのデバッグログで時間を計測してみたのですが、
> 42.6[MFLOPs]の計算量に対して362[us]かかったと表示されましたので、0.1[TOPS]と
> NPUの演算性能公称値には及びませんでした。
> ソフトウェア的な計測だとこれ以上の計測は難しいかと思われます。
知見の教示、ありがとうございます。助かります。
こちらでも NPU デバッグログを試行してみようと思います。

tetsuo.yamashita

2022年4月6日 19時15分

お世話になっております。
こちらでも
・Conv のみの推論モデルで 0.1TOPs 程度の性能を確認
・NPU デバッグログの取得
が確認できました。
情報ありがとうございました。

一方で、NPU の性能についてお聞きしたことがあります。
i.MX Machine Learning User's Guide の 3.2.3 NNAPI delegate、3.2.4 VX Delegate セクションにから、以下のように理解しています。

・NNAPI delegate
  ・ NNAPI は Android 向けで TFLite で使われる標準的な GPU/NPU を使うための仕組み
  ・ H/W が対応しているオペレーションでも、NNAPI 対応されていないと GPU/NPU を使えない
・VX delegate
  ・ NNAPI deledate 後継
  ・ i.MX 用 Yocto 向けで VeliSilicon 専用の delegator がある (/usr/bin/libvx_delegate.so)

上記の内容ですと、i.MX 8M-Plus の NPU 性能を引き出すには VX delegate の方が適切なように見えます。
この VX delegate を使う仕組みは Armadillo-Base-OS では提供されないのでしょうか?
(前提の理解が間違っているのであれば、指摘をお願いいたします。)

以上、よろしくお願いいたします。

tetsuo.yamashita

2022年4月6日 19時29分

訂正です。
・「0.1TOPs」 → 0.1TOPS
・「3.2.3 NNAPI delegate、3.2.4 VX Delegate セクションにから、」→ 3.2.3 NNAPI delegate、3.2.4 VX Delegate セクションから
以上、よろしくお願いいたします。

> 一方で、NPU の性能についてお聞きしたことがあります。
> i.MX Machine Learning User's Guide の 3.2.3 NNAPI delegate、3.2.4 VX Delegate セクションにから、以下のように理解しています。
>
> ・NNAPI delegate
>   ・ NNAPI は Android 向けで TFLite で使われる標準的な GPU/NPU を使うための仕組み
>   ・ H/W が対応しているオペレーションでも、NNAPI 対応されていないと GPU/NPU を使えない
> ・VX delegate
>   ・ NNAPI deledate 後継
>   ・ i.MX 用 Yocto 向けで VeliSilicon 専用の delegator がある (/usr/bin/libvx_delegate.so)
>
> 上記の内容ですと、i.MX 8M-Plus の NPU 性能を引き出すには VX delegate の方が適切なように見えます。
> この VX delegate を使う仕組みは Armadillo-Base-OS では提供されないのでしょうか?

まだ予定はありません。VX delegate自体が昨年時点ではexperimentalとなっており
正式リリースされたのが2021/12でしたので、製品に取り込める品質ではありませんでした。

互換性の都合NNAPIを維持したいのですが、性能差がそれほどあるのか疑問なので、評価次第で
対応したいと思っています。その後、Base OS(というより、debianユーザーランド用のパッケージ
ですね)への対応するとなれば、アップデートするので、その時はコチラにリプライ致します。

tetsuo.yamashita

2022年5月9日 13時54分

お世話になっております。

>>互換性の都合NNAPIを維持したいのですが、性能差がそれほどあるのか疑問なので、評価次第で
対応したいと思っています。

これに関して nxp フォーラムにあった pdf に「Yolo で NNAPU delegate : VX delegate = 178msec : 12msec」となったような記載がありました。(以下の P.35)
https://community.nxp.com/t5/i-MX-Processors-Knowledge-Base/i-MX8MP-NPU…

現状の NNAPI delegate を用いた DNN 推論の実測値では、やはり、公称値 2.3TOPS との乖離があまりに大きいです。
何か NXP 社から情報提供されておりませんでしょうか?

at_shiita.ishigaki

2022年5月9日 16時43分

石垣です。

> この VX delegate を使う仕組みは Armadillo-Base-OS では提供されないのでしょうか?
先月のアップデートにて、VX delegateに対応いたしました。
使用方法については、下記URLの「TensorFlow Lite を使う」をご覧ください。
https://manual.atmark-techno.com/armadillo-iot-g4/armadillo-iotg-g4_pro…
文中にも記載されていますが、tflite-runtimeパッケージとライブラリイメージ(imx_lib)のバージョンの組み合わせによっては、TensorFlow Liteを用いたアプリケーションが正しく動作しない場合がございますので、
tflite-runtimeのバージョンを2.6.0-1以降に、imx_libのバージョンを2.2.0以降にアップデートを行ってください。

NNAPIからVX delegateに移行することにより、モデルによっては推論速度が速くなる場合が確認できましたので、お手元の環境でモデルを動かして、ご確認ください。

tetsuo.yamashita

2022年5月10日 17時16分

ありがとうございます。
アップデート情報を見逃しておりました。大変失礼いたしました。
すぐに試行してみます。

> NNAPIからVX delegateに移行することにより、モデルによっては推論速度が速くなる場合が確認できましたので、お手元の環境でモデルを動かして、ご確認ください。
どのようなモデルがどの程度速くなったかについて、何か教えていただけないでしょうか?
例えば、このトピックで以前試行されている Conv のみのモデルや、サンプルアプリで採用されている SSD MobileNet V2 などで良いのですが)

at_shiita.ishigaki

2022年5月11日 11時07分

石垣です。

> どのようなモデルがどの程度速くなったかについて、何か教えていただけないでしょうか?

下記FAQに使用されている4つのモデルでNNAPIとVX delegateの推論速度を比較しました。
https://armadillo.atmark-techno.com/node/10723

比較結果は以下の通りです。

- mobilenet_v2
  - 推論速度(NNAPI delegate): 3.0ms
  - 推論速度(VX delegate): 2.4ms
- mobilenet_v3
  - 推論速度(NNAPI delegate): 12.6ms
  - 推論速度(VX delegate): 5.2ms
- inception_v4
  - 推論速度(NNAPI delegate): 33.1ms
  - 推論速度(VX delegate): 33.1ms
- resnet_v2_50
  - 推論速度(NNAPI delegate): 5.7ms
  - 推論速度(VX delegate): 5.3ms

また、armadillo-demo-experienceに含まれている物体検出、姿勢推定、セグメンテーションの3つのデモアプリケーションについても
VX delegateとNNAPIの速度比較を行なった所、以下のような結果となりました。

- 物体検出デモ
  - ベースモデル: ssd mobilenet v1
  - 推論速度(NNAPI delegate): 14.3ms
  - 推論速度(VX delegate): 10.4ms
- 姿勢推定デモ
  - ベースモデル: posenet
  - 推論速度(NNAPI delegate): 31.3ms
  - 推論速度(VX delegate): 31.3ms
- セグメンテーションデモ
  - ベースモデル: mobile-deeplab-v3-plus
  - 推論速度(NNAPI delegate): 66.7ms
  - 推論速度(VX delegate): 28.6ms

armadillo-demo-experienceについては以下URLをご覧ください。
https://manual.atmark-techno.com/armadillo-iot-g4/armadillo-iotg-g4_pro…

tetsuo.yamashita

2022年5月20日 9時44分

ありがとうございます。

簡易的ではありますが、こちらでも VX Delegate による処理速度の向上を確認できました。
Coral から提供されている SSD MobileNetV2 Object Detection (TF2) の TFLite ファイル (https://coral.ai/models/object-detection/) を用いて以下を確認できました。

・ NNAPI delegate : 約 30msec/frame
・ VX delegate : 約 20msec/frame

物体検出モデルとしては、教えて頂いた速度比較結果と大体同じ結果になりました。
(DNN モデルが完全に一致するかは分かりませんが、MobileNet をバックボーンにした Object Detection ということで、大きくは違わないと思います。)

今後も NPU 関連の更新や i.mx 8M-Plus NPU 向け DNN モデル最適化手法、対応していないオペレーションの回避例などノウハウ公開などを期待しております。

ありがとうございました。

tetsuo.yamashita

2022年5月20日 9時45分

> 物体検出モデルとしては、教えて頂いた速度比較結果と大体同じ結果になりました。
訂正、補足です。「大体同じ結果になりました」→「大体同じくらいの割合で速くなりました」