Посимвольная нейросетевая модель для автоматической акцентуации русского языка

Привет Хабр, решил поделиться небольшой моделью для расстановки ударений, которую обучил на датасете, из более 400 книг художественной прозы с лицензией MIT.

О чём речь

Разрабатывая систему синтеза речи на базе Silero TTS, столкнулся с проблемой: минимальные ошибки в расстановке ударений всего два процента из 100 приводят к ошибкам в каждом из 5-6 предложений. Для аудиокниг это критично, так процесс "выслушивания" и правки книги на 10000 предожений потребует не менее 10 часов ручного времени.

Сделал свою модель с фокусом на точность в хужожественных книгах. Получилось 99.7% на валидационном датасете. Упаковал в pip-пакет ruaccent-predictor.

Что умеет:

pip install ruaccent-predictor
ruaccent "мама мыла раму"
# → ма'ма мы'ла ра'му

Код и модель на GitHub, лицензия MIT.

Почему не достаточно Silero stress?

Silero-Stress — классная модель. Быстрая, бесплатная, для большинства задач достаточно точная.

Но:

Что важно

Silero

ruaccent-predictor

Точность

~98%

>99%

10k предложений

2-3 мин

~60 мин

Ошибок на 10k

~200

~30

Вес модели акцентора

50 Mb

30 Mb

Моя ниша: когда точность важнее скорости. Подготовка аудиокниг, учебные материалы, эталонные датасеты.

Silero-stress остаётся королём для real-time. Моя модель — для создателей аудиокниг.

Как это работает

Character-level подход

Вместо работы со словами обучил модель на символах. Почему:

Два формата вывода

# Апостроф после гласной (для чтения)
"В лесу' родила'сь ёлочка"

# Плюс перед гласной (для Silero TTS)
"В лес+у род+илась ёлочка"

Модель обучалась на апострофах, но я добавил автоконвертацию в формат Silero. Получился универсальный инструмент.

Архитектура

Transformer Encoder-Decoder
├─ 4 слоя encoder + 4 слоя decoder
├─ 8 attention heads
├─ 256 dimensions
└─ 12.5M параметров

Для сравнения: GPT-2 имеет 117M параметров. Моя модель в 10 раз меньше. На Github выложил все коды подготовки датасета и обучения модели, словарь vocab.json для прозрачности методики обучения.

Данные: 400+ книг

Использовал датасет Accentual-Syllabic Verse in Russian Prose — 400+ художественных произведений с валидацией пар при отборе.

Обработка:

470,000+ строк
  ↓ фильтрация (заголовки, короткие, без ударений)
224,000 валидных пар
  ↓ split
202k train + 22k validation

Словарь извлекается автоматически из данных:

Главная фича: теперь это pip-пакет

pip install ruaccent-predictor
ruaccent "привет мир"

Что сделал:

1. Упаковал в PyPI

2. Добавил CLI

# Быстрая проверка
ruaccent "текст для проверки"

# Файл целиком
ruaccent -i book.txt -o result.txt

# Формат для Silero
ruaccent --format synthesis "привет"

# Через pipe
cat file.txt | ruaccent

3. Простой Python API

from ruaccent import load_accentor

accentor = load_accentor()

# Одно предложение
result = accentor("привет мир")

# Batch обработка (быстрее)
results = accentor(texts, batch_size=8)

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

Умное кэширование

Повторяющиеся фразы ("сказал он", "ответила она") кэшируются:

accentor("привет мир")  # ~0.5 сек
accentor("привет мир")  # ~0.0001 сек (из кэша!)

На практике экономит ~30% времени при обработке книг.

Batch-обработка

# Медленно
for text in texts:
    result = accentor(text)

# Быстро (в 4 раза)
results = accentor(texts, batch_size=8)

Бенчмарки (Mac Mini M4):

Batch Size

Скорость

1

2.5 предл/сек

8

10.1 предл/сек

32

8.7 предл/сек

Оптимум — batch_size=8.

Поддержка железа

accentor = load_accentor(device='auto')
# → CUDA (NVIDIA GPU)
# → MPS (Apple Silicon)
# → CPU (fallback)

Точность: 99.7%

На валидации (22,000 предложений):

Важные ограничения

"Он подошел" → "Он подоше'л" (не "подошёл")
"ёлка" → "ёлка" (ё всегда ударная)
"я иду" → "я иду'" (не "я' иду'")

Примеры использования

CLI для быстрых задач

# Проверка
$ ruaccent "замок на замке"
за'мок на за'мке

# Файл
$ ruaccent -i book.txt -o book_accented.txt
Processing 254 lines... Done in 42s

# Формат Silero
$ ruaccent --format synthesis "привет"
прив+ет

Python для интеграции

from ruaccent import load_accentor

