物体検出のYOLOをJetson Nanoでやってみます。
以前やったのはYOLOv3 でしたが今回は趣向を変えてコンテナ+YOLOv4+TensorRT でやってみます。
また、姿勢推定 では、torch2trt というツールを使いましたが、今回はONNXを介してTensorRTで重みを最適化してみます。
チュートリアルはtensorrt_demos のDemo#5ですが、上で書いたようにちょっとアレンジしています。
USBカメラを使った物体検出もやってみました。
なお、Step1~Step6では作業に4時間くらいはかかります。
環境構築
Jetson Nano 、Jetpack 4.4.1(L4T R32.4.4) 、NVIDIAコンテナ
Nanoの初期設定はこちらをご参照 ください。
コンテナイメージはnvcr.io/nvidia/l4t-ml:r32.4.4-py3です。
作業環境を作成します。
ディレクトリのアーカイブをダウンロード
ホスト側で作業用ディレクトリを作成
mkdir work - tensorrt - demos
ダウンロードしたファイルの解凍先をこのディレクトリにします。
こういうディレクトリ構造になります。jetson は適宜ご自分のアカウント名で置き換えてください。
/home/jetson /work-tensorrt-demos/tensorrt_demos-master
Step1:コンテナ作成
イメージを取ってきます。
sudo docker pull nvcr . io / nvidia / l4t - ml : r32 . 4.4 - py3
コンテナの作成
sudo docker create - it -- name my_tensorrt_demos -- gpus all -- network host - e DISPLAY = $ DISPLAY -- device / dev / video0 : / dev / video0 - v / home / jetson / work - tensorrt - demos / tensorrt_demos - master : / work - v / tmp / . X11 - unix / : / tmp / . X11 - unix nvcr . io / nvidia / l4t - ml : r32 . 4.4 - py3
起動
sudo docker start - i my_tensorrt_demos
アップデート&アップグレードして他のパッケージをインストール
apt update
apt upgrade - y
apt install python - pip python3 - pip - y
python3 - m pip install -- upgrade pip
apt install wget
apt install nano
apt install unzip
apt install libcanberra - gtk* - y
Step2:OpenCV 4.1.1 のインストール
shellファイル作成
nano install_opencv4 . 1.1_Nano.sh
以下のコードをコピー・ペースト
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/bin/bash
#
# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
#
# NVIDIA Corporation and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA Corporation is strictly prohibited.
#
if [ "$#" - ne 1 ] ; then
echo "Usage: $0 <Install Folder>"
exit
fi
folder = "$1"
user = "nvidia"
passwd = "nvidia"
echo "** Remove other OpenCV first"
apt purge * libopencv*
echo "** Install requirement"
apt update
apt install - y build - essential cmake git libgtk2 . 0 - dev pkg - config libavcodec - dev libavformat - dev libswscale - dev
apt install - y libgstreamer1 . 0 - dev libgstreamer - plugins - base1 . 0 - dev
apt install - y python2 . 7 - dev python3 . 6 - dev python - dev python - numpy python3 - numpy
apt install - y libtbb2 libtbb - dev libjpeg - dev libpng - dev libtiff - dev libdc1394 - 22 - dev
apt install - y libv4l - dev v4l - utils qv4l2 v4l2ucp
apt install - y curl
apt update
echo "** Download opencv-4.1.1"
cd $ folder
curl - L https : //github.com/opencv/opencv/archive/4.1.1.zip -o opencv-4.1.1.zip
curl - L https : //github.com/opencv/opencv_contrib/archive/4.1.1.zip -o opencv_contrib-4.1.1.zip
unzip opencv - 4.1.1.zip
unzip opencv_contrib - 4.1.1.zip
cd opencv - 4.1.1 /
echo "** Apply patch"
sed - i 's/include <Eigen\/Core>/include <eigen3\/Eigen\/Core>/g' modules / core / include / opencv2 / core / private . hpp
echo "** Building..."
mkdir release
cd release /
cmake - D WITH_CUDA = ON - D CUDA_ARCH_BIN = "5.3,6.2,7.2" - D CUDA_ARCH_PTX = "" - D OPENCV_EXTRA_MODULES_PATH = . . / . . / opencv_contrib - 4.1.1 / modules - D WITH_GSTREAMER = ON - D WITH_LIBV4L = ON - D BUILD_opencv_python2 = ON - D BUILD_opencv_python3 = ON - D BUILD_TESTS = OFF - D BUILD_PERF_TESTS = OFF - D BUILD_EXAMPLES = OFF - D CMAKE_BUILD_TYPE = RELEASE - D CMAKE_INSTALL_PREFIX = / usr / local . .
make - j3
make install
echo 'export PYTHONPATH=$PYTHONPATH:' $ PWD '/python_loader/' >> ~ / . bashrc
source ~ / . bashrc
echo "** Install opencv-4.1.1 successfully"
echo "** Bye :)"
インストール実行
mkdir opencv
chmod 755 install_opencv4 . 1.1_Nano.sh
sh install_opencv4 . 1.1_Nano.sh opencv
確認
Python3(python2)
>>>import cv2
何もなければOK
Step3:ONNX 1.4.1 インストール
既存のONNX(1.7.0)を削除
(新しいバージョンでは不具合がでるそうで、1.4.1が指定されています)
バージョン指定(1.4.1)してインストール
apt install protobuf - compiler libprotoc - dev
pip3 install onnx == 1.4.1
Step4:protobuf-3.8.0 インストール
shellファイル作成
cd /
nano install_protobuf - 3.8.0.sh
以下のコードをコピー・ペースト
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash
set - e
folder = $ { HOME } / src
mkdir - p $ folder
echo "** Install requirements"
apt install - y autoconf libtool
echo "** Download protobuf-3.8.0 sources"
cd $ folder
if [ ! - f protobuf - python - 3.8.0.zip ] ; then
wget https : //github.com/protocolbuffers/protobuf/releases/download/v3.8.0/protobuf-python-3.8.0.zip
fi
if [ ! - f protoc - 3.8.0 - linux - aarch_64 . zip ] ; then
wget https : //github.com/protocolbuffers/protobuf/releases/download/v3.8.0/protoc-3.8.0-linux-aarch_64.zip
fi
echo "** Install protoc"
unzip protobuf - python - 3.8.0.zip
unzip protoc - 3.8.0 - linux - aarch_64 . zip - d protoc - 3.8.0
cp protoc - 3.8.0 / bin / protoc / usr / local / bin / protoc
echo "** Build and install protobuf-3.8.0 libraries"
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION = cpp
cd protobuf - 3.8.0 /
. / autogen . sh
. / configure -- prefix = / usr / local
make - j $ ( nproc )
make check
make install
ldconfig
echo "** Update python3 protobuf module"
# remove previous installation of python3 protobuf module
apt install - y python3 - pip
pip3 uninstall - y protobuf
pip3 install Cython
cd python /
python3 setup . py build -- cpp_implementation
python3 setup . py test -- cpp_implementation
python3 setup . py install -- cpp_implementation
echo "** Build protobuf-3.8.0 successfully"
インストール実行
chmod 755 install_protobuf - 3.8.0.sh
sh install_protobuf - 3.8.0.sh
確認
Step5:準備
「plugins /」サブディレクトリに移動し、「yolo_layer」プラグインをビルド
以下のファイルが作成されます。
libyolo_layer.so
YOLO(cfg、weights)をダウンロード
cd / work / yolo
. / download_yolo . sh
以下のファイルがダウンロードされます。
Creating yolov3-tiny-288.cfg and yolov3-tiny-288.weights
Creating yolov3-tiny-416.cfg and yolov3-tiny-416.weights
Creating yolov3-288.cfg and yolov3-288.weights
Creating yolov3-416.cfg and yolov3-416.weights
Creating yolov3-608.cfg and yolov3-608.weights
Creating yolov3-spp-288.cfg and yolov3-spp-288.weights
Creating yolov3-spp-416.cfg and yolov3-spp-416.weights
Creating yolov3-spp-608.cfg and yolov3-spp-608.weights
Creating yolov4-tiny-288.cfg and yolov4-tiny-288.weights
Creating yolov4-tiny-416.cfg and yolov4-tiny-416.weights
Creating yolov4-288.cfg and yolov4-288.weights
Creating yolov4-416.cfg and yolov4-416.weights
Creating yolov4-608.cfg and yolov4-608.weights
Creating yolov4-csp-256.cfg and yolov4-csp-256.weights
Creating yolov4-csp-512.cfg and yolov4x-csp-512.weights
Creating yolov4x-mish-320.cfg and yolov4x-mish-320.weights
Creating yolov4x-mish-640.cfg and yolov4x-mish-640.weights
テスト用画像をダウンロードしておく
cd / work
mkdir Pictures
wget https : //raw.githubusercontent.com/pjreddie/darknet/master/data/dog.jpg -O /work/Pictures/dog.jpg
Step6:TensorRT最適化
Step5で取得したデータはいろいろあります。YOLOv3とYOLOv4。
画像サイズが288、416、608のもの(サイズは32の倍数)。
ネットワークモデルは5種類。
通常のモデル以外に
tiny:conv layer数などを減らして、より軽量化したモデル、通常の1/10くらいのサイズ
SPP:Spatial Pyramid Pooling Based YOLO
CSP:Cross Stage Partial connections
mish:活性化関数
画像サイズ416のYOLOv4、tinyモデルでやってみます。
ONNXに変換
weights,cfg ー>onnx
python3 yolo_to_onnx . py - m yolov4 - tiny - 416
以下のファイルが作成されます。
yolov4-tiny-416.onnx
TensorRTエンジンに変換
onnxー>trt
python3 onnx_to_tensorrt . py - m yolov4 - tiny - 416
以下のファイルが作成されます。
yolov4-tiny-416.trt
In case “onnx_to_tensorrt.py” fails (process “Killed” by Linux kernel), it could likely be that the Jetson platform runs out of memory during conversion of the TensorRT engine. This problem might be solved by adding a larger swap file to the system. Reference: Process killed in onnx_to_tensorrt.py Demo#5.
「onnx_to_tensorrt.py」が失敗した場合(Linuxカーネルによる「Killed」プロセス)、TensorRTエンジンの変換中にJetsonプラットフォームのメモリが不足している可能性があります。 この問題は、より大きなスワップファイルをシステムに追加することで解決できる可能性があります。
killされないまま、プロセスに不具合が生じて完了しない場合もあります。10分以上経過しても終了せずjetson-statsを見てもCPUがどれもフル稼働していないような場合はコンテナを再起動してonnx_to_tensorrt.pyを再実行してみてください。
USBカメラを使う場合は、描画にtkinter + canvas を使うので、tkinter をインストールしておきます。
apt install python3 - tk - y
これで道具は一通りそろったので、コンテナを終了しておきます。
Ctrl + D で抜ける。
Step7:実行
Test the TensorRT “yolov4-tiny-416” engine with the “dog.jpg” image.
TensorRT「yolov4-tiny-416」エンジンを「dog.jpg」画像でテストします。
ホスト側でxhostを実行
sudo xhost si : localuser : root
コンテナを起動して以下を実行
sudo docker start - i my_tensorrt_demos
cd / work
python3 trt_yolo . py -- image / work / Pictures / dog . jpg - m yolov4 - tiny - 416
こんな感じ。
USBカメラを使ってみます。
こんな感じで物体検出します。
YOLOv4-tiny-416のTensorRTエンジンを使った場合。
この例では、Windowの下に赤字で検出した人の数を表示しています。
例えば、コードはこんな感じ。
category_numberやモデル名、画像サイズなどはハードコードしています、必要なら適宜変更してくださいませ。
詳しくは、trt_yolo.pyやtrt_yolo_cv.pyをご参照ください。
もうちょい細かくデータを取得したい場合は、utils/visualization.py などをご参照ください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# -*- coding: utf-8 -*-
import tkinter as tk
import cv2
from PIL import Image , ImageTk
import numpy as np
import pycuda . autoinit
from utils . yolo_classes import get_cls_dict
from utils . visualization import BBoxVisualization
from utils . yolo_with_plugins import get_input_shape , TrtYOLO
root = tk . Tk ( )
root . title ( "camera" )
root . geometry ( "416x416" )
root . resizable ( width = False , height = False )
canvas = tk . Canvas ( root , width = 416 , height = 416 , bg = "white" )
canvas . pack ( )
def capStart ( ) :
print ( 'camera-start' )
try :
global c , vis , trt_yolo
letter_box = False
category_number = 80
model_name = "yolov4-tiny-416"
c = cv2 . VideoCapture ( 0 )
cls_dict = get_cls_dict ( category_number )
vis = BBoxVisualization ( cls_dict )
h , w = get_input_shape ( model_name )
trt_yolo = TrtYOLO ( model_name , ( h , w ) , category_number , letter_box )
print ( 'width:' + str ( w ) + 'px/height:' + str ( h ) + 'px' )
except :
import sys
print ( "error" )
print ( sys . exec_info ( ) [ 0 ] )
print ( sys . exec_info ( ) [ 1 ] )
c . release ( )
cv2 . destroyAllWindows ( )
def up ( ) : #change update
global img
conf_th = 0.3
ret , frame = c . read ( )
if ret :
frame = frame [ 0 : 720 , 0 : 720 ]
size = ( 416 , 416 )
frame = cv2 . resize ( frame , size )
boxes , confs , clss = trt_yolo . detect ( frame , conf_th )
frame = vis . draw_bboxes ( frame , boxes , confs , clss )
img = ImageTk . PhotoImage ( Image . fromarray ( cv2 . cvtColor ( frame , cv2 . COLOR_BGR2RGB ) ) )
canvas . create_image ( 0 , 0 , image = img , anchor = "nw" )
else :
print ( "up failed" )
root . after ( 1 , up )
capStart ( )
up ( )
root . mainloop ( )
NanoとXavier NX とでは、検出精度に差はないと思われますが、カメラのパフォーマンスを含めると….(まぁ、当然ですけど)
Leave a Reply