Привет, Хабр! Сегодня я расскажу о том, как натренировать качественный русскоязычный пунктуатор и капитализатор для стенограмм (то есть, модель, превращающую только что распознанный Speech-to-Text’ом “привет хабр” в литературный “Привет, Хабр!”). Задача эта давно известная и в последние годы кое-как решаемая с помощью нейросетей-трансформеров, например, BERT. Ключевое слово здесь – “кое-как”. Мы пробовали множество открытых доступных моделей (подробности ниже), но результат сильно не дотягивал до нужного нам уровня. Пришлось доделывать модель самим.

Некоторые энтузиасты LLM сразу спросят: а зачем отдельно тренировать пунктуатор в 2023-м, когда есть универсальный ChatGPT? Одна из проблем в том, что ChatGPT работает только на зарубежных серверах, и как они там собирают данные – никому не известно. И это не говоря ещё о риске перевирания текста и высокой стоимости.

Если к вам обращаются заказчики за автономной системой протоколирования митингов, то ни о каком ChatGPT не может идти и речи. Что касается других LLM (Llama 2, T5 и т.д.), то они постоянно страдают галлюцинациями, потребляют в разы больше памяти и работают в десятки, а то и сотни раз медленнее, чем стандартный пунктуатор на BERT. Подробнее об экспериментах с использованием генеративных LLM – в разделе ниже.

В отличие от генеративных сетей, архитектура BERT в принципе хорошо подходит для расстановки знаков и заглавных букв: гарантия от галлюцинаций и быстрая работа, даже на CPU. Однако результат очень сильно зависит от того, на каких данных их обучали. Например, как мы выяснили на собственном опыте, пунктуаторы, натренированные на типичных больших русскоязычных корпусах (новости, энциклопедии, литература, рандомный кроулинг) очень редко ставят точки. Причём, как показали дальнейшие эксперименты, та же по строению модель справлялась намного лучше, если учить её на правильно подобранном датасете.

Для нашего проекта мы воспользовались стандартным набором скриптов из проекта NeMo от корпорации NVIDIA. Всё, что нужно ML-инженеру – это подготовить датасет из двух файлов: во-первых, сырого текста без пунктуации и заглавных букв, а во-вторых, файла с метками пунктуации и капитализации.

Казалось бы, что может быть проще? Берём самый большой датасет предложений на русском, раскладываем каждое предложение на сырой текст и метки (метод, делающий это, можно накидать за час-другой), скармливаем всё это тренировочному скрипту NeMo вместе с базовой моделью BERT (для русского языка это может быть DeepPavlov/rubert-base-cased-conversational) – и вуа-ля!

Однако на практике качество такого пунктуатора оказывается низким, когда дело доходит до обработки настоящих стенограмм, и особенно – при разбиении текста на отдельные предложения. На это жалуются авторы нескольких моделей (айн, цвайн – рискнули расставить запятые в статье с помощью своей нейронки, но не доверили ей точки).

Почему так?

Проблемы доступных датасетов

Во-первых, львиная доля датасетов русского языка – это наборы либо отдельных предложений, либо коротких абзацев, состоящих всего из нескольких предложений. Сможет ли модель обучиться ставить точки в середине строки, если на вход ей подавать только по одному предложению за раз? Конечно, не сможет. И самое неприятное: предложения в таких датасетах рандомно разбросаны, и если просто так их склеить друг с другом, не получится адекватного по смыслу текста, который потом встретится модели в продакшене (подход склейки рандомных предложений использовался здесь).

Во-вторых, большинство русских датасетов состоят из письменной речи. Очень популярны у нас новостные наборы (lenta.ru) и энциклопедические (Wikipedia). Но эти тексты мало похожи на устную речь. Предложения в Википедии обычно очень длинные и заумные, просторечия в них прямо запрещены политикой энциклопедии. Надеяться, что на таких данных пунктуатор научится разбивать на предложения разговорную речь, не стоит. А ведь основная задача пунктуаторов – работать именно на стенограммах, свеже полученных от Speech-to-Text.

В-третьих, само качество текстов часто подводит. Например, в Taiga Corpus есть саб-сеты с текстами из соц. сетей. А в сетях пишут, как правило, очень неграмотно. Такие данные не обучают пунктуатор – они его портят.

Вообще, грамотность русскоязычных носителей – это большая головная боль. Язык у нас сам по себе сложный, особенно когда дело доходит до пунктуации, и тем более – до дефисов, тире и двоеточий. Хотелось бы верить, что среднестатистический “native speaker” выдаёт достаточно надёжные тексты, чтобы на них что-то обучать (кроме подражания такой речи), но по факту надеяться можно только на профессионалов: лингвистов, филологов, журналистов, редакторов, писателей, стенографистов и т.п. И это сразу заставляет отсечь львиную долю датасетов из открытого доступа. Чего стоят только чудный бзик части русской общественности писать предлог “бес” как “без”, чтобы не “накликать бесов”, упорное нежелание ставить дефисы в “какой-то” и “кое-кто”, живучие запятые между сложным сказуемым и подлежащим, строчные буквы в начале предложений и т.д.

Некоторые в качестве русскоязычных корпусов рекомендуют массовые литературные порталы типа Проза.ру. Но туда пишут все подряд, без модерации и редактуры. Проза.ру хвастается на главной, что у неё опубликовано 327 000+ авторов. Но подумайте, какое будет качество у такого количества? Я открыл буквально первое попавшееся произведение первого рекомендуемого (!) автора и в первых же строках обнаружил следующее:

Не в обиду будь сказано графоманам, но на Прозу.ру большинство идёт с целью получить удовольствие от самовыражения. А написание грамотного текста - это в первую очередь труд, рутинный и зачастую неприятный. Безусловно, в мире должно быть место для самовыражения с поддержкой окружающих и без риска получить въедливую критику. Поэтому, например, мы поощряем детей за “каляки-маляки”. Но мы же не будем обучать на детских рисунках какой-нибудь Stable Diffusion или Midjourney, если хотим добиться от них фотореалистичных изображений?

Да, на Прозе.ру есть хорошие авторы, но гигантская масса неграмотных/ленивых убьют вам пунктуатор.

Наконец, четвёртая проблема, касающаяся в первую очередь капитализатора: обилие прямой речи в новостных датасетах (например, Lenta.ru). Обучить пунктуатор на расстановку кавычек очень сложно (подробнее об этом – в разделе “Форматируем датасет”), а если их игнорировать, то сложно понять, какую пунктуацию и капитализацию выставить на стыках цитат и пояснений. Вот часть новости из Ленты.ру от 2019-го года, с цитатой Сергея Шнурова:

