YOLO11 with TensorRT on Jetson Orin Nano

Jetson Orin

はじめに

こちらの記事に従い、Jetson Orin Nanoをセットアップします。今回この記事では、NVIDIA Jetson Linux 36.4.4 を使用しJetson OrinNanoをセットアップしました。

https://docs.ultralytics.com/ja/guides/nvidia-jetson を参考にしています。

なお以下の作業はすべてJetson Orin Nano上で行います。

nvidia dockerのインストール

sudo apt update
sudo apt install -y nvidia-container curl
curl https://get.docker.com | sh
sudo usermod -aG docker $USERCode language: Bash (bash)

ここまで実施したら一度再起動します

sudo rebootCode language: Bash (bash)

dockerコマンドが正しく動作するか確認します。

$ docker run --rm hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c9c5fd25a1bd: Pull complete 
Digest: sha256:ec153840d1e635ac434fab5e377081f17e0e15afab27beb3f726c3265039cfff
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
...Code language: Bash (bash)

dockerコマンドに失敗する場合、https://bone.jp/articles/2025/250314_docker_raw_table の記事を参照してください。なお、最新のJetPackではこの問題が解消されているようです。

yolo11s.pt と yolo11s.engine の作成

dockerコンテナで yolo11s.pt とTensorRT用の yolo11s.engine を取得します。

mkdir -p data
docker run -it --ipc=host --runtime=nvidia -v $(pwd)/data:/data ultralytics/ultralytics:latest-jetson-jetpack6Code language: Bash (bash)

dockerインスタンスで以下を実行します。

yolo export model=yolo11s.pt format=engine half=True
cp yolo11s.pt yolo11s.engine /dataCode language: Bash (bash)

一度dockerインスタンスを終了させます。

exitCode language: Bash (bash)

yolo11s.pt と yolo11s.engine の速度比較

以下のスクリプト pred.py を /data に配置します。

import time

import cv2
from ultralytics import YOLO


def draw_results(frame, results, names):
    for result in results:
        boxes = result.boxes

        if boxes is not None:
            for box in boxes:
                x1, y1, x2, y2 = box.xyxy[0].cpu().numpy().astype(int)
                confidence = box.conf[0].cpu().numpy()
                class_id = int(box.cls[0].cpu().numpy())
                class_name = (
                    names[class_id] if class_id < len(names) else f"Class_{class_id}"
                )
                cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
                label = f"{class_name}: {confidence:.2f}"

                (text_width, text_height), _ = cv2.getTextSize(
                    label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2
                )

                cv2.rectangle(
                    frame,
                    (x1, y1 - text_height - 5),
                    (x1 + text_width, y1),
                    (0, 255, 0),
                    -1,
                )

                cv2.putText(
                    frame,
                    label,
                    (x1, y1 - 5),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.5,
                    (0, 0, 0),
                    2,
                )


def main(dev, model):

    fps_counter = 0
    start_time = time.time()
    fps = 0

    yolo = YOLO(model)
    cap = cv2.VideoCapture(dev)
    if not cap.isOpened():
        print("error: cap.isOpened")
        return
    cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc("M", "J", "P", "G"))
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    cap.set(cv2.CAP_PROP_FPS, 60)

    w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    fps = cap.get(cv2.CAP_PROP_FPS)
    print(f"{w}x{h}@{fps}")

    while True:
        ret, frame = cap.read()
        if not ret:
            print("error: cap.read")
            return
        results = yolo.predict(frame, half=True, device="cuda:0", verbose=False)
        draw_results(frame, results, yolo.names)

        fps_counter += 1
        elapsed_time = time.time() - start_time
        if elapsed_time >= 1.0:  # show fps every second
            fps = fps_counter / elapsed_time
            fps_counter = 0
            start_time = time.time()

        fps_text = f"FPS: {fps:.1f}"
        cv2.putText(
            frame, fps_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2
        )
        # print(fps_text)

        cv2.imshow(f"{dev}", frame)
        key = cv2.waitKey(1) & 0xFF
        if key == ord("q"):
            print("quit")
            break

    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--dev", type=int, default=0, help="Camera device index")
    parser.add_argument(
        "--model",
        type=str,
        default="yolo11n.pt",
        help="Path to the YOLO model (default: yolo11n.pt)",
    )
    args = parser.parse_args()
    main(args.dev, args.model)
Code language: Python (python)

Jetson Orin NanoのUSBにwebカメラを接続し以下のコマンドでdockerインスタンスを起動させます。

xhost +local:
docker run -it --rm \
        --device=/dev/video0:/dev/video0:mrw \
        -e DISPLAY=$DISPLAY \
        -v /tmp/.X11-unix/:/tmp/.X11-unix \
        --ipc=host \
        -v $(pwd)/data:/data \
        --runtime=nvidia \
        ultralytics/ultralytics:latest-jetson-jetpack6Code language: Bash (bash)

dockerインスタンスで以下を実行します。

apt update
apt install libice6 libsm6Code language: Bash (bash)

yolo11s.pt の速度を見てみます。

python /data/pred.py --dev 0 --model /data/yolo11s.ptCode language: Bash (bash)

20fps程度でした。

つづいて、yolo11s.engine の速度を見てみます。

python /data/pred.py --dev 0 --model /data/yolo11s.engineCode language: Bash (bash)

22fps程度でした。

training memo

学習はdockerコンテナに /dataset をマウントし以下を実行します。特に Jetson Orin Nanoではbatch=4 を指定します。

yolo detect train data=/dataset/my-config.yaml model=yolo11s.pt batch=4 Code language: JavaScript (javascript)

以上です!

$ cat dataset/config.yaml
mode: train
data: /dataset/tiles-docker.yaml
model: yolo11s.pt
epochs: 1000
batch: 4
degrees: 180.0
translate: 0.1
scale: 0.5
shear: 5.0
perspective: 0.0005
flipud: 0.0
fliplr: 0.0
project: /run
$ docker run -it --rm -v $(pwd)/run:/run -v $(pwd)/dataset:/dataset--ipc host --runtime nvidia ultralytics/ultralytics:latest-jetson-jetpack6
# yolo detect train cfg=/dataset/config.yaml model=/run/train5/weights/best.ptCode language: PHP (php)

参照

NVIDIA ジェットソン
NVIDIA JetsonデバイスへのUltralytics YOLO11 、詳細なガイドをご覧ください。性能ベンチマークを調べ、AI機能を最大限に活用しましょう。
docker 28.0.1がJetson Linuxなどでiptables failedする(OSアップデートで解決)
docker-ceの28.0.0へ更新でJetson Linuxなどで不具合が出ました。28.0.1でもカーネルモジュールiptable_rawへの依存があり不具合が続いています。28.0.2ではdocker.serviceの環境変数追加で緩和されます。Jetson Linux 36.4.4へのアップデートで最終解決し...