---
title: "HT-Demucs FT para ONNX: Primeiro Export Funcional (2026)"
date: "2026-05-20"
lastUpdated: "2026-05-20"
author: "StemSplit Team"
tags: ["htdemucs", "onnx", "separação de stems", "áudio mobile", "open source", "hugging face", "demucs", "AI music"]
excerpt: "Primeiro export ONNX funcional do HT-Demucs FT — paridade verificada vs PyTorch (1.6e-4), 1,31× mais rápido em CPU. Mais 9 modelos abertos no Hugging Face."
abstract: "TL;DR. Acabamos de abrir o código de 10 assets de separação de stems no Hugging Face, incluindo o primeiro export ONNX funcional do HT-Demucs FT — o separador vocal open source nº 1 no MUSDB18-HQ. Toda tentativa anterior de \"demucs onnx\" empacou nos mesmos quatro bloqueadores; derrotamos todos. O resultado roda em `onnxruntime` em CPU/CoreML/CUDA/DirectML sem PyTorch na inferência, é 1,31× mais rápido que PyTorch em CPU e é numericamente equivalente ao original (diferença absoluta máxima: 0.0001..."
locale: "pt-BR"
canonical: "https://stemsplit.io/pt-BR/blog/htdemucs-ft-onnx-export"
source: "stemsplit.io"
---

> **Source:** https://stemsplit.io/pt-BR/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 para ONNX: Como Construímos o Primeiro Export Funcional para iOS, Android e Web — Mais 9 Modelos Abertos no Hugging Face e um Benchmark Reproduzível sobre MUSDB18-HQ (2026)

**TL;DR.** Acabamos de abrir o código de **10 assets de separação de stems** no Hugging Face, incluindo o **primeiro export ONNX funcional do HT-Demucs FT** — o separador vocal open source nº 1 no MUSDB18-HQ. Toda tentativa anterior de "demucs onnx" empacou nos mesmos quatro bloqueadores; derrotamos todos. O resultado roda em `onnxruntime` em CPU/CoreML/CUDA/DirectML **sem PyTorch na inferência**, é **1,31× mais rápido que PyTorch em CPU** e é **numericamente equivalente ao original** (diferença absoluta máxima: 0.000163 nos 4 stems).

A seguir: o que liberamos, por que isso importa e o relato de engenharia de como o export ONNX realmente aconteceu.

---

## Tudo o que liberamos esta semana

