ラベル JetsonNano の投稿を表示しています。 すべての投稿を表示
ラベル JetsonNano の投稿を表示しています。 すべての投稿を表示

2021年2月22日月曜日

Jetson (JetPack 4.5) でOpen3D + Open3D-MLをビルドする

目的


前回のブログではJetson Nano (Jetpack 4.5) でOpen3DをUSE_SYSTEM_LIBREALSENSE(インストール済みライブラリをリンク)でビルドした。

今回は、Open3D-MLも含めてビルドする。


リファレンス




準備


Pythonの仮想環境のインストール


Open3D-MLを含めてビルド後、Python パッケージをインストールすると、システムでインストール済みのpyyamlを競合してしまう。
このため、Pythonの仮想環境にインストールする。

好みでvirtualenv virtualenvwrapperを選択。
$ sudo pip3 install virtualenv virtualenvwrapper

# Add to .bashrc
# virtualenv and virtualenvwrapper
export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_VIRTUALENV=/usr/local/bin/virtualenv
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source /usr/local/bin/virtualenvwrapper.sh
export VIRTUALENVWRAPPER_ENV_BIN_DIR=bin

$ source .bashrc
$ mkvirtualenv --python=python3 open3d
$ workon open3d


TensorFlowのインストール


リファレンスを参考にインストール。
(open3d) $ sudo apt-get update
(open3d) $ sudo apt-get install libhdf5-serial-dev hdf5-tools libhdf5-dev zlib1g-dev zip libjpeg8-dev liblapack-dev libblas-dev gfortran

(open3d) $ pip3 install numpy==1.16.1 future==0.18.2 mock==3.0.5 h5py==2.10.0 keras_preprocessing==1.1.1 keras_applications==1.0.8 gast==0.2.2 futures protobuf pybind11
(open3d) $ pip3 install --pre --extra-index-url https://developer.download.nvidia.com/compute/redist/jp/v45 tensorflow


PyTorchのインストル


こちらもフォーラムにあるとおりにインストール。
(open3d) $ wget https://nvidia.box.com/shared/static/cs3xn3td6sfgtene6jdvsxlr366m2dhq.whl -O torch-1.7.0-cp36-cp36m-linux_aarch64.whl
(open3d) $ sudo apt-get install python3-pip libopenblas-base libopenmpi-dev
(open3d) $ pip3 install Cython
(open3d) $ pip3 install numpy torch-1.7.0-cp36-cp36m-linux_aarch64.whl


Open3Dのビルド


まずは、TensorFlow、PyTorchのCXX ABIの確認。
Open3Dのドキュメントにもあるとおり、TensorFlow、PyTorch、Open3Dで異なる CXX ABIであると問題が発生する。
(open3d) $ python -c "import torch; print(torch._C._GLIBCXX_USE_CXX11_ABI)"
True
(open3d) $ python -c "import tensorflow; print(tensorflow.__cxx11_abi_flag__)"
2021-02-22 18:53:09.238147: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.10.2
1

CXX ABIはすべてCXX11 ABIであることが確認できた。

事前にInstall dependenciesにあるソフトウェアをインストール。

メモリを確保するため、CUIモードで作業。
(open3d) $ sudo systemctl set-default multi-user.target
(open3d) $ sudo reboot

あとは、ビルドするだけ。
CMakeのオプションで注意する点は以下。
  • BUILD_CUDA_MODULEをON
  • GLIBCXX_USE_CXX11_ABIをON
  • BUNDLE_OPEN3D_MLをONにして、OPEN3D_ML_ROOTにOpen3D-MLのパスを指定
  • BUILD_TENSORFLOW_OPS、BUILD_PYTORCH_OPSをON
  • make pip-packageする前にyapfパッケージをpipでインストールする
    (なぜかmakeで失敗する。たぶん、requirements.txtに必要?)
$ workon open3d
(open3d) $ git clone --recursive https://github.com/intel-isl/Open3D
(open3d) $ git clone https://github.com/intel-isl/Open3D-ML.git
(open3d) $ cd Open3D/
(open3d) $ mkdir build && cd build
(open3d) $ cmake \
    -DPYTHON_EXECUTABLE=$(which python3) \
    -DBUILD_SHARED_LIBS=ON \
    -DBUILD_BENCHMARKS=ON \
    -DBUILD_CUDA_MODULE=ON \
    -DBUILD_CACHED_CUDA_MANAGER=ON \
    -DBUILD_GUI=ON \
    -DGLIBCXX_USE_CXX11_ABI=ON \
    -DBUILD_RPC_INTERFACE=ON \
    -DBUILD_TENSORFLOW_OPS=ON \
    -DBUILD_PYTORCH_OPS=ON \
    -DBUNDLE_OPEN3D_ML=ON \
    -DOPEN3D_ML_ROOT=../../Open3D-ML \
    -DCMAKE_BUILD_TYPE=Release \
    ..
(open3d) $ make -j 3 
(open3d) $ sudo make install
(open3d) $ pip install yapf
(open3d) $ sudo make pip-package
(open3d) $ pip install /home/jetson/Open3D/build/lib/python_package/pip_package/open3d-0.12.0+408d9d0a-cp36-cp36m-linux_aarch64.whl


確認


GUIモードに戻して、Window managerをLXDEに変更する(使えるメモリを増やすため)。
$ sudo systemctl set-default graphical.target
$ sudo reboot

その後、Open3D-MLのサンプルを動作させてみる。

ただ、Jetson Nanoのメモリ(4GB)では不足しているので
  • モデルはKPConvのみをロード
  • データも1種類(000700)だけロード
するように変更して実行する。



