[深度學習] 超長文,一篇講完 NVIDIA Jetson Hello AI World 全部教程(推理 & 訓練)
一、開始
規格頁面:https://developer.nvidia.com/embedded/jetson-tx1
從 GetStart 頁面:
- 找到我們這一款設備,點擊用戶指南,發現分別存檔了 23.1/23.2/24.1 三個版本;
- 發現官方建議學習順序是:購買套件 -> Hello AI World 教程 / Jetson AI 課程和認證 -> 注冊開發者在論壇提問 -> 在社區尋找靈感;
- 在 Tutorials / Resources 可以逐步深入;
1.1 安裝
發現:
- Jetson Nano、Orin Nano 和 Xavier NX 可以 SD 卡刷入系統
- Jetson TX1/TX2、AGX Xavier 和 AGX Orin 需要 NVIDIA SDK Manager
發現:
-
1)windows 版本的 sdk manager 不支持 jetson tx1 所需要的 sdk
-
2)不要直接下載指導文檔中的 sdkmanger 鏈接,其版本太老,會有問題
-
3)ubuntu 版本的 sdkmanger 支持:ubuntu1804, ubuntu2004, ubuntu2204, ubuntu2404
需要參考:https://developer.nvidia.com/sdk-manager#installation_get_startedwget https://developer.download.nvidia.com/compute/cuda/repos/[distro]/x86_64/cuda-keyring_1.1-1_all.deb sudo dpkg -i cuda-keyring_1.1-1_all.deb sudo apt-get update sudo apt-get -y install sdkmanagerPS: 根據自己系統 [distro] 填寫:ubuntu1804, ubuntu2004, ubuntu2204, ubuntu2404
-
4)發現我用的 Jetson TX1 的 SDK 只能再 ubuntu 16.04 和 ubuntu 18.04 上的 sdkmanager 才有
-
5)發現可以用 docker(僅支持 CLI 版本):
sdkmanager 的 docker 非常吃硬盤,因此先評估下 docker 默認存儲位置是否夠用,不夠的話遷移到一個大的地方:
sudo mkdir -p /home/docker_data sudo chown -R root:docker /home/docker_data sudo chmod -R 775 /home/docker_data sudo systemctl stop docker sudo mkdir /etc/docker sudo vim /etc/docker/daemon.json { "data-root": "/home/docker_data" } # 復制數據到新位置 sudo rsync -aP /var/lib/docker/ /home/docker_data/ sudo systemctl start docker在進行下面操作之前,要通過 USB 將開發板與運行 docker 的電腦相連,并且按住 recovery 按鈕,然后短按 reset 按鈕,然后松開 recovery 按鈕(此時在宿主機中運行
sudo lsusb能看到板子已經進入 recovery 模式):# 1)下載 ubuntu18.04 docker image # 2)加載容器: docker load -i sdkmanager-2.3.0.12617-Ubuntu_18.04_docker.tar.gz # 3)創建一個標簽方便用: docker tag sdkmanager:2.3.0.12617-Ubuntu_18.04 sdkmanager:latest # 4)運行: docker run -it --rm sdkmanager --help # 5)查詢 docker run -it --rm sdkmanager --query # 6)根據查詢到的命令安裝: docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb/ -v /dev:/dev -v /media/$USER:/media/nvidia:slave --name JetPack_Jetson_Tx1_Devkit sdkmanager --cli --action install --login-type devzone --product Jetson --version 4.6.6 --target-os Linux --host --target JETSON_TX1_TARGETS --flash --additional-sdk 'DeepStream 6.0.1'
安裝過程非常慢,需要FQ并且網速好,然后就會看到其自動配置宿主電腦和目標電腦。等到目標電腦的 Flash Jetson OS 成功之后,容器會繼續讓裝 Jetson SDK Components:

由于板子被重新刷了固件,從而板子重啟,其會基于 USB 模擬出一個網關,在宿主機器內通過:
ssh btfz@192.168.55.1可以連接,但是如果進入到虛擬機內看 ip 卻發現板子并沒有連接到虛擬機內(此時如果選擇安裝 Jetson SDK Components 會一直報錯):PS: 當您在宿主機上插拔外設(如 USB 設備)時,已運行的容器通常無法自動感知這些變化,因為 Docker 在容器啟動時會固定設備列表。
? Desktop docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c371f5ab0510 sdkmanager "docker-entrypoint.s…" 3 hours ago Up 3 hours JetPack_Jetson_Tx1_Devkit ? Desktop docker exec -it c371f5ab0510 bash # 用來登陸容器看 ip 的 ? Desktop docker commit c371f5ab0510 jetpack_jetson_tx1_devkit:4.6_flash # 46G 很慢,幾十分鐘之后 skip,然后退出之前的容器,然后:
# 宿主機 ssh 連接板子,配置默認連接 wifi,之后退出 ssh btfz@192.168.55.1 sudo nmcli dev wifi # 搜索下,看看周圍是否存在目標 SSID sudo nmcli dev wifi connect "SSID" password "YOUR_PASSWORD" exit # 重新進入容器,繼續安裝組件 docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb/ -v /dev:/dev -v /media/$USER:/media/nvidia:slave --network host jetpack_jetson_tx1_devkit:4.6_flash # 注意:由于只有 16G 空間,無法將所有組件安裝,因此這里最后兩個沒有安裝(Developer Tools、DeepStream) # 最后只剩下 100M,因此需要用下面命令刪除一些沒用的東西: sudo journalctl --vacuum-size=100M sudo apt-get install ncdu sudo ncdu / # 發現:usr/lib/aarch64-linux-gnu/libcudnn* 和 libnvinfer* 占了將近 3.2G # 發現:local/cuda 占了 2G # 發現瀏覽器占了不少,刪除一些占用多的,沒用的軟件: sudo apt-get remove chromium-browser sudo sudo apt-get remove libreoffice sudo apt-get remove thunderbird sudo apt-get clean # 清除安裝留下的垃圾 sudo rm -rf /tmp/* # 清除臨時文件
1.2 sdkmanger 細節介紹
1.2.1 host 和 target 配合
上面 sdkmanger 中包含了兩部分:HOST COMPONENTS 和 TARGET COMPONENTS,這里對這兩個做個詳細介紹:
Host Components:
- 定義:安裝在 開發主機(如 PC 或服務器) 上的組件,用于構建、編譯和部署應用程序。
- 用途:
- 交叉編譯工具鏈:在 x86 主機上編譯適用于 ARM 架構(Jetson 設備)的代碼。
- 開發環境:提供 TensorFlow、PyTorch 等框架的主機版本,用于模型訓練和調試。
- SDK 和庫:如 CUDA Toolkit、cuDNN 等,在主機上模擬 Jetson 的 GPU 環境,加速開發過程。
- 容器支持:配置 Docker 和 NVIDIA Container Runtime,實現容器化開發和部署。
- 示例場景:
- 在 PC 上使用 PyTorch 訓練模型,然后將優化后的模型部署到 Jetson 設備。
- 在主機上編譯 C++ 代碼,通過交叉編譯工具鏈生成可在 Jetson 上運行的二進制文件。
TARGET COMPONENTS:
- 定義:直接安裝到 Jetson 目標設備 上的組件,用于在設備上運行應用程序。
- 用途:
- 基礎系統:L4T(Linux for Tegra)操作系統,包含 Jetson 硬件驅動和內核。
- 運行時環境:CUDA、cuDNN、TensorRT 等庫的嵌入式版本,支持模型推理。
- 應用框架:如 DeepStream、VisionWorks 等,提供特定領域的優化功能。
- 多媒體支持:視頻編解碼庫(NVDEC/NVENC)、GStreamer 插件等。
- 示例場景:
- Jetson Nano 設備上運行 TensorRT 優化后的目標檢測模型。
- Jetson AGX Orin 實時處理多路攝像頭視頻流(需 DeepStream 和 Multimedia 組件)。
如何選擇?
- 開發階段:需要同時安裝 Host Components 和 TARGET COMPONENTS
- 在主機上開發和編譯代碼
- 將編譯好的應用部署到 Jetson 設備測試。
- 生產部署:通常只需要 TARGET COMPONENTS
- Jetson 設備作為獨立運行單元,只需安裝運行時依賴
1.2.2 Jetson SDK Components 介紹
| 名字 | 定位 | 功能 | 應用 |
|---|---|---|---|
| CUDA | 并行計算平臺和編程模型 | 提供 C/C++、Fortran 等編程語言的接口,使開發者能夠直接控制 GPU 資源,實現高效的并行算法 | 矩陣運算、深度學習模型訓練(底層算力支持)、計算流體動力學等 |
| CUDA-X AI | 基于 CUDA 的人工智能擴展庫集合 | cuDNN:深度學習神經網絡庫,優化卷積、池化、歸一化等操作,加速 TensorFlow、PyTorch 等框架的模型訓練和推理 cuML:機器學習庫,提供支持 GPU 加速的分類、聚類、回歸等算法(如隨機森林、PCA) Rapids:數據科學工具包,支持 GPU 加速的數據處理、分析和機器學習工作流 |
自動駕駛模型訓練、自然語言處理、推薦系統開發 |
| Computer Vision | 計算機視覺算法和工具集合 | OpenCV for Jetson:優化版 OpenCV,針對 Jetson GPU 加速圖像和視頻處理,支持特征檢測、圖像分割、目標跟蹤等 VisionWorks:NVIDIA 自研視覺庫,提供底層加速的視覺原語(如光流計算、立體視覺) TensorRT Vision Plugins:結合 TensorRT 的視覺推理優化插件,加速目標檢測、姿態估計等任務 |
工業質檢(缺陷檢測)、無人機視覺導航、醫療影像分析 |
| NVIDIA Container Runtime | 容器運行時環境,支持在 Jetson 上部署容器化應用 | 允許開發者將應用及其依賴打包為 Docker 容器,實現跨環境的一致性部署 支持 GPU 資源的隔離和分配,確保多個容器化應用高效利用 Jetson 的硬件資源 |
多任務并行開發(如同時運行視覺處理和深度學習服務)、邊緣設備的應用隔離部署 |
| Multimedia | 多媒體處理和編解碼組件 | NVDEC/NVENC:硬件加速的視頻解碼 / 編碼引擎,支持 H.264、H.265 等格式,降低 CPU 負載 MediaSDK:提供 API 用于處理視頻捕獲、編碼、解碼、渲染等全流程,支持多攝像頭輸入和實時視頻流處理 |
視頻監控系統(多路視頻流實時編碼)、視頻會議終端(4K 視頻解碼)、無人機航拍視頻處理 |
| Developer Tools | 開發者調試、優化和部署工具 | Nsight Systems/Compute:性能分析工具,用于跟蹤 GPU/CPU 資源使用情況,定位代碼瓶頸 Jetson Config Tool:配置 Jetson 設備的硬件參數(如 CPU/GPU 頻率、功耗模式),平衡性能和能耗 交叉編譯工具鏈:支持在 x86 平臺編譯代碼并部署到 Jetson ARM 架構上 |
開發階段的代碼性能優化、設備功耗管理(如嵌入式場景下的低功耗部署) |
| DeepStream | 端到端的 AI 視頻分析框架 | 支持多攝像頭視頻流的接入、處理和分析,集成目標檢測、分類、跟蹤等 AI 模型 提供流水線式架構,可串聯預處理(如去噪)、推理(如 YOLO 模型)、后處理(如結果聚合)等模塊 支持實時分析和事件觸發(如檢測到異常行為時報警) |
智能交通系統(車輛計數、違章檢測)、零售場景客流分析、安防領域的異常行為識別 |
各組件的協同關系:
- CUDA 提供底層算力,CUDA-X AI 基于此實現 AI 算法加速,Computer Vision/Multimedia 處理視覺和視頻數據,DeepStream 整合這些能力形成完整的分析流水線。
- NVIDIA Container Runtime 用于部署和管理這些組件的容器化應用,Developer Tools 則輔助開發和優化全流程。
只有 CUDA 是基礎需求,其他根據需求安裝,因為資源有限,全裝放不下:
- 純深度學習推理:CUDA + CUDA-X AI(cuDNN + TensorRT)
- 實時視頻分析:CUDA + CUDA-X AI + DeepStream + Multimedia
- 計算機視覺應用:CUDA + OpenCV for Jetson + VisionWorks(可選)
- 生產環境部署:CUDA + NVIDIA Container Runtime + 所需的 AI / 視覺庫
二、Hello AI World
Hello AI World 可以完全在您的 Jetson 上運行,包括使用 TensorRT 進行實時推理和使用 PyTorch 進行遷移學習。
有關安裝說明,請參閱系統設置。建議您先從推理部分開始熟悉相關概念,然后再深入訓練您自己的模型。
PS: 下面是參考 Hello AI World 中的各章節的指導,來上手 Hello AI World。只列出核心的一些概述或注意點,想要了解細節,建議看 Hello AI World 的 readme.md。
2.1 System Setup
JetPack 簡化了操作系統和驅動程序的安裝,并包含 L4T Linux 內核、CUDA 工具包、cuDNN、TensorRT 等。
- 對于帶有可移動 microSD 存儲的 Jetson 開發套件,建議的安裝方法是刷入最新的SD 卡映像;
- 其他 Jetson 設備需要通過下載NVIDIA SDK Manager下載到運行 Ubuntu x86_64 的主機電腦上進行刷寫。將 Micro-USB 或 USB-C 端口連接到主機電腦,并將設備置于恢復模式,然后繼續操作;
之后實驗可以在 docker 中實施,也可以自己編譯在 Jetson 內實施。
2.1.1 Docker
readme.md 鏈接中首先列出一些版本的 docker 容器,并說明需要和硬件匹配。
這個不重要,因為接下來就有全自動腳本來自動拉取(不用你自己找版本匹配再拉了)。
$ git clone --recursive --depth=1 https://github.com/dusty-nv/jetson-inference
$ cd jetson-inference
$ docker/run.sh
# PS:如果 docker/run.sh 報錯 docker: Error response from daemon: Unknown runtime specified nvidia.
# 表明 Docker 無法識別 nvidia 運行時,這通常是因為 NVIDIA Container Toolkit 沒有正確安裝或配置
# 參考:https://www.doubao.com/chat/8647245920655362
# 用下面命令修復:
# 1) 添加存儲庫并安裝
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install -y nvidia-docker2
# 2) 重啟 Docker 服務
sudo systemctl restart docker

PS: 我的板子是 r32.7.1 但是找不到,腳本就安裝了個 32.7.6
PS: 裝完用 df -h 命令查看 14G 還剩 3.3G
run 啟動容器后,執行推理 demo 發現報錯:
? jetson-inference git:(master) docker/run.sh
ARCH: aarch64
reading L4T version from /etc/nv_tegra_release
L4T BSP Version: L4T R32.7.6
CONTAINER_IMAGE: dustynv/jetson-inference:r32.7.1
DATA_VOLUME: --volume /home/xuyan/Downloads/jetson-inference/data:/jetson-inference/data --volume /home/xuyan/Downloads/jetson-inference/python/training/classification/data:/jetson-inference/python/training/classification/data --volume /home/xuyan/Downloads/jetson-inference/python/training/classification/models:/jetson-inference/python/training/classification/models --volume /home/xuyan/Downloads/jetson-inference/python/training/detection/ssd/data:/jetson-inference/python/training/detection/ssd/data --volume /home/xuyan/Downloads/jetson-inference/python/training/detection/ssd/models:/jetson-inference/python/training/detection/ssd/models --volume /home/xuyan/Downloads/jetson-inference/python/www/recognizer/data:/jetson-inference/python/www/recognizer/data
root@xuyan-desktop:/jetson-inference# cd build/aarch64/bin
root@xuyan-desktop:/jetson-inference/build/aarch64/bin# ./imagenet images/jellyfish.jpg images/test/jellyfish.jpg
./imagenet: error while loading shared libraries: /usr/lib/aarch64-linux-gnu/libnvinfer.so.8: file too short
GEMINI 介紹說網絡不穩定導致拉取不好,但是重新弄還是不行,因此準備重新編譯。
2.1.2 板上編譯
參考《板上編譯》首先將 apt 和 python 源都改為清華源:
https://www.doubao.com/chat/8635589019524866
# 創建工作空間(雖然 /run 里有 2G,但是每次重啟都會清空,因此別放)
cd ~/Downloads
mkdir hello_ai
cd hello_ai
# 編譯測試
sudo apt-get update
sudo apt-get install git cmake libpython3-dev python3-numpy
git clone --recursive --depth=1 https://github.com/dusty-nv/jetson-inference
cd jetson-inference
mkdir build
cd build
cmake ..
make -j$(nproc)
cd aarch64/bin
./imagenet images/jellyfish.jpg images/test/jellyfish.jpg
因為很多 demo 都需要 GUI,使用 tightvncserver 等各種都有問題,各種問題,直接放棄使用。這里使用:
ssh -Y btfz@192.168.55.1 # 登陸
nautilus # 打開文件夾
eog jellyfish.jpg # 打開圖片
2.2 推理
2.2.1 圖像分類
2.2.1.1 在 Jetson 上使用 ImageNet 程序
https://github.com/dusty-nv/jetson-inference/blob/master/docs/imagenet-console-2.md
深度學習網絡有多種類型,包括識別、檢測/定位和語義分割。本教程重點介紹的第一個深度學習功能是圖像識別,它使用在大型數據集上訓練過的分類網絡來識別場景和物體。

