RUAccent
A Python library that puts stress marks on Russian text — замок in, зам+ок or з+амок out,
decided from the sentence around it. Written by denis-petrov (GitHub Den4ikAI), MIT, 202
stars, and the first page in this wiki about the tts-front-end rather than about a model that
makes sound.
It exists because Russian orthography does not write stress and a synthesizer has to know it
anyway. Wrong stress is not an accent artifact; it is a different word, or a word that does not
exist. RUAccent sits in front of a text-to-speech model and emits text with + before each
stressed vowel, which the Russian open-weight synthesizers accept as input.
The pipeline is five models and four dictionaries
process_all() runs a sentence through, in this order. Everything neural is ONNX, run under
onnxruntime on CPU or CUDA; every checkpoint lives in the Hugging Face repo
ruaccent/accentuator and is downloaded on first
load().
- ё restoration. Russian text is written with
еwhereёis meant. A 549 KB dictionary substitutes the unambiguous cases; a DistilBERT token classifier (NO_YO/PUNCT/YO) handles the words that are ambiguous, against a 5.7 KB list of them. - Homograph disambiguation. A 219 KB dictionary says which words are ambiguous and what
their stressed variants are. For each hit the sentence is rewritten with the target wrapped in
<w>…</w>, and every variant is scored as a hypothesis by a sequence-pair classifier —(sentence, "зам+ок")→ P(true) — with the highest-scoring variant chosen. Framing stress as entailment rather than as a tagging problem is what lets one classifier serve any number of variants per word. Ten checkpoints are on offer, table below. - Stress-usage prediction. A 3-layer BERT of hidden size 312 (rubert-tiny class, 116 MB)
labels each token
STRESS/NO_STRESS/PUNCT, so clitics and monosyllables are left unmarked instead of being marked wrongly.tiny_mode=Trueskips this and marks everything. - Dictionary lookup. 21 MB of accented word forms, or a 846 KB reduced dictionary when
use_dictionary=False.custom_dict={'слово': 'сл+ово'}merges user entries over it. - Neural fallback for anything out-of-vocabulary. A character-level RoFormer token
classifier — 4 layers, hidden 128, vocabulary 45, 60 positions, 803 KB of ONNX — labels each
character and marks the one before the winning position, at a hard 0.55 score threshold. It also
predicts a
STRESS_SECONDARYclass that the caller throws away.
Outside tiny_mode a sixth stage runs: a rule engine over Ilya Koziev's rupostagger (CRF, via
python-crfsuite) and rulemma lemmatizer, both vendored into the weights repo. It resolves a
homograph by comparing the morphological tags of the sentence against the tags stored with each
accented form, scored as set overlap. So the neural homograph model and a morphological analyzer
are two answers to the same question, and both ship.
The homograph model ladder
Sizes are the ONNX files on Hugging Face; architectures are read from each checkpoint's own
config.json.
| Name | Architecture | ONNX size |
|---|---|---|
tiny |
DistilBERT | 10.5 MB |
tiny2 |
DistilBERT | 10.5 MB |
tiny2.1 |
DistilBERT | 41.5 MB |
small_poetry |
DistilBERT | 41.5 MB |
turbo |
DeBERTa, 6 layers / 768 | 328.6 MB |
turbo2 |
DeBERTa, 6 layers / 768 | 359.3 MB |
turbo3 |
DeBERTa, 6 layers / 768 | 359.3 MB |
turbo3.1 |
DeBERTa, 6 layers / 768 | 359.3 MB |
medium_poetry |
ELECTRA, 12 layers / 576 | 341.7 MB |
big_poetry |
ruBERT-base (BERT, 12 / 768) | 713.5 MB |
Two things the table shows that the README does not. The turbo line is distilled —
the checkpoints name themselves rudeberta_distilled/checkpoint-90000 and friends — which puts
this library in the same pattern as luxtts on the acoustic side: the usable artifact is a
cut-down copy of something bigger, and nobody publishes what the cut cost. And the _poetry
variants are a separate lineage trained for verse, where stress carries meter and a reader will
hear the error immediately.
The README says six models, then lists eight names; the code holds ten. medium_poetry and
small_poetry are reachable and undocumented.
What it does not publish
No accuracy number of any kind. No homograph-resolution accuracy, no held-out set, no
comparison against the rule engine it ships alongside, no per-model figure that would let anyone
choose between a 10 MB checkpoint and a 713 MB one. Ten checkpoints, one ordering implied by their
names, and no measurement — the buyer of turbo3.1 over tiny2 is trusting a version number.
That is the same absence tts-benchmarks and luxtts record on the acoustic side, and it is worse here, because stress accuracy is cheap to measure: it is a labelled classification task on a closed vocabulary of homographs, not a listening test. The dictionary of ambiguous forms shipped in the repo is itself the makings of an evaluation set.
Nothing about the training data either — what corpus the accents came from, who accented it, whether the poetry models saw copyrighted verse.
The licence says two things
The LICENSE file is MIT, "Copyright 2026 Denis Petrov", the Hugging Face card is tagged
license: mit, and the README announces the move in bold: "Мы переходим на лицензию MIT для всей
системы v1." But setup.py (version 1.5.8.3) still declares license='Apache License 2.0', and
pyproject.toml — which points its own license field at that MIT file — carries the classifier
License :: OSI Approved :: Apache Software License. Whatever PyPI shows comes from the
classifier, so the packaging metadata contradicts the file it points at.
Both are permissive and neither is restrictive, so nothing practical turns on it. It is recorded because it is the second licence discrepancy this wiki has hit in a month, after audio8-tts's Apache-vs-revenue-capped split — and unlike that one, this is a stale classifier rather than a disagreement about terms.
Running it
pip install ruaccent, then:
from ruaccent import RUAccent
accentizer = RUAccent()
accentizer.load(omograph_model_size='turbo3.1', use_dictionary=True, tiny_mode=False)
accentizer.process_all('на двери висит замок.')
load() takes device="CPU"|"CUDA" (CUDA needs onnxruntime-gpu), workdir for where weights
land, custom_homographs beside custom_dict, and tiny_mode, which drops the rule engine, the
stress-usage model and the big dictionary. The floor the author states for that mode is 512 MB
of RAM — a front-end that fits on the same class of machine as kokoro or vosk, which is
the point of having it. process_all(text, skip_regex=...) leaves matching spans untouched, for
markup or code inside the text.
One packaging gap: text_preprocessor imports razdel for sentence splitting, pyproject.toml
lists it, and requirements.txt does not — so pip install -r requirements.txt gives an
environment that cannot import the package. The published wheel is fine.
Reception
202 stars, 22 forks, 4 open issues, 55 commits on main, first pushed 2023-08-24 and last on
2026-07-17; 17 likes on the weights repo. Three years of work by one person, with no paper, no
benchmark and a donation link. Small numbers, but stress placement has an audience of exactly the
people building Russian TTS.
Correction: there is an alternative (2026-08-30)
This page previously closed by saying there is no obvious alternative to compare against. That was
an assumption, not a check, and re-reading the source on 2026-08-30 turned it up in one search:
snakers4/silero-stress— "Silero Stress — pre-trained enterprise-grade automated stress and homograph disambiguation for the Russian language." MIT, Python, 146 stars / 5 forks, created 2025-10-01, last pushed 2026-02-12 (GitHub API, 2026-08-30). Same task, same language, same licence, from Silero — the team behind the Russian TTS and VAD models, a name this wiki knows from the open-weight side.alphacep/awesome-russian-speech— a Russian speech-technology catalog, Apache-2.0, 406 stars, from Alpha Cephei, the authors of vosk. The obvious place a comparison would already be collected, and unread here.
silero-stress was ingested the same day by the quality cycle's research pass — see
silero-stress — and it publishes what this page reports RUAccent does not: F1 0.85 and 91%
per-word accuracy on ~2K homographs, plus 60–70% on unknown words. That does not make the two
comparable (different test set, no published protocol on either side), but it removes the last reason
to treat the absence here as a property of the field. What matters for this page is narrower and
firm: the comparison this page called impossible is available. RUAccent
publishes no accuracy figure and now has a same-task, same-licence competitor that can be run on the
same input, so "no measurement exists" stops being a property of the field and becomes a gap anyone
with both libraries and the shipped homograph dictionary could close in an afternoon.
Corrected 2026-10-04 (claim drain): someone has run it. The README of the
stressful library scores four accentuators on 58,605
multi-syllable words from 11,110 lines of hand-accented verse in the Russian National Corpus:
stressrnn 0.8395, ruaccent 0.9351, silero-stress 0.9629, stressful 0.9670. Two caveats keep it
from being the neutral run: stressful's author wrote the harness and tops the table, and verse is
not the prose RUAccent's 0.96/0.97 figures were measured on. The test set is not published
(copyright), so nobody can re-run it.
Retracted 2026-09-06 (claim drain). RUAccent does publish accuracy figures, in a peer-reviewed
venue this page never looked for: RUAccent: Advanced System for Stress Placement in Russian with
Homograph Resolution, COLING 2025 (ACL Anthology 2025.coling-main.444), reporting 0.96 on
homographs and 0.97 on non-homograph words. Silero Stress publishes its own side — roughly 4M
known word forms at dictionary accuracy, about 2K homographs at F1 0.85 / 91% per word / 93% over
the dataset. So both systems state numbers, and what is actually missing is narrower and more
ordinary: nobody has run them on the same test set. Each figure is its maker's, on a set the maker
chose, which is the corpus's standing complaint rather than a hole in the field. Corrected
2026-09-16 (claim drain): the COLING 2025 paper itself does run Silero on RUAccent's test set — its
comparison table gives Silero 0.952 against RUAccent 0.972 on non-homograph words, alongside
StressRNN and RUSS DeBERTa. That is one test set, chosen by one of the two makers, so the narrower
complaint survives: the only same-set comparison is the winner's, and Silero's own homograph figures
(F1 0.85 on ~2K forms) are on a different set again. Nobody neutral has run both. The growth edge
survives in that narrower form.
Recorded as the page's top growth edge rather than acted on: a route refreshes a page, it does not run a benchmark or ingest neighbours the curator did not send.
Why this page was refreshed
The URL arrived again through Telegram on 2026-08-30, three days after the first ingest. Under
the re-seen-source rule the page is refreshed in place rather than duplicated. Materially, three days
changed one star (201 → 202); forks, issues, last push and every technical fact above re-checked
identical. The first pass ran at ingest_effort: low and this one at high, which is what turned up
the correction above — the depth of that first page is not in question, but its one unverified
sentence was the one a slower pass could catch.
Related
tts-front-end · denis-petrov · text-to-speech · open-weight-tts · luxtts · tts-benchmarks · kokoro · vosk · audio8-tts · speech-audio-ai · tts-benchmarks · silero-stress