
Мы писали на Хабре про нашу быструю и качественную библиотеку для простановки ударений и разрешения омографов на русском языке. Потом к ней доехали ещё модели-акценторы для белорусского и украинского языков и словари ещё для 17 языков.
В этот раз у нас получилось очередное приключение на 20 минут. Изначально мы не планировали делать прямо большой релиз, но как обычно одно потянуло за собой другое, в процессе мы нашли много новых источников данных и получился прямо полноценный релиз:
Добавилась поддержка ещё около 395 слов-омографов;
В старом списке было омографов 1 924 слова, мы добавили 395 новых слов и убрали 111 старых слов. В итоге получается 1924 + 395 - 111 = 2 208 омографов. Полный список тут;
Мы в очередной раз пересобрали весь список омографов и отправили часть "токсичных" омографов в категорию "всегда ставить только более популярное ударение";
Мы вручную разметили огромный (около 100 тысяч новых предложений для около 5 000 омографов) валидационный сет с тройным перекрытием для независимой проверки качества моделей и качества списка омографов;
Мы добавили в обучающую выборку порядка 54М новых предложений (общий размер трейна достиг порядка 195М из разных типов источников, в этот раз данные ещё более качественные);
У весьма большого количества предложений в трейне сменилась метка, порядка 8М;
Мы решили проблему с "дрожанием" результатов модели при добавлении или убирании лишних знаков препинания;
Мы сняли подробные метрики как на старых датасетах, так и на новом "идеальном" ручном датасете для реального масштабного теста моделей;
Мы добавили регулярные выражения и словосочетания для самых популярных омографов и добавили функционал для пользователей для добавления собственных регулярных выражений и словосочетаний.
Оглавление
Итак, пойдём по порядку.
Как использовать
Для новых пользователей, все примеры использования описаны в документации тут и тут.
Приведём пару минималистичных примеров использования:
# pip install silero-stress from silero_stress import load_accentor accentor = load_accentor() # запускаем на CPU (поведение по умолчанию) accentor.to(device='cpu') # запускаем на GPU accentor.to(device='cuda:0') sample_sent = "Меня зовут Лева Королев. Я из готов. И я уже готов открыть все ваши замки любой сложности!" print(accentor(sample_sent)) # Мен+я зов+ут Л+ёва Корол+ёв. +Я +из г+отов. +И +я уж+е гот+ов откр+ыть вс+е в+аши замк+и люб+ой сл+ожности!
# using torch.hub import torch torch.set_num_threads(1) accentor = torch.hub.load(repo_or_dir='snakers4/silero-stress', model='silero_stress') sample_sent = "Меня зовут Лева Королев. Я из готов. И я уже готов открыть все ваши замки любой сложности!" print(accentor(sample_sent))
sample_sent = 'Моя мать, моя посуду, рассказала о нем, что он нем. Ну... Г+оворить не умеет. И с этого момента все завертелось, и все завертелись. А елка моей сестры засияла!' print(accentor(sample_sent, put_stress=False)) # Мо+я мать, м+оя посуду, рассказала о н+ём, что он н+ем. Ну... Г+оворить не умеет. И с этого момента вс+ё завертелось, и вс+ё завертелись. А ёлка моей сестр+ы засияла! print(accentor(sample_sent, put_yo=False)) # Мо+я мать, м+оя посуду, рассказала о н+ём, что он н+ем. Ну... Г+оворить не умеет. И с этого момента вс+ё завертелось, и вс+ё завертелись. А ёлка моей сестр+ы засияла! print(accentor(sample_sent, put_stress_homo=False)) # Моя м+ать, моя пос+уду, рассказ+ала +о нём, чт+о +он н+ем. Н+у... Г+оворить н+е ум+еет. +И с +этого мом+ента всё заверт+елось, +и всё заверт+елись. +А +ёлка мо+ей сестры заси+яла! print(accentor(sample_sent, put_yo_homo=False)) # Мо+я м+ать, м+оя пос+уду, рассказ+ала +о н+ем, чт+о +он н+ем. Н+у... Г+оворить н+е ум+еет. +И с +этого мом+ента вс+е заверт+елось, +и вс+е заверт+елись. +А +ёлка мо+ей сестр+ы заси+яла! print(accentor(sample_sent, stress_single_vowel=False)) # Мо+я мать, м+оя пос+уду, рассказ+ала о нём, что он нем. Ну... Г+оворить не ум+еет. И с +этого мом+ента всё заверт+елось, и всё заверт+елись. А +ёлка мо+ей сестр+ы заси+яла!
Не вспомню в какой версии мы добавили подробные флаги. По умолчанию все флаги выставлены на True:
put_stress: bool- вкл/выкл простановку ударений в словах, не являющихся омографами;put_yo: bool- вкл/выкл простановку буквыёв словах, не являющихся омографами;put_stress_homo: bool- вкл/выкл простановку ударений в омографах;put_yo_homo: bool- вкл/выкл простановку буквыёв омографах;stress_single_vowel- вкл/выкл простановку ударений в словах всего с одной гласной;words_to_ignore- список слов, которые нужно полностью игнорировать при расстановке ударений/ё.
Новые омографы