表示まで1、2分待ってなんとか動いた〜😅
(サンプルはPyTorchのモデルを実行するみたい。TensorFlowはどうだろうか?)

Jetson AGX XavierやJetson Xavier NXとかだとフルで動かせるのかな?

Open3DをUSE_SYSTEM_LIBREALSENSE(インストール済みライブラリをリンク)でビルドする

 目的


Open3DはRealSense SDK(librealsense)が組み込まれている。

ソースビルドした際、デフォルトではlibrealsenseをローカルでビルドし、静的リンクしている。Open3DのビルドオプションはFORCE_RSUSB_BACKEND=ONであったりするため、できればpre-install済みのバイナリを使いたい場合もある。

ビルド時に「USE_SYSTEM_LIBREALSENSE」を指定すればpre-install済みのバイナリをリンクするはずなのだが、実際には動作していないことがわかった。

このため、CMakeを修正し、「USE_SYSTEM_LIBREALSENSE」でpre-install済みのlibrealsenseをリンクするように対応する。


動機


前回のブログ「Jetson Nano(JetPack 4.5)でlibrealsenseをソースビルドする」でRealSense SDKをソースビルドしてインストールした。

このlibrealsenseを使ってOpen3DのRealSense IFを使ってみたかった。


リファレンス




手順


Open3Dに出したPull requestはマージされたのでcommit 41fcfdc 以降でビルドすればOK。

前回のブログのJetson Nano(librealsenseをソースビルドしてインストール)でビルドした(x86のUbuntuでも確認済み)。

Jetson Nanoの場合は、ARM supportの手順に従ってビルドする。
cmakeの際に
  • 「BUILD_LIBREALSENSE」と「USE_SYSTEM_LIBREALSENSE」をONにする。
  • 「GLIBCXX_USE_CXX11_ABI」をONにする。
    フラグをOFFにするとOpen3DとlibrealsenseのC++ ABIの違いで#2985の問題が発生する。
    このため、GLIBCXX_USE_CXX11_ABI=OFFを指定するとUSE_SYSTEM_LIBREALSENSEはOFFにしている。

$ git clone --recursive https://github.com/intel-isl/Open3D
$ cd Open3D
$ mkdir build && cd build
$ cmake \
    -DCMAKE_BUILD_TYPE=Release \
    -DBUILD_SHARED_LIBS=ON \
    -DBUILD_CUDA_MODULE=OFF \
    -DBUILD_GUI=ON \
    -DPYTHON_EXECUTABLE=$(which python3) \
    -DBUILD_LIBREALSENSE=ON \
    -DUSE_SYSTEM_LIBREALSENSE=ON \
    -DGLIBCXX_USE_CXX11_ABI=ON
    ..
$ make -j3
$ sudo make install
$ sudo make install-pip-package


動作確認


Jetson Nanoで確認。

Pythonで接続したRealSense(L515)を認識していること。
$ python
Python 3.6.9 (default, Oct  8 2020, 12:12:24) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import open3d as o3d
>>> o3d.t.io.RealSenseSensor.list_devices()
[Open3D INFO] [0] Intel RealSense L515: f0220613
[Open3D INFO] 	depth_resolution: [320,240]
[Open3D INFO] 	depth_format: [RS2_FORMAT_Z16]
[Open3D INFO] 	visual_preset: [RS2_L500_VISUAL_PRESET_CUSTOM | RS2_L500_VISUAL_PRESET_DEFAULT | RS2_L500_VISUAL_PRESET_LOW_AMBIENT | RS2_L500_VISUAL_PRESET_MAX_RANGE | RS2_L500_VISUAL_PRESET_NO_AMBIENT | RS2_L500_VISUAL_PRESET_SHORT_RANGE]
[Open3D INFO] 	color_fps: [15 | 30 | 6]
[Open3D INFO] 	depth_fps: [30]
[Open3D INFO] 	color_resolution: [640,480]
[Open3D INFO] 	color_format: [RS2_FORMAT_BGR8 | RS2_FORMAT_BGRA8 | RS2_FORMAT_RGB8 | RS2_FORMAT_RGBA8 | RS2_FORMAT_Y16 | RS2_FORMAT_YUYV]
[Open3D INFO] Open3D only supports synchronized color and depth capture (color_fps = depth_fps).
True
>>> 

RealSenseRecorderのサンプルが動作すること。

やった〜!
PRもマージされて、Open3DのContributorになったぞ〜!!

2021年2月21日日曜日

Jetson Nano(JetPack 4.5)でlibrealsenseをソースビルドする

目的


NVIDIA Jetson NanoでIntel RealSenseをソースビルド(Native Backend)する。

RealSenseのSDK(librealsense)でNative Backendを使うには、カーネルにパッチを当てたうえでソースビルドが必要。
しかし、librealsenseのJetson用のパッチはJetPack 4.3用のため、JetPack4.5ではパッチがエラーとなってしまう。
このため、パッチをJetPack 4.5に対応してビルドする。


注意事項


2021.2.21時点
  • 公式のリポジトリ(librealsense)が対応した場合、この内容は古くなってしまうため、必ず最新情報を確認すること。
  • パッチの内容について誤りがある可能性があること(公式の対応でないため)。


リファレンス



リポジトリ


librealsenseをforkしたリポジトリを用意した。



手順


カーネルのパッチ適用&ビルド


JetPack 4.5を書き込んだJetson Nanoを用意する。
あとは公式の「Building from Source using Native Backend」と同じ手順で問題ない。
途中でCloneしたカーネルソースのtag を求められるので「tegra-l4t-r32.5」を入力する。

$ sudo apt update
$ sudo apt upgrade

