Sima.ai Modalix Yolo26s capabilities

Sima.ai Modalix Yolo26s capabilities

July 10, 2026 by Anirudh Kuldeep
Share

160 FPS at the Edge: Deploying YOLO26s on SiMa Modalix pipeline diagram

160 FPS at the Edge: Deploying YOLO26s on the SiMa Modalix DevKit

A practical, no-nonsense walkthrough for getting a YOLO model running on dedicated NPU silicon.

We've all seen the flashy edge inference benchmarks boasting massive FPS numbers. But if you've ever actually tried taking a trained model checkpoint and squeezing genuine real-time throughput out of a dedicated NPU, you know the truth: the SDK quickstart guides conveniently skip the messy parts. They don't tell you how to export the model, where to split it before compression, which hyper-specific compiler flags your hardware actually demands, or how to map the raw output back into something usable.

This is a guide to getting YOLO26s running on the SiMa Modalix DevKit—taking a stock Ultralytics checkpoint and turning it into a compiled package doing real-time object detection on-device. The payoff? Roughly 160 frames per second at about 6.2 milliseconds of latency per frame. To get there, we have to navigate four specific bottlenecks where the wrong default setting will either break your build entirely or quietly sabotage your results. Let's break down the pipeline, the reasoning behind the fixes, and the actual commands you need to run.

How the Pipeline Is Organized

The workflow splits cleanly across two machines: your host computer and the DevKit itself. Think of your host machine as the workshop. This is where all the heavy, iterative prep work happens (exporting, restructuring, compressing, and compiling). Mistakes here are cheap and easy to fix. The DevKit (the edge device with the NPU) is just the showroom—it never sees the prep work; it only runs the finished, validated artifact.

Host Machine
Workshop

Exporting, restructuring, compressing, and compiling. Mistakes here are cheap and easy to fix.

DevKit
Showroom

The edge device with the NPU. It never sees the prep work; it only runs the finished, validated artifact.

Before we start: All the host-side prep work happens inside SiMa's dedicated SDK container, not your host's local Python environment. Fire up that container first, and then drop into the model-compilation environment:

# Start the SiMa SDK container
sima-cli sdk neat

# Inside the container, activate the model-compilation environment
activate-model-compilor

Everything from Step 2 onward assumes you are in this activated environment. If you get a "command not found" or import error, check that you're actually in the container before tearing your hair out over the pipeline.

Step 1: Gathering a Sample Set of Images

Before we can compress the model, we need a representative handful of real-world images. We don't need thousands—just a few dozen from a standard public dataset will do. These serve a dual purpose: calibrating the compression process and sanity-checking the deployed model later.

# Download COCO val2017 images
wget http://images.cocodataset.org/zips/val2017.zip
unzip val2017.zip

# Download annotations
wget http://images.cocodataset.org/annotations/annotations_trainval2017.zip
unzip -j annotations_trainval2017.zip 'annotations/instances_val2017.json'

# Pull out a 50-image subset for calibration + evaluation
mkdir -p calib_images
ls val2017/ | head -50 | while read f; do cp "val2017/$f" calib_images/; done

Step 2: Exporting the Model in Its Raw Form

Your first big decision is how to export the trained model. YOLO detectors usually give you the option to bake the final cleanup steps (like filtering overlapping detections) right into the exported model. Don't do it. Keep the model's internal structure simple by exporting only the raw prediction output. More importantly, leaving it raw keeps the predicted box positions and the class confidences bundled together for now, which sets us up for the most critical fix in this entire guide (see Step 4).

Step 3: Locking the Model to a Fixed Input Size

Hardware compilers despise flexibility. A model that can theoretically accept images of any shape or size is a nightmare to optimize. Do yourself a favor and mechanically lock your model to a single, fixed input size before compression. Stripping out the conditional logic leftover from training will save you from cryptic compiler errors down the road.

Step 4: The Fix That Matters Most

