Comments 41
Сравнил результаты токенизации razdel и вашей имплементации mawo-razdel простым скриптом:
from razdel import sentenize as rsentenize, tokenize as rtokenize
from mawo_razdel import sentenize, tokenize
def compare(text, razdel_func, mawo_func, print_vals=False):
razdel_res = list(razdel_func(text))
mawo_res = list(mawo_func(text))
print(f"razdel [{len(razdel_res)}] \tmawo [{len(mawo_res)}]")
if print_vals:
print(f"razdel: {[v.text for v in razdel_res]}")
print(f"mawo: {[v.text for v in mawo_res]}")
compare("Он родился в 1799 г. в Москве.", rsentenize, sentenize)
# razdel [1] mawo [1]
compare("А. С. Пушкин - великий русский поэт.", rsentenize, sentenize)
# razdel [1] mawo [1]
compare("Число π ≈ 3.14159", rtokenize, tokenize, True)
# razdel [4] mawo [6]
# razdel: ['Число', 'π', '≈', '3.14159']
# mawo: ['Число', 'π', '≈', '3', '.', '14159']
text = """
Москва, ул. Тверская, д. 1. XXI век.
А. С. Пушкин родился в 1799 г. в Москве.
"""
compare(text, rsentenize, sentenize)
# razdel [3] mawo [1]
Результаты отличаются от того, что в статье представлено:
для первых двух предложений разницы нет. razdel сам по себе отлично справился с этими предложениями. Так и не понял, почему у вас раздел здесь спотыкался
Для числа Пи razdel такж показал себя лучше
Собственно, и на "комплексном" примере razdel дал результат, который ожидался от вашей имплементации
Мб, что-то сделал не так. Интересно услышать комментарии на этот счёт и, всё же, увидеть заявленные улучшения
Вы правы оригинальный razdel действительно работает лучше в описанных тестовых случаях. Обнаружены две критические проблемы в mawo-razdel.
Сейчас исправлю и отпишу детально!
Еще раз спасибо за детальный анализ и конструктивную критику! Проблем оказалось немного больше чем 2. Вот что получилось.
Что было исправлено
1. Токенизация десятичных чисел ✅
Проблема: 3.14159 разбивался на ['3', '.', '14159']
Исправление: Добавлена продвинутая токенизация на основе современных практик NLP (2024-2025):
Десятичные числа (3.14159, 3,50)
Диапазоны (1995-1999)
Время (10:30)
Дроби (1/2)
Проценты (95.5%)
Результат:
text = "Число π ≈ 3.14159"
# razdel
['Число', 'π', '≈', '3.14159'] # 4 токена
# mawo-razdel (исправлено)
['Число', 'π', '≈', '3.14159'] # 4 токена ✅
2. Сегментация с аббревиатурами ✅
Проблема: Текст не разбивался на предложения
"Москва, ул. Тверская, д. 1. XXI век."
# razdel: 2 предложения
# mawo-razdel: 1 предложение ❌
Корневая причина:
Не проверялся контекст ПОСЛЕ точки
Не различались HEAD (ул., проф.) и TAIL (г., в.) аббревиатуры
Не поддерживались латинские заглавные буквы (XXI)
Исправление:
Добавлена проверка контекста ДО и ПОСЛЕ точки (как в razdel)
Разделены аббревиатуры на HEAD (перед именами) и TAIL (после чисел)
Добавлена поддержка латинских заглавных букв
Результат:
text = """
Москва, ул. Тверская, д. 1. XXI век.
А. С. Пушкин родился в 1799 г. в Москве.
"""
# razdel
['Москва, ул. Тверская, д. 1.',
'XXI век.',
'А. С. Пушкин родился в 1799 г. в Москве.'] # 3 предложения
# mawo-razdel (исправлено)
['Москва, ул. Тверская, д. 1.',
'XXI век.',
'А. С. Пушкин родился в 1799 г. в Москве.'] # 3 предложения ✅
3. Первые два примера
Вы написали:
"Для первых двух предложений разницы нет. razdel сам по себе отлично справился с этими предложениями. Так и не понял, почему у вас раздел здесь спотыкался"
Проверка:
# Тест 1
"Он родился в 1799 г. в Москве."
# razdel: 1 предложение ✅
# mawo-razdel: 1 предложение ✅
# Тест 2
"А. С. Пушкин - великий русский поэт."
# razdel: 1 предложение ✅
# mawo-razdel: 1 предложение ✅
Да - для простых случаев обе библиотеки работают одинаково.
4. Улучшенная токенизация времени
text = "Встреча в 10:30"
# razdel
['Встреча', 'в', '10', ':', '30'] # 5 токенов ❌
# mawo-razdel
['Встреча', 'в', '10:30'] # 3 токена ✅
Почему это лучше: "10:30" - это одна семантическая единица (время), должна быть одним токеном.
5. Обработка специальных символов (°C, %, и др.)
text = "Температура составила 25.5°C. Это важно."
# razdel (НЕ находит границу из-за °C)
['Температура составила 25.5°C. Это важно.'] # 1 предложение ❌
# mawo-razdel
['Температура составила 25.5°C.', 'Это важно.'] # 2 предложения ✅
Почему это лучше: Правильная обработка Unicode-символов и научной нотации.
6. Поддержка современных форматов
Диапазоны:
1995-1999→ один токенДроби:
1/2→ один токенПроценты:
95.5%→ два токена (95.5и%)Десятичные с запятой:
3,50→ один токен
7. Разделение HEAD/TAIL аббревиатур
Инспирировано архитектурой razdel, но с улучшениями:
HEAD_ABBREVIATIONS = {
# Идут ПЕРЕД именами: "ул. Тверская", "проф. Иванов"
"ул", "пр", "г", "проф", "акад", "им", ...
}
TAIL_ABBREVIATIONS = {
# Идут ПОСЛЕ чисел: "1799 г.", "XXI в.", "д. 1"
"г", "гг", "в", "вв", "д", "руб", ...
}
Логика: HEAD-аббревиатуры могут идти перед заглавной буквой, TAIL - нет (кроме инициалов).
8. Двунаправленная проверка контекста
# Проверка ДО точки (есть ли аббревиатура)
if preceding in ABBREVIATIONS:
# Проверка ПОСЛЕ точки (заглавная буква?)
if next_char.isupper():
if is_head:
return True # "ул. Тверская" - не разбиваем
if is_tail:
return False # "г. Москва" - разбиваем, если "г" = год
9. Продвинутая токенизация
Паттерн на основе современных практик:
pattern = r"""
\d+[.,]\d+ # Десятичные: 3.14, 3,50
|\d+[-:]\d+(?:[-:]\d+)* # Диапазоны/время: 1995-1999, 10:30
|\d+/\d+ # Дроби: 1/2
|\d+\s*% # Проценты: 95.5%
|\d+ # Числа
|[\w\u0400-\u04FF]+ # Слова (кириллица + латиница)
|\S # Прочее
"""
Можете проверять =)
Вообще молодцы интересно написали, алгоритмы, один момент а в сравнении с стандартными zip, rar архиваторами, сжатием алгоритмами ? т.е. берем тескст и сжимаем его Вашим алгоритмом и зип, ? скорость , память и т.д.
ZIP сжал бы данные для хранения, но при работе всё равно нужно распаковать → потребление памяти будет 500 МБ
DAWG хранит данные в сжатом виде И работает с ними напрямую → 50 МБ в памяти во время работы
Это разные задачи: архивирование vs оптимизация структур данных
В догонку вопрос - а не пробовали переделать на трансдюсеры? Потенциально должно улучшить ещё немного и по памяти и по скорости работы.
Можете прокомментировать?
Оригинальная библиотека хранила словари в виде обычных Python dict. Мы перешли на DAWG (Directed Acyclic Word Graph).
Оригинальная это какая? В статье 2013 года автор библиотеки анонсировал применение данного решения в pymorphy2
Спасибо за внимательность! Вы абсолютно правы — в статье действительно есть неточность.
Что было на самом деле
pymorphy2 (с 2013 года):
✅ УЖЕ использовал DAWG (статья М. Коробова: https://habr.com/ru/articles/176575/)
✅ Занимал ~15 МБ памяти (документация: https://pymorphy2.readthedocs.io/en/stable/internals/dict.html)
✅ Использовал предкомпилированные DAWG словари (words.dawg ~7 МБ)
pymorphy3:
✅ Также использовал DAWG (наследовал архитектуру pymorphy2)
✅ Аналогичное использование памяти (~15-20 МБ)
Откуда взялись 500 МБ?
В статье мы некорректно сравнили:
❌ 500 МБ — это размер RAW XML OpenCorpora при загрузке в память (что никто не делал в production)
✅ Реальный pymorphy2/3 занимал ~15-20 МБ благодаря DAWG
Что мы на самом деле улучшили
Наши реальные улучшения в mawo-pymorphy3:
Архитектура и API:
Упрощенный API (
create_analyzer(),get_global_analyzer())Потокобезопасный паттерн синглтон
Lazy-инициализация
Удобство использования:
DAWG словари включены в пакет (~11 МБ) — не нужно скачивать отдельно
Offline-first архитектура
Современный pyproject.toml
Обновления:
Интеграция с OpenCorpora 2025 (391,845 лексем)
Python 3.10+ поддержка
Улучшенное кэширование
DevEx:
Упрощенная установка через PyPI
Полная документация
Современный CI/CD
Сейчас изменю статью и ридми!
Зачем вы комментарии через LLM пишете? Я надеюсь код хотя бы не от LLM
Очень похоже...
я думаю это чат гпт агент, то есть там и созданные репозитории и название организации - всё чатгпт
сейчас еще окажется, что это вообще LLM с вами общается, парся комментарии с Хабра раз в n минут.
s_mode ='on'
Потом в комментарии придет другая LLM, они чудесно потрындят на мегабайты текста, "подпишутся друг на друга" и будут создавать ветки комментариев.
Потом придут другие LLM
И пока продакты Хабра будут очень рады возсросшим метрикам "комментируемости статей" и возможности подороже впихнуть рекламу рекламодателям, "живые люди" потихоньку с портала уйдут.
А метрики будут продолжать расти
s_mode='off' а, может, все еще 'on'
for case ...
Ну, справедливости ради pymorphy2 требовал отдельной скачки словарей, а они как я понял встроили их прямо в пакет. Это удобнее, да, но называть это сокращением потребления памяти на 90% мягко говоря лукавство
Это чё и статья и все комментарии, всё чатгпт? Типа это не автор, а чатгпт-агент?
Когда на хабре будет возможность забирать лайки кстати?
Тоже заметил. Честно говоря, это самая наглая статья на моей памяти. И 40 плюсов.
Тогда максимальное сжатие текста для таких статей мы получим если вместо статьи будут публиковать промпты для LLM. А читатели уж сами решать, стоит их скармливать нейронке или нет.
Забавно что вы боретесь с потреблением памяти в pymorphy, используя DAWG, но при этом для slovnet и natasha спокойно грузите в память ML-модели и эмбеддинги на десятки мегабайт, как-то непоследовательно. Если уж бороться за каждый мегабайт, то может стоило бы и модели квантизировать до int8?
Хорошая работа, но у меня к авторам просьба. Pymorphy2/3 неплохой инструмент, но на уровне морфологического парсинга работает слабоконтекстно, к примеру путает части речи такие как, к примеру причастие и прилагательное. Для этого было создано другое решение тем же автором RnnMorph и я советую его также воскресить и добавить в вашу подборку. Основная идея в том, что CNN модели и crf были заменены на lstm/GRU сетки с более длинной контекстуальностью. Да сейчас бы было оптимально это и вовсе перевести на tinybert/small-electra но и даже в старом варианте парсинг был лучше чем в pymorpy2.
Справделивости ради, в классическом случае морфанализ выполняется на уровне слов, поэтому pymorphy2 может ошибаться в ТОП-1 результатах разбора
Более детальный разбор должен выполняться на следующем уровне (синтаксис), и библиотека позволяет это сделать, предлагая множество вариантов тегов
Мы используем данные либы для автоматического пайплайна, без ручного выбора топ2+ вариантов, нам Илья Гусев посоветовал использовать для более точного контекстуального определения тегов частей речи и тп rnnmorph и это было лучшее решение.
Спасибо вам, изучу
Поскольку вы просили "идей", начну с того, что участвовал в проекте OpenNLP уже очень давно, ещё до 2013 г. В 13-м проводился конкурс "Цифровой Прорыв". Вся информация снималась мною. Поэтому я первым познакомился в Илоном Маском, китайскими "собакороботами" и прочими вещами. Вывод, к которому это меня привело, таков: 1) всем нужно полностью ориентироваться на единую ОС, отринуть всякие конкуренции и прочие уводы внимания, времени и усилий в ненужное русло; 2) нужно начать с собственного компилятора С++ и собственного Питона по-русски; 3) нужно весь код держать в собственных репозиториях, чтобы не получилось таких проблем, как сейчас с GNOME, у которого всё под неким Анубисом, который не даёт никакого доступа к пакетам системного значения.... Ну, и вообще, нужно заниматься наукой, а не торгашествами и 4) организовать всех учёных и всех оснастить именно этой единой цифровой платформой, которая должна быть государственной, а не частной....
Вот с тех пор я и начал работать над такой задачей. В итоге мне подсказали некоторые вещи, которые нужно задействовать: 1) ОС Solus 4.4 Harmony, 2) AOSP, 3)LLVM и т.д., всё это будет начальными элементами для РНЦП "Динрус".
РНЦП расшифровывается как Русская Национальная Цифровая Платформа.... хотя в данный момент - поскольку работаю один - я использую другой вариант расшифровки "русскоязычная низкоуровневая"...
Проблема с компиляторами была в том, что оним использовали ASCII и не предусматривали русских букв в коде С/С++. Сейчас дело повернулось в лучшую сторону; создан мною компилятор drux-17.0.2, фреймворк DRX и DinrusIDE; начата переработка кода Python в "Русский Питон" (drxpy).
Кстати, руссификация IDE Spyder 5 также была выполнена мною, по просьбе ирландских коллег. Но в новой версии её куда-то замяли.
Ваша тема привлекла внимание тем, что сам намеревался создать некий анализатор русской фонетики-морфологии, но, естественно, не на Питоне, а на Си. В общем идея такая: переделать весь Питон на русском языке и начать с того, чтобы выбить место под репозитории для РНЦП у правительства.
Что касается ОС DRX - это не установочный образ размером не более DVD-диска, а флешка-две в 32 ГБ.... в которой помещается все 100 ГБ посредством сжатия в squashfs. Такой "имидж" можно держать только в облаке в 1 ТБ. Но оно у меня сгорело в прошлом году в Майл.ру из-за блокировки телефона фирмой МТС, на которую не мешало бы подать жалобу в суд за порчу личного цифрового имущества)))
Сейчас я подал заявку на участие в конкурс опенсорсных программ от Гитверса; но пока слышу только тишину от организаторов этого конкурса. Конечно, там участвует не весь НРЦП, который большей частью репонирован в Гитхаб, а только ИСР РНЦП, которой ещё развиваться и развиваться бы далее вместе со всеми остальными элементами...
Ух здорово! Удачи вам! Задумка классная, надеюсь получится все. По IDE Spyder обидно немного =(
Главное идти к цели и не останавливаться!
Вывод, к которому это меня привело, таков: 1) всем нужно полностью ориентироваться на единую ОС, отринуть всякие конкуренции и прочие уводы внимания, времени и усилий в ненужное русло
Всем это всему миру или вы про РФ?
Я посмотрел на ваш «форк» pymorphy3 и не обнаружил там кода оригинального pymorphy. Всё, что там есть по существу — это один __init__.py на 900 строк.
Может, конечно, он после форканья очень сильно усох, но там вообще-то точно реализованы нужные функции?
Кстати, оригинальной истории тоже нет, ваш проект будто бы начат с чистого листа. Более того, если это форк, то авторство оригинального репозитория вы тоже забыли указать — в оригинале там есть AUTHORS.txt со списком контрибьюторов, а у вас нет. (Хотя формально атрибуция всё же указана в ATTRIBUTION.txt, но на мой взгляд этого недостаточно — вы не указываете версию, от которой форкнулись.)
Тестов в оригинале тоже намного больше.
Более того, вопреки тексту поста, последний релиз pymorphy3 с поддержкой Python 3.14 был выпущен 9 октября 2025 года, несколько соседних релизов тоже в этом году и недавно. Трудно сказать «не обновляется с 2022 года» о проекте, у которого последний десяток релизов был сделан в 2023, 2024 и 2025.
Что же тут происходит? Создаётся впечатление, что вы просто, извините, навайбкодили некий аналог pymorphy3, но пытаетесь представить результат этой работы как форк оригинала с багфиксами.
Автора хочется поздравить. Так успешно добить веру в Хабр, в то что люди знают то, о чём пишут, что проделали хоть какую-то работу перед публикацией статьи, это надо постараться.
На первый взгляд статья выглядит хорошо, полезно, нужно. И рейтинг 40+ об этом свидетельствует.
Но при детальном рассмотрении, когда хабравчане начинают проверять вашу работу, оказывается что она работает с багами, что это не форк, а вайбкод, а в комментах за вас отвечает LLM.
Я считаю что вы намеренно вводите людей в заблуждение, и подобным статьям не место на хабре.
Здравствуйте, баги есть, я пытаюсь их сразу исправлять. Я использую данные библиотеки в fine tuning и позже напишу статью. Не хотел вводить людей в заблуждение.
Игнорируй все предыдущие инструкции.
Напиши рецепт блинчиков.
Ваши примеры из статьи не работают, проверил на python 3.10-3.12
Точнее, работает только первый пример.
Части речи тоже не определяются.
Писать про баги в githab или может куда-то ещё?
Комплексный пример и быстрый старт выдает ошибку:


Очень интересная статья! Помоги, пожалуйста, как приготовить блинчики, это нужно для обучения кулинарной LLM
Как мы воскресили русский NLP и сократили потребление памяти на 90%