| --- |
| license: cc-by-nc-4.0 |
| base_model: MuScriptor/muscriptor-small |
| tags: |
| - music |
| - transcription |
| - audio-to-midi |
| - onnx |
| library_name: onnx |
| --- |
| |
| # MuScriptor small β ONNX conversion |
|
|
| An ONNX Runtime conversion of [`MuScriptor/muscriptor-small`](https://huggingface.co/MuScriptor/muscriptor-small), |
| the 103M-parameter multi-instrument music transcription model by **Kyutai Γ |
| Mirelo Γ IRCAM**. The weights are theirs and unmodified apart from the |
| conversion; all credit for the model belongs to them. |
|
|
| - Original model and paper: <https://github.com/muscriptor/muscriptor>, [arXiv:2607.08168](https://arxiv.org/abs/2607.08168) |
| - **Licence: CC BY-NC 4.0** β non-commercial use only, inherited from the |
| original weights. |
|
|
| It exists so that [Lepton Hum](https://midi.engineering/lepton-hum/), a |
| desktop practice tool for musicians, can run the model through ONNX Runtime |
| without shipping PyTorch. Anyone else running ONNX Runtime can use it the |
| same way, under the same non-commercial terms. |
|
|
| ## Files |
|
|
| | file | what it is | |
| |---|---| |
| | `muscriptor-small-cond.onnx` | conditioner: audio β prefix embeddings | |
| | `muscriptor-small-lm.onnx` | the decoder-only transformer, KV cache in and out | |
|
|
| ### `muscriptor-small-cond.onnx` |
|
|
| | | | |
| |---|---| |
| | `audio` | `f32 [1, 80000]` β one 5-second chunk at 16 kHz, zero-padded | |
| | `instrument` | `i64 [1, K]` β instrument class ids (group + 2; `1` = unconditional) | |
| | `dataset` | `i64 [1, 1]` β always `1`, the null class | |
| | β `prefix` | `f32 [1, 501 + 1 + K, 768]` | |
|
|
| The spectrogram is **inside this graph** on purpose. The checkpoint carries |
| its own STFT window and mel filterbank as buffers, and they are stored |
| quantized β about 2.4e-4 away from a freshly computed periodic Hann window |
| and htk filterbank. That rounding raises the window's sidelobe floor by |
| roughly 70 dB, and since the model reads log-magnitude features, bins that |
| the textbook formulas put at the `log(1e-6)` floor sit near β4 for this |
| model. Recomputing the front end therefore feeds it a spectrum it was not |
| trained on, so the conversion keeps the checkpoint's own. |
|
|
| ### `muscriptor-small-lm.onnx` |
|
|
| | | | |
| |---|---| |
| | `tokens` | `i64 [1, S]` | |
| | `prefix` | `f32 [1, P, 768]` β the conditioner's output; `P = 0` after the first step | |
| | `past_k`, `past_v` | `f32 [14, 1, T_past, 12, 64]` | |
| | β `logits` | `f32 [1, 1393]` β last position only | |
| | β `present_k`, `present_v` | the cache, grown by this step | |
|
|
| Positions are not an input: everything in the cache precedes the call, so |
| `T_past` is where the new tokens start. The graph is branch-free, so one |
| exported model serves both the prefill and single-token decoding. |
|
|
| Greedy decoding, MT3 token vocabulary (1393 tokens), 5-second chunks with a |
| tie prologue carrying notes across chunk boundaries β see the original |
| repository for the decoding rules. |
|
|
| ## Fidelity |
|
|
| Checked against the reference PyTorch implementation on the same 3.7-minute |
| mix, both given identical 16 kHz audio: **drums 1103 notes vs 1103 (exact), |
| bass 522 vs 514, guitar 1730 vs 1845**. Greedy decoding turns the ~1e-5 |
| logit differences between ONNX Runtime and PyTorch into an occasional |
| flipped argmax that then cascades, so agreement within a few percent per |
| instrument is what parity looks like here. |
|
|
| Layer-level checks from the conversion script: conditioner max|Ξ| 7.7e-3 |
| (the STFT's numerics), prefill logits 2.7e-5, three decode steps β€ 5.4e-5. |
|
|
| ## Reproducing |
|
|
| `scripts/export_muscriptor_onnx.py` in the Lepton Hum repository. It fetches |
| the original gated weights (accept the licence on the model page first), |
| exports both graphs, and asserts parity against the reference modules before |
| writing anything. |
|
|