---
title: "HT-Demucs FT в ONNX: первый рабочий экспорт (2026)"
date: "2026-05-20"
lastUpdated: "2026-05-20"
author: "StemSplit Team"
tags: ["htdemucs", "onnx", "разделение стемов", "мобильное аудио", "open source", "hugging face", "demucs", "ИИ-музыка"]
excerpt: "Первый рабочий ONNX-экспорт HT-Demucs FT — паритет с PyTorch (1,6e-4), на 31% быстрее на CPU. Плюс 9 открытых моделей на Hugging Face."
abstract: "TL;DR. Мы только что выложили в open source 10 ассетов для разделения стемов на Hugging Face, включая первый рабочий ONNX-экспорт HT-Demucs FT — открытого вокального сепаратора №1 на MUSDB18-HQ. Все предыдущие попытки «demucs onnx» спотыкались об одни и те же четыре блокера; мы победили их все. Результат работает в `onnxruntime` на CPU/CoreML/CUDA/DirectML без PyTorch на инференсе, на 1,31× быстрее, чем PyTorch на CPU, и численно эквивалентен оригиналу (максимальная абсолютная разница: 0,000163 ..."
locale: "ru"
canonical: "https://stemsplit.io/ru/blog/htdemucs-ft-onnx-export"
source: "stemsplit.io"
---

> **Source:** https://stemsplit.io/ru/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 в ONNX: как мы сделали первый рабочий экспорт для iOS, Android и веба — плюс 9 открытых моделей на Hugging Face и воспроизводимый бенчмарк MUSDB18-HQ (2026)

**TL;DR.** Мы только что выложили в open source **10 ассетов для разделения стемов** на Hugging Face, включая **первый рабочий ONNX-экспорт HT-Demucs FT** — открытого вокального сепаратора №1 на MUSDB18-HQ. Все предыдущие попытки «demucs onnx» спотыкались об одни и те же четыре блокера; мы победили их все. Результат работает в `onnxruntime` на CPU/CoreML/CUDA/DirectML **без PyTorch на инференсе**, **на 1,31× быстрее, чем PyTorch на CPU**, и **численно эквивалентен оригиналу** (максимальная абсолютная разница: 0,000163 по всем 4 стемам).

Ниже — что мы выпустили, почему это важно и инженерный разбор того, как именно был сделан ONNX-экспорт.

---

## Что мы выпустили на этой неделе

