HandBrake for TinyML - quantize and compress small neural networks (Keras, TFLite, ONNX, scikit-learn) for ESP32, STM32, nRF52, RP2040 and ATmega microcontrollers, then get a FITS / TIGHT / TOO BIG verdict with a proof report before you flash. 100% local CLI - no cloud, no telemetry.
2
stars
2
commits
Python
primary language
Aug 25, 2026
updated
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.
.cc/.h) for
LiteRT-M / CMSIS-NN.espdl via ESP-PPQ (optional extra)report.md + report.html after every conversion
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|float|inline | 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"}]}
On PyPI the package is
shrinkray-cli(the nameshrinkraywas 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 |
.tflite file is not supported — pass the original
.keras/.h5 (or use --method float to repackage as a C array).pip install shrinkray-cli[espdl]; without it the command
prints install instructions and exits 2 — everything else keeps working.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.
2 commits
Python
100.0%
HandBrake for TinyML - quantize and compress small neural networks (Keras, TFLite, ONNX, scikit-learn) for ESP32, STM32, nRF52, RP2040 and ATmega microcontrollers, then get a FITS / TIGHT / TOO BIG verdict with a proof report before you flash. 100% local CLI - no cloud, no telemetry.
2
stars
2
commits
Python
primary language
Aug 25, 2026
updated
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.
.cc/.h) for
LiteRT-M / CMSIS-NN.espdl via ESP-PPQ (optional extra)report.md + report.html after every conversion
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|float|inline | 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"}]}
On PyPI the package is
shrinkray-cli(the nameshrinkraywas 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 |
.tflite file is not supported — pass the original
.keras/.h5 (or use --method float to repackage as a C array).pip install shrinkray-cli[espdl]; without it the command
prints install instructions and exits 2 — everything else keeps working.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.
2 commits
Python
100.0%