Почему потоковый TTS и что такое VoXtream
Большинство моделей синтеза работают офлайн: получили весь текст, подумали, выдали аудио целиком. Для голосового ассистента или синхронного перевода это плохо — важна задержка до первого звука. LLM генерирует ответ токен за токеном, и от TTS хочется того же: начать говорить, пока текст ещё дописывается.
VoXtream (KTH, ICASSP 2026) — это full-stream TTS: он принимает текст инкрементально и начинает говорить с первого слова, с задержкой до первого пакета аудио ~100 мс на обычной GPU. Архитектура — три авторегрессионных трансформера поверх нейрокодека Mimi:

Цвета на схеме: зелёное — три трансформера, которые обучаются (именно они дообучались под русский); розовое — предобученные компоненты, чьи веса не трогаются (кодек Mimi и спикер-энкодер); жёлтое — необучаемая обработка вне модели (G2P и SRC); синее — входы.
Phoneme Transformer (PT) — шаг за шагом кодирует поток фонем. Ключевая идея — ограниченный look-ahead: модель видит вперёд не всю фразу, а несколько фонем, поэтому может начинать генерацию, не дожидаясь конца предложения.
Temporal Transformer (TT) — главный генератор. На каждом кадре (Mimi работает на 12.5 Гц, кадр = 80 мс) он предсказывает семантический токен кодека и duration-токен. Duration-токен — самое интересное место: он кодирует «остаёмся на текущей фонеме или двигаемся дальше, и сколько фонем помещается в кадр» (сдвиг 0/1/2 × 1/2 фонемы = 6 состояний). Получается монотонное выравнивание фонем и аудио, встроенное прямо в генерацию.
Depth Transformer (DT) — по выходу TT и семантическому токену достраивает акустические токены остальных кодбуков Mimi (тембр, детали). Сюда же подмешивается эмбеддинг диктора (ReDimNet) — так работает клонирование голоса.
Далее Mimi-декодер превращает токены в звук, кадр за кадром.
Как можно было понять из текста выше, что модель учится на пофонемных длительностях. Чтобы обучить duration-токены, каждому кадру аудио нужно сопоставить конкретные фонемы. Значит, весь датасет должен быть пофонемно выровнен форс-алайнером - и качество этого выравнивания напрямую становится качеством ритма речи.
Чем VoXtream2 отличается от первого
VoXtream2 отличается от исходной VoXtream по нескольким ключевым параметрам. Для G2P (преобразования текста в фонемы) VoXtream использовала g2pE, который поддерживал только английский язык. VoXtream2 перешла на espeak-ng с IPA, что дало мультиязычность. Глубина look-ahead по фонемам выросла с 10 до 25, что улучшает просодию (при дообучении на русский эта величина не фиксировалась, а семплировалась на каждом шаге обучения: в 70% случаев — из плотной сетки 1–30 фонем, в 30% — из разреженной сетки дальних значений 40…450 и «вся фраза». Это одновременно аугментация и способ получить одну модель для двух режимов: потокового, где look-ahead мал, и офлайн, где текст известен целиком и просодия заметно лучше — в частности, вопросительная интонация). Число кодбуков Mimi увеличилось с 12 до 16, что повышает качество звука. Для текста промпта VoXtream требовала транскрипт с выравниванием, тогда как VoXtream2 использует prompt text masking — фонемы промпта помечаются как UNK. Пунктуация: VoXtream её не поддерживала, а VoXtream2 вводит знаки .,!? как отдельные фонемные токены. Управление темпом речи в VoXtream отсутствовало, а в VoXtream2 появился SRC — distribution matching по duration-токенам, позволяющий менять темп на лету. CFG (classifier-free guidance) в VoXtream не применялось, а VoXtream2 использует его на всех кондиционированиях. Наконец, задержка до первого звука снизилась со 102 до 74 мс, при этом генерация идёт в 4 раза быстрее реального времени.
Prompt text masking. В первой версии, чтобы клонировать голос, нужен был транскрипт промпта и его выравнивание. Во второй фонемы промпта просто заменяются на UNK-токены — модель кондиционируется на промпт чисто акустически. Следствие: промпт может быть на любом языке. Дал английскую запись — получил русскую речь тем же голосом.
SRC — speaking rate control. Duration-токены каждого шага образуют распределение. SRC сравнивает целевую гистограмму длительностей (для заданных «слогов в секунду») с накопленной за последние секунды генерации и мягко перевзвешивает логиты duration-токенов. Никакого переобучения — темп меняется прямо во время произнесения фразы.
Дообучение на русский
Расширение словаря: единый espeak-IPA словарь с ударениями. Забавное инженерное ограничение: пайплайн пишет фонемные потоки в uint8, словарь обязан влезать в 255 токенов — редкие фонемы отсекаются порогом частоты. Итог — 166 токенов.
Хирургия эмбеддингов: матрица phone_embeddings расширяется, новые русские строки инициализируются от ближайшей английской фонемы (tʲ ← t, ˈɑ ← ɑ…), спец-токены переезжают в конец. Всё остальное — веса трансформеров — берётся от английского чекпоинта как есть.
Своя акустическая модель для MFA — готовые русские модели выравнивания используют другой фонемный алфавит, а нужен ровно espeak, иначе цикл «данные ↔ инференс» рвётся. Пришлось переобучить MFA на своём корпусе под espeak-словарь с ударениями.
Ударения и омографы на инференсе — RUAccent (за́мок/замо́к решает контекстная модель, ручной
+в тексте имеет приоритет). Отдельная мелочь: espeak читает+как «плюс», поэтому ударение из разметки нельзя подавать в G2P — оно переносится пост-обработкой, перестановкой ˈ на нужную гласную.
Дальше классика: сначала претрейн TT+PT с замороженным Depth Transformer (пока эмбеддинги новых фонем «встают на место», тембровую часть не трогаем), потом разморозка DT, потом специализированные стадии.
Данные
Русской речи в открытом доступе много, но она разного качества и в разных форматах. Все доступные наборы данных (~3.6 млн клипов, ~4500 часов) были приведены к единой схеме метаданных с помощью audiogear. Audiogear считает по каждому клипу набор метрик качества (нейро-MOS, SNR, разборчивость, полоса, согласие ASR с текстом). На выходе получилось ~1870 часов.
Основные моменты по фильтрации и предобработке аудио:
Доверенные студийные наборы использовались целиком, остальные по метрикам: DistillMOS ≥ 3.0–3.3, WADA-SNR ≥ 14, STOI ≥ 0.9, полоса ≥ 9 кГц. Для наборов с ASR-текстами — дополнительный фильтр по CER независимого ASR (GigaAM-v3 ≤ 0.10): если два распознавателя не согласны, то аудио отбрасываем.
Никакого денойза. Модель выучивает артефакты энхансеров очень быстро, поэтому апсемплились нейросетью только 16-кГц аудио.
Пунктуация из аудио. В некотором количестве аудио пунктуация отсутствует, поэтому пришлось прогоняеть через ASR для востановление пунктуации.
Ударения: Для ударений использовался RUAccent.
Цифры: клипов с цифрами в тексте всего 0.24% — имплицитно числительные не выучить (и тут не понятно как с mfa их разметить). Для работы с цифрами используем RUNorm.
Громкость: каждый клип приводится к −23 LUFS, и промпт на инференсе — к тому же уровню.
Как готовить данные для VoXtream
VoXtream учится на длинных последовательностях (55 секунд = 688 кадров Mimi), а корпус состоит из клипов по 3–15 секунд. Значит, клипы одного диктора нужно склеивать в группы. И эта склейка — не техническая формальность, а место, где вы программируете просодию будущей модели. Всё, что вы вклеите между фразами, модель выучит как «так люди делают паузы».