$ git clone -b jetson_l4t-r32.5-4.9 https://github.com/NobuoTsukamoto/librealsense.git
$ cd librealsense
$ ./scripts/patch-realsense-ubuntu-L4T.sh

~~~~~~~~~~
Create the sandbox - NVidia L4T source tree(s)
Downloading default kernel/kernel-4.9 source...
Cloning into '/home/jetson/librealsense/Tegra/sources/kernel/kernel-4.9'...
remote: Enumerating objects: 5207472, done.
remote: Counting objects: 100% (5207472/5207472), done.
remote: Compressing objects: 100% (833434/833434), done.
remote: Total 5207472 (delta 4367040), reused 5173766 (delta 4333423)
Receiving objects: 100% (5207472/5207472), 943.55 MiB | 1.03 MiB/s, done.
Resolving deltas: 100% (4367040/4367040), done.
The default kernel/kernel-4.9 source is downloaded in: /home/jetson/librealsense/Tegra/sources/kernel/kernel-4.9
Please enter a tag to sync /home/jetson/librealsense/Tegra/sources/kernel/kernel-4.9 source to
(enter nothing to skip): 

ここで、「tegra-l4t-r32.5」入力してEner。あとはビルドが終わるのを待つ。

~~~~~~~~~~
Copying the patched modules to (~/)
~/librealsense
Move the modified modules into the modules tree
Insert the modified kernel modules
Replacing uvcvideo  -
        Applying the patched module ...  succeeded
Replacing hid_sensor_accel_3d  -
        Applying the patched module ...  succeeded
Replacing hid_sensor_gyro_3d  -
        Applying the patched module ...  succeeded
Replacing hid_sensor_trigger  -
        Applying the patched module ...  succeeded
Replacing hid_sensor_iio_common  -
        Module hid_sensor_iio_common  is used by hid_sensor_trigger
        Unloading dependency hid_sensor_trigger
        Module is resident, unloading ...  succeeded.
        Applying the patched module ...  succeeded      Reloading dependent kernel module hid_sensor_trigger ...  succeeded.


Script has completed. Please consult the installation guide for further instruction.


librealsenseのビルド


あとはlibrealsenseのビルドを行う。
念のため再起動してcloneしたlibrealsenseディレクトリに移動。

$ mkdir build && cd build
$ export PATH=${PATH}:/usr/local/cuda/bin
$ cmake \
  -DBUILD_WITH_CUDA=ON \
  -DBUILD_WITH_OPENMP=ON \
  -DBUILD_PYTHON_BINDINGS=ON \
  -DCMAKE_BUILD_TYPE=Release \
  ..
$ make -j$(($(nproc)-1))
$ sudo make install

Pythonラッパーを使う場合は、/usr/lib/python3/dist-packages/pyrealsense2/にパスを通しておく。

$ export PYTHONPATH=$PYTHONPATH:/usr/lib/python3/dist-packages/pyrealsense2/


確認


realsense-viewerを起動してFrame Metadataが正しそうなことを確認する。


できたー!

2020年6月6日土曜日

Jetson NanoでTF-TRTを試す(JetPack 4.4 Developer Preview)

目的


(ずいぶん前になるが)
JetPack 4.4 Developer Previewがリリースされたので、TF-TRT(TensorFlow integration with TensorRT)を使ってFP16に最適化したモデルでの処理時間を計測する。
また、TensorFlow Object Detection APIにも新しいモデル(MnasFPN、MobileDets)が追加されたので試してみる。


まとめ


  • SSDLite MobileNet V3は前回(JetPack4.3 + TF1.15)より多少の改善がみられる。
  • MnasFPNは思った効果(推論時間)は確認できなかった。
  • MobileNet V3がMobileNet V2より有効(推論時間がはやい)ことが確認できた。
  • Object detection modelではMobileDetsが良さそう。


インストール


JetPack4.4、TensorFlow、TF-TRT modelsのインストールを行う。


JetPack


JetPack SDKからJetPack 4.4 Developer PreviewのSDイメージをダウンロードして、SDカードに書き込み。


TensorFlow


TensorFlow on Jetson Platform をもとにTensorFlowをインストールする。
注意することは、バージョンは1.xをインストールすること(TensorFlow Object Detection APIは1.x系のみ対応)。
インストール時は‘tensorflow<2’をつける。
※2020.6.6時点では1.15.2がインストールされる。


TF-TRT Models


TF-TRT Models(TensorFlow/TensorRT Models on Jetson)のリポジトリをcloneし、インストールする。
なお、オリジナルのリポジトリからforkして、変更を加えている。
  • submodule(TensorFlow Model Garden)を更新。
    (MobileDetsを変換したいため)
  • 変換スクリプト、ベンチマークスクリプトを追加



まず、TensorFlow Object Detection APIに必要なパッケージをインストールする。

$ sudo apt install pyton3-tk python3-matplotlib
$ pip3 install --user tf_slim

その後、TF-TRT Modelsのリポジトリをcloneし、インストールスクリプトを実行する。

$ git clone https://github.com/NobuoTsukamoto/tf_trt_models.git
$ cd tf_trt_models/
$ ./install.sh python3

※Python3での実行のみ確認している。


モデルの変換


変換スクリプトを使用して、TF-TRT FP16モデルに変換する。


Object detection model


pre-trained modelの場合は、prefixを指定すれば変換する。
ただ、mobiledetはフォルダの構成が他と違うため手動でダウンロード&変換が必要。
今回の対象モデルは以下。
  • ssdlite_mobilenet_v2 (※)
  • ssdlite_mobilenet_v3_small
  • ssdlite_mobilenet_v3_large
  • ssd_mobilenet_v2_mnasfpn
  • ssdlite_mobiledet_cpu
  • ssdlite_mobiledet_edgetpu
  • ssdlite_mobiledet_dsp
  • ssdlite_mobilenet_edgetpu

