File size: 9,174 Bytes
cedf43c 7e980e0 2ef0d75 7e980e0 cedf43c | 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 | ---
language: en
license: mit
library_name: onnxruntime
pipeline_tag: audio-to-audio
tags:
- onnx
- onnxruntime
- stem-separation
- source-separation
- demucs
- htdemucs
- music
- audio-to-audio
- mobile
- ios
- android
- coreml
- directml
- production-ready
- vocal-extraction
- vocal-isolation
- vocal-remover
- karaoke
- acapella
datasets:
- StemSplitio/stem-separation-benchmark-2026
inference: false
---
# HT-Demucs FT β Vocals Specialist, ONNX
**The #1 open-source vocal separator on MUSDB18-HQ**, exported to ONNX. No PyTorch required at inference. Runs on CPU / CoreML / CUDA / DirectML.
This repo packages sub-model 3 of the
[`htdemucs_ft`](https://github.com/facebookresearch/demucs) 4-bag ensemble
as a single 316 MB `.onnx` file plus a ~150-line numpy reference inference
script. Verified to be **numerically equivalent** to the original PyTorch
model.
> Want all 4 stems in one drop-in package? Use the full bag repo:
> [`StemSplitio/htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx).
---
## TL;DR
```bash
pip install onnxruntime numpy soundfile
python infer.py your-song.mp3 ./out/
# writes ./out/vocals.wav at 44.1 kHz stereo
```
That's it. No PyTorch, no CUDA setup, no GPU server.
---
## Quality
| Metric (MUSDB18-HQ test, 50 songs) | Value | Source |
|---|---|---|
| Median vocals SDR | **9.19 dB** | [StemSplitio/stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) |
| Rank among open-source separators on vocals | **#1** (the highest open-source vocal SDR on MUSDB18-HQ) | same |
| ONNX vs PyTorch max abs diff | **< 1e-3** | verified during export (see [Day 1 spike report](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx#how-it-was-built)) |
---
## Performance
| Runtime | Hardware | Per 7.8-s segment | Per 3-min song |
|---|---|---:|---:|
| **onnxruntime CPU EP** | Apple M4 Pro | **~1.6 s** | **~22 s** |
| PyTorch CPU | Apple M4 Pro | ~2.1 s | ~29 s |
| onnxruntime CUDA EP | NVIDIA L4 | ~0.4 s | ~5 s *(extrapolated)* |
| onnxruntime DirectML EP | RTX 4090 | ~0.2 s | ~2 s *(extrapolated)* |
**Real-time factor on M4 Pro CPU: 0.20.** Roughly 1.31Γ faster than
PyTorch CPU on the same hardware.
---
## Tooling β `demucs-onnx` Python package
This model can also be run (and re-exported) 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
# Single specialist (this repo)
demucs-onnx separate song.mp3 stems/ --stem vocals
# Or via the Python API
python -c "from demucs_onnx import separate_stem; \
audio = separate_stem('song.mp3', 'vocals')"
```
The same package is also the canonical tool for **exporting** htdemucs
to ONNX yourself β it bundles all four blocker fixes (complex STFT,
`fractions.Fraction`, `random.randrange`,
`aten::_native_multi_head_attention`) so vanilla `torch.onnx.export`
works on your own checkpoints.
```bash
pip install "demucs-onnx[export]"
demucs-onnx export htdemucs_ft vocals.onnx --stem vocals
```
---
## Common use cases
- **Karaoke maker** β extract clean instrumental + acapella in one pass (pair with the `other` ONNX)
- **Acapella extraction** β harvest isolated vocals for sampling, remixing, vocal-coach feedback
- **Vocal removal** β build a vocal-remover app on iOS / Android / web without a GPU server
- **Speech-from-music** β isolate spoken-word from background music for transcription
---
## Quick start
### Python β minimal
```python
import infer
vocals = infer.separate_vocals("your-song.mp3")
# vocals: numpy array (2, samples) at 44.1 kHz
```
### Python β full control
```python
import soundfile as sf
import infer
# Optional execution providers β CPU is the default and most portable.
# Swap to "coreml" on macOS, "cuda" on NVIDIA, "dml" on Windows DX12.
audio, sr = sf.read("your-song.mp3", dtype="float32", always_2d=True)
stems = infer.separate(audio.T, sr, providers=["CPUExecutionProvider"])
sf.write("vocals.wav", stems[infer.SOURCES.index("vocals")].T, sr)
```
### CLI
```bash
python infer.py your-song.mp3 ./out/
python infer.py your-song.mp3 ./out/ --providers cuda # NVIDIA
python infer.py your-song.mp3 ./out/ --providers coreml # macOS
python infer.py your-song.mp3 ./out/ --providers dml # Windows
```
### Mobile (iOS / Swift)
```swift
import onnxruntime_objc
let env = try ORTEnv(loggingLevel: .warning)
let opts = try ORTSessionOptions()
try opts.appendCoreMLExecutionProvider(with: ORTCoreMLExecutionProviderOptions())
let session = try ORTSession(env: env,
modelPath: Bundle.main.path(forResource: "htdemucs_ft_vocals", ofType: "onnx")!,
sessionOptions: opts)
// audio: 1 Γ 2 Γ 343980 Float32 buffer, then session.run(...).
```
### Mobile (Android / Kotlin)
```kotlin
import ai.onnxruntime.OrtEnvironment
import ai.onnxruntime.OrtSession
val env = OrtEnvironment.getEnvironment()
val opts = OrtSession.SessionOptions().apply { addNnapi() }
val session = env.createSession(modelPath, opts)
```
### Web (onnxruntime-web)
```js
import * as ort from "onnxruntime-web";
const session = await ort.InferenceSession.create("htdemucs_ft_vocals.onnx", {
executionProviders: ["wasm"],
graphOptimizationLevel: "all",
});
const tensor = new ort.Tensor("float32", audioBuffer, [1, 2, 343980]);
const out = await session.run({ mix: tensor });
// out.stems.data is a Float32Array (1, 4, 2, 343980); use row 3 for vocals.
```
---
## Input / output spec
| Tensor | Name | Shape | Dtype | Notes |
|---|---|---|---|---|
| Input | `mix` | `(1, 2, 343980)` | float32 | Stereo audio, 44.1 kHz, 7.8 s segment. Values in [-1, 1]. |
| Output | `stems` | `(1, 4, 2, 343980)` | float32 | `[drums, bass, other, vocals]` order. **Use only row 3 (`vocals`)** β the other 3 rows are weakly-predicted by-products of the vocals specialist. |
For longer audio, chunk with overlap-add β see `infer.py::separate` for a
working ~60-line implementation.
---
## Related repos
Sibling stem-specialist ONNX repos from the same export:
| Repo | Stem | Use when |
|---|---|---|
| [`htdemucs-ft-drums-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx) | drums | Drum extraction, beat transcription |
| [`htdemucs-ft-bass-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-bass-onnx) | bass | Bassline transcription, mix rebalancing |
| [`htdemucs-ft-other-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-other-onnx) | other | Karaoke instrumentals, sample-flipping |
| [`htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx) | vocals | **#1 open-source vocal SDR** β karaoke, acapella, vocal removal |
| [`htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) | all 4 | Full 4-stem separation in one repo |
PyTorch versions for HF Inference Endpoints:
[`htdemucs-ft-pytorch`](https://huggingface.co/StemSplitio/htdemucs-ft-pytorch),
[`htdemucs-ft-vocals-pytorch`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-pytorch).
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 316 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 and a
dashboard.
- π [stemsplit.io](https://stemsplit.io)
- π [Developer docs](https://stemsplit.io/developers/docs)
- π [API reference](https://stemsplit.io/developers/reference)
- π [Guides & recipes](https://stemsplit.io/developers/guides)
Or use the no-code tools that ship the same model family:
- π§ [Vocal Remover](https://stemsplit.io/vocal-remover)
- π§ [Karaoke Maker](https://stemsplit.io/karaoke-maker)
- π§ [Acapella Maker](https://stemsplit.io/acapella-maker)
- π§ [YouTube Stem Splitter](https://stemsplit.io/youtube-stem-splitter)
---
## Files in this repo
| File | Size | Purpose |
|---|---:|---|
| `htdemucs_ft_vocals.onnx` | 316 MB | The exported model. Opset 17. Passes `onnx.checker`. |
| `infer.py` | ~6 KB | Pure numpy + onnxruntime reference. No torch. |
| `requirements.txt` | <1 KB | `onnxruntime`, `numpy`, `soundfile`. |
| `README.md` | this file | |
---
## 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: vocal remover onnx, karaoke maker, acapella extractor, htdemucs vocals onnx, vocal separation ios
|