글 혹은 그림의 출처가 문제있다면 수정 및 삭제하겠습니다. 우측의 Tags 와 검색기능을 이용하여 편하게 찾을 수 있습니다.
Please check buttons on the right like Tags and language options if can't read this blog (*mobile not support)
9/24/2019
TensorRT 관련사항 (자료수집후 정리 )
https://github.com/NVIDIA-AI-IOT/deepstream_4.x_apps
https://github.com/NVIDIA-AI-IOT/torch2trt
https://github.com/NVIDIA-AI-IOT/redaction_with_deepstream
TensorRT 관련 동작구조도
https://programmer.help/blogs/tensorrt-learns-to-use-c.html
TensorRT 관련내용 ( Serialiaze)
https://devtalk.nvidia.com/default/topic/1058409/jetson-tx2/how-to-load-and-deserialize-the-engine-file-/
OpenVINO,Opencv
라즈베리파이에서 관련자료수집
https://www.pyimagesearch.com/2019/04/08/openvino-opencv-and-movidius-ncs-on-the-raspberry-pi/
9/22/2019
TensorRT의 Layer 비교
각 Activation Layer 비교
https://en.wikipedia.org/wiki/Activation_function
https://keras.io/api/layers/activations/
https://keras.io/layers/merge/
https://caffe.berkeleyvision.org/tutorial/layers/concat.html
9/20/2019
IOU (Intersection over Union)
- IOU (Intersection over Union)
아래와 같이 두개의 Box가 겹칠 경우 Intersection의 부분의 비율을 알아보는 것이다.
출처
https://medium.com/@ageitgey/snagging-parking-spaces-with-mask-r-cnn-and-python-955f2231c400
https://ahyuo79.blogspot.com/2019/07/opencv-object-tracking.html
NVIDIA-DeepStream의 nvInfer 의 Tracker
https://ahyuo79.blogspot.com/2019/07/deepstream-gst-nvinfer-tensorrt-iplugin.html
1.1 IOU 계산 방법
- IOU 계산방법
상위 방법은 Python으로 사용하면 쉽게 구할 수 있을 것 같은데, 소스의 동작원리를 정확하게 모르겠다.
일반적인 좌표를 사용하게 되면 어떻게 구현이 될까라는 것도 궁금하다
- 좌표로만 IOU 직접 계산방법
Left(X), Top(Y) , Width, Height
이때 사각형의 대각선 좌표값으로, X, Y 좌표와 (X+Width) , ( Y+Height) 좌표 두개로 쉽게 IOU를 감지하고 이를 계산가능
ex) A-BBOX의 좌표 X(3) , Y (3) , widht (3) ,height(4) 이라고 하면 아래 두 좌표로 4각형을 인지가능
- A-BBOX의 A-MIN 좌표 (3,3)
- A-BBOX의 A-MAX 좌표 (6,7)
- B-BBOX 의 B-MIN 좌표 X >=3 && Y>=3 일 때
- B-MIN 좌표의 X, Y가 아래 두 조건 충족시 IOU 계산
- 3 < X < 6 (3+width)
- 3 < Y < 7 (3+height)
- InterSection Size = A-MAX - B-MIN (각각의 크기나옴)
- B-BBOX의 B-MIN 좌표 X < 3 || Y < 3 일 때
- B-MAX 좌표의 X, Y가 아래 두 조건 충족시 IOU 계산
- 3 < X < 6 (3+width)
- 3 < Y < 7 (3+height)
- InterSection Size = B-MAX - A-MIN (각각의 크기나옴)
상위와 같이 InterSection Size만 알면, 모든 계산이 쉬어진다.
현재 상위 조건은 모눈종이에 직접 그려서 생각해본 것 이며, 오류가 아직 존재할 수 있다.
추후 소스로 작성된 소스 검증을 해봐야겠다.
- 모눈종이 PDF 문서
머리가 나뻐서 자꾸, 모눈 종이가 필요해서 아래 링크
http://blog.daum.net/miparang/7058252
- IOU 관련소스 자료모음
https://bskyvision.com/465
아래의 소스는 상위 소스에서 간단히 IOU를 만드는 소스를 만들어 보았는데, 아직 검증을 제대로 해보지를 못했다.
static int max(int v1 , int v2) { if(v1 > v2) return v1; else return v2; } static int min(int v1 , int v2) { if(v1 > v2) return v2; else return v1; } static int interSection(int Ax1, int Ay1, int Ax2, int Ay2, int Bx1, int By1, int Bx2, int By2) { int left = max(Ax1, Bx1); int top = max(Ay1, By1); int right = min(Ax2, Bx2); int bottom = min(Ay2, By2); int interArea = 0; if (left < right && bottom > top) interArea = ((right - left) + 1) * ((bottom - top)+1); return interArea; }
1.2 IOU 사용용도
IOU 사용용도는 다양한 것 같으며, 일단, 아래의 사이트 에서 처럼 실제 BBOX와 예측된 BBOX의 차이를 알아서 교정을 위해서 도 사용이 되어진다.
- Ground-Truth bouning Box: 실제 모델의 Box, 손으로 직접 Label
- Predicted bouning Box: Deep Learning을 통해 예측된 BBOX
https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/
또한 동일한 Object를 여러개의 Object로 인식을 할 경우, 이때 IOU값에 따라 나머지를 없애는 데에도 사용되어 지는 것 같다.
더불어 Tracking 알고리즘에서도 역시 IOU는 사용이 되어지는데, Object Detection이 되고 이전 Frame 과 이후 Frame IOU값을 가지고 지속적으로
Tracking 하기위해서도 사용되어지는 것 같다.
이외에도 개인적으로 생각을 해보면, ROI(Region of Interest) BBOX 와 Object Detection 된 BBOX의 IOU를 이용도 가능 할 것 같다.
이는 각각의 ROI의 영역이 서로 겹칠 경우, 상위 Smart Parking System일 경우 이용 가능할 것 같다.
간단하지만, 생각해보면 아주 다양하게 이용이 되어지기 때문에 꼭 필요하다
9/16/2019
Jetson Nano 개발환경구축
기존의 SDKmanager를 설치를 해주었다면, Upgrade를 진행을 해주면되고, 아래의 Site에서 Download하자
Jetson Nano의 경우는 eMMC Type이 아닌 SD Card방식이므로 아래의 사이트에서 별도의 SD Card Image를 제공하고 있으므로,
SDKManger 설치가 익숙지 않는다면, 이것으로 Download하여 Image를 Write하여 사용하자
Jetpack Download
https://developer.nvidia.com/embedded/jetpack
Jetson Nano Board 및 JetPack 설치 Manual
https://developer.download.nvidia.com/embedded/L4T/r32-2_Release_v1.0/Jetson_Nano_Developer_Kit_User_Guide.pdf?vFL9evtTTiizks2dE50I2tofKlel_baFRnCEFgz-IiCbAttHALUknCurJNUO0-MfoWoONyJRa0QWOHj1GH_3fUJvLFv4elzlagbtYoV6eDmXciTVuQq7mxreo1r4b0fK6SM-NmeQeCU4wUoQRXxgbyp_c3RYdO1WiI_m3YytnaP2Z_CT8BOi
1.1 Jetson Nano의 보드 구성
Jetson Nano의 구성을 살펴보면, Jetson TX2와 같이 Carrier Board와 Module로 두개로 분리되어있으며, 추후 Module만 구입가능할지는 다시 봐야 할 것 같다.
- Jetson Nano의 기본권장사항
- Storage : microSD 지원 권장사양 16GB or 그이상
- Power 선택 : micro B USB Power(J28) or Power Jack(J25) (5V,4A)
- micro B USB(J28) 로 USB Device로 연결되므로, 가급적 Power Jack 사용권장
- Power Jack으로 사용시 J48 Jumper 필요
- Serial 사용: J44지원 or micro B USB로 연결시 ACM0으로 연결
Jetson Nano Get Started
https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit
https://desertbot.io/blog/jetson-nano-usb-login
1.2 Force Recovery Mode 설정
기존 Jetson 처럼 Force Recovery Mode를 제공하고 있지만, Button 형식으로 제공을 하고 있지 않다
상위 Manual을 읽어보면, 상위 기반은 Adapter 로 Power로 공급하고, J28 micro B USB는 USB Device로 만 사용해야지만, 가능한 이야기이다.
Manual을 읽어보면, 최소 필요사항은 다음과 같다
- DC Adapter (5V,4A)
- HDMI Cable 과 필요한 모니터
- USB Keyboard와 Mouse
- Jumper
- Force Recovery Mode (아직 못해봄 )
- J40 의 PIN3,4 연결 (with Jumper)
- J48 Pin 의 Power 선택 (USB Power or Adapter Power)
- J28 micro USB Power (without Jumper, Default)
- J25 Power Jack (with Jumper)
- J48 Pin의 선택에 따라 각 Power를 연결 ( USB Power or Adapter Power)
- J40의 PIN3,4 Jumper 제거
혹시나해서 NVIDIA Site에서 가능한지 물어봤지만, USB Power로만 가능하려면, 우선 PC의 USB 전원 공급이 가능하다면, 가능하다고 한다
https://devtalk.nvidia.com/default/topic/1063210/jetson-nano/jetson-nano-recovery-mode-/post/5384033/#5384033
- Force Recovery Mode 설정위치 (J40)
2. Jetpack 4.2.2 설치
가능하다면 SDK Manager를 설치해서 Host에도 NVIDIA의 관련 Tools 과 함께 설치진행하자.
만약 Jetson Nano의 상위 Force Recovery Mode 설정이 어렵다면 NVIDIA에서 제공하는 SD Card Image만을 Download하여 dd로 Image를 Write하자
2.1 SD Card Image Write 방법
SD card Image Download 후 아래와 같이 SD Card를 삽입하여, SD Card 위치 파악
$ lsusb -t /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/6p, 5000M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M |__ Port 6: Dev 28, If 0, Class=Mass Storage, Driver=usb-storage, 480M |__ Port 9: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M |__ Port 11: Dev 4, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 11: Dev 4, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 12: Dev 5, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop1 7:1 0 202.9M 1 loop /snap/vlc/1049 sdd 8:48 1 59.7G 0 disk //새로 연결된 SD Card 확인 └─sdd1 8:49 1 59.7G 0 part loop4 7:4 0 89M 1 loop /snap/core/7713 loop2 7:2 0 202.3M 1 loop /snap/vlc/770 loop0 7:0 0 184.8M 1 loop /snap/eclipse/40 sda 8:0 0 2.7T 0 disk ├─sda4 8:4 0 2.7T 0 part / ├─sda2 8:2 0 513M 0 part /boot/efi ├─sda3 8:3 0 976M 0 part [SWAP] └─sda1 8:1 0 1M 0 part loop5 7:5 0 192.1M 1 loop /snap/eclipse/29 loop3 7:3 0 88.7M 1 loop /snap/core/7396
- SD Card Image Write (Linux)
## 4M 가 잘 동작이 안된다면, 1M로 설정을 변경해서 하자 $ unzip -p jetson-nano-sd-r32.2.1.zip | sudo dd of=/dev/sdd bs=4M conv=fsync or $ sudo dd bs=4M if=sd-blob-b01.img of=/dev/sdd status=progress conv=fsync
출처
https://www.raspberrypi.org/documentation/installation/installing-images/linux.md
Linux에서도 Etcher가 가능(미테스트)
https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit#write
Write 한 후 Jetson Nano에 연결한 후 HDMI와 USB Keyboard/Mouse로 연결하여 Ubuntu 초기설정을 진행하고, ID/PW를 만들자
이것으로 설정을 하니, DeepStream이 기본으로 설정이 되어있지 않으므로, 가능하다면, SDKmanager로 설치를 해보도록하거나, 별도로 DeepStream을 설치를 진행하자
- DeepStream 별도설치가능
2.2 SDKmanager 기반 설치
기존에 SDK Manager를 설치를 했다면, Upgrade를 진행하여, 설치가 쉬우며, 아래와 같이 선택만 하면된다
다만 Jetson Series Board가 동일하게 SDK Manager로 동작할 때는 반드시 상위 Force Recovery Mode를 숙지를 해야한다.
JetPack 4.2.2 부터는 Target SDK에 Tensorflow도 새롭게 추가되어 기본으로 들어가있음
- Host에서 USB를 통하여 Jetson OS Write
- STEP에서 Download를 다 진행된 후 아래의 Message가 확인
- Jetson Nano와 Micro B USB로 연결 확인
- Manual로 Setup 설정할 경우 Force Recovery Mode로 진입 (Auto Setup일 경우 필요없음)
- Username/Password 설정
- Flash 진행
- Jetson OS Flash 종료 후 SSH Message 확인
- Flash 도중에 SSH에 연결하는 Message 확인 (Ubuntu 초기화해야함)
- HDMI로 연결된 화면과 USB Keyboard/Mouse를 이용하여 Ubuntu 초기화설정
- Username/Password 설정 후 자동 Reboot 후 SSH Server동작
- 설정된 Username/Password로 SSH 접속 후 Package 설치 진행
SSH로 연결하여, 나머지 추가적인 Package를 설치하는데 시간이 많이 걸리며, 아래와 같이 완료
3. SD Card 용량 제한사항
이미 Partition Size가 이미 정해져 있다보니, 용량이 부족한 현상이 발생하며, 아래의 명령으로 늘리는 것이 가능하지만, flash.sh 의 명령의 경우 14G로 제한이 있다고 한다.
(flash명령을 아직 테스트를 해보지 않음)
flash.sh 사용법은 이전의 JetPack을 참조 (Jetson TX2와 거의 동일)
https://developer.download.nvidia.com/embedded/L4T/r27_Release_v1.0/Docs/Jetson_X2_Developer_Kit_User_Guide.pdf?WG5M_7R8_PzZIb_pcScGrQ3imdfQKUv-NmkuOrUe6RaL5Oz5n0Z7fKm_GZnY1rpumVTduYDvxD3f2QxlUlzcIo3XEjN_nunH-4UGSicgdfo7hAvy3A3KtYivCggScKJr8Ho23QJnhy-VubjOb7D4BGbKL1-Rw5DDs3cIBkKztH91RD9e116atw
용량을 증량하려면, 아래와 같이 직접 SD Card Image를 만들고, 이를 구운다음 DeepStream SDK 별도 설치진행하거나 상위 sdkmanger를 이용하여 설치를 진행하자
- Host PC에서 직접 본인의 SD Card Image 생성
$ cd ~/nvidia/nvidia_sdk/JetPack_4.2.2_Linux_GA_P3448/Linux_for_Tegra $ ls // 기존과 다르게 create_jetson_nano_sd-card-image 존재 create-jetson-nano-sd-card-image.sh flash.sh .. 중략 ## 16G 설정하면, 최대값으로 설정됨 $ sudo ./create-jetson-nano-sd-card-image.sh -o sd-blob.img -s 16G -r 100 $ sudo dd bs=4M if=sd-blob.img of=/dev/sdd status=progress conv=fsync
상위명령으로 생성된 Image는 기본적인 Jetson OS만 생성하며, Jetson SDK Components를 포함하고 있지 않다.
sdkmanager를 이용하거나 본인 별도로 각각의 Jetson SDK를 설치를 해야한다
- SDKManager 이용할 경우
출처
https://devtalk.nvidia.com/default/topic/1050105/jetson-nano/jetson-nano-sd-card-partitions-can-not-extend-/
https://devtalk.nvidia.com/default/topic/1050105/jetson-nano/jetson-nano-sd-card-partitions-can-not-extend-/
9/10/2019
Anacoda 관련사용법 및 virtual 환경 자료수집
- Python 기본설명 및 용어
- Python 자료모음 및 관련링크
1.1 Anaconda download 및 설치
두가지 배포판으로 제공해주고 있으며, 아래의 사이트에서 쉽게 Download 및 설치가 가능하다
- Python 3.7 Version : Anaconda3.date.OS.Arch
- Python 2.7 Version: Anaconda2.date.OS.Arch
Anaconda Download
https://www.anaconda.com/distribution/#download-section
https://repo.anaconda.com/archive/
Anacoda의 사이트 및 소개
https://www.anaconda.com/
- Anaconda 설치방법 (Ubuntu 기반)
$ cd /tmp $ curl -O https://repo.anaconda.com/archive/Anaconda3-2019.03-Linux-x86_64.sh // Python 3.7 $ sha256sum Anaconda3-2019.03-Linux-x86_64.sh // checksum 확인 $ bash Anaconda3-2019.03-Linux-x86_64.sh // 설치진행 $ conda list // 설치 후 package 확인
출처: Anaconda 설치 방법
https://www.digitalocean.com/community/tutorials/how-to-install-anaconda-on-ubuntu-18-04-quickstart
Anaconda는 일반적으로 conda도 package를 관리하며, pip인 python의 package 방식과 유사하지만, 다른부분이 많아 이를 비교한다.
- Conda 와 pip 의 기본비교
https://www.anaconda.com/blog/understanding-conda-and-pip |
- Tensorflow을 위한 pip 와 anaconda 성능비교
python의 pip 처럼 conda를 기반으로 설치가 가능하며, 본인이 원하는 환경을 구성하여 각각의 version을 설정도 가능하다고 한다.
- conda / pip package 기본관리
$ conda install package // pip install $ conda remove package // pip uninstall $ conda list // pip list $ conda search package // pip search
- conda 의 일반 명령어
- conda 와 pip 의 동작비교
Task | Conda package and environment manager command | Pip package manager command | Virtualenv environment manager command |
---|---|---|---|
Install a package |
|
| X |
Update a package |
|
| X |
Update package manager |
| Linux/macOS: | X |
Uninstall a package |
|
| X |
Create an environment |
| X |
|
Activate an environment |
| X |
|
Deactivate an environment |
| X |
|
Search available packages |
|
| X |
Install package from specific source |
|
| X |
List installed packages |
|
| X |
Create requirements file |
|
| X |
List all environments |
| X | Install virtualenv wrapper, then |
Install other package manager |
|
| X |
Install Python |
| X | X |
Update Python |
| X | X |
* conda activate
only works on conda 4.6 and later versions. For conda versions prior to 4.6, type:
1.4 conda 설치후 Tensorflow 관련설정
conda 설치 진행후 tensorflow를 사용하기 위해서 관련부분 설치 진행
- 나만의 환경구성
$ conda list | grep python ipython 7.6.1 py37h39e3cac_0 ipython_genutils 0.2.0 py37_0 msgpack-python 0.6.1 py37hfd86e86_1 python 3.7.3 h0371630_0 python-dateutil 2.8.0 py37_0 python-libarchive-c 2.8 py37_11 $ conda create --name my_env python=3 $ conda activate my_env $ conda create -n tensorflow_gpuenv tensorflow-gpu // tensorflow_gpuenv 환경 만들고 필요한 package를 tensorflow-gpu 설정 $ conda activate tensorflow_gpuenv // 나만의 환경설정으로 시작
출처
https://www.anaconda.com/tensorflow-in-anaconda/
- TensorBoard 기본사용법
https://medium.com/trackin-datalabs/tensorboard-tensorboard-%EA%B8%B0%EC%B4%88-6163e1642bb0
https://medium.com/trackin-datalabs/tensorboard-%EA%B0%84%EB%8B%A8%ED%9E%88-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-18a4fda2efb1
https://pinkwink.kr/1086
https://pythonkim.tistory.com/39
1.5 Pycharm 기반의 Conda 관련내용 링크
Pycharm 기반의 Conda
https://www.anaconda.com/pycharm
https://itsfoss.com/install-pycharm-ubuntu/
https://itsfoss.com/install-pycharm-ubuntu/
Anaconda 를 비롯하여 여러가지 Virtual 환경을 제공을 하고 있으며, Python의 Package들을 독립적으로 Virtual 환경마다 관리가 가능하기때문에 편리하다.
최근에는 주로 사용하는 Vritual 환경은 pip 기반의 virtualenv/venv 와 conda 기반으로 사용하며, 각각의 기능을 알아보자.
- Python 다양한 Virtual 환경 비교
https://wikidocs.net/16402
https://stackoverflow.com/questions/38217545/what-is-the-difference-between-pyenv-virtualenv-anaconda
- Python Package는 전체관리와 가상환경관리로 구분
- 전체 관련 Package 관리
- 각 독자 가상환경 구성 후 아래의 명령어로 Package 관리
- pip 기반의 package 관리(venv 적용후 관리해도됨)
$ pip install -r requirement.txt $ pip freeze > requirement.txt
- conda 기반의 package 관리(가상환경기반으로해도됨)
$ conda install --file packagelist.txt $ conda list --export > packagelist.txt
- python3의 venv 설정(가상환경) 및 기본 사용법
$ python3 -m venv 설정이름 // create venv , virtualenv도 거의 동일 $ source 설정이름/bin/activate // active 가상환경가동 in Linux > 설정이름/bin/activate.bat // active in Window > 설정이름/bin/activate.ps // active in Window $ deactivate // decativate 가상환경에서 빠져나오기
- conda 의 가상환경 및 기본사용법
$ conda create -n 설정이름 $ source activate 설정이름 $ source deactivate
https://medium.com/@dan_kim/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%B4%88%EC%8B%AC%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-pip-%EA%B7%B8%EB%A6%AC%EA%B3%A0-virtualenv-%EC%86%8C%EA%B0%9C-a53512fab3c2
9/06/2019
TensorRT 5 Python uff_custom_plugin 분석
우선 TensorRT Python UFF Custom Layer Source를 이해하기전에 아래의 소스들을 기본적으로 이해를 하고 오는 것이 좋을 것 같다
- TensorRT Python Code 분석
https://ahyuo79.blogspot.com/2019/09/tensorrt-5-python-tensorflow-mnist.html
TensorRT 5 기본구조
https://ahyuo79.blogspot.com/2019/08/tensorrt-5-python.html
아래사항은 Tensorflow와 TensorRT 설치가이드이며 관련사항이므로 참고하자
- Tensorflow 와 TensorRT Package
https://docs.nvidia.com/deeplearning/sdk/tensorrt-install-guide/index.html#installing
1.1 TensorRT 소스구조 파악 과 실행
현재 모든 Manual이 X86기반으로 되어 있으므로, ARM Version이 맞게 이를 변경하고 관련된 Package를 설치하여 아래의 소스를 실행해보자
- UFF_Custom_PlugIn의 README 정보
https://docs.nvidia.com/deeplearning/sdk/tensorrt-sample-support-guide/index.html#uff_custom_plugin
- UFF Custom PlugIn 소스구조 및 필요사항 확인
$ cd /usr/src/tensorrt/samples/python/uff_custom_plugin $ tree -t . ├── CMakeLists.txt // cmake 필요 ├── __init__.py ├── lenet5.py ├── README.md // 반드시 참조 ├── requirements.txt ├── sample.py └── plugin ├── clipKernel.cu // CUDA Complier 필요 ├── clipKernel.h ├── customClipPlugin.cpp // GCC->G++ Compiler 필요 └── customClipPlugin.h $ cat requirements.txt Pillow pycuda numpy tensorflow
- C++ PlugiN 빌드를 위해 cmake 설정 변경
$ vi CMakeLists.txt # We need cmake >= 3.8, since 3.8 introduced CUDA as a first class language cmake_minimum_required(VERSION 3.8 FATAL_ERROR) project(ClipPlugin LANGUAGES CXX CUDA) # Enable all compile warnings set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -Werror") # Sets variable to a value if variable is unset. macro(set_ifndef var val) if (NOT ${var}) set(${var} ${val}) endif() message(STATUS "Configurable variable ${var} set to ${${var}}") endmacro() # -------- CONFIGURATION -------- ##set_ifndef(TRT_LIB /usr/lib/x86_64-linux-gnu) ##set_ifndef(TRT_INCLUDE /usr/include/x86_64-linux-gnu) set_ifndef(TRT_LIB /usr/lib/aarch64-linux-gnu/) set_ifndef(TRT_INCLUDE /usr/include/aarch64-linux-gnu/ ) # Find dependencies: message("\nThe following variables are derived from the values of the previous variables unless provided explicitly:\n") # TensorRT's nvinfer lib find_library(_NVINFER_LIB nvinfer HINTS ${TRT_LIB} PATH_SUFFIXES lib lib64) set_ifndef(NVINFER_LIB ${_NVINFER_LIB}) # -------- BUILDING -------- # Add include directories include_directories(${CUDA_INC_DIR} ${TRT_INCLUDE} ${CMAKE_SOURCE_DIR}/plugin/) # Define clip plugin library target add_library(clipplugin MODULE ${CMAKE_SOURCE_DIR}/plugin/clipKernel.cu ${CMAKE_SOURCE_DIR}/plugin/customClipPlugin.cpp ${CMAKE_SOURCE_DIR}/plugin/clipKernel.h ${CMAKE_SOURCE_DIR}/plugin/customClipPlugin.h ) # Use C++11 target_compile_features(clipplugin PUBLIC cxx_std_11) # Link TensorRT's nvinfer lib target_link_libraries(clipplugin PRIVATE ${NVINFER_LIB}) # We need to explicitly state that we need all CUDA files # to be built with -dc as the member functions will be called by # other libraries and executables (in our case, Python inference scripts) set_target_properties(clipplugin PROPERTIES CUDA_SEPARABLE_COMPILATION ON ) $ find / -name pybind* 2> /dev/null $ find / -name cuda* 2> /dev/null $ find / -name libnvinfer.so 2> /dev/null $ find / -name NvInfer.h 2> /dev/null or find / -name NvUffParser.h 2> /dev/null $ which cmake //필요사항 cmake, pybind11 필요 $ sudo apt install cmake $ sudo pip3 install pybind11
- C++ PlugIn Build 진행
$ echo $PATH /home/nvidia/.local/bin:/usr/local/cuda-10.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin // cmake 실행시 CUDACXX 를 /etc/environment 넣거나, CMAKE_CUDA_COMPILER=/usr/local/cuda-10.0/bin/nvcc 설정진행 $ sudo vi /etc/environment PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games" CUDACXX=/usr/local/cuda-10.0/bin/nvcc $ sudo mkdir build && pushd build $ sudo cmake .. or //X86기반 설정을 ARM으로 현재사항에 맞게변경 $ sudo cmake .. \ -DPYBIND11_DIR=/usr/local/include/python3.6/pybind11/ \ -DCUDA_ROOT=/usr/local/cuda-10.0/ \ -DPYTHON3_INC_DIR=/usr/include/python3.6/ \ -DNVINFER_LIB=/usr/lib/aarch64-linux-gnu/libnvinfer.so \ -DTRT_INC_DIR=/usr/include/aarch64-linux-gnu/ \ -DTRT_LIB=/usr/lib/aarch64-linux-gnu/ $ sudo make -j Scanning dependencies of target clipplugin [ 50%] Building CXX object CMakeFiles/clipplugin.dir/plugin/customClipPlugin.cpp.o [ 50%] Building CUDA object CMakeFiles/clipplugin.dir/plugin/clipKernel.cu.o [ 75%] Linking CUDA device code CMakeFiles/clipplugin.dir/cmake_device_link.o [100%] Linking CXX shared module libclipplugin.so [100%] Built target clipplugin $ popd
빌드관련 설정사항 (CUDACXX)
https://github.com/jetsonhacks/buildLibrealsense2TX/issues/13
- MNIST Training과 TEST 진행 후 모델로 저장
$ sudo python3 lenet5.py ...... Epoch 1/10 2019-09-06 15:23:04.843040: I tensorflow/stream_executor/platform/default/dso_loader.cc:42] Successfully opened dynamic library libcublas.so.10.0 60000/60000 [==============================] - 8s 139us/sample - loss: 0.2036 - acc: 0.9403 Epoch 2/10 60000/60000 [==============================] - 8s 126us/sample - loss: 0.0816 - acc: 0.9756 Epoch 3/10 60000/60000 [==============================] - 7s 124us/sample - loss: 0.0525 - acc: 0.9839 Epoch 4/10 60000/60000 [==============================] - 7s 124us/sample - loss: 0.0375 - acc: 0.9879 Epoch 5/10 60000/60000 [==============================] - 7s 122us/sample - loss: 0.0277 - acc: 0.9915 Epoch 6/10 60000/60000 [==============================] - 7s 122us/sample - loss: 0.0223 - acc: 0.9928 Epoch 7/10 60000/60000 [==============================] - 7s 122us/sample - loss: 0.0158 - acc: 0.9948 Epoch 8/10 60000/60000 [==============================] - 7s 123us/sample - loss: 0.0152 - acc: 0.9949 Epoch 9/10 60000/60000 [==============================] - 7s 122us/sample - loss: 0.0104 - acc: 0.9969 Epoch 10/10 60000/60000 [==============================] - 7s 123us/sample - loss: 0.0119 - acc: 0.9961 10000/10000 [==============================] - 1s 73us/sample - loss: 0.0810 - acc: 0.9800 Test loss: 0.08098314766188651 Test accuracy: 0.9800000190734863 W0906 15:24:20.296670 547944542224 ............................
- 생성된 모델을 이용하여 예측 테스트
생성된 모델을 읽어서 Custom Layer를 적용후 Test Case와 예측 Case를 비교
$ sudo python3 sample.py ...... UFF Version 0.6.3 === Automatically deduced input nodes === [name: "InputLayer" op: "Placeholder" attr { key: "dtype" value { type: DT_FLOAT } } attr { key: "shape" value { shape { dim { size: -1 } dim { size: 1 } dim { size: 28 } dim { size: 28 } } } } ] ========================================= Using output node OutputLayer/Softmax Converting to UFF graph Warning: No conversion function registered for layer: CustomClipPlugin yet. Converting trt_relu6 as custom op: CustomClipPlugin W0906 15:26:19.200886 548537745424 deprecation_wrapper.py:119] From /usr/lib/python3.6/dist-packages/uff/converters/tensorflow/converter.py:179: The name tf.AttrValue is deprecated. Please use tf.compat.v1.AttrValue instead. DEBUG: convert reshape to flatten node No. nodes: 13 UFF Output written to /usr/src/tensorrt/samples/python/uff_custom_plugin/models/trained_lenet5.uff UFF Text Output written to /usr/src/tensorrt/samples/python/uff_custom_plugin/models/trained_lenet5.pbtxt === Testing === Loading Test Case: 6 Prediction: 6 $ ls models // models directory 생성되었으며, pb/uff 파일 생성 trained_lenet5.pb trained_lenet5.pbtxt trained_lenet5.uff
2. TensorRT Python Custom Layer(C++) 소스
왜 Tensorflow의 Layer 중 TensorRT로 사용시 제약사항있어 Custom Layer를 사용할까?
그리고, 언제 사용되는지에 대해 구체적으로 알고 싶었다.
우선 아래의 소스는 TensorRT가 ReLU6를 미지원해서 이를 Custom Layer를 재정의하여 사용하는 구조이다
- ReLU/ReLU6 의 차이
- Relu y = max(x ,0) 그래프, x좌표가 0기반으로 y좌표 증가
- Relu6 y = min(max(x, 0), 6) 그래프, x좌표가 0기반으로 y좌표 증가 x좌표의 6까지 한계
https://woolulu.tistory.com/84
https://www.tensorflow.org/api_docs/python/tf/nn/relu
https://www.tensorflow.org/api_docs/python/tf/nn/relu6
http://www.cs.utoronto.ca/~kriz/conv-cifar10-aug2010.pdf
- Tensorflow와 TensorRT 제약사항
우선 TensorRT의 제약사항을 아래에서 확인가능하다
그리고, 두번째 Site에서 Tensorflow의 UFF Parser 지원사항을 보면 ReLU6 지원가능을 볼수 있다
이렇게 보면 TensorRT도 지원가능할 것 같지만, 이것은 UFF Parser까지만 인식가능가능하다는 말이다
https://docs.nvidia.com/deeplearning/sdk/tensorrt-support-matrix/index.html
https://docs.nvidia.com/deeplearning/sdk/tensorrt-support-matrix/index.html#supported-ops
UFF에서 인식가능
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/python_api/uff/Operators.html?highlight=relu#activation
- TensorRT API C++/Python 확인 (Activition Layer에서 ReLu만 지원)
Python의 API를 보면 더 쉽다
https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#layers
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/c_api/classnvinfer1_1_1_i_activation_layer.html
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/c_api/namespacenvinfer1.html#acbd177748000d30ae0277ee980757eb6
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/python_api/infer/Graph/Layers.html#iactivationlayer
- TensorRT로 Network 직접 구성할때 Relu 예제참조 (C++/Python)
https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#create_network_c
https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#create_network_python
- DLA의 ReLu 제약사항 (참고사항, Xavier만 해당)
2.1 lenet5.py 분석
이전 소스와 거의 유사하지만 아래의 build_model시 network 구조가 다르다고 보면된다
$ cat lenet5.py import tensorflow as tf import numpy as np import os WORKING_DIR = os.environ.get("TRT_WORKING_DIR") or os.path.dirname(os.path.realpath(__file__)) ## 생성될 Model의 저장장소 MODEL_DIR = os.path.join( WORKING_DIR, 'models' ) ## Google mnist data를 download하여 ReShape 진행 def load_data(): mnist = tf.keras.datasets.mnist (x_train, y_train),(x_test, y_test) = mnist.load_data() x_train, x_test = x_train / 255.0, x_test / 255.0 ## 기존과 다르게 reshape를 하여, 1차원을 추가하는데, -1 값이 60000 과 10000로 정의되는 것 같음 ## https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html#numpy.reshape x_train = np.reshape(x_train, (-1, 1, 28, 28)) x_test = np.reshape(x_test, (-1, 1, 28, 28)) return x_train, y_train, x_test, y_test ## Tensorflow Keras를 이용하여 Model의 Network 정의 def build_model(): # Create the keras model model = tf.keras.models.Sequential() model.add(tf.keras.layers.InputLayer(input_shape=[1, 28, 28], name="InputLayer")) model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(512)) ## ReLU6 부분이 TensorRT로 Custom Layer로 재정의 될 부분이다 ## TensorRT는 ReLU6을 지원하지 못하므로, 이 부분을 C++로 PlugIn으로 재정의하고 Custom Layer로 구현한다 ## https://devtalk.nvidia.com/default/topic/1037149/tensorrt/relu6-not-supported-in-tensorrt-for-mobilenetv2/ model.add(tf.keras.layers.Activation(activation=tf.nn.relu6, name="ReLU6")) model.add(tf.keras.layers.Dense(10, activation=tf.nn.softmax, name="OutputLayer")) return model ## Model의 Build 부터 설정 부터 Training def train_model(): ## 기본 Network 정의 # Build and compile model model = build_model() model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) ## Model의 TESTSET의 Download와 설정변경 # Load data x_train, y_train, x_test, y_test = load_data() ## 실제 Training 할 숫자 정의, epochs , verbose는 1은 Prograss bar 설정 # Train the model on the data model.fit( x_train, y_train, epochs = 10, verbose = 1 ) ## 실제 Training 과 TEST 진행 # Evaluate the model on test data test_loss, test_acc = model.evaluate(x_test, y_test) print("Test loss: {}\nTest accuracy: {}".format(test_loss, test_acc)) return model ## Save Model를 위해서 Mkdir def maybe_mkdir(dir_path): if not os.path.exists(dir_path): os.makedirs(dir_path) ## Training/Test가 된 model을 freezing 하여 저장 def save_model(model): output_names = model.output.op.name sess = tf.keras.backend.get_session() graphdef = sess.graph.as_graph_def() frozen_graph = tf.graph_util.convert_variables_to_constants(sess, graphdef, [output_names]) frozen_graph = tf.graph_util.remove_training_nodes(frozen_graph) # Make directory to save model in if it doesn't exist already maybe_mkdir(MODEL_DIR) model_path = os.path.join(MODEL_DIR, "trained_lenet5.pb") with open(model_path, "wb") as ofile: ofile.write(frozen_graph.SerializeToString()) if __name__ == "__main__": ## Model 생성부터 Training/Test 관련 설정 과 Training/Test 진행 model = train_model() ## 생성된 Model 저장 save_model(model)
- Tensorflow Keras model 관련함수
https://www.tensorflow.org/api_docs/python/tf/keras/Sequential
2.2 sample.py 분석
$ cat sample.py import sys import os import ctypes from random import randint from PIL import Image import numpy as np import tensorflow as tf import pycuda.driver as cuda import pycuda.autoinit import tensorrt as trt import graphsurgeon as gs import uff # ../common.py sys.path.insert(1, os.path.join( os.path.dirname(os.path.realpath(__file__)), os.pardir ) ) import common # lenet5.py import lenet5 # MNIST dataset metadata MNIST_IMAGE_SIZE = 28 MNIST_CHANNELS = 1 MNIST_CLASSES = 10 WORKING_DIR = os.environ.get("TRT_WORKING_DIR") or os.path.dirname(os.path.realpath(__file__)) # Path where clip plugin library will be built (check README.md) CLIP_PLUGIN_LIBRARY = os.path.join( WORKING_DIR, 'build/libclipplugin.so' ) # Path to which trained model will be saved (check README.md) MODEL_PATH = os.path.join( WORKING_DIR, 'models/trained_lenet5.pb' ) # Define global logger object (it should be a singleton, # available for TensorRT from anywhere in code). # You can set the logger severity higher to suppress messages # (or lower to display more messages) TRT_LOGGER = trt.Logger(trt.Logger.WARNING) ## 기본설정된 정의는 이곳에서 모두 확인 # Define some global constants about the model. class ModelData(object): INPUT_NAME = "InputLayer" INPUT_SHAPE = (MNIST_CHANNELS, MNIST_IMAGE_SIZE, MNIST_IMAGE_SIZE) RELU6_NAME = "ReLU6" OUTPUT_NAME = "OutputLayer/Softmax" OUTPUT_SHAPE = (MNIST_IMAGE_SIZE, ) DATA_TYPE = trt.float32 ## TensorRT의 Custom Layer 연결부분 (핵심) # Generates mappings from unsupported TensorFlow operations to TensorRT plugins def prepare_namespace_plugin_map(): # In this sample, the only operation that is not supported by TensorRT # is tf.nn.relu6, so we create a new node which will tell UffParser which # plugin to run and with which arguments in place of tf.nn.relu6. ## Model의 ReLU6 -> trt_relu6 Layer 재정의하고 , 이 부분을 C++에서 Custom Layer에 연결구현 ## customClipPlugin.cpp의 CustomClipPlugin 연결하며, clipMin ,clipMax Argument로 설정 Plugin의 Arg ## IPluginV2 C++ Class 의 Override로 구현(customClipPlugin.cpp)하고 있으며, 아래의 TensorRT C++ 참조 ## https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/c_api/classnvinfer1_1_1_i_plugin_v2.html ## python API- create_plugin_node ## https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/python_api/graphsurgeon/graphsurgeon.html ## https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#graphsurgeon ## 상위 C++ 소스는 iPlugInv2를 사용하며, 이로 재정의한다 ## iPlugIn도 Python API가 있는데, C++ 예제만 있으니, 이소스의 한계는 여기까지이다. ## clipMax/clipMin 값은 상위 Relu/Relu6의 차이를 보면될 것 같다 # The "clipMin" and "clipMax" fields of this TensorFlow node will be parsed by createPlugin, # and used to create a CustomClipPlugin with the appropriate parameters. trt_relu6 = gs.create_plugin_node(name="trt_relu6", op="CustomClipPlugin", clipMin=0.0, clipMax=6.0) namespace_plugin_map = { ModelData.RELU6_NAME: trt_relu6 } return namespace_plugin_map ## PB파일이름을 UFF파일으로 변경 # Transforms model path to uff path (e.g. /a/b/c/d.pb -> /a/b/c/d.uff) def model_path_to_uff_path(model_path): uff_path = os.path.splitext(model_path)[0] + ".uff" return uff_path ## PB파일을 UFF로 변경하는 것으로 PB파일과 PlugIN 정보 # Converts the TensorFlow frozen graphdef to UFF format using the UFF converter def model_to_uff(model_path): ## Model의 Layer 중 ReLU6 이 부분을 C++ PlugIn으로 연결하고 재정의 # Transform graph using graphsurgeon to map unsupported TensorFlow # operations to appropriate TensorRT custom layer plugins dynamic_graph = gs.DynamicGraph(model_path) dynamic_graph.collapse_namespaces(prepare_namespace_plugin_map()) ## UFF File로 저장 # Save resulting graph to UFF file output_uff_path = model_path_to_uff_path(model_path) uff.from_tensorflow( dynamic_graph.as_graph_def(), [ModelData.OUTPUT_NAME], output_filename=output_uff_path, text=True ) return output_uff_path ## Build TensorRT Engine이며, Pb파일을 UFF로 변경하고 이를 기준으로 정의 # Builds TensorRT Engine def build_engine(model_path): with trt.Builder(TRT_LOGGER) as builder, builder.create_network() as network, trt.UffParser() as parser: builder.max_workspace_size = common.GiB(1) ## PB를 UFF로 변경 상위 함수 호출 uff_path = model_to_uff(model_path) ## INPUT_SHAPE 1,28,28로 설정 parser.register_input(ModelData.INPUT_NAME, ModelData.INPUT_SHAPE) parser.register_output(ModelData.OUTPUT_NAME) parser.parse(uff_path, network) ## TensorRT Engine 생성 return builder.build_cuda_engine(network) ## pagelocked_buffer는 Host(CPU) input buffer에 Data 저장 하고 random으로 test case를 설정하고 이 결과를 반환 # Loads a test case into the provided pagelocked_buffer. Returns loaded test case label. def load_normalized_test_case(pagelocked_buffer): _, _, x_test, y_test = lenet5.load_data() num_test = len(x_test) case_num = randint(0, num_test-1) img = x_test[case_num].ravel() np.copyto(pagelocked_buffer, img) return y_test[case_num] def main(): ## PlugIn File 없으면, 에러처리 # Load the shared object file containing the Clip plugin implementation. # By doing this, you will also register the Clip plugin with the TensorRT # PluginRegistry through use of the macro REGISTER_TENSORRT_PLUGIN present # in the plugin implementation. Refer to plugin/clipPlugin.cpp for more details. if not os.path.isfile(CLIP_PLUGIN_LIBRARY): raise IOError("\n{}\n{}\n{}\n".format( "Failed to load library ({}).".format(CLIP_PLUGIN_LIBRARY), "Please build the Clip sample plugin.", "For more information, see the included README.md" )) ## PlugIn을 동적 라이브러리 연결 ctypes.CDLL(CLIP_PLUGIN_LIBRARY) ## 학습된 Model이 없으면 에러 발생 # Load pretrained model if not os.path.isfile(MODEL_PATH): raise IOError("\n{}\n{}\n{}\n".format( "Failed to load model file ({}).".format(MODEL_PATH), "Please use 'python lenet5.py' to train and save the model.", "For more information, see the included README.md" )) ## build_engine 함수 호출 # Build an engine and retrieve the image mean from the model. with build_engine(MODEL_PATH) as engine: ## 기존의 common.py 참조하면, host(CPU) /device(GPU) buffer 할당 inputs, outputs, bindings, stream = common.allocate_buffers(engine) ## Engine 생성 with engine.create_execution_context() as context: ## 기존과 동일하게 host(CPU) 정보를 넣고, Random으로 설정한 test_case 표시 print("\n=== Testing ===") test_case = load_normalized_test_case(inputs[0].host) print("Loading Test Case: " + str(test_case)) ## common.py의 inference해서 얻은 결과 표시하여 상위 값과 비교 # The common do_inference function will return a list of outputs - we only have one in this case. [pred] = common.do_inference(context, bindings=bindings, inputs=inputs, outputs=outputs, stream=stream) print("Prediction: " + str(np.argmax(pred))) if __name__ == "__main__": main()
3. TensorRT Python Custom Layer(Python) 소스
상위 구현된 IPluginV2와 관련된 함수를 Python으로 구현을 한번 해보자
아래와 같이 Python으로도 IPlugInV2를 지원을 해주고 있다
Python의 iPlugInv2 부분 아래 주소
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/python_api/infer/Plugin/pyPlugin.html
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/python_api/infer/Plugin/IPluginV2.html
다음은 Custom Layer의 예제 C++과 Python의 예제를 다루고 있다
Custom Layer C++ Example
https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#add_custom_layer
3.1 Python Custom Layer Example
Python Custom Layer Example은 이곳을 보면 되고 구성은 두개로 나뉘어 지면, 연결하는 Interface인 IPlugin에 관련되어서만 서술하고 있다.
Custom Layer의 구현에 대해서 별다른 이야기가 없다
TensorRT Manual이 계속 변경되니, 추후에 예제도 추가될지도 모른다
https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#add_custom_layer_python
- Layer를 새롭게 정의하여 Network에 추가방식 (IPluginCreator)
Layer의 구체적인 동작방식은 정의하지 않았다 (동작방식은 C++로 구현?)
https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#example1_add_custom_layer_python
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/python_api/infer/Plugin/IPluginCreator.html
https://docs.nvidia.com/deeplearning/sdk/tensorrt-api/python_api/infer/Graph/Network.html?highlight=add_plugin_v2#tensorrt.INetworkDefinition.add_plugin_v2
- UFF Parser에 존재하는 Layer를 재정의해서 구현하는 방식 (IPluginV2)
https://docs.nvidia.com/deeplearning/sdk/tensorrt-developer-guide/index.html#example2_add_custom_layer_no_uff_python
만약 상위 소스를 Python으로만 수정한다면 PlugIn의 Custom Layer부분이 Serialize가 되어야 할 것인데, 이 부분이 어떻게 될까 한번 생각해보면, 일단
C++은 Compiler라서 이미 Binary이기때문에 Serialize가 쉽지만, Python은 Interpreter 이므로 PlugIn을 Python으로 구현하면 성능뿐만 아니라, 동작구현에도 어려움이 있을 것 같다
내 개인생각으로는 PlugIn은 Python으로 해도, 동작방식(Custom Layer)은 C++으로 구현을 해야할 것 같다
이 부분은 생각해볼만한 문제이며, 만약 순수 Python 구현된 Custom Layer 예제가 나오면 어떻게 나올지 궁금하다