accentor = load_accentor()

# Простой случай
text = "Мама мыла раму."
print(accentor(text))
# → Ма'ма мы'ла ра'му.

# Batch
texts = ["первое", "второе", "третье"]
results = accentor(texts, batch_size=8)

# Оба формата
apostrophe, synthesis = accentor(text, format='both')

Интеграция с Silero TTS

from ruaccent import load_accentor
import torch

accentor = load_accentor()

# Загрузка Silero
model, _ = torch.hub.load(
     repo_or_dir='snakers4/silero-models',
     model='silero_tts',
     language='ru',
     speaker='v5_cis_base'    
)

# Подготовка текста
text = "Мама мыла раму."
accented = accentor(text, format='synthesis')

# Синтез
audio = model.apply_tts(text=accented, speaker='ru_eduard')

Кому это подойдёт

✅ Используйте ruaccent-predictor если:

❌ Используйте Silero-stress если:

Планы развития

Ближайшее:

Среднесрочное:

Попробуйте

pip install ruaccent-predictor
ruaccent "ваш текст здесь"

Полезные ссылки:

Обратная связь:

Итого

Модель ruaccent-predictor — инструмент для точной расстановки ударений:

>99% точности — меньше ошибок чем у аналогов на художественных текстах
Один pip install — работает из коробки
Два формата — для чтения и TTS
Открытый код — MIT, используйте как хотите

Не заменяет Silero в real-time, но хорош для оффлайн работы. В настоящий момент мой пайплайн включает комбинированную обработку silero-stress и ruaccent-predictor.

Попробуйте и поделитесь опытом в комментариях!

Вопросы к сообществу:

  1. Используете ли модели для расстановки ударений? Какие?

  2. Какая точность достаточна для ваших задач?

  3. Какие фичи были бы полезны?

@Kubataba
05.02.2026 02:46 UTC
Первоисточник

Комментарии

@MaxAkaAltmer
04.02.2026 23:02 UTC
+1

"В лесу' родила'сь ёлочка"

Тут уже ошибка, должно быть роди'лась, по крайней мере, мы именно так всегда в детском саду пели.

@Kubataba
05.02.2026 01:00 UTC
+1

Добрый вечер, спасибо за комментарий -

✅ Accentor initialized successfully!

В лесу' родила'сь ёлочка

Ваш вариант ударения относиться к ограничению модели -

  • Авторская метрика vs обычное произношение

Если вы поставите ударение в предложении - Моя дочь родилась в Москве - вы услышите что в обычном произношении правильно родила'сь

@debagger
05.02.2026 03:46 UTC
+1

Ударения могут зависеть от контекста. Если "точность важнее скорости", то можно в LLM текст загнать. И то, chatGPT в примерах ниже, правильно расставил ударения только с включенными рассуждениями:

Я в Москве' родила'сь,
Э'то моя' ипо'стась.

Но

Я в Москве' роди'лась,
Тут и пригоди'лась.

05.02.2026 07:09 UTC
0

Эту же модель можно попробовать дообучить и на поэзии - вопрос нужен хороший датасет. Что касается LLM - это долго и дорого - символьная модель запускается локально и работает относительно быстро.

05.02.2026 13:42 UTC
0

Так в "ипостась" тоже неправильно указано. Более того, вся рифма рушится.

05.02.2026 13:59 UTC
0

модель ставит обычное произношение в этой фразе корректно

📖 Loading vocabulary from /opt/homebrew/lib/python3.11/site-packages/ruaccent/model/vocab.json...

   Vocabulary size: 224

🤖 Initializing model...

📦 Loading weights from /opt/homebrew/lib/python3.11/site-packages/ruaccent/model/acc_model.pt...

✅ Accentor initialized successfully!

Э'то моя' ипоста'сь

06.02.2026 00:33 UTC
0

Да, вы правы, не обратил внимание на это, когда писал комментарий.
Я поэкспериментировал с разными LLM и все они ошибаются на этой задаче. Даже если и была правильная выдача, то при повторной генерации появлялись ошибки.

@titulusdesiderio
05.02.2026 06:11 UTC
0

Справится ли оно с билингвальным текстом?

"Залей этот commit в ветку."

@Kubataba
05.02.2026 07:10 UTC
0

Модель понимает и русские и аншлийские символы

@Kubataba
05.02.2026 08:57 UTC
+1

📖 Loading vocabulary from model/vocab.json...

   Vocabulary size: 224

🤖 Initializing model...

📦 Loading weights from model/acc_model.pt...

✅ Accentor initialized successfully!


Зале'й э'тот commit в ве'тку.

@awoland
05.02.2026 06:43 UTC
0

Windows 11 Pro 25H2 26200.7623
Python 3.13.7
FileNotFoundError: Model file not found: model/acc_model.pt