«Перед нами ангел, который поет: ""Сильная женщина плачет у окна"". Откуда это, зачем?» — возмутился он.

Что делать здесь на границах цитат? Например, нужно ли оставлять “Сильная” с большой буквы, и если да, то не начнёт ли капитализатор делать заглавными слова после двоеточий, даже если это не начало цитат и не имена собственные?

Опять же, в стенограммах (а пунктуаторы применяются в основном для стенограмм) цитат не так уж много, в отличие от новостных текстов (где пунктуатор не нужен, потому что текст уже написан профессионалом), поэтому попытка включить в обучающую выборку такие тексты может создать больше проблем, чем пользы.

Какие датасеты нужны

Итак, нам где-то нужно найти данные, удовлетворяющие следующим требованиям:

  • грамотные (лучше – профессиональные)

  • длинные

  • связанные

  • стенограммы

В Интернете их не так много. Один из вариантов – это проект OpenSubtitles. Да, это не вполне стенограммы, потому что изначально персонажи фильмов и роликов говорят то, что написано в сценариях. Но всё же сценаристы хотя бы пытаются имитировать живую устную речь, чего в больших объёмах не встретишь в новостных, энциклопедических и даже литературных датасетах. И да, качество пунктуации в субтитрах немного хромает, ведь они часто выполняются любителями. И всё же оно неизмеримо выше, чем у текстов, рандомно натасканных с просторов Интернета кроулерами и скраперами.

Ещё можно посмотреть в сторону художественной литературы – там тоже встречается имитация устной речи. Но, во-первых, современную русскую литературу сложно достать из-за авторского права, а во-вторых, тексты классической литературы мало похожи на нынешнюю речь, да ещё и зачастую получены не очень качественным OCR со сканов. Так что ошибок в них хватает.

К счастью, есть в Интернете вариант получше – это стенограммы заседаний законодательных собраний России. Тут есть масса плюсов:

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

  2. Находятся в открытом доступе.

  3. Выполнены профессионалами.

  4. Большие объёмы: некоторые зак. собрания ведут их с нулевых, если не с девяностых годов и за это время накопили сотни стенограмм.

  5. Высокая связанность: один текст отражает несколько часов заседаний подряд.

  6. Покрывает сложные случаи с топонимами, фамилиями и т.д.

  7. Автоматически пополняются: можно периодически тащить их к себе в data lake и дообучать модель на свежих данных (касается в первую очередь работы с новыми словами в языке, но также и новых правил, если такие возникнут).

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

Пишем веб-скраперы

Не буду утомлять техническими деталями питоновского кода – можете просто посмотреть исходники. Но расскажу основные принципы и сложности.

Я выбрал 2 зак. собрания для подготовки данных – Государственную Думу и Московскую городскую Думу. Можно найти стенограммы и в других зак. собраниях. Но они менее представительны (просто ввиду меньшей численности электората), и поэтому собираются реже. Может оказаться так, что создание адаптированного скрапера для них не окупится тем улучшением, которые они дадут для модели. Кроме того, объёмы указанных двух зак. собраний плюс данные с OpenSubtitles и так составили почти 2 гигабайта, что вполне неплохо для пунктуатора.

Тексты стенограмм ГосДумы хранятся у них на сайте в сыром HTML, что очень удобно. Главная сложность – очистка от представлений спикеров, которые вписаны прямо в текст (“В.В. Жириновский. Не согласен!”) и имеют самый разный формат (жирный шрифт или не жирный, с отчеством или без, с титулом или без и т.д.). Пришлось писать мудрёный алгоритм, учитывающий все эти нюансы.

Пример текста с представлениями спикеров, который сложно разобрать. Учтите, что не во всех стенограммах Госдумы представления выделены жирным и/или курсивом.

У Мосгордумы другие проблемы: сайт не даёт стабильного подключения для urllib, стенограммы хранятся в документах (docx, rtf и т.д.), из-за чего проблематично выделить в них жирные абзацы (представления спикеров в Мосгордумы выделяются жирным), а кроме того – в этих документах много лишней информации, и не всегда понятно, как её отделить от собственно стенограммы.

Первая проблема частично решалась мимикрией запросов под браузер и периодическими ретраями, но иногда соединение сбрасывалось намертво, и никакие автоматические переподключения не помогали. В результате пришлось вести скачивание в полу-автоматическом режиме: скрипт постоянно кроулит сайт Мосгордумы, а я раз в 2-3 минуты дополнительно открываю его же в браузере для “освежения доверия к себе”. Следствие ли это защиты Мосгордумы от DDoS-атак или просто случайность – осталось для меня загадкой.

Вторая проблема решилась конвертацией документов в html с помощью команды soffice --convert-to html от LibreOffice, а третья – банальным наблюдением за тем, по каким признакам начинаются тексты стенограмм.

С OpenSubtitles всё было намного проще: достаточно скачать архив, удалить файлы нерусских субтитров и удалить в каждой строке текст до третьего таба включительно, чтобы избавиться от временным меток.

Для датасета новостей от Lenta.ru я написал почти все функции, но в процессе понял, что по вышеуказанной причине (из-за обилия прямой речи с кавычками, которые мы не можем учитывать) предобработанные тексты содержат слишком много ошибок в плане пунктуации и капитализации. В результате я решил не включать Ленту в финальную обучающую выборку.

Теперь пришла пора готовить датасет в формате NeMo.

Форматируем датасет для пунктуации/капитализации

Продвинутые метки

Обычно таким моделям ставят самые простые задачи. В плане пунктуации – расставлять запятые (в хорошем случае – ещё и точки, в лучшем – восклицательные и вопросительные знаки). В плане капитализации – решать, писать слово с заглавной буквы или нет.

Но раз уж мы накачали столько хороших стенограмм, почему бы не выжать из BERT’а больше? Сделаем следующие наборы допустимых меток:

Для пунктуации:

O , . ? ! : ; … ⁈ - —

Здесь “O” означает “отсутствие пунктуации”, короткая чёрточка “-” – дефис, длинная “—” – тире, остальные говорят сами за себя.

Для капитализации:

O U T

Здесь “O” означает “оставить все буквы строчными”, “U” (upper) – “сделать только первую букву заглавной”, “T” (total upper case) – “аббревиатура, все буквы должны стать заглавными”.

