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
onnxlibrary 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
.rknnfiles.
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
.rknnfiles. - Create a new GitHub Release tagged
models-<run_id>containing the.rknnfiles as assets and release notes.
- Download: Go to the Releases page of your repository and download the
.rknnfiles 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.ymlto 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 ofWidthxHeightresolutions 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.-vor--verbose(optional): Add this for more detailed logs fromrknn-toolkit2.
- Run the conversion:
docker-compose up --build
--buildis only needed the first time or if you changeDockerfileorconvert.py.- Watch the logs. The script should download the model (if needed) and convert it for each specified resolution.
- Find your models: The generated
.rknnfiles 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
.rknnmodel 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"
.rknnfiles generated by this method are larger than expected. The conversion process isn't always perfectly optimized.
dynamic_inputis broken/misleading: Don't use it inrknn.config. It doesn't provide true dynamic shapes and often leads to errors or crashes.input_size_listis key: Specifying a fixed shape viainput_size_listinrknn.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.inputsparameter is critical: You must provide the correct input tensor name(s) via theinputsparameter inrknn.load_onnx(), otherwiseinput_size_listmight be ignored, defaulting to 128x128 or 64x64 input. (This script detects the name automatically).- Weird parameters: Some
rknn.configoptions likecompress_weightmight increase model size, andquantize_weightis deprecated in a way that makes it unusable on some platforms. Stick to basics unless you enjoy pain. librknnrt.solocation: The Python toolkit expects the native runtime library (librknnrt.so) in weird hardcoded paths like/usr/lib64. The NPU service (upscaler.pyin 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.