Тут всё просто, всего у нас вышло добавить около 395 омографов, на которые мы смогли найти порядка 10М новых обучающих предложений. Вот полный список совсем новых омографов:
Полный список новых омографов
равно, статью, кости, осени, коробку, оси, подвиг, воротам, спешил, хором, скобы, складные, спешит, сизо, сковороды, повода, волокна, стоим, установите, короба, сучка, пропустите, хлопка, спешили, болей, крупы, пушка, чека, седла, парку, проводки, брони, складной, относитесь, чеки, руды, бензопилы, скачки, смолы, заморозки, погоню, честной, побеги, трусах, балу, сопли, торопитесь, гвоздики, блесны, колонок, учитесь, аминокислоты, ухе, проводка, козлы, стоите, кладу, страстная, спешим, тельце, срезать, подвижной, нападавших, подвижного, простыней, вводите, стрелке, стрелку, предложите, проходим, сосок, парком, сует, остроты, дружку, извести, гвоздика, джемпера, коробках, цените, стоящему, сходите, уколов, подвижных, исправим, качка, чеке, складная, молитесь, попадала, нападали, бору, десны, чеку, валу, милей, страстное, гряды, конуса, ведомый, дружки, учите, скорлупы, стрелками, скверны, геном, заморозка, упустите, железу, срезал, борозды, страстных, страстного, печенью, дружке, пятками, коробками, колы, жиру, хлопком, паря, пробегали, иванове, нападал, стоящими, зажили, урезать, насыпать, сложите, ведомые, восемью, признаете, скачках, пробегал, сердитесь, сучку, попадало, страстном, тащите, носке, подвижным, страстную, нападавший, заду, поживу, крестной, комбикорма, шлепки, скачками, носка, соску, раскроя, трусами, служите, меху, раскрою, срезали, терема, гребли, стоящем, калмыков, заморозке, маркера, смените, проводок, пятка, заправил, терпим, врезалось, развернут, уложите, врезаться, пробегала, семенам, замковый, терпите, ведомая, лихом, сердит, волок, рапорта, электропоезда, культе, хули, стек, складных, отпуску, промокнуть, сопоставим, рытье, забегать, хвалите, ведомым, задвигались, разложите, юнкера, ведомого, коробочек, вороха, утопали, проводке, утопал, бронепоезда, повернут, смычки, писаря, удали, хлева, туше, парю, зажил, забегает, стогу, тельцу, гвоздику, стрелкам, спуститесь, косят, сознаюсь, газам, фраера, срезала, гвоздиками, дедка, хромом, ведомой, сознается, кинозвезды, перевернут, трусил, ведомых, смычка, крестных, заправила, складное, свернут, скачке, треску, обитая, скачку, сучке, досыпать, нападала, зажило, казачки, ровней, ростовой, клешней, дельца, утопала, ростовых, подвижную, сползал, рассыпавшиеся, переборов, коробкам, скверна, врежу, бабья, задвигался, заезжая, осыпь, трусить, графах, закуси, власа, соске, подвижном, пробегать, веретена, уступите, складным, явитесь, складного, баском, задвигал, вязанки, опознают, ссыпал, почесть, забегают, простою, снохи, сучками, стрелках, ездок, блекло, бойком, задвигалась, затыкают, складную, страстному, стону, заморозками, подвигаться, терему, признаетесь, осмотритесь, ведомое, бельма, гвоздике, схватите, пробегаю, путаной, уводите, трусам, осыпалось, спустите, поручи, проводками, трусила, расспросите, хлопке, лебеде, засеки, подвижному, складном, мороси, хороните, недалеки, нападало, уносите, треске, замковым, графам, складными, степенная, трусили, рассыпавшихся, застегнут, ведомыми, недалека, крестными, удержите, заползали, лихача, согнут, уроните, ведомому, графами, изогнут, сознаются, ссыпали, травите, набегу, градской, устою, гумна, степенного, носку, надоев, осыпало, измерим, загнут, поводами, ведомом, ссыпать, подвигался, подвигалась, хлопку, отбегал, трусят, обегать, смычку, набухал, ссыпались, отбегали, уловим, жидок, задвигали, ссыпала, подвигались, засыпался, заметя, хворая, засеку, настою, рассыпавшийся, сознаешься, возки, дельцу, сходитесь, срезался, ссыпался, перечеркнут, длинноты, засыпались, разомкнут, смычке, атласах, сознаетесь, подвигаются, поводах, запашка, запашки
Пересборка списка омографов

