Qwen3-TTS-12Hz-1.7B для русского: ударение по знаку
Qwen3-TTS-12Hz-1.7B-Base,
дообученная слушаться знака ударения в тексте: сто́ит и стои́т, за́мок
и замо́к она читает так, как размечено. Исходная модель обучалась без разметки
ударений: знак она не понимает, а слово с ним ещё и коверкает.
Модель сделана для voicy — локального речевого сервера — и работает только для русского языка. Формат тот же, что у sknyazev/qwen3-tts-12hz-1.7b-base-gguf: GGUF и ONNX для llama.cpp и ONNX Runtime, без PyTorch и без Python.
Послушать: абзац с омографами и пары «до / после».
Как ставится знак
U+0301 (комбинируемое ударение) сразу после ударной гласной: сто́ит,
замо́к. Слова с ё и односложные не размечаются. Текст без знаков модель
читает как исходная — сама ставит ударения, где их нет.
Расставлять знаки вручную не нужно: voicy делает это сам перед синтезом —
RUAccent (MIT), перенесённый в Rust, плюс
словарь произношений проекта, запись которого главнее RUAccent. Отключить —
--no-stress или "stress": false в запросе.
Что изменилось, в числах
Замер через voicy — ровно то, что лежит здесь: говорящая часть q5_k
на llama.cpp, знаки ставит RUAccent в Rust. RTX 3080, голос turgenev.
Ударение определяет автоматический измеритель: контур громкости слова
сравнивается с эталонами Silero, где ударение поставлено на каждый слог по
очереди; проверен до использования — 10–12% ложных тревог, находит 71%
сдвинутых ударений.
| исходная | эта модель | |
|---|---|---|
| знак на ненормативном слоге: ударение там, где знак (24 фразы × все слоги × 3 сида) | 26% из 134 | 43% из 215, p = 0.0008 |
| то же у Silero с той же разметкой — предел измерителя | 66% | |
| обычный текст, 79 фраз × 2 сида: ударение не там, где у RUAccent (с поправкой на измеритель) | 14% | 12% |
| CER обратного распознавания, те же фразы | 3.6% | 4.3% (ДИ разницы −0.15…+1.65 п.п.) |
| сходство голоса с образцом (кодировщик диктора Qwen; замер в Python, bf16) | 0.985 | 0.983 |
Главное — первая строка: исходная модель знак не понимает (26% — почти случайно, а слово со знаком ещё и коверкает), эта следует ему. Квантование на это не влияет: f16 даёт 44%, q5_k — 43%. На обычном тексте разницы в пределах шума: исходная модель и так ставит верно около 85% слов, и выигрыш от знаков там меньше, чем различает измеритель. Худшие фразы по CER — с английскими терминами кириллицей («экстендс», «он делит каскад»): их ударение RUAccent угадывает (см. «Ограничения»).
Замеры в Python (bf16, адаптер отдельно) и все промежуточные варианты — в отчёте эксперимента.
Использование
С voicy — одной командой: voicy setup качает эту модель по умолчанию, дальше
voicy serve. Сервер ставит знаки, только если рядом с весами лежит
stress.json — у исходной модели его нет, и знаков она не получает.
Вне voicy файлы — обычные входы llama.cpp и ONNX Runtime, но конвейер вокруг
них нестандартный; самое короткое его описание — реализация:
rust/src/native/qwen.rs.
Файлы
| файл | что это | размер |
|---|---|---|
qwen3_tts_talker.q5_k.gguf | говорящая часть с влитым адаптером, q5_k — по умолчанию | 1.0 ГБ |
qwen3_tts_talker.q8_0.gguf | то же, q8_0 | 1.5 ГБ |
qwen3_tts_talker.f16.gguf | то же без квантования | 2.8 ГБ |
qwen3_tts_predictor.q8_0.gguf | предсказатель кодбуков — без изменений | 151 МБ |
qwen3_tts_decoder.fp16.onnx | декодер кодека — без изменений | 230 МБ |
qwen3_tts_codec_encoder.fp32.onnx (+ .data) | кодировщик образца голоса — без изменений | 226 МБ |
qwen3_tts_speaker_encoder.fp32.onnx (+ .data) | кодировщик диктора — без изменений | 48 МБ |
embeddings/ | таблицы эмбеддингов, .npy — без изменений | 866 МБ |
tokenizer.json | токенизатор модели | 11 МБ |
stress.json | метка для voicy: модель понимает знак ударения | — |
lora/adapter.safetensors, lora/adapter.json | сам адаптер LoRA — для воспроизводимости | 35 МБ |
От исходной модели отличается только говорящая часть: адаптер влит в её веса, форма и скорость те же.
Как обучалась
LoRA ранга 16 на слоях внимания и MLP основного трансформера (17.4 млн параметров, ~1% модели), одна эпоха, lr 1e-4, RTX 3080 10 ГБ. Эмбеддинги, головы и предсказатель кодбуков заморожены. Раскладка примеров — та, в какой voicy генерирует: клонирование голоса по образцу.
Данные:
- Russian LibriSpeech (OpenSLR 96, копия istupakov/russian_librispeech) — аудиокниги LibriVox, общественное достояние в США. 11.9 ч, 5 дикторов (не больше 2.5 ч на диктора), ударения размечены RUAccent.
- 3000 фраз со сдвинутыми ударениями, озвученных ESpeech-TTS-1 RL-V2 (Apache-2.0): в 70% фраз 1–3 слова уведены на другой слог, и на них знак стоит всегда. Без таких примеров знак почти всегда совпадает с привычкой модели, и учить его читать нечему.
Всё — скрипты, проверка измерителя, три варианта адаптера, в том числе неудачные, — в отчёте эксперимента; решение — в ADR 0023.
Ограничения
- Ударение — то, что даёт RUAccent, с его ошибками. На английских терминах кириллицей он ставит норму или угадывает («джене́рики» вместо «дже́нерики», «он де́лит каскад»), омограф в начале предложения («Замок…») не разбирает, а изредка ошибается и в обычных омографах. Исправляется записью словаря произношений со знаком — её voicy ставит поверх RUAccent.
- На словах с сильной привычкой модель слушается знака не всегда.
- Измеритель ударений автоматический и по одному слову шумит (10–12% ложных тревог); на слух результат проверял один человек, слепого теста не было.
- Только русский. Для других языков берите исходные веса.
Лицензия
Apache-2.0, от Qwen3-TTS-12Hz-1.7B-Base;
LICENSE приложен. Изменения относительно исходной модели: в веса говорящей
части влит адаптер LoRA, обученный на данных выше; веса переведены в GGUF и
ONNX и квантованы (говорящая часть — q5_k, предсказатель — q8_0, декодер —
fp16) скриптами HaujetZhao/Qwen3-TTS-GGUF (MIT).
Все обучающие данные — под свободными лицензиями или в общественном достоянии.
Ответственность за синтезированное — в том числе за клонирование голоса —
лежит на том, кто синтезирует.