Metadata-Version: 2.5
Name: shrinkray-cli
Version: 0.1.0
Summary: Compress and quantize small neural networks for microcontrollers, and prove they fit.
Author: ShrinkRay contributors
License: AGPL-3.0-only
License-File: LICENSE
Keywords: embedded,microcontroller,quantization,tflite,tinyml
Requires-Python: <3.13,>=3.10
Requires-Dist: emlearn>=0.16
Requires-Dist: flatbuffers>=23.1
Requires-Dist: jinja2>=3.1
Requires-Dist: numpy>=1.24
Requires-Dist: rich>=13.0
Requires-Dist: tensorflow>=2.15
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: typer>=0.16
Provides-Extra: dev
Requires-Dist: onnx>=1.15; extra == 'dev'
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: scikit-learn>=1.3; extra == 'dev'
Provides-Extra: espdl
Requires-Dist: esp-ppq>=1.0; extra == 'espdl'
Description-Content-Type: text/markdown

# ShrinkRay

[![CI](https://github.com/TarulAhsan/shrinkray/actions/workflows/test.yml/badge.svg)](https://github.com/TarulAhsan/shrinkray/actions/workflows/test.yml)
[![License: AGPL v3](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](LICENSE)
[![Python 3.10–3.12](https://img.shields.io/badge/python-3.10%E2%80%933.12-blue.svg)](pyproject.toml)
[![Platforms](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)](#install-matrix)

**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](docs/index.html)** — 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**

## Demo

<!--
TODO(maintainer): record a 20–30s terminal GIF and save it as docs/demo.gif.
Suggested flow: shrinkray chips → shrinkray inspect model.keras →
shrinkray convert model.keras --target esp32s3 --method int8 --data cal.npy.
Recording tools: ScreenToGif (Windows), asciinema + svg-term, or Kap (macOS).
Keep it under ~2 MB so the README stays light.
-->
![demo](docs/demo.gif)

## 30-second quickstart

```bash
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:

```text
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.

## Commands

| 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.

## Config file

Drop a `shrinkray.toml` in your project directory to stop repeating flags
(CLI flags always win over the file):

```toml
[defaults]
target = "esp32s3"
data = "cal.npy"
out = "build"
```

## Chip database

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):

```json
{"chips": [{"name": "myboard", "flash_kb": 512, "sram_kb": 128,
            "clock_mhz": 100, "features": ["dsp"], "runtime": "cmsis-nn"}]}
```

## Fit model

- **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.

## Install matrix

> On PyPI the package is **`shrinkray-cli`** (the name `shrinkray` was already
> taken by an unrelated project). The command it installs is still `shrinkray`.

| 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 |

## Honest limitations (v0.1)

- **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+).

## Development

```bash
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.

## License

GNU Affero General Public License v3.0 (AGPL-3.0-only) — see [LICENSE](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.
