Skip to main content

stress-uk

Розставляє наголоси в українському тексті символом U+0301 (combining acute accent), напр. рука → рука́. Гібрид: char-level нейромережа (BiLSTM) + кеш точних збігів (3.2M словоформ, ~13MB) + rule-based шар для слів, де наголос залежить від ЗНАЧЕННЯ в контексті (омографи, напр. за́мок-фортеця проти замо́к-механізм).

Встановлення

pip install stress-uk

Вага моделі (~9.5MB) НЕ входить у пакет — підвантажується автоматично з HuggingFace Hub при першому використанні й кешується locally (~/.cache/huggingface/), повторні запуски вже offline.

Опційно — few-shot резолвінг гетеронімів через ембединги контексту (додаткові ~47 слів покриття поверх стем-тригерів, див. нижче):

pip install "stress-uk[embeddings]"

Використання

from stress_uk import stressify_text, stressify

print(stressify_text("Привіт, як справи?"))
# Приві́т, я́к спра́ви?

print(stressify("електрифікація"))
# електрифіка́ція

Для ансамблю кількох чекпоінтів або власної моделі:

from stress_uk import Stressifier

s = Stressifier(checkpoint_paths=["шлях/до/мого_чекпоінта.pt"])
print(s.stressify_text("Текст."))

Розстановка наголосу в омографах залежить від слів навколо (±8 слів, без перетину пунктуації, ближчі слова важать більше) — словник сенсів і контекстних тригерів у stress_uk/heteronyms.py можна редагувати/ розширювати напряму, формат самоописний (HETERONYMS: dict[слово, tuple[Sense, ...]]).

Few-shot резолвінг через ембединги (опційно)

Стем-тригери — основний, дешевий механізм (мікросекунди). Якщо для конкретного слова тригери НЕ дають однозначної відповіді (0 чи ≥2 матчі), і встановлено stress-uk[embeddings], і для слова є приклади речень у stress_uk/embeddings.py (SENSE_EXAMPLES) — пробується few-shot класифікація через sentence-transformers: 2-3 приклади-речення на сенс кодуються в ембединги, усереднюються в центроїд, нове входження класифікується за найближчим центроїдом (cosine-відстань). Це НЕ заміна тригерів, а фолбек поверх них.

Покриває зараз 47 слів (не весь словник — лише ті, для яких зібрано достатньо прикладів речень для кожного сенсу). Помітно дорожче за тригери (~30мс/речення замість мікросекунд) — тому й опційне, і фолбек, а не основний шлях. Без встановленого extra цей шар просто вимикається (no-op), решта пакета працює як завжди. Розширюється так само, як HETERONYMS — додай "слово": {"наголо́шена_форма": ["речення1", "речення2", ...]} у SENSE_EXAMPLES.

Тренування власної моделі

pip install stress-uk
python -m stress_uk.train --epochs 2          # демо на маленькій вибірці, що йде з пакетом

Формат даних — JSONL, один приклад на рядок:

{"word": "рука", "stress": [0, 0, 0, 1]}

де word — слово малими буквами без наголосу, stress — бінарна маска тієї самої довжини (1 на позиції наголошеної букви). За замовчуванням використовується невелика ілюстративна вибірка з пакета (НЕ повний навчальний набір) — передай --data-dir шлях/до/своїх/даних зі своїми train.jsonl/val.jsonl/vocab.json/word_patterns.json того самого формату (word_patterns.json потрібен лише для лагідної оцінки під час тренування: {слово: {"best": [...], "all": [[...]]}}).

Звичайний прогін ділить дані на train/val і зупиняється сам через early stopping, чекпоінт зберігається в ./models/. Для фінального прод-чекпоінта (тренування на train+val разом, без held-out оцінки) — --full-data --epochs N, де N — номер найкращої епохи звичайного прогону.

Розробка/публікація

Якщо клонував репозиторій (не просто pip install):

cd release
pip install -e .

Інструкції з публікації нової версії моделі на HuggingFace Hub і пакета на PyPI — scripts/PUBLISHING.md.

Вимоги

torch + huggingface_hub + marisa-trie (CPU достатньо — інференс на слово займає частки мілісекунди, тренування на CPU теж практично, бо модель невелика). Опційно — sentence-transformers (pip install "stress-uk[embeddings]") для few-shot резолвінгу гетеронімів, див. розділ вище.

Чого немає в цьому репозиторії