If you only take one idea from this guide, make it this: separate the two kinds of output. A YOLO detector does not produce one clean, uniform result. Instead, it emits a bundled set of values for every candidate box: the box coordinates, which describe where the object is and how large it is, plus the class confidence scores, which describe how likely each class is. On paper, they arrive together. In practice, they are very different kinds of numbers.

That difference matters because the two outputs live on completely different scales. Box coordinates are usually measured in pixels, so they can reach into the hundreds or even higher depending on the image size. Confidence scores, by contrast, are tiny probabilities or logits that often sit between zero and one. They carry very different meaning, and they behave very differently when you compress them.

Box Coordinates
Measured in pixels, these values can span a wide numerical range and need room to stay precise.
Confidence Scores
These are delicate decimal values, usually squeezed between zero and one, where even small distortions can change the model's decisions.

Once you compress a model to a lower-precision format for the NPU, the hardware toolchain typically applies one shared scale across an entire output tensor. That works only when the values in that tensor are numerically similar. But here, the coordinates and the confidence scores are not similar at all. If the scale is widened enough to preserve the large coordinate values, the small confidence values lose their detail and collapse into nearly useless noise.

In other words, the model may still run, but it stops being trustworthy. The detections start to look unstable because the confidence values no longer have enough resolution to express meaningful differences between classes. A score that should clearly separate a strong prediction from a weak one can get flattened into something too coarse to use well.

The fix: Physically split the outputs before compression starts. Give box positions their own wide scale, and give confidence scores their own narrow scale. That small structural change protects precision where it matters most and keeps the compressed model usable on real hardware.

This is a tiny rewrite of the output structure, but it has an outsized effect. It allows the compiler and quantization process to treat each kind of data appropriately instead of forcing both through the same numeric bottleneck. The result is simple: the detector can still fit the hardware constraints without sacrificing the quality of its predictions.

Step 5: Compressing and Compiling for the Hardware

With the outputs already separated into clean, hardware-friendly groups, we can finally move into the part that turns a trained model into something the Modalix chip can actually execute efficiently: compression and compilation.

Compression reduces numerical precision so the model uses less memory and fits the chip's execution constraints. Compilation goes a step further—it rewrites the model into the exact instruction flow the NPU expects. On a chip like Modalix, this matters a lot because the hardware is optimized for aggressive parallelism, fast on-chip routing, and specialized internal layouts that are much more rigid than a general-purpose GPU or CPU.

That flexibility is also where the pain comes from. Modalix supports advanced compute patterns, including attention-style operations and other nonstandard detection-head behaviors, but those patterns do not automatically map cleanly onto the chip's default assumptions. If the compiler is left to guess, it may place tensors in the wrong geometry or choose a layout the runtime cannot execute efficiently. The result is the dreaded geometry mismatch error—usually discovered only after a long compile cycle, and often with very little context to explain what went wrong.

This is why the process has to be explicit. You are not just shrinking the model; you are teaching the compiler how to respect the chip's internal structure. The more accurately you describe the model's layout and data flow, the more likely the compiler is to generate a build that is both correct and performant.

python3 quantize_compile.py \
  --model_path yolo26s_noe2e_split.onnx \
  --model_layout NHWC \
  --device modalix \
  --build_dir ./build \
  --real_data \
  --dataset_images ./calib_images \
  --num_calib_samples 50 \
  --calib_method mse \
  --any_shape_on_mla \
  --auto_layout \
  --mla-tesselation \
  --compile

Why these flags matter

