Распознавание речи ВКонтакте: орфография и пунктуация

МЕНЮ


Искусственный интеллект
Поиск
Регистрация на сайте
Помощь проекту

ТЕМЫ


Новости ИИРазработка ИИВнедрение ИИРабота разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика

Авторизация



RSS


RSS новости


Второе выступление с онлайн-митапа от Команды ВКонтакте VK Tech Talks | ASR, который прошёл 24 сентября, было посвящёно орфографии и пунктуации при распознавании речи. Спикер — Надя Зуева, разработчик команды исследований ВКонтакте. Надя занимается задачами, которые связаны с NLP и автоматическим распознаванием речи. Во время трансляции она рассказала о декодинге, выборе языковой модели, нормализации текста, проблемах, с которыми столкнулись разработчики, и о планах социальной сети на будущее.

Делимся с вами расшифровкой доклада от лица Нади.

То, что выдаёт акустическая модель QuartzNet,или то, что выдаёт ContextNet,который мы сейчас используем, у нас выглядит вот таким образом:

По факту это просто матрица, где по оси OX откладываются таймстемпы — время, разбитое на дискретные отрезки, а по оси OY идёт наш словарь, то есть те самые символы или фонемы, которые умеет распознавать наша акустическая модель.

Для того, чтобы преобразовать нашу матрицу в читаемый вид, который будет понятен пользователю, можно использовать, наверное, самый тупой способ — просто выбирать по каждому распределению максимум и смотреть, какой фонеме или какому символу из алфавита соответствует этот максимум распределения, а потом просто конкатить их. Такой подход, когда мы просто берём максимальные значения по каждому таймстемпу, и затем их соединяем, — по сути просто жадный алгоритм, он называется greedy decoder.

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

Первая проблема заключается в том, что использование СTС loss делает нашу модель быстрой, но не авторегрессивной. Предсказания генерируются frame-by-frame, и они не зависят от прошлого. Они вообще не умеют смотреть в прошлое и не знают, что происходило до этого. Поэтому они генерируются независимо, без учёта контекста.

Вторая проблема — может быть несколько интерпретаций для каждого слова.

Что же можно сделать? Решение, которое используют для распознавания речи, — beam search decoding или beam search decoder, который осуществляет этот самый декодинг.

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

Как это работает: на вход нам приходит матрица, которая по оси OX имеет таймстемпы, по оси OYфонемы или символы, у нас их порядка тридцати, которые умеет распознавать наша акустическая модель.

Рассмотрим немного игрушечный пример: пусть у нас есть алфавит мощностью 5 (пять различных символов) и есть ещё такое понятие, как beam width, то есть ширина. Мы думаем, какой топ гипотез в числе мы храним на каждой итерации, а итерируемся мы по таймстемпам. Здесь он равен двум. И когда мы переходим к следующему таймстемпу, то мы учитываем, что было сгенерировано до этого, и выбираем максимум вероятности с учётом того, что уже было сгенерировано. Таким образом, храним тоже топ-две гипотезы, а в результате получаем уже какие-то ответы, более разумные, чем просто greedy decoder.

Но на этом всё не заканчивается. У нас немного иной скорер. Мы не просто используем выход из акустической модели, но и к тому же используем информацию о языке, то есть мы знаем, как выглядят слова, которые мы все говорим и, соответственно, можем использовать эту информацию.

Здесь, в первой части (слайд ниже), у нас соберётся логарифм от вероятности, которую выдала нам акустическая модель, где ? — выход, а x — вход, который подаётся на вход акустической модели. Мы его суммируем с логарифмом от вероятности, которую выдаёт языковая модель, которая в принципе показывает, насколько вероятно получить такую фразу в нашем языке.

? — гиперпараметр, который настраивается. Его можно настроить с помощью тестовой выборки.

Посмотрим на реальные примеры, которые мы прогнали через пайплайн с помощью greedy decoder, LM decoder с beam search. Оригинал: «привет сонь пойдем сегодня в кинчик». Greedy неправильно расставил бланки и ещё, по наблюдениям, есть такая тенденция при использовании только выхода из акустической модели с greedy decoder, что часто слова «схлопываются», и иногда бывает такое, что весь текст — одно длинное слово. При необходимости можно понять, что сказал человек, но всё же это будет нечитаемо, и никто таким пользоваться не захочет. Если же посмотреть на то, что выдаёт beam search LM decoder с использованием знаний о языке, то получается уже что-то адекватное, и, если посмотрите, то заметите разницу: «соня» на нашем корпусе, на котором мы обучали языковую модель, видимо, было более вероятно получить, чем «сонь», поэтому такое исправление.

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