Обратите внимание: каждая метка должна быть единым символом (к счастью, для многоточия и “усиленного вопросительного знака” в кодировках есть отдельные символы).

Мало того, скрипт NeMo нативно не поддерживает такие сложные вещи как дефисы, тире и аббревиатуры. Он может только ставить один знак препинания (тот, что указан в метке) сразу после слова и писать это слово либо с заглавной, либо со строчной буквы (метки “O” и ”U” соответственно). Если мы попытаемся использовать наши продвинутые метки без кастомной обработки, то “как то” превратится не в “как-то”, а в “как- то”, а “оаэ часть опек” превратится не в “ОАЭ – часть ОПЕК.”, а в “Оаэ– часть Опек.”

Это значит, что мы не можем воспользоваться встроенным скриптом от NeMo, который сам раскладывает исходные тексты на сырые предложения и метки. Например, он не поймёт, что для слова “КВН” нужно выставить метки “OT”. В лучшем случае, он превратит это в “OU” (только первая буква заглавная), а то и вовсе в “OO”. Аналогично “кое-кто” едва ли превратится в “OO -O”, а скорее всего останется единым словом для скрипта. И когда в продакшене от STT вам придёт “кое кто” как два отдельных слова без дефиса, модель не будет знать, что с ними делать.

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

Два отдельных вопроса:

  1. Можно ли добавить в метки пунктуации скобки, кавычки и т.д.?

  2. Можно ли добавить комбинированную капитализацию слов? (например, ChatGPT)

На первый вопрос ответ положительный. Технически это возможно. Но на практике получится масса проблем. Во-первых, скобки и кавычки очень часто попадаются не отдельно, а в качестве составной пунктуации, причём как до слова, так и после. Например:

“Семён!” – окликнула его Варя.

Сколько здесь знаков пунктуации, относящихся к слову “Семён”? Четыре. Кавычка до, кавычка после, восклицательный знак и тире. Теоретически мы можем завести метку, которая будет обозначать эту комбинацию (“!”–). Но сколько таких валидных комбинаций есть в русском языке? Многие и многие десятки. И какой у каждой из них будет support, даже в таком большом датасете? Мизерный. Понятно, что нормально модель для таких редких комбинаций не обучится.

Но самое главное: кавычки и скобки – это парные знаки препинания. И зачастую закрывающая кавычка/скобка находится за многие десятки слов от открывающей. Если реакцию на отсутствующую запятую у читателя будет “ну нет и нет, и так примерно понятно, что тут происходит”, то, наткнувшись на открывающую кавычку, пользователь будет подсознательно искать закрывающую до самого упора. Чтение текста намного затруднится из-за ненужного саспенса, нагнанного нашей моделью.

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

Поэтому в рамках этой задачи мы не берём в расчёт никакие парные знаки, а из составных берём только ⁈ и …, которых набралось хотя бы по несколько тысяч в обучающем датасете.

То же касается и второго вопроса – сложной капитализации (как в названии ChatGPT).

Технически мы можем представить капитализацию как битовую маску (1 – капитализируем конкретную букву, 0 – нет), и тогда каждому бинарному набору значений можно будет придумать свою метку. Например:

Метка

Третья буква

Вторая буква

Первая буква

a

0

0

0

b

0

0

1

c

0

1

0

d

0

1

1

e

1

0

0

f

1

0

1

g

1

1

0

h

1

1

1

Формула капитализации слова “ChatGPT” в таком случае будет: 1110001

Но это сработает только для маленьких слов, потому что число требуемых меток = 2 в степени максимального числа букв в слове. Для слов типа ChatGPT это будет уже 128 меток. И разумеется, support каждой из них в датасете будет мизерным, кроме нулевой метки и метки капитализации первой буквы.

Так что такой подходнепрактичен.

Ещё вариант – перейти на суб-словарную или даже посимвольную токенизацию, но это потребует глубокой переработки скриптов NeMo или написания своего алгоритма обучения. Вместе с тем, слов с такой сложной капитализацией немного и они очень специфические – их, как правило, можно найти чёткой логикой и поправить им капитализацию regex’ом уже после инференса. Поэтому в рамках нашей задачи мы просто будем считать капитализированной только первую букву у таких слов.

Конкатенация предложений

Мы уже обсуждали, что обучать пунктуатор на отдельных предложениях не имеет смысла – он не научится ставить точки, многоточия, восклицательные и вопросительные знаки. С другой стороны, в нашем датасете есть заседания по несколько часов подряд, и конечно, они не влезут в модель целиком. Упомянутый выше DeepPavlov/rubert-base-cased-conversational принимает на вход 512 токенов.

Отсюда идея следующего алгоритма: мы бежим по файлу заседания (или субтитров сериала) и конкатенируем предложения до тех пор, пока они в сумме не дадут больше токенов, чем лимит у модели. Группу предложений, которая убралась в лимит, выделяем в одну строку датасета, и вот её уже делим на сырой текст и метки. Затем продолжаем бежать по файлу и собирать новые группы предложений. Таким образом, каждый обучающий сэмпл будет включать много, зачастую десятки предложений.

К сожалению, тот факт, что нам на каждом предложении нужно пользоваться токенайзером, катастрофически увеличивает время на подготовку датасета. Просто собрать предложения по всем стенограммам Госдумы заняло бы, может, несколько секунд времени. Но сделать это с учётом токенизации – задача на несколько часов.

Очистка предложений

Естественно, помимо указанной выше пред-обработки нужно совершить ещё массу операций, чтобы подготовить строки для обучения пунктуатора:

  1. Убрать кавычки

  2. Убрать строки, содержащие скобки (в случае стенограмм и субтитров в них содержится, как правило, только техническая информация)

  3. Для субтитров – убрать строки с тэгами и знаками музыки ♪ (опять же, техническая информация)

  4. Знаки номеров (№) и процентов (%) заменить на слова, потому что именно в таком виде они будут приходить от STT в пунктуатор

  5. Троеточия (...) и усиленные вопросительные знаки (?!) нужно заменить на односимвольные аналоги (… и ⁈)

  6. Из остальной составной пунктуации оставить только по одному знаку (например, “? —” превратить в “?”)

  7. Тире, записанные дефисами, превратить в настоящие тире (“ - ” в “ — ”)

  8. “Отлепить” дефисы от последующих слов

  9. Множественные пробелы заменить на одинарные

  10. Прочие мелкие операции