変換は以下のように実行

cd examples/detection/
$ python3 convert.py --model=ssdlite_mobilenet_v2_coco
$ python3 convert.py --model=ssdlite_mobilenet_v3_small_coco --force_nms_cpu
$ python3 convert.py --model=ssdlite_mobilenet_v3_large_coco --force_nms_cpu
$ python3 convert.py --model=ssd_mobilenet_v2_mnasfpn_coco --force_nms_cpu

# ssdlite_mobilenet_edgetpuはwgetできないのでリンクをクリックしてダウンロード
$ cd data/
$ tar xf checkpoints_ssdlite_mobilenet_edgetpu_coco_quant.tar.gz
$ cd ../
$ python3 convert.py --path=data/ssdlite_mobilenet_edgetpu_coco_quant/ --force_nms_cpu

$ cd data/
$ wget http://download.tensorflow.org/models/object_detection/ssdlite_mobiledet_cpu_320x320_coco_2020_05_19.tar.gz
$ tar xf ssdlite_mobiledet_cpu_320x320_coco_2020_05_19.tar.gz
$ cd ssdlite_mobiledet_cpu_320x320_coco_2020_05_19
$ mv model.ckpt-400000.data-00000-of-00001  model.ckpt.data-00000-of-00001
$ mv model.ckpt-400000.index model.ckpt.index
$ mv model.ckpt-400000.meta model.ckpt.meta
$ cd ../../
$ python3 convert.py --path=data/ssdlite_mobiledet_cpu_320x320_coco_2020_05_19 --force_nms_cpu

$ cd data/
$ wget http://download.tensorflow.org/models/object_detection/ssdlite_mobiledet_edgetpu_320x320_coco_2020_05_19.tar.gz
$ tar xf ssdlite_mobiledet_edgetpu_320x320_coco_2020_05_19.tar.gz
$ cd data/ssdlite_mobiledet_edgetpu_320x320_coco_2020_05_19/fp32/
$ mv model.ckpt-400000.data-00000-of-00001  model.ckpt.data-00000-of-00001
$ mv model.ckpt-400000.index model.ckpt.index
$ mv model.ckpt-400000.meta model.ckpt.meta
$ cd ../../
$ python3 convert.py --path=data/ssdlite_mobiledet_edgetpu_320x320_coco_2020_05_19/fp32 --force_nms_cpu

$ cd data/
$ wget http://download.tensorflow.org/models/object_detection/ssdlite_mobiledet_dsp_320x320_coco_2020_05_19.tar.gz
$ tar xf ssdlite_mobiledet_dsp_320x320_coco_2020_05_19.tar.gz
$ cd data/ssdlite_mobiledet_dsp_320x320_coco_2020_05_19/fp32/
$ mv model.ckpt-400000.data-00000-of-00001  model.ckpt.data-00000-of-00001
$ mv model.ckpt-400000.index model.ckpt.index
$ mv model.ckpt-400000.meta model.ckpt.meta
$ cd ../
$ python3 convert.py --path=data/ssdlite_mobiledet_dsp_320x320_coco_2020_05_19/fp32  --force_nms_cpu

※前回のブログでもふれた「NMSをCPU実行に書き換えると変換できない」が発生するため、NMSはそのまま(GPUで実行)とする。変換スクリプトに"--force_nms_cpu"を指定する。


Image classification model


こちらも変換スクリプトを用意している。
pre-trained modelのprefixを指定すれば変換する。
今回の対象モデルは以下(Inputはすべて244x244)。
  • mobilenet_v2 (depth_multiplier=0.5)
  • mobilenet_v2 (depth_multiplier=1.0)
  • mobilenet_v2 (depth_multiplier=1.4)
  • mobilenet_v3_small
  • mobilenet_v3_small

$ cd examples/classification/
$ python3 convert.py --model=mobilenet_v2_0p5_224
$ python3 convert.py --model=mobilenet_v2_1p0_224
$ python3 convert.py --model=mobilenet_v2_1p4_224
$ python3 convert.py --model=mobilenet_v3_small
$ python3 convert.py --model=mobilenet_v3_small_224


ベンチマーク


ベンチマーク実施はMax power&CUIモードで実行する。

$ sudo systemctl set-default multi-user.target
$ sudo reboot
$ sudo jetson_clocks

Object detection model


  • ssdlite_mobilenet_v3_small / largeは前回(JetPack4.3+TF1.15)と比べると推論時間が改善している。
  • ssdlite_mobilenet_v2はNMSのCPU実行ができない分、推論時間が遅い。
  • ssdlite_mobilenet_v2_mnasfpnは想定よりかなり遅い。
    CPUに最適化しているからだろうか?
  • 精度(mAP)と推論時間のトータルを考慮するとssdlite_mobiledet_edgetpuが一番。
  • ssdlite_mobilenet_v3_small or largeも使える。

初回の推論時間

Model
Input size
Inference time [ms]
TF-TRT (FP16)
ssdlite_mobilenet_v2300x30013025
ssdlite_mobilenet_v3_small320x3208375
ssdlite_mobilenet_v3_large320x3207366
ssdlite_mobilenet_v2_mnasfpn320x32017502
ssdlite_mobiledet_cpu320x3208117
ssdlite_mobiledet_edgetpu320x3207332
ssdlite_mobiledet_dsp320x3208203
ssdlite_mobilenet_edgetpu320x32023643


