[Amazon SageMaker] DLR(Deep Learning Runtime)の最新バージョン(1.4.0)をJetson Nanoで使用してみました
1 はじめに
CX事業本部の平内(SIN)です。
Jetson nano + Sagemaker Neoでの推論は、今まで色々試しているのですが、最新版では少し要領が変わっている部分もあり、ちょっと手間取ったので、改めて、今回作業した手順を纏めさせて頂きました。
2 JetPack 4.2
Jetpackの最新は4.4となってますが、2020/10/17現在、手元では、ライブラリの依存関係からDLRが動作できなかったため、アーカイブから4.2を使用しました。
https://developer.nvidia.com/jetpack-4_2
3 DLR 1.4
SageMaker Neoでコンパイルされたモデルで推論するためには、DLRが必要です。
参考:https://github.com/neo-ai/neo-ai-dlr
x86_64CPU向けは、pipで最新リリースのインストールが可能になっていますが、GPUで使用する場合などは、別途インストールが必要です。
DLRのインストールを案内するページでは、ビルド済みのバイナリリリース(1.3)も公開されていますが、今回は、最新版をコンパイルすることにしました。
参考:Installing DLR
コンパイルの手順については、以下のとおりです。
参考:Building for NVIDIA GPU on Jetson Devices
(1) pip及び、setuptools
最後に使用するインストールスクリプト(python/setup.py)で、「No module named 'setuptools'」となるので、予め、pip及び、setuptoolsをインストールします。
$ sudo apt-get update $ sudo apt-get install python3-pip $ pip3 install setuptools
(2) cmake 3.17.2
DLRの構築には、cmake 3.13以降が必要とのことで、最初にcmakeをインストールします。
$ sudo apt-get install libssl-dev $ wget https://github.com/Kitware/CMake/releases/download/v3.17.2/cmake-3.17.2.tar.gz $ tar xvf cmake-3.17.2.tar.gz $ cd cmake-3.17.2 $ ./bootstrap $ make -j4 $ sudo make install $ cmake --version cmake version 3.17.2
(3) DLR 1.4
DLRは、最新版をgitからダウンロードしてコンパイル・インストールします。
$ git clone --recursive https://github.com/neo-ai/neo-ai-dlr $ cd neo-ai-dlr $ mkdir build $ cd build $ cmake .. -DUSE_CUDA=ON -DUSE_CUDNN=ON -DUSE_TENSORRT=ON $ make -j4 $ cd ../python $ python3 setup.py install --user
(4) 確認
python3でimportして、バージョンを確認しています。
Ver1.4では、パフォーマンスの向上のためのメトリックを収集に関する同意を求めるメッセージと、それを処理する案内が表示されるようになっています。
nvidia@nvidia-desktop:~$ python3 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 dlr CALL HOME FEATURE ENABLED You acknowledge and agree that DLR collects the following metrics to help improve its performance. By default, Amazon will collect and store the following information from your device: record_type: <enum, internal record status, such as model_loaded, model_>, arch: <string, platform architecture, eg 64bit>, osname: <string, platform os name, eg. Linux>, uuid: <string, one-way non-identifable hashed mac address, eg. 8fb35b79f7c7aa2f86afbcb231b1ba6e>, dist: <string, distribution of os, eg. Ubuntu 16.04 xenial>, machine: <string, retuns the machine type, eg. x86_64 or i386>, model: <string, one-way non-identifable hashed model name, eg. 36f613e00f707dbe53a64b1d9625ae7d> If you wish to opt-out of this data collection feature, please follow the steps below: 1. Disable it with through code: from dlr.counter.phone_home import PhoneHome PhoneHome.disable_feature() 2. Or, create a config file, ccm_config.json inside your DLR target directory path, i.e. python3.6/site-packages/dlr/counter/ccm_config.json. Then added below format content in it, {"enable_phone_home" : false} 3. Restart DLR application. 4. Validate this feature is disabled by verifying this notification is no longer displayed, or programmatically with following command: from dlr.counter.phone_home import PhoneHome PhoneHome.is_enabled() # false as disabled >>> print(dlr.__version__) 1.4.0
4 SWAP
使用するモデルによりますが、今回使用したモデルでは、デフォルト(メモリ4G SWAP 2G)では、不足して動作できないため、6GByteの /swapfile を作成し、SWAPを拡張しました。
$ sudo dd if=/dev/zero of=/swapfile bs=1G count=6 $ sudo swapoff -a $ sudo mkswap /swapfile $ sudo swapon /swapfile $ free -h total used free shared buff/cache available Mem: 3.9G 1.3G 1.4G 48M 1.2G 2.3G Swap: 6.0G 0B 6.0G
5 Sagemaker Neo
元となるモデルは、Amazon SageMakerの組み込みアルゴリズム(Image Classification)で作成したものです。
SageMaker Neoで、以前に作成したモデルは、DLR 1.4では、そのまま利用できなかったため、コンパイルし直しました。
データ入力設定は、{"data":[1,3,224,224]} 、機械学習フレームワークは、MXNet、ターゲットデバイスは、jetson_nanoを設定しています。
作成されたモデルのファイル構造は、以下のとおりでした。 以前のものとは、ファイル数が変わっています。(dlr.h及び、libdlr.soが増えている)
6 推論動作の確認
ブランク画像で問題なく推論できるかを確認します。Neoで作成したモデルは、解凍して./modelの下に配置しています。
. ├── model │ ├── compiled.meta │ ├── compiled_model.json │ ├── compiled.params │ ├── compiled.so │ ├── dlr.h │ ├── libdlr.so │ └── model-shapes.json └── run.py
下記のコードを実行することで動作の確認ができます。
PhoneHome.disable_feature()は、メトリック収集に関する記述です。
また、TVM_TENSORRT_CACHE_DIR=',' の指定でカレントディレクトリにキャッシュを作成します。
以下のコードでは、無効化されていますが、TVM_TENSORRT_USE_FP16='1' を有効にすると、16ビット浮動小数点精度に変換し、高速化が図れます。
参考:Additional Options for TensorRT Optimized Models
run.py
import numpy as np import time import os import dlr from dlr.counter.phone_home import PhoneHome PhoneHome.disable_feature() os.environ['TVM_TENSORRT_CACHE_DIR'] = '.' # os.environ['TVM_TENSORRT_USE_FP16'] = '1' model = dlr.DLRModel('model/', 'gpu', 0) img = np.random.rand(1, 3, 224, 224) for _ in range(10): start = time.time() model.run({'data': img}) processing_time = time.time() - start print("{:.2f} sec".format(processing_time))
以下のような出力であれば問題なしです。(モデルがキャッシュされていない場合、1回目の推論にかなり時間がかかります)
$ python3 run.py 2020-10-17 14:10:29,074 INFO Found libdlr.so in model artifact. Using dlr from model/libdlr.so [14:11:08] /home/nvidia/neo-ai-dlr/3rdparty/tvm/src/runtime/contrib/tensorrt/tensorrt_module.cc:261: Loading cached TensorRT engine from ./8507350289998171460.plan [14:11:29] /home/nvidia/neo-ai-dlr/src/dlr_tvm.cc:62: Loading metadata file: model/compiled.meta 0.71 sec 0.17 sec 0.17 sec 0.17 sec 0.17 sec 0.17 sec 0.17 sec 0.17 sec 0.17 sec 0.17 sec
キャシュが有効になると、xxx.meta及びxxx.planファイルができています。
. ├── 8507350289998171460.meta ├── 8507350289998171460.plan ├── model │ ├── compiled.meta │ ├── compiled_model.json │ ├── compiled.params │ ├── compiled.so │ ├── dlr.h │ ├── libdlr.so │ └── model-shapes.json └── run.py
ちなみに、下記は、os.environ['TVM_TENSORRT_USE_FP16'] = '1' を有効にして、実行した1回目(キャッシュなし)と2回目のログです。推論自体は、倍近く早くなってるようです。(0.17sec -> 0.1sec)
$ python3 run.py 2020-10-17 14:13:28,225 INFO Found libdlr.so in model artifact. Using dlr from model/libdlr.so [14:14:07] /home/nvidia/neo-ai-dlr/src/dlr_tvm.cc:62: Loading metadata file: model/compiled.meta [14:14:10] /home/nvidia/neo-ai-dlr/3rdparty/tvm/src/runtime/contrib/tensorrt/tensorrt_module.cc:80: Building new TensorRT engine for subgraph tensorrt_0 [16:31:41] /home/nvidia/neo-ai-dlr/3rdparty/tvm/src/runtime/contrib/tensorrt/tensorrt_module.cc:296: Caching TensorRT engine to ./8507350289998171460_fp16.plan [16:31:57] /home/nvidia/neo-ai-dlr/3rdparty/tvm/src/runtime/contrib/tensorrt/tensorrt_module.cc:90: Finished building TensorRT engine for subgraph tensorrt_0 8269.84 sec 0.20 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec
$ python3 run.py 2020-10-17 16:32:24,707 INFO Found libdlr.so in model artifact. Using dlr from model/libdlr.so [16:33:04] /home/nvidia/neo-ai-dlr/3rdparty/tvm/src/runtime/contrib/tensorrt/tensorrt_module.cc:261: Loading cached TensorRT engine from ./8507350289998171460_fp16.plan [16:33:21] /home/nvidia/neo-ai-dlr/src/dlr_tvm.cc:62: Loading metadata file: model/compiled.meta 0.28 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec 0.10 sec
F16のキャッシュは、別に作られています。
$ ls -la total 418668 drwxrwxr-x 3 nvidia nvidia 4096 10月 17 16:31 . drwxr-xr-x 19 nvidia nvidia 4096 10月 17 13:12 .. -rw-rw-r-- 1 nvidia nvidia 111 10月 17 16:31 8507350289998171460_fp16.meta -rw-rw-r-- 1 nvidia nvidia 194759992 10月 17 16:31 8507350289998171460_fp16.plan -rw-rw-r-- 1 nvidia nvidia 111 10月 17 13:34 8507350289998171460.meta -rw-rw-r-- 1 nvidia nvidia 233920904 10月 17 13:34 8507350289998171460.plan drwxrwxr-x 2 nvidia nvidia 4096 10月 17 12:55 model -rw-r--r-- 1 nvidia nvidia 455 10月 17 14:13 run.py
7 Webカメラの画像推論
最後に、Webカメラの動画を約10FPSで推論しているサンプルコードです。
import cv2 import numpy as np import dlr import time import os from dlr.counter.phone_home import PhoneHome PhoneHome.disable_feature() os.environ['TVM_TENSORRT_CACHE_DIR'] = '.' os.environ['TVM_TENSORRT_USE_FP16'] = '1' SHAPE = 224 MODEL_PATH = './model' CLASSES = ["ポリッピー(GREEN)","OREO","カントリーマム","ポリッピー(RED)","柿の種(わさび)","通のとうもろこし","CHEDDER_CHEESE","ピーナッツ","ストーンチョコ","PRETZEL(YELLOW)","海味鮮","柿の種","カラフルチョコ","フルグラ(BROWN)","NOIR","BANANA(BLOWN)","チーズあられ","俺のおやつ","PRIME","CRATZ(RED)","CRATZ(GREEN)","揚一番","ポリッピー(YELLOW)","こつぶっこ","アスパラガス","海苔ピーパック","いちご","梅しそチーズあられ","通のえだ豆","柿の種(梅しそ)","PRETZEL(BLACK)","辛子明太子","CRATZ(ORANGE)","チョコメリゼ","フライドポテト(じゃがバター味)","BANANA(BLUE)","でん六豆","パズル","フルグラ(RED)","PRETZEL(GREEN)","フライドポテト(しお味)",] DEVICE_ID = 0 WIDTH = 800 HEIGHT = 600 GST_STR = ('v4l2src device=/dev/video{} ! video/x-raw, width=(int){}, height=(int){} ! videoconvert ! appsink').format(DEVICE_ID, WIDTH, HEIGHT) def main(): PhoneHome.disable_feature() cap = cv2.VideoCapture(GST_STR, cv2.CAP_GSTREAMER) model = dlr.DLRModel('model/', 'gpu', 0) while(True): _, frame = cap.read() if(frame is None): continue frame = frame[0 : int(HEIGHT), 0 : int(HEIGHT)] # 横長の長方形 => 正方形 # 入力画像生成 img = cv2.resize(frame, dsize=(SHAPE, SHAPE)) # height * height => 224 * 224 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR => RGB img = img.transpose((2, 0, 1)) # 224,244,3 => 3,224,224 img = img[np.newaxis, :] # 3,224,224 => 1,3,224,224 print("img.shape: {}".format(img.shape)) # 推論 start = time.time() # 時間計測 out = model.run({'data': img}) processing_time = time.time() - start print(processing_time) # 表示 prob = np.max(out) index = np.argmax(out[0]) print("{} {:.2f} {:.2f}sec".format(CLASSES[index], prob, processing_time)) main()
8 最後に
今回は、DLR(Deep Learning Runtime)の最新バージョン(1.4.0)をJetson Nanoで使用してみました。
キャッシュする時に、非常に時間がかかりますが、2回目以降は、起動自体も以前のものより早くなっている気がしました。(すいません、個人的体感です)
なお、DLRでは、モデルのバージョン互換が必要なので、以前に作成したモデルは注意が必要です。