Ну и наконец, для каждого слова в каждой очищенной строке мы смотрим, какие там заглавные буквы и какой знак препинания находится после слова. И готовим сразу два соответствующих файла, как просит NeMo: text.txt с сырым текстом и labels.txt с метками.

Всего субтитры дали 378 мегабайт датасета, Мосгордума – 269 мегабайт, Госдума – 1.2 гигабайта.

Обучение, оценка и проверка

После подготовки датасета остальные процедуры кажутся до неприличия простыми. Нужно лишь скачать необходимые скрипты и шаблоны NeMo (если вдруг ещё не сделано), немного подкрутить шаблон конфига для тренировки, установить переменные окружения и запустить саму тренировку в одну строку:

!python $NEMO_ROOT/examples/nlp/token_classification/punctuation_capitalization_train_evaluate.py -‑config‑name=trainer_ru_transcription_config.yaml -‑config‑path=<path to config>

Сама процедура обучения в моём случае (NVIDIA GeForce RTX 3070) заняла примерно 5 часов для 6 эпох и порядка 7 GB VRAM.

Вот такую оценку обученной модели выдал скрипт NeMo:

Пунктуация

Label

Precision

Recall

F1

Support

O

97.03

98.01

97.52

8971117

,

80.24

79.63

79.93

1248052

.

77.60

80.53

79.04

1066049

?

70.54

60.36

65.05

158034

!

58.24

31.66

41.02

49775

:

72.75

54.37

62.23

48144

;

38.97

13.26

19.79

2503

48.57

11.81

19.00

32140

42.93

6.88

11.85

2429

-

94.84

92.20

93.50

98157

60.42

36.25

45.31

81217

Средние оценки по пунктуации:

Metric

Precision

Recall

F1

Support

micro avg

92.76

92.76

92.76

11757617

macro avg

67.47

51.36

55.84

11757617

weighted avg

92.44

92.76

92.51

11757617

Видно, что оценки для массовых меток (‘O’, ‘,’, ‘.’) достаточно высокие, так же как и для дефисов. Для тех же меток, которые связаны с эмоциональной окраской предложений (тире, двоеточия, многоточия, восклицательные и вопросительные знаки), оценки низкие. И это понятно – сами эмоции намного сложнее определить по голому тексту, без данных о звучании голоса.

Приятная особенность: precision у спорных “эмоциональных” меток намного выше, чем recall. Это значит, что модель склонна откатываться к более безопасным стратегиям в случае сомнений. Например, ставить точки вместо многоточий, но не наоборот.

Я построил confusion matrix для прогона на тестовом под-наборе (то есть, том, который не участвовал в обучении и валидации):

Идеал\Модель

O

,

.

?

!

:

;

-

O

8786810

93286

63494

8131

1061

1973

99

1214

9

2851

6530

,

127574

995160

103452

9401

3790

2537

249

861

22

1042

6151

.

79581

96942

861895

17031

5333

3109

249

1104

16

411

3889

?

16009

12239

32538

95805

650

144

0

305

129

111

536

!

3703

8406

19791

1129

15819

130

1

90

20

78

272

:

5949

6402

7404

368

117

25948

8

41

0

14

1631

;

333

970

842

17

9

19

304

0

0

3

38

11316

6656

8839

1231

348

48

0

4152

0

158

138

259

259

386

1215

61

6

0

4

170

6

16

-

4584

1668

756

178

65

9

1

219

0

90749

227

19462

17853

10830

1141

235

1660

20

380

9

358

29706

К ней требуется несколько пояснений.

Диагональ сверху слева вних вправо – верные ответы модели (была запятая – модель поставила запятую). По вертикали указаны идеальные метки и под-набора, по горизонтали – те, которые поставила модель во время теста. То есть, самое нижнее левое число “19462” в таблице означает, что в 19462 случаях мы ожидали тире, согласно датасету, но модель не поставила никакого знака препинания.

Дальше – интереснее. Я разместил метки в том порядке, в каком добавлял их в конфиг, но можно заметить, что в целом они идут от менее сложных и спорных ко всё более сложным и спорным. Исключением оказался дефис, который угадывается с очень большой точностью, несмотря на не очень большой support, и отчасти – тире.

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

Например, для ситуаций, когда нужно было поставить знак ⁈, модель сделала это 170 раз, но при этом обычный знак ? поставила аж 1215 раз. При этом с обратной ситуацией (нужно поставить простой ?, а модель ставит усиленный ⁈) было всего лишь 129 ошибок.

Разумеется, это недостаток модели, но довольно безопасный. Вряд ли заказчик на нас обидится, если в стенограмме делового совещания мы его представим чуть более строгим и уравновешенным, чем он был на самом деле.

Таким образом, мы не особо проиграли от того, что ввели эти сложные знаки препинания.

Кстати, интересно, что при вызове NeMo’вской функции add_punctuation_capitalization с низким параметром max_seq_length (например, 64) время выполнения значительно увеличивается, но результат в confusion matrix магическим образом улучшается на 1-2% (то есть, больше значений на диагонали, меньше – по бокам, при сохранении общей суммы). Можно предположить, что низкий max_seq_length заставляет модель бить большие строки на более мелкие, и обрабатывать каждую из них отдельно, но непонятно, каким образом это может положительно влиять на точность/полноту.

Теперь сравним наши результаты по метрике F1 с пунктуатором Silero (в той редакции, в которой она изначально была опубликована на Хабре):

Метка

Ru BERT на стенограммах

Silero

O

0.9752

0.98

.

0.7963

0.68

,

0.7904

0.61

-

0.9350

0.72

!

0.4102

0.28

?

0.6505

0.60

0.4531

nan

Результаты значительно выше по всем параметрам, кроме отсутствия знака пунктуации (и то – смотря как Silero округлили F1 до 0.98).

Конечно, это не так уж о многом говорит, если учесть, что базовая модель, источник датасета и механизмы предобработки были другие. Кроме того, модель Silero мультиязычная, так что здесь наверняка имела место классическая дилемма “качество или универсальность”.

Тем не менее, я подчеркну наши преимущества:

  • Если вас интересует именно русский язык, то модель rubert-base-cased-conversational, обученная на стенограммах, показывает лучший результат.

  • Сам по себе выбор датасета я считаю более удачным, потому что он построен не на изначально письменных текстах, а ровно на том, на чём и должен работать пунктуатор после STT – на стенограммах устных выступлений.