Напомним, что всего омографов в русском языке около 30 тысяч. Примерно 10 тысяч являются хоть сколько-то частотными и по ним реально найти хотя бы реальные предложения без разметки в товарном количестве. Из них порядка 5+ тысяч можно назвать "настоящими" омографами. Эти пять тысяч (а точнее 5,628) мы в очередной раз переразметили следующим образом:
1 924 слов-омографов было с прошлого раза;
395 совсем новых добавилось, 111 убавилось в категорию "всегда ставить одно ударение";
650 слов теоретически являются омографами, но мы не успели их решить или просеять;
2 770 слов мы просто не считаем омографами;
Омографов сейчас получается 2 208 = 1 924 + 395 - 111;
Краткие итоги разбора датасета: 5 628 = (1 924 + 395 - 111) + 650 + 2 770.
Список слов-кандидатов в омографы был довольно "грязным" (мы брали с запасом). Но реальные люди разметили порядка 100 тысяч предложений с тройным перекрытием. И так мы смогли более предметно отфильтровать эти "не-омографы". Раньше мы делали такое чисто экспертно, на глаз, что понижало точность упражнения.
Проблема тут ещё состоит в том, что некоторые омографы имеют дисбаланс в частотности условно 1-к-100 или более (и это только на основе наших данных). Яркий пример такого омографа — слово "один". Имя бога Одина встречается на много порядков реже. И тем не менее, если, например, в случае когда пользователь подаёт в модель слишком длинный и несанированный инпут (модель является тулкитом, то есть она предназначена для разбора предложений / абзацев с сохранением авторской пунктуации), то модель может сильно чаще, чем это обещают метрики, выдавать слово "Один" вместо "один", что вызывает соответствующую реакцию пользователя.
По сути в этот раз мы уже более научно подошли к этому процессу и отсматривали "подозрительные" слова уже не просто сверху вниз из пула 10 тысяч самых популярных омографов, а через призму массовой разметки данных.
Таким образом, самые яркие примеры реальных дисбалансных омографов, которым мы теперь ставим один вариант:
Омографы с дисбалансом, которым мы теперь ставим один вариант:
Какая → как+ая (
к+акая— незначительный вариант в сравнении со сверхчастотным местоимениемкак+ая);Нем → н+ём (
н+ем(от слованемой) — незначительный вариант в сравнении со сверхчастотным местоимениемнём);Кому → ком+у (
к+ому(от словакома) — незначительный вариант в сравнении со сверхчастотным местоимениемком+у).
В идеале эти слова, конечно, нужно распознавать. Но "цена ошибки" здесь оказывается крайне ощутимой, учитывая частотность вариантов. По-хорошему и легендарное "+уже / уж+е" надо в этот же список перенести, но рука не поднимается.
Люди размечали эти слова всегда одинаково — на 20 примеров всегда было одно ударение (с тройным перекрытием).
Полный список
после, лет, один, времени, тому, части, нем, кому, какая, написать, сведения, боли, написал, объем, выходит, летом, небе, неба, метод, маша, любая, отчего, попали, берет, голубой, сведений, черных, воле, органами, выходят, небом, выходя, выходил, выходили, выходила, буря, бури, выходило, выходи, ведома, сведению, курок, свежую, компас, молоке, написав, страшны, делись, бочке, орденами, чисты, курят, скрою, тенями, бункера, броска, заметите, варвар, вывозить, выносили, бостоне, врезать, бостона, бочках, какою, честны, роковым, врали, броски, вывозят, рокового, ладах, варварами, допили, чертит, галин, бухло, видениями, затыкать, дохнут, корректора, добрел, выходивших, вывозил, выходившие, остроге, выноси, вывозит, варварам, бухла, запахнет, летам, остроги, выходивший, вывозим, затыкали, роковом, роковыми, курке, роковому, заточено, затыкай, бухнуло, летами, вывозила, душки, всыпали, бочкам, вывозилось, вывозиться, варварах
Теоретически кандидаты в омографы есть ещё в следующем списке.
Теоретические кандидаты в омографы
Сюда входят слова, которым люди проставляли разные варианты ударений. В их число входят как омографы, так и просто случайные и непонятные слова. Часть этих слов попала сюда потому, что у нас просто нет данных, чтобы их решить. Часть этих слов архаичны, и скорее всего просто не имеют устойчивого ударения в современном языке.
По сути они отличаются только тем от 2 770 слов, что люди путаются в том, какое ударение в них ставить.
Скрытый текст
села, туры, тура, помните, серьги, пушки, украинский, сели, украинских, ставок, украинского, украинской, украинские, украинская, отдали, добре, шаровые, туре, договорная, маркеры, фрезы, филе, шаровой, шитье, лимиты, комплексная, корпусов, сведениям, украинским, велики, языковые, снято, стартер, шура, слесарь, украинском, корпусная, переходные, биты, складах, сметана, тракторов, ценим, чума, сынов, суете, гендиректора, скулы, украинское, сметаны, подвижные, шрифты, сковороду, тошноты, сведениями, честная, украинскими, сени, стопам, черни, семени, угольник, совки, телки, корпусные, корпусной, тете, спален, договорных, валки, снятые, слюни, шаровая, слободы, украинскую, переходной, щелей, уставного, компасы, переходного, углем, ведомо, снегов, атласы, шкалы, сома, десятью, шипов, старшины, украинскому, договорные, фили, соляной, таганке, серпуховская, хвои, стопа, долота, языковых, стеблей, хоре, комплексную, ступней, сколов, угольный, переходная, комплексном, писалось, штабов, договорной, дельце, телок, телку, средам, челюстями, корпусах, сведениях, федору, челюстей, хвоя, яру, слесаря, языкового, средах, угольных, шаровых, снялись, текстовой, компаса, хера, стержней, подвижная, фельдшера, попадаем, шевелятся, честному, сливной, ухи, фата, хану, хмеля, честную, стежка, слепоты, стволовых, уставной, соплей, сукна, маркеров, угле, комплексному, уставные, штуцера, подъездной, снастей, языковая, комплексным, девятью, треста, шутов, сини, угольная, текстового, точны, тряпье, сложена, штабы, снятое, силки, снятой, переходных, ходок, чудным, суша, туру, соляная, нажитое, сливные, храмовой, сетевом, тазу, унты, сотку, посыпалась, хлеву, ценна, слою, совка, подвижными, скудно, густоты, фату, утер, корпусами, сползать, шлепок, тощей, шрифтов, чуму, восстановим, хаджи, стежки, лимите, углями, строги, подъездные, брега, сомы, убрались, угольного, чаду, посыпался, штормов, нищая, широки, уставных, стебле, планер, шулера, штабеля, смиренный, написавший, сливного, компасом, удались, урезали, сложено, подъездных, ярки, чуме, снятую, снятого, спирту, абдула, черен, стеблями, процедите, старье, снятая, хмельного, черпал, уда, ату, фонов, нажитого, чинит, скобами, чудного, щепы, пересели, бремен, софы, серу, чудную, солями, фаты, тикали, ушка, сосенки, тесноты, слег, стопах, делец, стопами, сласти, подсели, стеблях, складами, скачи, жерла, написавших, шляху, чинят, договорное, хмелю, сосочки, суставных, чумной, переходном, тушите, скромны, шоферов, сохи, базилики, чудном, щедры, церквам, переходное, остудите, шипа, храмовых, тракторами, компасу, храмового, снеговой, лимиту, переложите, тетерева, тюков, исполним, щелях, писавший, хвою, шипом, штабах, сухи, подвижное, прозоров, тупиков, тверды, чуди, подъездную, слесарей, снятым, токаря, потеки, слюды, переходным, серьгами, серпуховской, манок, юнкеров, кроки, тенора, хмельным, корпусам, сеча, отделите, глазках, соляных, посыпалось, углям, тлей, смиренной, строчные, хмельная, чудны, церквами, снятом, узды, худом, ярка, написавшего, тащим, смочите, смотритесь, передохнув, трусит, сознают, сибирячка, сторожка, шалей, маркерами, юрок, торгу, страннее, снятыми, чудными, тракторах, подъездная, слизни, шарового, тикать, учен, забегаю, тюками, шаровую, скупы, заползает, смиренного, тощее, скудны, таганка, угольную, пристегнут, вычитается, снастями, серпуховском, тесны, щелями, уставным, писало, смиренных, угре, шабаша, языковом, храмовая, сходна, напоенный, утопать, фельдшеров, смиренные, валка, челюстях, угра, уде, колера, аги, ярма, договорным, написало, узки, мальме, затыкает, щелям, средами, страды, писавшего, чертят, строчной, штормами, угольным, чуден, пастилы, снастях, слепни, чудачка, черпала, стапелей, урезал, хмельных, щавелем, храбры, тенета, писавших, скирды, степенные, подвигает, теша, убыло, удалые, смиренное, степенной, торопите, положитесь, стержнями, шестерней, сырью, смирен, скачкам, строфах, стежку, яри, табеля, угры, сливных, соляную, отмерять, наклонитесь, токах, потушите, степе, смыкает, усыпали, сливное, угольном, утрами, смиренная, турами, нажитые, ветлы, нажитым, чугунки, запахнув, напоят, ткала, кирками, сознаем, просфоры, спились, штабами, хвалим, филей, уду, хорах, уды, сползаю, срезало, смыкал, отмеряет, шрифтами, базилику, соляным, трезвы, сторожами, серьгам, съезжая, углю, шулеров, стороже, ходка, серьгах, шевелят, штемпеля, тавра, писавшие, синею, недвижимом, сучье, приходитесь, скопа, слесарю, толстячка, степенным, наклоните, спаду, скроюсь, чугунке, смирна, снеговых, чумная, стезей, подвигается, создались, храмовым, берда, трюфелями, ушку, ските, смирны, штабелей, угольное, нажитых, глазкам, храмовом, отмеряют, сосенок, храмовое, снялось, врезавшийся, чугунка, напоим, суставного, надоем, строчных, угров, подложите, чану, смотру, степенных, бабью, заползать, штормах, заползал, уставными, отделим, фраеров, сознаешь, промокнет, напоите, подъездного, убыла, вычитаются, штабам, осыпавшейся, сеттера, смиренную, кошмы, заползают, слепленные, старей, шафера, толсты, компасов, хорами, суками, смыкали, стапелях, свежею, чудному, уставная, сторожам, шоферами, теноров, стойком, смиренном, удалых, тресты, унтах, сменен, флигелей, дельцами, дельцам, написавшая, чините, напоишь, старшинам, смыкала, хорошею, упились, скоры, сознаете, щипки, обегает, устоя, строчная, ужились, переплету, строчными, токам, смыкать, сосенке, тресту, недвижимому, воспроизводим, штемпелей, описавший, строфами, пахнувшей, смиренному, слеги, писавшим, удалым, черкал, соизмерим, удалую, нажитый, учены, фельдъегеря, пахнувшую, напоенные, флюгерами, уставному, напоенная, честною, снеговыми, подвигают, соотносим, солях, угру, написавшей, обедней, юнкерами, штемпелями, тифу, степенную, новины, фельдшерами, основною, юнкерам, роковою, степенное, писавшей, удалое, остротою, зачеркнут, сравнены, степенному, сравнен, учено
Сюда мы также внесли правки по репортам наших юзеров. Небольшое количество слов было вынесено из омографов и небольшое количество слов поменяло своё ударение в словаре (это были просто баги). Благодарим всех за репорты и предлагаем протестировать новую версию.
Решение проблемы "дрожания"