--model_path yolo26s_noe2e_split.onnx points the tool at the split-output model, which is the version that can be safely quantized without mixing box coordinates and confidence scores into one fragile range.
--model_layout NHWC tells the compiler how the tensor dimensions are organized, so it can interpret the model consistently and map data movement correctly across the chip.
--device modalix selects the target hardware profile, which is important because the compiler needs to optimize for Modalix-specific execution rules instead of a generic accelerator model.
--build_dir ./build keeps the generated artifacts in a dedicated folder, making it easier to inspect logs, compare builds, and rerun the pipeline without cluttering the project root.
--real_data, --dataset_images ./calib_images, and --num_calib_samples 50 tell the compressor to calibrate using real COCO-style images instead of synthetic placeholders, which usually produces a much more trustworthy quantization range.
--calib_method mse asks the compiler to preserve the values that matter most by minimizing reconstruction error, which is especially useful when small activation differences can affect detection quality.
--any_shape_on_mla and --auto_layout give the compiler permission to adapt unusual attention-style operations to Modalix's matrix/layout accelerator path instead of rejecting them outright.
--mla-tesselation is the key compatibility flag for the runtime routing problem. It helps break the work into pieces that fit the chip's internal topology, which is often what resolves geometry-related failures.
--compile actually starts the build. This is where the compiler spends real time scheduling operators, assigning memory, and translating the model into a hardware-executable form.

Step 6: Moving the Compiled Package to the Device

The hard part is over. Now, we just transfer the compiled package and our test images over the network to the DevKit.

DEVKIT_IP="${1:-192.168.0.27}"
DEVKIT_USER="${2:-sima}"
REMOTE_DIR="/home/${DEVKIT_USER}/yolo_eval"

# Prepare remote directory
ssh "${DEVKIT_USER}@${DEVKIT_IP}" "mkdir -p ${REMOTE_DIR}/test_images"

# Copy the compiled package
scp build/yolo26s_noe2e_split/yolo26s_noe2e_split_mpk.tar.gz \
  "${DEVKIT_USER}@${DEVKIT_IP}:${REMOTE_DIR}/"

