2019年10月1日火曜日

Jetson NanoでTF-TRTを試す(Image Classification)その2

前回まで


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)を短縮できるかを確認する。


動機


前回のまとめをTweetしたところ、@koansin さんから指摘を頂いた(ありがとうございます。感謝!)。
MobileNet v1, v2は私の測定結果より早くなるはずとのこと。
確かに約17msは私の計測結果(v1: 約25ms、v2: 約29ms)より早い。



このため、何が処理時間に影響しているのかを調査することにした。


まとめとかいろいろ


前回の計測で処理時間が遅くなっていた原因が特定できた。原因は2つ。
  1. FP16のモデルの生成はJetson Nano上で行う。
    Host と Jetson Nano のTensorRTのバージョンが一致しないため、最適化がモデルロード時に行われてしまう。このときメモリ不足等?によって最適化がうまく行われない可能性がある。
  2. モデルの生成時、 Relu6(x )を relu(x) - relu(x - 6)に置き換えをやめることにより、処理時間が短縮される(MobileNet v1, v2で有効)。
    オリジナルの NVIDIA-AI-IOT/tf_trt_models リポジトリの更新が止まっていて(1年以上)古い最適化のコードが残っていることが原因。
    少なくとも、Jetson Nanoでは Relu6 を置き換えないほうが有効である。



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)を指定する。

    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 の置き換えあり。



Model
Inference time [ms]
Original
(FP32)
TF-TRT
(FP16)
TF-TRT (FP16)
Replacing Relu6
MobileNet_v1_1.0_2242755128482931
MobileNet_v2_1.0_2242122428482934


Jetson Nano 初回の推論時間を比較


Jetson Nanoの2回目以降の推論時間


Relu6 の置き換えをやめることで処理時間が更に短縮したことを確認できた。
Original(FP32) の半分以下の処理時間になった。
約15〜16msは十分扱える処理時間だと思う。


Model
Inference time [ms]
Original
(FP32)
TF-TRT (FP16)TF-TRT (FP16)
Replacing Relu6
MobileNet_v1_1.0_224341524
MobileNet_v3_1.0_224371627


Jetson nanoの推論時間(2回目以降、100回の平均)

0 件のコメント:

コメントを投稿