Вообще наша библиотека специально не трогает авторскую пунктуацию и не вносит своих "гениальных" представление о санации текста в текст пользователя. Мы уважаем пользователя и считаем, что его пунктуация "правильная" и "авторская".
Но это породило некоторые порочные представления у пользователей:
Что можно подавать целые главы книг в утилиту (она кушает предложение плюс небольшой контекст);
Что вообще никакая санация текста не нужна (лучше, конечно, чистить от нарочитого мусора);
Дружба это магияКак следствие, что библиотека должна быть устойчивой к любой безумной пунктуации.
Раньше мы тренировали модели в парадигме, что "что не убивает меня делает меня сильнее". Но мы перешли к парадигме аккуратной санации текста на вход по причинам описанным выше. Изменить пользователей мы не сможем, а вот обеспечить стабильность путём внутренней санации и повышения устойчивости модели — можем.
При этом интерфейс остался таким же. Мы не трогаем авторскую пунктуацию и не заставляем пользователя делать diff и ломать голову, что же наша библиотека сломала в его тексте.
Яркие примеры "дрожания":
Скрытый текст
# v1.4 # 1 sent = 'Лень самому вставать, подай пожалуйста мне чашечку чая.' print(accentor(sent)) # Л+ень самом+у встав+ать, под+ай пож+алуйста мн+е ч+ашечку ч+ая. sent = 'Лень самому вставать, подай пожалуйста мне чашечку чая!' print(accentor(sent)) # Л+ёнь самом+у встав+ать, под+ай пож+алуйста мн+е ч+ашечку ч+ая! # 2 sent = 'Все мои сестры стоят на берегу.' print(accentor(sent)) # Вс+е мо+и с+ёстры сто+ят н+а б+ерегу. sent = '<p> Все мои сестры стоят на берегу. </p>' print(accentor(sent)) # <p> Вс+ё мо+и сестр+ы сто+ят н+а б+ерегу. </p> # v1.5 # 1 sent = 'Лень самому вставать, подай пожалуйста мне чашечку чая.' print(accentor(sent)) # Л+ень самом+у встав+ать, под+ай пож+алуйста мн+е ч+ашечку ч+ая. sent = 'Лень самому вставать, подай пожалуйста мне чашечку чая!' print(accentor(sent)) # Л+ень самом+у встав+ать, под+ай пож+алуйста мн+е ч+ашечку ч+ая! # 2 sent = 'Все мои сестры стоят на берегу.' print(accentor(sent)) # Вс+е мо+и с+ёстры сто+ят н+а берег+у. sent = '<p> Все мои сестры стоят на берегу. </p>' print(accentor(sent)) # <p> Вс+е мо+и с+ёстры сто+ят н+а берег+у. </p>
Метрики наших новых и старых моделей на старых и новых датасетах