| Ассет | Тип | Что это |
|---|---|---|
| [stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) | **Датасет** | Воспроизводимый бенчмарк SDR / ISR / SIR / SAR всех популярных open-source сепараторов (`htdemucs`, `htdemucs_ft`, `htdemucs_6s`, `mdx_extra_q`, `mdx_net_inst_hq3`) на MUSDB18-HQ. 850 строк, полный пайплайн оценки в open source. |
| [Music Source Separation Toolkit 2026](https://huggingface.co/collections/StemSplitio/music-source-separation-toolkit-2026-6a0d059a55a1b261e939c9c6) | **Коллекция** | Кураторская подборка из 17 пунктов — open-source модели разделения стемов, которые имеет смысл использовать в 2026 году. |
| [htdemucs-ft-pytorch](https://huggingface.co/StemSplitio/htdemucs-ft-pytorch) | Модель | Полный PyTorch-bag для Hugging Face Inference Endpoints. Возвращает все 4 стема. |
| [htdemucs-ft-\{drums,bass,other\}-pytorch](https://huggingface.co/StemSplitio) | Модели (×3) | PyTorch-специалисты по стемам. ~160 MB каждая, ~2,6× быстрее полного bag, идентичное качество по своему стему. |
| [**htdemucs-ft-onnx**](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) | **Модель** | **Полный 4-стемный ONNX-bag** + numpy-агрегатор. ~1,26 GB в сумме. Готовый пакет, если нужны все 4 стема на mobile / edge / web. |
| [htdemucs-ft-drums-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx) | Модель | Специалист по барабанам в ONNX. ~75% меньше полного bag, ~4× быстрее, если нужны только барабаны. |
| [htdemucs-ft-bass-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-bass-onnx) | Модель | Специалист по басу в ONNX. |
| [htdemucs-ft-other-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-other-onnx) | Модель | Специалист по «other» / инструменталу в ONNX. |
| [htdemucs-ft-vocals-onnx](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx) | Модель | **Открытый вокальный SDR №1 (9,19 dB)** в ONNX. Защитимое ядро для любого iOS/Android приложения по удалению вокала. |

Всё под MIT-лицензией, всё на [странице организации StemSplitio](https://huggingface.co/StemSplitio).

**Главное:** ONNX-репозитории — это, насколько нам известно, **первые рабочие ONNX-экспорты HT-Demucs FT на Hugging Face**. Не «первая попытка» — первые, которые загружаются, запускаются, выдают корректные числа и идут с верифицированными бенчмарками паритета.

---

## Зачем мы это сделали

### Пробел в бенчмарках

Если вы пытались выбрать модель для разделения стемов в 2026 году, вы столкнулись с бардаком. Каждый репозиторий уверяет, что его модель — «state of the art». Мало кто публикует воспроизводимые бенчмарки. Ещё меньше тестируют те же модели друг против друга на том же железе с теми же метриками.

Мы исправили это, опубликовав [**stem-separation-benchmark-2026**](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) — 850 строк значений SDR / ISR / SIR / SAR по моделям `htdemucs`, `htdemucs_ft`, `htdemucs_6s`, `mdx_extra_q` и `mdx_net_inst_hq3` на MUSDB18-HQ, с полностью открытым пайплайном оценки. Любой может склонировать его, перезапустить и оспорить наши цифры.

Главный вывод: **`htdemucs_ft` — открытый вокальный сепаратор №1 (медианный SDR вокала 9,19 dB)**, а **`mdx_extra_q` — открытый сепаратор №1 для барабанов/баса/остального** (11,49 / 11,42 / 7,67 dB). Разные модели для разных стемов.

### Пробел в ONNX

Проблема серьёзнее: если вы хотели использовать HT-Demucs FT на iOS, Android или в браузере — вы не могли. Мобильная история PyTorch грустная, MPS/CUDA — только серверные, а очевидный ответ — ONNX — никто так и не сделал.

В репозитории demucs висит как минимум четыре открытых issue с просьбой об ONNX-экспорте. Несколько полусломанных форков. PR 2023 года, который не мёржится. Пара экспериментов на MLX, требующих Mac на M1+. Ничего, что просто «работает».

Причина: у HT-Demucs есть архитектурные решения, которые в PyTorch выглядят безобидно, но ломают ONNX-экспортеры неочевидными способами. Мы наткнулись на все четыре и починили — остальная часть поста об этом.

---

## Как HT-Demucs FT ломает любой ONNX-экспортер

Сначала мы попробовали `torch.onnx.export`, затем `torch.onnx.dynamo_export`. Оба упали в разных местах. Вот полный каталог блокеров и то, как каждый был починен:

### Блокер 1: вывод STFT в формате `complex64`

`HT-Demucs` начинается с кратковременного преобразования Фурье (`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")
```

Этот `return_complex=True` возвращает тензор `complex64`. У MIL CoreML нет комплексного dtype. У STFT-оператора ONNX (opset 17+) тоже нет поддержки комплексных выходов. Любая последующая операция slice/transpose в графе тут же падает.

**Решение.** Заменить `torch.stft` на `Conv1d` с sin/cos-ядрами, который сразу выдаёт два вещественных канала:

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

Верифицировано с **максимальной абсолютной разницей 5 × 10⁻⁶** против `torch.stft` напрямую. Тот же трюк для обратного преобразования с `ConvTranspose1d` и overlap-add огибающей window-squared.

После этого исправления все `view_as_real` / `view_as_complex` в `_magnitude` и `_mask` переписываются так, чтобы вещественные канальные тензоры проходили через весь forward-проход. Никаких комплексных тензоров.

### Блокер 2: `fractions.Fraction` в `model.segment`

Предобученный `htdemucs_ft` хранит длину сегмента как `Fraction(39, 5)` (= 7,8 секунды). Dynamo не может трассировать арифметику `Fraction` — он бросает `torch._dynamo.exc.Unsupported: call_function UserDefinedClassVariable(<class 'fractions.Fraction'>)`.

**Решение.** Привести к float перед экспортом:

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

Тривиально. На инференсе математика идентична.

### Блокер 3: `random.randrange` в cross-transformer

`CrossTransformerEncoder._get_pos_embedding` вызывает питоновский `random.randrange`:

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

На инференсе `sin_random_shift=0`, поэтому `random.randrange(1)` всегда возвращает 0 — no-op. Но ONNX-экспортер всё равно не видит сквозь модуль `random` и падает.

**Решение.** Замонкипатчить сам метод так, чтобы `shift=0` был зашит:

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

Математически идентично на инференсе; экспортируется.

### Блокер 4: `aten::_native_multi_head_attention`

В современном PyTorch `nn.MultiheadAttention.forward` срезает путь до сплавленного C++-ядра (`_native_multi_head_attention`), когда его предусловия выполнены. У этого ядра **нет ONNX-символики ни на одном opset**, и экспортер бросает `UnsupportedOperatorError`.

**Решение.** Заменить forward каждого инстанса `nn.MultiheadAttention` на drop-in реализацию, использующую только простые операции со стабильной ONNX-символикой (`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
```

Патч накатывается на каждый MHA-инстанс в модели. Верифицированный паритет: максимальная разница 1 × 10⁻⁶ против сплавленного fast-path.

### Результат

С наложенными всеми четырьмя патчами `torch.onnx.export` (legacy-экспортер, opset 17, `dynamo=False`) пишет чистый `.onnx`-файл размером 316 MB за 6,5 секунды. Он проходит `onnx.checker.check_model`, содержит 24 765 узлов и запускается в `onnxruntime` из коробки.

| Проверка | Значение | Пройдено |
|---|---:|:---:|
| Round-trip STFT против `torch.stft` / `torch.istft` | 5 × 10⁻⁶ макс. абс. разница | ✅ |
| Пропатченная модель против оригинального PyTorch | 1 × 10⁻⁶ макс. абс. разница | ✅ |
| ONNX Runtime CPU против PyTorch CPU (стем drums) | 1.63 × 10⁻⁴ макс. абс. разница | ✅ |
| ONNX Runtime CPU против PyTorch CPU (стем bass) | 1.1 × 10⁻⁵ макс. абс. разница | ✅ |
| ONNX Runtime CPU против PyTorch CPU (стем other) | 7.4 × 10⁻⁴ макс. абс. разница | ✅ |
| ONNX Runtime CPU против PyTorch CPU (стем vocals) | 8 × 10⁻⁶ макс. абс. разница | ✅ |

Все четыре стема математически эквивалентны официальному PyTorch-`htdemucs_ft` на fp32, с большим запасом до толерантности 1e-3, которой объясняется дрейф накопления чисел с плавающей запятой.

Экспортированные ONNX-модели **на 31% быстрее** на CPU, чем PyTorch-бейзлайн на том же железе — 1,59 с против 2,09 с для 7,8-секундного сегмента, — потому что оптимизатор графа ONNX Runtime может сворачивать и сплавлять очищенный граф агрессивнее, чем eager-рантайм PyTorch.

---

## Что это значит для каждой платформы

Один и тот же `.onnx`-файл работает везде, где работает `onnxruntime`. Ниже — быстрый старт по платформам.

### Python (любая ОС, CPU или 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
```

Соответствующий репозиторий: [`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(...)
```

Положите `.onnx` на 316 MB (или меньшего специалиста) в бандл приложения. CoreML execution provider берёт на себя основную работу на Apple Neural Engine, когда он доступен.

### 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()` даёт вам Android Neural Networks API для ускоренного инференса на NPU Tensor / Snapdragon / MediaTek.

### Веб / `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 });
```

Да, HT-Demucs FT можно запустить в браузере. Да, это медленнее, чем CPU EP (налог WebAssembly), но работает у пользователя без какой-либо установки.

---

## Цифры производительности

Замеры на Apple M4 Pro (24 GB унифицированной памяти) для 3-минутной песни:

| Бэкенд | Латентность | Real-time factor |
|---|---:|---:|
| ONNX Runtime CPU EP (полный bag) | ~88 с | 0.49 |
| ONNX Runtime CPU EP (один специалист) | ~22 с | 0.12 |
| PyTorch CPU (полный bag) | ~125 с | 0.69 |
| PyTorch MPS (полный bag, GPU) | ~47 с | 0.26 |
| ONNX Runtime CUDA (NVIDIA L4, экстраполяция) | ~6 с | 0.03 |

**Одиночный ONNX-специалист в 5,7× быстрее PyTorch CPU** для того же стема при идентичном качестве. Это и есть выигрыш от того, чтобы класть в приложение по удалению вокала `htdemucs-ft-vocals-onnx` вместо полного PyTorch-bag: меньший бинарник, более быстрый инференс, тот же SDR.

---

## Как получаются специалисты по стемам (изящный трюк)

«bag» `htdemucs_ft` — это на самом деле 4 отдельные модели. Матрица весов 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
```

Это значит, что выход drums у bag **есть** выход drums суб-модели 0, бит-в-бит. Поэтому если вам нужны только drums, поставка одной суб-модели 0 (160 MB) даёт идентичное качество drums, как и полный bag на 640 MB, при ~1/4 стоимости инференса.

Мы вынесли это в пять отдельных репозиториев Hugging Face: один полный bag в ONNX ([`htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx)) для удобства, плюс четыре стем-специфичных ONNX-репозитория для продакшен-деплоев, которым нужен один стем. Тот же трюк работает и для родственных PyTorch-репозиториев.

Если вы строите **экстрактор драм-сэмплов** — берите [`htdemucs-ft-drums-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx). **Транскрайбер басовых линий**? [`htdemucs-ft-bass-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-bass-onnx). **Удалитель вокала** или **караоке-мейкер**? [`htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx).

---

## Что дальше

Это День 1 + День 2 трёхдневного ONNX-проекта. **День 3:**

1. **Профилирование CoreML execution provider.** Первая компиляция MLProgram графа из 24 тыс. узлов заняла более 5 минут на M4 Pro в наших тестах. Нужно разобраться с `MinimumDeploymentTarget`, `ComputeUnits=CPUAndNeuralEngine` и правилами фолбэка подграфов, чтобы сделать CoreML EP по-настоящему быстрым на iOS / macOS.
2. **Динамическая квантизация INT8.** `onnxruntime.quantization.quantize_dynamic` для каждой модели — обычно файлы в 4× меньше (~80 MB каждый), падение SDR на музыкальных моделях обычно до 0,3 dB. Огромная мобильная победа, если сработает на этой архитектуре.
3. **Демо-Space на `onnxruntime-web`** на Hugging Face. Разделение стемов только в браузере, drag-and-drop, без установок и сервера. Такие демо разлетаются в Twitter и попадают в Awesome-ONNX-листы.

Подписывайтесь на [организацию StemSplitio на Hugging Face](https://huggingface.co/StemSplitio), чтобы узнать об этом первыми.

---

## Как HT-Demucs ONNX соотносится с PyTorch в 2026 году?

Для серверных Python-деплоев, где вы контролируете рантайм, PyTorch годится — чуть медленнее ONNX Runtime на CPU, но из коробки совместим с overlap-add помощниками `apply_model`.

Для **всего остального** — приложений iOS, приложений Android, инструментов для браузера, встраиваемых устройств, десктоп-инструментов под Windows, которые хотят избежать установки PyTorch на 2 GB — ONNX единственный путь. До этой недели путь был заблокирован. Теперь — нет.

Если вы выбираете между ONNX-репозиториями и StemSplit API для своего продукта, трейд-офф такой:

- **ONNX-репозитории** = никаких затрат за запрос, никакой инфраструктуры, но 316+ MB в приложении и расход CPU/батареи устройства пользователя.
- **StemSplit API** = оплата по секундам, но мгновенный cold-start, качество GPU-уровня, без бандлинга моделей и поддержки версий.

Для пользовательских приложений с >1 тыс. разделений в месяц API обычно выигрывает по совокупной стоимости и пользовательскому опыту. Для одноразовых инструментов или self-hosted установок ONNX-модели — правильный выбор.

---

## Попробуйте StemSplit API — те же модели, развёрнутые для вас

Не хочется класть модель на 316 MB в приложение, держать GPU-пул и писать overlap-add нарезку? [**StemSplit API**](/ru/developers) гоняет те же модели `htdemucs_ft`, что вы найдёте в этих репозиториях Hugging Face — с кредитами, очередями и дашбордом.

- 🌐 [stemsplit.io](https://stemsplit.io) — главная продукта
- 📘 [Документация для разработчиков](/ru/developers/docs) — начать здесь
- 🔌 [Справочник API](/ru/developers/reference) — полный список эндпоинтов
- 📚 [Гайды и рецепты](/ru/developers/guides) — типовые интеграции

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

Или используйте no-code инструменты, в которых уже сегодня крутится то же семейство моделей:

- 🎤 [Удаление вокала](/ru/vocal-remover) — уберите вокал из любой песни за секунды
- 🎶 [Караоке-мейкер](/ru/karaoke-maker) — инструментал + акапелла за один проход
- 🎙️ [Акапелла-мейкер](/ru/acapella-maker) — чистый изолированный вокал
- 📺 [YouTube Stem Splitter](/ru/youtube-stem-splitter) — вставьте ссылку, получите 4 стема
- 🎛️ [Stem Splitter](/ru/stem-splitter) — универсальное разделение на 4 стема

---

## Частые вопросы

### Можно ли экспортировать HT-Demucs FT в ONNX для использования на iOS и Android в 2026 году?

Да — с мая 2026 года [`StemSplitio/htdemucs-ft-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-onnx) даёт первый рабочий ONNX-экспорт полного 4-стемного bag `htdemucs_ft`. Он работает в `onnxruntime-mobile` на iOS (CoreML EP) и Android (NNAPI EP) с тем же численным выходом, что и оригинал на PyTorch. Предыдущие попытки падали потому, что `htdemucs_ft` использует комплексные тензоры, питоновский `fractions.Fraction`, `random.randrange` и сплавленное ядро multi-head attention из PyTorch — а стандартные ONNX-экспортеры отказываются всё это обрабатывать. Этот релиз патчит все четыре блокера и верифицирует паритет в пределах максимальной абсолютной разницы 1,63 × 10⁻⁴.

### Насколько точен ONNX-экспорт по сравнению с моделью HT-Demucs FT на PyTorch?

Бит-эквивалент на fp32 в пределах обычного дрейфа накопления чисел с плавающей запятой. А именно, максимальная абсолютная разница между выходом ONNX Runtime и выходом PyTorch составляет **0,000163 на drums**, **0,000011 на bass**, **0,000739 на other** и **0,000008 на vocals** — все с большим запасом до толерантности 0,001, которой обычно объясняется переупорядочивание операций fp32. Значения SDR на тестовом сете MUSDB18-HQ из [stem-separation-benchmark-2026](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) идентичны PyTorch-бейзлайну.

### Действительно ли HT-Demucs FT в виде ONNX быстрее, чем в PyTorch?

На CPU — да, примерно в 1,31× быстрее (1,59 с против 2,09 с за 7,8-секундный сегмент на M4 Pro). Оптимизатор графа ONNX Runtime агрессивнее сворачивает и сплавляет очищенный граф, чем eager-рантайм PyTorch. На GPU PyTorch и ONNX Runtime + CUDA примерно равны; оба с большим отрывом обгоняют CPU. Бóльший выигрыш получается от поставки одного специалиста (drums/bass/other/vocals) вместо полного bag — они ~4× быстрее полного bag при идентичном качестве своего стема.

### Какой лучший способ запустить HT-Demucs FT в браузере для веб-приложения по удалению вокала?

Возьмите [`StemSplitio/htdemucs-ft-vocals-onnx`](https://huggingface.co/StemSplitio/htdemucs-ft-vocals-onnx) с `onnxruntime-web`. WebAssembly execution provider поддерживает модель целиком. Ожидайте более высокой латентности, чем у нативного решения (налог браузерной песочницы), но без установки и без серверных расходов. Для боевого трафика [StemSplit API](/ru/developers) обычно лучше и по экономике, и по UX — та же модель, GPU-ускорение, оплата по секундам.

### Можно ли обучить свою ONNX-модель HT-Demucs с нуля?

Да — [официальный репозиторий demucs](https://github.com/facebookresearch/demucs) поставляет тренировочный код. Как только у вас на руках обученный чекпоинт `.th`, патчи из наших [скриптов coreml-conversion](https://huggingface.co/StemSplitio/htdemucs-ft-drums-onnx#how-it-was-built) применяются без изменений. Мы думаем над тем, чтобы открыть пайплайн экспорта в виде Python-пакета `demucs-onnx` — открывайте дискуссию в любом из [репозиториев моделей StemSplitio](https://huggingface.co/StemSplitio), если это было бы вам полезно.

---

## Узнайте о Дне 3 первыми

Подпишитесь на [организацию StemSplitio на Hugging Face](https://huggingface.co/StemSplitio) или поставьте watch на [датасет бенчмарка](https://huggingface.co/datasets/StemSplitio/stem-separation-benchmark-2026) — туда в первую очередь приземлятся INT8-квантизованные варианты, разбор профилирования CoreML и браузерный демо-Space.

Если вы что-то строите на этих моделях, нам будет интересно об этом узнать. [Открывайте дискуссию в любом из репозиториев](https://huggingface.co/StemSplitio) или пишите нам на [stemsplit.io/contact](/ru/contact).

---

*Все артефакты этого релиза под MIT-лицензией. Оригинальный HT-Demucs от Rouard, Massa и Défossez (Meta AI); пожалуйста, цитируйте их [статью ICASSP 2023](https://github.com/facebookresearch/demucs), если используете модель в исследованиях.*

---

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