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
1pip install onnxruntime numpy soundfile
23# 258 MB fp32 model — all 6 stems:4python infer.py your-song.mp3 ./out/
56# 136 MB fp16weights variant (same runtime cost):7python infer.py your-song.mp3 ./out/ --small
89# Just the guitar stem:10python infer.py your-song.mp3 ./out/ --stems guitar
The repo contains:
htdemucs_6s.onnx — 258 MB, opset 17, parity-verified vs PyTorch fp32.
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.
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
1import soundfile as sf
2import infer
34audio, sr = sf.read("your-song.mp3", dtype="float32", always_2d=True)5stems = infer.separate(audio.T, sr,6 model_path=infer.DEFAULT_MODEL,7 providers=["CPUExecutionProvider"])8sf.write("guitar.wav", stems["guitar"].T, sr)9sf.write("piano.wav", stems["piano"].T, sr)
CLI
bash
1python infer.py your-song.mp3 ./out/ # all 6 stems2python infer.py your-song.mp3 ./out/ --stems guitar piano # guitar + piano only3python infer.py your-song.mp3 ./out/ --providers coreml # macOS arm644python infer.py your-song.mp3 ./out/ --providers cuda # Linux + NVIDIA5python infer.py your-song.mp3 ./out/ --small # 136 MB variant
Mobile / Web
swift
1// iOS / Swift — 258 MB or 136 MB bundled2import onnxruntime_objc
3let session =tryORTSession(env: env,4 modelPath:Bundle.main.path(forResource:"htdemucs_6s_fp16weights",5 ofType:"onnx")!,6 sessionOptions: opts)
js
1// Browser2import*as ortfrom"onnxruntime-web";3const sess =await ort.InferenceSession.create(4"htdemucs_6s_fp16weights.onnx",5{executionProviders:["wasm"]},6);7const t =newort.Tensor("float32", audioBuffer,[1,2,343980]);8const 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.
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 Python package
on PyPI. It auto-downloads from this repo on first use.
bash
1pip install demucs-onnx
23# 6-stem mode — all 6 stems, single session:4demucs-onnx separate song.mp3 stems/ --model htdemucs_6s
56# Just guitar + piano:7demucs-onnx separate song.mp3 stems/ --model htdemucs_6s --stems guitar piano
89# Python API:10python -c "from demucs_onnx import separate_stem; \
11 guitar = separate_stem('song.mp3', 'guitar')"
The export pipeline lives in the open-source
demucs-onnx package at
demucs_onnx/export/.
It applies the same four patches that make htdemucs_ft exportable:
Complex-typed torch.stft outputs → Conv1d with sin/cos kernels.
model.segmentfractions.Fraction → plain float.
random.randrange in transformer pos-embedding → hardcoded shift=0.
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.
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
instead — same model under the hood, hosted for you, with credits.
This repo is MIT-licensed, matching the original HT-Demucs.
bibtex
1@inproceedings{rouard2023hybrid,
2 title = {Hybrid Transformers for Music Source Separation},
3 author = {Rouard, Simon and Massa, Francisco and D{\'e}fossez, Alexandre},
4 booktitle = {ICASSP},
5 year = {2023}
6}