File size: 8,513 Bytes
fb179b8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | ---
language: en
license: mit
library_name: onnxruntime
pipeline_tag: audio-to-audio
tags:
- onnx
- onnxruntime
- stem-separation
- source-separation
- 6-stem
- guitar-extraction
- piano-extraction
- vocal-remover
- demucs
- htdemucs
- htdemucs_6s
- music
- audio-to-audio
- mobile
- ios
- android
- coreml
- directml
- production-ready
datasets:
- StemSplitio/stem-separation-benchmark-2026
inference: false
---
# HT-Demucs 6-stem β ONNX (with guitar + piano)
The **first ONNX export of the 6-stem `htdemucs_6s` variant** on the
Hugging Face Hub. Adds **guitar** and **piano** stems on top of the
standard 4 (drums / bass / other / vocals). Runs in `onnxruntime` on
CPU out of the box, and on CoreML / CUDA / DirectML with a one-line
provider change. **No PyTorch required at inference.**
If you need guitar or piano isolation, this is the only off-the-shelf
ONNX model on the Hub that gives you that.
---
## TL;DR
```bash
pip install onnxruntime numpy soundfile
# 258 MB fp32 model β all 6 stems:
python infer.py your-song.mp3 ./out/
# 136 MB fp16weights variant (same runtime cost):
python infer.py your-song.mp3 ./out/ --small
# Just the guitar stem:
python infer.py your-song.mp3 ./out/ --stems guitar
```
The repo contains:
- `htdemucs_6s.onnx` β 258 MB, opset 17, parity-verified vs PyTorch fp32.
- `htdemucs_6s_fp16weights.onnx` β 136 MB, fp16-stored weights, same runtime memory / latency.
- `infer.py` β pure-numpy reference inference (~200 lines, no torch).
- `requirements.txt` β three small packages, no PyTorch.
---
## What stems do I get?
```python
SOURCES = ("drums", "bass", "other", "vocals", "guitar", "piano")
```
Output tensor: `stems[1, 6, 2, 343980]` in that exact stem order. The
6-stem variant overlaps with the 4-stem on the first 4 stems but with
slightly different separation behavior β the extra guitar and piano
heads change what "other" learns to keep.
---
## Quality
Parity vs PyTorch fp32 (random input, 7.8 s segment):
- `htdemucs_6s.onnx` max abs diff: **2.42 Γ 10β»β΄**
- `htdemucs_6s_fp16weights.onnx` max abs diff (vs fp32 weights): **1.06 Γ 10β»β΄**
Both well within the 1e-3 publish threshold.
Stem-specific SDR (informal; the official paper covers in-depth eval):
| Stem | SDR (MUSDB18-HQ, approx.) |
|---|---:|
| drums | ~9.5 dB |
| bass | ~9.0 dB |
| other | ~5.5 dB (lower because the model now also predicts guitar + piano) |
| vocals | ~8.5 dB |
| guitar | extracted-track-quality (no public SDR baseline on MUSDB) |
| piano | extracted-track-quality (no public SDR baseline on MUSDB) |
If you care about absolute drums/vocals SDR, prefer
[`htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx).
If you specifically need guitar or piano isolation,
**this is the model**.
---
## Performance
Single 7.8 s segment, Apple M4 Pro CPU:
| Variant | RAM | Latency | RTF |
|---|---:|---:|---:|
| `htdemucs_6s.onnx` (fp32) | ~1.1 GB | ~1.6 s | 0.20 |
| `htdemucs_6s_fp16weights.onnx` | ~1.1 GB | ~1.6 s | 0.20 |
CUDA / DirectML / CoreML EPs are typically β₯ 5Γ faster on real GPUs.
---
## Quick start
### Python
```python
import soundfile as sf
import infer
audio, sr = sf.read("your-song.mp3", dtype="float32", always_2d=True)
stems = infer.separate(audio.T, sr,
model_path=infer.DEFAULT_MODEL,
providers=["CPUExecutionProvider"])
sf.write("guitar.wav", stems["guitar"].T, sr)
sf.write("piano.wav", stems["piano"].T, sr)
```
### CLI
```bash
python infer.py your-song.mp3 ./out/ # all 6 stems
python infer.py your-song.mp3 ./out/ --stems guitar piano # guitar + piano only
python infer.py your-song.mp3 ./out/ --providers coreml # macOS arm64
python infer.py your-song.mp3 ./out/ --providers cuda # Linux + NVIDIA
python infer.py your-song.mp3 ./out/ --small # 136 MB variant
```
### Mobile / Web
```swift
// iOS / Swift β 258 MB or 136 MB bundled
import onnxruntime_objc
let session = try ORTSession(env: env,
modelPath: Bundle.main.path(forResource: "htdemucs_6s_fp16weights",
ofType: "onnx")!,
sessionOptions: opts)
```
```js
// Browser
import * as ort from "onnxruntime-web";
const sess = await ort.InferenceSession.create(
"htdemucs_6s_fp16weights.onnx",
{ executionProviders: ["wasm"] },
);
const t = new ort.Tensor("float32", audioBuffer, [1, 2, 343980]);
const out = await sess.run({ mix: t }); // out.stems is (1, 6, 2, 343980)
```
For a turnkey browser demo with file-picker + chunked overlap-add, see
[`demucs-onnx browser-demo`](https://github.com/StemSplit/demucs-onnx#browser-demos).
---
## Input / output spec
| Tensor | Name | Shape | Dtype | Notes |
|---|---|---|---|---|
| Input | `mix` | `(1, 2, 343980)` | float32 | Stereo, 44.1 kHz, 7.8 s segment. Values in [-1, 1]. |
| Output | `stems` | `(1, 6, 2, 343980)` | float32 | Stems in order `[drums, bass, other, vocals, guitar, piano]`. |
For longer audio, chunk with overlap-add β see `infer.py::separate`.
---
## Tooling β `demucs-onnx` Python package
This model can be run via the open-source
[`demucs-onnx`](https://github.com/StemSplit/demucs-onnx) Python package
on PyPI. It auto-downloads from this repo on first use.
```bash
pip install demucs-onnx
# 6-stem mode β all 6 stems, single session:
demucs-onnx separate song.mp3 stems/ --model htdemucs_6s
# Just guitar + piano:
demucs-onnx separate song.mp3 stems/ --model htdemucs_6s --stems guitar piano
# Python API:
python -c "from demucs_onnx import separate_stem; \
guitar = separate_stem('song.mp3', 'guitar')"
```
To re-export your own fine-tune:
```bash
pip install 'demucs-onnx[export]'
demucs-onnx export htdemucs_6s out/htdemucs_6s.onnx
```
---
## How it was built
The export pipeline lives in the open-source
[`demucs-onnx`](https://github.com/StemSplit/demucs-onnx) package at
[`demucs_onnx/export/`](https://github.com/StemSplit/demucs-onnx/tree/main/src/demucs_onnx/export).
It applies the same four patches that make `htdemucs_ft` exportable:
1. Complex-typed `torch.stft` outputs β `Conv1d` with sin/cos kernels.
2. `model.segment` `fractions.Fraction` β plain `float`.
3. `random.randrange` in transformer pos-embedding β hardcoded `shift=0`.
4. `aten::_native_multi_head_attention` (no ONNX symbolic) β drop-in
`nn.MultiheadAttention.forward` built from `Linear`/`bmm`/`softmax`.
The 6-stem head is wider than the 4-stem one but the surgery is
identical β no new blockers. Parity at 2.42 Γ 10β»β΄ on first try.
---
## Related work
Sibling ONNX repos from the same export pipeline:
| Repo | Stems | Use when |
|---|---|---|
| [`htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) | 4 (bag) | Best SDR on the standard 4 stems. |
| [`htdemucs-onnx`](https://huggingface.co/StemSplitio/htdemucs-onnx) | 4 (single) | Fastest 4-stem startup. |
| `htdemucs-6s-onnx` *(this)* | **6** | You need **guitar** or **piano** as a stem. |
| [`htdemucs-ft-{drums,bass,other,vocals}-onnx`](https://huggingface.co/StemSplitio) | 1 | Fastest single-stem inference. |
Full benchmark across every popular open-source separator:
[StemSplitio/stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026).
---
## Skip the infrastructure β use the StemSplit API
Don't want to ship a 258 MB model in your app, manage a GPU pool, or
write overlap-add chunking? Use the **[StemSplit API](https://stemsplit.io/developers)**
instead β same model under the hood, hosted for you, with credits.
- π [stemsplit.io](https://stemsplit.io)
- π [Developer docs](https://stemsplit.io/developers/docs)
- π [API reference](https://stemsplit.io/developers/reference)
---
## License & attribution
This repo is **MIT-licensed**, matching the original HT-Demucs.
```bibtex
@inproceedings{rouard2023hybrid,
title = {Hybrid Transformers for Music Source Separation},
author = {Rouard, Simon and Massa, Francisco and D{\'e}fossez, Alexandre},
booktitle = {ICASSP},
year = {2023}
}
```
- Original PyTorch model: [`facebookresearch/demucs`](https://github.com/facebookresearch/demucs)
- ONNX export, parity verification, and packaging by [StemSplit](https://stemsplit.io)
- Search keywords: **htdemucs 6 stem onnx**, **htdemucs_6s onnx**, **guitar isolation onnx**,
**piano isolation onnx**, **demucs 6-stem mobile**, **stem separation guitar onnx**.
|