2回目以降の100回の推論の平均時間

Model
Input size
Inference time [ms]
TF-TRT (FP16)
ssdlite_mobilenet_v2300x30088
ssdlite_mobilenet_v3_small320x32056
ssdlite_mobilenet_v3_large320x32068
ssdlite_mobilenet_v2_mnasfpn320x320223
ssdlite_mobiledet_cpu320x32073
ssdlite_mobiledet_edgetpu320x32070
ssdlite_mobiledet_dsp320x32080
ssdlite_mobilenet_edgetpu320x320186



Image classification model


  • mobilenet_v2 (depth_multiplier=0.5)とmobilenet_v3_smallがほぼ同等の推論時間。
  • mobilenet_v2 (depth_multiplier=1.0)とmobilenet_v3_largeがほぼ同等の推論時間。
  • FP32での精度を考えるとmobilenet_v3を使うのが良いかも?


初回の推論時間

Model
Input size
Inference time [ms]
TF-TRT (FP16)
mobilenet_v2_0.5_224224x2243477
mobilenet_v2_1.0_224224x22411354
mobilenet_v2_1.4_224224x2249356
mobilenet_v3_small_224224x2244187
mobilenet_v3_large_224224x2245387


2回目以降の100回の推論の平均時間

Model
Input size
Inference time [ms]
TF-TRT (FP16)
mobilenet_v2_0.5_224224x22410
mobilenet_v2_1.0_224224x22416
mobilenet_v2_1.4_224224x22423
mobilenet_v3_small_224224x22410
mobilenet_v3_large_224224x22417



最後に


Jetson Nano(JetPack 4.4 Developer Preview)でTF-TRT モデルの推論時間をベンチマークしてみた。

結果からMobileNet V3ベースまたは、SSDLite MobileDets Edge TPUが良い結果に思える。
FP16にした場合の制度の低下がどれぐらいかは気になるところではあるが、FP32とほぼ同等(の低下)と考えれば、MobileNet V3、MobileDetsは良い選択肢になると思う。
(あとはどのぐらい学習しやすさによるか?)

Object detection modelはモバイルCPU、Edge TPU、DSPに特化したモデルが登場した(MnasFpn、MobileDets)。
これらのモデルの中にはJetson NanoのGPUではそれほど良い結果は得られなかった。
これはモデルがHWに特化していることも要因の一つに思える。

あとは、Efficientnet、EfficientDetも試してみたい。

2020年2月29日土曜日

Jetson NanoでTF-TRTを試す(JetPack4.3)

目的


(ずいぶん前になるが)JetPack4.3がリリースされたので、TF-TRT(TensorFlow integration with TensorRT)を使ってFP16に最適化したモデルでの処理時間を計測する。


動機


前回のブログ「Jetson NanoでTF-TRTを試す(Object detection)」で、よくわからない事象として「SSDLite MobileNet v3 LargeのPre-trained Modelで検出ができない」をあげていた。これはtensorflow/modelsにIssueを報告していたのだけど、アップされたmodelに問題があったとのことで新しいmodelがPRされた(2020.2.29時点ではまだマージされていない)。

問題が解決したのと、JetPackがアップデートされたので、再度、処理時間を計測しようと思った。


まとめ


  • SSDLite MobileNet v3 large / smallはJetpack 4.2 + TF1.14と比べ処理時間が遅くなっている。
  • MobileNet v3以外のDetection model(v1, v2など)は、NonMaxSupperssionをCPU実行に書き換えるとTF-TRT FP16のモデル変換に失敗する。
  • Classification model(MobileNet v1, v2)はJetPack 4.2 + TF1.14と比べ処理時間が若干だが早くなっている。

早くなっているね!で終わると思っていたのだが、つぶやいたとおりいろいろとあった。



環境


今回、3つのバージョンで計測した。
  • JetPack 4.2.2 + TF1.14
    JetPack: 4.2.2 (r32.2.1)
    TensorRT: 5.1.6
    TensorFlow: 1.14.0+nv19.10
    Python: 3.6.9
  • JetPack4.2.2 + TF1.15
    JetPack: 4.2.2 (r32.2.1)
    TensorRT: 5.1.6
    TensorFlow: 1.15.0+nv19.11
    Python: 3.6.9
  • JetPack4.3 + TF1.15
    JetPack: 4.3 (r32.3.1)
    TensorRT: 6.0.1
    TensorFlow: 1.15.0+nv20.1
    Python: 3.6.9

モデルの生成


TF-TRT FP16 のモデル変換は前回と同様、本家よりForkしたリポジトリを使用する。



なお、SSDLite MobileNet v3 large/smallのpre-trained modelのリンクは変更済みである。モデルの変換および、ベンチマークの際は、CUIモード&jetson_clocksで実行している。


Detection modelのベンチマーク


今回は対象を以下のモデルに絞って行った。
  • ssdlite_mobilenet_v2_coco
  • ssdlite_mobilenet_v3_small_coco
  • ssdlite_mobilenet_v3_large

TF-TRT FP16への変換、計測方法は前回のブログと同様である。
 NonMaxSupperssion(NMS)をCPU実行に書き換えて、TF-TRT FP16に変換。変換後、ベンチマーク用のスクリプト(初回の推論を除く100回の平均)で計測した。

JetPack4.2.2+TF1.15、JetPack4.3+TF1.15の場合、ssdlite_mobilenet_v2_coco モデルがモデル変換時に「Aborted (core dumped) 」となり失敗する。

