dusty-nv/jetson-inference 譯

前言

此篇文章僅為在學習過程中順手翻譯,由於本人英文能力甚差,故翻譯可能會較多錯誤或不通順之處,若有還煩請來信告知,感謝!

另外,由於原專案 README.md 中有部分可能因 JetPack 更新或其他因素導致有其他作法或修正,故本人會以 Holey: 來表示當前狀況或額外註解,使翻譯內容盡量與原內容相符。

在本篇之前開始,建議先閱讀 NVIDIA Jetson TX2 環境部署 以進行組件與系統安裝的動作。


NVIDIA JETSON TX2

安裝 NVIDIA 驅動於本機

在這一節上,JetPack 將會刷新 Jetson 的 L4T BSP,並在 Jetson 與本機上安裝 CUDA 工具包。然而, NVIDIA PCIe 驅動仍需要安裝在主機上才能啟動 GPU 加速訓練。從主機執行以下命令以從 Ubuntu repo 安裝 NIVDIA 驅動程式:

1
2
$ sudo apt-get install nvidia-375
$ sudo reboot

重新開機之後,NVIDIA 驅動程式應該將會列表在 lsmod 下:

1
2
3
4
5
6
7
$ lsmod | grep nvidia
nvidia_uvm 647168 0
nvidia_drm 49152 1
nvidia_modeset 790528 4 nvidia_drm
nvidia 12144640 60 nvidia_modeset,nvidia_uvm
drm_kms_helper 167936 1 nvidia_drm
drm 368640 4 nvidia_drm,drm_kms_helper

若要驗證 CUDA 工具包以及 NVIDIA 驅動程式是否能運作,可以執行 CUDA 所提供的一些測試樣本:

1
2
3
4
5
$ cd /usr/local/cuda/samples
$ sudo make
$ cd bin/x86_64/linux/release/
$ ./deviceQuery
$ ./bandwidthTest --memory=pinned

安裝 cuDNN 於本機

下一個步驟是安裝 NVIDIA cuDNN 函式庫於本機上。從 NVIDIA 網站下載 libcudnn 與 libcudnn 組件:

1
2
https://developer.nvidia.com/compute/machine-learning/cudnn/secure/v6/prod/8.0_20170307/Ubuntu16_04_x64/libcudnn6_6.0.20-1+cuda8.0_amd64-deb
https://developer.nvidia.com/compute/machine-learning/cudnn/secure/v6/prod/8.0_20170307/Ubuntu16_04_x64/libcudnn6-dev_6.0.20-1+cuda8.0_amd64-deb

接著執行以下命令以安裝這些組件:

1
2
$ sudo dpkg -i libcudnn6_6.0.20-1+cuda8.0_amd64.deb
$ sudo dpkg -i libcudnn6-dev_6.0.20-1+cuda8.0_amd64.deb

安裝 NVcaffe 於本機

NVcaffe 是 Caffe 的 NVIDIA 分支,且針對 GPU 進行了優化。NVcaffe 使用 cuDNN 並用於訓練 DNNs。為了安裝它,需要先從 Github 上 Clone NVcaffe repo 並編譯來源,以下使用 NVcaffe-0.15。

note: 對於本節,NVcaffe 只需要在主機上(用於訓練),在推理(inferencing)階段,Jetson 使用 TensorRT 而不需要 caffe。

在安裝 Caffe 之前需要先安裝一些必要組件,包括 DIGITS 所需要的 Python 連結(Python bindings):

1
2
3
4
5
6
7
8
9
10
$ sudo apt-get install --no-install-recommends build-essential cmake git gfortran libatlas-base-dev libboost-filesystem-dev libboost-python-dev libboost-system-dev libboost-thread-dev libgflags-dev libgoogle-glog-dev libhdf5-serial-dev libleveldb-dev liblmdb-dev libprotobuf-dev libsnappy-dev protobuf-compiler python-all-dev python-dev python-h5py python-matplotlib python-numpy python-opencv python-pil python-pip python-protobuf python-scipy python-skimage python-sklearn python-setuptools
$ sudo pip install --upgrade pip
$ git clone -b caffe-0.15 http://github.com/NVIDIA/caffe
$ cd caffe
$ sudo pip install -r python/requirements.txt
$ mkdir build
$ cd build
$ cmake ../ -DCUDA_USE_STATIC_CUDA_RUNTIME=OFF
$ make --jobs=4
$ make pycaffe

至此,Caffe 應可被配置與建構。現在編輯用戶下的 ~/.bashrc 來引入 Caffe tree 的路徑(記得替換路徑為自己的):