@Kubataba
05.02.2026 08:12 UTC
0

Добрый день, нашел баг с относительными путями в коде - сейчас обновлю

@Kubataba
05.02.2026 11:30 UTC
0

Обновил версию 1.2.0 перенес файлы модели в папку акцентора и теперь модель корректно скачивается с пакетом. Обновите командой pip install ruaccent-predictor --upgrade или pip uninstall ruaccent-predictor и потом обновите pip install ruaccent-predictor==1.2.0

05.02.2026 12:26 UTC
0

Да, теперь всё замечательно. Большое спасибо за оперативность и за потраченный труд в целом. Весьма полезный проект.

05.02.2026 12:49 UTC
0

Спасибо за оценку, вчера поздно выгружал и упустил, но вы помогли быстро устранить ошибку.

@Sontref
05.02.2026 06:56 UTC
+1

400+ художественных произведений с ручной разметкой ударений

А это точно так? В карточке датасета написано, что они размечали его с помощью этой тулзы, которая в свою очередь на russtress основана. Мы когда-то тестили russtress, было так себе.

Если валидация из этого же сета взята, то вполне может быть, что метрики не совсем реальность отражают.

@Kubataba
05.02.2026 09:13 UTC
0

Убрал из статьи упоминание о ручной разметки - валидировал отобранные пары, но не вручную, а перепроверяя через silero stress при фильтрации

@Kubataba
05.02.2026 12:17 UTC
0

Прогнал "стресс-тест" на 50 уникальных предложениях, чтобы обойти кэширование и проверить именно чистую работу нейросети на посимвольном анализе. Результаты ниже:

  1. Морфологическая интуиция: Тест на "Глокой куздре" пройден корректно. Модель верно расставила ударения в несуществующих словах (Гло'кая куздра' штеко' будла'нула), что подтверждает к обобщающую способность.

  2. Устойчивость к "грязным" данным: Опечатки в словах и смешанный регистр (мгази'нзАбО'рЧиКоМ) не сбивают модель — она корректно восстанавливает позицию ударения по контексту символов.

  3. Омографы: Порадовало разрешение омографа в связке мо'лол муку'. Контекст "мельницы" считан верно.

  4. Производительность: Без кэша на MPS около 440 симв/сек (в среднем 98 мс на фразу). Для посимвольной модели потребуется около 30 минут на книгу.

Лог тестов прилагаю:

text

============================================================
Loading Custom Accentor
============================================================
✅ Using Apple MPS (Metal)
📖 Loading vocabulary from /opt/homebrew/lib/python3.11/site-packages/ruaccent/model/vocab.json...
   Vocabulary size: 224
🤖 Initializing model...
📦 Loading weights from /opt/homebrew/lib/python3.11/site-packages/ruaccent/model/acc_model.pt...
✅ Accentor initialized successfully!

🚀 Запуск теста на 50 УНИКАЛЬНЫХ предложениях (без кэша)...
============================================================
⏱  Чистое время обработки: 4.8993 сек
📊 Среднее на фразу: 97.99 мс
🚀 Скорость: 439 симв/сек
============================================================
-> Вчра я пошл в мгази'н за вксуны'м кфе.
-> Прграмми'ст нписа'л кд на я'зке Питн.
-> Тэо'Т тЕкст НаПиСа'н зАбО'рЧиКоМ дЛя ПровЕ'рКи.
-> Шла Са'ша по шоссе' и соса'ла су'шку.
-> The quick bron fox jumps ove ver the lazy dog.
-> Устано'вка Xindoms заверши'лась с крити'ческой оши'бкой 0x0001.
-> Ква'нтовая суперпози'ция электро'на в а'томе водоро'да.
-> Архите'ктор Растре'лли спроекти'ровал Зи'мний дворе'ц.
-> В антаркти'де пингви'ны гре'ются друг о дру'га.
-> Синхрофазотро'н испо'льзуется для ускоре'ния элемента'рных ча'стиц.
-> Ма'ма мыла' ра'му чи'стым мы'лом до'лго.
-> Гло'кая куздра' штеко' будла'нула бокра'.
-> Битко'ин и эфи'риум обвали'лись на криптоби'рже.
-> Ста'рый ме'льник мо'лол му'ку на ме'льнице.
-> Ю'ный натура'лист изуча'л пова'дки ди'ких живо'тных.
12.08.2026 08:25 UTC
0

Всегда считал, что
Гло'кая ку'здра ште'ко будлану'ла

@Kubataba
05.02.2026 09:06 UTC
+1

К сожалению какой датасет был такой и использован, по мере озвучки книг и исправления ошибок буду обновлять датасет парами с ручной разметкой и переобучать при необходимости. Попытаюсь еще валидировать разными акценторами отобранный датасет.