エッジでAIを動作させる仕組みが増えてきました。
AI動作が可能なエッジ機器としてはAI組込済のエッジ機器、RaspberryPi、FPGA、RISC-Vチップなど色々と選択肢があります。但し、現状では深層学習処理をしようとするとパフォーマンスの問題でGPUが前提となるケースがあります。
このケースに限ってはNVIDIA製のエッジ機器であるJetsonシリーズの使用が前提となります。
今回はNVIDIA製のエッジ機器である「Jetson Nano」上でDeepstreamを使ってストリーム処理で物体検出させる手順を記事にしたいと思います。
Jetsonとは何か?
Jetsonとは、NVIDIA社が製造・販売するGPUを備えた画像認識、機械学習や自動運転等を想定した組込み用のARMベースのシングルボードコンピュータシリーズです。
特徴としてはCUDAを搭載しているため、CUDAに対応したAIフレームワーク(Pytorch、TensorFlow、Chainerなど)を動作させることが可能です。
OSはUbuntuになります。
シリーズやハードウェア詳細については以下公式ページがよくまとまっているので参照ください。
Jetsonシリーズについて
Deepstreamとは何か?
Deepstreamとは、
「NVIDIA社が提供するGPU上で、gstreamer と TensorRT の2つの技術をメインに使用してAIを組み込んだストリーム処理を可能にするプラグイン・低レベルAPIをまとめたSDK」
です。
対象となるGPUはエッジサイドはJetson上のGPU(Tegra)、およびサーバサイドはTeslaシリーズとなります。
Deepstreamの基本的な構成は以下のようになります。
大きくはパイプラインを構築するための独自プラグイン(Gst-nv~と命名されているプラグインがNVIDIA独自プラグイン)とプラグインを作成するための低レベルAPI群を提供します。
プラグインの特徴的な部分としては、メディアストリーム処理に特化したGst-nvmultistreamtilerやGst-nvdsosd等のプラグインとAI処理に特化したGst-nvstreammuxやGst-nvinfer等のプラグインが用意されている点です。
AI処理についてはGst-nvinferプラグインをパイプライン上に最大で2つ設定可能なため、例えば検出したものを更に分類するなど2段階のAI推論処理を構築することが可能となっています。
更にDeepstreamの面白いところとしては、以下のように1台のJetson上で複数ストリームを処理することができる点です。
Deepstreamのセットアップ方法
Deepstreamのセットアップについては、Qiitaなど見ずに公式ドキュメントを元にするのが近道です。
Deepstreamを支える技術
Deepstreamの技術ベースになっているGstreamerとTensorRTについて以下では簡単に説明します。
Gstreamerとは何か?
Gstreamerとは、
ビデオ編集ソフト、メディアプレーヤなどのストリーミングメディアアプリケーションを作成するためのフリーのフレームワーク
です。
マルチメディア系のデータをストリーム処理するためのパイプライン制御に特化したフレームワークと言えます。
パイプライン制御についてはいくつかの前提基礎が必要となるため、Deepstreamを使いこなすためにはgstreamerの理解が必要となります。
日本語マニュアルの「I. GStreamer について」を一読することをおススメします。
私はGstreamerに関する基礎知識がなかったために、独自のパイプラインを構築する際にソースコードの理解に苦労しました。
TensorRTとは何か?
TensorRTとは、
NVIDIA製の高性能ディープラーニング推論最適化の実行ライブラリ。低レイテンシ・高スループットのAI推論処理が可能になる。
です。
TensorRT では以下のような最適化・高速化をディープニューラルネットワークに適用することで高スループットと実現してます。
但し注意点としては使用しているGPU向けに学習済モデルがコンバートされるため、異なるGPU間でのコンバート済の学習済モデルの流用はできません(対象のGPUに合わせて学習済モデルのコンバートが必要)。
コンバート自体は対象プログラムの起動時に自動的に実施されます。但し、コンバートには数分の時間がかかるため2回目以降の起動時にはコンバート済の学習済モデルを指定することでこのステップをキャンセルすることができます。
Deepstreamにて物体検出させる方法
Deepstreamには大きく2つのサンプルが提供されています。
- ソースコードを書かずに設定ファイルのみでAI推論処理を実施するリファレンスアプリ
- 独自にパイプラインを構築したサンプルソース
今回は1.を使いこなす方法について記載します。
1.についてはリファレンスアプリ(Reference Application)といいながら、実は提供されるすべてのプラグインを組み込み、それらを設定ファイルに制御するアプリケーションとなっています。
よってDeepstreamの動作理解や簡単な動作確認についてはリファレンスアプリを活用することで動作確認することが可能です。
但し、リファレンスアプリは推論結果を①画面表示、②ファイル保存、③RTSP streamingの3つの方法でしか出力することができません。
そのため本格的にサーバに推論結果のJson形式データを送信したい場合は独自にパイプラインを作成する必要があります。
又、パイプラインの途中に独自の分岐処理を入れることができないため、これらを実現したい場合にも独自にパイプラインを作成する必要があります。
カメラ画像からの入力を使い物体検出させる方法
カメラ画像からの動画データを元にストリームで物体検出する手順を以下説明します。
独自設定ファイルを作成する
ベースとなるリファレンスアプリのサンプル設定ファイルをコピーして独自の設定ファイルを作成します。
リファレンスアプリの設定ファイルのサンプルは以下に保存されています。
[deepstreamの展開先フォルダ]/deepstream_sdk_v4.0.1_jetson/samples/configs/deepstream-app
Jetson Nano用の設定ファイルであるsource8_1080p_dec_infer-resnet_tracker_tiled_display_fp16_nano.txt を別名でコピーします。
設定ファイルを編集する
今回はカメラ画像を入力ストリームとするため、以下のように設定ファイルを編集します。
[application] enable-perf-measurement=1 perf-measurement-interval-sec=5 #gie-kitti-output-dir=streamscl [tiled-display] enable=0 rows=1 columns=1 width=1280 height=720 gpu-id=0 nvbuf-memory-type=0 [source0] enable=1 type=1 drop-frame-interval=2 gpu-id=0 camera-id=0 camera-width=640 camera-height=480 camera-fps-n=30 camera-fps-d=1 camera-v4l2-dev-node=0 cudadec-memtype=0 [sink0] enable=1 type=5 sync=1 source-id=0 gpu-id=0 qos=0 nvbuf-memory-type=0 overlay-id=1 container = 1 [osd] enable=1 gpu-id=0 border-width=1 text-size=15 text-color=1;1;1;1; text-bg-color=0.3;0.3;0.3;1 font=Serif show-clock=0 clock-x-offset=800 clock-y-offset=820 clock-text-size=12 clock-color=1;0;0;0 nvbuf-memory-type=0 [streammux] gpu-id=0 live-source=0 batch-size=8 batched-push-timeout=40000 width=1920 height=1080 enable-padding=0 nvbuf-memory-type=0 [primary-gie] enable=1 gpu-id=0 model-engine-file=../../models/Primary_Detector_Nano/resnet10.caffemodel_b8_fp16.engine batch-size=8 #Required by the app for OSD, not a plugin property bbox-border-color0=1;0;0;1 bbox-border-color1=0;1;1;1 bbox-border-color2=0;0;1;1 bbox-border-color3=0;1;0;1 interval=4 gie-unique-id=1 nvbuf-memory-type=0 config-file=config_infer_primary_nano.txt [tracker] enable=1 tracker-width=480 tracker-height=272 #ll-lib-file=/opt/nvidia/deepstream/deepstream-4.0/lib/libnvds_mot_iou.so ll-lib-file=/opt/nvidia/deepstream/deepstream-4.0/lib/libnvds_mot_klt.so #ll-config-file required for IOU only #ll-config-file=iou_config.txt gpu-id=0 [tests] file-loop=0
実行する
以下コマンドにてリファレンスアプリに設定ファイルを読み込ませて実行します。
deepstream-app -c [上記で作成した設定ファイルへのパス]
設定ファイル上のポイント
設定ファイル上のポイントについて説明します。
入力ストリームの制御
入力ストリームについては、[sourceX]セクションで制御します。
[source0] enable=1 type=1 drop-frame-interval=2 gpu-id=0 camera-id=0 camera-width=640 camera-height=480 camera-fps-n=30 camera-fps-d=1 camera-v4l2-dev-node=0 cudadec-memtype=0
typeパラメータにより、入力タイプを指定します。今回のケースでは「1:カメラ」を指定します。
更にcamera-XXXXパラメータにはカメラが対応している情報を設定します。
カメラの情報については以下コマンドにて取得します(ひとつ目のコマンドにてカメラID取得、ふたつ目のコマンドにて取得したカメラIDを使ってカメラ情報を取得します)。
v4l2-ctl --list-devices v4l2-ctl -d /dev/video0 --list-formats-ext
例えば、動画ファイルを入力したい場合には、以下のようにtypeパラメータに[2:URL]を指定してURIパラメータとして動画ファイルパスを指定します。
[source0] enable=1 type=2 uri=file://../../streams/sample_1080p_h264.mp4
動画ストリームについては複数指定することもでき、複数指定したい場合には[source0][source1][source2]・・・のように連番でセクションを作成します。
使用AIモデルの制御
使用AIモデルについては、[primary-gie]セクションで制御します。
[primary-gie] enable=1 gpu-id=0 model-engine-file=../../models/Primary_Detector_Nano/resnet10.caffemodel_b8_fp16.engine batch-size=8 ~以下省略~
学習済モデルについては、model-engine-fileパラメータに、TensorRTのエンジンファイルのパスを指定します。
但し、注意点としてリファレンスアプリでは、TensorRT形式にコンバートされたenginファイルしか指定ができません。
そのため、ONNXやCaffeのモデルファイルを使用したい場合には「独自にパイプラインを構築したサンプルソース」を元にした独自実装します。
結果出力
推論結果の出力方法は、[sink]セクションで制御します。
[sink0] enable=1 type=5 ~ 以下省略 ~
画面表示する場合は、typeパラメータに「5: Overlay 」を指定します。
例えば検出結果を動画ファイルに保存したい場合には、以下のようにtypeパラメータに「3: Encode + File Save」設定した上で保存先ファイル名やコーデックの種類も指定します。
type=3 codec=1 sync=1 source-id=0 gpu-id=0 qos=0 nvbuf-memory-type=0 output-file = /home/tsuji/deepstream/deepstream_sdk_v4.0.1_jetson/samples/output.mp4
まとめ
Jetson NanoでDeepstreamのリファレンスアプリを使って物体検出する方法を記事にしました。
当記事の内容を元に操作することでDeepstremaの概要を実感できると思います。
但し、サーバと連携するIoTシステムとしてJetson Nanoを使用する場合には「パイプラインの独自実装」が前提となります。
これについてはまたの機会に記事にできればと思います。