nncase: compiling ONNX, TFLite and Caffe models for Kendryte K210, K230 and K510 accelerators
Open deep learning compiler stack for Kendryte AI accelerators ✨
At a glance
- What is it?
- nncase is a C# neural network compiler that lowers trained models onto Kendryte AI accelerators, with a Python front end and a separate KPU runtime package. It is useful when the target chip is already fixed, and it is the wrong tool when it is not.
- Who is it for?
- Adopt nncase if your board is already a K230, K210 or K510 and your model is a TFLite, Caffe or ONNX graph whose operators appear in the corresponding ops list. Do not adopt it to compare accelerator vendors or to run a model with custom operators you cannot rewrite.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 60 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem nncase solves is a fixed target, not a fixed model
Most edge inference projects start from the silicon. You have a K230 module, or a K210 board, and you have a model that was trained somewhere else in ONNX, TFLite or Caffe. Something has to translate the graph into the instruction set and memory layout that the on-chip accelerator expects. nncase is that translator. The README describes it in one line as a neural network compiler for AI accelerators, and the repository topics list k210, k230 and k510 alongside ai-compiler and deep-learning.
The intended user is therefore not a general machine learning engineer picking a runtime. It is someone who has already committed to a Kendryte part and needs the model to execute there. That constraint shapes everything else about the project: the operator coverage is enumerated per source format rather than described as broad, the runtime is a separate installable package, and the version of nncase is tied to the version of the vendor SDK you are building against. If you are still choosing hardware, nncase answers a question you have not asked yet.
Two version lines, and the K210/K510 line lives on a branch
The README splits its documentation into two blocks. The first covers K230 and points at docs/USAGE_v2_EN.md, docs/FAQ_EN.md, an example notebook at examples/user_guide/k230_simulate-EN.ipynb, and a Colab link. The second covers K210 and K510 and points at the release/1.0 branch: USAGE_EN.md, FAQ_EN.md and the examples/user_guide directory all carry that branch prefix in their URLs.
That is the single most important structural fact about the project. If you are on K230, you are on the current line, and the recent releases bear this out: v2.11.0 in February 2026, v2.10.0 in August 2025, v2.9.0 in July 2024. If you are on K210 or K510, your documentation is not in the default branch at all. Anyone evaluating nncase without noticing the branch split will read the wrong install instructions and the wrong operator tables. The README does not spell out a support policy for the 1.0 line, so treat the branch as the authoritative artifact and check it yourself rather than assuming parity with v2.
The pipeline: a Python front end, a C# compiler, a separate KPU runtime
The primary language of the repository is C#, which is unusual for this category and worth stating plainly. The user-facing surface is Python, but the compiler itself is a .NET codebase. For most users the split only matters when something fails deep in the stack and you need to read source rather than documentation.
On the K230 path the install is two packages, not one. On Linux the README gives a single command, pip install nncase nncase-kpu. On Windows it is deliberately more manual: pip install nncase, then download nncase_kpu-2.x.x-py2.py3-none-win_amd64.whl from the releases page, then pip install that wheel by filename. The kpu package is the part that targets the accelerator; the nncase package is the compiler. Installing only the first will not get you a runnable artifact.
One design choice in the feature list is worth flagging. The README states static memory allocation, no heap memory acquired. That is a deliberate fit for embedded targets where a heap allocator is either absent or a source of fragmentation. It also means memory is committed up front, so a model that barely fits on a desktop simulator can fail to fit on the device, and the failure will be about the plan rather than about runtime behaviour.
Operator coverage is a table you must read, not a claim you can assume
The README does not say which operators nncase supports in prose. It links to lists: tflite_ops.md, caffe_ops.md and onnx_ops.md for the K230 line, and the same three filenames again on the release/1.0 branch for K210 and K510. Those lists are the contract. A graph containing an operator that is absent from the relevant file is not a configuration problem you can tune away.
The benchmark table in the README gives a sense of what has been exercised. It covers image classification (mobilenetv2 at 224x224, resnet50V2, yolov8s_cls), object detection (yolov5s_det and yolov8s_det at 640x640), segmentation (yolov8s_seg) and pose estimation (yolov8n_pose at 320 and 640, yolov8s_pose). Every row uses u8/u8 quantisation, and the accuracy columns compare the source framework result against the nncase result. For yolov8s_det the README reports mAP50-90 dropping from 0.446 to 0.404 and mAP75 from 0.484 to 0.45, while yolov8s_seg and the pose rows are close to identical. Those are the project's own published figures on the stated datasets, not an independent measurement, and the spread across rows is a reminder that quantisation loss is model-dependent rather than uniform.
Installation and the version-matching step the README outsources
The commands are short. On Linux: pip install nncase nncase-kpu. On Windows, the three-step sequence above, with the wheel downloaded from the releases page. That is the whole install story in the README.
The part that is not in the README is version matching. Two of the K230 links point at the Canaan developer site: one page documents the version relationship between nncase and K230_SDK, and another documents how to update the nncase runtime library inside the SDK. Neither is reproduced in the repository. This is a real friction point. A pip install resolves to whatever the index serves, while the runtime library on your board comes from the SDK image. If those two disagree, the symptom will appear at load or inference time rather than at install time. The README's own framing, that the SDK page describes a version relationship, tells you the project expects you to consult it before pairing a compiler with a board image.
For K210 and K510 the install instructions are on the release/1.0 branch and are not shown in the material available here, so do not reuse the K230 commands for those parts.
Where nncase is the wrong choice
The clearest failure mode is a model whose operators are not in the ops list for your source format. nncase is a compiler for a specific accelerator family, so there is no fallback path where an unsupported node simply runs on the CPU at acceptable speed. You either rewrite the model to use supported operators, or you change target.
The second case is portability. A compiled nncase artifact is tied to the Kendryte part it was built for. If the same model must also run on a phone, a Jetson or a desktop GPU, you are maintaining a second toolchain in parallel, and the quantisation scheme (u8/u8 throughout the published benchmark table) is now a constraint on both. Teams that expect one intermediate representation to serve all targets will find this arrangement awkward.
The third case is the K210 and K510 line specifically. Because its documentation sits on release/1.0 while the default branch documents K230, a K210 user is reading a branch that the recent v2.x releases do not describe. Whether that branch still receives updates is not stated in the material here, and that uncertainty should be resolved before starting new work on those parts.
How nncase differs from a general-purpose inference runtime
The natural alternative for someone already in the ONNX ecosystem is ONNX Runtime, which executes a graph through a set of execution providers. The difference in approach is where the work happens. ONNX Runtime carries the graph to the hardware and dispatches nodes to whatever provider can handle them, falling back to CPU where none can. nncase does the opposite: it compiles ahead of time for one accelerator family, allocates memory statically with no heap acquisition, and produces an artifact that assumes the Kendryte part is present.
That trade is legible. You give up target portability and the ability to absorb an unsupported operator through a CPU fallback, and you get a build that is sized and scheduled for the device before it ever runs. It also explains why the operator lists are per source format rather than a single capability statement: the compiler is reasoning about what it can lower onto fixed hardware, not about what a generic runtime can execute somewhere.
For a K230 board, the comparison is not really nncase versus ONNX Runtime. It is nncase versus writing the kernel work yourself, which is the situation the project exists to avoid.
Licence, maintenance and what to verify before committing
nncase is Apache-2.0. That is a permissive licence, and it is the same identifier for the repository as a whole; the material here does not break out per-file licensing or third-party components, so if your organisation has strict review requirements, check the repository's own notices rather than relying on the top-level identifier. Nothing here is legal advice.
On maintenance cost, the release cadence visible in the material is uneven: v2.9.0 in July 2024, v2.10.0 in August 2025, v2.11.0 in February 2026. The gaps are measured in months, not weeks. The upgrade cost that matters is not the pip command, it is the pairing between the nncase version and the K230_SDK version, which the README delegates to an external page. A board image and a compiler wheel that drift apart are the failure you are managing.
Before committing, verify three things against the repository rather than against this article. First, that every operator in your graph appears in the ops file for your source format and your chip line. Second, which branch applies to your part, since K210 and K510 documentation lives on release/1.0 and not on master. Third, the nncase-to-SDK version pairing on the developer site the README links. If your model is a yolov8-family detection or pose network at 640x640 in u8/u8, the published table gives you a starting point for expected accuracy drift; if it is anything else, that table tells you nothing about your case.
Editorial conclusion
Adopt nncase if your board is already a K230, K210 or K510 and your model is a TFLite, Caffe or ONNX graph whose operators appear in the corresponding ops list. Do not adopt it to compare accelerator vendors or to run a model with custom operators you cannot rewrite. Before writing production code, check the K230_SDK version relationship page against the nncase release you plan to install, and confirm that every operator in your graph is listed for your source format.
Community notes