前回まで
Jetson NanoでTF-TRTを試す(Image Classification)では、TF-TRT(TensorFlow integration with TensorRT)を使ってFP16に最適化したモデルを生成し、NVIDIA GPU、Jetson Nanoでどの程度最適化の効果ががあるのかを確認した。
目的
今回はMobileNet v1, v2のFP16の処理時間を最適化する。
前回計測した処理時間の結果(MobileNet v1: 約25ms、v2: 約29ms)を短縮できるかを確認する。
前回計測した処理時間の結果(MobileNet v1: 約25ms、v2: 約29ms)を短縮できるかを確認する。
動機
前回のまとめをTweetしたところ、@koansin さんから指摘を頂いた(ありがとうございます。感謝!)。
MobileNet v1, v2は私の測定結果より早くなるはずとのこと。
確かに約17msは私の計測結果(v1: 約25ms、v2: 約29ms)より早い。
MobileNet v1, v2は私の測定結果より早くなるはずとのこと。
確かに約17msは私の計測結果(v1: 約25ms、v2: 約29ms)より早い。
Converting frozen pb to tf-trt enabled pb on Jetson Nano is a bit tricky. The very first thing to make sure is that you have large enough memory. If the conversion goes well, Mobilenet V1/V2 fp16 tf-trt should around 17 ms. With trt .uff, they should be around 13 ms.— freedom Koan-Sin Tan (@koansin) September 21, 2019
このため、何が処理時間に影響しているのかを調査することにした。
まとめとかいろいろ
前回の計測で処理時間が遅くなっていた原因が特定できた。原因は2つ。
- FP16のモデルの生成はJetson Nano上で行う。
Host と Jetson Nano のTensorRTのバージョンが一致しないため、最適化がモデルロード時に行われてしまう。このときメモリ不足等?によって最適化がうまく行われない可能性がある。 - モデルの生成時、 Relu6(x )を relu(x) - relu(x - 6)に置き換えをやめることにより、処理時間が短縮される(MobileNet v1, v2で有効)。
オリジナルの NVIDIA-AI-IOT/tf_trt_models リポジトリの更新が止まっていて(1年以上)古い最適化のコードが残っていることが原因。
少なくとも、Jetson Nanoでは Relu6 を置き換えないほうが有効である。
I was able to get the result you told me before!— nb.o (@Nextremer_nb_o) September 27, 2019
(JetPack 4.2.2 MobileNet V1: 15ms, V2: 16ms)
Replacing Relu6 with Relu (x) -Relu (x-6) was the cause of the slow speed. Relu6 optimization is built in TF1.12, so it is faster not to replace Relu6.
Thanks!https://t.co/e9SrMg9NNv pic.twitter.com/P8m9SpYwci
2.について、ここからは推測になるが、
- オリジナルの NVIDIA-AI-IOT/tf_trt_models リポジトリは Jetson TX2 向けであった。
- ここのコメントから推測するに、当時は TensorFlow 1.7 であった。
このときの TF-TRT は Relu6 の最適化をサポートしていなかった。
(Relu6 のサポートは、TensorFlow 1.12 のようだ) - このため、Relu6 を Relu に置き換えることが有効であった。
- しかし、TensorFlow 1.12以降のTF-TRTでは Relu6 がサポートされたため、置き換えないほうが最適化されるはずが、本家のリポジトリは更新されないまま...
検証結果
ここからは、検証結果を記載する。
リポジトリ
今回検証で使用したリポジトリは本家よりForkしたリポジトリを使用している。
JetsonNanoの環境
バージョン
- JetPack 4.2.2 (r32.2.1)
- TensorRT: 5.1.6
- TensorFlow:1.14.0 (NVIDIA がリリースしたバイナリをインストール)
- Python:3.6.8
メモリリーソースを確保するため、CLIとして動作させる。
モデルの生成
モデルの生成はJetson Nanoで行う。
変換用のスクリプトを作成して行う。
Relu6 -> Relu(x) - Relu(x - 6)の置き換えをやめる
モデルの変換時、ckptファイルからモデルをロードした後に、Relu6 を Relu に変換する箇所がある。
今回、この変換をやめるように処理を変更した。
ちなみに、この convert_relu6 関数は、こちら(tf_trt_models/graph_utils.py)で定義されている。
モデルの変換
変換用のスクリプトを作成して行う。
前回の計測では、Host PC でTrtGraphConverterを使ってモデルを変換する際に、is_dynamic_op = True を指定している(Host PC と Jetson NanoでTensorRTのバージョンが一致しないため)。
Host PC と Jetson NanoでTensorRTのバージョンが一致しないと、モデルのロード時に、モデルの最適化が行われてしまう。今回はこの影響をなくすため、Jetson Nanoでモデル生成を行うこととした(is_dynamic_op = Falseを指定)。
Jetson Nanoで変換を行う場合の注意としては、max_workspace_size_bytes = trt.DEFAULT_TRT_MAX_WORKSPACE_SIZE_BYTES を指定するとメモリ不足で変換が失敗する。このため、1 << 25 (3G)を指定する。
Host PC と Jetson NanoでTensorRTのバージョンが一致しないと、モデルのロード時に、モデルの最適化が行われてしまう。今回はこの影響をなくすため、Jetson Nanoでモデル生成を行うこととした(is_dynamic_op = Falseを指定)。
Jetson Nanoで変換を行う場合の注意としては、max_workspace_size_bytes = trt.DEFAULT_TRT_MAX_WORKSPACE_SIZE_BYTES を指定するとメモリ不足で変換が失敗する。このため、1 << 25 (3G)を指定する。
converter = trt.TrtGraphConverter( input_graph_def=frozen_graph, nodes_blacklist=output_names, #output nodes max_batch_size=1, is_dynamic_op=False, max_workspace_size_bytes = 1 << 25, precision_mode=trt.TrtPrecisionMode.FP16, minimum_segment_size=50)
ベンチマーク
ベンチマークスクリプトは以前と同様。
Relu6の置き換えをする/しないで比較を行った。
Jetson Nanoの初回の推論
Original(FP32) は前回計測したもの。
TF-TRT(FP16) は FP16 に変換、Relu6 の置き換えなし。
TF-TRT(FP16) Replacing Relu6 は FP16 に変換、Relu6 の置き換えあり。
Jetson Nano 初回の推論時間を比較 |
Jetson Nanoの2回目以降の推論時間
Relu6 の置き換えをやめることで処理時間が更に短縮したことを確認できた。
Original(FP32) の半分以下の処理時間になった。
約15〜16msは十分扱える処理時間だと思う。
Jetson nanoの推論時間(2回目以降、100回の平均) |
0 件のコメント:
コメントを投稿