1
2
export CAFFE_ROOT=/home/dusty/workspace/caffe
export PYTHONPATH=/home/dusty/workspace/caffe/python:$PYTHONPATH

接著關閉並重新開啟終端機(Terminal)來讓變更生效。

安裝 DIGITS 於本機

NVIDIA DIGITS 是基於 Python 的 Web 服務,可以交互式訓練 DNNs 並管理資料檔案。在 DIGITS 的工作流程中,它在主機上執行並在訓練階段時建立網路模型,接著將受過訓練的模型從主機複製到 Jetson,以用於運行 TensorRT 的推理階段。

在安裝 DIGITS 之前先安裝需要的組件,接著再從 Github Clone DIGITS repo:

1
2
3
4
$ sudo apt-get install --no-install-recommends graphviz python-dev python-flask python-flaskext.wtf python-gevent python-h5py python-numpy python-pil python-pip python-protobuf python-scipy python-tk
$ git clone http://github.com/nvidia/DIGITS
$ cd DIGITS
$ sudo pip install -r requirements.txt

啟動 DIGITS 伺服器

假設你的終端機仍然在 DIGITS 目錄中,則可以通過執行 digits-devserver 的 Python 腳本來啟動 Web 伺服器:

1
2
3
4
5
6
7
$ ./digits-devserver
___ ___ ___ ___ _____ ___
| \_ _/ __|_ _|_ _/ __|
| |) | | (_ || | | | \__ \
|___/___\___|___| |_| |___/ 5.1-dev

2017-04-17 13:19:02 [INFO ] Loaded 0 jobs.

DIGITS 將會儲存使用者的工作(訓練資料檔案和模型快照)在 digits\jobs 資料夾下。

開啟瀏覽器並進入 0.0.0.0:5000 可以訪問交互式 DIGITS 對話。

note: DIGITS 伺服器預設為使用 port 5000,若要修改可在使用 digits-devserver 腳本時加入 --port 參數來自定義。

Building from Source on Jetson

Provided along with this repo are TensorRT-enabled deep learning primitives for running Googlenet/Alexnet on live camera feed for image recognition, pedestrian detection networks with localization capabilities (i.e. that provide bounding boxes), and segmentation. This repo is intended to be built & run on the Jetson and to accept the network models from the host PC trained on the DIGITS server.

最新的版本可以在 Github 上取得並在 Jetson TX1/TX2 上編譯。

note: 這個分支是針對以下 BSP 版本進行驗證:

  • Jetson TX2 - JetPack 3.0 / L4T R27.1 aarch64 (Ubuntu 16.04 LTS)
  • Jetson TX1 - JetPack 2.3 / L4T R24.2 aarch64 (Ubuntu 16.04 LTS)
  • Jetson TX1 - JetPack 2.3.1 / L4T R24.2.1 aarch64 (Ubuntu 16.04 LTS)

Clone the Repo

在取得這個 repository 之前,先確定選擇的資料夾是 Jetson。首先,確認 git 和 cmake 在本機是已經安裝的:

1
$ sudo apt-get install git cmake

Holey: 若出現問題建議可先 sudo apt-get update 再次嘗試安裝

接著 Clone jetson-inference 的 repo:

1
$ git clone http://github.com/dusty-nv/jetson-inference

配置 CMake

當 cmake 已在運作,可以運行一個特別的安裝腳本(CMakePreBuild.sh)來自動安裝任何相依項(dependencies)。

1
2
3
4
$ cd jetson-inference
$ mkdir build
$ cd build
$ cmake ../

note: cmake 命令在啟動 CMakePrebuild.sh 腳本時將會要求 sudo 以確保先決條件組件已安裝在 Jetson 上。該腳本也會從 Web 服務下載網路模型快照。

編譯專案

請先確認資料夾仍然在 jetson-inference/build,若是則直接執行第二項命令:

1
2
$ cd jetson-inference/build			# omit if pwd is already /build from above
$ make

根據不同的架構,組件將會被構建為 armhfaarch64,並具有以下目錄結構:

1
2
3
4
5
6
7
8
9
|-build
\aarch64 (64-bit)
\bin where the sample binaries are built to
\include where the headers reside
\lib where the libraries are build to
\armhf (32-bit)
\bin where the sample binaries are built to
\include where the headers reside
\lib where the libraries are build to

位於 aarch64/bin 的二進制文件,其標頭在 aarch64/include,函式庫則在aarch64/lib

Digging Into the Code (這段不翻)

For reference, see the available vision primitives, including imageNet for image recognition and detectNet for object localization.

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
/*
* Image recognition with GoogleNet/Alexnet or custom models, using TensorRT.
*/
class imageNet : public tensorNet
{
public:
/**
* Network choice enumeration.
*/
enum NetworkType
{
ALEXNET,
GOOGLENET
};

/**
* Load a new network instance
*/
static imageNet* Create( NetworkType networkType=GOOGLENET );

/**
* Load a new network instance
* @param prototxt_path File path to the deployable network prototxt
* @param model_path File path to the caffemodel
* @param mean_binary File path to the mean value binary proto
* @param class_info File path to list of class name labels
* @param input Name of the input layer blob.
*/
static imageNet* Create( const char* prototxt_path, const char* model_path, const char* mean_binary,
const char* class_labels, const char* input="data", const char* output="prob" );

/**
* Determine the maximum likelihood image class.
* @param rgba float4 input image in CUDA device memory.
* @param width width of the input image in pixels.
* @param height height of the input image in pixels.
* @param confidence optional pointer to float filled with confidence value.
* @returns Index of the maximum class, or -1 on error.
*/
int Classify( float* rgba, uint32_t width, uint32_t height, float* confidence=NULL );
};

Both inherit from the shared tensorNet object which contains common TensorRT code.

以 ImageNet 進行圖片分類

有多種類型的深度學習網路可使用,包括識別、擷取/局部和立即分割。在本節中強調的第一個深度學習能力是使用已被訓練用來識別類似對象的 imageNet 的圖片識別。

imageNet 接受輸入圖片並輸出每個類別的相似度,目前已經有 1000 個對象在 ImageNet 數據庫上進行過訓練。而標準的 AlexNet 和 GoogleNet 網路已經在上面的步驟 2 中下載。而我們提供一個名為 imagenet-console 的命令列介面和一個名為 imagenet-camera 的即時相機程式作為使用 imageNet 的示例。

使用 Console Program 於 Jetson 上

首先,試著使用 imagenet-console 程式在一些測試圖片上測試 imageNet 識別。它會讀取圖片,使用 TensorRT 和 imageNet 類來執行推理,接著在圖片上印上分類並儲存輸出的圖片。

在 building 之後,先確認你的終端機在 aarch64/bin 資料夾下:

1
$ cd jetson-inference/build/aarch64/bin

接著就可以利用 imagenet-console 來分類測試圖片。imagenet-console 接收兩個命令列參數:輸入圖片的路徑和輸出圖片(印上分類)的路徑。

1
./imagenet-console orange_0.jpg output_0.jpg

classify an orange image with the imagenet-console

1
$ ./imagenet-console granny_smith_1.jpg output_1.jpg

classify an granny smith image with the imagenet-console

接著,我們將使用 imageNet 來分類來自 Jetson 上的相機所得到的即時影像。

進行即時相機識別演示

與上一個例子類似,即時圖片識別演示(realtime image recognition demo)位於 arrch64/bin 中,稱為 imagenet-camera。它在即時相機串流(live camera stream)上執行且根據使用者給予的參數,以 TensorRT 加載 googlenetalexnet

1
2
$ ./imagenet-camera googlenet           # to run using googlenet
$ ./imagenet-camera alexnet # to run using alexnet

幀率(Frame per Second,FPS)、物件類別名稱和相似度將會印於 openGL 視窗的標題列。在預設情況下,程式可以識別多達 1000 種不同類型的物件,這是因為 Googlenet 和 Alexnet 在 ILSVRXC12 ImageNet 資料庫上進行了訓練,而該資料庫包含 1000 種物件。這 1000 種物件類型的名稱可以在 repo 中的 data/networks/ilsvrc12_synset_words.txt 找到。

note: 預設情況下,Jetson 開發版所搭載的 CSI 視訊鏡頭將會被用做視訊源,如果你希望使用 USB 攝影機,請更改 imagenet-camera.cpp 頂部的 DEFAULT_CAMERA 定義,以對應在 /dev/video V4L2 裝置中你的 USB 攝影機。在下方測試中使用的設備型號是 Logitech C920。

Holey: 目前在 openGL 視窗上,標題列僅會顯示 FPS,而物件類別名稱和相似度將會直接印於視窗上。

classify an orange with the imagenet-camera

classify an granny smith with the imagenet-camera

利用 DIGITS 重新訓練網路

從 repo 所下載的現有 GoogleNet 與 AlexNet 模型是由 ImageNet ILSVRC23 基準測試所預先訓練的 1000 種物件類別。

若要識別一個新的物件類別,可以使用 DIGITS 來重新對網路進行新的數據訓練。你還可以將現有的物件類別以不同的方式組織,包括將多個子類別組合成一個子類別。例如,在本教學中,我們將使用 1000 個類別中的 230 個,將它們分組到 12 個類別中並重新訓練網路。

讓我們先從下載 ILSVRC12 圖片開始,或者將自己的數據集替換進圖片資料夾。

下載圖片識別數據集

圖像識別數據集是由大量按其分類類型(通常按目錄)排序的圖片所組成。ILSVRC12 數據集是用於訓練預設的 GoogleNet 和 AlexNet 模型,它的大小約為 100GB,包括 1000 多種不同的類別的 100 萬張圖片。數據集將會使用 imagenet-download.py 圖片爬蟲來下載到 DIGITS 伺服器。

為了下載數據集,首先必須確定你的 DIGITS 伺服器有足夠的硬碟空間(建議為 120GB),接著在你希望儲存數據集的伺服器資料夾上執行以下命令:

1
2
3
4
$ wget --no-check-certificate https://nvidia.box.com/shared/static/gzr5iewf5aouhc5exhp3higw6lzhcysj.gz -O ilsvrc12_urls.tar.gz
$ tar -xzvf ilsvrc12_urls.tar.gz
$ wget https://rawgit.com/dusty-nv/jetson-inference/master/tools/imagenet-download.py
$ python imagenet-download.py ilsvrc12_urls.txt . --jobs 100 --retry 3 --sleep 0

在上面的命令中,在啟動爬蟲程序之前會先下載圖片 URL 清單以及腳本。

note: 由公司網路執行圖片爬蟲時需要注意 IT 可能會標記這項動作。It will probably take overnight on a decent connection to download the 1000 ILSVRC12 classes (100GB).

爬蟲將會下載圖片至其對應的分類子目錄中。每個圖片類別都儲存在自己的目錄中,共有 1000 個目錄(ILSVRC12 中的每個類別各一個)。資料夾的命名方式類似於:

1
2
3
4
5
6
n01440764/
n01443537/
n01484850/
n01491361/
n01494475/
...

這些資料夾的 8 位數字 ID 被稱為類別的 synset ID,該類別的名稱字串可以在 ilsvrc12_synset_words.txt 查詢。例如:synset n01484850 great white shark

自訂物件類別

我們在上一步中下載的數據集,用來自不同核心類群的 1000 個物件類別來訓練預設的 AlexNet 與 GoogleNet 模型,包括不同種類的鳥、植物、水果、魚、狗、貓、車輛類型等。為了實現目的,我們可以考慮 GoogleNet 的伴隨模型,該模型識別了由原始的 1000 個類別所組成的十幾個核心類群(例如將 122 種不同品種的狗全部組合為一個普通的狗類型)。這 12 個核心類群可能比 1000 個單獨的 synsets 更加實用,且跨類別的組合可以獲得更多的訓練數據和更強的群體分類。

DIGITS 會從資料夾結構來取得數據,因此我們可以建立群組目錄,然後象徵性地連接到上面所下載的 ILSVRC12 的 synsets。DIGITS 將自動組合根目錄下所有資料夾中的圖片。目錄結構類似於下面的內容,括號中的值表示用於組成群組的類型數量,箭頭旁邊的值為指示連結到的 synset ID。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
‣ ball/  (7)
• baseball (→n02799071)
• basketball (→n02802426)
• soccer ball (→n04254680)
• tennis ball (→n04409515)
• ...
‣ bear/ (4)
• brown bear (→n02132136)
• black bear (→n02133161)
• polar bear (→n02134084)
• sloth bear (→n02134418)
• bike/ (3)
• bird/ (17)
• bottle/ (7)
• cat/ (13)
• dog/ (122)
• fish/ (5)
• fruit/ (12)
• turtle/ (5)
• vehicle/ (14)
• sign/ (2)

既然實際上有很多從 ILSVRC12 連結到的 synsets,我們提供了 imagenet-subset.sh 腳本,以生成目錄結構和指定給數據集的路徑連結,從 DIGITS 伺服器執行以下命令:

1
2
3
4
$ wget https://rawgit.com/dusty-nv/jetson-inference/master/tools/imagenet-subset.sh
$ chmod +x imagenet-subset.sh
$ mkdir 12_classes
$ ./imagenet-subset.sh /opt/datasets/imagenet/ilsvrc12 12_classes

在這個範例中,連結將會建立在 12_classed 資料夾中,而腳本的第一個參數則是上一步下載的 ILSVRC12 路徑。

References