2020-02-19 18:42:53.932561: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1304] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 1208 MB memory) -> physical GPU (device: 0, name: NVIDIA Tegra X1, pci bus id: 0000:00:00.0, compute capability: 5.3)
2020-02-19 18:43:21.378537: I tensorflow/compiler/tf2tensorrt/segment/segment.cc:460] There are 1379 ops of 31 different types in the graph that are not converted to TensorRT: Range, Sum, GreaterEqual, Where, Select, ConcatV2, Less, Fill, ExpandDims, Unpack, GatherV2, NoOp, TopKV2, Cast, Slice, Transpose, Pad, Placeholder, ResizeBilinear, Squeeze, Mul, Reshape, AddV2, Pack, Identity, NonMaxSuppressionV5, Shape, Greater, Sub, Minimum, StridedSlice, (For more information see https://docs.nvidia.com/deeplearning/frameworks/tf-trt-user-guide/index.html#supported-ops).
2020-02-19 18:43:22.630756: I tensorflow/compiler/tf2tensorrt/convert/convert_graph.cc:633] Number of TensorRT candidate segments: 2
2020-02-19 18:43:22.784932: F tensorflow/core/util/device_name_utils.cc:92] Check failed: IsJobName(job) 
Aborted (core dumped)

これは、この方のブログ「JetPack-4.3 for Jetson Nano」でも同様の事象が発生するとあり、NMSをCPU実行に書き換えることをやめると変換に成功するとあった(実際に成功する)。ssdlite_mobilenet_v3は変換に成功するため、単純にNMSのCPU実行の書き換えが問題でないと思われる。

このため、NMSを書き換えない場合も計測した。


NMSをCPU実行に書き換えた場合


Detection model
(force_nms_cpu=True)
Inference [ms]
JetPack4.2.2+TF1.14JetPack4.2.2+TF1.15JetPack4.3+
TF1.15
ssdlite_mobilenet_v2_coco_fp16.pb53.62--
ssdlite_mobilenet_v3_small_coco_fp1648.8964.9259.13
ssdlite_mobilenet_v3_large_coco_fp1666.0180.5073.45
-: モデル変換時にAborted (core dumped) が発生



NMSを書き換えない場合


Detection model
(force_nms_cpu=False)
Inference [ms]
JetPack4.2.2+TF1.14JetPack4.2.2+TF1.15JetPack4.3+
TF1.15
ssdlite_mobilenet_v2_coco_fp16.pb68.3978.2388.34
ssdlite_mobilenet_v3_small_coco_fp1699.22110.26119.78
ssdlite_mobilenet_v3_large_coco_fp16111.26120.45123.28



ベンチマーク結果


JetPack4.3 + TF1.15は
  • TF-TRT FP16 に変換できるモデルに限りがある。
    今のところはSSDLite MobileNet v3 small / large(SSDLite MobileNet EdgeTPU)が確認できている。
    (おそらく、モデルを学習した時のTensorFlowのバージョンが関係する?)
  • SSDLite MobileNet v3 small / largeは
    JetPack4.2.2 + TF1.14と比べ、推論の処理時間が遅くなっている。
    JetPack4.2.2 + TF1.15と比べ、推論の処理時間は早くなっている。
  • NMSのCPU実行への書き換えを行わなければモデルの変換に成功するが、推論時間は長くなってしまう(ためおすすめではない)。
  • (NMSになにかありそう???)

Classification modelのベンチマーク


こちらも、以下のモデルでベンチマークを行った。
  • mobilenet_v1_1.0_224
  • mobilenet_v2_1.0_224

(以前のブログ「Jetson NanoでTF-TRTを試す(Image Classification)その2」)と同様、TF-TRT FP16に変換。変換後、ベンチマーク用のスクリプト(初回の推論を除く100回の平均)で計測した。

こちらは、変換時に問題も発生することはなく、JetPack4.3 + TF1.15で処理時間が早くなっていることが確認できた。

Classification model
Inference [ms]
JetPack4.2.2+TF1.14JetPack4.2.2+TF1.15JetPack4.3+
TF1.15
mobilenet_v1_1.0_22423.6822.7421.58
mobilenet_v2_1.0_22427.4526.6924.95



2019年11月24日日曜日

Jetson NanoでTF-TRTを試す(Object detection)

目的


Object detectionのモデルについて、TF-TRT(TensorFlow integration with TensorRT)を使ってFP16に最適化したモデルを生成し、Jetson Nanoでどの程度最適化の効果ががあるのかを確認する。


動機


Jetson NanoでTF-TRTを試す(Image Classification)その2では、モデルの生成時、 Relu6(x )を relu(x) - relu(x - 6)に置き換えをやめることにより、処理時間が短縮されることを確認した。
また、2019年10月にSSDLite MobileNet V3のモデルが公開された。
このため、Object detectionのモデルについて、TF−TRTの変換および、効果を確認する。


まとめ

  • 前回と同様、Relu6の置き換えを行うことで推論の処理時間短縮になることを確認した。
  • 本家リポジトリが行っているGraphの書き換え(NonMaxSuppressionのCPU実行)が推論の処理時間の短縮になっていることを確認した。
  • Jetson Nanoでは、SSDLite MobileNet V3 Large、Smallは、精度(mAP)が同等のモデルと比べた場合、推論の処理時間が遅いことがわかった。
  • (個人的には)SSD MobileNet V1 FPNが動作することに驚いた。
    ターゲットにもよるがこれは使える可能性がある。


環境


2019.11.23時点の環境で確認。

  • JetPack 4.2.2 (r32.2.1)
  • TensorRT: 5.1.6
  • TensorFlow: 1.14.0+nv19.10
  • Python:3.6.8


モデルの作成


変換用のスクリプトは、本家よりForkしたリポジトリにアップしている。