Ниже представлены метрики для наших новых и старых публичной и приватной моделей (приватная дотренируется через несколько дней, мы запиним комментарий и обновим табличку). Метрики других публичных решений (большая часть академических решений почти никогда не обновляется после первоначального релиза), насколько мы смотрели, не изменились, их можно посмотреть в оригинальной статье.
Методология метрик подробно описана тут.
Комментарий по "физическому смыслу" метрик
Total_acc — просто точность по всему валидационному датасету. То есть просто accuracy с усреднением по предложениям валидационного сета. Эта метрика — по сути просто среднее по больнице, с уклоном в сильный жёсткий дисбаланс слов и омографов. По сути она показывает некое приближение к тому, что вы будете видеть на больших корпусах текстов, но ничего не говорить про реальное качество библиотеки. Можно получить 0.85 просто всегда выставляя более популярный вариант каждому омографу.
Word_acc - та же accuracy, но сначала посчитанная для каждого слова, а потом уже усреднённая. Эта метрика по сути уже очищена от разной частотности слов в датасете. Чем больше слов в датасете, тем меньше эта метрика отличается от total_acc.
PR / RE / F1 - это просто precision / recall / F1 посчитанные для каждого омографа (у слова всегда 2 омографа-варианта) отдельно, потом усреднённые по слову, а потом уже усреднённые по всем словам. Эти метрики уже очищены ещё и от дисбаланса ВНУТРИ каждого слова. То есть они показывают "истинное" положение дел. Минус и плюс такой метрики в том, что она никак не учитывает частотность и измеряет сферические слова в вакууме.
Версия библиотеки | Набор омографов | PR / RE | F1 | Word_acc | Total_acc |
|---|---|---|---|---|---|
silero-stress-private 1.5 | 2208 | . | . | . | . |
silero-stress-private 1.5 | 2027 | . | . | . | . |
silero-stress 1.5 | 2208 | 0.86 / 0.90 | 0.86 | 0.92 | 0.93 |
silero-stress 1.5 | 2027 | 0.92 / 0.93 | 0.92 | 0.94 | 0.94 |
silero-stress 1.0 | 1924 | 0.84 / 0.9 | 0.85 | 0.92 | 0.93 |
silero-stress-private 1.0 | 1924 | 0.9 / 0.96 | 0.91 | 0.96 | 0.96 |
Наборы омографов тут следующие:
1924 — это оригинальный валидационный датасет из первой статьи;
2027 — это "идеальный" отложенный тестовый датасет, размеченный людьми с тройным перекрытием. Тут полностью отсутствует алгоритмическая и автоматическая разметка;
2208 — это новый полный датасет (он включает в себя 2027). В нём есть как и более шумные, так и "идеальные" данные.
По сути тут основные выводы такие:
Стало больше омографов;
Метрики в целом чуть подросли для новых моделей;
Метрики на старых данных как минимум не поплыли;
Новая "идеальная" валидация, собранная в "естественной среде обитания" и размеченная с тройным перекрытием, показывает ещё более высокие метрики;
Сравнение с прошлыми моделями чуть поплыло, так как набор омографов изменился, но зато появился точно "идеальный" огромный датасет (сабсет тех 100 000 предложений) в размере около 40 000 предложений размеченных с тройным перекрытием.
Гистограмма метрик по каждому офографу