Капитализация

Label

Precision

Recall

F1

Support

O

97.63

97.88

97.76

9532366

U

90.23

89.15

89.68

1681799

T

92.21

91.48

91.84

543452

Средние оценки по капитализации:

Metric

Precision

Recall

F1

Support

micro avg

96.34

96.34

96.34

11757617

macro avg

93.36

92.84

93.09

11757617

weighted avg

96.32

96.34

96.33

11757617

На случай, если вы спрашиваете, почему у аббревиатур support аж 540 000 штук, отвечаю: в этот класс включаются все слова, состоящие только из заглавных букв. То есть, однобуквенный предлог в начале предложения (“А что?”) получит метку “T”, как и настоящая аббревиатура. Вероятно, это может портить ситуацию из-за того, что случаи “заглавная буква в начале предложения” оказываются размазанными по двум классам (U и T), но метрики в любом случае довольно хороши, поэтому я не стал тратить время на проверку этой гипотезы.

В целом, ничего необычного в полученных оценках по капитализации нет, они плюс-минус типичны и для других русскоязычных моделей.

Инференс

При загрузке в GPU модель занимает 1362 мегабайта VRAM (при том, что файл модели весит 2.1 GB). Плюс сколько-то мегабайт на каждую строку в батче. Например, одна строка размером почти в лимит модели добавляет около 1 GB VRAM при инференсе. Соответственно, на видеокарте с 8 GB на борту лучше не запускать больше 5 строк за один батч.

В случае загрузки в CPU модель у меня работает примерно в раз 5-7 медленнее. На GPU работа над примером ниже заняла у модели где-то 0.3 секунды, а на CPU – примерно 2 секунды.

Посмотрим, как справилась модель на выступлении депутата в Гордуме Петербурга (в датасете этой Гордумы не было):

Очищенный ввод для модели

Вывод модели

Оригинал в официальной стенограмме

мы же понимаем что вообще сама необходимость в этом законе возникла ровно из за того что раковая опухоль платных парковок бесконтрольно расползается по городу вот получаю вчера письмо от избирательницы за месяц три штрафа 2 тысячи рублей на парковку вчера стояла около детской больницы раухфуса пыталась ребенка госпитализировать 600 рублей спрашивается за что исполнительная власть в вопросе о платных парковках слушать ни депутатов ни жителей не желает одна единственная крошечная уступка да можно парковаться по льготным разрешениям в пределах района а не муниципалитета а на все остальные претензии отвечают в стиле незабвенного виктора степановича черномырдина все ваши предложения мы положим в одно место и мы знаем в какое и вы знаете

Мы же понимаем, что вообще сама необходимость в этом законе возникла ровно из-за того, что раковая опухоль платных парковок бесконтрольно расползается по городу. Вот получаю вчера письмо от избирательницы: за месяц три штрафа 2 тысячи рублей на парковку. Вчера стояла около детской больницы Раухфуса, пыталась ребенка госпитализировать — 600 рублей. Спрашивается: за что исполнительная власть в вопросе о платных парковках слушать ни депутатов, ни жителей не желает? Одна-единственная крошечная уступка — да, можно парковаться по льготным разрешениям в пределах района, а не муниципалитета. А на все остальные претензии отвечают в стиле незабвенного Виктора Степановича Черномырдина. Все ваши предложения мы положим в одно место, и мы знаем, в какое. И вы знаете.

Мы же понимаем, что вообще сама необходимость в этом законе возникла ровно из-за того, что раковая опухоль платных парковок бесконтрольно расползается по городу. Вот получаю вчера письмо от избирательницы: за месяц три штрафа, 2 тысячи рублей на парковку, вчера стояла около детской больницы Раухфуса, пыталась ребенка госпитализировать – 600 рублей. Спрашивается за что? Исполнительная власть в вопросе о платных парковках слушать ни депутатов, ни жителей не желает. Одна-единственная крошечная уступка – да, можно парковаться по льготным разрешениям в пределах района, а не муниципалитета. А на все остальные претензии отвечают в стиле незабвенного Виктора Степановича Черномырдина: все ваши предложения мы положим в одно место, и мы знаем в какое. И вы знаете.

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

В предложении про штрафы пропущены тире и запятая, но они опциональны: по сторонам от тире нет подлежащего и сказуемого, а “три штрафа 2 тысячи рублей” можно интерпретировать как “три штрафа по 2 тысячи рублей”, и в таком случае запятая скорее желательна, чем обязательна.

Точка перед “Вчера стояла” выглядит даже более логичной, чем запятая в официальной стенограмме, потому что речь идёт об отдельном примере, после и без того сложного предложения с двоеточием.

Вывод “Спрашивается: за что исполнительная власть слушать… не желает?” конечно, выглядит странно, но всё же имеет право на существование. В том смысле, что “жители сделали что-то плохое власти, и из-за этого она теперь не желает их слушать”. Чтобы точно понять, что “за что” относилось к штрафу за парковку, нужно слышать интонацию выступающего, чего модель, разумеется, сделать не могла.

Наконец, по цитате в духе Черномырдина: можно сказать, что двоеточие здесь выглядит лучше, потому что вторая часть предложения является пояснением первой. Но ведь следующее предложение (“И вы знаете”) тоже относится к этой псевдо-цитате. Таким образом, цитата всё равно оказывается разбросана по двум предложениям, и тот факт, что первая её часть оказывается прикреплённой к представлению цитаты через двоеточие, лучше ситуацию не делает.

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

Пробуем генеративные LLM

Вернёмся к вопросу о том, можно ли использовать универсальные генеративные LLM в качестве пунктуатора/капитализатора. Совместно с инженерами, имеющими доступ к Llama 2 и ChatGPT, я скормил указанный выше текст из Гордумы Петербурга трём моделям:

  • FRED-T5-large с LoRA, обученным на под-сете из стенограмм Госдумы.

  • Llama-2-7B

  • ChatGPT

Получилось следующее:

FRED-T5-large с LoRA

Llama-2-7B

ChatGPT

Мы же понимаем, что вообще сама необходимость в этом законе возникла ровно из-за того: чтобы раковая опухоль платных парковок бесконтрольно расползалась по городу. Вот получаю вчера письмо от избирательницы — за месяц три штрафа 2 тысячи рублей на стоянку! Вчера стояла около детской больницы Раухфуса пыталась ребенка госпитализировать 600 рублей!!! Спрашивается – "За ЧТО?" Исполнительная власть.. В вопросе о Платные парковки слушать ни депутатов,ни жителей не желает одна единственная крошечная уступка (да можно парковаться только при льготных разрешениях) и лишь во время стоянки с ними разговаривать нельзя; все ваши предложения мы положим...в одно место? И вы знаете куда?!