# Copy the same sample images used for calibration
scp calib_images/*.jpg "${DEVKIT_USER}@${DEVKIT_IP}:${REMOTE_DIR}/test_images/"

# Copy the dataset's annotation file (vital for Step 7)
scp instances_val2017.json "${DEVKIT_USER}@${DEVKIT_IP}:${REMOTE_DIR}/"

Step 7: Running Inference and Making Sense of the Output

Now we run the pipeline end-to-end on the hardware. Here is what happens under the hood to get usable data back:

1
Letterboxing (Resizing without distorting)
You can't just stretch rectangular camera images into the model's square input—it ruins object proportions. You have to shrink the image proportionally and pad the empty space with a neutral color. When the model outputs boxes later, you have to reverse-engineer that math (undo the padding, then undo the resize ratio) to map the boxes back to the original image.
2
Decoding Boxes
The model outputs a center point, width, and height. You have to do the quick arithmetic to turn that into usable top-left and bottom-right corners.
3
Non-Maximum Suppression (NMS)
The model will guess the same object multiple times. NMS takes the most confident box and deletes any other boxes that heavily overlap it and claim to be the same category.
4
Mapping Labels
Beware the silent failure. Models output categories as index numbers (e.g., "Category 62"). But public datasets often have gaps in their numbering schemes, meaning Index 62 might not equal Dataset Label 63. You have to build a mapping directly from the dataset's JSON, rather than relying on a hardcoded offset. If you skip this, your model will look highly confident while quietly mislabeling everything.

Kick off the loop on your device with:

source ~/pyneat/bin/activate
cd ~/yolo_eval
python3 evaluate_devkit.py \
  yolo26s_noe2e_split_mpk.tar.gz \
  test_images \
  instances_val2017.json \
  50

Step 8: The "Sanity Check" (Optional but Recommended)

Before you blame the NPU or the compiler for weird results, run the exported model on your standard host computer using a basic CPU inference script. We aren't looking for performance here; we are isolating variables. If your bounding boxes are drawing in the wrong places, running it on the CPU will tell you if you have a bug in your Python resizing math, rather than sending you on a wild goose chase debugging hardware quantization.

Why This Check Matters

The CPU path gives you a trustworthy baseline. If the exported model behaves strangely on CPU, the issue is usually in preprocessing, postprocessing, label mapping, or export settings—not the accelerator itself. That makes the sanity check the fastest way to separate model bugs from hardware bugs.

What to Look For
  • Do boxes appear in the correct place on the image?
  • Are the box sizes roughly reasonable?
  • Do class labels match the objects you expect?
  • Are confidence scores sensible, or are they all tiny or all maxed out?
  • Does the model detect the same objects on repeated runs?
Common Failure Modes
  • Wrong resize or padding math: boxes drift, shift, or appear stretched.
  • Channel order mismatch: RGB/BGR confusion changes image content entirely.
  • Normalization mismatch: values may need 0–1 or mean/std scaling.
  • Label map mismatch: class IDs don't line up with dataset labels.
  • Threshold too high or low: filters out real detections or keeps noise.
  • NMS differences: hides valid boxes or duplicates them.
How to Diagnose It
  1. Run one known image on CPU and save the raw outputs before any plotting.
  2. Print the top few boxes, scores, and class IDs to confirm the model is producing sane numbers.
  3. Overlay the boxes on the original image and compare against the resized input.
  4. Temporarily disable parts of postprocessing, such as NMS or score filtering.
  5. Check one stage at a time: load, resize, pad, model input, output, decode, draw.

Comparing CPU vs NPU Outputs

Once the CPU baseline looks right, compare it with the NPU output on the same image. Small differences are normal, but the overall result should still be recognizable and stable.

Stage 1
Compare Raw Outputs
If possible, compare the tensors before postprocessing. Slight numeric differences are expected because different runtimes and quantization paths use different arithmetic.
Stage 2
Compare Decoded Boxes
After decoding, the NPU and CPU should still agree on object locations, class order, and general confidence ranking. Minor shifts are okay; major shifts are not.
Stage 3
Compare Final Overlays
The final visual output should look nearly the same. If the CPU looks correct and the NPU is wildly off, the problem is usually in export, quantization, or accelerator-side preprocessing assumptions.

Objectives Achieved

End-to-end deployment pipeline validated. A stock Ultralytics YOLO26s checkpoint was carried all the way from export through INT8 quantization and compilation to a running, hardware-executable package on the Modalix DevKit.
Sub-10ms latency achieved. Per-frame latency dropped from around 200ms on CPU to about 6.2ms on the NPU, comfortably inside real-time budgets.
Output-splitting fix prevented precision collapse. Separating box coordinates from confidence scores before quantization kept detection quality intact instead of flattening confidence values into noise.
Geometry mismatch errors resolved. The correct combination of layout, tesselation, and auto-layout flags let the compiler map the model onto Modalix's internal topology without manual intervention.
Calibration done on real data. Using a real 50-image COCO subset for MSE-based calibration produced a trustworthy quantization range instead of relying on synthetic placeholders.
CPU and NPU outputs cross-validated. Raw tensors, decoded boxes, and final overlays were checked stage by stage, confirming the NPU results were stable and trustworthy against the CPU baseline.
Label mapping handled correctly. Category indices were mapped directly from the dataset's JSON rather than a hardcoded offset, avoiding silent mislabeling.

Practical Debugging Tips

  • Use one simple test image first, preferably with large, obvious objects.
  • Keep a copy of the exact preprocessing code used for both CPU and NPU runs.
  • Log image shape, scale ratio, padding values, and output tensor shape.
  • Test with NMS off once to see whether the issue is decoding or suppression.
  • Verify that the same label file and class order are used in every stage.
  • If the CPU result is wrong too, fix the Python pipeline before touching the hardware path.

A good sanity check saves hours: it turns vague "the accelerator is broken" symptoms into a short list of concrete places to inspect and fix.


The Numbers That Matter

When everything is working, the jump in performance validates all the headaches.

Metric Throughput
Regular CPU A handful of frames per second
Modalix DevKit (NPU) ~160 frames per second
Latency per frame ~200 ms
Modalix DevKit (NPU) ~6.2 ms
26x
Jump in Throughput
That is a 26x jump in throughput.
160
FPS on NPU
~160 frames per second
6.2ms
Latency per Frame
~6.2 ms

Get Your Own SiMa.ai Modalix DevKit

Run this same pipeline on real edge NPU hardware. Available from Think Robotics.

Buy the SiMa.ai Modalix DevKit