Паузы — из эмпирики, с правильной структурой дисперсии. Статистика с 4.5 млн реальных межфразовых пауз: медиана после точки 0.39 с, после вопроса 0.42, после запятой 0.27. Но вставлять всем одну медиану нельзя (робот), и семплировать каждую паузу независимо из общего распределения тоже нельзя — тогда внутри одной фразы разброс будет как между разными дикторами. Работает расщеплённая дисперсия: пауза = медиана_знака × темп_группы × шум, где темп группы — один лог-нормальный множитель на всю группу (межгрупповая вариация), а шум — покадровый (внутригрупповая, CV≈0.54, как у живого человека). И обязательно клампы на хвосты распределения: без них модель выучила редкие двухсекундные паузы и стала вставлять их где попало.
Тишина — это не ноль. Паузы нельзя заполнять цифровым нулём: в реальных записях там комнатный тон, и модель отлично слышит разницу. Первая версия «комнатного тона» тайлила зеркальным повтором 60-мс окно тишины — период 8 Гц слышался как вертолёт, и модель честно выучила вертолёт. Правильно: синтезировать стационарный шум со спектральной огибающей тихого участка самого клипа (случайные фазы + overlap-add). Автокорреляция упала с 0.97 до 0.03.
Фейды — только внутри собственной тишины клипа, raised-cosine до 40 мс. Двухмиллисекундный фейд в ноль слышен как обрыв; фейд, наезжающий на речь, смягчает согласные.
Не ломайте причинные связи аугментацией. Темпо-аугментация (копии клипов ×0.75 и ×1.3 скорости) — полезная вещь, но если такие копии попадают в один пул с оригиналами, модель видит группы, где промпт медленный, а продолжение быстрое — и делает логичный вывод: «темп промпта ничего не значит». Аугментированные версии — строго отдельными пулами. По той же причине группы собираются однородными по темпу (клипы бинуются по слогам-в-секунду).
Мелочи, которые оказались не мелочами: порядок клипов в группе = порядок записи (у аудиокниг это даёт естественные продолжения мысли); 10% коротких групп (5–35 с) лечат галлюцинации на коротких промптах; спикер-эмбеддинги считаются мульти-кропом (6 кропов разной длины с разных мест группы, при обучении семплируется один) — так покрытие вариативности реальных промптов гораздо лучше, чем от изотропного шума поверх одного эмбеддинга.
MFA: форс-алайнер для VoXtream — не вспомогательный инструмент, а источник ground truth: из пофонемной разметки берутся duration-токены (ритм!), позиции пауз, темп клипов, статистика для склейки групп. Почему MFA. Для русского языка, к сожалению, нет ни одного нормального выравнивателя кроме MFA.
Как кадры выравниваются по фонемам
Mimi работает на 12.5 кадрах в секунду — кадр 80 мс. Фонема в беглой речи длится 30–120 мс: в один кадр помещается одна или две фонемы, а долгая ударная гласная тянется на несколько кадров. Из TextGrid берутся только начала фонем; конец каждой — начало следующей (паузы sil — такие же фонемы), последняя тянется до конца слота. При склейке группы клипы кладутся на общую шкалу времени с учётом вставленных пауз. Дальше строится миллисекундная сетка — каждой миллисекунде приписан индекс фонемы, — и кадр i = окно [80i, 80i+80): множество фонем, попавших в окно, и есть «фонемы кадра». Их не больше двух: если из-за очень коротких звуков в кадр попало три, самая короткая выбрасывается из потока, чтобы выравнивание осталось монотонным с меньше или равно двум фонемами на кадр.

Duration-состояние кадра — пара (сдвиг, число фонем): сдвиг = индекс первой фонемы этого кадра минус индекс последней фонемы предыдущего (0 — остались на той же, 1 — перешли к следующей, 2 — перескочили одну совсем короткую), число фонем — 1 или 2. Итого шесть состояний. Именно их Temporal Transformer учится предсказывать совместно с семантическим токеном — один softmax над (словарь Mimi × 6), — а на инференсе предсказанное состояние двигает указатель по фонемной последовательности: так выравнивание генерируется вместе со звуком, и модель не может ни перескочить слово, ни зациклиться.
Две последние детали. Знаки препинания вставляются в поток отдельными токенами после последней фонемы слова — их видит Phoneme Transformer (контекст интонации), но перед Temporal Transformer они удаляются, так как знак препинания — не фонема, и кадр ему не нужен. Ударение переносится из accent_text перестановкой ˈ на нужную гласную внутри слова.
Какие проблемы были в словаре
Односимвольные предлоги записаны названиями букв:
в → v ˈɛ(«вэ»),к → k ˈɑ(«ка»),с → ˈɛ s(«эс»). MFA, доверяя словарю, впихивал несуществующий гласный в аудио: медиана длительности предлога «в» получалась 140 мс вместо реальных 40–80. Предлог «в» встречается в четверти клипов — то есть ~40% корпуса имело испорченный ритм. Фикс: варианты произношения с ассимиляцией звонкости (в → v|f,к → k|ɡ) — MFA сам выбирает вариант по акустике.Междометия — тем же способом: «хм» = «ха-эм», «ммм» = «эм-эм-эм» (1858 вхождений). Жемчужина коллекции — статья
ь, которая разворачивалась в транскрипцию целой фразы «мягкий знак».А вот аббревиатуры (ссср, нтв, днк) по буквам — правильно, их трогать нельзя. Автоаудит на этот класс простой: слова без гласных букв, у которых в произношении есть гласные фонемы.
Потерянная ё. Корпус для MFA собирался из колонки
text, где ё давно заменена на е. Модель училась говорить «мое» вместо «моё» — на 13.3% корпуса. Правильные статьи в словаре были всегда — не было правильных текстов. Пересборка изaccent_text+ числовой гейт: в клипах с ё фонема ɵ обязана присутствовать (после фикса — 92.9%).Дефисные слова. Если слова «мюнди-баре» нет в словаре, MFA молча пишет в разметку ДВА слова; при этом 18 тысяч дефисных слов, которые в словаре есть, идут одним. Пословный сопоставитель на этом рассинхронизировался, и группа молча выбрасывалась из обучения — это была не ошибка MFA, а моя.
OOV-слова MFA выравнивает как
spn— на месте редкого слова в потоке появляется «пауза», под которой на самом деле речь. Покрытие словаря у меня 99.97%, так что класс редкий, но знать о нём надо: клипы с цифрами до фикса выпадали целиком именно так.
Алгоритм создания датасета целиком — от сырых записей до обучения:
Сбор и унификация. Все источники приводятся к единой схеме метаданных (путь, текст, спикер, длительность, метрики качества), аудио — к 24 кГц mono.
Отбор. Фильтры по DistillMOS, SNR, STOI, полосе и CER независимого ASR; дедупликация; доверенные студийные наборы — целиком.
Тексты. Пунктуация нормализуется до
.,!?; знаки переносятся из ASR-транскрипта; RUAccent расставляет ударения и восстанавливает ё (accent_text); клипы с цифрами разворачиваются RUNorm с ASR-валидацией; словарь произношений проходит аудит.Корпус для MFA. На каждый клип —
<спикер>/<id>.wavи.labс текстом изaccent_text(без+, в нижнем регистре, без пунктуации).Выравнивание.
mfa alignсо словарём espeak-IPA и собственной акустической моделью — по-клиповое, на выходе TextGrid со словами и фонемами с таймингами.Статистика. По TextGrid снимаются распределения пауз по знакам (4.5 млн стыков) и темп каждого клипа (гласные фонемы / озвученное время) — из него темпо-корзины.
Склейка групп по спикеру до 55 с: порядок записи, паузы = медиана знака × темп группы × шум (с клампами), комнатный тон из спектра тихого окна, фейды внутри тишины, −23 LUFS, 10% коротких групп, аугментации отдельными пулами.
Фичи. Выравниваются mimi-коды (16 кодбуков), фонемные последовательности из TextGrid (
silсохраняются, знаки препинания вставляются после последней фонемы слова, ударения переносятся изaccent_text), покадровые индексы фонем и duration-состояния, мульти-кроп спикер-эмбеддинги, SPS-бины. (TextGrid используются по-клиповые, до склейки: так паузы клипов остаются естественными)
Итоги по цифрам
Метрики получены на небольшом количестве аудио на незнакомых для модели спикеров:
CER (GigaAM-v3) |
Паузы (медиана) |
Ровность темпа (CV) |
Переключения голоса |
|---|---|---|---|
~0.010 |
0.4–0.5 с |
0.16 |
0–2% |
Ссылки:
Комментарии (4)

Brakanier
27.08.2026 15:45Автору спасибо! Пойду тестить.
с задержкой до первого пакета аудио ~100 мс на обычной GPU
На какой GPU замерялось?
А то обычная GPU часто оказывается h100)
n0isy
Здорово! А можно мультиязычность (ну хотя бы ru+en, чтобы ITшную речь можно было диктовать)?
monkey_llm Автор
Да, но не скоро)