Мы же понимаем, что вообще сама необходимость в этом законе возникла ровно из-за того, что раковая опухоль платных парковок бесконтрольно расползается по городу, вот получаю вчера письмо от избирательницы за месяц три штрафа 2 тысячи рублей на парковку вчера стояла около детской больницы, раухфуса, пыталась ребенка госпитализировать 600 рублей, спрашивается за что исполнительная власть в вопросе о платных парковках слушать ни депутатов ни жителей не желает, одна единичная крошечная уступка да можно парковаться по льготным разрешениям в пределах района, а не муниципалитета, а на все остальные претензии отвечают в стиле Забвенного Виктора Степановича Черномырдина, все ваши предложения мы положим в одно место и мы знаем, в какое и вы знаете.

Обратите внимание, что в этом фрагменте использованы следующие знаки пунктуации:

* ровно (роunda) – скобки

* бесконтрожно (бесконтрожно) – акут

* вчера (вчера) – акут

* раухфуса (раухфуса) – акут

* госпитализировать (госпитализировать) – акут

* льготным (льготным) – акут

* пределах (пределах) – акут

* не (не) – акут

* все (все) – акут

* Забвенного (Забвенного) – акут

* Виктора Степановича Черномырдина (Виктора Степановича Черномырдина) – акут

Кроме того, в этом фрагменте использованы следующие заглавные буквы:

* М

Мы же понимаем, что вообще сама необходимость в этом законе возникла ровно из-за того, что раковая опухоль платных парковок бесконтрольно расползается по городу. Вот получаю вчера письмо от избирательницы: за месяц три штрафа, 2 тысячи рублей на парковку. Вчера стояла около детской больницы Раухфуса, пыталась ребенка госпитализировать – 600 рублей. Спрашивается, за что? Исполнительная власть в вопросе о платных парковках слушать ни депутатов, ни жителей не желает. Одна единственная крошечная уступка – да, можно парковаться по льготным разрешениям в пределах района, а не муниципалитета. А на все остальные претензии отвечают в стиле незабвенного Виктора Степановича Черномырдина: "все ваши предложения мы положим в одно место, и мы знаем, в какое, и вы знаете".

Видно, что ChatGPT хорошо справился с задачей. Единственный спорный момент – если уж выражение взято в кавычки как прямая речь, желательно начать его с заглавной буквы. В остальном, разница между оригинальной стенограммой и результатом ChatGPT есть, но это такая же вкусовщина, как и разница с результатом BERT. Впрочем, к несомненным преимуществам можно отнести поддержку кавычек и вообще сложных знаков препинания, от которых мы отказались в нашем пунктуаторе.

Не забудем и про стоимость. По свежим данным, цена работы GPT-4 на 1000 токенов - 3 цента. Стенограмма полноценного заседания Госдумы составляет около 30 000 слов. Если предположить, что для русского языка на одно слово приходится 2 токена (очень грубая оценка) плюс что-то на пунктуацию, то за один прогон заседания придётся потратить 120 000+ токенов минимум (половина на входе для текста от STT, половина на выходе уже с пунктуацией). Это 3,6$. Вроде, немного (и уж точно на порядки дешевле, чем нанимать живого человека), но если таких стенограмм будут сотни, то это может стать проблемой. Для сравнения, дешёвый сервер на AWS с поддержкой GPU будет стоить около 1$ в час, и пунктуатор на BERT сможет обработать такой митинг, грубо говоря, за 4-5 минут. То есть, за 9 центов. При условии полной загрузки такого сервера пунктуатор на BERT берёт в 40 раз дешевле, чем GPT-4, за такой же текст. А ведь можно сэкономить ещё больше, взяв сервер только с CPU - просто работать будет помедленнее.

Поскольку ChatGPT был единственным достойным соперником среди имеющихся в распоряжении генеративных LLM, я решил протестировать его дополнительно на более длинной выборке, чтобы посчитать метрики и убедиться в отсутствии галлюцинаций на больших данных. Для этого я скормил ему 7610 первых слов из 1590-го заседания Мосгордумы (это первые 20 строк из получившегося мосгордумовского датасета для пунктуатора).

И хотя GPT в целом показывает на удивление высокую сопротивляемость к галлюцинациям (если учесть, что ему нужно повторить слово в слово длинный текст, да ещё и расставить там знаки), без ошибок не обошлось. Почти в половине из 20 строк оказались добавлены или пропущены 2-3 слова (например, обращение “коллеги”).

Но одна галлюцинация была особенно выдающейся.

Запрос на пунктуацию/капитализацию

Ответ ChatGPT

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

Проект внесен в план. Почему этот план саботируете? Кто дал вам право решать проходной или нет? А даже если непроходной, то само обсуждение проекта или отрицательный результат тоже результат, ведь это показывает, кто есть ху, как говорили классики, то есть кто поддерживает эту идею, а кто против нее. А вот те, кто против нее, они не дают вам выносить. Оппозиция, кто ее тогда оппозицией называет? Еще одно странное заявление Степана Владимировича о том, чтобы подавать поправки. Их будут рассматривать? Подождите, вы же отвечаете за то, чтобы этот план выполнялся, вы лично его докладываете все время. Как же вы игнорируете тот факт, что председатели комиссий полностью его игнорируют и не выполняют эти законопроекты? Перекочевывают из года в год, из сессии в сессию и не рассматриваются. Это нормально в уважающем себя парламенте, в уважающем себя законодательном органе? Я считаю, что это полный абсурд. Вы говорите вносить поправки. Ну внесу я поправку, я уже обещал, она у меня уже написана. А что толку? Депутат Ступин сказал, что ее все равно отклонят. Да ее не отклонят эту поправку, в регламент просто не поставят на рассмотрение. Поэтому не знаю, я внесу конечно такую поправку, чтобы дать четкое указание и установить срок, в какой период законопроект должен быть рассмотрен на комиссии и вынесен на заседание. А если он не будет вынесен, предлагаю применять штрафы и вычитать из зарплаты председателя комиссии энную сумму, если он плюет на план законодательных работ, как это сейчас делает чуть ли не половина председателей комиссий. Обязуюсь внести такие поправки и надеюсь, что Степан Владимирович, как лидер фракции Партии Единая Россия, сдержит свое слово и эта поправка в регламент просаботирована не будет. Спасибо. Голосую против. Депутат Соловьев.