該 imageNet 對象接受一張輸入圖像并輸出每個類別的概率。GoogleNet 和 ResNet-18 模型已在包含 1000 個對象的 ImageNet ILSVRC 數據集上進行訓練,并在構建步驟中自動下載。其他可供下載和使用的分類模型請參見下文。
作為使用該類的示例 imageNet,提供了 C++ 和 Python 的示例程序:
- imagenet.cpp(C++)
- imagenet.py(Python)
這些示例能夠對圖像、視頻和攝像頭信息流進行分類。如需詳細了解所支持的各種輸入/輸出流類型,請參閱攝像頭流式傳輸和多媒體頁面。
1)在 Jetson 上使用 ImageNet 程序
首先,讓我們嘗試使用該 imagenet 程序在一些示例圖像上測試 ImageNet 識別。它會加載一張(或多張)圖像,使用 TensorRT 和 imageNet 類進行推理,然后疊加分類結果并保存輸出圖像。該項目附帶了示例圖像,位于 images/ 目錄下供您使用。
構建項目后,請確保您的終端位于以下 aarch64/bin 目錄中:
$ cd jetson-inference/build/aarch64/bin
接下來,讓我們使用該程序對示例圖像進行分類 imagenet,可以使用 C++ 或 Python 版本。如果您使用的是Docker 容器,建議將分類后的輸出圖像保存到 images/test 已掛載的目錄中。這樣,您就可以在主機設備上的jetson-inference/data/images/test 目錄中輕松查看這些圖像(更多信息,請參閱已掛載的數據卷)。
# C++
$ ./imagenet images/orange_0.jpg images/test/output_0.jpg # (default network is googlenet)
# Python
$ ./imagenet.py images/orange_0.jpg images/test/output_0.jpg # (default network is googlenet)
注意:第一次運行每個模型時,TensorRT 將花費幾分鐘來優化網絡。
然后,此優化的網絡文件將緩存到磁盤,因此將來使用該模型的運行將加載得更快。
# C++
$ ./imagenet images/strawberry_0.jpg images/test/output_1.jpg
# Python
$ ./imagenet.py images/strawberry_0.jpg images/test/output_1.jpg
除了加載單張圖片外,您還可以加載目錄、圖片序列或視頻文件。更多信息,請參閱相機流媒體和多媒體頁面,或使用 flag 啟動應用程序 --help。
2)下載其他分類模型
以下預先訓練的圖像分類模型可供使用并將自動下載(默認為googlenet):
| 網絡 | CLI 參數 | NetworkType 枚舉 |
|---|---|---|
| AlexNet | alexnet | ALEXNET |
| GoogleNet | googlenet | GOOGLENET |
| GoogleNet-12 | googlenet-12 | GOOGLENET_12 |
| ResNet-18 | resnet-18 | RESNET_18 |
| ResNet-50 | resnet-50 | RESNET_50 |
| ResNet-101 | resnet-101 | RESNET_101 |
| ResNet-152 | resnet-152 | RESNET_152 |
| VGG-16 | vgg-16 | VGG-16 |
| VGG-19 | vgg-19 | VGG-19 |
| Inception-v4 | inception-v4 | INCEPTION_V4 |
一般來說,更復雜的網絡可以具有更高的分類精度,并且運行時間也更長。
3)使用不同的分類模型
--network 您可以通過將命令行上的標志設置為上表中相應的 CLI 參數之一來指定要加載的模型。默認情況下,如果 --network 未指定可選標志,則會加載 GoogleNet。
以下是使用 ResNet-18 模型的一些示例:
# C++
$ ./imagenet --network=resnet-18 images/jellyfish.jpg images/test/output_jellyfish.jpg
# Python
$ ./imagenet.py --network=resnet-18 images/jellyfish.jpg images/test/output_jellyfish.jpg
# C++
$ ./imagenet --network=resnet-18 images/stingray.jpg images/test/output_stingray.jpg
# Python
$ ./imagenet.py --network=resnet-18 images/stingray.jpg images/test/output_stingray.jpg
# C++
$ ./imagenet --network=resnet-18 images/coral.jpg images/test/output_coral.jpg
# Python
$ ./imagenet.py --network=resnet-18 images/coral.jpg images/test/output_coral.jpg
您可以隨意嘗試不同的模型,看看它們的準確率和性能有何不同——您可以使用模型下載器工具下載更多模型。您還可以在下方找到各種測試圖像 images/
4)處理視頻
相機流媒體和多媒體頁面顯示了程序可以處理的不同類型的流 imagenet。
以下是在磁盤視頻上運行該程序的示例:
# Download test video (thanks to jell.yfish.us)
$ wget https://nvidia.box.com/shared/static/tlswont1jnyu3ix2tbf7utaekpzcx4rc.mkv -O jellyfish.mkv
# C++
$ ./imagenet --network=resnet-18 jellyfish.mkv images/test/jellyfish_resnet18.mkv
# Python
$ ./imagenet.py --network=resnet-18 jellyfish.mkv images/test/jellyfish_resnet18.mkv
注意:如果直接用 ssh -Y/-X 執行上面命令會報錯

