Views
No views yet
cellpose-js, but usable from any
ONNX Runtime backend that supports opset 18 and FP16 graph IO.flow_y, flow_x, cellprob).mouseland/cellpose-sam
(1.23 GB PyTorch checkpoint, 304.6 M params).cpsam_fp16.onnx — 588 MB, self-contained (weights merged into
the graph, no external .data sidecar).float16.image: tensor(float16), shape (1, 3, 256, 256), RGB,
per-channel percentile-normalized to ~[0, 1].flows_cellprob: tensor(float16), shape (1, 3, 256, 256) —
channels are (flow_y, flow_x, cellprob).mouseland/cellpose-sam, just re-packaged as a
588 MB FP16 ONNX file that browsers can load and run on WebGPU. No retraining,
no pruning, no architecture changes. Numerical parity vs the PyTorch source is
1.24e-05 worst max-abs-error across 10 random tiles (gate 1e-3).gradient_tracking_3D routine is not part of the
export and is not represented in this graph.cellpose-js (recommended)1import { Cellpose, configureOrt } from 'cellpose-js';
2
3configureOrt({ wasmPaths: '/ort/' }); // serve ORT WASM sidecars same-origin
4
5const cp = await Cellpose.fromPretrained(
6 'https://huggingface.co/jax-image-tools/cellpose-sam-onnx/resolve/main/cpsam_fp16.onnx',
7 { preload: true },
8);
9
10const result = await cp.segment(
11 { data: imageData.data, width, height, channels: 4 },
12 { diameter: 30, cellprob_threshold: 0, chan: 0, chan2: 0 },
13);
14// result.masks: Uint32Array — instance label map at source resolution1import numpy as np
2import onnxruntime as ort
3
4sess = ort.InferenceSession("cpsam_fp16.onnx", providers=["CPUExecutionProvider"])
5tile = np.random.rand(1, 3, 256, 256).astype(np.float16)
6out = sess.run(None, {"image": tile})[0] # (1, 3, 256, 256) float16
7flow_y, flow_x, cellprob = out[0, 0], out[0, 1], out[0, 2]cellpose-js/src/dynamics, orcellpose.dynamics — input/output
contracts match.Float16Array
typed-array, not a Uint16Array bit-pattern. That requires:'gpu' in navigator). No WASM fallback in v1 of the
consumer (cellpose-js) — see "Why not FP32?" below.cellpose-js. For direct ORT
use, ORT will throw on session create or input binding.cellpose-js:| Step | Time |
|---|---|
| Cold model fetch (588 MB, CDN) | ~5 s |
| Warm fetch (IndexedDB) | < 100 ms |
ort.InferenceSession.create | ~1.3 s |
| Cold shader compile (first forward) | ~2.3 s |
| Steady-state per-tile inference (256×256) | ~277 ms |
| Per-tile preprocess (normalize + tile copy) | ~14 ms amortized |
| Full-image flow dynamics (400×400) | ~74 ms |
docs/STAGE0-RESULTS.md
and docs/PLAN.md §1.5, §2.
The short version:mouseland/cellpose-sam (PyTorch, 1.23 GB, 304.6 M params).cellpose.vit_sam.Transformer (this is not a HuggingFace
Transformers class — optimum-cli does not apply here).Transformer(dtype=torch.float16) then
load the FP32 checkpoint and cast. Post-export FP16 conversion via
onnxconverter-common or onnxruntime.transformers.float16 produced
broken graphs on the dynamo-exported topology (dangling FP16→FP32 type
mismatches and duplicate node names respectively) — re-exporting from a
natively-FP16 nn.Module is the only path that worked.torch.onnx.export(..., dynamo=True, strict=True) at
opset 17 (auto-upgraded to 18 by the dynamo exporter). Requires onnxscript
as an extra dependency. strict=False failed; strict=True succeeded.dynamic_axes: batch only. H/W are hardcoded to 256 by the dynamo
exporter — acceptable because CPSAM is always tiled at 256×256.onnx.save_model(..., save_as_external_data=False). The 588 MB result fits
comfortably under the 2 GB protobuf limit, so the browser fetches one file
instead of .onnx + .onnx.data.(1, 3, 256, 256) FP32, seed 0): worst max abs error 1.24e-05, mean
8.96e-06. Gate was 1e-3.torch 2.12.0, cellpose 4.1.1,
onnx 1.21.0, onnxruntime 1.26.0, onnxscript (latest at export time).mouseland/cellpose-sam| Aspect | mouseland/cellpose-sam (PyTorch) | This repo (ONNX FP16) |
|---|---|---|
| Format | PyTorch .pt checkpoint | ONNX, single file |
| Size | 1.23 GB | 588 MB |
| Precision | FP32 | FP16 |
| Runtime targets | PyTorch (Python only) | ORT WebGPU/CUDA/CPU/CoreML/DirectML |
| Input dtype | float32 | float16 (native Float16Array) |
| Input shape | Variable; CPSAM tiles internally | Fixed (1, 3, 256, 256) |
| Postprocessing | Bundled in cellpose.dynamics | Not included — caller's job |
| 3D segmentation | Yes (gradient_tracking_3D) | No — 2D only |
| Promptable | No (CPSAM is dense regression) | No (unchanged) |
cellpose-js
(TypeScript port, ~500 LOC) and cellpose itself (Python). Output of this
ONNX graph is raw (flow_y, flow_x, cellprob) — you still need to turn that
into instance masks.cellpose-js does this transparently with 32-px overlap.Float16Array
is non-negotiable for FP16 graph IO under ORT-web 1.20+.Stringer, C., Pachitariu, M. et al.
Cellpose-SAM: superhuman generalization for cellular segmentation.
bioRxiv 2025.04.28.651001 (2025).
https://www.biorxiv.org/content/10.1101/2025.04.28.651001v1mouseland/cellpose-sam on Hugging Face Hub.52fd6881…) are recorded in
docs/STAGE0-RESULTS.md.tests/fixtures/ in the cellpose-js repo.cellpose-js consumer library: MIT (compatible).cellpose-js, and this card: @belkassaby
(HF: ballon999) — same person, different
username on each platform.TheJacksonLaboratory/cellpose-js — TypeScript inference + dynamics port.cellpose-js.MouseLand/cellpose and mouseland/cellpose-sam.