Добавление своих регулярных выражений

Пока часть людей используют облачные LLM от гигакорпораций для простановки ударений или тяжелые нейросети, которые по сути не работают без GPU, мы стремимся сделать наше решение как можно более минималистичным. В этом релизе скорость нашего решения не изменилась. Метрики по скорости есть в первой статье. Наше решение продолжает успешно работать на 1 потоке процессора.
Вспоминая наше общение с пользователями, мы также решили добавить поддержку великой и ужасной технологии древних... регулярных выражений (кажется, это лучше, чем вводить 101-й специальный стандарт словаря, регулярки — более универсальный "язык"). Теперь если у вас есть какой-то словарик устойчивых выражений, вы можете добавить свои регулярки и словосочетания при использовании нашего решения следующим образом:
# загружает словарь словосочетаний accentor.homosolver.load_phrases_dict('phrases_example.json') # загружает словарь регулярок accentor.homosolver.load_regex_dict('regex_example.json')
phrases_example.json и regex_example.json
{ "замок": { "высокий замок": "з+амок", "взломать замок": "зам+ок" }, "пельмени": { "вкусные пельмени": "пельм+ени", "пельмени сырные": "пельмен+и", "проклятые пельмени сатаны": "п+ельмени" } }
{ "все": { "вс+е": [ "(\\bвс)(е|ё)\\b\\s\\b(вокруг)\\b\\s([\\S]+(лись)\\b)", "(\\bвс)(е|ё)\\b\\s\\b(до)\\b\\s\\b(одного)", "(\\bвс)(е|ё)\\b\\s\\b(её)\\b\\s([\\S]+(мые|ения)\\b)", "(\\bвс)(е|ё)\\b\\s\\b(ещё)\\b\\s(\\bи в тёмных|мели)\\b", "(\\bвс)(е|ё)\\b\\s\\b(же)\\b\\s[\\S]+(езут)\\b", "(\\bвс)(е|ё)\\b\\s\\b(как)\\b\\s(на подбор)\\b", "(\\bвс)(е|ё)\\b\\s\\b(мы)\\b\\s(после)\\b", "(\\bвс)(е|ё)\\b\\s\\b(на)\\b\\s(выход|посту\\,)" ], "вс+ё": [ "(\\bвс)е\\b\\s\\b(ж|же)\\b", "(\\bвс)е\\b\\s\\b(из за)\\b\\s\\b(той)", "(\\bвс)е\\b\\s\\b(по)\\b\\s\\b((традиции)\\b(\\.\\.\\.|\\.|\\,|\\!|\\?|\\ -|\\;))", "(\\bвс)е\\b\\s\\b(так же)\\b\\s\\b(томительно|тянулись)\\b" ] } }
При этом остальная логика работы сохраняется, а приоритеты выставлены следующим образом:
Поиск по пользовательским регулярным выражениям;
Поиск по пользовательским словосочетаниям;
Поиск по "встроенным" словосочетаниям;
Если ничего так и не нашлось, отправляем в нейросеть-классификатор.
Таким образом, пользователь может как расширить, так и перезаписать/скорректировать поведение акцентора.
Вывод

Мы продолжаем развивать нашу библиотеку простановки ударений и разрешения омографов в меру своих возможностей. Теперь она получила новые слова, больше устойчивости, метрики подросли. И самое главное — пользователи могут добавлять свои регулярные выражения.
В принципе с новым подходом к проверке данных "на реальных людях" мы приближаемся к краю разумного покрытия омографов (естественно приходится срезать углы, т.к. никто не даст нам инвестиций на публичную библиотеку для, как ни странно, общепринятой и полезной задачи, а публичные датасеты или не существуют или "приватизированы" Яндексом).
Мы неизбежно вынуждены помечать многие слова ("один", "какая", "нем") с огромных дисбалансом как "неомографы", но это тоже закономерный этап развития библиотеки. В принципе если принять точность 95%-97% на корпусе чистых данных как некую асимптоту (думаю когда-нибудь F1 тоже будет в районе 0.95), то становится понятно, что слова с дисбалансом сильно больше чем 1-к-100 по сути лучше не решать. И получается как раз хороший юзкейс для пользовательских регулярок или словосочетаний (яркий пример тут слова как+ая и к+акая).