接下來,我們將從頭開始編寫您自己的圖像識別程序,首先使用 Python,然后使用 C++。
2.2.1.2 編寫你自己的圖像識別程序(Python)
在上一步中,我們運行了 jetson-inferencerepo 附帶的示例應用程序。
現在,我們將學習如何用 Python 從頭開始??創建一個名為 my-recognition.py 的圖像識別程序。該腳本將從磁盤加載任意圖像,并使用 imageNet 對象對其進行分類。完整的源代碼位于 python/examples/my-recognition.py
#!/usr/bin/python3
import jetson.inference
import jetson.utils
import argparse
# parse the command line
parser = argparse.ArgumentParser()
parser.add_argument("filename", type=str, help="filename of the image to process")
parser.add_argument("--network", type=str, default="googlenet", help="model to use, can be: googlenet, resnet-18, ect.")
args = parser.parse_args()
# load an image (into shared CPU/GPU memory)
img = jetson.utils.loadImage(args.filename)
# load the recognition network
net = jetson.inference.imageNet(args.network)
# classify the image
class_idx, confidence = net.Classify(img)
# find the object description
class_desc = net.GetClassDesc(class_idx)
# print out the result
print("image is recognized as '{:s}' (class #{:d}) with {:f}% confidence".format(class_desc, class_idx, confidence * 100))
1)設置項目
如果您正在使用 Docker 容器,則需要將代碼存儲在已掛載目錄 (Mounted Directory)中。這樣,當您關閉容器時,代碼就不會丟失。為簡單起見,本指南將在主機設備上位于用戶主目錄下的目錄中創建它 ~/my-recognition-python ,然后將該路徑掛載到容器中。
從終端(容器外部)運行以下命令來創建目錄、源文件并下載一些測試圖像:
# run these commands outside of container
$ cd ~/
$ mkdir my-recognition-python
$ cd my-recognition-python
$ touch my-recognition.py
$ chmod +x my-recognition.py
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/black_bear.jpg
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/brown_bear.jpg
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/polar_bear.jpg
然后,當你啟動容器時,掛載剛剛創建的目錄:
$ docker/run.sh --volume ~/my-recognition-python:/my-recognition-python # mounted inside the container to /my-recognition-python
接下來,我們將程序的 Python 代碼添加到我們在此處創建的空源文件中。
2)源代碼
my-recognition.py 在您選擇的編輯器中打開(或運行 gedit my-recognition.py)。您可以在容器外部進行編輯。
首先,讓我們在文件的最頂部添加一個生命序列以自動使用 Python 解釋器:
#!/usr/bin/python3
接下來,我們將導入腳本中要使用的 Python 模塊。
導入模塊
添加語句以 import 加載用于識別圖像和加載圖像的模塊。我們還將加載用于解析命令行的標準包。
jetson.inference jetson.utils argparse
import jetson.inference
import jetson.utils
import argparse
注意:這些 Jetson 模塊是在構建 repo
sudo make install的步驟中安裝的。
如果您沒有運行,那么當我們運行示例時將找不到這些包。
解析命令行
接下來,添加一些樣板代碼來解析圖像文件名和可選 --network 參數:
# parse the command line
parser = argparse.ArgumentParser()
parser.add_argument("filename", type=str, help="filename of the image to process")
parser.add_argument("--network", type=str, default="googlenet", help="model to use, can be: googlenet, resnet-18, ect. (see --help for others)")
args = parser.parse_args()
此示例加載并分類用戶指定的圖像。預計運行方式如下:
$ ./my-recognition.py my_image.jpg
需要加載的圖像文件名應該替換為 my_image.jpg。您還可以選擇指定 --network 參數來更改使用的分類網絡(默認為 GoogleNet):
$ ./my-recognition.py --network=resnet-18 my_image.jpg
有關下載其他網絡的更多信息,請參閱上一頁的下載其他分類模型部分。
從磁盤加載圖像
您可以使用該函數將圖像從磁盤加載到共享 CPU/GPU 內存中 loadImage()。支持的格式包括 JPG、PNG、TGA 和 BMP。
添加此行以使用從命令行指定的文件名加載圖像:
img = jetson.utils.loadImage(args.filename)
返回的圖像將是一個 jetson.utils.cudaImage 包含寬度、高度和像素格式等屬性的對象:
<jetson.utils.cudaImage>
.ptr # memory address (not typically used)
.size # size in bytes
.shape # (height,width,channels) tuple
.width # width in pixels
.height # height in pixels
.channels # number of color channels
.format # format string
.mapped # true if ZeroCopy
有關從 Python 訪問圖像的更多信息,請參閱使用 CUDA 進行圖像處理頁面。為簡單起見,我們在此僅加載單幅圖像。要加載視頻或圖像序列,您需要 videoSource 像上一個 imagenet.py 示例一樣使用 API。
加載圖像識別網絡
使用該 imageNet 對象,以下代碼將使用 TensorRT 加載所需的分類模型。除非您使用標志指定了其他網絡,否則默認情況下它將加載 GoogleNet,該模型在您最初構建代碼庫 --network 時已下載(默認情況下也選擇下載該模型)。jetson-inference ResNet-18
所有可用的分類模型均在 ImageNet ILSVRC 數據集上進行預訓練,可以識別多達 1000 種不同類別的物體,例如不同種類的水果和蔬菜、許多不同種類的動物,以及日常人造物體,如車輛、辦公家具、運動器材等。
# load the recognition network
net = jetson.inference.imageNet(args.network)
對圖像進行分類
接下來,我們將使用以下 imageNet.Classify() 函數通過識別網絡對圖像進行分類:
# classify the image
class_idx, confidence = net.Classify(img)
imageNet.Classify() 接受圖像及其尺寸,并使用 TensorRT 執行推理。
它返回一個元組,其中包含圖像被識別為的對象類的整數索引,以及結果的浮點置信度值。
解釋結果
作為最后一步,讓我們檢索類別描述并打印出分類結果:
# find the object description
class_desc = net.GetClassDesc(class_idx)
# print out the result
print("image is recognized as '{:s}' (class #{:d}) with {:f}% confidence".format(class_desc, class_idx, confidence * 100))
imageNet.Classify() 返回已識別對象類別的索引(在 ILSVRC 上訓練的模型中,介于 0 和 999 之間)。給定類別索引,該函數 imageNet.GetClassDesc() 將返回包含該類別文本描述的字符串。這些描述會自動從 ilsvrc12_synset_words.txt 加載。
就是這樣!這就是我們進行圖像分類所需的全部 Python 代碼。請參閱上面完整的源代碼。
3)運行示例
現在我們的 Python 程序已經完成,讓我們對本頁開頭下載的測試圖像進??行分類:
$ ./my-recognition.py polar_bear.jpg
image is recognized as 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus' (class #296) with 99.999878% confidence
$ ./my-recognition.py brown_bear.jpg
image is recognized as 'brown bear, bruin, Ursus arctos' (class #294) with 99.928925% confidence
$ ./my-recognition.py black_bear.jpg
image is recognized as 'American black bear, black bear, Ursus americanus, Euarctos americanus' (class #295) with 98.898628% confidence
您還可以通過 --network 指定標志來選擇使用不同的網絡,如下所示:
$ ./my-recognition.py --network=resnet-18 polar_bear.jpg
image is recognized as 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus' (class #296) with 99.743396% confidence
接下來,我們將逐步介紹如何創建該程序的 C++ 版本(這里先不介紹,人生苦短,我用 python)。
2.2.1.3 編寫你自己的圖像識別程序(C++)
2.2.1.4 運行實時攝像頭識別演示
我們之前使用的 imagenet.cpp/imagenet.py 示例也可用于實時攝像頭流式傳輸。支持的攝像頭類型包括:
- MIPI CSI 攝像頭(
csi://0) - V4L2 攝像頭(
/dev/video0) - RTP/RTSP 流(
rtsp://username:password@ip:port)
有關視頻流和協議的更多信息,請參閱攝像機流和多媒體頁面。
以下是通過攝像機啟動該程序的一些典型場景(運行 `--help``以獲取更多選項):
C++
$ ./imagenet csi://0 # MIPI CSI camera
$ ./imagenet /dev/video0 # V4L2 camera
$ ./imagenet /dev/video0 output.mp4 # save to video file
Python
$ ./imagenet.py csi://0 # MIPI CSI camera
$ ./imagenet.py /dev/video0 # V4L2 camera
$ ./imagenet.py /dev/video0 output.mp4 # save to video file
注意:例如要使用的相機,請參閱 Jetson Wiki 的以下部分:
- Nano:https://eLinux.org/Jetson_Nano#Cameras
- Xavier:https://eLinux.org/Jetson_AGX_Xavier#Ecosystem_Products_.26_Cameras
- TX1/TX2:開發套件包括板載 MIPI CSI 傳感器模塊(0V5693)
OpenGL 窗口中顯示的是實時攝像頭流、已分類對象的名稱、已分類對象的置信度以及網絡的幀率。在 Jetson Nano 上,GoogleNet 和 ResNet-18 的幀率最高可達約 75 FPS(在其他 Jetson 上速度更快)。
該應用程序最多可以識別 1000 種不同類型的對象,因為其分類模型是在包含 1000 個對象類別的 ILSVRC ImageNet 數據集上訓練的。這 1000 種對象的名稱映射,您可以在代碼庫中找到:data/networks/ilsvrc12_synset_words.txt
至此,Hello AI World 教程中關于圖像分類的部分就結束了。接下來,我們將開始使用目標檢測網絡,該網絡可以為我們提供每幀圖像中多個目標的邊界框坐標。
2.2.1.5 圖像標記的多標簽分類
多標簽分類模型能夠同時識別多個對象類別,用于執行圖像標記等任務。多標簽深度神經網絡 (DNN) 的拓撲結構與普通的單類模型幾乎相同,只是它們使用的是 S 型激活層,而不是 Softmax 激活層。resnet18-tagging-voc 目前有一個預訓練的多標簽模型,該模型是在 Pascal VOC 數據集上訓練的:

要啟用圖像標記,您需要運行 imagenet/imagenet.py 以及 --topK=0 和 --threshold 做選擇:
# C++
$ imagenet --model=resnet18-tagging-voc --topK=0 --threshold=0.25 "images/object_*.jpg" images/test/tagging_%i.jpg
# Python
$ imagenet.py --model=resnet18-tagging-voc --topK=0 --threshold=0.25 "images/object_*.jpg" images/test/tagging_%i.jpg
使用 --topK=0 意味著所有置信度得分超過閾值的類都將被分類器返回。
1)從代碼中檢索多個圖像標簽
當指定 topK 參數時,imageNet.Classify() 函數將返回元組 (classID, confidence)。有關使用多個分類結果的代碼示例,請參閱 imagenet.cpp 或 imagenet.py
C++
imageNet::Classifications classifications; // std::vector<std::pair<uint32_t, float>> (classID, confidence)
if( net->Classify(image, input->GetWidth(), input->GetHeight(), classifications, topK) < 0 )
continue;
for( uint32_t n=0; n < classifications.size(); n++ )
{
const uint32_t classID = classifications[n].first;
const char* classLabel = net->GetClassLabel(classID);
const float confidence = classifications[n].second * 100.0f;
printf("imagenet: %2.5f%% class #%i (%s)\n", confidence, classID, classLabel);
}
Python
predictions = net.Classify(img, topK=args.topK)
for n, (classID, confidence) in enumerate(predictions):
classLabel = net.GetClassLabel(classID)
confidence *= 100.0
print(f"imagenet: {confidence:05.2f}% class #{classID} ({classLabel})")
請注意,topK 也可以用于單類分類以獲得前 N 個結果,盡管這些模型并未針對圖像標記進行訓練。
2.2.2 物體檢測
2.2.2.1 使用 DetectNet 定位物體
前面的識別示例輸出代表整個輸入圖像的類別概率。接下來我們將重點介紹物體檢測,并通過提取邊界框來查找幀中各種物體的位置。與圖像分類不同,物體檢測網絡能夠在每幀中檢測許多不同的物體。

該 detectNet 對象接受圖像作為輸入,并輸出檢測到的邊界框的坐標列表及其類別和置信度值。 可基于 Python 和 C++ 使用 detectNet。下文介紹了可供下載的各種預訓練檢測模型。默認使用的模型是在 MS COCO 數據集上訓練的 91 類 SSD-Mobilenet-v2 模型,該模型借助 TensorRT 在 Jetson 上實現了實時推理。
作為使用該類的示例 detectNet,我們提供了 C++ 和 Python 的示例程序:
- detectnet.cpp(C++)
- detectnet.py(Python)
這些示例能夠檢測圖像、視頻和攝像頭圖像中的物體。如需詳細了解所支持的各種輸入/輸出流類型,請參閱攝像頭流和多媒體頁面。
1)從圖像中檢測物體
首先,讓我們嘗試使用該 detectnet 程序在靜態圖像中定位對象。除了輸入/輸出路徑外,還有一些其他命令行選項:
- 可選
--network標志,用于更改正在使用的檢測模型(默認為 SSD-Mobilenet-v2)。 - 可選
--overlay標志,可以是逗號分隔的box、lines、labels、conf和none的組合- 默認
--overlay=box,labels,conf顯示框、標簽和置信度值 - 該
box選項繪制填充的邊界框,而lines僅繪制未填充的輪廓
- 默認
- 可選
--alpha值,用于設置疊加期間使用的 alpha 混合值(默認值為120)。 - 可選
--threshold值,設置檢測的最小閾值(默認值為0.5)。
如果您使用的是 Docker 容器,建議將輸出鏡像保存到 images/test 已掛載的目錄。這樣,您就可以在主機設備上輕松查看這些鏡像 jetson-inference/data/images/test(更多信息,請參閱已掛載的數據卷)。
以下是使用默認 SSD-Mobilenet-v2 模型檢測圖像中行人的一些示例:
# C++
$ ./detectnet --network=ssd-mobilenet-v2 images/peds_0.jpg images/test/output.jpg # --network flag is optional
# Python
$ ./detectnet.py --network=ssd-mobilenet-v2 images/peds_0.jpg images/test/output.jpg # --network flag is optional
# C++
$ ./detectnet images/peds_1.jpg images/test/output.jpg
# Python
$ ./detectnet.py images/peds_1.jpg images/test/output.jpg
注意:第一次運行每個模型時,TensorRT 將花費幾分鐘來優化網絡。
然后,此優化的網絡文件將緩存到磁盤,因此將來使用該模型的運行將加載得更快。
以下是控制臺程序輸出的更多檢測示例。基于 SSD 的模型訓練的 91 類 MS COCO 數據集包含人物、車輛、動物以及各種類型的家居物品。
images/ 下面有各種圖像可供測試,例如 cat_*.jpg、dog_*.jpg、horse_*.jpg、peds_*.jpg 等
2)處理目錄或圖像序列
如果您有多個想要同時處理的圖像,則可以detectnet使用包含圖像或通配符序列的目錄路徑啟動該程序:
# C++
./detectnet "images/peds_*.jpg" images/test/peds_output_%i.jpg
# Python
./detectnet.py "images/peds_*.jpg" images/test/peds_output_%i.jpg
注意:使用通配符時,請務必將其括在引號 ( "*.jpg") 中。否則,操作系統將自動擴展序列并修改命令行上的參數順序,這可能會導致其中一個輸入圖像被輸出覆蓋。
有關加載/保存圖像序列的更多信息,請參閱相機流和多媒體頁面。
3)處理視頻文件
您還可以處理磁盤中的視頻。有關加載/保存視頻的更多信息,請參閱此處。
# Download test video
wget https://nvidia.box.com/shared/static/veuuimq6pwvd62p9fresqhrrmfqz0e2f.mp4 -O pedestrians.mp4
# C++
./detectnet pedestrians.mp4 images/test/pedestrians_ssd.mp4
# Python
./detectnet.py pedestrians.mp4 images/test/pedestrians_ssd.mp4
# Download test video
wget https://nvidia.box.com/shared/static/i5i81mkd9wdh4j7wx04th961zks0lfh9.avi -O parking.avi
# C++
./detectnet parking.avi images/test/parking_ssd.avi
# Python
./detectnet.py parking.avi images/test/parking_ssd.avi
請記住,您可以使用該--threshold設置來調高或調低檢測靈敏度(默認值為 0.5)。
4)預訓練檢測模型可用
下面是可供使用的預訓練對象檢測網絡的表格,以及用于加載預訓練模型的相關--network參數:detectnet
| Model | CLI argument | NetworkType enum | Object classes |
|---|---|---|---|
| SSD-Mobilenet-v1 | ssd-mobilenet-v1 | SSD_MOBILENET_V1 | 91 (COCO classes) |
| SSD-Mobilenet-v2 | ssd-mobilenet-v2 | SSD_MOBILENET_V2 | 91 (COCO classes) |
| SSD-Inception-v2 | ssd-inception-v2 | SSD_INCEPTION_V2 | 91 (COCO classes) |
| TAO PeopleNet | peoplenet | PEOPLENET | person, bag, face |
| TAO PeopleNet (已??修剪) | peoplenet-pruned | PEOPLENET_PRUNED | person, bag, face |
| TAO DashCamNet | dashcamnet | DASHCAMNET | person, car, bike, sign |
| TAO TrafficCamNet | trafficcamnet | TRAFFICCAMNET | person, car, bike, sign |
| TAO FaceDetect | facedetect | FACEDETECT | face |
其他:
| Model | CLI argument | NetworkType enum | Object classes |
|---|---|---|---|
| DetectNet-COCO-Dog | coco-dog | COCO_DOG | 狗 |
| DetectNet-COCO-Bottle | coco-bottle | COCO_BOTTLE | 瓶子 |
| DetectNet-COCO-Chair | coco-chair | COCO_CHAIR | 椅子 |
| DetectNet-COCO-Airplane | coco-airplane | COCO_AIRPLANE | 飛機 |
| ped-100 | pednet | PEDNET | pedestrians (行人) |
| multiped-500 | multiped | PEDNET_MULTI | pedestrians (行人), luggage (行李) |
| facenet-120 | facenet | FACENET | faces |
5)運行不同的檢測模型
您可以通過 --network 將命令行上的標志設置為上表中相應的 CLI 參數之一來指定要加載的模型。如果 --network 未指定可選標志,則默認加載 SSD-Mobilenet-v2。
例如,如果您選擇使用模型下載器工具下載 SSD-Inception-v2,則可以像這樣使用它:
# C++
$ ./detectnet --network=ssd-inception-v2 input.jpg output.jpg
# Python
$ ./detectnet.py --network=ssd-inception-v2 input.jpg output.jpg
6)源代碼
作為參考,下面是源代碼 detectnet.py:
import jetson.inference
import jetson.utils
import argparse
import sys
# parse the command line
parser = argparse.ArgumentParser(description="Locate objects in a live camera stream using an object detection DNN.")
parser.add_argument("input_URI", type=str, default="", nargs='?', help="URI of the input stream")
parser.add_argument("output_URI", type=str, default="", nargs='?', help="URI of the output stream")
parser.add_argument("--network", type=str, default="ssd-mobilenet-v2", help="pre-trained model to load (see below for options)")
parser.add_argument("--overlay", type=str, default="box,labels,conf", help="detection overlay flags (e.g. --overlay=box,labels,conf)\nvalid combinations are: 'box', 'labels', 'conf', 'none'")
parser.add_argument("--threshold", type=float, default=0.5, help="minimum detection threshold to use")
try:
opt = parser.parse_known_args()[0]
except:
print("")
parser.print_help()
sys.exit(0)
# load the object detection network
net = jetson.inference.detectNet(opt.network, sys.argv, opt.threshold)
# create video sources & outputs
input = jetson.utils.videoSource(opt.input_URI, argv=sys.argv)
output = jetson.utils.videoOutput(opt.output_URI, argv=sys.argv)
# process frames until the user exits
while True:
# capture the next image
img = input.Capture()
# detect objects in the image (with overlay)
detections = net.Detect(img, overlay=opt.overlay)
# print the detections
print("detected {:d} objects in image".format(len(detections)))
for detection in detections:
print(detection)
# render the image
output.Render(img)
# update the title bar
output.SetStatus("{:s} | Network {:.0f} FPS".format(opt.network, net.GetNetworkFPS()))
# print out performance info
net.PrintProfilerTimes()
# exit on input/output EOS
if not input.IsStreaming() or not output.IsStreaming():
break
接下來,我們將在實時攝像機流上運行對象檢測。
2.2.2.2 運行實時攝像頭檢測演示
我們之前使用的 detectnet.cpp/detectnet.py 示例也可用于實時攝像頭流式傳輸。支持的攝像頭類型包括:
- MIPI CSI 攝像頭(
csi://0) - V4L2 攝像頭(
/dev/video0) - RTP/RTSP 流(
rtsp://username:password@ip:port) - WebRTC 流(
webrtc://@:port/stream_name)
有關視頻流和協議的更多信息,請參閱攝像機流和多媒體頁面。
運行該程序以 --help 查看完整的選項列表(其中一些特定于 detectNet 的選項包括):
--network改變正在使用的檢測模型的標志(默認為SSD-Mobilenet-v2)。--overlay標志可以是逗號分隔的box、labels、conf、track和none- 默認
--overlay=box,labels,conf顯示框、標簽和置信度值
- 默認
--alpha值設置了疊加期間使用的 alpha 混合值(默認值為120)。--threshold設置檢測的最小閾值的值(默認值為0.5)。
以下是通過攝像頭啟動該程序的一些典型場景:
C++
$ ./detectnet csi://0 # MIPI CSI camera
$ ./detectnet /dev/video0 # V4L2 camera
$ ./detectnet /dev/video0 output.mp4 # save to video file
Python
$ ./detectnet.py csi://0 # MIPI CSI camera
$ ./detectnet.py /dev/video0 # V4L2 camera
$ ./detectnet.py /dev/video0 output.mp4 # save to video file
注意:例如要使用的相機,請參閱 Jetson Wiki 的以下部分:
- Nano:https://eLinux.org/Jetson_Nano#Cameras
- Xavier:https://eLinux.org/Jetson_AGX_Xavier#Ecosystem_Products_.26_Cameras
- TX1/TX2:開發套件包括板載 MIPI CSI 傳感器模塊(0V5693)
可視化
OpenGL 窗口中顯示的是實時攝像頭數據流,其上疊加了檢測到的物體的邊界框。請注意,基于 SSD 的模型目前性能最高。
如果視頻源中未檢測到所需的物體,或者您得到了虛假檢測,請嘗試使用參數降低或增加檢測閾值 --threshold(默認值為 0.5)。
接下來,我們將介紹如何使用 Python 創建攝像頭檢測應用程序的代碼。
2.2.2.3 編寫你自己的物體檢測程序
在本教程的這一步,我們將指導您如何創建自己的 Python 腳本,僅用 10-15 行代碼即可在實時攝像頭信號中進行實時物體檢測。該程序將捕獲視頻幀,并使用檢測深度神經網絡 (DNN) 處理這些幀,并利用 detectNet 目標物體進行處理。
完整的源代碼可以在 python/examples/my-detection.py repo 文件中獲取,但以下指南將默認它們位于用戶的主目錄或您選擇的任意目錄中。以下是我們將要講解的 Python 代碼的快速預覽:
from jetson_inference import detectNet
from jetson_utils import videoSource, videoOutput
net = detectNet("ssd-mobilenet-v2", threshold=0.5)
camera = videoSource("csi://0") # '/dev/video0' for V4L2
display = videoOutput("display://0") # 'my_video.mp4' for file
while display.IsStreaming():
img = camera.Capture()
if img is None: # capture timeout
continue
detections = net.Detect(img)
display.Render(img)
display.SetStatus("Object Detection | Network {:.0f} FPS".format(net.GetNetworkFPS()))
YouTube 上還有此編碼教程的視頻截屏:
1)源代碼
首先,打開您選擇的文本編輯器并創建一個新文件。下面我們假設您將該文件保存在主機設備上的用戶主目錄下 ~/my-detection.py,但您可以根據需要命名和存儲它。如果您使用的是 Docker 容器,則需要將代碼存儲在已掛載目錄中,類似于我們在 Python 圖像識別示例中所做的操作。
導入模塊
在源文件的頂部,我們將導入將在腳本中使用的 Python 模塊。添加語句以 import 加載用于對象檢測和攝像頭捕捉的模塊。
from jetson_inference import detectNet
from jetson_utils import videoSource, videoOutput
注意:這些 Jetson 模塊是在構建 repo
sudo make install的步驟中安裝的。
如果您沒有運行,那么當我們運行示例時將找不到這些包。
加載檢測模型
接下來使用以下行創建一個 detectNet 加載 91 類 SSD-Mobilenet-v2 模型的對象實例:
# load the object detection model
net = detectNet("ssd-mobilenet-v2", threshold=0.5)
請注意,您可以將模型字符串更改為此表中的值之一,以加載不同的檢測模型。0.5 為了便于說明,我們還在此處將檢測閾值設置為默認值(您可以根據需要稍后進行調整)。
打開相機流
為了連接到攝像機設備進行流式傳輸,我們將創建該 videoSource 對象的一個??實例:
camera = videoSource("csi://0") # '/dev/video0' for V4L2
傳遞給 videoSource() 的字符串實際上可以是任何有效的資源 URI,無論是相機、視頻文件還是網絡流。有關視頻流和協議的更多信息,請參閱攝像機流和多媒體頁面。
注意:要使用兼容相機,請參閱 Jetson Wiki 的以下部分:
- Nano:https://eLinux.org/Jetson_Nano#Cameras
- Xavier:https://eLinux.org/Jetson_AGX_Xavier#Ecosystem_Products_.26_Cameras
- TX1/TX2:開發套件包括板載 MIPI CSI 傳感器模塊(0V5693)
顯示循環
接下來,我們將使用該對象創建一個視頻輸出接口 videoOutput,并創建一個一直運行直到用戶退出的主循環:
display = videoOutput("display://0") # 'my_video.mp4' for file
while display.IsStreaming():
# main loop will go here
請注意,以下代碼的其余部分應在此while循環下方縮進。與上述類似,您可以將 URI 字符串替換為此頁面上的其他類型的輸出(例如視頻文件等)。
相機捕捉
主循環中發生的第一件事是從攝像機捕獲下一個視頻幀。camera.Capture() 將等到下一幀從攝像機發送并加載到 GPU 內存中。
img = camera.Capture()
if img is None: # capture timeout
continue
返回的圖像將是一個 jetson.utils.cudaImage 包含寬度、高度和像素格式等屬性的對象:
<jetson.utils.cudaImage>
.ptr # memory address (not typically used)
.size # size in bytes
.shape # (height,width,channels) tuple
.width # width in pixels
.height # height in pixels
.channels # number of color channels
.format # format string
.mapped # true if ZeroCopy
有關從 Python 訪問圖像的更多信息,請參閱使用 CUDA 進行圖像處理頁面。
檢測物體
接下來,檢測網絡使用該函數 net.Detect() 處理圖像。它從以下位置獲取圖像 camera.Capture() 并返回檢測列表:
detections = net.Detect(img)
此功能還會自動將檢測結果疊加在輸入圖像上。
如果需要,您可以在 print(detections) 此處添加一條語句,這樣每次檢測結果的坐標、置信度和類別信息都會打印到終端。另請參閱 detectNet 文檔,了解返回的結構體中用于在自定義應用程序中直接訪問的不同成員的信息 Detection。
渲染
最后,我們將使用 OpenGL 將結果可視化,并更新窗口的標題以顯示當前性能:
display.Render(img)
display.SetStatus("Object Detection | Network {:.0f} FPS".format(net.GetNetworkFPS()))
該 Render() 功能將自動翻轉后緩沖區并在屏幕上顯示圖像。
源列表
就是這樣!為了完整起見,下面是我們剛剛創建的 Python 腳本的完整源代碼:
from jetson_inference import detectNet
from jetson_utils import videoSource, videoOutput
net = detectNet("ssd-mobilenet-v2", threshold=0.5)
camera = videoSource("csi://0") # '/dev/video0' for V4L2
display = videoOutput("display://0") # 'my_video.mp4' for file
while display.IsStreaming():
img = camera.Capture()
if img is None: # capture timeout
continue
detections = net.Detect(img)
display.Render(img)
display.SetStatus("Object Detection | Network {:.0f} FPS".format(net.GetNetworkFPS()))
請注意,此版本假設您使用的是 MIPI CSI 攝像頭。Opening the Camera Stream 有關如何將其更改為使用其他輸入類型的信息,請參閱上文。
2)運行程序
要運行我們剛剛編寫的應用程序,只需使用 Python 解釋器從終端啟動它:
$ python3 my-detection.py
為了調整結果,您可以嘗試更改加載的模型以及檢測閾值。祝您玩得開心!
2.2.2.4 使用 TAO 檢測模型
NVIDIA 的 TAO 工具包包含高精度高分辨率物體檢測模型,針對 INT8 精度進行了優化/修剪和量化。jetson-inference 支持基于 DetectNet_v2 DNN 架構的 TAO 模型,包括以下預訓練模型:
| Model | CLI argument | Object classes |
|---|---|---|
| TAO PeopleNet | peoplenet | person, bag, face |
| TAO PeopleNet (pruned) | peoplenet-pruned | person, bag, face |
| TAO DashCamNet(行車記錄儀) | dashcamnet | person, car, bike, sign |
| TAO TrafficCamNet | trafficcamnet | person, car, bike, sign |
| TAO FaceDetect | facedetect | face |
盡管下面的部分介紹了如何加載您自己的 TAO 模型,但讓我們先看看如何使用預先訓練的模型。
1)PeopleNet
PeopleNet 是一個高分辨率 960x544 模型,在檢測人物、包袋和人臉方面準確率高達 90%。它基于 DetectNet_v2 和 ResNet-34 主干網絡。運行 detectnet/detectnet.py --model=peoplenet 即可在支持 TAO PeopleNet 的平臺上以 INT8 精度運行該模型(其他平臺則為 FP16)。此外,還有一個 peoplenet-pruned 速度更快但準確率略低的模型。

# Download test video
wget https://nvidia.box.com/shared/static/veuuimq6pwvd62p9fresqhrrmfqz0e2f.mp4 -O pedestrians.mp4
# C++
$ detectnet --model=peoplenet pedestrians.mp4 pedestrians_peoplenet.mp4
# Python
$ detectnet.py --model=peoplenet pedestrians.mp4 pedestrians_peoplenet.mp4
您還可以調整 --confidence 和 --clustering 閾值(由于準確率更高,這些 TAO 模型似乎不會在較低的閾值下引入太多誤報)。Flask Web 應用是一個便捷的工具,可以以交互方式操作這些設置。
2)DashCamNet
與 PeopleNet 類似,DashCamNet 是一款基于 DetectNet_v2 和 ResNet-34 的 960x544 檢測器。其預期用途是從街道視角和第一人稱視角檢測行人和車輛。TrafficCamNet 與之類似,但適用于從更高視角拍攝的圖像。

# C++
$ detectnet --model=dashcamnet input.mp4 output.mp4
# Python
$ detectnet.py --model=dashcamnet input.mp4 output.mp4
注意:您可以使用“相機流媒體和多媒體”頁面中的任何輸入/輸出來運行它
3)FaceDetect
FaceDetect 是一個僅用于檢測人臉的 TAO 模型。該模型基于一個包含超過 180 萬個從各種攝像機角度采集的樣本的數據集進行訓練,準確率高達 85% 左右。其分辨率為 736x416,使用 DetectNet_v2 和 ResNet-18 主干網絡。

# C++
$ detectnet --model=facedetect "images/humans_*.jpg" images/test/facedetect_humans_%i.jpg
# Python
$ detectnet.py --model=facedetect "images/humans_*.jpg" images/test/facedetect_humans_%i.jpg
4)導入您自己的 TAO 檢測模型
雖然 jetson-inference 可以自動下載、轉換和加載上述預訓練的 TAO 檢測模型,但您可能希望使用這些模型的其他版本,或者您自己使用 TAO 訓練或微調的 DetectNet_v2 模型。為此,請將訓練好的 ETLT 模型以及相應版本的 tao-converter 工具復制到您的 Jetson 中。然后,根據模型的配置(詳細信息通常可在模型卡上找到),您可以運行如下腳本,從 ETLT 生成 TensorRT 引擎:
# model config
MODEL_DIR="peoplenet_deployable_quantized_v2.6.1"
MODEL_INPUT="$MODEL_DIR/resnet34_peoplenet_int8.etlt"
MODEL_OUTPUT="$MODEL_INPUT.engine"
INPUT_DIMS="3,544,960"
OUTPUT_LAYERS="output_bbox/BiasAdd,output_cov/Sigmoid"
MAX_BATCH_SIZE="1"
WORKSPACE="4294967296" # 4GB (default)
PRECISION="int8" # fp32, fp16, int8
CALIBRATION="$MODEL_DIR/resnet34_peoplenet_int8.txt"
ENCRYPTION_KEY="tlt_encode"
# generate TensorRT engine
tao-converter \
-k $ENCRYPTION_KEY \
-d $INPUT_DIMS \
-o $OUTPUT_LAYERS \
-m $MAX_BATCH_SIZE \
-w $WORKSPACE \
-t $PRECISION \
-c $CALIBRATION \
-e $MODEL_OUTPUT \
$MODEL_INPUT
轉換后,您可以使用 detectnet/detectnet.py 加載它,如下所示:
$ detectnet \
--model=$MODEL_DIR/resnet34_peoplenet_int8.etlt.engine \
--labels=$MODEL_DIR/labels.txt \
--input-blob=input_1 \
--output-cvg=output_cov/Sigmoid \
--output-bbox=output_bbox/BiasAdd \
input.mp4 output.mp4
注意:jetson-inference 目前僅支持 TAO DetectNet_v2 模型,因為它是為該網絡的預/后處理設置的
在您自己的應用程序中,您還可以使用 detectNet API 的擴展形式直接從 C++ 或 Python 加載它們。
2.2.2.5 視頻中的對象跟蹤
盡管利用現代檢測 DNN 的準確性,您基本上可以進行“通過檢測進行跟蹤”,但一定程度的時間濾波有利于平滑檢測中的閃爍和視頻中的暫時遮擋。jetson-inference 包括使用幀間 IOU(交并比)邊界框比較的基本(但快速)多對象跟蹤(DeepStream 有更全面的跟蹤實現,可從此處 High-Speed Tracking-by-Detection Without Using Image Information 獲得)。
![]()
要使用 detectnet/detectnet.py 啟用跟蹤,請使用 --tracking 標志運行它。
# Download test video
wget https://nvidia.box.com/shared/static/veuuimq6pwvd62p9fresqhrrmfqz0e2f.mp4 -O pedestrians.mp4
# C++
$ detectnet --model=peoplenet --tracking pedestrians.mp4 pedestrians_tracking.mp4
# Python
$ detectnet.py --model=peoplenet --tracking pedestrians.mp4 pedestrians_tracking.mp4
1)跟蹤參數
您可以使用以下命令行選項更改其他跟蹤器設置:
objectTracker arguments:
--tracking flag to enable default tracker (IOU)
--tracker-min-frames=N the number of re-identified frames for a track to be considered valid (default: 3)
--tracker-drop-frames=N number of consecutive lost frames before a track is dropped (default: 15)
--tracker-overlap=N how much IOU overlap is required for a bounding box to be matched (default: 0.5)
這些設置也可以通過 Python 中的 detectNet.SetTrackerParams() 函數或 C++ 中的 objectTracker API 進行:
Python
from jetson_utils import detectNet
net = detectNet()
net.SetTrackingEnabled(True)
net.SetTrackingParams(minFrames=3, dropFrames=15, overlapThreshold=0.5)
C++
#include <jetson-inference/detectNet.h>
#include <jetson-inference/objectTrackerIOU.h>
detectNet* net = detectNet::Create();
net->SetTracker(objectTrackerIOU::Create(3, 15, 0.5f));
要以交互方式使用這些設置,您可以使用瀏覽器中的 Flask webapp 。
2)跟蹤狀態
當啟用跟蹤時,detectNet.Detection 從 Detect() 返回的結果將激活由跟蹤器更新的附加變量并描述每個對象的跟蹤狀態(例如 TrackID、TrackStatus、TrackFrames 和 TrackLost):
struct Detection
{
// Detection Info
uint32_t ClassID; /**< Class index of the detected object. */
float Confidence; /**< Confidence value of the detected object. */
// Tracking Info
int TrackID; /**< Unique tracking ID (or -1 if untracked) */
int TrackStatus; /**< -1 for dropped, 0 for initializing, 1 for active/valid */
int TrackFrames; /**< The number of frames the object has been re-identified for */
int TrackLost; /**< The number of consecutive frames tracking has been lost for */
// Bounding Box Coordinates
float Left; /**< Left bounding box coordinate (in pixels) */
float Right; /**< Right bounding box coordinate (in pixels) */
float Top; /**< Top bounding box cooridnate (in pixels) */
float Bottom; /**< Bottom bounding box coordinate (in pixels) */
};
這些都可以從 C++ 和 Python 中訪問。例如,從 Python 中:
detections = net.Detect(img)
for detection in detections:
if detection.TrackStatus >= 0: # actively tracking
print(f"object {detection.TrackID} at ({detection.Left}, {detection.Top}) has been tracked for {detection.TrackFrames} frames")
else: # if tracking was lost, this object will be dropped the next frame
print(f"object {detection.TrackID} has lost tracking")
如果跟蹤丟失(TrackStatus=-1),則該對象將被丟棄,并且不再包含在后續幀的檢測數組中。
2.2.3 語義分割
2.2.3.1 使用 SegNet 進行語義分割
0)總述
本教程將介紹的下一個深度學習功能是語義分割。語義分割基于圖像識別,但分類發生在像素級別,而非整幅圖像。這是通過對預先訓練的圖像識別主干進行卷積來實現的,這將模型轉換為能夠逐像素標記的全卷積網絡 (FCN)。語義分割對于環境感知尤其有用,它可以對每個場景中的許多不同潛在對象(包括場景前景和背景)進行密集的逐像素分類。

segNet 接受二維圖像作為輸入,并輸出帶有逐像素分類掩碼疊加的第二幅圖像。掩碼的每個像素對應于被分類的對象類別。
segNet 可從 Python 和 C++ 使用。
作為使用該類的示例 segNet,我們提供了 C++ 和 Python 示例程序:
- segnet.cpp(C++)
- segnet.py(Python)
這些示例能夠分割圖像、視頻和攝像頭信號。如需詳細了解所支持的各種輸入/輸出流類型,請參閱攝像頭流式傳輸和多媒體頁面。
請參閱下文,了解各種基于 FCN-ResNet18 網絡的預訓練分割模型,這些模型可在 Jetson 上實時運行。這些模型適用于各種環境和主題,包括城市、越野路徑以及室內辦公空間和住宅。
1)可用的預訓練分割模型
下表列出了可用的預訓練語義分割模型,以及用于加載這些模型的相關 --network 參數 segnet。它們基于 21 類 FCN-ResNet18 網絡,并使用 PyTorch 在各種數據集和分辨率上進行了訓練,并導出為 ONNX 格式以便使用 TensorRT 加載。
| Dataset Resolution | CLI Argument | Accuracy | Jetson Nano | Jetson Xavier |
|---|---|---|---|---|
| Cityscapes / 城市景觀 | 512x256 | fcn-resnet18-cityscapes-512x256 | 83.3% | 48 FPS |
| Cityscapes / 城市景觀 | 1024x512 | fcn-resnet18-cityscapes-1024x512 | 87.3% | 12 FPS |
| Cityscapes / 城市景觀 | 2048x1024 | fcn-resnet18-cityscapes-2048x1024 | 89.6% | 3 FPS |
| DeepScene / 深度場景 | 576x320 | fcn-resnet18-deepscene-576x320 | 96.4% | 26 FPS |
| DeepScene / 深度場景 | 864x480 | fcn-resnet18-deepscene-864x480 | 96.9% | 14 FPS |
| Multi-Human / 多人 | 512x320 | fcn-resnet18-mhp-512x320 | 86.5% | 34 FPS |
| Multi-Human / 多人 | 640x360 | fcn-resnet18-mhp-640x360 | 87.1% | 23 FPS |
| Pascal VOC / 帕斯卡 VOC | 320x320 | fcn-resnet18-voc-320x320 | 85.9% | 45 FPS |
| Pascal VOC / 帕斯卡 VOC | 512x320 | fcn-resnet18-voc-512x320 | 88.5% | 34 FPS |
| SUN RGB-D / 太陽RGB-D | 512x400 | fcn-resnet18-sun-512x400 | 64.3% | 28 FPS |
| SUN RGB-D / 太陽RGB-D | 640x512 | fcn-resnet18-sun-640x512 | 65.1% | 17 FPS |
- 如果 CLI 參數中省略了分辨率,則加載最低分辨率模型
- 準確度表示模型驗證數據集的像素分類準確度
nvpmodel 0使用 JetPack 4.2.1 (MAX-N) 測量 GPU FP16 模式的性能
2)從命令行分割圖像
首先,讓我們嘗試使用該 segnet 程序分割靜態圖像。除了輸入/輸出路徑之外,還有一些其他命令行選項:
- 可選
--network標志更改正在使用的分割模型(見上文) - 可選
--visualize標志接受mask和/或overlay模式(默認為overlay) - 可選
--alpha標志設置alpha混合值overlay(默認為120) - 可選
--filter-mode標志接受point或linear采樣(默認為linear)
啟動帶有標志的應用程序--help以獲取更多信息,并參考相機流和多媒體頁面了解支持的輸入/輸出協議。
以下是該程序的一些用法示例:
C++
$ ./segnet --network=<model> input.jpg output.jpg # overlay segmentation on original
$ ./segnet --network=<model> --alpha=200 input.jpg output.jpg # make the overlay less opaque
$ ./segnet --network=<model> --visualize=mask input.jpg output.jpg # output the solid segmentation mask
Python
$ ./segnet.py --network=<model> input.jpg output.jpg # overlay segmentation on original
$ ./segnet.py --network=<model> --alpha=200 input.jpg output.jpg # make the overlay less opaque
$ ./segnet.py --network=<model> --visualize=mask input.jpg output.jpg # output the segmentation mask
3)城市景觀
讓我們看一些不同的場景。以下是使用 Cityscapes 模型分割城市街道場景的示例:
# C++
$ ./segnet --network=fcn-resnet18-cityscapes images/city_0.jpg images/test/output.jpg
# Python
$ ./segnet.py --network=fcn-resnet18-cityscapes images/city_0.jpg images/test/output.jpg
city-*.jpg 在子目錄下有更多名為 “found” 的測試圖像,images/ 用于試用 Cityscapes 模型。
4)深度場景
DeepScene 數據集包含越野森林小徑和植被,有助于戶外機器人進行路徑跟蹤。
以下是通過指定參數生成分割疊加層和蒙版的示例 --visualize:
C++
$ ./segnet --network=fcn-resnet18-deepscene images/trail_0.jpg images/test/output_overlay.jpg # overlay
$ ./segnet --network=fcn-resnet18-deepscene --visualize=mask images/trail_0.jpg images/test/output_mask.jpg # mask
Python
$ ./segnet.py --network=fcn-resnet18-deepscene images/trail_0.jpg images/test/output_overlay.jpg # overlay
$ ./segnet.py --network=fcn-resnet18-deepscene --visualize=mask images/trail_0.jpg images/test/output_mask.jpg # mask
trail-*.jpg 子目錄下還有更多名為的示例圖像 images/。
5)多人解析(MHP)
多人解析可以對身體部位進行密集標注,例如手臂、腿、頭部以及不同類型的衣服。
以下是一些測試圖像,用于測試 MHP 模型:humans-*.jpgimages/
# C++
$ ./segnet --network=fcn-resnet18-mhp images/humans_0.jpg images/test/output.jpg
# Python
$ ./segnet.py --network=fcn-resnet18-mhp images/humans_0.jpg images/test/output.jpg
6)帕斯卡 VOC
Pascal VOC 是用于語義分割的原始數據集之一,包含各種人物、動物、車輛和家居用品。
其中包含一些用于 object-*.jpg 測試 Pascal VOC 模型的示例圖像:
# C++
$ ./segnet --network=fcn-resnet18-voc images/object_0.jpg images/test/output.jpg
# Python
$ ./segnet.py --network=fcn-resnet18-voc images/object_0.jpg images/test/output.jpg
7)太陽 RGB-D
SUN [RGB-D][] 數據集為辦公室和家庭中常見的許多室內物體和場景提供了分割真實值。
查看子目錄 room-*.jpg 下名為 found 的圖像 images/,以測試 SUN 模型:
# C++
$ ./segnet --network=fcn-resnet18-sun images/room_0.jpg images/test/output.jpg
# Python
$ ./segnet.py --network=fcn-resnet18-sun images/room_0.jpg images/test/output.jpg
8)處理目錄或圖像序列
如果您想要處理目錄或圖像序列,則可以使用包含圖像或通配符序列的目錄路徑啟動程序:
# C++
$ ./segnet --network=fcn-resnet18-sun "images/room_*.jpg" images/test/room_output_%i.jpg
# Python
$ ./segnet.py --network=fcn-resnet18-sun "images/room_*.jpg" images/test/room_output_%i.jpg
注意:使用通配符時,請務必將其括在引號 (
"*.jpg") 中。否則,操作系統將自動擴展序列并修改命令行上的參數順序,這可能會導致其中一個輸入圖像被輸出覆蓋。
有關加載/保存圖像序列的更多信息,請參閱相機流和多媒體頁面。接下來,我們將對實時相機或視頻流進行分割。
2.2.3.2 運行實時攝像頭分割演示
我們之前使用的 segnet.cpp / segnet.py 示例也可用于實時攝像頭流式傳輸。支持的攝像頭類型包括:
- MIPI CSI 攝像頭(
csi://0) - V4L2 攝像頭(
/dev/video0) - RTP/RTSP 流(
rtsp://username:password@ip:port)
有關視頻流和協議的更多信息,請參閱攝像機流和多媒體頁面。
運行該程序以 --help 查看完整的選項列表(其中一些特定于 segNet 的選項包括):
- 可選
--network標志更改正在使用的分割模型(參見可用網絡) - 可選
--visualize標志接受mask和/或overlay模式(默認為overlay) - 可選
--alpha標志設置覆蓋層的alpha混合值(默認為120) - 可選
--filter-mode標志接受point或linear``采樣(默認為linear`)
以下是啟動該程序的一些典型場景 - 請參閱此表了解可用的模型。
C++
$ ./segnet --network=<model> csi://0 # MIPI CSI camera
$ ./segnet --network=<model> /dev/video0 # V4L2 camera
$ ./segnet --network=<model> /dev/video0 output.mp4 # save to video file
Python
$ ./segnet.py --network=<model> csi://0 # MIPI CSI camera
$ ./segnet.py --network=<model> /dev/video0 # V4L2 camera
$ ./segnet.py --network=<model> /dev/video0 output.mp4 # save to video file
注意:例如要使用的相機,請參閱 Jetson Wiki 的以下部分:
- Nano:https://eLinux.org/Jetson_Nano#Cameras
- Xavier:https://eLinux.org/Jetson_AGX_Xavier#Ecosystem_Products_.26_Cameras
- TX1/TX2:開發套件包括板載 MIPI CSI 傳感器模塊(0V5693)
可視化
OpenGL 窗口中顯示的是實時攝像機數據流與分割輸出疊加,為了清晰起見,還附上了實心分割蒙版。以下是一些在不同模型上的使用示例,可??供您嘗試:
# C++
$ ./segnet --network=fcn-resnet18-mhp csi://0
# Python
$ ./segnet.py --network=fcn-resnet18-mhp csi://0
# C++
$ ./segnet --network=fcn-resnet18-sun csi://0
# Python
$ ./segnet.py --network=fcn-resnet18-sun csi://0
# C++
$ ./segnet --network=fcn-resnet18-deepscene csi://0
# Python
$ ./segnet.py --network=fcn-resnet18-deepscene csi://0
您可以隨意嘗試適合室內和室外環境的不同模型和分辨率。
2.2.4 姿態估計
姿勢估計包括定位構成骨架拓撲(又稱鏈接)的各個身體部位(又稱關鍵點)。姿勢估計具有多種應用,包括手勢、AR/VR、HMI(人機界面)以及姿勢/步態校正。我們提供用于人體和手勢估計的預訓練模型,能夠每幀檢測多個人物。

該 poseNet 對象接受圖像作為輸入,并輸出一個物體姿態列表。每個物體姿態包含一個檢測到的關鍵點列表,以及它們的位置和關鍵點之間的鏈接。您可以查詢這些列表以查找特定特征。該對象 poseNet 可以在 Python 和C++ 中使用。
posenet.cpp(C++)posenet.py(Python)
這些示例能夠檢測圖像、視頻和攝像頭圖像中多個人物的姿勢。如需詳細了解所支持的各種輸入/輸出流類型,請參閱攝像頭流式傳輸和多媒體頁面。
圖像姿態估計
首先,讓我們嘗試 posenet 在一些示例圖像上運行該示例。除了輸入/輸出路徑之外,還有一些可選的命令行選項:
- 可選
--network標志,用于改變正在使用的姿勢模型(默認為resnet18-body)。 - 可選
--overlay標志,可以是逗號分隔的box、links、keypoints的組合和none- 默認設置是
--overlay=links,keypoints在關鍵點上顯示圓圈,在鏈接上顯示線條
- 默認設置是
- 可選
--keypoint-scale值,控制疊加層中關鍵點圓的半徑(默認值為0.0052) - 可選
--link-scale值,控制覆蓋層中鏈接線的線寬(默認值為0.0013) - 可選
--threshold值,設置檢測的最小閾值(默認值為0.15)。
如果您使用的是 Docker 容器,建議將輸出鏡像保存到 images/test 已掛載的目錄。這樣,您就可以在主機設備上輕松查看這些鏡像 jetson-inference/data/images/test(更多信息,請參閱已掛載的數據卷)。
以下是使用默認的 Pose-ResNet18-Body 模型進行人體姿勢估計的一些示例:
# C++
$ ./posenet "images/humans_*.jpg" images/test/pose_humans_%i.jpg
# Python
$ ./posenet.py "images/humans_*.jpg" images/test/pose_humans_%i.jpg

注意: 第一次運行每個模型時,TensorRT 將花費幾分鐘來優化網絡。
然后,此優化的網絡文件將緩存到磁盤,因此將來使用該模型的運行將加載得更快。
下面還有人物測試圖像,images/peds_*.jpg 您也可以嘗試一下。
視頻姿態估計
要在實時攝像機流或視頻上運行姿勢估計,請從攝像機流和多媒體頁面傳入設備或文件路徑。
# C++
$ ./posenet /dev/video0 # csi://0 if using MIPI CSI camera
# Python
$ ./posenet.py /dev/video0 # csi://0 if using MIPI CSI camera
# C++
$ ./posenet --network=resnet18-hand /dev/video0
# Python
$ ./posenet.py --network=resnet18-hand /dev/video0
預訓練姿態估計模型
以下是可用的預訓練姿態估計網絡,以及用于加載預訓練模型的相關 --network 參數:posenet
| Model | CLI argument | NetworkType enum | Keypoints |
|---|---|---|---|
| Pose-ResNet18-Body | resnet18-body | RESNET18_BODY | 18 |
| Pose-ResNet18-Hand | resnet18-hand | RESNET18_HAND | 21 |
| Pose-DenseNet121-Body | densenet121-body | DENSENET121_BODY | 18 |
您可以通過將命令行上的 --network 標志設置為上表中相應的 CLI 參數之一來指定要加載的模型。默認情況下,如果 --network 未指定可選標志,則使用 Pose-ResNet18-Body。
處理物體姿勢
如果您想訪問姿勢關鍵點位置,該 poseNet.Process() 函數將返回一個結構列表 poseNet.ObjectPose。每個物體姿勢代表一個物體(例如一個人),并包含檢測到的關鍵點和鏈接的列表(更多信息請參閱 Python 和 C++ 文檔)。
下面是 Python 偽代碼,通過在 left_shoulder 和 left_wrist 關鍵點之間形成一個向量,找到一個人指向的 2D 方向(在圖像空間中) :
poses = net.Process(img)
for pose in poses:
# find the keypoint index from the list of detected keypoints
# you can find these keypoint names in the model's JSON file,
# or with net.GetKeypointName() / net.GetNumKeypoints()
left_wrist_idx = pose.FindKeypoint('left_wrist')
left_shoulder_idx = pose.FindKeypoint('left_shoulder')
# if the keypoint index is < 0, it means it wasn't found in the image
if left_wrist_idx < 0 or left_shoulder_idx < 0:
continue
left_wrist = pose.Keypoints[left_wrist_idx]
left_shoulder = pose.Keypoints[left_shoulder_idx]
point_x = left_shoulder.x - left_wrist.x
point_y = left_shoulder.y - left_wrist.y
print(f"person {pose.ID} is pointing towards ({point_x}, {point_y})")
這是一個簡單的例子,但你可以通過進一步操作向量并查找更多關鍵點來使其更加實用。還有一些更高級的技術,例如在 trt_hand_pose 項目中,使用機器學習對姿勢結果進行手勢分類。
2.2.5 動作識別
動作識別可以對視頻幀序列中發生的活動、行為或手勢進行分類。深度神經網絡 (DNN) 通常使用添加了時間維度的圖像分類主干模型。例如,基于 ResNet18 的預訓練模型使用 16 幀的窗口。您還可以跳過幀來延長模型對動作進行分類的時間窗口。

該 actionNet 對象每次接收一個視頻幀,將其緩沖為模型的輸入,并輸出置信度最高的類。 actionNet 可以在 Python 和 C++ 中使用。
作為使用該類 actionNet 的示例 ,有針對 C++ 和 Python 的示例程序:
- actionnet.cpp(C++)
- actionnet.py(Python)
運行示例
要在實時攝像機流或視頻上運行動作識別,請從攝像機流和多媒體頁面傳入設備或文件路徑。
# C++
$ ./actionnet /dev/video0 # V4L2 camera input, display output (default)
$ ./actionnet input.mp4 output.mp4 # video file input/output (mp4, mkv, avi, flv)
# Python
$ ./actionnet.py /dev/video0 # V4L2 camera input, display output (default)
$ ./actionnet.py input.mp4 output.mp4 # video file input/output (mp4, mkv, avi, flv)
命令行參數
這些可選的命令行參數可與 actionnet/actionnet.py 一起使用:
--network=NETWORK pre-trained model to load, one of the following:
* resnet-18 (default)
* resnet-34
--model=MODEL path to custom model to load (.onnx)
--labels=LABELS path to text file containing the labels for each class
--input-blob=INPUT name of the input layer (default is 'input')
--output-blob=OUTPUT name of the output layer (default is 'output')
--threshold=CONF minimum confidence threshold for classification (default is 0.01)
--skip-frames=SKIP how many frames to skip between classifications (default is 1)
默認情況下,模型會每隔一幀進行處理,以延長對動作進行分類的時間窗口。您可以使用 --skip-frames 參數(使用 --skip-frames=0 將處理每一幀)更改此設置。
預訓練動作識別模型
以下是可用的預先訓練的動作識別模型,以及用于加載它們的相關 --network 參數:actionnet
| Model | CLI argument | Classes |
|---|---|---|
| Action-ResNet18-Kinetics | resnet18 | 1040 |
| Action-ResNet34-Kinetics | resnet34 | 1040 |
resnet18 是默認值,這些模型在 Kinetics 700 和 Moments in Time 數據庫上訓練(請參閱[此處][]的類別標簽列表)
2.2.6 背景去除
背景去除(又稱背景減法或顯著物體檢測)會生成一個蒙版,將圖像的前景與背景分割開來。您可以使用它來替換或模糊背景(類似于視頻會議應用),或者它可以輔助其他視覺深度神經網絡(例如物體檢測/追蹤或運動檢測)的預處理。所使用的模型是全卷積網絡 U2-Net。

該 backgroundNet 對象拍攝圖像并輸出前景蒙版。backgroundNet 可以從 Python 和 C++ 使用。
作為使用該類的示例 backgroundNet,有針對 C++ 和 Python 的示例程序:
- backgroundnet.cpp(C++)
- backgroundnet.py(Python)
運行示例
以下是刪除和替換圖像背景的示例:

# C++
$ ./backgroundnet images/bird_0.jpg images/test/bird_mask.png # remove the background (with alpha)
$ ./backgroundnet --replace=images/snow.jpg images/bird_0.jpg images/test/bird_replace.jpg # replace the background
# Python
$ ./backgroundnet.py images/bird_0.jpg images/test/bird_mask.png # remove the background (with alpha)
$ ./backgroundnet.py --replace=images/snow.jpg images/bird_0.jpg images/test/bird_replace.jpg # replace the background
命令行 --replace 參數接受用于替換背景的圖像文件名。該圖像將被重新縮放到與輸入相同的分辨率。
直播
要在實時攝像頭流上運行背景移除或替換,請從攝像頭流和多媒體頁面傳入設備:
# C++
$ ./backgroundnet /dev/video0 # remove the background
$ ./backgroundnet --replace=images/coral.jpg /dev/video0 # replace the background
# Python
$ ./backgroundnet /dev/video0 # remove the background
$ ./backgroundnet --replace=images/coral.jpg /dev/video0 # replace the background
通過指定輸出流,您可以在顯示器(默認)上、通過網絡(如使用 WebRTC)查看它,或將其保存到視頻文件中。
2.2.7 單目深度
深度感知在地圖繪制、導航和障礙物檢測等任務中非常有用,但過去它需要立體攝像頭或 RGB-D 攝像頭。現在,深度神經網絡 (DNN) 能夠從單目圖像推斷出相對深度(也稱為單深度)。請參閱 MIT 的 FastDepth 論文,其中介紹了一種使用全卷積網絡 (FCN) 實現此目標的方法。

該 depthNet 對象接受單張彩色圖像作為輸入,并輸出深度圖。深度圖已著色以便于可視化,但原始深度場也可供直接訪問。depthNet 可從 Python 和 C++ 使用。
作為使用該類 depthNet 的示例 ,我們提供了 C++ 和 Python 的示例程序:
- depthnet.cpp(C++)
- depthnet.py(Python)
這些示例能夠從圖像、視頻和攝像頭數據中推斷深度。如需詳細了解所支持的各種輸入/輸出流類型,請參閱攝像頭流式傳輸和多媒體頁面。
圖像上的單色深度
首先,讓我們嘗試 depthnet 在一些示例圖像上運行該示例。除了輸入/輸出路徑之外,還有一些可選的命令行選項:
- 可選
--network標志,用于改變正在使用的深度模型(建議使用默認值fcn-mobilenet)。 - 可選
--visualize標志,可以是逗號分隔的組合input,depth- 默認設置是
--visualize=input,depth并排顯示輸入圖像和深度圖像 - 要僅查看深度圖像,請使用
--visualize=depth
- 默認設置是
- 可選
--depth-size值,用于縮放深度圖相對于輸入的大小(默認值為1.0) - 可選
--filter-mode標志,用于選擇point或linear過濾用于上采樣(默認為linear) - 可選
--colormap標志,用于設置可視化期間使用的顏色映射(默認值為viridis_inverted)
如果您使用的是 Docker 容器,建議將輸出鏡像保存到 images/test 已掛載的目錄。這樣,您就可以在主機設備上輕松查看這些鏡像 jetson-inference/data/images/test(更多信息,請參閱已掛載的數據卷)。
以下是室內場景中單聲道深度估計的一些示例:
# C++
$ ./depthnet "images/room_*.jpg" images/test/depth_room_%i.jpg
# Python
$ ./depthnet.py "images/room_*.jpg" images/test/depth_room_%i.jpg
注意: 第一次運行每個模型時,TensorRT 將花費幾分鐘來優化網絡。
然后,此優化的網絡文件將緩存到磁盤,因此將來使用該模型的運行將加載得更快。
以下是一些戶外場景的拍攝:
# C++
$ ./depthnet "images/trail_*.jpg" images/test/depth_trail_%i.jpg
# Python
$ ./depthnet.py "images/trail_*.jpg" images/test/depth_trail_%i.jpg
視頻的單目深度
要在實時攝像機流或視頻上運行單聲道深度估計,請從攝像機流和多媒體頁面傳入設備或文件路徑。
# C++
$ ./depthnet /dev/video0 # csi://0 if using MIPI CSI camera
# Python
$ ./depthnet.py /dev/video0 # csi://0 if using MIPI CSI camera
注意: 如果屏幕太小,無法容納輸出,您可以使用
--depth-scale=0.5減小深度圖像的尺寸
,或者使用減小相機的尺寸--input-width=X --input-height=Y
獲取原始深度場
如果您想訪問原始深度圖,可以使用 depthNet.GetDepthField()。這將返回一個單通道浮點圖像,該圖像通常比原始輸入更小(224x224),這代表了模型的原始輸出。另一方面,用于可視化的彩色深度圖像會進行上采樣,以匹配原始輸入的分辨率(或任何 --depth-size 比例設置的值)。
下面是用于訪問原始深度場的 Python 和 C++ 偽代碼:
Python
import jetson.inference
import jetson.utils
import numpy as np
# load mono depth network
net = jetson.inference.depthNet()
# depthNet re-uses the same memory for the depth field,
# so you only need to do this once (not every frame)
depth_field = net.GetDepthField()
# cudaToNumpy() will map the depth field cudaImage to numpy
# this mapping is persistent, so you only need to do it once
depth_numpy = jetson.utils.cudaToNumpy(depth_field)
print(f"depth field resolution is {depth_field.width}x{depth_field.height}, format={depth_field.format})
while True:
img = input.Capture() # assumes you have created an input videoSource stream
net.Process(img)
jetson.utils.cudaDeviceSynchronize() # wait for GPU to finish processing, so we can use the results on CPU
# find the min/max values with numpy
min_depth = np.amin(depth_numpy)
max_depth = np.amax(depth_numpy)
C++
#include <jetson-inference/depthNet.h>
// load mono depth network
depthNet* net = depthNet::Create();
// depthNet re-uses the same memory for the depth field,
// so you only need to do this once (not every frame)
float* depth_field = net->GetDepthField();
const int depth_width = net->GetDepthWidth();
const int depth_height = net->GetDepthHeight();
while(true)
{
uchar3* img = NUL;
input->Capture(&img); // assumes you have created an input videoSource stream
net->Process(img, input->GetWidth(), input->GetHeight());
// wait for the GPU to finish processing
CUDA(cudaDeviceSynchronize());
// you can now safely access depth_field from the CPU (or GPU)
for( int y=0; y < depth_height; y++ )
for( int x=0; x < depth_width; x++ )
printf("depth x=%i y=%i -> %f\n", x, y, depth_map[y * depth_width + x]);
}
嘗試使用單深度測量絕對距離可能會導致不準確,因為它通常更適合相對深度估計。原始深度場中的值范圍可能因場景而異,因此這些值通常會動態地重新計算。例如,在可視化過程中,會對深度場執行直方圖均衡化,以使顏色圖在深度值范圍內更均勻地分布。
接下來,我們將介紹遷移學習的概念,并使用 PyTorch 在 Jetson 上訓練我們自己的 DNN 模型。
2.3 訓練
2.3.1 使用 PyTorch 進行遷移學習
遷移學習是一種在新數據集上重新訓練 DNN 模型的技術,比從頭開始訓練網絡耗時更少。通過遷移學習,可以對預訓練模型的權重進行微調,使其能夠對自定義數據集進行分類。在這些示例中,我們將使用 ResNet-18 和 SSD-Mobilenet 網絡,但您也可以嘗試其他網絡。

盡管由于通常使用的數據集很大且相關的計算需求較大,訓練通常在具有獨立 GPU 的 PC、服務器或云實例上進行,但通過使用遷移學習,我們能夠重新訓練 Jetson 上的各種網絡,以開始訓練和部署我們自己的 DNN 模型。
PS:
-
Jetson TX1 的推理和 RK3588 比不占優勢,但是其訓練有優勢,因為有 cuda 加速
-
Jetson TX1 的 cuda 為 200 多,普通 RTX 英偉達顯卡都有數千個,因此不如在 PC 上訓練
-
Jetson TX1 的 cuda 為 200 多,比 i5 集成顯卡跑推理和訓練快很多很多,因此不能用 i5 集成顯卡跑,太慢
-
Jetson TX1 的默認存儲為 16G,安裝完之后剩下的 1G 可憐,外加一個 8G U 盤,跑訓練存儲仍然不夠,非常夠嗆,不建議在上面跑推理
我通過命令刪除無用的東西,最后只能騰出 1.6G:
# 默認的 16G 存儲跑推理還行,跑遷移裝個 pytouch 不夠,即使刪除下面一堆東西,還是有問題:
dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -nr | awk '{printf "%.1f MB\t%s\n", $1/1024, $2}' | head -n 40
sudo apt-get purge ubuntu-desktop
sudo apt-get purge --auto-remove chromium-browser
sudo apt-get purge thunderbird
sudo apt-get purge docker.io
sudo apt-get purge docker
sudo apt-get purge openjdk
sudo apt-get purge openjdk-11-jre-headless
sudo apt-get purge libnvinfer-samples
sudo apt-get purge cuda-samples-10-2
因此我直接不嘗試官方的推薦,在 Jetson TX1 上訓練模型了,不過官方的一些性能參數可以參考下(下表包含數據集及其相關訓練時間的摘要):
| 類型 | 數據集 | 尺寸 | 課程 | 訓練圖像 | 每個時期的時間* | 訓練時間** |
|---|---|---|---|---|---|---|
| 分類 | Cat/Dog | 800MB | 2 | 5,000 | 約7-8分鐘 | 約4小時 |
| 分類 | PlantCLEF | 1.5GB | 20 | 10,475 | 約 15 分鐘 | ~8 小時 |
| 檢測 | Fruit | 2GB | 8 | 6,375 | 約 15 分鐘 | ~8 小時 |
* 使用 Jetson Nano 對數據集進行一次完整訓練的大約時間
** 使用 Jetson Nano 對模型進行 35 個 epoch 訓練的大約時間
不同型號設備訓練對比:
| 型號 | CUDA 核心數 | CPU/GPU 架構及配置 | 訓練 LeNet-5 時間(秒 /epoch) | 訓練 AlexNet 時間(秒 /epoch) | 訓練 ResNet-18 時間(秒 /epoch) | 適用場景 | 適合搭配的 CPU |
|---|---|---|---|---|---|---|---|
| Jetson TX1 | 256 | GPU: 256-core Maxwell,1.3 TFLOPS FP32 CPU: 4 核 ARM Cortex-A57 @ 1.73GHz 內存: 4GB LPDDR4 @ 25.6GB/s 功耗: 10-15W |
~15 | ~45 | ~90 | 邊緣計算、嵌入式視覺系統、小型機器人、低功耗 AI 應用 | 嵌入式模塊,自帶 ARM CPU,無需額外搭配 |
| Jetson TX2 | 256 | GPU: 256-core Pascal,1.6 TFLOPS FP32 CPU: 2 核 Denver2 + 4 核 Cortex-A57 @ 2.0GHz 內存: 8GB LPDDR4 @ 51.2GB/s 功耗: 7.5-15W |
~10 | ~30 | ~60 | 高級邊緣計算、無人機視覺處理、工業自動化、高性能嵌入式 AI 應用 | 嵌入式模塊,自帶 ARM CPU,無需額外搭配 |
| Core i5-2540M | 0 | CPU: 雙核 Intel Core i5-2540M @ 2.6GHz(4 線程),0.25 TFLOPS FP32 內存:最高 16GB DDR3 @ 21.3GB/s 功耗: 35W |
~120 | ~500 | 無法完成 | 老舊筆記本電腦、輕度辦公、低性能計算任務 | 本身為 CPU,無需搭配其他 CPU |
| RTX 3060 | 3584 | GPU: 3584-core Ampere,12.7 TFLOPS FP32 顯存: 12GB GDDR6 @ 360GB/s 功耗: 170-200W |
~1 | ~5 | ~10 | 中端游戲電腦、深度學習入門、中等規模數據訓練、圖形設計 | Intel i5/i7 10 代及以上或 AMD Ryzen 5/7 系列 |
| RTX 3070 | 5888 | GPU: 5888-core Ampere,20.1 TFLOPS FP32 顯存: 8GB GDDR6 @ 448GB/s 功耗: 220W |
~0.8 | ~4 | ~8 | 高端游戲電腦、專業圖形處理、深度學習研究、中等規模 AI 訓練 | Intel i7/i9 10 代及以上或 AMD Ryzen 7/9 系列 |
| RTX 3080 | 8704 | GPU: 8704-core Ampere,29.7 TFLOPS FP32 顯存: 10GB GDDR6X @ 760GB/s 功耗: 320W |
~0.5 | ~3 | ~6 | 高端游戲、專業 3D 渲染、大規模深度學習訓練、AI 研究 | Intel i9 或 AMD Ryzen 9 系列 |
| RTX 4080 | 9728 | GPU: 9728-core Ada Lovelace,49 TFLOPS FP32 顯存: 16GB GDDR6X @ 1TB/s 功耗: 320W |
~0.3 | ~2 | ~4 | 旗艦級游戲、專業級 AI 訓練、大規模數據處理、高性能計算 | Intel i9 12 代及以上或 AMD Ryzen 9 7000 系列及以上 |
| RTX 4090 | 12432 | GPU: 12432-core Ada Lovelace,82.6 TFLOPS FP32 顯存: 24GB GDDR6X @ 1TB/s 功耗: 450W |
~0.2 | ~1 | ~2 | 頂級游戲、超大規模 AI 訓練、數據中心高性能計算、專業級 3D 渲染 | Intel i9 13 代及以上或 AMD Ryzen 9 7000 系列及以上 |
| A100 | 6912 | GPU: 6912-core Ampere,19.5 TFLOPS FP32 / 312 TFLOPS Tensor FP16 顯存: 40/80GB HBM2e @ 2TB/s 功耗: 400W |
~0.1 | ~0.5 | ~1 | 數據中心大規模 AI 訓練、科學計算、高性能數據分析 | Intel Xeon 或 AMD EPYC 服務器級 CPU |
| H100 | 18432 | GPU: 18432-core Hopper,51 TFLOPS FP32 / 1979 TFLOPS Tensor FP16 顯存: 80GB HBM3 @ 3.35TB/s 功耗: 700W |
~0.05 | ~0.2 | ~0.4 | 下一代數據中心 AI 訓練、超大規模模型訓練、高級科學計算 | Intel Xeon 或 AMD EPYC 最新一代服務器級 CPU |
2.3.2 分類/識別(ResNet-18)
2.3.2.1 在貓/狗數據集上進行重新訓練
https://github.com/dusty-nv/jetson-inference/blob/master/docs/pytorch-cat-dog.md
1)概述
我們將要重新訓練的第一個模型是一個簡單的模型,它可以識別兩個類別:貓或狗。

下面提供了一個 800MB 的數據集,其中包含 5000 張訓練圖像、1000 張驗證圖像和 200 張測試圖像,每張圖像均等地分布在貓類和狗類之間。訓練圖像集用于遷移學習,驗證集用于評估訓練期間的分類準確率,測試圖像供我們在訓練完成后使用。網絡不會直接在驗證集和測試集上進行訓練,而只會在訓練集上進行訓練。
數據集中的圖像包含許多不同品種的貓狗,包括老虎和美洲獅等大型貓科動物,因為可用的貓科動物圖像數量略少于狗類圖像。有些圖像中還包含人類,檢測器經過訓練后,會忽略這些人類作為背景,而專注于貓狗圖像。
首先,請確保您的 PC 上已安裝 PyTorch,然后下載下方數據集并啟動訓練腳本。之后,我們將在 TensorRT 中使用一些靜態圖像和實時攝像頭信號測試重新訓練后的模型。
# 注意安裝過程中很慢,有時候需要多次實驗,有一次網速變好
cd ./Desktop/08-tensorflow/
python3.9 -m venv .venv
. .venv/bin/activate
pip install --upgrade pip
pip install torch torchvision torchaudio
pip install tensorboard # 是 PyTorch 中用于可視化訓練過程的工具
2)下載數據
采用下面命令拉取代碼與下載數據:
git clone --recursive --depth=1 https://github.com/dusty-nv/jetson-inference
cd jetson-inference/python/training/classification/data
wget https://nvidia.box.com/shared/static/o577zd8yp3lmxf5zhm38svrbrv45am3y.gz -O cat_dog.tar.gz
tar xvzf cat_dog.tar.gz
數據集的鏡像可以在這里找到:
- https://drive.google.com/file/d/16E3yFvVS2DouwgIl4TPFJvMlhGpnYWKF/view?usp=sharing
- https://nvidia.box.com/s/o577zd8yp3lmxf5zhm38svrbrv45am3y
3)重新訓練 ResNet-18 模型
PyTorch 訓練腳本位于 jetson-inference/python/training/classification/ 中。這些腳本并不針對任何特定數據集,因此我們將對本教程中的每個示例數據集使用相同的 PyTorch 代碼。默認情況下,它設置為訓練 ResNet-18 模型,但您可以使用標志 --arch 進行更改 。
要啟動訓練,請運行以下命令:
$ cd jetson-inference/python/training/classification
$ python3 train.py --model-dir=models/cat_dog data/cat_dog
訓練開始時,您應該會看到控制臺中出現如下文本:
Use GPU: 0 for training
=> dataset classes: 2 ['cat', 'dog']
=> using pre-trained model 'resnet18'
=> reshaped ResNet fully-connected layer with: Linear(in_features=512, out_features=2, bias=True)
Epoch: [0][ 0/625] Time 0.932 ( 0.932) Data 0.148 ( 0.148) Loss 6.8126e-01 (6.8126e-01) Acc@1 50.00 ( 50.00) Acc@5 100.00 (100.00)
Epoch: [0][ 10/625] Time 0.085 ( 0.163) Data 0.000 ( 0.019) Loss 2.3263e+01 (2.1190e+01) Acc@1 25.00 ( 55.68) Acc@5 100.00 (100.00)
Epoch: [0][ 20/625] Time 0.079 ( 0.126) Data 0.000 ( 0.013) Loss 1.5674e+00 (1.8448e+01) Acc@1 62.50 ( 52.38) Acc@5 100.00 (100.00)
Epoch: [0][ 30/625] Time 0.127 ( 0.114) Data 0.000 ( 0.011) Loss 1.7583e+00 (1.5975e+01) Acc@1 25.00 ( 52.02) Acc@5 100.00 (100.00)
Epoch: [0][ 40/625] Time 0.118 ( 0.116) Data 0.000 ( 0.010) Loss 5.4494e+00 (1.2934e+01) Acc@1 50.00 ( 50.30) Acc@5 100.00 (100.00)
Epoch: [0][ 50/625] Time 0.080 ( 0.111) Data 0.000 ( 0.010) Loss 1.8903e+01 (1.1359e+01) Acc@1 50.00 ( 48.77) Acc@5 100.00 (100.00)
Epoch: [0][ 60/625] Time 0.082 ( 0.106) Data 0.000 ( 0.009) Loss 1.0540e+01 (1.0473e+01) Acc@1 25.00 ( 49.39) Acc@5 100.00 (100.00)
Epoch: [0][ 70/625] Time 0.080 ( 0.102) Data 0.000 ( 0.009) Loss 5.1142e-01 (1.0354e+01) Acc@1 75.00 ( 49.65) Acc@5 100.00 (100.00)
Epoch: [0][ 80/625] Time 0.076 ( 0.100) Data 0.000 ( 0.009) Loss 6.7064e-01 (9.2385e+00) Acc@1 50.00 ( 49.38) Acc@5 100.00 (100.00)
Epoch: [0][ 90/625] Time 0.083 ( 0.098) Data 0.000 ( 0.008) Loss 7.3421e+00 (8.4755e+00) Acc@1 37.50 ( 50.00) Acc@5 100.00 (100.00)
Epoch: [0][100/625] Time 0.093 ( 0.097) Data 0.000 ( 0.008) Loss 7.4379e-01 (7.8715e+00) Acc@1 50.00 ( 50.12) Acc@5 100.00 (100.00)
要隨時停止訓練,您可以按 Ctrl+C。您也可以稍后使用 --resume 和 --epoch-start 標志重新開始訓練,這樣您無需等待訓練完成后再測試模型。
運行 python3 train.py --help 以獲取有關每個可供您使用的選項的更多信息,包括您可以使用 --arch 標志嘗試的其他網絡。
訓練指標
訓練過程中輸出的上述統計數據分別對應以下信息:
- epoch:一個 epoch 是對數據集進行一次完整的訓練
Epoch: [N]表示您當前處于時期 0、1、2 等。- 默認運行 35 個 epoch(您可以使用
--epochs=N標志更改此設置)
- [N/625] 是當前所在紀元的圖像批次
- 訓練圖像以小批量處理以提高性能
--batch=N默認批量大小為 8 張圖片,可以通過標志設置- 將括號中的數字乘以批次大小(例如批次
[100/625]-> 圖像[800/5000])
- 時間:當前圖像批次的處理時間(以秒為單位)
- 數據:當前圖像批次的磁盤加載時間(以秒為單位)
- 損失:模型產生的累積誤差(預期與預測)
Acc@1:批次內 Top-1 分類準確率- Top-1,表示模型預測的類別完全正確
Acc@5:批次的 Top-5 分類準確率- Top-5,意味著正確的類別是模型預測的前 5 個輸出之一
- 由于這個貓/狗的例子只有 2 個類(貓和狗),所以 Top-5 總是 100%
- 本教程中的其他數據集有 5 個以上的類別,其中 Top-5 是有效的
您可以在訓練期間關注這些統計數據,以評估模型的訓練效果,并決定是否要繼續訓練或停止并進行測試。如上所述,您可以根據需要稍后重新開始訓練。
模型準確率
在這個包含 5000 幅圖像的數據集上,在 Jetson Nano 上訓練 ResNet-18 大約需要每輪 7-8 分鐘,或者大約需要 4 個小時才能將模型訓練到 35 輪,達到 80% 的分類準確率。下圖是分析訓練輪次與模型準確率之間關系的圖表:

在第 30 個周期左右,ResNet-18 模型的準確率達到了 80%,在第 65 個周期時收斂到 82.5%。隨著訓練時間的增加,您可以通過增加數據集的大小(請參閱下文的“生成更多數據”部分)或嘗試更復雜的模型來進一步提高準確率。
默認情況下,訓練腳本的運行周期為 35 個 epoch,但如果您不想等待那么長時間來測試模型,可以提前退出訓練并繼續下一步(也可以選擇稍后從上次中斷的地方重新開始訓練)。您也可以從此處下載這個已訓練 100 個 epoch 的完整模型:
請注意,模型保存在 jetson-inference/python/training/classification/models/cat_dog/ 下,包括最新 epoch 的檢查點以及分類準確率最高的性能最佳的模型。此 classification/models 目錄會自動掛載到容器 中,因此即使容器關閉,您訓練好的模型仍會保留。
4)將模型轉換為 ONNX
為了使用 TensorRT 運行我們重新訓練的 ResNet-18 模型進行測試和實時推理,首先我們需要將 PyTorch 模型轉換為 ONNX 格式,以便 TensorRT 可以加載它。ONNX 是一種開放的模型格式,支持許多流行的機器學習框架,包括 PyTorch、TensorFlow、TensorRT 等,因此它簡化了工具之間的模型傳輸。
PyTorch 內置了將 PyTorch 模型導出到 ONNX 的支持,因此請運行以下命令,使用提供的 onnx_export.py 腳本轉換我們的 Cat/Dog 模型:
python3 onnx_export.py --model-dir=models/cat_dog
這將在 jetson-inference/python/training/classification/models/cat_dog/ 下創建一個名為 resnet18.onnx 的模型。
5)使用 TensorRT 處理圖像
為了對一些靜態測試圖像進??行分類,我們將使用擴展的命令行參數來imagenet加載我們之前重新訓練的自定義 ResNet-18 模型。要運行這些命令,終端的工作目錄仍應位于: jetson-inference/python/training/classification/
NET=models/cat_dog
DATASET=data/cat_dog
# C++
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/cat/01.jpg cat.jpg
# Python
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/cat/01.jpg cat.jpg