Уважаемые депутаты, наверное, я тоже буду голосовать против, потому что вот эти призывы докладчика проголосовать за, чтобы мы все это рассмотрели, меня что-то не вдохновляют. Я уже точно знаю, что мои законопроекты рассмотрены не будут. Зачем я буду за это голосовать? Мне вся эта ерунда, которую мы каждый день тут обсуждаем, просто не интересна. Про штрафы уже говорили, еще какие-то глупости. Мне интересны реальные проблемы, которыми я занимаюсь, например, чтобы запретить передвижение тяжелой техники в парках и скверах, что кстати запрещено федеральным законом по отношению к национальным паркам, а в Москве разрешено. Но председатель комиссии по экологии, Александр Сергеевич, с этим согласен. Вот он побоялся сейчас передо мной выступать. Мы с ним затеяли игру, потому что он боится. Он хочет, чтобы сама тема обсуждалась. Я не понимаю аргумент, который высказывал Александр Сергеевич. Наверное, он еще раз сейчас повторит после меня, что это типа проходное или непроходное. Ваше какое дело? Вы исполняйте свои обязанности!

Сергей Сергеевич Митрохин: уважаемые депутаты, я глубоко убежден, что это можно назвать единороссовским лоббизмом. Сейчас, например, прозвучало, что оппозиция тоже возглавляет комиссии. Ну, сейчас не будем рассуждать насколько это оппозиция, кто возглавляет комиссии и получает такие же заоблачные зарплаты. Допустим, оппозиция возглавляет комиссии. Вот мне не дали задать вопрос о том, сколько законопроектов прошло, например, в прошлом квартале через комиссии, которые возглавляют Зюганов и Зубрилин, как вы говорите, оппозиция. Вот я что-то не припомню. Может, подскажете? Поэтому, несмотря на то, что в плане стоит мой законопроект, я буду голосовать против в знак протеста той системе, которая сложилась в работе Московской городской думы.

Стоит ли доверять пунктуацию генеративным сетям, если даже лучшие из них могут подкинуть вам в текст такой “подарок”?

Метрики ниже были получены на том же 1590-м заседании. Это может быть не вполне справедливо по отношению к ChatGPT, потому что BERT видел эти предложения при обучении. Но с другой стороны, поскольку и GPT обучался “на всём Интернете”, то он их, вполне возможно, тоже видел.

Метка

Метрика

Наш BERT

ChatGPT

Метка

Метрика

Наш BERT

ChatGPT

O (пункт)

P

0.996

0.980

P

0.0

0.0

R

0.993

0.983

R

0.0

0.0

F1

0.995

0.982

F1

0.0

0.0

,

P

0.923

0.831

P

N/A

N/A

R

0.890

0.759

R

N/A

N/A

F1

0.906

0.793

F1

N/A

N/A

.

P

0.829

0.747

-

P

1.0

1.0

R

0.909

0.769

R

1.0

0.846

F1

0.867

0.758

F1

1.0

0.917

?

P

0.849

0.797

P

0.0

0.0

R

0.804

0.839

R

N/A

N/A

F1

0.826

0.817

F1

N/A

N/A

!

P

0.0

0.0

O (капит)

P

0.990

0.951

R

0.0

0.0

R

0.986

0.976

F1

0.0

0.0

F1

0.988

0.963

:

P

0.667

0.364

U

P

0.932

0.842

R

0.667

0.667

R

0.947

0.744

F1

0.667

0.471

F1

0.939

0.790

;

P

N/A

N/A

T

P

0.943

0.873

R

N/A

N/A

R

0.982

0.743

F1

N/A

N/A

F1

0.962

0.803

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

Разумеется, тут нужно делать поправку на то, что ChatGPT пользуется дополнительными знаками (скобки, кавычки), и для того чтобы сравнение было более-менее адекватным, я заменил в его ответе скобки на запятые, а кавычки убрал (тем более, что в ground truth на этом наборе данных скобок всё равно не было). Но даже если вам позарез нужны скобки с кавычками от пунктуатора, остаётся открытым вопрос, стоит ли рисковать и переходить на ChatGPT или лучше дообучить BERT на датасете с соответствующими метками, как было предложено выше.

Возвращаясь к исходному небольшому куску текста из Питерской Гордумы: Llama 2 расставила пунктуацию довольно плохо, некоторые куски просто проигнорировала. Кроме того, нарицательное “незабвенного” превратила в собственное имя “Забвенного”, а это уже галлюцинация, недопустимая для пунктуатора. Ну и после расстановки знаков принялась бредить, о чём её не просили. Кроме того, генерация заняла пару десятков секунд, в отличие от BERT, который тратит долю секунды на такой же кусок.

Понятно, что бред в конце ответа можно предотвратить с помощью изменения промпта, P-tuning’а или, на худой конец, файнтюнинга/RLHF. Но вот удастся ли на такой малой модели предотвратить галлюцинации типа “незабвенный” -> “Забвенный”? Глядя на галлюцинации от ChatGPT выше, я бы сказал, что нет.

Наконец, российский FRED-T5-large был мной выбран потому, что у него точно не будет проблем с лицензией при использовании для российских заказчиков, плюс он достаточно компактен, чтобы влезть в обычную пользовательскую видеокарту.

В сыром виде FRED-T5 задачу вообще не понимает и просто генерирует бред. Чтобы поставить модель хоть в приблизительно равные условия, я обучил для неё адаптер LoRA на всех декабрьских собраниях Госдумы с 2014 до 2022 год – получилось около 32 МБ данных. Датасет был построен по схожим принципам: на входе подаётся текст без знаков пунктуации только из строчных букв, на выходе – соответствующий оригинальный текст из стенограммы.

Обучение на 3 эпохи заняло примерно 6 часов – примерно столько же, сколько у BERT. С той разницей, что BERT успел пройти за это время 6 эпох и в 60 раз больше данных в каждой.

Как видно, в результате FRED-T5 научился понимать задачу, но малый размер модели не позволяет ей в точности запомнить падежи, имена собственные и прочие нюансы. Да и с расстановкой пунктуации/капитализации у модели большие проблемы. Особенно заметна излишняя эмоциональность, что, кстати, наблюдается при генерации текста и на “чистой” модели, без всяких адаптеров.