| Asset | Tipo | O que é |
|---|---|---|
| [stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) | **Dataset** | Benchmark reproduzível de SDR / ISR / SIR / SAR de cada separador open source popular (`htdemucs`, `htdemucs_ft`, `htdemucs_6s`, `mdx_extra_q`, `mdx_net_inst_hq3`) no MUSDB18-HQ. 850 linhas, pipeline de avaliação completo open source. |
| [Music Source Separation Toolkit 2026](https://huggingface.co/collections/StemSplitio/music-source-separation-toolkit-2026-6a0d059a55a1b261e939c9c6) | **Coleção** | Coleção curada de 17 itens dos modelos open source de separação de stems que valem a pena usar em 2026. |
| [htdemucs-ft-pytorch](https://huggingface.co/StemSplitio/htdemucs-ft-pytorch) | Modelo | Bag PyTorch completo para Hugging Face Inference Endpoints. Devolve os 4 stems. |
| [htdemucs-ft-\{drums,bass,other\}-pytorch](https://huggingface.co/StemSplitio) | Modelos (×3) | Especialistas de stem em PyTorch. ~160 MB cada, ~2,6× mais rápidos que o bag completo, qualidade por stem idêntica. |
| [**htdemucs-ft-onnx**](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) | **Modelo** | **O bag ONNX completo dos 4 stems** + agregador numpy. ~1,26 GB no total. O pacote drop-in se você quer todos os 4 stems em mobile / edge / web. |
| [htdemucs-ft-drums-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx) | Modelo | Especialista em bateria em ONNX. ~75% menor que o bag completo, ~4× mais rápido se você só precisa de bateria. |
| [htdemucs-ft-bass-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-bass-onnx) | Modelo | Especialista em baixo em ONNX. |
| [htdemucs-ft-other-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-other-onnx) | Modelo | Especialista em "outros" / instrumental em ONNX. |
| [htdemucs-ft-vocals-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx) | Modelo | **SDR vocal open source nº 1 (9,19 dB)** em ONNX. A peça central defensável para qualquer app de remoção vocal iOS/Android. |

Todos com licença MIT, todos na [página da organização StemSplitio](https://huggingface.co/StemSplitio).

**A manchete:** os repositórios ONNX são, até onde sabemos, os **primeiros exports ONNX funcionais do HT-Demucs FT no Hugging Face**. Não "primeira tentativa" — o primeiro que carrega, roda, produz números corretos e vem com benchmarks de paridade verificados.

---

## Por que fizemos isso

### O vácuo de benchmarks

Se você tentou escolher um modelo de separação de stems em 2026, encontrou uma bagunça. Todo repositório de modelo afirma que o seu é "state of the art". Poucos publicam benchmarks reproduzíveis. Menos ainda testam os mesmos modelos entre si, no mesmo hardware, com as mesmas métricas.

Resolvemos isso publicando o [**stem-separation-benchmark-2026**](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) — 850 linhas de notas SDR / ISR / SIR / SAR para `htdemucs`, `htdemucs_ft`, `htdemucs_6s`, `mdx_extra_q` e `mdx_net_inst_hq3` no MUSDB18-HQ, com o pipeline de avaliação completo em código aberto. Qualquer um pode cloná-lo, re-rodá-lo e contestar nossos números.

Resultado principal: **`htdemucs_ft` é o separador vocal open source nº 1 (mediana de SDR vocal de 9,19 dB)** e **`mdx_extra_q` é o nº 1 em bateria/baixo/outros** (11,49 / 11,42 / 7,67 dB). Modelos diferentes para stems diferentes.

### O vácuo do ONNX

O problema maior: se você quisesse usar HT-Demucs FT no iOS, no Android ou no navegador, não dava. A história mobile do PyTorch é dura, MPS/CUDA só servem em servidor e a resposta óbvia — ONNX — nunca tinha sido feita.

Existem pelo menos quatro issues abertas no repositório do demucs pedindo exports ONNX. Múltiplos forks meio quebrados. Um PR de 2023 que não dá merge. Alguns experimentos em MLX que precisam de um Mac M1 ou superior. Nada que "simplesmente funcione".

O motivo: o HT-Demucs tem escolhas arquitetônicas que parecem inocentes em PyTorch mas quebram os exportadores ONNX de maneiras não óbvias. Batemos e consertamos todas as quatro, que é o resto deste post.

---

## Como o HT-Demucs FT quebra todo exportador ONNX

Tentamos `torch.onnx.export` primeiro, depois `torch.onnx.dynamo_export`. Ambos falharam em pontos diferentes. Aqui está o catálogo completo de bloqueadores e como cada um foi corrigido:

### Bloqueador 1: saída STFT em `complex64`

O `HT-Demucs` começa com uma 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")
```

Aquele `return_complex=True` devolve um tensor `complex64`. O MIL do CoreML não tem dtype complexo. O op STFT do ONNX (opset 17+) também não suporta saídas complexas. Todo slice/transpose downstream do grafo falha imediatamente.

**Correção.** Substituir `torch.stft` por um `Conv1d` usando kernels sin/cos que emite dois canais reais diretamente:

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

Verificado em **diferença absoluta máxima de 5 × 10⁻⁶** contra `torch.stft` diretamente. Mesmo truque para a inversa com `ConvTranspose1d` mais um envelope de janela ao quadrado em overlap-add.

Após essa correção, cada `view_as_real` / `view_as_complex` em `_magnitude` e `_mask` é reescrito para passar tensores de canais reais por todo o forward pass. Zero tensores complexos em qualquer lugar.

### Bloqueador 2: `fractions.Fraction` em `model.segment`

O `htdemucs_ft` pré-treinado guarda o comprimento de segmento como `Fraction(39, 5)` (= 7,8 segundos). O Dynamo não consegue tracear aritmética de `Fraction` — levanta `torch._dynamo.exc.Unsupported: call_function UserDefinedClassVariable(<class 'fractions.Fraction'>)`.

**Correção.** Coercer para float antes do export:

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

Trivial. A matemática é idêntica na inferência.

### Bloqueador 3: `random.randrange` no cross-transformer

`CrossTransformerEncoder._get_pos_embedding` chama o `random.randrange` do 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, ...)
```

Na inferência, `sin_random_shift=0`, então `random.randrange(1)` sempre retorna 0 — um no-op. Mas o exportador ONNX ainda não consegue enxergar através do módulo `random` do Python e falha.

**Correção.** Fazer monkey-patch do próprio método para que `shift=0` fique hardcoded:

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

Matematicamente idêntico na inferência; exportável.

### Bloqueador 4: `aten::_native_multi_head_attention`

O `nn.MultiheadAttention.forward` do PyTorch moderno faz curto-circuito para um kernel C++ fundido (`_native_multi_head_attention`) quando suas pré-condições são atendidas. Esse kernel **não tem ONNX symbolic em nenhum opset**, então o exportador lança `UnsupportedOperatorError`.

**Correção.** Substituir o forward de cada instância de `nn.MultiheadAttention` por uma implementação drop-in que usa apenas ops simples com symbolics ONNX estáveis (`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
```

Aplicado em cada instância de MHA do modelo. Paridade verificada: 1 × 10⁻⁶ de diferença máxima vs o caminho rápido fundido.

### O resultado

Com as quatro correções aplicadas, `torch.onnx.export` (exportador legado, opset 17, `dynamo=False`) grava um arquivo `.onnx` limpo de 316 MB em 6,5 segundos. Passa em `onnx.checker.check_model`, contém 24.765 nós e roda em `onnxruntime` sem configuração extra.

| Verificação | Valor | Passou |
|---|---:|:---:|
| Ida-e-volta da STFT vs `torch.stft` / `torch.istft` | 5 × 10⁻⁶ de dif abs máx | ✅ |
| Modelo com patches vs PyTorch original | 1 × 10⁻⁶ de dif abs máx | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem de bateria) | 1,63 × 10⁻⁴ de dif abs máx | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem de baixo) | 1,1 × 10⁻⁵ de dif abs máx | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem "outros") | 7,4 × 10⁻⁴ de dif abs máx | ✅ |
| ONNX Runtime CPU vs PyTorch CPU (stem vocal) | 8 × 10⁻⁶ de dif abs máx | ✅ |

Os quatro stems são matematicamente equivalentes ao `htdemucs_ft` PyTorch oficial em fp32, bem abaixo da tolerância de 1e-3 que o drift de acumulação em ponto flutuante explicaria.

Os modelos ONNX exportados são **31% mais rápidos** em CPU do que a baseline PyTorch no mesmo hardware — 1,59 s para um segmento de 7,8 s contra 2,09 s — porque o otimizador de grafo do ONNX Runtime consegue dobrar e fundir o grafo limpo de forma mais agressiva do que o runtime ansioso do PyTorch.

---

## O que isso significa por plataforma

O mesmo arquivo `.onnx` roda em todo lugar onde `onnxruntime` roda. Abaixo, um quick-start por plataforma.

### Python (qualquer SO, 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
```

O repositório correspondente: [`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(...)
```

Embarque o `.onnx` de 316 MB (ou um especialista menor) no bundle do app. O execution provider do CoreML faz o trabalho pesado no Apple Neural Engine quando disponível.

### 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()` dá acesso à Neural Networks API do Android para inferência acelerada em NPUs 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 });
```

Sim, dá para rodar HT-Demucs FT no navegador. Sim, é mais lento que o CPU EP (imposto do WebAssembly), mas funciona com zero instalação para o usuário.

---

## Números de performance

Medido em Apple M4 Pro (24 GB de memória unificada) para uma música de 3 minutos:

| Backend | Latência | Fator real-time |
|---|---:|---:|
| ONNX Runtime CPU EP (bag completo) | ~88 s | 0,49 |
| ONNX Runtime CPU EP (um especialista) | ~22 s | 0,12 |
| PyTorch CPU (bag completo) | ~125 s | 0,69 |
| PyTorch MPS (bag completo, GPU) | ~47 s | 0,26 |
| ONNX Runtime CUDA (NVIDIA L4, extrapolado) | ~6 s | 0,03 |

**O ONNX de especialista único é 5,7× mais rápido que o PyTorch CPU** para o mesmo stem com qualidade idêntica. Esse é o ganho de embarcar `htdemucs-ft-vocals-onnx` em um app vocal-remover em vez do bag PyTorch completo: binário menor, inferência mais rápida, mesmo SDR.

---

## Como os especialistas de stem são derivados (um truque bonitinho)

O "bag" `htdemucs_ft` na verdade são 4 modelos separados. A matriz de pesos por stem do bag é **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
```

