HandBrake for TinyML — one tool that takes any small model and produces a chip-ready artifact, with a report proving it fits.
📖 New here? Read the full user guide — installation, every command, and troubleshooting.
ShrinkRay compresses/quantizes small neural networks for microcontrollers and tells you — before you touch a firmware build — whether the result fits your target chip's flash and RAM.
- ✅
FITS/⚠️ TIGHT/ ❌** TOO BIG**verdict per chip - Keras/TFLite → int8/int16/float TFLite + C byte array (
.cc
/.h
) for LiteRT-M / CMSIS-NN - scikit-learn → single portable
C99 header(via emlearn; works even on ATmega328P) - ONNX →
.espdl
via ESP-PPQ (optional extra) - Self-contained
report.md
+report.html
after every conversion - 100% local: no network calls, no telemetry, no account
pip install shrinkray-cli
shrinkray chips # the 12-chip database
shrinkray inspect model.keras # params, size, ops, FLOPs
shrinkray convert model.keras --target esp32s3 --method int8 --data cal.npy
Output:
wrote outputs/model_int8.tflite (2.7 KiB)
wrote outputs/model_int8.cc
wrote outputs/model_int8.h
accuracy max-abs-error 0.002717, top-1 agreement 100.0%
esp32s3: ✅ FITS — flash 2.7 KiB / 8192.0 KiB (0.0%), est. RAM 0.1 KiB / 512.0 KiB (0.0%)
wrote outputs/report.md
wrote outputs/report.html
--data cal.npy
is a small float32 array of representative samples
(numpy.save("cal.npy", x[:100].astype("float32"))
). With it you get full-integer quantization and an accuracy-delta check; without it, int8 falls back to dynamic-range quantization.
| Command | What it does |
|---|---|
shrinkray inspect <model> |
|
Format, parameter count, file size, operator histogram, FLOP estimate for .keras / .h5 / .tflite / .onnx / .pkl |
|
shrinkray chips [--chips extra.json] |
|
| Print the chip database; merge your own chips from JSON | |
shrinkray convert <model> --target <chip> |
|
| Convert + fit verdict + reports |
Useful convert
flags:
| Flag | Meaning |
|---|---|
| `--method int8 | int16 |
int16 needs --data ; inline is for scikit-learn .pkl |
|
--data cal.npy |
|
| Calibration samples (full-integer quant + accuracy check) | |
--out DIR |
|
Output directory (default: outputs/ ) |
|
--all-chips |
|
| Fit-check against the whole database, ranked by headroom (always exits 0) | |
--chips mychips.json |
|
| Merge custom chip definitions |
Exit codes: 0
ok · 1
model error · 2
missing optional dependency ·
3
converted but doesn't fit the target.
Drop a shrinkray.toml
in your project directory to stop repeating flags (CLI flags always win over the file):
[defaults]
target = "esp32s3"
data = "cal.npy"
out = "build"
Ships with 12 chips: esp32, esp32s3, esp32p4, stm32f407, stm32h743, stm32u575, nrf52840, nrf5340, rp2040, rp2350, nano33ble, atmega328p. Each entry: flash KiB, SRAM KiB, clock MHz, feature flags (dsp / simd / ai-instructions), preferred runtime (litert-m / cmsis-nn / esp-dl / emlearn).
Extend it with your own JSON (--chips mychips.json
; your entries override built-ins on name collision):
{"chips": [{"name": "myboard", "flash_kb": 512, "sram_kb": 128,
"clock_mhz": 100, "features": ["dsp"], "runtime": "cmsis-nn"}]}
Flash= actual artifact bytes measured on disk.** Peak RAM**= tensor-liveness analysis of the TFLite graph: the largest sum of concurrently live activation tensors × 1.2 safety factor.Verdicts: FITS = flash ≤ 90% and RAM ≤ 70%; TIGHT = flash ≤ 100% and RAM ≤ 90%; otherwise TOO BIG.
On PyPI the package is
(the nameshrinkray-cli
shrinkray
was already taken by an unrelated project). The command it installs is stillshrinkray
.
| Method | Command | Notes |
|---|---|---|
| pip (Win/Linux/macOS) | pip install shrinkray-cli |
|
| Python 3.10–3.12, CPU-only is fine | ||
| pip + ESP-DL pipeline | pip install shrinkray-cli[espdl] |
|
| adds ESP-PPQ (heavier deps) | ||
| pipx | pipx install shrinkray-cli |
|
| isolated CLI install | ||
| Standalone binary | GitHub Releases | experimental; bundles TF, so it's big — pip is recommended |
| winget / brew | planned | not published yet |
No GUI, no training— input is an already-trained model ≤ ~100 MB.- Pipeline A (Keras→TFLite) requires TensorFlow (CPU build is fine). Everything else — TFLite inspect, sklearn pipeline, chips, reports — works without it.
- RAM estimates are heuristics, not measurements: TFLite liveness ×1.2 for Pipeline A; not estimable for emlearn C code (reported as n/a).
- Quantizing an already-
.tflite
file is not supported — pass the original.keras
/.h5
(or use--method float
to repackage as a C array). - Pipeline C requires
pip install shrinkray-cli[espdl]
; without it the command prints install instructions and exits 2 — everything else keeps working. - No ONNX Runtime quantization, no RISC-V paths, no model zoo (v0.2+).
pip install -e ".[dev]"
pytest --cov=shrinkray.core --cov=shrinkray.pipelines # coverage gate: 80%
CI runs pytest on Windows / Ubuntu / macOS × Python 3.10 / 3.11 / 3.12
(.github/workflows/test.yml
); tag pushes build standalone binaries
(.github/workflows/release.yml
).
Test fixtures (tiny Keras net, sklearn forest, ONNX graph) are generated at runtime — no binary models in the repo.
GNU Affero General Public License v3.0 (AGPL-3.0-only) — see LICENSE.
Free for everyone to use, study, and modify — including commercial internal use. If you distribute ShrinkRay or a modified version, or offer it as a network service, you must share your source under the same license. Commercial closed-source licensing is available on request; contact the maintainer.