# C++
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/dog/01.jpg dog.jpg
# Python
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/dog/01.jpg dog.jpg

處理所有測試圖像
數據集中包含 200 張貓狗類別的測試圖像,或者你可以下載自己的圖片進行測試。你可以像這樣處理它們:
mkdir $DATASET/test_output_cat $DATASET/test_output_dog
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/../labels.txt \
$DATASET/test/cat $DATASET/test_output_cat
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/../labels.txt \
$DATASET/test/dog $DATASET/test_output_dog
在這種情況下,所有圖像將從數據集的 test/ 目錄中讀取,并保存到該 test_output/ 目錄中。
接下來,我們將嘗試在實時攝像機畫面上運行重新訓練的模型。
6)運行實時攝像頭程序
如果你家里有寵物,可以運行相機程序看看它是怎么工作的!與上一步類似,imagenet 支持擴展命令行參數來加載自定義模型:
# C++ (MIPI CSI)
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt csi://0
# Python (MIPI CSI)
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt csi://0

7)生成更多數據(可選)
貓/狗數據集中的圖像是使用腳本 cat-dog-dataset.sh 從更大的 22.5GB ILSCRV12 子集中隨機提取的。為了縮短訓練時間,特意將第一個貓/狗數據集保持較小,但您可以使用此腳本重新生成包含更多圖像的數據集,從而創建更穩健的模型。
更大的數據集需要更多的時間來訓練,因此您可以暫時繼續下一個示例,但如果您想擴展貓/狗數據集,請首先從這里下載源數據:
提取此檔案后,進行 tools/cat-dog-dataset.sh 以下修改:
- 在
IMAGENET_DIR變量中替換提取的ilsvrc12_subset的位置 - 然后為
cat_dog創建一個空文件夾,并在OUTPUT_DIR中替換該位置 - 通過修改
NUM_TRAIN、NUM_VAL和NUM_TEST變量來更改數據集的大小
該腳本會在 OUTPUT_DIR 目錄下創建 train、val 和 test 子目錄,并為每個目錄填充指定數量的圖像。之后,您可以按照上述方式訓練模型 --resume,也可以選擇使用和 --epoch-start 標志從上次中斷的地方繼續訓練(如果您不想從頭開始訓練)。重新訓練后,請務必將模型重新導出到 ONNX。
在下面的示例中,我們將在支持 20 個對象類的植物和樹木數據集上訓練另一個模型。
2.3.2.2 在 PlantCLEF 數據集上進行重新訓練
1)概述
接下來,我們將訓練一個模型,該模型能夠對 PlantCLEF 數據集中的 20 種不同種類的植物和樹木進行分類。

