A Dockerized tool to convert ONNX models (specifically targeting image upscalers like ESRGAN) to the RKNN format for Rockchip NPUs (tested on RK3566).
Converting models for Rockchip NPUs using their official rknn-toolkit2
is... an experience. Its documentation is a masterpiece of obfuscation, and key features like dynamic_input
(essential for models that should handle variable input sizes, like image upscalers) are fundamentally broken for many (if not all) architectures, leading to crashes (Segmentation fault
) or garbage output during inference.
After much suffering, apparently the only reliable method found was to generate separate RKNN models for each specific, fixed input resolution needed, bypassing the buggy dynamic shape handling. Doing this manually for multiple resolutions is tedious and error-prone.
This tool takes a single ONNX model (which should ideally support dynamic input dimensions, although the tool can sometimes force a fixed size even on static ONNX files) and generates multiple RKNN models, each compiled for a specific, fixed input resolution (e.g., 1280x256, 1920x1080).
It uses the rknn-toolkit2
library inside a Docker container with pinned dependencies to ensure a consistent environment, leveraging the (working) input_size_list
parameter during rknn.load_onnx()
to force the desired input shape for each conversion.
- Dockerized: Packages everything into a neat container with pinned dependencies (
rknn-toolkit2==2.3.0
, specificonnx
,numpy
, etc.) for reproducibility. - Handles URLs and Local Files: Provide an HTTP(S) URL or a local filename for the source ONNX model.
- Multiple Resolutions: Generates multiple RKNN models for a list of specified fixed input resolutions (e.g.,
1440x384
,1536x512
). - Automatic Input Name Detection: Uses the
onnx
library to find the input tensor name automatically. - Fixed Shape Output: Generates reliable RKNN models by targeting fixed input shapes.
- GitHub Actions Workflow: Includes a workflow to automatically:
- Build the converter Docker image (caching layers in GHCR).
- Download an ONNX model from a URL.
- Convert the model for specified resolutions in parallel.
- Create a GitHub Release containing the generated
.rknn
files.
This repository includes a reusable GitHub Actions workflow to automate the process entirely within GitHub.
- Fork this repository.
- Go to the "Actions" tab of your repository fork.
- Select the "ONNX to RKNN Conversion" workflow.
- Click "Run workflow".
- Fill in the inputs:
URL of ONNX model to convert
: URL to the source ONNX model.Comma-separated list of target resolutions
: Just like it saysTarget platform for conversion
: Target Rockchip platform (e.g.,RK3566
,RK3588
). Default:RK3566
.Custom release tag
: (Optional) A custom tag for your release. If left empty, the release tag will bemodels-<run_id>
Custom release name
: (Optional) A custom name for your release. If left empty, the release name will look like<source_model_filename> for <target_platform>
- Click "Run workflow".
- Wait: The workflow will:
- Build and push the converter Docker image to your repository's GHCR (it will be used as a cache in the next runs).
- Download the ONNX model.
- Run the conversion for each specified resolution in parallel jobs.
- Collect all generated
.rknn
files. - Create a new GitHub Release tagged
models-<run_id>
containing the.rknn
files as assets and release notes.
- Download: Go to the Releases page of your repository and download the
.rknn
files attached to the newly created release.
This is useful for testing or converting models locally.
Prerequisites:
- Docker and Docker Compose installed.
Setup:
- Clone this repository.
- (Optional) Place your local ONNX model file inside the
./input_models/
directory. - Edit the
command:
section indocker-compose.yml
to specify your conversion parameters:--model_source
: Change this to your ONNX model's URL or the filename of a model placed in./input_models/
.--resolutions
(optional): Provide a comma-separated list ofWidthxHeight
resolutions you need (e.g.,"1440x320,1536x576"
). If omitted, it uses a default list defined in the script.--target_platform
(optional): Specify the target chip (e.g.,RK3588
). Defaults toRK3566
.-v
or--verbose
(optional): Add this for more detailed logs fromrknn-toolkit2
.
- Run the conversion:
docker-compose up --build
--build
is only needed the first time or if you changeDockerfile
orconvert.py
.- Watch the logs. The script should download the model (if needed) and convert it for each specified resolution.
- Find your models: The generated
.rknn
files will appear in the./output_models/
directory on your host machine. The filenames will include the target platform and resolution (e.g.,YourModel_rk3566_1440x320.rknn
). - Stop the container:
docker-compose down
Examples of command
in docker-compose.yml
:
-
Using a URL and specific resolutions to run on the RK3588 platform:
command: > --model_source https://huggingface.co/some_user/some_model/resolve/main/model.onnx --resolutions 1280x256,1024x512 --target_platform RK3588 --verbose
-
Using a local file and default resolutions:
command: > --model_source my_local_esrgan.onnx
- Segmentation Faults during Inference: If the generated
.rknn
model still crashes the NPU during inference (especially with large resolutions), it might be hitting hardware memory limits or bugs in the specific model/operator conversion for that size. Try converting for slightly smaller resolutions. - Model Size: Don't be surprised if the "fixed-shape"
.rknn
files generated by this method are larger than expected. The conversion process isn't always perfectly optimized.
dynamic_input
is broken/misleading: Don't use it inrknn.config
. It doesn't provide true dynamic shapes and often leads to errors or crashes.input_size_list
is key: Specifying a fixed shape viainput_size_list
inrknn.load_onnx()
is the reliable way to generate a model for a specific target resolution, even from an ONNX model that claims to have dynamic axes.inputs
parameter is critical: You must provide the correct input tensor name(s) via theinputs
parameter inrknn.load_onnx()
, otherwiseinput_size_list
might be ignored, defaulting to 128x128 or 64x64 input. (This script detects the name automatically).- Weird parameters: Some
rknn.config
options likecompress_weight
might increase model size, andquantize_weight
is deprecated in a way that makes it unusable on some platforms. Stick to basics unless you enjoy pain. librknnrt.so
location: The Python toolkit expects the native runtime library (librknnrt.so
) in weird hardcoded paths like/usr/lib64
. The NPU service (upscaler.py
in the other project) uses a workaround to copy/link this library at container start. The converter doesn't need this library as it only uses the toolkit's Python parts.
Feel free to open issues or PRs if you find bugs or ways to improve this clusterfuck.