Skip to main content

ResNet101 Image Classification

Run ResNet101 image classification with the glasses.jpg image supplied by Qualcomm. The sample resizes the input to 224 x 224, runs inference on the DSP through the QNN HTP backend, and publishes the highest-scoring class as a text message.

This page covers local image input only. QRB, GMSL, and USB camera input were not verified.

Pipeline

glasses.jpg
-> image_publisher -> /image_raw
-> resize to 224 x 224
-> /qrb_inference_input_tensor
-> QNN ResNet101 inference
-> /qrb_inference_output_tensor
-> ImageNet label mapping
-> /resnet101_output

ROS 2 Topics

TopicTypeDescription
/image_rawsensor_msgs/msg/ImageInput image
/qrb_inference_input_tensorqrb_ros_tensor_list_msgs/msg/TensorListPreprocessed tensor
/qrb_inference_output_tensorqrb_ros_tensor_list_msgs/msg/TensorListQNN inference output tensor
/resnet101_outputstd_msgs/msg/StringImageNet classification label

The Qualcomm user guide lists /resnet101_results in its topic table, but both the current Debian package and source publish /resnet101_output.

Prerequisites

  • QIR SDK installed
  • GitHub and Hugging Face access from the Q900
  • At least 50 MB free under /opt/model

Run the Debian Package

Step 1: Install the Sample

radxa@airbox$
sudo apt install -y ros-jazzy-sample-resnet101

Step 2: Verify the Model and Repair the ImageNet Labels

First verify the model downloaded by the package. The post-installation script in ros-jazzy-sample-resnet101 1.0.1 uses a GitHub path that has since moved and may leave a zero-byte /opt/model/imagenet_labels.txt, so download the labels from their current path:

radxa@airbox$
echo "bfed3e96598ed276600a1e53c8a59decd287258881cd9849141a20a76e0da803  /opt/model/ResNet101_w8a8.bin" | \
sha256sum --check
sudo wget \
https://raw.githubusercontent.com/quic/ai-hub-models/refs/heads/main/src/qai_hub_models/labels/imagenet_labels.txt \
-O /opt/model/imagenet_labels.txt
echo "e697a491aa735cc6c2aaf982f8e86e8fc7b0a1ea7750a2cc6a2bdfc1e109012f /opt/model/imagenet_labels.txt" | \
sha256sum --check

Expected output:

/opt/model/ResNet101_w8a8.bin: OK
/opt/model/imagenet_labels.txt: OK

Step 3: Launch the Sample

radxa@airbox$
source /opt/ros/jazzy/setup.bash
export ROS_DOMAIN_ID=123
ros2 launch sample_resnet101 launch_with_image_publisher.py

The launch file publishes /opt/ros/jazzy/share/sample_resnet101/glasses.jpg at 10 Hz by default and uses /opt/model/ResNet101_w8a8.bin. You can also specify another local image:

radxa@airbox$
ros2 launch sample_resnet101 launch_with_image_publisher.py \
image_path:=<your-local-image-path>

Build from Source

Step 1: Install Dependencies

radxa@airbox$
sudo apt install -y \
ros-dev-tools \
ros-jazzy-rclpy \
ros-jazzy-sensor-msgs \
ros-jazzy-std-msgs \
ros-jazzy-cv-bridge \
ros-jazzy-ament-index-python \
ros-jazzy-qrb-ros-tensor-list-msgs \
ros-jazzy-image-publisher \
ros-jazzy-qrb-ros-nn-inference \
ros-jazzy-qrb-ros-camera \
python3-opencv \
python3-numpy

Step 2: Prepare the Model and Labels

radxa@airbox$
sudo mkdir -p /opt/model
sudo wget \
https://huggingface.co/qualcomm/ResNet101/resolve/121564046ebb2353d4a0aa67bf89c11e0c8e80d9/ResNet101_w8a8.bin?download=true \
-O /opt/model/ResNet101_w8a8.bin
sudo wget \
https://raw.githubusercontent.com/quic/ai-hub-models/refs/heads/main/src/qai_hub_models/labels/imagenet_labels.txt \
-O /opt/model/imagenet_labels.txt

Verify both files:

radxa@airbox$
echo "bfed3e96598ed276600a1e53c8a59decd287258881cd9849141a20a76e0da803  /opt/model/ResNet101_w8a8.bin" | \
sha256sum --check
echo "e697a491aa735cc6c2aaf982f8e86e8fc7b0a1ea7750a2cc6a2bdfc1e109012f /opt/model/imagenet_labels.txt" | \
sha256sum --check

Step 3: Clone the Source

Use the workspace path from the official sample:

radxa@airbox$
mkdir -p ~/qrb_ros_ws/src && cd ~/qrb_ros_ws/src
git clone https://github.com/qualcomm-qrb-ros/qrb_ros_samples.git

Step 4: Build

radxa@airbox$
cd ~/qrb_ros_ws/src/qrb_ros_samples/ai_vision/sample_resnet101
source /opt/ros/jazzy/setup.bash
colcon build
source install/setup.bash

Expected output:

Starting >>> sample_resnet101
Finished <<< sample_resnet101
Summary: 1 package finished

Step 5: Run the Source Build

radxa@airbox$
cd ~/qrb_ros_ws/src/qrb_ros_samples/ai_vision/sample_resnet101
source /opt/ros/jazzy/setup.bash
source install/setup.bash
export ROS_DOMAIN_ID=123
ros2 launch sample_resnet101 launch_with_image_publisher.py

Expected Output

The model initializes and repeatedly performs inference:

Loaded 1000 class labels.
/usr/lib/libQnnHtp.so initialize successfully
Qnn device initialize successfully
Initialize Qnn graph from binary file successfully
Inference init successfully!
Inference execute successfully!

Validation

Check the actual output topic from another terminal:

radxa@airbox$
export ROS_DOMAIN_ID=123
source /opt/ros/jazzy/setup.bash
ros2 topic info /resnet101_output -v
ros2 topic echo /resnet101_output --once

The default glasses.jpg should produce:

data: sunglass
---

The Debian package 1.0.1 may display extra line breaks after sunglass. This is a formatting difference caused by how that version reads the labels and does not affect the classification result. The current source removes the extra line break.

Stop

Press Ctrl + C in the terminal running the sample.

When stopped during continuous inference, the QNN container may exit with -11, and the Python nodes may print ExternalShutdownException. These errors occur during shutdown and do not affect classifications published earlier; confirm that the related processes have exited.

Limitations

  • Only the local image supplied by Qualcomm was verified. Camera input was not tested.
  • Cross-device topic inspection was not tested. Only local Q900 inference and result publication were validated.
  • ResNet101 returns one of 1000 ImageNet labels; it does not return object locations or bounding boxes.

    You need to be logged into GitHub to post a comment. If you are already logged in, please ignore this message.

    Radxa-docs © 2026 by Radxa Computer (Shenzhen) Co.,Ltd. is licensed under CC BY 4.0