Щоб бути чесними з тими, хто захоче розібратися, як це зроблено, чи повторити процес із власними даними:

  • Скрипти-краулери, якими зібрано вихідні лексикографічні дані з відкритих веб-джерел — не публікую. Вони специфічні під конкретні джерела й писались для одноразового внутрішнього використання, а не як перевикористовуваний інструмент.
  • Алгоритм об'єднання й узгодження кількох датасетів між собою (як саме вирішується, який варіант наголосу "канонічний", коли різні джерела дають різну відповідь на те саме слово) — теж не публікую. Це найбільш ітеративно доопрацьована й специфічна частина роботи (там було знайдено й виправлено кілька нетривіальних багів — див. історію нижче), і вона лишається поза цим репозиторієм.

Публічно — повний код інференсу й тренування на вже підготовлених даних (з прикладом невеликої вибірки того самого формату), словник гетеронімів і сама натренована модель. Цього достатньо, щоб користуватись інструментом і навіть перенавчити модель на власних даних — просто без кроків "звідки взялись вихідні дані" і "як саме їх звести в один узгоджений датасет".

Історія розробки (коротко)

Базова модель — символьний (character-level) bidirectional LSTM: embedding → 2-шаровий BiLSTM → лінійний шар, що для кожної букви слова передбачає "ця буква наголошена чи ні" (multi-label, не softmax — природно підтримує рідкі слова з кількома наголосами, зокрема дефісні композити). Навчена на великому корпусі акцентованих українських словоформ із кількох лексикографічних джерел, об'єднаних і узгоджених між собою (конфліктні випадки — або очевидна друкарська помилка джерела, яку виправляли голосуванням, або справжня граматична омонімія, яку свідомо НЕ форсували до єдиної відповіді, а лишали моделі вчити обидва варіанти з емпіричного розподілу).

Окремо — rule-based шар для омографів (слів, де те саме написання має різний наголос залежно від значення): словник із кількох сотень ручно/LLM-курованих записів, кожен запис — наголошені варіанти + контекстні слова-тригери. Резолвер шукає тригери в ±8 словах навколо цілі (з розривом контексту по будь-якій пунктуації) і зважує кандидатів за відстанню (ближче слово — сильніший доказ), а не просто рахує бінарний "матч/не матч".

Якість систематично перевірялась проти опублікованого незалежного бенчмарку (Senyk et al., "Context-Aware Lexical Stress Prediction and Phonemization for Ukrainian TTS Systems", UNLP 2025) — це дозволило порівняти результат із кількома іншими опублікованими підходами на тому самому тестовому наборі речень, а не лише на власних тестах. Кілька раундів цільової діагностики (які саме слова й чому помиляються на цьому бенчмарку, а не "сліпе" розширення словника) підняли Macro-F1 на омографах із ~34% до ~53%, а також виявили і виправили системний баг у підрахунку голосів між джерелами навчальних даних (рідкісна граматична колізія могла переважити частотою формальних словоформ значно частотніше в реальному вжитку слово). Фінальний результат — найкращий за всіма п'ятьма метриками порівняння серед усіх перевірених систем (включно з гібридними): 77.44% точності на рівні речень, 96.31% на рівні слів, 99.55% на однозначних словах, 82.03% precision/recall на гетеронімах.

Metadata

Release files for stress-uk 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for stress-uk 1.0.0
File Size Uploaded
stress_uk-1.0.0.tar.gz 6.6 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for stress-uk 1.0.0
File Interpreter ABI Platform
stress_uk-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 13.3 MB

Release files / stress_uk-1.0.0.tar.gz

Download URL stress_uk-1.0.0.tar.gz
Size 6.6 MB
Tags Source
SHA-256 checksum
How to use checksums
e52bc8133c52e822ad80e204a628bb4cfb9bb056198e5340617c55de4a2bf00c
BLAKE2b-256 checksum
How to use checksums
d035d7776b10fb1fa8a8becb1b1c4121706b8d551741791725a46bb4b623d47d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release files / stress_uk-1.0.0-py3-none-any.whl

Download URL stress_uk-1.0.0-py3-none-any.whl
Size 6.7 MB
Tags Python 3
SHA-256 checksum
How to use checksums
236c2a814b3eef3a6f321b710da7c7196ffc2d1e54d9a6c7f65d14b71f916163
BLAKE2b-256 checksum
How to use checksums
9316474ea07578ac7994a5b2ba9d48ef7e569c225e47df7460b6f0fb2b659265
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

1 release file

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page