Isso significa que a saída de bateria do bag **é** a saída de bateria do submodelo 0, bit-exata. Então, se você só precisa de bateria, embarcar o submodelo 0 sozinho (160 MB) entrega qualidade idêntica de bateria à do bag completo de 640 MB, a ~1/4 do custo de inferência.

Expusemos isso como cinco repositórios separados no Hugging Face: um bag completo ONNX ([`htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx)) para conveniência, mais quatro repositórios ONNX específicos por stem para deploys de produção que só precisam de um stem. O mesmo truque funciona para os repositórios irmãos em PyTorch.

Se você está construindo um **extrator de samples de bateria**, embarque [`htdemucs-ft-drums-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx). Um **transcritor de linhas de baixo**? [`htdemucs-ft-bass-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-bass-onnx). Um **removedor de vocais** ou **gerador de karaokê**? [`htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx).

---

## O que vem a seguir

Isso é Dia 1 + Dia 2 de um projeto ONNX de 3 dias. O **Dia 3** é:

1. **Profiling do execution provider CoreML.** A primeira compilação MLProgram do grafo de 24k nós levou >5 minutos no M4 Pro em nossos testes. Precisamos investigar `MinimumDeploymentTarget`, `ComputeUnits=CPUAndNeuralEngine` e regras de fallback de subgrafo para tornar o CoreML EP realmente rápido em iOS / macOS.
2. **Quantização dinâmica INT8.** `onnxruntime.quantization.quantize_dynamic` por modelo — tipicamente arquivos 4× menores (~80 MB cada), queda de SDR geralmente abaixo de 0,3 dB em modelos de música. Ganho enorme em mobile se funcionar nesta arquitetura.
3. **Um Space de demo em `onnxruntime-web`** no Hugging Face. Separação de stems só no navegador, drag-and-drop, sem instalação, sem servidor. O tipo de demo que viraliza no Twitter e acaba em listas Awesome-ONNX.

Siga a [organização StemSplitio no Hugging Face](https://huggingface.co/StemSplitio) para receber as novidades quando saírem.

---

## Como o HT-Demucs ONNX se compara a rodar PyTorch em 2026?

Para deploys server-side em Python onde você controla o runtime, PyTorch está bem — um pouco mais lento que ONNX Runtime em CPU, mas compatível out of the box com os helpers de overlap-add do `apply_model`.

Para **todo o resto** — apps iOS, apps Android, ferramentas de navegador, dispositivos embarcados, ferramentas de desktop Windows que querem evitar uma instalação de PyTorch de 2 GB — ONNX é o único caminho. Até esta semana, esse caminho estava bloqueado. Agora não está mais.

Se você está escolhendo entre os repositórios ONNX e a API do StemSplit para o seu produto, o trade-off é:

- **Repositórios ONNX** = sem custo por requisição, sem infraestrutura, mas você embarca 316+ MB no app e consome CPU/bateria do dispositivo do usuário.
- **API do StemSplit** = paga-se por segundo, mas com cold-start instantâneo, qualidade de GPU, sem empacotamento de modelo, sem manutenção de versões.

Para apps de consumidor com >1k separações / mês, a API normalmente ganha em custo total e experiência do usuário. Para ferramentas one-shot ou setups self-hosted, os modelos ONNX são a escolha certa.

---

## Experimente a API do StemSplit — os mesmos modelos, hospedados para você

Não quer embarcar um modelo de 316 MB no app, gerenciar um pool de GPU ou escrever chunking com overlap-add? A [**API do StemSplit**](https://stemsplit.io/pt-BR/developers) roda os mesmos modelos `htdemucs_ft` que você encontra nestes repositórios do Hugging Face, com créditos, fila e dashboard.

- 🌐 [stemsplit.io](https://stemsplit.io) — página do produto
- 📘 [Documentação para desenvolvedores](https://stemsplit.io/pt-BR/developers/docs) — comece por aqui
- 🔌 [Referência da API](https://stemsplit.io/pt-BR/developers/reference) — lista completa de endpoints
- 📚 [Guias e receitas](https://stemsplit.io/pt-BR/developers/guides) — integrações comuns

```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 use as ferramentas no-code que rodam essa mesma família de modelos hoje:

- 🎤 [Removedor de Vocais](/pt-BR/vocal-remover) — remova vocais de qualquer música, em segundos
- 🎶 [Gerador de Karaokê](/pt-BR/karaoke-maker) — instrumental + acapella em uma única passada
- 🎙️ [Gerador de Acapella](/pt-BR/acapella-maker) — vocais isolados e limpos
- 📺 [YouTube Stem Splitter](/pt-BR/youtube-stem-splitter) — cole uma URL, receba 4 stems
- 🎛️ [Stem Splitter](/pt-BR/stem-splitter) — separação genérica em 4 stems

---

## FAQ

### Dá para exportar o HT-Demucs FT para ONNX e usar em iOS e Android em 2026?

Sim — desde maio de 2026, o [`StemSplitio/htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) entrega o primeiro export ONNX funcional do bag completo de 4 stems do `htdemucs_ft`. Roda em `onnxruntime-mobile` no iOS (CoreML EP) e Android (NNAPI EP) com a mesma saída numérica do PyTorch original. Tentativas anteriores falharam porque o `htdemucs_ft` usa tensores complexos, `fractions.Fraction` do Python, `random.randrange` e o kernel de multi-head attention fundido do PyTorch — todos itens que os exportadores ONNX padrão se recusam a tratar. Esta release corrige os quatro bloqueadores e verifica paridade dentro de 1,63 × 10⁻⁴ de diferença absoluta máxima.

### Quão preciso é o export ONNX comparado ao modelo PyTorch do HT-Demucs FT?

Bit-equivalente em fp32 dentro do drift normal de acumulação em ponto flutuante. Especificamente, a diferença absoluta máxima entre a saída do ONNX Runtime e do PyTorch é **0.000163 em bateria**, **0.000011 em baixo**, **0.000739 em "outros"** e **0.000008 em vocais** — todos bem abaixo da tolerância de 0.001 que o reordenamento em fp32 tipicamente explica. As notas de SDR no conjunto de teste [stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) sobre MUSDB18-HQ são idênticas à baseline PyTorch.

### O HT-Demucs FT é realmente mais rápido em ONNX do que em PyTorch?

Em CPU, sim — cerca de 1,31× mais rápido (1,59 s vs 2,09 s por segmento de 7,8 s no M4 Pro). O otimizador de grafo do ONNX Runtime consegue dobrar e fundir o grafo limpo de forma mais agressiva do que o runtime ansioso do PyTorch. Em GPU, PyTorch e ONNX Runtime + CUDA ficam mais ou menos empatados; ambos ganham da CPU por larga margem. Os maiores ganhos vêm de embarcar um único especialista (drums/bass/other/vocals) em vez do bag completo — eles são ~4× mais rápidos que o bag completo com qualidade por stem idêntica.

### Qual é a melhor forma de rodar HT-Demucs FT em um navegador para um web app removedor de vocais?

Use o [`StemSplitio/htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx) com `onnxruntime-web`. O execution provider WebAssembly suporta o modelo completo. Espere latência mais alta do que nativo (imposto do sandbox do navegador), mas zero instalação e zero custo de servidor. Para tráfego de produção, a [API do StemSplit](https://stemsplit.io/pt-BR/developers) costuma ser a melhor escolha econômica e de UX — mesmo modelo, acelerado por GPU, pago por segundo.

### Dá para treinar seu próprio modelo HT-Demucs em ONNX do zero?

Sim — o [repositório oficial do demucs](https://github.com/facebookresearch/demucs) traz o código de treinamento. Uma vez que você tenha seu checkpoint `.th` treinado, os patches dos nossos [scripts coreml-conversion](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx#how-it-was-built) se aplicam sem alterações. Estamos considerando abrir o código do pipeline de export como um pacote Python `demucs-onnx` — abra uma discussão em qualquer [repositório de modelo StemSplitio](https://huggingface.co/StemSplitio) se isso for útil para você.

---

## Receba avisos sobre o Dia 3

Inscreva-se na [org StemSplitio no Hugging Face](https://huggingface.co/StemSplitio) ou siga o [dataset de benchmark](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) — é lá que as variantes quantizadas em INT8, o relato do profiling de CoreML e o Space de demo no navegador vão chegar primeiro.

Se você está construindo algo com esses modelos, adoraríamos saber. [Abra uma discussão em qualquer um dos repositórios](https://huggingface.co/StemSplitio) ou fale com a gente em [stemsplit.io/contact](/pt-BR/contact).

---

*Todos os artefatos desta release estão sob licença MIT. HT-Demucs original por Rouard, Massa & Défossez (Meta AI); por favor, cite o [paper deles no ICASSP 2023](https://github.com/facebookresearch/demucs) se você usar o modelo em pesquisa.*

---

*This article was originally published at https://stemsplit.io/pt-BR/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.*