Выбор языковой модели

Конечно, часто хочется использовать какую-нибудь классную SOTA-нейросеть, например BERT, чтобы дать нашей модели знания о языке, но если посмотреть на бенчмарки на известных датасетах, например LibriSpeech или TIMIT,то они не дают значительного прироста по сравнению с какими-нибудь n-граммными моделями.

Мы тоже пробовали сделать нейросетевую модель, и у нас получилось так, что с n-граммами лучше.

Что такое n-граммная модель? Это просто статистическая модель, которая знает о том, с какой вероятностью появится следующее слово при условии, что там было предыдущее или несколько предыдущих. N показывает, на сколько слов назад мы смотрим.

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

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

В процессе разработки системы распознавания речи мы постоянно сталкивались с какими-то проблемами. Языковая модель в классическом формате, который выдаёт KenLM (который ARPA), может весить, например, 30 гигабайт, если у вас большой корпус текстов. И ещё одна проблема — практически все корпусы, если брать большое количество данных, будут денормализованы. То есть из акустической модели мы на выходе имеем последовательность символов, которые лежат в нашем алфавите для акустической модели — 30 букв русского языка, без «ё», в нижнем регистре и ещё пробел. Соответственно, мы хотим уметь обучать нашу языковую модель без цифр, без сокращений, мы хотим всё уметь расшифровывать, ещё и ставить правильный падеж, потому что, например, когда пишем 24 сентября 2020 года, мы ничего не знаем про то, в каком падеже это должно было стоять.

На текущий момент мы никак не учитываем интонацию, когда расставляем пунктуацию, ориентируемся только статистически по тексту.

Решение проблемы с большим количеством гигабайт — бинаризация. Открываем в запакованном формате. Там примерно в 3–4 раза уменьшается размер.

Решение второй проблемы — предобработка данных и их нормализация.

В идеале мы хотим, чтобы у нас люди писали не символами, а буквами, например не «в 1 раз», а «в первый раз».

Но люди, к сожалению, привыкли всё сокращать, поэтому нам приходится восстанавливать текст до такого варианта, как на слайде выше.

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

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

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

После того, как мы натренируем наш трансформер, у нас уже получается что-то осмысленное.

Откуда вообще такие данные можно брать? Мы берём те случаи, когда у нас всё было написано текстом и специально пытаемся их портить. Впоследствии учим нашу модель восстанавливать то, что мы испортили. Так и происходит обучение.

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

Различные SOTA-модели сейчас полагаются на трансформеры, но у них есть значительная проблема — они большие. А у нас 200 миллионов аудиосообщений в сутки, и получается, что у нас огромная нагрузка, то есть все модели должны быть супербыстрыми. Это как раз причина того, почему мы часто запускаем модель из C++, а не из Python.

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

Желаемый вариант в нашем представлении:

Выход из языковой модели (набор символов, который есть в алфавите акустической модели):

С точки зрения данных мы делаем следующее. Мы используем BPE-токенизацию для того, чтобы разбить на токены наш вход — выход из языковой модели. Что значат единички и нолики? Для каждого BPE-токена мы предсказываем метку класса из двух частей. Первая часть метки показывает, нужна ли капитализация (1 — нужно, 0 — не нужно), а дальше идёт символ пунктуации, если его необходимо поставить. В последней модели у нас было порядка 14 классов (2 ? 7; 2 — классы, отвечающие за капитализацию, 7— символы различной пунктуации). На выходе по такому набору классов мы умеем уже однозначно восстанавливать, как нужно преобразовать выход из языковой модели, чтобы показать пользователю то, что он должен увидеть, с пунктуацией и капитализацией.

Используемая архитектура

У нас есть часть трансформера, который энкодер. На вход мы подаём нашу последовательность, которая на выходе из языковой модели, токенизируем её, дальше используем слой эмбеддингов и вместо декодера, который долгий, у нас идёт sequential-слой, где на выходе число классов, которые мы предсказываем. Сейчас их 14, но, возможно, будет больше.

С точки зрения этих классов, там используется простой энкодер ch2idx — мы просто каждую единичку и запятую нумеруем и получаем то, по чему мы уже умеем восстанавливать, то, что мы уже показываем пользователю.

Всё должно происходить очень быстро. Мы учили эту модель на PyTorch, джиттили, чтобы всё запускалось быстрее, и потом уже мы дёргаем нашу модель в пайплайне из С++.

Планы на будущее

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

Полная версия выступления:

 


Источник: m.vk.com

Комментарии: