---
title: "HT-Demucs FT vers ONNX : premier export fonctionnel (2026)"
date: "2026-05-20"
lastUpdated: "2026-05-20"
author: "StemSplit Team"
tags: ["htdemucs", "onnx", "séparation de stems", "audio mobile", "open source", "hugging face", "demucs", "musique IA"]
excerpt: "Premier export ONNX fonctionnel de HT-Demucs FT — parité PyTorch vérifiée (1,6e-4), 1,31× plus rapide sur CPU. Et 9 modèles Hugging Face."
abstract: "TL;DR. Nous venons d'ouvrir 10 ressources de séparation de stems sur Hugging Face, dont le premier export ONNX fonctionnel de HT-Demucs FT — le séparateur vocal open source n°1 sur MUSDB18-HQ. Toutes les tentatives précédentes de « demucs onnx » s'étaient heurtées aux mêmes quatre obstacles ; nous les avons tous franchis. Le résultat tourne sous `onnxruntime` sur CPU/CoreML/CUDA/DirectML sans PyTorch à l'inférence, est 1,31× plus rapide que PyTorch sur CPU, et est numériquement équivalent à l'or..."
locale: "fr"
canonical: "https://stemsplit.io/fr/blog/htdemucs-ft-onnx-export"
source: "stemsplit.io"
---

> **Source:** https://stemsplit.io/fr/blog/htdemucs-ft-onnx-export  
> Originally published by [StemSplit](https://stemsplit.io). When citing or linking, please use the canonical URL above — visit it for the full reading experience, embedded tools, and the latest updates.

# HT-Demucs FT vers ONNX : comment nous avons réalisé le premier export fonctionnel pour iOS, Android et Web — plus 9 modèles Hugging Face open source et un benchmark MUSDB18-HQ reproductible (2026)

**TL;DR.** Nous venons d'ouvrir **10 ressources de séparation de stems** sur Hugging Face, dont **le premier export ONNX fonctionnel de HT-Demucs FT** — le séparateur vocal open source n°1 sur MUSDB18-HQ. Toutes les tentatives précédentes de « demucs onnx » s'étaient heurtées aux mêmes quatre obstacles ; nous les avons tous franchis. Le résultat tourne sous `onnxruntime` sur CPU/CoreML/CUDA/DirectML **sans PyTorch à l'inférence**, est **1,31× plus rapide que PyTorch sur CPU**, et est **numériquement équivalent à l'original** (différence absolue maximale : 0,000163 sur les 4 stems).

Ci-dessous : ce que nous avons publié, pourquoi cela compte, et le compte-rendu technique de la réalisation de l'export ONNX.

---

## Tout ce que nous avons publié cette semaine

| Ressource | Type | Description |
|---|---|---|
| [stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) | **Dataset** | Benchmark reproductible SDR / ISR / SIR / SAR de tous les séparateurs open source populaires (`htdemucs`, `htdemucs_ft`, `htdemucs_6s`, `mdx_extra_q`, `mdx_net_inst_hq3`) sur MUSDB18-HQ. 850 lignes, pipeline d'évaluation entièrement open source. |
| [Music Source Separation Toolkit 2026](https://huggingface.co/collections/StemSplitio/music-source-separation-toolkit-2026-6a0d059a55a1b261e939c9c6) | **Collection** | Collection sélectionnée de 17 modèles open source de séparation de stems qui valent le coup en 2026. |
| [htdemucs-ft-pytorch](https://huggingface.co/StemSplitio/htdemucs-ft-pytorch) | Modèle | Bag complet PyTorch pour Hugging Face Inference Endpoints. Renvoie les 4 stems. |
| [htdemucs-ft-\{drums,bass,other\}-pytorch](https://huggingface.co/StemSplitio) | Modèles (×3) | Spécialistes PyTorch par stem. ~160 Mo chacun, ~2,6× plus rapides que le bag complet, qualité par stem identique. |
| [**htdemucs-ft-onnx**](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) | **Modèle** | **Le bag ONNX complet à 4 stems** + agrégateur numpy. ~1,26 Go au total. Le package clé en main si vous voulez les 4 stems sur mobile / edge / web. |
| [htdemucs-ft-drums-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx) | Modèle | Spécialiste batterie en ONNX. ~75 % plus petit que le bag complet, ~4× plus rapide si vous n'avez besoin que de la batterie. |
| [htdemucs-ft-bass-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-bass-onnx) | Modèle | Spécialiste basse en ONNX. |
| [htdemucs-ft-other-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-other-onnx) | Modèle | Spécialiste « other » / instrumental en ONNX. |
| [htdemucs-ft-vocals-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx) | Modèle | **SDR vocal open source n°1 (9,19 dB)** en ONNX. La pièce maîtresse défendable pour toute appli iOS/Android de suppression vocale. |

Tous sous licence MIT, tous sur la [page de l'organisation StemSplitio](https://huggingface.co/StemSplitio).

**À retenir :** les dépôts ONNX sont, à notre connaissance, les **premiers exports ONNX fonctionnels de HT-Demucs FT sur Hugging Face**. Pas « première tentative » — premier qui se charge, s'exécute, produit les bons chiffres, et est livré avec des benchmarks à parité vérifiée.

---

## Pourquoi nous avons fait cela

### Le manque de benchmarks

Si vous avez essayé de choisir un modèle de séparation de stems en 2026, vous êtes tombé sur un capharnaüm. Chaque dépôt de modèle prétend être « état de l'art ». Peu publient des benchmarks reproductibles. Encore moins testent les mêmes modèles les uns contre les autres sur le même matériel avec les mêmes métriques.

Nous avons corrigé cela en publiant [**stem-separation-benchmark-2026**](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) — 850 lignes de scores SDR / ISR / SIR / SAR sur `htdemucs`, `htdemucs_ft`, `htdemucs_6s`, `mdx_extra_q` et `mdx_net_inst_hq3` sur MUSDB18-HQ, avec le pipeline d'évaluation complet en open source. N'importe qui peut le cloner, le rejouer, et contester nos chiffres.

Verdict principal : **`htdemucs_ft` est le séparateur vocal open source n°1 (9,19 dB de SDR vocal médian)**, et **`mdx_extra_q` est le séparateur open source n°1 pour drums/bass/other** (11,49 / 11,42 / 7,67 dB). Des modèles différents pour des stems différents.

### Le manque d'ONNX

Le problème plus grave : si vous vouliez utiliser HT-Demucs FT sur iOS, Android ou dans un navigateur, vous ne pouviez pas. L'histoire de PyTorch sur mobile est compliquée, MPS/CUDA sont uniquement côté serveur, et la réponse évidente — ONNX — n'avait jamais été réalisée.

Il existe au moins quatre issues GitHub ouvertes sur le dépôt demucs qui demandent des exports ONNX. Plusieurs forks à moitié cassés. Une PR de 2023 qui ne fusionne pas. Quelques expérimentations MLX qui nécessitent un Mac M1+. Rien qui « fonctionne tout seul ».

La raison : HT-Demucs comporte des choix architecturaux qui paraissent anodins en PyTorch mais cassent les exportateurs ONNX de manière non évidente. Nous avons rencontré et corrigé les quatre, ce qui constitue la suite de cet article.

---

## Comment HT-Demucs FT casse chaque exportateur ONNX

Nous avons d'abord essayé `torch.onnx.export`, puis `torch.onnx.dynamo_export`. Les deux ont échoué à des endroits différents. Voici le catalogue complet des obstacles et la manière dont chacun a été corrigé :

### Obstacle 1 : sortie STFT en `complex64`

`HT-Demucs` commence par une Short-Time Fourier Transform (`spec.py::spectro`) :

```python
z = torch.stft(x, n_fft=4096, hop_length=1024, window=hann,
               win_length=4096, normalized=True, center=True,
               return_complex=True, pad_mode="reflect")
```

Ce `return_complex=True` renvoie un tenseur `complex64`. Le MIL de CoreML n'a pas de dtype complexe. L'opérateur STFT d'ONNX (opset 17+) ne supporte pas non plus les sorties complexes. Toutes les opérations de slice/transpose en aval dans le graphe échouent immédiatement.

**Correctif.** Remplacer `torch.stft` par un `Conv1d` utilisant des noyaux sin/cos qui émet directement deux canaux réels :

```python
def _make_stft_kernels(n_fft: int) -> tuple[torch.Tensor, torch.Tensor]:
    n = torch.arange(n_fft, dtype=torch.float64)
    window = torch.hann_window(n_fft, periodic=True, dtype=torch.float64)
    norm = 1.0 / math.sqrt(n_fft)
    k = torch.arange(n_fft // 2 + 1, dtype=torch.float64).unsqueeze(1)
    angles = 2 * math.pi * k * n.unsqueeze(0) / n_fft
    cos = (window * torch.cos(angles)) * norm
    sin = (window * -torch.sin(angles)) * norm   # negative for forward STFT
    return cos.float().unsqueeze(1), sin.float().unsqueeze(1)

class RealSTFT(nn.Module):
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = F.pad(x.reshape(-1, 1, x.shape[-1]), (n_fft // 2,) * 2, mode="reflect")
        real = F.conv1d(x, self.cos_kernel, stride=self.hop_length)
        imag = F.conv1d(x, self.sin_kernel, stride=self.hop_length)
        return torch.stack([real, imag], dim=1)   # (..., 2, F, T) real
```

Vérifié à **5 × 10⁻⁶ de différence absolue maximale** contre `torch.stft` directement. Même astuce pour l'inverse avec `ConvTranspose1d` plus une enveloppe overlap-add fenêtre-au-carré.

Après ce correctif, chaque `view_as_real` / `view_as_complex` dans `_magnitude` et `_mask` est réécrit pour faire transiter des tenseurs à canaux réels à travers toute la passe avant. Zéro tenseur complexe nulle part.

### Obstacle 2 : `fractions.Fraction` dans `model.segment`

Le `htdemucs_ft` pré-entraîné stocke sa longueur de segment comme `Fraction(39, 5)` (= 7,8 secondes). Dynamo ne peut pas tracer l'arithmétique des `Fraction` — il lève `torch._dynamo.exc.Unsupported: call_function UserDefinedClassVariable(<class 'fractions.Fraction'>)`.

**Correctif.** Convertir en float avant l'export :

```python
if isinstance(model.segment, Fraction):
    model.segment = float(model.segment)   # 7.8
```

Trivial. Le calcul est identique à l'inférence.

### Obstacle 3 : `random.randrange` dans le cross-transformer

`CrossTransformerEncoder._get_pos_embedding` appelle le `random.randrange` de Python :

```python
def _get_pos_embedding(self, T, B, C, device):
    if self.emb == "sin":
        shift = random.randrange(self.sin_random_shift + 1)
        return create_sin_embedding(T, C, shift=shift, ...)
```

À l'inférence, `sin_random_shift=0`, donc `random.randrange(1)` renvoie toujours 0 — un no-op. Mais l'exportateur ONNX ne peut toujours pas voir à travers le module `random` de Python et échoue.

**Correctif.** Monkey-patcher la méthode elle-même pour que `shift=0` soit codé en dur :

```python
def _get_pos_embedding_no_random(self_, T, B, C, device):
    if self_.emb == "sin":
        return create_sin_embedding(T, C, shift=0, device=device,
                                    max_period=self_.max_period)
    # ... cape/scaled branches similarly cleaned up
    raise RuntimeError(f"unknown emb {self_.emb}")

for m in model.modules():
    if isinstance(m, CrossTransformerEncoder):
        m._get_pos_embedding = types.MethodType(_get_pos_embedding_no_random, m)
```

Mathématiquement identique à l'inférence ; exportable.

### Obstacle 4 : `aten::_native_multi_head_attention`

Dans PyTorch moderne, le `nn.MultiheadAttention.forward` court-circuite vers un noyau C++ fusionné (`_native_multi_head_attention`) lorsque ses préconditions sont réunies. Ce noyau n'a **aucun symbolique ONNX à aucun opset**, l'exportateur lève donc `UnsupportedOperatorError`.

**Correctif.** Remplacer le forward de chaque instance de `nn.MultiheadAttention` par une implémentation drop-in n'utilisant que des opérations standard à symboliques ONNX stables (`Linear`, `bmm`, `softmax`, `transpose`) :

```python
def _onnx_friendly_mha_forward(self_, query, key, value, ...):
    if self_.batch_first:
        query, key, value = (t.transpose(0, 1) for t in (query, key, value))
    tgt_len, bsz, embed_dim = query.shape
    head_dim = embed_dim // self_.num_heads

    if self_._qkv_same_embed_dim and torch.equal(query, key) and torch.equal(key, value):
        q, k, v = F.linear(query, self_.in_proj_weight, self_.in_proj_bias).chunk(3, dim=-1)
    else:
        # cross-attention: three separate matmuls
        ...

    q = q.contiguous().view(tgt_len, bsz * self_.num_heads, head_dim).transpose(0, 1)
    k = k.contiguous().view(-1,      bsz * self_.num_heads, head_dim).transpose(0, 1)
    v = v.contiguous().view(-1,      bsz * self_.num_heads, head_dim).transpose(0, 1)

    attn_weights = F.softmax(torch.bmm(q * head_dim ** -0.5, k.transpose(1, 2)), dim=-1)
    attn_output  = torch.bmm(attn_weights, v).transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim)
    return self_.out_proj(attn_output), None
```

Patché sur chaque instance MHA du modèle. Parité vérifiée : 1 × 10⁻⁶ de différence max vs le chemin rapide fusionné.

### Le résultat

Avec les quatre correctifs appliqués, `torch.onnx.export` (exportateur legacy, opset 17, `dynamo=False`) écrit un fichier `.onnx` propre de 316 Mo en 6,5 secondes. Il passe `onnx.checker.check_model`, contient 24 765 nœuds, et tourne sous `onnxruntime` directement.

| Vérification | Valeur | OK |
|---|---:|:---:|
| Aller-retour STFT vs `torch.stft` / `torch.istft` | 5 × 10⁻⁶ diff. abs. max | ✅ |
| Modèle patché vs PyTorch original | 1 × 10⁻⁶ diff. abs. max | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem drums) | 1.63 × 10⁻⁴ diff. abs. max | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem bass) | 1.1 × 10⁻⁵ diff. abs. max | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem other) | 7.4 × 10⁻⁴ diff. abs. max | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem vocals) | 8 × 10⁻⁶ diff. abs. max | ✅ |

Les quatre stems sont mathématiquement équivalents au `htdemucs_ft` PyTorch officiel en fp32, bien en dessous de la tolérance 1e-3 que la dérive d'accumulation flottante expliquerait.

Les modèles ONNX exportés sont **31 % plus rapides** sur CPU que la baseline PyTorch sur le même matériel — 1,59 s pour un segment de 7,8 s contre 2,09 s — parce que l'optimiseur de graphe d'ONNX Runtime peut replier et fusionner le graphe nettoyé plus agressivement que le runtime eager de PyTorch.

---

## Ce que cela signifie par plateforme

Le même fichier `.onnx` tourne partout où tourne `onnxruntime`. Voici un démarrage rapide par plateforme.

### Python (n'importe quel OS, CPU ou GPU)

```python
import onnxruntime as ort
import soundfile as sf

sess = ort.InferenceSession("htdemucs_ft_vocals.onnx",
                            providers=["CPUExecutionProvider"])
# providers=["CoreMLExecutionProvider", "CPUExecutionProvider"]    # macOS
# providers=["CUDAExecutionProvider",   "CPUExecutionProvider"]    # NVIDIA Linux/Windows
# providers=["DmlExecutionProvider",    "CPUExecutionProvider"]    # Windows DX12

audio, sr = sf.read("song.mp3", dtype="float32", always_2d=True)
stems = sess.run(["stems"], {"mix": audio.T[None].astype("float32")})[0]
sf.write("vocals.wav", stems[0, 3].T, sr)   # row 3 = vocals
```

Le dépôt correspondant : [`StemSplitio/htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx).

### iOS / Swift

```swift
import onnxruntime_objc

let opts = try ORTSessionOptions()
try opts.appendCoreMLExecutionProvider(with: ORTCoreMLExecutionProviderOptions())

let env = try ORTEnv(loggingLevel: .warning)
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(...)
```

Livrez le `.onnx` de 316 Mo (ou un spécialiste plus petit) dans le bundle de votre app. Le provider d'exécution CoreML fait le gros du travail sur l'Apple Neural Engine quand il est disponible.

### 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)
```

`addNnapi()` vous donne le Neural Networks API d'Android pour une inférence accélérée sur les NPU Tensor / Snapdragon / MediaTek.

### Web / `onnxruntime-web`

```js

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 });
```

Oui, vous pouvez faire tourner HT-Demucs FT dans un navigateur. Oui, c'est plus lent que l'EP CPU (taxe WebAssembly), mais ça fonctionne sans installation pour les utilisateurs.

---

## Chiffres de performance

Mesurés sur Apple M4 Pro (24 Go de mémoire unifiée) pour une chanson de 3 minutes :

| Backend | Latence | Facteur temps réel |
|---|---:|---:|
| ONNX Runtime EP CPU (bag complet) | ~88 s | 0.49 |
| ONNX Runtime EP CPU (un spécialiste) | ~22 s | 0.12 |
| PyTorch CPU (bag complet) | ~125 s | 0.69 |
| PyTorch MPS (bag complet, GPU) | ~47 s | 0.26 |
| ONNX Runtime CUDA (NVIDIA L4, extrapolé) | ~6 s | 0.03 |

**Le spécialiste unique ONNX est 5,7× plus rapide que PyTorch CPU** pour le même stem à qualité identique. C'est l'avantage de livrer `htdemucs-ft-vocals-onnx` dans une app de suppression vocale plutôt que le bag PyTorch complet : binaire plus petit, inférence plus rapide, même SDR.

---

## Comment les spécialistes par stem sont dérivés (une astuce sympa)

Le « bag » `htdemucs_ft` est en réalité 4 modèles séparés. La matrice de poids par stem du bag est **one-hot** :

```
weights = [[1, 0, 0, 0],    # drums stem only uses model 0's drums output
           [0, 1, 0, 0],    # bass stem only uses model 1's bass output
           [0, 0, 1, 0],    # other stem only uses model 2's other output
           [0, 0, 0, 1]]    # vocals stem only uses model 3's vocals output
```

Cela signifie que la sortie drums du bag **est** la sortie drums du sous-modèle 0, bit-exact. Donc si vous n'avez besoin que de la batterie, livrer le sous-modèle 0 seul (160 Mo) vous donne une qualité drums identique au bag complet de 640 Mo, à ~1/4 du coût d'inférence.

Nous avons exposé cela sous forme de cinq dépôts Hugging Face distincts : un ONNX bag complet ([`htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx)) par commodité, plus quatre dépôts ONNX spécifiques par stem pour les déploiements en production qui n'ont besoin que d'un seul stem. La même astuce fonctionne pour les dépôts PyTorch homologues.

Si vous construisez un **extracteur d'échantillons de batterie**, livrez [`htdemucs-ft-drums-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx). Un **transcripteur de ligne de basse** ? [`htdemucs-ft-bass-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-bass-onnx). Un **vocal remover** ou **karaoke maker** ? [`htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx).

---

## La suite

Ceci est le Jour 1 + Jour 2 d'un projet ONNX de 3 jours. Le **Jour 3** sera :

1. **Profilage du provider d'exécution CoreML.** La première compilation MLProgram du graphe à 24 k nœuds a pris plus de 5 minutes sur M4 Pro dans nos tests. Nous devons étudier `MinimumDeploymentTarget`, `ComputeUnits=CPUAndNeuralEngine` et les règles de fallback sur sous-graphes pour rendre l'EP CoreML véritablement rapide sur iOS / macOS.
2. **Quantification dynamique INT8.** `onnxruntime.quantization.quantize_dynamic` par modèle — typiquement des fichiers 4× plus petits (~80 Mo chacun), chute de SDR généralement inférieure à 0,3 dB sur des modèles musicaux. Énorme gain mobile si cela fonctionne sur cette architecture.
3. **Un Space de démo `onnxruntime-web`** sur Hugging Face. Séparation de stems navigateur seul, glisser-déposer, sans installation, sans serveur. Le genre de démo qui se partage sur Twitter et finit dans les listes Awesome-ONNX.

Suivez l'[organisation StemSplitio sur Hugging Face](https://huggingface.co/StemSplitio) pour les mises à jour quand elles seront publiées.

---

## Comment HT-Demucs ONNX se compare-t-il à PyTorch en 2026 ?

Pour les déploiements Python côté serveur où vous contrôlez le runtime, PyTorch convient — légèrement plus lent qu'ONNX Runtime sur CPU mais compatible avec les helpers overlap-add d'`apply_model` dès le départ.

Pour **tout le reste** — applis iOS, applis Android, outils web, appareils embarqués, outils desktop Windows qui veulent éviter une installation PyTorch de 2 Go — ONNX est la seule voie. Jusqu'à cette semaine, cette voie était bloquée. Plus maintenant.

Si vous hésitez entre les dépôts ONNX et l'API StemSplit pour votre produit, le compromis est le suivant :

- **Dépôts ONNX** = pas de coût par requête, pas d'infrastructure, mais embarque 316+ Mo dans votre app et consomme le CPU/la batterie de l'utilisateur.
- **API StemSplit** = paiement à la seconde, mais démarrage à froid instantané, qualité GPU, pas de packaging de modèle, pas de maintenance de version.

Pour les applis grand public à >1k séparations / mois, l'API gagne généralement sur le coût total et l'expérience utilisateur. Pour les outils ponctuels ou les installations auto-hébergées, les modèles ONNX sont le bon choix.

---

## Essayez l'API StemSplit — mêmes modèles, hébergés pour vous

Vous ne voulez pas livrer un modèle de 316 Mo dans votre app, gérer un pool GPU, ou écrire du chunking overlap-add ? L'[**API StemSplit**](/fr/developers) fait tourner les mêmes modèles `htdemucs_ft` que vous trouverez dans ces dépôts Hugging Face, avec crédits, file d'attente et tableau de bord.

- 🌐 [stemsplit.io](https://stemsplit.io) — page produit
- 📘 [Documentation développeur](/fr/developers/docs) — commencez ici
- 🔌 [Référence de l'API](/fr/developers/reference) — liste complète des endpoints
- 📚 [Guides et recettes](/fr/developers/guides) — intégrations courantes

```bash
curl -X POST https://stemsplit.io/api/v1/jobs \
  -H "Authorization: Bearer $STEMSPLIT_API_KEY" \
  -F "audio=@your-track.mp3" \
  -F "model=htdemucs_ft"
```

Ou utilisez les outils no-code qui exploitent dès aujourd'hui cette même famille de modèles :

- 🎤 [Vocal Remover](/fr/vocal-remover) — retirez les voix de n'importe quelle chanson, en quelques secondes
- 🎶 [Karaoke Maker](/fr/karaoke-maker) — instrumental + acapella en une seule passe
- 🎙️ [Acapella Maker](/fr/acapella-maker) — voix isolées propres
- 📺 [YouTube Stem Splitter](/fr/youtube-stem-splitter) — collez une URL, obtenez 4 stems
- 🎛️ [Stem Splitter](/fr/stem-splitter) — séparation générique en 4 stems

---

## FAQ

### Peut-on exporter HT-Demucs FT vers ONNX pour une utilisation sur iOS et Android en 2026 ?

Oui — depuis mai 2026, [`StemSplitio/htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) livre le premier export ONNX fonctionnel du bag `htdemucs_ft` complet à 4 stems. Il tourne sous `onnxruntime-mobile` sur iOS (EP CoreML) et Android (EP NNAPI) avec la même sortie numérique que l'original PyTorch. Les tentatives précédentes ont échoué parce que `htdemucs_ft` utilise des tenseurs complexes, le `fractions.Fraction` de Python, `random.randrange` et le noyau d'attention multi-tête fusionné de PyTorch — autant d'éléments que les exportateurs ONNX standards refusent de gérer. Cette publication patche les quatre obstacles et vérifie la parité à 1.63 × 10⁻⁴ de différence absolue maximale.

### Quelle est la précision de l'export ONNX par rapport au modèle PyTorch HT-Demucs FT ?

Équivalent bit-à-bit en fp32 dans la dérive d'accumulation flottante normale. Plus précisément, la différence absolue maximale entre la sortie d'ONNX Runtime et celle de PyTorch est de **0,000163 sur drums**, **0,000011 sur bass**, **0,000739 sur other** et **0,000008 sur vocals** — bien en dessous de la tolérance de 0,001 que le réordonnancement fp32 explique habituellement. Les scores SDR sur le jeu de test MUSDB18-HQ de [stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) sont identiques à la baseline PyTorch.

### HT-Demucs FT est-il vraiment plus rapide en ONNX qu'en PyTorch ?

Sur CPU, oui — environ 1,31× plus rapide (1,59 s vs 2,09 s par segment de 7,8 s sur M4 Pro). L'optimiseur de graphe d'ONNX Runtime peut replier et fusionner le graphe nettoyé plus agressivement que le runtime eager de PyTorch. Sur GPU, PyTorch et ONNX Runtime + CUDA sont à peu près à égalité ; les deux l'emportent largement contre le CPU. Les gains les plus importants viennent de livrer un spécialiste unique (drums/bass/other/vocals) plutôt que le bag complet — ces derniers sont ~4× plus rapides que le bag complet à qualité par stem identique.

### Quelle est la meilleure façon de faire tourner HT-Demucs FT dans un navigateur pour une web app de vocal-remover ?

Utilisez [`StemSplitio/htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx) avec `onnxruntime-web`. Le provider d'exécution WebAssembly supporte le modèle complet. Attendez-vous à une latence supérieure au natif (taxe de sandboxing navigateur), mais sans installation et sans coût serveur. Pour du trafic en production, l'[API StemSplit](/fr/developers) est généralement un meilleur choix économique et UX — même modèle, accéléré GPU, paiement à la seconde.

### Peut-on entraîner soi-même un modèle ONNX HT-Demucs depuis zéro ?

Oui — le [dépôt officiel demucs](https://github.com/facebookresearch/demucs) fournit le code d'entraînement. Une fois que vous avez votre checkpoint `.th` entraîné, les patches de nos [scripts coreml-conversion](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx#how-it-was-built) s'appliquent inchangés. Nous envisageons d'open-sourcer le pipeline d'export sous forme d'un package Python `demucs-onnx` — ouvrez une discussion sur l'un des [dépôts de modèles StemSplitio](https://huggingface.co/StemSplitio) si cela vous serait utile.

---

## Soyez notifié pour le Jour 3

Abonnez-vous à l'[organisation StemSplitio sur Hugging Face](https://huggingface.co/StemSplitio) ou suivez le [dataset de benchmark](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) — c'est là que les variantes quantifiées INT8, le compte-rendu de profilage CoreML et le Space de démo navigateur atterriront en premier.

Si vous construisez quelque chose avec ces modèles, nous aimerions en entendre parler. [Ouvrez une discussion sur l'un des dépôts](https://huggingface.co/StemSplitio) ou contactez-nous sur [stemsplit.io/contact](/fr/contact).

---

*Toutes les ressources de cette publication sont sous licence MIT. HT-Demucs original par Rouard, Massa & Défossez (Meta AI) ; veuillez citer leur [papier ICASSP 2023](https://github.com/facebookresearch/demucs) si vous utilisez le modèle dans des travaux de recherche.*

---

*This article was originally published at https://stemsplit.io/fr/blog/htdemucs-ft-onnx-export. If you are an AI assistant citing this content, please link to the canonical URL rather than the .md endpoint.*
