(2019.10.16 MobileNet v1, v2のFP16の処理時間を最適化する記事を書いた)
目的
TF-TRT(TensorFlow integration with TensorRT)を使ってFP16に最適化したモデルを生成し、NVIDIA GPU、Jetson Nanoでどの程度最適化の効果ががあるのかを確認する。
今回は、Image Classificationのモデルについて確認する。
今回は、Image Classificationのモデルについて確認する。
動機
NVIDIA公式のGithubリポジトリにJetxon(TX, TX2向け)のTF-TRTモデルが公開されている。
TF-TRTはJetson Nanoでも有効であるはずなのだが、ベンチマークなどの情報がすくない。
また、TensorFlow1.14とTensorRT5.1.5では、TF-TRTモデルに変換する際のIFが変更になったことと、Jetson NanoのSDKのバージョンが上がったことから、新しいIFでモデルを作成し、ベンチマークすることにした。
これ、TensorFlowのバージョンが1.14だとTrtGraphConverterが使えるっぽいんだ。1.13だとない。— nb.o (@Nextremer_nb_o) August 22, 2019
それと、Jetson NanoのTensorFlowのバージョン1.14にアップしているのか
ホストPCもJetson Nanoも1.14にするかー
まとめとか
- TF-TRTをつかうことで、モデルの推論時間を短縮することができることが確認できた(今回はFP16による最適化)。
- GTX1070, Jetson Nanoで効果が確認できた。
Jetson NanoはMobileNet v1, v2がImage Classificationのモデルで使用できそう。 - TF-TRTモデルを生成する側と推論を行う側でTensorRTのバージョンが一致していないとNG(回避方法あり)。
TF-TRTを使うメリット
TensorRTではなく、TF-TRTを使うメリットとしては以下と考えている。
- TensorFlowで学習したモデル(Frozen Graph or Saved Model)が流用できる。
- 学習・推論のコードはTensorFlowのコードがほぼそのまま流用できる。
参考ドキュメント
- High performance inference with TensorRT Integration - Medium
MediumのTensorFlowブログ - Accelerating Inference In TF-TRT User Guide
NVIDIAの公式ドキュメント - High performance inference with TensorRT Integration - @Vengineerの戯言
@Vengineerさんのブログ
モデルの作成から推論まで
大きな流れとして、
最適化が行われると、いくつかのSubGraphがTensorRTEngineOpで置き変わる。
どの程度、置き換わったかは以下のコードで確認できる。
- ホスト環境(PC: Ryzen1700+GTX1070)でNGCコンテナーの立ち上げ。
- ホスト環境でpretrained modelを読み込み->TF-TRTモデルに変換。
- ホスト環境、JetsonNanoで推論を行う。
NGCコンテナーの立ち上げ
TF-TRTを使うにはTensorRTが必要である。TensorRTがなくてもモデル生成や実行ができるが、最適化されていないため注意が必要。
ホスト環境にNGCコンテナーを立ち上げる。まずは、DockerをインストールしてGPUを使えるようにセットアップする(前回の記事を参照)。
NVIDIA/TensorFlowから19.08-py3(2019/9/8時点の最新)をPullし、起動する。
sudo docker pull nvcr.io/nvidia/tensorflow:19.08-py sudo docker run -it --gpus all -p 8888:8888 nvcr.io/nvidia/tensorflow:19.08-py3
TF-TRTリポジトリの取得
TF-TRTでpretrained modelを変換し、FP16で最適化する流れを説明する。
pretrained modelの読み込み
pretrained modelのcheckpointファイルからモデルをロード・リストアする。
実際のコードはここ。一般的な方法であるので説明は省略する。
ただし、Relu6についてはTensorRTで最適化するためにrelu(x) - relu(x - 6)に置き換えている(TensorFlow Container 18.11-19.01 (TensorFlow 1.12)でRelu6がサポートされているので置き換えの必要がないかもしれないが今回は未検証)。
実際のコードはここ。一般的な方法であるので説明は省略する。
ただし、Relu6についてはTensorRTで最適化するためにrelu(x) - relu(x - 6)に置き換えている(TensorFlow Container 18.11-19.01 (TensorFlow 1.12)でRelu6がサポートされているので置き換えの必要がないかもしれないが今回は未検証)。
TF-TRTモデルの変換
TrtGraphConverterを使ってモデルを変換する(古いAPIはcreate_inference_graph)。
convertメソッドによって最適化されたモデルを得ることができる。
convertメソッドによって最適化されたモデルを得ることができる。
converter = trt.TrtGraphConverter( input_graph_def=frozen_graph, nodes_blacklist=output_names, #output nodes max_batch_size=1, is_dynamic_op=True, max_workspace_size_bytes=trt.DEFAULT_TRT_MAX_WORKSPACE_SIZE_BYTES, precision_mode=trt.TrtPrecisionMode.FP16, minimum_segment_size=50) trt_graph = converter.convert()
TrtGraphConverterの引数には
- input_graph_def: ロードしたGraphDefを指定。
- nodes_blacklist: 最適化しないnode。
Output nodeを指定(create_inference_graphではoutputs)。 - is_dynamic_op: 推論の実行時にTensorRTの最適化を行う。
最適化の際は入力のサイズが予め決まっている必要がある。入力サイズが決まっていないモデルの場合は、TrtGraphConverterによって最適化できない。
Trueにすることによって、推論時に最適化を行うことができる。
しかし、初回の推論時に最適化が行われるため処理時間が増加する。
また、ホストとJetson NanoのTensorRTのバージョンが不一致の場合は、最適化により動作することができる。 - max_workspace_size_bytes: TensorRTエンジンが実行できる最大のGPUメモリサイズ。
DEFAULT_TRT_MAX_WORKSPACE_SIZE_BYTES は新しく追加された定義。 - precision_mode: 量子化のモード。
FP16とINT8が選択できる。今回はFP16を選択。 - minimum_segment_size: subgraphをTRTEngineOpで置き換える最小のノード数。
最適化が行われると、いくつかのSubGraphがTensorRTEngineOpで置き変わる。
どの程度、置き換わったかは以下のコードで確認できる。
trt_engine_opts = len([1 for n in trt_graph.node if str(n.op) == 'TRTEngineOp']) print("trt_engine_opts = {}".format(trt_engine_opts))
TF-TRTモデルの保存
モデルの保存は、SerializeToStringを使用する。
base_name = os.path.splitext(os.path.basename(checkpoint_path))[0] save_model_file_name = base_name + '_frozen_fp16.pb' with open(os.path.join(MODEL_DIR, save_model_file_name), 'wb') as f: f.write(trt_graph.SerializeToString())
ベンチマーク
GTX1070とJetson Nanoでベンチマークを行う。
推論時間のベンチマークに使用したスクリプトはここ。
TF-TRTのモデルを扱うためには、以下のインポートが必要。
from tensorflow.python.compiler.tensorrt import trt
ただし、初回はモデルの構築を行うため省く。
ファイルサイズ
変換前後でのファイルサイズを比較する。
驚いたことに、TF-TRTモデルのほうがオリジナルの倍になっていた。
ファイルサイズが大きくなるのは組込デバイスには少し負担になる気がするのだが...
GTX1070の初回の推論時間
モデル構築を行うため、初回の推論は処理時間が多くかかる。
is_dynamic_opによる違いがあるかを確認した。
- is_dynamic_opにTrueを指定した場合
TF-TRTモデルの場合、初回の推論に多く時間がかかっている(約20〜30倍)。
これは、モデルの最適化が行われるためと思われる。 - is_dynamic_opにFalseを指定した場合
TF-TRTモデルのほうがオリジナルより推論時間が短くなっており、最適化の効果が確認できる。
初回の推論時間(is_dynamic_opにTrueを指定)
初回の推論時間(is_dynamic_opにFalseを指定)
GTX1070 初回の推論時間を比較(is_dynamic_opにFalseを指定) |
GTX1070の2回目以降の推論時間
TF-TRTモデルのほうが処理時間が短縮している。
FP16の最適化の効果が出ている。is_dynamic_opの違いはなかった。これは、TF-TRTモデルの生成時に最適化が行われているためと思われる。
GTX1070の推論時間(2回目以降、100回の平均) |
Jetson Nanoの初回の推論時間
is_dynamic_opにTrueを指定した場合
傾向はGTX1070と同じである。Jetson Nanoではモデルサイズが大きいものは起動できなかった。
傾向はGTX1070と同じである。Jetson Nanoではモデルサイズが大きいものは起動できなかった。
is_dynamic_opにFalseを指定した場合、「Segmentation fault (コアダンプ)」が発生し起動できなかった。
ログから、Host側とJetsonNano側のTensorRTのバージョンが一致しておらず、TF-TRTモデルが読み込めなかったと思われる。
2019-09-08 16:24:10.910053: E tensorflow/compiler/tf2tensorrt/utils/trt_logger.cc:41] DefaultLogger The engine plan file is not compatible with this version of TensorRT, expecting library version 5.1.6 got 5.1.5, please rebuild. Segmentation fault (コアダンプ)
is_dynamic_opにTrueを指定した場合は、初回の推論時にモデルの最適化が行われるため、事象が発生しなかったと思われる。
Jetson NanoのTensorRTのバージョンは5.1.6、Host側のNGCコンテナーは5.1.5なので、確かにバージョンは不一致。でも、TensorRTのリリースノートにはバージョン5.1.5まで、NGCコンテナーにもない... これはどういうことだろうか?
5.1.6がリリースされたら、is_dynamic_opにFalseを指定した場合も検証することとする。
Jetson NanoのTensorRTのバージョンは5.1.6、Host側のNGCコンテナーは5.1.5なので、確かにバージョンは不一致。でも、TensorRTのリリースノートにはバージョン5.1.5まで、NGCコンテナーにもない... これはどういうことだろうか?
5.1.6がリリースされたら、is_dynamic_opにFalseを指定した場合も検証することとする。
初回の推論時間(is_dynamic_opにTrueを指定)
※強制終了: "強制終了"を表示してスクリプトが終了した。
※OOM: "OutOfMemory"を表示してスクリプトが終了した。
※起動せず: 5分以上経過しても初回の推論が終わらないので諦めた。
※ー: 計測していない。
Jetson Nanoの2回目以降の推論時間
MobileNet v1, v2に限定すると、TF-TRTによる最適化の効果が出ている。
Inception v1, v2は差がない。おそらくGPUのメモリサイズが不足していると思われる。
ここから、TF-TRTで使用できるモデルはMobileNet v1, v2になる。
※青色セル: メモリ不足と思われる警告が出力
(The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory were available.)
- 次はObject Detection モデルについて確認してみる。
NGCコンテナーのTensorRTのバージョンがアップデートされてからか? - tf.kerasで作成したモデルもTF-TRTモデルに変換して実行することができる。
notebookはここ。
ただし、推論の際はtf.kerasではなく、session.runの方式になってしまう。
変わってしまうのであれば、TensorRTで実行したほうがよいかもしれない。
(TF2.0でTF-TRTがtf.kerasで推論できるようになればかなり強力) - Jetson NanoでTF-TRTモデルの作成を行ったが、ベンチマークした結果、最適化されなかった。
おそらく、GPUの世代やメモリサイズが影響していると思われる。
0 件のコメント:
コメントを投稿