Не хотелось бы подозревать самое плохое, но кажется, что бедного FRED-T5 заставляли предобучаться на Прозе.ру, “Ответах Mail.ru” и комментариях в Одноклассниках. Возможно, пришла пора для ИТ-сообщества разработать закон о гуманном обращении с нейросетями.

Выводы

Нам удалось обучить качественную модель пунктуатора и капитализатора с поддержкой тире, дефисов и аббревиатур, которая работает локально и успевает обрабатывать стенограммы в realtime на CPU (то есть, выдавать ответ в то время, как участники заседания смотрят на субтитры прямо во время общения). В процессе обучения мы пришли к следующим выводам.

Во-первых, если хотите отсрочить восстание роботов, пишите тексты безграмотно.

Во-вторых, стенограммы зак. собраний – это недооценённый кладезь для задач NLP, а также – для STT и TTS (поскольку часто вместе со стенограммами можно найти и аудио/видео выступлений). Причём по поведению некоторых российских генеративных LLM видно, что их пред-обучали на заседаниях Госдумы. Но вот почему-то среди популярных русскоязычных датасетов эти данные не фигурируют.

В-третьих, пунктуаторы, конечно, можно запускать на задачах типа grammar checking. Но в таких задачах человек всё-таки худо-бедно сам старается расставить препинания, и потому текст выглядит читабельным. А вот задачи, где без пунктуатора вообще не обойтись – это обработка транскрипций после STT, которая в принципе не ставит ни одного знака препинания, ни одной заглавной буквы. Такие тексты нечитаемы. И важно понять, что они основаны на устной речи, которая выглядит по-другому, использует другие наборы слов, другие пропорции синтаксических конструкций и т.д.

Поэтому пунктуаторы, обученные на письменной речи, будут малоэффективны для таких задач. Да, достать датасеты на основе профессиональных стенограмм труднее. Но затраты окупятся качеством.

В-четвёртых, попытки использования генеративных LLM для задач пунктуации приведут либо к некачественному результату, либо к необходимости отдавать данные чужим компаниям за большие деньги, либо к необходимости содержать локально чудовищно большую модель за чудовищные деньги. И при этом ни в одном из случаев вам не будет гарантирована защита от галлюцинаций.

Ну и пятый вывод: мусорные корпусы (типа комментариев в соц. сетях и Прозы.ру) зачастую портят модель, а не улучшают её.

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

Собственно, мы видим подтверждение этому и у передовых моделей. Скажем, первая Llama и Stable Diffusion обучались, условно, на “всём Интернете”, но при этом на результаты работы при попытке внедрить их в бизнес без адаптаций не взглянешь без слёз. В то время как коммерческие ChatGPT и Midjourney готовы решать реальные задачи, как говорится, “out of the box”. Почему? Потому что эти модели после пред-обучения ещё долго и мучительно файнтюнили на отборных датасетах для решения конкретных прикладных задач.

В целом, исходя из моего опыта, современные ML-модели работают, грубо говоря, на один уровень ниже, чем качество датасета, на которых их обучали. А уровни – это условно “превосходно”, “отлично”, “хорошо”, “удовлетворительно”, “плохо” и “ужас”. Если мощную модель как следует обучили на гениальном датасете, она будет выдавать отличные результаты. Если на отличном – будет работать хорошо. И так далее. То есть, идея “сделать сильный искусственный интеллект”, протащив его по всему Интернету, едва ли выгорит. В лучшем случае это будет интеллект на уровень ниже среднестатического пользователя Сети.

Датасеты с рандомных сайтов – это, как правило, нечто среднее между уровнями “удовлетворительно” и “ужас”. Берегите ваши модели от них. И балуйте их отборными, продуманными датасетами.

Спасибо за внимание.

Ссылки на результаты работы

Готовая модель

Скрипты для работы с ней (сбор датасета, обучение, инференс)

Готовый датасет (с данными до июля 2023 года)

Комментарии (10)


  1. Kristaller486
    14.11.2023 06:49
    +2

    Спасибо за статью. Whisper, который SOTA для Speech-to-Text, на русском вроде в том числе, сам расставляет и знаки препинания, и заглавные буквы. Только что проверил. Рекомендую посмотреть на него, тем более на днях третья версия опенсорснулась.


    1. DenisBerezutskiy Автор
      14.11.2023 06:49

      Спасибо. Думаю, из сравнения качества пунктуации у BERT и Whisper можно будет сделать отдельную статью.


  1. MMik
    14.11.2023 06:49

    Улучшить модель можно добавив разметку частей речи. Попробуйте.


    1. DenisBerezutskiy Автор
      14.11.2023 06:49

      Спасибо за совет. А как вы рекомендуете размечать части речи в исходных текстах? Какой-нибудь другой моделью? Если так, то не получится ли, что ошибки этой модели повлекут за собой и ошибки пунктуатора?


      1. MMik
        14.11.2023 06:49

        От перемножения ошибок качество не улучшается, конечно. То есть, для лучших результатов нужно использовать один (ваш) датасет, с разметкой и частей речи, и пунктуации одновременно. Открытых моделей не встречал. Обучите сами.


      1. pacupa
        14.11.2023 06:49
        +2

        Для морфологического анализа русскоязычного текста есть Mystem от Яндекса, и Python-привязка к нему.


  1. Heimerdingirl
    14.11.2023 06:49

    Спасибо за статью!


  1. AigizK
    14.11.2023 06:49

    У чатжпт галлюцинации можно легко отследить. Вы же даете известный текст, результат от чатжпт переводите обратно в нижний регистр и удаляете все знаки и сравниваете два текста. Если отличаются, там галлюцинации. Можно этот только кусок дать еще раз.
    А так написали про Whisper. И вот его можно натравить на всяких блогеров, интервьюверов и насобирать еще больше датасета. Там возможно домен будет еще ближе к решаемым задачам.

    А за статью и исходники большое спасибо.


  1. AigizK
    14.11.2023 06:49

    Вот что выдает https://openchat.team/


  1. konstantin-s-yakovlev
    14.11.2023 06:49

    Очень интересная статья, спасибо. Было бы здорово услышать (возможно - через какое-то время) о реальных случаях использования. Сейчас, если честно, не до конца понятно (для человека со стороны) - для чего это нужно :) например, режим «реального времени» - он для чего?