今回は、pre-trained models(Tensorflow detection model zoo)をダウンロードしてFP16のモデルへの変換と、自前で学習したモデルの変換を行うようにした。

インストール方法については、本家と同様の手順である。
モデルの変換および、ベンチマークの際は、CUIモード&jetson_clocksで実行している。


TF-TRTモデルの変換


本家リポジトリでは、チェックポイントからGraphを作成する際に大きく2つ変更を行っている。これが最終的な推論の速度にも影響している。

  • Relu6(x )を relu(x) - relu(x - 6)に置き換え
    これは、前回と同様。
    本家のリポジトリでは置き換えが有効になっている。
    現在はRelu6のままTF-TRTモデルに変換したほうが推論の処理時間の短縮につながるため、置き換えをしない。
  • NonMaxSuppressionをCPUで実行するように書き換え
    "Optimize NVIDIA GPU performance for efficient model inference"に詳細が解説されているが、NonMaxSupperssionはGPUで実行するコストが高い。
    (GPUに対応していないOpeがCPUで実行されるため、CPU-GPU間でデータ転送を頻繁に行ってしまう。制御文が含まれるOpeはGPUでの実行が遅い。)
    本家のリポジトリではNonMaxSuppressionをCPUで実行するようにGraphを書き換えている。今回は書き換えを行う・行わないでの違いを確認する。

TF-TRTモデルに変換する際のTrtGraphConverterのパラメータは前回と同様である。
    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)



Pre-trained modelsの変換


リポジトリをClone後、"tf_trt_models/examples/detection"ディレクトリに移動して変換用スクリプトを実行する。

python3 convert.py --model="pre-trained model prefix" --output="path to output dir"

--modelで変換したいpre-trained modelを指定する。サポートしているpre-trained modelsは、こちらを参照。
--outputにTF-TRTで変換したFP16のモデルが出力される。モデルのファイル名は"model_frozen_16.pb"である。


自前で学習したモデルの変換


TensorFlow Object detection APIで学習したモデルを変換する。学習後、Exporting a trained model for inferenceに従って、モデルをエクスポートする。
エクスポート後のディレクトリ(model.ckpt.*、pipeline.configファイルを含む)をJetson Nanoにコピーする。

python3 convert.py --path="path to export model dir" --output="path to output dir"

--pathフラグでコピーしたディレクトリのパスを指定する。


ベンチマーク


ベンチマークスクリプトはここ。
初回の推論と、2回目以降の推論100回の平均をベンチマークする。

なお、画像サイズはモデルのinputと合わせるように推論前にリサイズしている(推論の時間に含めてない)。

対象のモデルはpre-trained models(Tensorflow detection model zoo)で公開されているSSDのモデルとする。

  • ssd_mobilenet_v1_0.75_depth_coco
  • ssd_mobilenet_v1_coco
  • ssd_mobilenet_v1_fpn_coco
  • ssdlite_mobilenet_v2_coco 
  • ssd_mobilenet_v2_coco
  • ssd_mobilenet_v3_small_coco
  • ssd_mobilenet_v3_large_coco
  • ssd_inception_v2_coco
  • ssd_resnet_50_fpn_coco


モデルサイズ


前回でも判明していたが、モデルサイズは変換後(FP16)のほうがサイズが大きくなる。
なお、ssd_inception_v2、ssd_resnet_50_fpnは変換ができなかった(変換中にKilledとなってしまう)。おそらく、メモリが不足していると思われる。

Model
モデルサイズ [MB]
FP32FP16
ssd_mobilenet_v1_07.5_depth1926
ssd_mobilenet_v12842
ssd_mobilenet_v1_fpn130135
ssdlite_mobilenet_v21930
ssd_mobilenet_v267100
ssdlite_mobilenet_v3_small813
ssdlite_mobilenet_v3_large1321
ssd_inception_v2980
ssd_resnet_50_fpn_coco1290



Jetson Nanoでの初回の推論


変換前(FP32)、変換後(FP16)について、NonMaxSupperssionをCPUで実行する・市しないで比較した。
表・グラフ中で

  • FP32 nms_gpu
    変換前かつ、NonMaxSupperssionの書き換えを行わない
  • FP32nms_cpu
    変換前かつ、NonMaxSupperssionをCPU実行に書き換え
  • FP16 nms_gpu
    FP16に変換かつ、NonMaxSupperssionの書き換えを行わない
  • FP32nms_cpu
    FP16に変換かつ、NonMaxSupperssionをCPU実行に書き換え
である。

結果から、
  • FP32よりFP16のモデルのほうが処理時間が短くなっている。
  • 初回の推論ではNonMaxSupperssionの効果は確認できない。
ことがわかる。


Model
Inference time [ms]
FP32 nms_gpuFP32 nms_cpuFP16 nms_gpuFP16 nms_cpu
ssd_mobilenet_v1_0.75_depth30694301951042010076
ssd_mobilenet_v1377183852873279294
ssd_mobilenet_v1_fpn1023241052941863021492
ssd_mobilenet_v247367661181154516043
ssdlite_mobilenet_v282924145826152566360
ssdlite_mobilenet_v3_small246232439298458208
ssdlite_mobilenet_v3_large380773842550125431
ssd_inception_v20000
ssd_resnet_50_fpn0000

※ssd_inception_v2, ssd_resnet_50_fpnは実行時にKilledとなってしまう。

結果をグラフ化してみる。
ssdlite_mobilenet_v2のFP32 nms_gpuの場合、突出して処理時間がかかっているため、対数目盛とした。また、ssd_inception_v2, ssd_resnet_50_fpnは除く。