下面提供的是一個 1.5GB 的子集,包含 20 個植物和樹木類別的 10,475 張訓練圖像、1,155 張驗證圖像和 30 張測試圖像。這些類別選自 PlantCLEF 2017 數據集,原始數據集中至少包含 500 張訓練圖像。
? ash
? beech
? cat-tail
? cedar
? clover
? cyprus
? daisy
? dandelion
? dogwood
? elm
? fern
? fig
? fir
? juniper
? maple
? poison ivy
? sweetgum
? sycamore
? trout lily
? tulip tree
2)下載數據
運行以下命令下載并提取準備好的 PlantCLEF 數據集:
$ cd jetson-inference/python/training/classification/data
$ wget https://nvidia.box.com/shared/static/vbsywpw5iqy7r38j78xs0ctalg7jrg79.gz -O PlantCLEF_Subset.tar.gz
$ tar xvzf PlantCLEF_Subset.tar.gz
數據集的鏡像可以在這里找到:
- https://drive.google.com/file/d/14pUv-ZLHtRR-zCYjznr78mytFcnuR_1D/view?usp=sharing
- https://nvidia.box.com/s/vbsywpw5iqy7r38j78xs0ctalg7jrg79
3)重新訓練 ResNet-18 模型
我們將使用與上一個示例相同的訓練腳本,該腳本位于 python/training/classification/ 下。默認情況下,它設置為訓練 ResNet-18 模型,但您可以使用 --arch 標志進行更改。
要啟動訓練,請運行以下命令:
$ cd jetson-inference/python/training/classification
$ python3 train.py --model-dir=models/plants data/PlantCLEF_Subset
訓練開始時,您應該會看到控制臺中顯示如下文本:
Use GPU: 0 for training
=> dataset classes: 20 ['ash', 'beech', 'cattail', 'cedar', 'clover', 'cyprus', 'daisy', 'dandelion', 'dogwood', 'elm', 'fern', 'fig', 'fir', 'juniper', 'maple', 'poison_ivy', 'sweetgum', 'sycamore', 'trout_lily', 'tulip_tree']
=> using pre-trained model 'resnet18'
=> reshaped ResNet fully-connected layer with: Linear(in_features=512, out_features=20, bias=True)
Epoch: [0][ 0/1307] Time 49.345 (49.345) Data 0.561 ( 0.561) Loss 3.2172e+00 (3.2172e+00) Acc@1 0.00 ( 0.00) Acc@5 25.00 ( 25.00)
Epoch: [0][ 10/1307] Time 0.779 ( 5.211) Data 0.000 ( 0.060) Loss 2.3915e+01 (1.5221e+01) Acc@1 0.00 ( 5.68) Acc@5 12.50 ( 27.27)
Epoch: [0][ 20/1307] Time 0.765 ( 3.096) Data 0.000 ( 0.053) Loss 3.6293e+01 (2.1256e+01) Acc@1 0.00 ( 5.95) Acc@5 37.50 ( 27.38)
Epoch: [0][ 30/1307] Time 0.773 ( 2.346) Data 0.000 ( 0.051) Loss 2.8803e+00 (1.9256e+01) Acc@1 37.50 ( 6.85) Acc@5 62.50 ( 27.42)
Epoch: [0][ 40/1307] Time 0.774 ( 1.962) Data 0.000 ( 0.050) Loss 3.7734e+00 (1.5865e+01) Acc@1 12.50 ( 8.84) Acc@5 37.50 ( 29.88)
Epoch: [0][ 50/1307] Time 0.772 ( 1.731) Data 0.000 ( 0.049) Loss 3.0311e+00 (1.3756e+01) Acc@1 25.00 ( 10.29) Acc@5 37.50 ( 32.35)
Epoch: [0][ 60/1307] Time 0.773 ( 1.574) Data 0.000 ( 0.048) Loss 3.2433e+00 (1.2093e+01) Acc@1 0.00 ( 9.84) Acc@5 25.00 ( 32.79)
Epoch: [0][ 70/1307] Time 0.806 ( 1.462) Data 0.000 ( 0.048) Loss 2.9213e+00 (1.0843e+01) Acc@1 12.50 ( 8.98) Acc@5 37.50 ( 33.27)
Epoch: [0][ 80/1307] Time 0.792 ( 1.379) Data 0.000 ( 0.048) Loss 3.2370e+00 (9.8715e+00) Acc@1 0.00 ( 9.26) Acc@5 25.00 ( 34.41)
Epoch: [0][ 90/1307] Time 0.770 ( 1.314) Data 0.000 ( 0.048) Loss 2.4494e+00 (9.0905e+00) Acc@1 25.00 ( 9.75) Acc@5 75.00 ( 36.26)
Epoch: [0][ 100/1307] Time 0.801 ( 1.261) Data 0.001 ( 0.048) Loss 2.6449e+00 (8.4769e+00) Acc@1 25.00 ( 10.40) Acc@5 62.50 ( 37.00)
模型準確率
在包含 10,475 幅圖像的 PlantCLEF 數據集上,使用 Jetson Nano 訓練 ResNet-18 大約需要每輪約 15 分鐘,或者訓練 35 輪大約需要 8 小時。下圖是分析訓練輪次進度與模型準確率的圖表:

大約在第 30 個周期時,ResNet-18 模型的 Top-5 準確率達到了 75%,而在第 65 個周期時,其 Top-5 準確率收斂到 85%。有趣的是,ResNet-18 模型的這些穩定點和收斂點出現的時間與之前的 Cat/Dog 模型相似。該模型的 Top-1 準確率為 55%,考慮到 PlantCLEF 數據集的多樣性和挑戰性(例如,每張圖片包含多個重疊的植物品種,以及許多幾乎難以區分的樹葉和樹干圖片),我們會發現這個準確率在實踐中非常有效。
默認情況下,訓練腳本的運行周期為 35 個 epoch,但如果您不想等待那么長時間來測試模型,可以提前退出訓練并繼續下一步(也可以選擇稍后從上次中斷的地方重新開始訓練)。您也可以從此處下載這個已訓練 100 個 epoch 的完整模型:
請注意,模型保存在 jetson-inference/python/training/classification/data/plants/ 下,包括最新 epoch 的檢查點和分類準確率最高的性能最佳的模型。您可以通過修改 --model-dir 標志來更改模型的保存目錄。
4)將模型轉換為 ONNX
就像貓/狗的例子一樣,接下來我們需要將訓練好的模型從 PyTorch 轉換為 ONNX,以便我們可以用 TensorRT 加載它:
python3 onnx_export.py --model-dir=models/plants
這將在 jetson-inference/python/training/classification/models/plants/ 下創建一個名為 resnet18.onnx 的模型。
5)使用 TensorRT 處理圖像
為了對一些靜態測試圖像進??行分類,我們將像之前一樣使用擴展的命令行參數 imagenet 來加載我們之前重新訓練的自定義 ResNet-18 模型。要運行這些命令,終端的工作目錄仍應位于: jetson-inference/python/training/classification/
NET=models/plants
DATASET=data/PlantCLEF_Subset
# C++
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/cattail.jpg cattail.jpg
# Python
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/cattail.jpg cattail.jpg
# C++
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/elm.jpg elm.jpg
# Python
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/elm.jpg elm.jpg
# C++
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/juniper.jpg juniper.jpg
# Python
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt $DATASET/test/juniper.jpg juniper.jpg
數據集中包含大量測試圖像,或者您可以下載自己的圖片進行嘗試。
處理所有測試圖像
如果要一次性對所有測試圖像進??行分類,可以對整個目錄運行該程序:
mkdir $DATASET/test_output
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/../labels.txt \
$DATASET/test $DATASET/test_output
在這種情況下,所有圖像將從數據集的 test/ 目錄中讀取,并保存到 test_output/ 目錄中。
6)運行實時攝像頭程序
您還可以嘗試在實時攝像機流上運行重新訓練的植物模型,如下所示:
# C++ (MIPI CSI)
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt csi://0
# Python (MIPI CSI)
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt csi://0
接下來,我們將介紹一種基于攝像頭的工具,用于收集和標記從實時視頻中捕獲的數據集。
2.3.2.3 收集你自己的分類數據集
為了收集您自己的數據集來訓練自定義模型來對您選擇的對象或場景進行分類,我們創建了一個易于使用的工具,用于 camera-capture 從實時視頻中捕獲和標記 Jetson 上的圖像:
該工具將在磁盤上創建具有以下目錄結構的數據集:
? train/
? class-A/ # 每個對象類數據
? class-B/
? ...
? val/
? class-A/
? class-B/
? ...
? test/
? class-A/
? class-B/
? ...
請注意,以上是我們一直使用的 PyTorch 訓練腳本所期望的組織結構。如果您檢查 Cat/Dog 和 PlantCLEF 數據集,它們也以相同的方式組織。
創建標簽文件
在 jetson-inference/python/training/classification/data 下,創建一個空目錄用于存儲數據集,并創建一個用于定義類標簽的文本文件(通常名為 labels.txt)。該標簽文件每行包含一個類標簽,并按字母順序排列(這一點很重要,因為標簽文件中類的順序與磁盤上相應子目錄的順序一致)。如上所述,該 camera-capture 工具將自動根據此標簽文件為每個類填充必要的子目錄。
這是一個 labels.txt 包含 5 個類的示例文件:
background
brontosaurus
tree
triceratops
velociraptor
以下是該工具將創建的相應目錄結構:
? train/
? background/
? brontosaurus/
? tree/
? triceratops/
? velociraptor/
? val/
? background/
? brontosaurus/
? tree/
? triceratops/
? velociraptor/
? test/
? background/
? brontosaurus/
? tree/
? triceratops/
? velociraptor/
啟動工具
該工具的源代碼 camera-capture 可以在 jetson-inference/tools/camera-capture/ 下找到,并且像 repo 中的其他程序一樣,它被構建到 aarch64/bin 目錄中并安裝在 /usr/local/bin/
以下是啟動該工具的一些示例命令:
$ camera-capture csi://0 # using default MIPI CSI camera
$ camera-capture /dev/video0 # using V4L2 camera /dev/video0
收集數據
下面是 Data Capture Control 窗口,它允許您選擇數據集的所需路徑并加載上面創建的類標簽文件,然后提供選擇當前對象類和當前正在收集數據的訓練/驗證/測試集的選項:

首先,打開數據集路徑和類標簽。然后,該工具將創建上述數據集結構(除非這些子目錄已經存在),您將看到您的對象標簽填充在 Current Class 下拉列表中。將數 Dataset Type 保留為分類。
然后將相機放置在您當前在下拉列表中選擇的對象或場景處,并在準備拍攝圖像時單擊“捕獲”按鈕(或按空格鍵)。圖像將保存在 train, val, 或 test 集中的類子目錄下。狀態欄顯示該類別下已保存的圖像數量。
建議在嘗試訓練之前,每個類至少收集 100 張訓練圖像。驗證集的經驗法則是,它應該大約是訓練集大小的 10-20%,測試集的大小只是由你想要測試的靜態圖像數量決定的。如果你愿意,你也可以運行相機來測試你的模型。
重要的是,您的數據是從不同的對象方向、相機視點、照明條件收集的,最好是使用不同的背景,以創建一個對噪聲和環境變化具有魯棒性的模型。如果你發現你的模型沒有達到你想要的效果,試著添加更多的訓練數據,并在各種條件下進行試驗。
訓練你的模型
當你收集了一堆數據后,你可以試著在上面訓練一個模型,就像我們以前做的那樣。訓練過程與前面的示例相同,并且使用了相同的 PyTorch 腳本:
$ cd jetson-inference/python/training/classification
$ python3 train.py --model-dir=models/<YOUR-MODEL> data/<YOUR-DATASET>
$ python3 onnx_export.py --model-dir=models/<YOUR-MODEL>
訓練并轉換后的模型存儲在 models/<YOUR-MODEL>/resnet18.onnx,然后可以使用 imagenet 來測試它:
NET=models/<YOUR-MODEL>
DATASET=data/<YOUR-DATASET>
# C++ (MIPI CSI)
imagenet --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt csi://0
# Python (MIPI CSI)
imagenet.py --model=$NET/resnet18.onnx --input_blob=input_0 --output_blob=output_0 --labels=$DATASET/labels.txt csi://0
接下來,我們將使用 PyTorch 訓練我們自己的對象檢測模型。
2.3.3 物體檢測(SSD-Mobilenet)
2.3.3.1 重新訓練 SSD-Mobilenet
接下來,我們將使用 PyTorch 和 Open Images 數據集訓練我們自己的 SSD-Mobilenet 目標檢測模型。SSD-Mobilenet 是一種流行的網絡架構,用于在移動和嵌入式設備上進行實時目標檢測,它結合了 SSD-300 單次多框檢測器和 Mobilenet 主干網絡。

