Magpie-TTS Multilingual
NVIDIA Magpie-TTS Multilingual 357M в Swift на Apple Silicon — авторегрессионная мультикодбук TTS-модель поверх 22,05 кГц Nano-Codec от NeMo. Девять языков (английский, испанский, немецкий, французский, итальянский, вьетнамский, хинди, мандаринский, японский), пять встроенных голосовых идентичностей. Квантование INT4 (~247 МБ) или INT8 (~411 МБ). Стриминг с задержкой первого пакета ~120 мс.
Magpie — правильный выбор, когда нужна одна небольшая сборка, говорящая на девяти языках одним и тем же голосом. Пять встроенных голосов сохраняют идентичность между языками — полезно для многоязычных ассистентов, образовательных приложений и озвучки аудиокниг со сменой языка. Для zero-shot клонирования голоса используй CosyVoice3, Qwen3-TTS Base или VoxCPM2.
Архитектура
Magpie — это MLX-пайплайн из 4 бандлов: текстовый энкодер → декодер с cross-attention → LocalTransformer-голова кодбуков → причинный HiFi-GAN аудиокодек. Бандлы разделяют веса декодера между точками входа prefill и step для совместимости с CoreML-разметкой FluidInference upstream.
| Этап | Модуль | Детали |
|---|---|---|
| 1. Токенизация | MagpieTokenizer | Поязычный G2P (IPA-словарь / byT5-байты / пиньинь / катакана), общий словарь на 2360 токенов + потокенайзерные смещения, EOS всегда добавляется |
| 2. Текстовый энкодер | MagpieTextEncoder | 6 каузальных Transformer-слоёв, d=768, conv FFN k=3 |
| 3. Decoder prefill | MagpieDecoder | 12 каузальных слоёв с cross-attention. Засеивает KV-кеш 110-кадровым контекстом встроенного голоса + BOS. |
| 4. LocalTransformer | MagpieLocalTransformer | 1-слойная AR-голова кодбуков, d=256. Сэмплит 8 кодбуков на кадр последовательно из hidden декодера. |
| 5. Decoder step | MagpieDecoder | Один AR-шаг на кадр до EOS или лимита в 500 кадров (~23 с). |
| 6. NanoCodec | MagpieNanoCodec | FSQ-инверсия → каузальный HiFi-GAN → моно-волна 22,05 кГц. |
Языки и G2P
Все девять языков проходят круговой обход через Qwen3-ASR в testMultilingualRoundTrip SDK. Для каждого свой пайплайн:
| Язык | Код | Пайплайн G2P |
|---|---|---|
| Английский | en | CMU IPA-словарь (125 тыс. записей, встроен) |
| Испанский | es | Испанский IPA-словарь (встроен) |
| Немецкий | de | Немецкий IPA-словарь (встроен) |
| Французский | fr | Кодировщик UTF-8-байтов byT5 |
| Итальянский | it | Кодировщик UTF-8-байтов byT5 |
| Вьетнамский | vi | Кодировщик UTF-8-байтов byT5 |
| Хинди | hi | Поиск по код-поинтам деванагари + last-wins под-словарь |
| Мандаринский | zh | Сегментация слов NLTokenizer(.simplifiedChinese) + Apple .mandarinToLatin + встроенный словарь пиньинь → IPA + тоновые маркеры #N |
| Японский | ja | Чтение иероглифов через CFStringTokenizer + NFC-сохранение дакутэн + хейбан-маркеры высоты + переопределения частиц/приветствий |
Общий словарь на 2360 токенов конкатенирует под-токенайзеры каждого языка со смещением (зафиксировано в MagpieSubVocab). Text-embedding добавляет две строки сверх словаря для BOS/EOS; eos_id = 2361 добавляется в каждую входную последовательность.
Встроенные голоса
Чекпойнт встраивает пять голосовых контекстов (по 110 кадров × 768 измерений), используемых префиксом каждого AR-декодирования. Идентичность голоса согласована на всех девяти языках.
| Индекс | Имя CLI | Идентичность |
|---|---|---|
| 0 | sofia | Sofia (по умолчанию) |
| 1 | aria | Aria |
| 2 | jason | Jason |
| 3 | leo | Leo |
| 4 | john | John Van Stan |
Варианты модели
| Вариант | Диск | RAM (загрузка + декод) | HuggingFace |
|---|---|---|---|
| INT4 (по умолчанию) | ~247 МБ | ~1,3 ГБ | aufklarer/Magpie-TTS-Multilingual-357M-MLX-4bit |
| INT8 | ~411 МБ | ~1,6 ГБ | aufklarer/Magpie-TTS-Multilingual-357M-MLX-8bit |
Оба бандла используют MLX flat-affine-квантование (mlx_affine_flat, group size 64) и деквантуются в FP32 при загрузке — активации в рантайме в полной точности. INT4 и INT8 на слух неотличимы для этой модели; выбирай INT4, если только нет лишнего места.
Использование CLI
# Английский, жадное декодирование
speech speak "Hello, world." --engine magpie --magpie-speaker aria \
--magpie-temperature 0 -o out.wav
# Испанский (любой из 9 языков — выбирай через --language)
speech speak "Hola, mundo." --engine magpie --language es \
--magpie-speaker aria -o out.wav
# Японский — нужно стохастическое декодирование (жадное застревает на первой фразе)
speech speak "こんにちは世界、これは音声合成システムです。" \
--engine magpie --language ja --magpie-temperature 0.6 \
--magpie-top-k 80 --seed 42 -o out.wav
# Стриминг с воспроизведением
speech speak "Streaming test" --engine magpie --stream --play
# Список 5 встроенных голосов
speech speak --engine magpie --list-speakers
# Пред-фонемизированный IPA пропускает поязычный G2P
speech speak "həˈloʊ" --engine magpie --magpie-prephonemized -o out.wav
Опции
| Опция | По умолчанию | Описание |
|---|---|---|
--magpie-variant | int4 | Вариант квантования: int4 или int8 |
--magpie-speaker | sofia | Встроенный голос: sofia, aria, jason, leo, john |
--magpie-temperature | 0.6 | Температура сэмплирования (0 = жадное) |
--magpie-top-k | 80 | Top-k фильтр для сэмплирования |
--magpie-max-frames | 500 | Жёсткое ограничение кадров кодека (~23 с) |
--magpie-min-frames | 4 | Минимум кадров до разрешения EOS |
--magpie-prephonemized | выкл | Считать вход потоком IPA/фонем; пропустить поязычный G2P |
--language | english | Выбор поязычного токенайзера |
--stream | выкл | Эмитить AsyncStream<AudioChunk> вместо одного WAV |
--seed | — | Воспроизводимое Gumbel-сэмплирование |
Японские входы длиннее одного слова требуют стохастического декодирования (--magpie-temperature 0.6 --magpie-top-k 80 --seed 42 зеркалит референс-тест NeMo). Жадное декодирование застревает на первой фразе, потому что хейбан-эвристика тона отклоняется от пословной истины.
Клонирование голоса — не поддерживается
В Magpie нет zero-shot кондиционирования голоса в модели; в бандле только 5 встроенных идентичностей. CLI отвергает общие флаги --voice-sample, --speaker, --instruct с действенной ошибкой, указывающей на --magpie-speaker или на движки с поддержкой клонирования (Qwen3-TTS Base, CosyVoice3, VoxCPM2).
Производительность (M4 Pro)
| Настройка | Аудио | Время | RTF |
|---|---|---|---|
| Батч, INT4, жадное, короткий промпт | 2.8 с | 0.88 с | 0.32 |
| Батч, INT4, жадное, предложение | 5.8 с | 1.35 с | 0.23 |
| Батч, INT4, сэмплинг, выход 23 с | 23 с | 5.6 с | 0.24 |
| Стриминг, INT4, сэмплинг | 23 с | 21.6 с | 0.93 |
Задержка первого пакета в режиме стриминга ≈120 мс после загрузки модели. RTF стриминга выше, потому что кодек повторно вызывается на полном буфере кодов при каждом выпуске чанка (в будущей версии можно кешировать состояние кодека).
Swift API
import MagpieTTS
let model = try await MagpieTTS.fromPretrained(variant: .int4)
// Батч-синтез (en/es/de/fr/it/vi/hi/zh — жадное работает)
let audio = try model.synthesize(
text: "Hello, world.",
speaker: .aria,
language: .english,
params: MagpieTTSParams(temperature: 0, topK: 1, maxSteps: 500))
// Японский — использовать стохастическое сэмплирование
let audioJA = try model.synthesize(
text: "こんにちは世界、これは音声合成システムです。",
speaker: .aria,
language: .japanese,
params: MagpieTTSParams(temperature: 0.6, topK: 80,
maxSteps: 300, seed: 42))
// Стриминг (AsyncStream<AudioChunk>)
let stream = model.synthesizeStream(
text: "Streaming text",
speaker: .aria,
language: .english,
firstChunkFrames: 8,
framesPerChunk: 25)
for try await chunk in stream {
// chunk.samples — Float32 моно 22,05 кГц
}
CoreML-бэкенд (--engine magpie-coreml)
Помимо MLX-бандла, Magpie поставляет CoreML-бандл (aufklarer/Magpie-TTS-Multilingual-357M-CoreML-8bit, ~342 МБ INT8). Четыре пакета .mlmodelc — text_encoder, decoder_prefill, decoder_step, nanocodec_decoder — выполняются на ANE / GPU; обратное FSQ на стороне Swift превращает сэмплированные коды в 32-мерные латенты, которые потребляет кодек.
# 8 языков (без японского), 5 встроенных голосов
speech speak "Hello world." --engine magpie-coreml --magpie-speaker aria -o hi.wav
speech speak "Hola mundo." --engine magpie-coreml --language es --magpie-speaker leo -o es.wav
# --language ja автоматически перенаправляется на MLX-бэкенд (заметка в stderr)
speech speak "こんにちは" --engine magpie-coreml --language ja -o ja.wav
Оговорки относительно --engine magpie:
- Гибридный пайплайн сейчас. 1-слойный LocalTransformer (настоящая голова сэмплирования кодбуков, которую обучает NeMo) и 8 таблиц аудио-эмбеддингов не поставляются внутри CoreML-бандла. При первой синтезации CoreML-движок подгружает MLX INT4-бандл, чтобы вести оба компонента. ASR round-trip побитово идентичен MLX-бэкенду; разница в том, что этот движок также скачивает MLX-бандл. Чистый CoreML-путь для развёртывания только на ANE iOS требует, чтобы бандл поставлял
local_transformer/*.npy+audio_embedding_*.npyи LT на Swift Accelerate (отслеживаемая последующая задача). - Без стриминга.
nanocodec_decoder.mlmodelcотслежен с фиксированным окном в 64 кадра. Более длинные последовательности чанкуются внутренне, но задержка первого пакета была бы ~3 с при эмиссии на границах чанков.--streamотклоняется с актуальной ошибкой. - Без японского токенизатора. CoreML-бандл пока не поставляет JSON японского токенизатора.
--language jaс этим движком автоматически переходит на MLX-бэкенд.
Порядок голосов соответствует speaker_info.json CoreML-бандла (0=John, 1=Sofia, 2=Aria, 3=Jason, 4=Leo — отличается от MLX); enum голосов мапится внутренне, чтобы CLI-имена работали для обоих движков.
Замечания по реализации
Три бага, о которых стоит знать при портировании NeMo-style многоязычного TTS:
- Целочисленное деление FSQ —
/в MLX-swift — это вещественное деление (mlx_divide); FSQ-инверсия NeMo использует Python//. ИспользуйMLX.floorDivide(...), иначе каждый FSQ-слот декодируется с дробными смещениями и кодек размывает звук. - Смещения под-словарей —
AggregatedTTSTokenizerNeMo конкатенирует словари по языкам со смещениями. Наивная глобальная first-occurrence-карта всегда попадает в английскую область и даёт бессмысленный звук для других языков. - Дедуп last-wins для хинди —
HindiCharsTokenizerэмитит дублирующиеся записи деванагари в своём словаре (CHARSET пересекается с PUNCT_LIST). Python-словарное включение{l: i for i, l in enumerate(tokens)}сохраняет последнее присваивание; зеркалируй это, не используй first-occurrence.
Все три исправления задокументированы inline в Swift-модуле.
Источники
- Upstream-веса: nvidia/magpie_tts_multilingual_357m (NVIDIA Open Model License)
- Кодек: nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps
- Статья: NanoCodec: Towards High-Quality Ultra Fast Speech LLM Inference (2025)
- Референс-CoreML-порт: FluidInference/mobius
- Swift-модули: MagpieTTS (MLX) + MagpieTTSCoreML (CoreML)
- CoreML-бандл: aufklarer/Magpie-TTS-Multilingual-357M-CoreML-8bit
Лицензия
- Веса модели: NVIDIA Open Model License (коммерческое использование разрешено; см. страницу HuggingFace)
- Swift-порт + встроенные IPA/пиньинь-словари: то же, что upstream NeMo (словари Apache 2.0, модель NVIDIA OML)