Jetson Nanoでの2回目以降の推論


2回目以降の推論の処理時間を比較する。

  • FP32よりFP16のモデルのほうが処理時間が短くなっている。
  • NonMaxSupperssionをCPU実行に書き換えたほうが処理時間が短くなっている(ssd_mobilenet_v1_fpnのFP32 は除く)。
  • ssdslite_mobilenet_v3_smallは、ssd_mobilenet_v1_0.75_depthよりも処理時間がかかり、ssd_mobilenet_v1とほぼ同等の処理時間である(ssd_mobilenet_v1_0.75_depthとはmAPがほぼ同等)。
  • ssdlite_mobilenet_v3_largeは、ssdlite_mobilenet_v2よりも処理時間がかかる(ssdlite_mobilenet_v2とはmAPがほぼ同等)。
ことが確認できる。

MobileNet V3の論文では、MobileNet V2より早い処理時間となっている。
もともと論文にもあるとおり、MobileNet V3はモバイルCPU向けであり、
  • TF-Liteモデルでのベンチマークであること。
    (6.1.2 Measurement setupを参照)
  • TF-LiteでH-swishのOpeを最適化していること。
    (6.1.2 Measurement setupおよび、Figure 9を参照)

から、GPU実行やTF-TRTのOpeの最適化がないことが影響していると考えられる(後述も参照。このため、今後Opeの最適化があれば十分早くなる可能性あり?)。ただ、これはあくまでも私感であり、間違っている可能性がある。

Model
Inference time [ms]
FP32 nms_gpuFP32 nms_cpuFP16 nms_gpuFP16 nms_cpu
ssd_mobilenet_v1_0.75_depth83545742
ssd_mobilenet_v199726348
ssd_mobilenet_v1_fpn8351146474460
ssd_mobilenet_v21031836955
ssdlite_mobilenet_v216066757252
ssdlite_mobilenet_v3_small119599647
ssdlite_mobilenet_v3_large1298310964
ssd_inception_v20000
ssd_resnet_50_fpn0000

※ssd_inception_v2, ssd_resnet_50_fpnは実行時にKilledとなってしまう。

結果をグラフ化してみる。
ssdlite_mobilenet_v2のFP32 nms_gpuの場合、突出して処理時間がかかっているため、対数目盛とした。また、ssd_inception_v2, ssd_resnet_50_fpnは除く。

もう少しわかりやすいように、ssdlite_mobilenet_v2のFP32 nms_gpuを除いたものも掲載する。

ssdlite_mobilenet_v2のFP32 nms_gpuの処理時間をを除いた


問題点・不明な事象...


今回のベンチマークを行うにあたり、2つのよくわからない事象にあたった。。。書き残しておく(これは筆者の手順ミスの可能性もあるので注意)。


SSDLite MobileNet v3 LargeのPre-trained Modelで検出ができない


これは、Jetson NanoやTF-TRTの問題ではない。
Pre-trainedのモデル(ssd_mobilenet_v3_large_coco)のチェックポイントからモデルをfreeze graph(エクスポート)するしたもを利用するとなぜかオブジェクトを検出しない。。。
ssd_mobilenet_v3_small_cocoはうまくいく(オブジェクトを検出する)。
エクスポートする手順は変わっていないはずなのだが?


MobileNet V3 LargeとSmallの違いはネットワークぐらいで、使っているOpeは同じだと思っていたので、理由がさっぱりわからない。。。

なお、Google colabで再現するnotebookを作成して試してみても再現する(TensorFlowのバージョンは1.12, 1.14, 1.15で確認)。


自分で再学習した場合は、オブジェクトを検出するようになる。
再学習したチェックポイントは、一応、公開しておく(ただし、十分学習できていない。また、都合により削除する場合あるので注意)。


TF-TRTで変換したモデルが再現できない(SSDLite MobileNet V3 Large、Small)


今回、SSDLite MobileNet V3 Large、SmallのTF-TRTモデルの変換を行っていた中で、一度だけFP16のモデルの変換に成功?したのか、推論の処理時間が早くなったモデルが生成できた。

下の表のFP16 nms_cpu(最速?)の列は、何故か推論の処理時間が早くなったモデルである。FP16 nms_cpu(ベンチ)の列は、ベンチマークで記載したものである。


Model
Input size
Inference time [ms]
FP16 nms_cpu
(最速?)
FP16 nms_cpu
(ベンチ)
ssdlite_mobilenet_v3_small320×3203347
ssdlite_mobilenet_v3_large320×3205164


  • ssdlite_mobilenet_v3_smallはmAPが同等のssd_mobilenet_v1よりも早い。
  • ssdlite_mobilenet_v3_largeはssdlite_mobilenet_v2とほぼ同じ。

その後、何度か再現(モデルの変換)を試みたが再現できなかった。
当初、モデルの変換の際に誤って違うモデルを選んだのかと思ったのだが、モデルの構造をみると、

TRTEngineOpのinput_shapeが320×320となっている。MobileNet V3以外でinputが320×320はないため間違いとは思えない。。。

TrtGraphConverterのパラメータをいじっても再現しない。もし、これが再現できるのであれば、SSDLite MobileNet V3は、推論の処理時間とmAPをみても十分使えるものになると考えられる。

こssdlite_mobilenet_v3_smallのモデルについて公開してこうと思う(筆者の都合により削除する場合あるので注意)。


最後に


TF-TRTについてObject detectionモデルの変換についてまとめてみた。とりあえず、Image classification、Object detectionのモデルについてはやってみた。今後は、新しいモデルの登場、TF-TRTのバージョンアップがあればやってみようと思う。