在下面的示例中,我們將訓練一個自定義檢測模型,用于定位 8 種不同的水果品種。當然,您也可以從 Open Images 數據集的 600 個類別中任意選擇,來訓練您的模型。您可以點擊此處直觀地瀏覽數據集。

首先,請確保您的 Jetson 已安裝 JetPack 4.4(或更高版本)和用于 Python3 的 PyTorch。JetPack 4.4 包含 TensorRT 7.1,這是支持通過 ONNX 加載 SSD-Mobilenet 的最低 TensorRT 版本。更高版本的 TensorRT 也可以。
設置
用于訓練 SSD-Mobilenet 的 PyTorch 代碼位于 jetson-inference/python/training/detection/ssd 下的倉庫中。如果您尚未運行 Docker 容器,則在使用前需要執行以下幾個步驟:
# you only need to run these if you aren't using the container
$ cd jetson-inference/python/training/detection/ssd
$ wget https://nvidia.box.com/shared/static/djf5w54rjvpqocsiztzaandq1m3avr7c.pth -O models/mobilenet-v1-ssd-mp-0_675.pth
$ pip3 install -v -r requirements.txt
這將下載基礎模型 ssd/models 并安裝一些所需的 Python 包(這些包已安裝到容器中)。基礎模型已在另一個數據集 (PASCAL VOC) 上進行預訓練,因此我們無需從頭開始訓練 SSD-Mobilenet,那樣會花費更多時間。我們將使用遷移學習對其進行微調,以檢測我們選擇的新對象類別。
下載數據
Open Images 數據集包含 600 多個對象類別供您選擇。我們提供一個名為 open_images_downloader.py 的腳本,可以自動為您下載所需的對象類別。
注意: 使用的類別越少,模型推理速度越快。Open Images 還可能包含數百 GB 的數據,具體取決于您選擇的類別 - 因此在下載您自己的類別之前,請參閱下面的“限制數據量”部分。
我們將使用的類別是 "Apple,Orange,Banana,Strawberry,Grape,Pear,Pineapple,Watermelon",例如水果采摘機器人的類別——盡管您也可以從類別列表中替換您自己的選擇。水果類別有大約 6500 張圖片,這是一個合適的中間值。
$ python3 open_images_downloader.py --class-names "Apple,Orange,Banana,Strawberry,Grape,Pear,Pineapple,Watermelon" --data=data/fruit
...
2020-07-09 16:20:42 - Starting to download 6360 images.
2020-07-09 16:20:42 - Downloaded 100 images.
2020-07-09 16:20:42 - Downloaded 200 images.
2020-07-09 16:20:42 - Downloaded 300 images.
2020-07-09 16:20:42 - Downloaded 400 images.
2020-07-09 16:20:42 - Downloaded 500 images.
2020-07-09 16:20:46 - Downloaded 600 images.
...
2020-07-09 16:32:12 - Task Done.
默認情況下,數據集將下載到 jetson-inference/python/training/detection/ssd 下的 data/ 目錄中,但您可以通過 --data=<PATH> 指定選項來更改。根據數據集的大小,可能需要使用外部存儲。如果您下載多個數據集,則應將每個數據集存儲在各自的子目錄中。
限制數據量
根據您選擇的類別,Open Images 可能包含大量數據——在某些情況下,數據量太大,無法在合理的時間內完成訓練,無法滿足我們的目標。尤其是包含人物和車輛的類別,其圖像數量非常龐大(>250GB)。
因此,在選擇您自己的類別時,建議在下載數據之前先運行帶有 --stats-only 該選項的下載程序腳本。這將顯示您的類別有多少張圖片,而無需實際下載任何圖片。
$ python3 open_images_downloader.py --stats-only --class-names "Apple,Orange,Banana,Strawberry,Grape,Pear,Pineapple,Watermelon" --data=data/fruit
...
2020-07-09 16:18:06 - Total available images: 6360
2020-07-09 16:18:06 - Total available boxes: 27188
-------------------------------------
'train' set statistics
-------------------------------------
Image count: 5145
Bounding box count: 23539
Bounding box distribution:
Strawberry: 7553/23539 = 0.32
Orange: 6186/23539 = 0.26
Apple: 3622/23539 = 0.15
Grape: 2560/23539 = 0.11
Banana: 1574/23539 = 0.07
Pear: 757/23539 = 0.03
Watermelon: 753/23539 = 0.03
Pineapple: 534/23539 = 0.02
...
-------------------------------------
Overall statistics
-------------------------------------
Image count: 6360
Bounding box count: 27188
注意:
--stats-only確實下載了注釋數據(大約~1GB),但尚未下載圖像。
實際上,為了縮短訓練時間(并節省磁盤空間),您可能希望將圖像總數保持在 10K 以下。雖然使用的圖像越多,模型的準確性就越高。您可以使用以下選項來限制下載的數據量:
--max-images將總數據集限制為指定數量的圖像,同時保持每個類別的圖像分布與原始數據集大致相同。如果一個類別的圖像數量多于另一個類別,則該比例將保持大致相同。--max-annotations-per-class將每個類別限制為指定數量的邊界框,如果某個類別的可用數量少于該數量,則將使用它的所有數據 - 如果數據分布在各個類別之間不平衡,這將很有用。
例如,如果您只想使用 2500 張水果數據集圖像,則可以像這樣啟動下載器:
$ python3 open_images_downloader.py --max-images=2500 --class-names "Apple,Orange,Banana,Strawberry,Grape,Pear,Pineapple,Watermelon" --data=data/fruit
如果未設置 --max-boxes 或 --max-annotations-per-class 選項 ,則默認下載所有可用數據 - 因此,請務必事先使用 --stats-only 檢查數據量。遺憾的是,無法提前確定圖像的實際磁盤大小要求,但此數據集的一般經驗法則是每張圖片預算約 350KB(水果約 2GB)。
訓練的成績
以下是 SSD-Mobilenet 訓練的近似性能,以幫助估計訓練所需的時間:
| 條目 | Images/sec | Time per epoch* |
|---|---|---|
| Nano | 4.77 | 17 min 55 sec |
| Xavier NX | 14.65 | 5 min 50 sec |
- 在水果測試集上進行的測試 (5145 training images, batch size 4)
訓練 SSD-Mobilenet 模型
數據下載完成后,運行 train_ssd.py 腳本啟動訓練:
python3 train_ssd.py --data=data/fruit --model-dir=models/fruit --batch-size=4 --epochs=30
以下是運行訓練腳本時可以使用的一些常用選項:
| Argument | Default | Description |
|---|---|---|
--data |
data/ | 數據集的位置 |
--model-dir |
models/ | 輸出訓練好的模型檢查點的目錄 |
--resume |
None | 恢復訓練的現有檢查點的路徑 |
--batch-size |
4 | 根據可用內存,嘗試增加該參數 |
--epochs |
30 | 最好到達 100,但是會增加訓練時間 |
--workers |
2 | 數據加載器線程數(0 = 禁用多線程) |
隨著時間的推移,你會看到損失減少:
2020-07-10 13:14:12 - Epoch: 0, Step: 10/1287, Avg Loss: 12.4240, Avg Regression Loss 3.5747, Avg Classification Loss: 8.8493
2020-07-10 13:14:12 - Epoch: 0, Step: 20/1287, Avg Loss: 9.6947, Avg Regression Loss 4.1911, Avg Classification Loss: 5.5036
2020-07-10 13:14:13 - Epoch: 0, Step: 30/1287, Avg Loss: 8.7409, Avg Regression Loss 3.4078, Avg Classification Loss: 5.3332
2020-07-10 13:14:13 - Epoch: 0, Step: 40/1287, Avg Loss: 7.3736, Avg Regression Loss 2.5356, Avg Classification Loss: 4.8379
2020-07-10 13:14:14 - Epoch: 0, Step: 50/1287, Avg Loss: 6.3461, Avg Regression Loss 2.2286, Avg Classification Loss: 4.1175
...
2020-07-10 13:19:26 - Epoch: 0, Validation Loss: 5.6730, Validation Regression Loss 1.7096, Validation Classification Loss: 3.9634
2020-07-10 13:19:26 - Saved model models/fruit/mb1-ssd-Epoch-0-Loss-5.672993580500285.pth
要在完成所有 epoch 訓練之前測試你的模型,你可以按下 Ctrl+C 來終止訓練腳本,然后稍后使用參數重新開始訓練。你可以在這里 --resume=<CHECKPOINT> 下載已經訓練了 100 個 epoch 的水果模型。
將模型轉換為 ONNX
接下來,我們需要將訓練好的模型從 PyTorch 轉換為 ONNX,以便可以使用 TensorRT 加載它:
python3 onnx_export.py --model-dir=models/fruit
這將在 jetson-inference/python/training/detection/ssd/models/fruit/ 保存一個名為 ssd-mobilenet.onnx 的模型。
使用 TensorRT 處理圖像
為了對一些靜態測試圖像進??行分類,我們將使用 detectnet 并通過擴展命令行參數來加載自定義的 SSD-Mobilenet ONNX 模型。要運行這些命令,終端的工作目錄仍應位于: jetson-inference/python/training/detection/ssd/
IMAGES=<path-to-your-jetson-inference>/data/images # substitute your jetson-inference path here
detectnet --model=models/fruit/ssd-mobilenet.onnx --labels=models/fruit/labels.txt \
--input-blob=input_0 --output-cvg=scores --output-bbox=boxes \
"$IMAGES/fruit_*.jpg" $IMAGES/test/fruit_%i.jpg
以下是輸出到 $IMAGES/test 目錄的一些圖像:

運行實時攝像頭程序
您還可以嘗試在攝像機或視頻流上運行重新訓練的植物模型,如下所示:
detectnet --model=models/fruit/ssd-mobilenet.onnx --labels=models/fruit/labels.txt \
--input-blob=input_0 --output-cvg=scores --output-bbox=boxes \
csi://0
2.3.3.2 收集您自己的檢測數據集
之前使用的 camera-capture 工具還可以標記來自實時視頻的對象檢測數據集:

當 Dataset Type 下拉菜單處于 Detection 模式時,該工具會創建 Pascal VOC 格式的數據集。
注意:如果您想標記一組已有的圖像(而不是從相機捕獲的圖像),請嘗試使用類似 CVAT 的工具,并將數據集導出為 Pascal VOC 格式。然后在數據集中創建一個包含每個對象類別名稱的
labels.txt文件。
創建標簽文件
在 jetson-inference/python/training/detection/ssd/data 下創建一個空目錄用于存儲數據集,以及一個用于定義類標簽的文本文件(通常名為 labels.txt)。標簽文件每行包含一個類標簽,例如:
Water
Nalgene
Coke
Diet Coke
Ginger ale
如果您正在使用容器,您將需要將數據集存儲在像上面那樣的已掛載目錄中,以便在容器關閉后保存它。
啟動工具
該 camera-capture 工具在命令行上接受與“相機流和多媒體”頁面上相同的輸入 URI。
以下是啟動該工具的一些示例命令:
$ camera-capture csi://0 # using default MIPI CSI camera
$ camera-capture /dev/video0 # using V4L2 camera /dev/video0
收集數據
下面是 Dataset Type 下拉菜單設置為檢測模式后的 Data Capture Control 窗口。

然后,打開您創建的數據集路徑和類標簽。Freeze/Edit 和 Save 按鈕將變為活動狀態。
將攝像機對準場景中的對象,然后點擊 Freeze/Edit 按鈕(或按下空格鍵)。實時攝像機視圖將被“凍結”,您可以在對象上繪制邊界框。然后,您可以在控制窗口的網格表中為每個邊界框選擇合適的對象類別。完成圖像標記后,再次點擊按下的按鈕 Freeze/Edit 以保存數據并解凍攝像機視圖以準備下一張圖像。
控制窗口中的其他小部件包括:
- Save on UnfreezeFreeze/Edit-解凍后自動保存數據
- Clear on Unfreeze- 解凍時自動刪除先前的邊界框
- Merge Sets- 在訓練集、驗證集和測試集中保存相同的數據
- Current Set- 從訓練/驗證/測試集中選擇
- 對于物體檢測,你至少需要訓練集和測試集
- 盡管如果你檢查Merge Sets,數據將被復制為訓練、驗證和測試
- JPEG Quality- 控制保存圖像的編碼質量和磁盤大小
重要的是,您的數據應從不同的物體方向、相機視角、光照條件以及理想情況下不同的背景中收集,以創建一個能夠抵御噪聲和環境變化的模型。如果您發現模型的性能不如預期,請嘗試添加更多訓練數據并嘗試不同的條件。
訓練你的模型
收集到大量數據后,您可以嘗試使用相同的 train_ssd.py 腳本在其上訓練模型。訓練過程與上一個示例相同,但需要設置 --dataset-type=voc 和 --data=<PATH> 參數。
$ cd jetson-inference/python/training/detection/ssd
$ python3 train_ssd.py --dataset-type=voc --data=data/<YOUR-DATASET> --model-dir=models/<YOUR-MODEL>
與之前一樣,訓練結束后,您需要將 PyTorch 模型轉換為 ONNX:
$ python3 onnx_export.py --model-dir=models/<YOUR-MODEL>
轉換后的模型將保存在 <YOUR-MODEL>/ssd-mobilenet.onnx 下,然后您可以像前面的示例中一樣使用 detectnet 程序加載該模型:
NET=models/<YOUR-MODEL>
detectnet --model=$NET/ssd-mobilenet.onnx --labels=$NET/labels.txt \
--input-blob=input_0 --output-cvg=scores --output-bbox=boxes \
csi://0
注意: 務必使用生成到模型目錄的標簽文件進行推理,而不是使用最初為數據集創建的標簽文件。這是因為
BACKGROUND類會在 ``train_ssd.py` 過程中被添加到類標簽中,并保存到模型目錄(訓練好的模型預期會使用)。
如果需要,請返回并收集更多訓練數據,然后重新訓練模型。您可以重新啟動并使用 --resume 參數(運行 python3 train_ssd.py --help 以獲取更多信息)從上次中斷的地方繼續。重新訓練后,請務必將模型重新導出到 ONNX。
2.4 WebApp框架
jetson-inference 包含一個集成的 WebRTC 服務器,用于與 Web 瀏覽器進行低延遲實時視頻流傳輸,可用于構建由 Jetson 和后端邊緣 AI 驅動的動態 Web 應用程序和數據可視化工具。WebRTC 通過videoSource/videoOutputjetson-utils 的接口與 DNN 推理流水線無縫協作,后者通過 GStreamer 利用硬件加速的視頻編碼和解碼。它支持同時向多個客戶端發送和接收多個流(無需為每個獨立客戶端重新編碼視頻),并包含一個內置的 Web 服務器前端,用于遠程觀看視頻流。
此 repo 中包含使用 WebRTC 的各種示例 webapps,可在 jetson-inference/python/www 下找到:
+ python/
+ www/
- dash # Plotly Dashboard
- html # core HTML/JavaScript
- flask # Flask + REST
- recognizer # interactive training
Flask 是一個流行的 Python Web 微框架,它將 HTTP/HTTPS 請求路由到用戶實現的 Python 函數。您還可以使用它輕松處理后端 REST 請求,客戶端可以使用這些請求動態控制屬性并根據用戶輸入觸發前端內容。
Plotly Dash 是一個基于 Python 的 Web 框架,用于構建數據驅動的儀表板和交互式 UI。它在前端使用 React.js 客戶端,將狀態更改連接到服務器上運行的 Python 回調。借助它,您可以快速開發豐富的可視化效果,并與后端處理管道和數據分析集成。在此示例(位于 python/www/dash 下)中,用戶可以動態創建流、加載 DNN 模型、可視化事件以及設置由事件觸發的可擴展操作:

Recognizer 是一款基于 Flask 的視頻標記/分類 Web 應用,具有交互式數據收集和訓練功能。在視頻標記和錄制過程中,更新后的模型會在后臺使用 PyTorch 逐步重新訓練,然后通過 TensorRT 進行推理。推理和訓練可以同時進行,并且重新訓練的模型會在運行時動態加載以進行推理。


浙公網安備 33010602011771號