# Разделение Demucs

Разделяйте музыку на стемы (вокал, ударные, бас, другое) с помощью Demucs.

{% hint style="success" %}
Все примеры можно запускать на GPU-серверах, арендуемых через [CLORE.AI Marketplace](https://clore.ai/marketplace).
{% endhint %}

## Аренда на CLORE.AI

1. Посетите [CLORE.AI Marketplace](https://clore.ai/marketplace)
2. Отфильтруйте по типу GPU, объему VRAM и цене
3. Выберите **On-Demand** (фиксированная ставка) или **Spot** (цена по ставке)
4. Настройте ваш заказ:
   * Выберите Docker-образ
   * Установите порты (TCP для SSH, HTTP для веб-интерфейсов)
   * Добавьте переменные окружения при необходимости
   * Введите команду запуска
5. Выберите способ оплаты: **CLORE**, **BTC**, или **USDT/USDC**
6. Создайте заказ и дождитесь развертывания

### Доступ к вашему серверу

* Найдите данные для подключения в **Моих заказах**
* Веб-интерфейсы: используйте URL HTTP-порта
* SSH: `ssh -p <port> root@<proxy-address>`

## Что такое Demucs?

Demucs от Meta AI может:

* Отделять вокал от музыки
* Извлекать ударные, бас и другие инструменты
* Обрабатывать любые аудиоформаты
* Высококачественное извлечение стемов

## Быстрое развертывание

**Docker-образ:**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime
```

**Порты:**

```
22/tcp
7860/http
```

**Команда:**

```bash
pip install demucs gradio && \
python -c "
import gradio as gr
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torch
import torchaudio
import tempfile
import os

model = get_model('htdemucs')
model.cuda()

def separate(audio_path, stem):
    wav, sr = torchaudio.load(audio_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    stems = {'drums': 0, 'bass': 1, 'other': 2, 'vocals': 3}
    output = sources[stems[stem]].cpu()

    with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as f:
        torchaudio.save(f.name, output, sr)
        return f.name

demo = gr.Interface(
    fn=separate,
    inputs=[gr.Audio(type='filepath'), gr.Dropdown(['vocals', 'drums', 'bass', 'other'])],
    outputs=gr.Audio(),
    title='Demucs Audio Separator'
)
demo.launch(server_name='0.0.0.0', server_port=7860)
"
```

## Доступ к вашему сервису

После развертывания найдите ваш `http_pub` URL в **Моих заказах**:

1. Перейдите на **Моих заказах** страницу
2. Нажмите на ваш заказ
3. Найдите `http_pub` URL (например, `abc123.clorecloud.net`)

Используйте `https://YOUR_HTTP_PUB_URL` вместо `localhost` в примерах ниже.

## Установка

```bash
pip install demucs

# или
pip install -e git+https://github.com/facebookresearch/demucs#egg=demucs
```

## Использование в командной строке

### Базовое разделение

```bash

# Разделить на 4 стема
demucs song.mp3

# Вывод: separated/htdemucs/song/{drums,bass,other,vocals}.wav
```

### Параметры

```bash
demucs \
    --two-stems vocals \     # Только вокал + инструментал
    -n htdemucs \            # Название модели
    -d cuda \                # Использовать GPU
    -o ./output \            # Каталог вывода
    --mp3 \                  # Вывести в MP3
    song.mp3
```

### Обработка папки

```bash
demucs --two-stems vocals -d cuda ./songs/*.mp3
```

## Python API

### Базовое разделение

```python
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torchaudio
import torch

# Загрузить модель
model = get_model('htdemucs')
model.cuda()
model.eval()

# Загрузить аудио
wav, sr = torchaudio.load("song.mp3")
wav = wav.cuda()

# Разделить
with torch.no_grad():
    sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

# форма sources: [4, channels, samples]

# 0: drums, 1: bass, 2: other, 3: vocals

# Сохранить стемы
stems = ['drums', 'bass', 'other', 'vocals']
for i, stem in enumerate(stems):
    torchaudio.save(f"{stem}.wav", sources[i].cpu(), sr)
```

### Получить только вокал

```python
def extract_vocals(audio_path):
    wav, sr = torchaudio.load(audio_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    vocals = sources[3].cpu()  # Индекс 3 = вокал
    return vocals, sr

vocals, sr = extract_vocals("song.mp3")
torchaudio.save("vocals.wav", vocals, sr)
```

### Получить инструментал (без вокала)

```python
def extract_instrumental(audio_path):
    wav, sr = torchaudio.load(audio_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    # Сумма ударных + баса + другого
    instrumental = sources[0] + sources[1] + sources[2]
    return instrumental.cpu(), sr

instrumental, sr = extract_instrumental("song.mp3")
torchaudio.save("instrumental.wav", instrumental, sr)
```

## Варианты моделей

| Модель       | Стемы | Качество | Скорость |
| ------------ | ----- | -------- | -------- |
| htdemucs     | 4     | Лучшее   | Средне   |
| htdemucs\_ft | 4     | Best+    | Медленно |
| htdemucs\_6s | 6     | Отлично  | Средне   |
| mdx\_extra   | 4     | Отлично  | Быстро   |

### Модель с 6 стемами

```python
model = get_model('htdemucs_6s')

# Стемы: drums, bass, other, vocals, guitar, piano
```

### Дообученная модель

```python
model = get_model('htdemucs_ft')

# Более высокое качество, но медленнее
```

## Пакетная обработка

```python
import os
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torchaudio
import torch

model = get_model('htdemucs')
model.cuda()
model.eval()

input_dir = "./songs"
output_dir = "./separated"

for filename in os.listdir(input_dir):
    if filename.endswith(('.mp3', '.wav', '.flac')):
        input_path = os.path.join(input_dir, filename)
        song_output_dir = os.path.join(output_dir, filename.rsplit('.', 1)[0])
        os.makedirs(song_output_dir, exist_ok=True)

        print(f"Processing: {filename}")

        wav, sr = torchaudio.load(input_path)
        wav = wav.cuda()

        with torch.no_grad():
            sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

        stems = ['drums', 'bass', 'other', 'vocals']
        for i, stem in enumerate(stems):
            torchaudio.save(
                os.path.join(song_output_dir, f"{stem}.wav"),
                sources[i].cpu(),
                sr
            )

        print(f"Saved: {song_output_dir}")
```

## API-сервер

```python
from fastapi import FastAPI, UploadFile
from fastapi.responses import FileResponse
from demucs.pretrained import get_model
from demucs.apply import apply_model
import torchaudio
import torch
import tempfile
import os

app = FastAPI()

model = get_model('htdemucs')
model.cuda()
model.eval()

@app.post("/separate")
async def separate(file: UploadFile, stem: str = "vocals"):
    # Сохранить загруженный файл
    with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
        content = await file.read()
        tmp.write(content)
        tmp_path = tmp.name

    # Загрузить и разделить
    wav, sr = torchaudio.load(tmp_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    stems = {'drums': 0, 'bass': 1, 'other': 2, 'vocals': 3}
    output = sources[stems[stem]].cpu()

    # Сохранить вывод
    with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as out:
        torchaudio.save(out.name, output, sr)
        return FileResponse(out.name, media_type="audio/wav")

@app.post("/instrumental")
async def get_instrumental(file: UploadFile):
    with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as tmp:
        content = await file.read()
        tmp.write(content)
        tmp_path = tmp.name

    wav, sr = torchaudio.load(tmp_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    # Объединить не-вокальные стемы
    instrumental = sources[0] + sources[1] + sources[2]

    with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as out:
        torchaudio.save(out.name, instrumental.cpu(), sr)
        return FileResponse(out.name, media_type="audio/wav")

# Запуск: uvicorn server:app --host 0.0.0.0 --port 8000
```

## Оптимизация памяти

### Для длинного аудио

```python
from demucs.apply import apply_model

# Использовать разбиение для длинного аудио
sources = apply_model(
    model,
    wav.unsqueeze(0),
    split=True,         # Разбивать на части
    overlap=0.25,       # Перекрытие между частями
    progress=True
)[0]
```

### Для ограниченной видеопамяти (VRAM)

```python

# Использовать CPU для некоторых операций
model.cpu()
wav = wav.cpu()

# Или использовать сегментную обработку
sources = apply_model(
    model,
    wav.unsqueeze(0),
    split=True,
    segment=10  # сегменты по 10 секунд
)[0]
```

## Сценарии использования

### Караоке трек

```python
def create_karaoke(song_path):
    wav, sr = torchaudio.load(song_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    # Всё кроме вокала
    karaoke = sources[0] + sources[1] + sources[2]
    return karaoke.cpu(), sr
```

### Подготовка ремикса

```python
def extract_all_stems(song_path, output_dir):
    wav, sr = torchaudio.load(song_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    stems = ['drums', 'bass', 'other', 'vocals']
    paths = {}

    for i, stem in enumerate(stems):
        path = os.path.join(output_dir, f"{stem}.wav")
        torchaudio.save(path, sources[i].cpu(), sr)
        paths[stem] = path

    return paths
```

### Извлечение акапеллы

```python
def extract_acapella(song_path):
    wav, sr = torchaudio.load(song_path)
    wav = wav.cuda()

    with torch.no_grad():
        sources = apply_model(model, wav.unsqueeze(0), split=True)[0]

    vocals = sources[3]
    return vocals.cpu(), sr
```

## Советы по качеству

### Для наилучших результатов

* Используйте без потерь вход (WAV, FLAC)
* Более высокая частота дискретизации = лучшее качество
* Используйте `htdemucs_ft` для критической работы

### Постобработка

```python
from pydub import AudioSegment
from pydub.effects import normalize, high_pass_filter

# Загрузить разделённый вокал
vocals = AudioSegment.from_wav("vocals.wav")

# Удалить низкие шумы
vocals = high_pass_filter(vocals, 80)

# Normalize
vocals = normalize(vocals)

vocals.export("vocals_clean.wav", format="wav")
```

## Производительность

| Длина аудио      | GPU      | Время   |
| ---------------- | -------- | ------- |
| 3-минутная песня | RTX 3090 | \~15с   |
| 3-минутная песня | RTX 4090 | \~10с   |
| 3-минутная песня | A100     | \~8s    |
| 1-часовой альбом | RTX 3090 | \~5 мин |

## Устранение неполадок

### Недостаточно памяти

```bash

# Использовать меньшие сегменты
demucs --segment 10 song.mp3
```

### Плохое разделение

* Используйте модель htdemucs\_ft
* Проверьте качество входа
* Избегайте сильно сжатых MP3

### Артефакты

* Увеличьте перекрытие
* Используйте модель более высокого качества
* Проверьте наличие клиппинга на входе

## Оценка стоимости

Типичные ставки на маркетплейсе CLORE.AI (по состоянию на 2024):

| GPU       | Почасовая ставка | Дневная ставка | Сессия 4 часа |
| --------- | ---------------- | -------------- | ------------- |
| RTX 3060  | \~$0.03          | \~$0.70        | \~$0.12       |
| RTX 3090  | \~$0.06          | \~$1.50        | \~$0.25       |
| RTX 4090  | \~$0.10          | \~$2.30        | \~$0.40       |
| A100 40GB | \~$0.17          | \~$4.00        | \~$0.70       |
| A100 80GB | \~$0.25          | \~$6.00        | \~$1.00       |

*Цены варьируются в зависимости от провайдера и спроса. Проверьте* [*CLORE.AI Marketplace*](https://clore.ai/marketplace) *для текущих тарифов.*

**Экономьте деньги:**

* Используйте **Spot** рынок для гибких рабочих нагрузок (часто на 30–50% дешевле)
* Платите с помощью **CLORE** токенов
* Сравнивайте цены у разных провайдеров

## Дальнейшие шаги

* [RVC Клонирование голоса](https://docs.clore.ai/guides/guides_v2-ru/audio-i-golos/rvc-voice-clone) - Обрабатывать извлечённый вокал
* [AudioCraft Music](https://docs.clore.ai/guides/guides_v2-ru/audio-i-golos/audiocraft-music) - Генерировать новую музыку
* [Whisper Transcription](https://docs.clore.ai/guides/guides_v2-ru/audio-i-golos/whisper-transcription) - Транскрибировать вокал
