Русский
Русский
English
Статистика
Реклама

Bert

Трансформеры в Поиске как Яндекс применил тяжёлые нейросети для поиска по смыслу

25.11.2020 12:06:49 | Автор: admin

Привет, Хабр. Меня зовут Саша Готманов, я руковожу группой нейросетевых технологий в поиске Яндекса. На YaC 2020 мы впервые рассказали о внедрении трансформера новой нейросетевой архитектуры для ранжирования веб-страниц. Это наиболее значимое событие в нашем поиске за последние 10 лет.

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

Задача поиска

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

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

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

По такому принципу и работал поиск Яндекса до 2016 года. За годы разработки для повышения качества было придумано множество остроумных эвристических алгоритмов. Одних только способов посчитать общие слова запроса и документа было предложено и внедрено несколько десятков. Вот так, к примеру, выглядит один из сравнительно простых:

Здесь каждому хиту t (то есть вхождению слова из запроса в документ, от англ. hit, попадание) присваивается вес с учётом частотности слова в корпусе (IDF, Inverse Document Frequency) и расстояний до ближайших вхождений других слов запроса в документ слева и справа по тексту (LeftDist и RightDist). Затем полученные значения суммируются по всем найденным хитам. Каждая такая эвристика при внедрении позволяла получить небольшой, но статистически значимый прирост качества модели, то есть чуть лучше приблизить ту самую смысловую связь. Суммарный эффект от простых факторов постепенно накапливался, и внедрения за длительный период (полгода-год) уже заметно влияли на ранжирование.

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

[можно ли купаться в баренцевом море летом]
[путешествие по северному ледовитому океану]
[города и поселки на побережье северного ледовитого океана]

(Это реальные примеры расширений запроса, взятые из поиска Яндекса.)

Как найти похожие слова и запросы тема отдельного рассказа. Для этого в нашем поиске тоже есть разные алгоритмы, а решению задачи очень помогают логи запросов, которые нам задают пользователи. Сейчас важно отметить, что если похожий запрос найден, то его можно использовать во всех эвристических расчётах сразу; достаточно взять уже готовый алгоритм и заменить в нём один текст запроса на другой. Таким методом можно получить сразу много полезной информации для ранжирования. Что может быть чуть менее очевидно аналогично запросу можно расширять и документ, собирая для него альтернативные тексты, которые в Яндексе называют словом стримы (от англ. stream). Например, стрим для документа может состоять из всех текстов входящих ссылок или из всех текстов запросов в поиск, по которым пользователи часто выбирают этот документ на выдаче. Точно так же стрим можно использовать в любом готовом эвристическом алгоритме, заменив на него исходный текст документа.

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

В результате многих лет работы над качеством поиска у нас накопились тысячи самых разных факторов. При решении задачи ранжирования все они подаются на вход одной итоговой модели. Для её обучения мы используем нашу открытую реализацию алгоритма GBDT (Gradient Boosting Decision Trees) CatBoost.

Нейросети в ранжировании

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

Первые нейронные сети в поиске обладали простой feed-forward-архитектурой. На вход сети подаётся исходный текст в виде мешка слов (bag of words). Каждое слово превращается в вектор, вектора затем суммируются в один, который и используется как представление всего текста. Взаимный порядок слов при этом теряется или учитывается лишь частично с помощью специальных технических трюков. Кроме того, размер словаря у такой сети ограничен; неизвестное слово в лучшем случае удаётся разбить на частотные сочетания букв (например, на триграммы) в надежде сохранить хотя бы часть его смысла. Вектор мешка слов затем пропускается через несколько плотных слоёв нейронов, на выходе которых образуется семантический вектор (иначе эмбеддинг, от англ. embedding, вложение; имеется в виду, что исходный объект-текст вкладывается в n-мерное пространство семантических векторов).

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

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

Пример архитектуры сети в подходе с семантическими эмбеддингами. Более подробное описание этого подхода тут.

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

Тем не менее, использование плотных feed-forward-сетей в своё время позволило существенно улучшить качество поиска Яндекса, что легло в основу двух крупных релизов: Палех и Королёв. В значительной степени этого удалось добиться за счёт длительных экспериментов с обучающими выборками и подбором правильных контентных признаков на входе моделей. То есть ключевыми вопросами для нас были: На какой (кликовый) таргет учить? и Какие данные и в каком виде подавать на вход?

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

Нейронная сеть, сначала обученная на миллиардах переформулировок, а затем дообученная на сильно меньшем количестве экспертных оценок, заметно улучшает качество ранжирования. Это характерный пример применения подхода transfer learning: модель сначала обучается решать более простую или более общую задачу на большой выборке (этот этап также называют предварительным обучением или предобучением, англ. pre-tain), а затем быстро адаптируется под конкретную задачу уже на сильно меньшем числе примеров (этот этап называют дообучением или настройкой, англ. fine-tune). В случае простых feed-forward-сетей transfer learning уже приносит пользу, но наибольшего эффекта этот метод достигает с появлением архитектур следующего поколения.

Нейросети-трансформеры

Долгое время самой активно развивающейся областью применения для сложных алгоритмов анализа текста была задача машинного перевода. Результат работы переводчика это полностью сгенерированный текст, и даже небольшие смысловые ошибки сразу заметны пользователю. Поэтому для решения задач перевода всегда использовались самые сложные модели, которые могли учесть порядок слов в тексте и их взаимное влияние друг на друга. Сначала это были рекуррентные нейронные сети (Recurrent Neural Networks, RNN), а затем трансформеры. Далее речь пойдёт только о трансформерах, которые по сути являются более технологически совершенным развитием идеи рекуррентных сетей.

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

Применительно к задаче ранжирования, по запросу [купить кофеварку] такая нейронная сеть может выделить часть документа (e.g. страницы интернет-магазина), в которой речь идёт именно о нужном пользователю товаре. Остальные части тоже могут быть учтены, но их влияние на результат будет меньше. Трансформеры могут хорошо выучивать сложные зависимости между словами и активно используются для генерации естественных текстов в таких задачах, как перевод и ответы на вопросы (англ. question answering). Поэтому в Яндексе они применяются уже достаточно давно. В первую очередь, конечно, в Яндекс.Переводчике.

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

Transformers + transfer learning

Глубокие нейронные сети достаточно требовательны к объёму примеров для обучения. Если данных мало, то никакого выигрыша от применения тяжёлой архитектуры не получится. При этом практических задач всегда много, и они несколько отличаются друг от друга. Собрать миллиарды примеров для каждый задачи просто невозможно: не хватит ни времени, ни бюджета. На помощь снова приходит подход transfer learning. Как мы уже разобрались на примере feed-forward-сетей, суть в том, чтобы переиспользовать информацию, накопленную в рамках одной задачи, для других задач. В Яндексе этот подход применяется повсеместно, особенно он хорош в компьютерном зрении, где обученная на поиске изображений базовая модель легко дообучается почти на любые задачи. В трансформерах transfer learning тоже ожидаемо заработал.

В 2018-м команда OpenAI показала, что если обучить трансформер на сыром корпусе текстов большого размера в режиме языковой модели, а затем дообучать модель на малых данных для конкретных задач, то результат оказывается существенно лучше, чем раньше. Так родился проект GPT (Generative Pre-trained Transformer). Похожая идея чуть позже легла в основу проекта BERT (Bidirectional Encoder Representations from Transformers) от Google.

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

Трансформеры в поиске Яндекса

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

Для иллюстрации приведу несколько результатов из наших экспериментов. Давайте возьмём открытую модель BERT-Base Multilingual и обучим на наши экспертные оценки. Можно измерить полезность такого трансформера как дополнительного фактора в задаче ранжирования; получим статистически значимое уменьшение ошибки предсказания релевантности на 3-4%. Это хороший фактор для ранжирования, который мы бы немедленно внедрили, если бы он не требовал применения 12-слойного трансформера в рантайме. Теперь возьмём вариант модели BERT-Base, который мы обучили с нуля, и получим уменьшение ошибки предсказания почти на 10%, то есть более чем двукратный рост качества по сравнению с ванильной версией, и это далеко не предел. Это не значит, что модель Multilingual от Google низкого качества. С помощью открытых моделей BERT уже было получено много интересных результатов в разных задачах NLP (Natural Language Processing, то есть в задачах обработки текстов на естественном языке). Но это значит, что она плохо подходит для ранжирования веб-страниц на русском языке.

Первая трудность, которая возникает на пути к обучению своего трансформера, это вычислительная сложность задачи. Новые модели хорошо масштабируются по качеству, но при этом в миллионы раз сложнее, чем те, которые применялись в поиске Яндекса раньше. Если раньше нейронную сеть удавалось обучить за один час, то трансформер на таком же графическом ускорителе Tesla v100 будет учиться 10 лет. То есть без одновременного использования хотя бы 100 ускорителей (с возможностью быстрой передачи данных между ними) задача не решается в принципе. Необходим запуск специализированного вычислительного кластера и распределённое обучение на нём.

Нам потребовалось немного времени, пара сотен GPU-карт, место в одном из дата-центров Яндекса и классные инженеры. К счастью, всё это у нас было. Мы собрали несколько версий кластера и успешно запустили на нём обучение. Теперь модель одновременно обучается примерно на 100 ускорителях, которые физически расположены в разных серверах и общаются друг с другом через сеть. И даже с такими ресурсами на обучение уходит около месяца.

Несколько слов про само обучение. Нам важно, чтобы получившаяся модель решала с оптимальным качеством именно задачу ранжирования. Для этого мы разработали свой стек обучения. Как и BERT, модель сначала учится свойствам языка, решая задачу MLM (Masked Language Model), но делает это сразу на текстах, характерных для задачи ранжирования. Уже на этом этапе вход модели состоит из запроса и документа, и мы с самого начала обучаем модель предсказывать ещё и вероятность клика на документ по запросу. Удивительно, но тот же самый таргет переформулировок, который был разработан ещё для feed-forward-сетей, отлично показывает себя и здесь. Обучение на клик существенно увеличивает качество при последующем решении семантических задач ранжирования.

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

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

Итак, мы научились обучать модели в офлайне, но вот работать им уже нужно в онлайне, то есть в реальном времени в ответ на тысячи пользовательских запросов в секунду. Тут заключается вторая принципиальная трудность. Применение трансформера это тяжелая для рантайма задача; модели такой сложности можно применять только на GPU-картах, иначе время их работы окажется чрезмерным и легко может превысить время работы всего поиска. Потребовалось разработать с нуля и развернуть несколько сервисов для быстрого применения (инференса, англ. inference) трансформеров на GPU. Это новый тип инфраструктуры, который до этого не использовался в поиске.

Непосредственно для применения мы доработали внутреннюю библиотеку для инференса трансформеров, которая разработана нашими коллегами из Яндекс.Переводчика и, по нашим замерам, как минимум не уступает другим доступным аналогам. Ну и конечно, всё считается в FP16 (16-битное представление чисел с плавающей точкой).

Однако, даже с учетом использования GPU и оптимизированного кода для инференса, модель с максимальным уровнем качества слишком большая для внедрения в рантайм поиска. Для решения этой проблемы есть классический приём knowledge distillation (или dark knowledge). В Яндексе мы используем менее пафосный термин пародирование. Это обучение более простой модели, которая пародирует поведение более сложной, обучаясь на её предсказания в офлайне.

В результате пародирования сложность модели удаётся уменьшить в разы, а потери качества остаются в пределах ~10%.

Это не единственный способ оптимизации. Мы также научились делать многозадачные модели, когда одна модель подражает сразу нескольким сложным моделям, обученным на разные задачи. При этом суммарная полезность модели для ранжирования существенно возрастает, а её сложность почти не увеличивается.

Если же хочется добиться максимального качества, то возможностей одной дистилляции недостаточно. Приходится поделить модель на несколько частей, каждая из которых применяется независимо. Часть модели применяется только к запросу; часть только к документу; а то, что получилось, затем обрабатывается финальной связывающей моделью. Такой метод построения раздельной или split-модели распределяет вычислительную нагрузку между разными компонентами системы, что позволяет сделать модель более сложной, увеличить размер её входа и заметно повысить качество.

Внедрение split-модели опять приводит нас к новым и интересным инженерным задачам, но рассказать обо всём в одном посте, увы, невозможно. Хотя архитектура нейросетей-трансформеров известна уже достаточно давно, а их использование для задач NLP приобрело огромную популярность после появления BERT в 2018 году, внедрение трансформера в современную поисковую систему невозможно без инженерной изобретательности и большого числа оригинальных технологических улучшений в обучении и рантайме. Поэтому мы назвали нашу технологию YATI Yet Another Transformer (with Improvements), что, как нам кажется, хорошо отражает её суть. Это действительно ещё один трансформер, архитектурно похожий на другие модели (а их в последние годы появилось великое множество), но уникальный тем, что благодаря совокупности улучшений он способен работать и приносить пользу в поиске самом сложном сервисе Яндекса.

Итоги

Что в итоге? У нас появилась своя инфраструктура обучения и дистилляции тяжёлых моделей, адаптированная под наш стек задач ранжирования. С её помощью мы сначала обучили большие модели-трансформеры высокого качества, а затем дистиллировали их в многозадачную split-модель, которая внедрена в рантайм на GPU в виде нескольких частей, независимо применяемых к запросу и документу.

Это внедрение принесло нам рекордные улучшения в ранжировании за последние 10 лет (со времён внедрения Матрикснета). Просто для сравнения: Палех и Королёв вместе повлияли на поиск меньше, чем новая модель на трансформерах. Более того, в поиске рассчитываются тысячи факторов, но если выключить их все и оставить только новую модель, то качество ранжирования по основной офлайн-метрике упадёт лишь на 4-5%!

В таблице ниже сравнивается качество нескольких нейросетевых алгоритмов в задаче ранжирования. % NDCG это нормированное значение обычной метрики качества DCG по отношению к идеальному ранжированию на нашем датасете. 100% означает, что модель располагает документы в порядке убывания их истинных офлайн-оценок. Худший результат ожидаемо даёт подход предыдущего поколения, то есть просто обучение feed-forward-сети на кликовый таргет. Дообучение готовых моделей BERT существенно проигрывает по качеству специализированной версии, которая показывает рекордный результат в 95,4% сравнимо с качеством дистилляции YATI в feed-forward-сеть. Все модели, кроме первой, дообучались на одном и том же множестве экспертных оценок.

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

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

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

Подробнее..

Маленький и быстрый BERT для русского языка

10.06.2021 02:22:28 | Автор: admin

BERT нейросеть, способная весьма неплохо понимать смысл текстов на человеческом языке. Впервые появивишись в 2018 году, эта модель совершила переворот в компьютерной лингвистике. Базовая версия модели долго предобучается, читая миллионы текстов и постепенно осваивая язык, а потом её можно дообучить на собственной прикладной задаче, например, классификации комментариев или выделении в тексте имён, названий и адресов. Стандартная версия BERT довольно большая: весит больше 600 мегабайт, обрабатывает предложение около 120 миллисекунд (на CPU). В этом посте я предлагаю уменьшенную версию BERT для русского языка 45 мегабайт, 6 мс на предложение. Уже есть tinybert для английского от Хуавея, есть моя уменьшалка FastText'а, а вот маленький (англо-)русский BERT, кажется, появился впервые. Но насколько он хорош?

Дистилляция путь к маленькости

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

Если очень коротко, то BERT работает так: сначала токенизатор разбивает текст на токены (кусочки размером от одной буквы до целого слова), от них берутся эмбеддинги из таблицы, и эти эмбеддинги несколько раз обновляются, используя механизм self-attention для учёта контекста (соседних токенов). При предобучении классический BERT выполняет две задачи: угадывает, какие токены в предложении были заменены на специальный токен [MASK], и шли ли два предложения следом друг за другом в тексте. Как потом показали, вторая задача не очень нужна. Но токен [CLS], который ставится перед началом текста и эмбеддинг которого использовался для этой второй задаче, употреблять продолжают, и я тоже сделал на него ставку.

Дистилляция способ перекладывания знаний из одной модели в другую. Это быстрее, чем учить модель только на текстах. Например, в тексте [CLS] Ехал Грека [MASK] реку "верное" решение поставить на место маски токен через, но большая модель знает, что токены на, в, за в этом контексте тоже уместны, и это знание полезно для обучения маленькой модели. Его можно передать, заставляя маленькую модель не только предсказывать высокую вероятность правильного токена через, а воспроизводить всё вероятностное распределение возможных замаскированных токенов в данном тексте.

В качестве основы для модели я взял классический bert-multilingual (веса), ибо хочу, чтобы модель понимала и русский, и английский, и его же использую на ранних стадиях дистилляции как учителя по распределению токенов. Словарь этой модели содержит 120К токенов, но я отобрал только те, которые часто встречаются в русском и английском языках, оставив 30К. Размер эмбеддинга я сократил с 768 до 312, число слоёв с 12 до 3. Эмбеддинги я инициализировал из bert-multilingual, все остальные веса случайным образом.

Поскольку я собираюсь использовать маленький BERT в первую очередь для классификации коротких текстов, мне надо, чтобы он мог построить хорошее векторное представление предложения. Поэтому в качестве учителей для дистилляции я выбрал модели, которые с этим здорово справляются: RuBERT (статья, веса), LaBSE (статья, веса), Laser (статья, пакет) и USE (статья, код). А именно, я требую, чтобы [CLS] эмбеддинг моей модели позволял предсказать эмбеддинги предложений, полученные из этих трёх моделей. Дополнительно я обучаю модель на задачу translation ranking (как LaBSE). Наконец, я решил, что неплохо было бы уметь полностью расшифровывать предложение назад из CLS-эмбеддингов, причём делать это одинаково для русских и английских предложений как в Laser. Для этих целей я примотал изолентой к своей модели декодер от уменьшенного русского T5. Таким образом, у меня получилась многозадачная модель о восьми лоссах:

  • Обычное предсказание замаскированных токенов (я использую full word masks).

  • Translation ranking по рецепту LaBSE: эмбеддинг фразы на русском должен быть ближе к эмбеддингу её перевода на английский, чем к эмбеддингу остальных примеров в батче. Пробовал добавлять наивные hard negatives, но заметной пользы они не дали.

  • Дистилляция распределения всех токенов из bert-base-multilingual-cased (через несколько эпох я отключил её, т.к. она начала мешать).

  • Приближение CLS-эмбеддингов (после линейной проекции) к эмбеддингам DeepPavlov/rubert-base-cased-sentence (усреднённым по токенам).

  • Приближение CLS-эмбеддингов (после другой линейной проекции) к CLS-эмбеддингам LaBSE.

  • Приближение CLS-эмбеддингов (после третьей проекции) к эмбеддингам LASER.

  • Приближение CLS-эмбеддингов (после ещё одной проекции) к эмбеддингам USE.

  • Расшифровка декодером от T5 предложения (на русском) из последней проекции CLS-эмбеддинга.

Скорее всего, из этих лоссов больше половины можно было безболезненно выкинуть, но ресурсов на ablation study я пока не нашёл. Обучал я это всё в течении нескольких дней на Colab, по пути нащупывая learning rate и другие параметры. В общем, не очень научно, но дешево и результативно. В качестве обучающей выборки я взял три параллельных корпуса англо-русских предложений: от Яндекс.Переводчика, OPUS-100 и Tatoeba, суммарно 2.5 млн коротких текстов. Весь процесс создания модели, включая некоторые неудачные эксперименты, содержится в блокноте. Сама модель, названная мною rubert-tiny (или просто Энкодечка), выложена в репозитории Huggingface.

И как этим пользоваться?

Если у вас есть Python и установлены пакет transformers и sentencepiece, скачать и запустить модель просто. Например, вот так вы можете получить 312-мерный CLS-эмбеддинг предложения.

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

Насколько быстр и мал мой Энкодечка? Я сравил его с другими BERT'ами, понимающими русский язык. Скорость указана в расчёте на одно предложение из Лейпцигского веб-корпуса русского языка.

Модель

Скорость (CPU)

Скорость (GPU)

Вес на диске

cointegrated/rubert-tiny

6 мс

3 мс

45 мб

bert-base-multilingual-cased

125 мс

8 мс

680 мб

DeepPavlov/rubert-base-cased-sentence

110 мс

8 мс

680 мб

sentence-transformers/LaBSE

120 мс

8 мс

1.8 гб

sberbank-ai/sbert_large_nlu_ru

420 мс

16 мс

1.6 гб

Все расчёты я выполнял на Colab (Intel(R) Xeon(R) CPU @ 2.00GHz и Tesla P100-PCIE c батчом размера 1 (если использовать крупные батчи, то ускорение на GPU ещё заметнее, т.к. с маленькой моделью можно собрать более большой батч).

Как видим, rubert-tiny на CPU работает раз в 20 быстрее своих ближайших соседей, и легко помещается на бюджетные хостинги типа Heroku (и даже, наверное, на мобильные устройства). Надеюсь, эта модель сделает предобученные нейросети для русского языка в целом более доступными для прикладных применений. Но надо ещё убедиться, что модель хоть чему-то научилась.

Оценка качества эмбеддингов

Рекомендованный и проверенный временем рецепт использования BERT дообучать его на конечную задачу. Но дообучение процесс небыстрый и наукоёмкий, а гипотезу об осмысленности выученных эмбеддингов хочется проверить побыстрее и попроще. Поэтому я не дообучаю модели, а использую их как готовые feature extractors, и обучаю поверх их эмбеддингов простые модели логистическую регрессию и KNN.

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

STS: бенчмарк по семантической близости предложений (переведённый с английского). Например, фразы "Кошка спит на фиолетовой простыне" и "Черно-белый кот спит на фиолетовом одеяле" из этого датасета оценены на 4 из 5 баллов сходства. Качество моделей на нём я мерял ранговой корреляций этих баллов с косинусной близостью эмбеддингов предложений. Для наилучшей модели, LaBSE, корреляция оказалась 77%, для моей 65%, на одном уровне с моделью от Сбера, которая в 40 раз больше моей.

Paraphraser: похожий бенчмарк по семантической близости, но с чисто русскими новостными заголовками и трёхбалльной шкалой. Эту задачу я решил так: обучил поверх косинусных близостей логистическую регрессию, и ей предсказывал, к какому из трёх классов пара заголовков относится. На этом бенчмарке моя модель выдала точность 43% и победила все остальные (впрочем, с небольшим отрывом).

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

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

OKMLCup: детекция токсичных комментариев из Одноклассников. Тут моя модель заняла четвёртое место по ROC AUC, обогнав только bert-base-cased-multilingual.

Inappropriateness: детекция сообщений, неприятных для собеседника или вредящих репутации. Тут моя модель оказалась на последнем месте, но таки набрала 68% AUC (у самой лучшей, Сберовской, вышло 79%).

Классификация интентов: накраудсоршенные обращения к голосовому помощнику, покрывающие 18 доменов и 68 интентов. Они собирались на английском языке, но я перевёл их на русский простой моделькой. Часть переводов получились странными, но для бенчмарка сойдёт. Оценивал я по точности логистической регрессии или KNN (что лучше). LaBSE набрала точность 75%, модель от Сбера 68%, от DeepPavlov 60%, моя 58%, мультиязычная 56%. Есть, куда расти.

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

factRuEval-2016: задача распознавания классических именованных сущностей (адреса, организации, личности). Я обучал логистическую регрессию поверх эмбеддингов токенов, а качество мерял макро F1 скором (относительно токенов же, что не вполне корректно). Оказалось, что на таком NER моя модель работает откровенно плохо: она набрала скор 43%, остальные 67-69%.

RuDReC: распознавание медицинских именованных сущностей. Тут моя модель тоже проиграла остальным, но с меньшим отрывом: 58% против 62-67%.

Для всех задач, кроме NER, я пробовал для каждой модели два вида эмбеддингов: из CLS токена и усреднённые по всем токенам. Для меня было неожиданностью, что на многих задачах и моделях эмбеддинг СLS-токена оказывался даже лучше, чем средний (в целом, у него так себе репутация). Поэтому рекомендую не лениться и пробовать оба варианта. Код и результаты моей оценки можно взять из этого блокнота, но лучше подождать, пока я ещё причешу этот бенчмарк.

По итогам оценки оказалось, что модель LaBSE очень крутая: она заняла первое место на 6 из 10 задач. Поэтому я решил выложить LaBSE-en-ru, у которой я отрезал эмбеддинги всех 99 языков, кроме русского и английского. Модель похудела с 1.8 до 0.5 гигабайт, и, надеюсь, таким образом стала чуть более удобной для практического применения. Ну а rubert-tiny оказался по качеству в целом близок к моделям от DeepPavlov и Sber, будучи при этом на порядок меньше и быстрее.

Заключение

Я обещал сделать компактную модель для эмбеддингов русских предложений, и я это наконец сделал. Процесс дистилляции, скорее всего, я настроил неоптимально, и его ещё можно сильно улучшать, но уже сейчас маленькая модель на некоторых задачах приближается к уровню своих учителей и даже иногда обходит его. Так что если вам нужен маленький и быстрый BERT для русского языка, то пользуйтесь: https://huggingface.co/cointegrated/rubert-tiny.

Впереди работы много: с одной стороны, хочется обучить маленький BERT решать задачи из RussianSuperGLUE (и не только), с другой затащить в русский язык хорошие небольшие модели для контролируемой генерации текста (я уже начал делать это для T5). Посему лайкайте данный пост, подписывайтесь на мой канал про NLP, подкидывайте в комментариях и в личке интересные задачи, и, если у вас доведутся руки попробовать rubert-tiny, то обязательно оставляйте обратную связь!
Мне и самому интересно, что будет дальше.

Подробнее..

Перевод Когда в лотерею играет BERT, все билеты выигрывают

08.02.2021 18:21:29 | Автор: admin


Спустя два года после того как BERT был представлен миру, трансформеры по-прежнему доминируют в списках лидеров и породили многочисленные последующие исследования.

Первая версия нашей попытки обзора литературы по BERT (Rogers et al., 2020) содержала обзор около 40 статей в феврале 2020 года. К июню их было более сотни.

Окончательная версия TACL c достаточно хорошим внешним видом содержит около 150 цитат, связанных с BERT, и нет никаких иллюзий завершённости: в августе 2020 года у нас закончились отведённые для журнала страницы.

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



Многие исследования показывают, что BERT имеет много информации о языке, что должно объяснить его высокую производительность. Однако большинство аналитических работ BERT сосредоточены на различных типах зондов: прямых исследованиях модели замаскированного языка или различных задачах (POS-разметка, NER, синтаксический анализ и т. д.), для которых контролируемый классификатор обучается поверх полного BERT или его части. Первый на самом деле мало что говорит нам о тонко настроенном BERT, как он чаще всего используется, а второй добавляет дополнительные параметры, что затрудняет однозначное приписывание базовым представлениям BERT. Кроме того, теперь ясно, что многие текущие наборы данных НЛП имеют всевозможные предубеждения и артефакты, и BERT действительно их использует.

Недавняя работа даёт подсказки для альтернативного направления исследований:

  • Гипотеза лотерейного билета предполагает, что случайно инициализированные нейронные сети содержат подсети, которые могут быть повторно обучены отдельно, чтобы достичь (а иногда и превысить) производительности полной модели;
  • Большинство параллельных проходов через механизм самонаблюдения BERT можно обрезать на основе оценок важности, полученных из градиентов модели;
  • Для моделей Base-Transformer, обученных машинному переводу, последние упрощённые параллельные проходы самонаблюдения, как правило, имеют синтаксические функции.

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

В совместном проекте с Sai Prasanna (Zoho) и Anna Rumshisky (UMass Lowell) мы обнаружили, что неструктурированная обрезка весов BERT, основанная на их величине, согласуется с прогнозами основной гипотезы лотерейных билетов и даёт стабильные подсети. Однако обрезка параллельных проходов и MLP на основе оценок их важности не даёт хороших подсетей, согласованных при инициализациях тонкой настройки или даже при выполнении аналогичных задач (что указывает на согласованные стратегии рассуждений). Эти подсети также не содержат преимущественно параллельных проходов самонаблюдения, которые кодируют потенциально интерпретируемые паттерны. Для большинства задач GLUE хорошие подсети можно переобучить, чтобы достичь производительности, близкой к производительности полной модели, но то же самое можно сделать и для подсетей того же размера, выбранных случайным образом. Это хорошая новость для сжатия BERT (это лотерея, в которой нельзя проиграть), но плохая новость для интерпретируемости.

Обрезка BERT


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

Классическая гипотеза лотерейного билета в основном проверялась с помощью неструктурированной обрезки, в частности обрезки по величине (m-обрезки), при котором веса с наименьшей величиной обрезаются независимо от их положения в модели. Мы итеративно сокращаем 10 % весов с наименьшей величиной по всей тонко настроенной модели (кроме векторных представлений) и оцениваем на наборе для разработки до тех пор, пока производительность обрезанной подсети составляет более 90 % производительности полной модели.

Мы также экспериментируем со структурированной обрезкой (s-обрезкой) целых компонентов архитектуры BERT на основе их оценок важности: в частности, мы удаляем наименее важные параллельные проходы самонаблюдения и MLP, применяя маску. На каждой итерации мы удаляем 10 % проходов BERT и 1 MLP, пока производительность обрезанной подсети это более 90 % производительности полной модели. Чтобы определить, какие проходы и MLP нужно обрезать, мы используем аппроксимацию, основанную на потерях: оценки важности, предложенные Michel, Levy and Neubig (2019) для проходов самонаблюдения, которые мы распространяем на MLP. Пожалуйста, ознакомьтесь с нашей статьёй и оригинальной формулировкой, чтобы узнать больше.

Для обоих методов маски определяются по отношению к полной производительности модели на конкретном наборе данных. Мы заинтересованы найти подсети, которые позволят BERT эффективно выполнять полный набор из 9 задач GLUE. Наборы тестов GLUE не общедоступны, и мы используем наборы для разработки как для поиска масок обрезки, так и для тестирования модели. Поскольку нас интересуют стратегии рассуждений BERT, а не обобщение, этот подход позволяет нам увидеть лучшие и худшие возможные подсети для этих конкретных данных.

Насколько стабильны хорошие подсети при случайной инициализации?


Недавняя работа показала, что существует значительная разница в производительности BERT при случайных инициализациях слоя, который специфичен для конкретной задачи (Dodge et al., 2020), до такой степени, что разные инициализации приводят к резко различающейся производительности обобщения.

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

Пример хорошей подсети: два метода обрезки выбирают очень разные подсети.

Ясно, что подсети с m-обрезкой довольно стабильны (стандартное отклонение обычно около 0,01). Но этого нельзя сказать о s-обрезке: есть несколько параллельных проходов, которые особенно живучи (супер-выжившие) (т. е. они выживают во всех случайных данных инициализации), а некоторые после обрезки не выживают никогда, но примерно для 70 % параллельных проходов самонаблюдения стандартное отклонение находится в диапазоне 0,450,55. Каппа Флейсса для масок выживания прохода / MLP для случайных чисел инициализации также низкая, в диапазоне 0,10,3.

Причина этого, по всей видимости, заключается в том, что оценки важности для большинства параллельных проходов самонаблюдения BERT одинаково низкие. Вот пример распределения оценок важности для CoLA на первой итерации обрезки: большинство проходов одинаково не важны, их все можно обрезать с примерно одинаковым эффектом.

Распределение оценок внимания: CoLA, итерация 1. Большинство проходов имеют низкие оценки важности.

Насколько стабильны хорошие подсети при выполнении задач?


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

Кажется, что связанные задачи, с точки зрения хороших подсетей, не всегда имеют больше общего. На следующей диаграмме показано среднее количество общих параллельных проходов самонаблюдения в подсетях для всех пар задач GLUE. Например, QQP и MRPC ближе с точки зрения постановки задач, чем QQP и MNLI, но в хороших подсетях в обоих случаях общие 5255 проходов.

Общие проходы с самонаблюдением в хороших подсетях для задач GLUE: связанные теснее задачи не всегда имеют больше общих проходов (например, QQP/MRPC и QQP/MNLI).

Гипотеза лотерейного билета для BERT?


Мы рассматриваем три экспериментальные установки:

  • Хорошие подсети: элементы, выбранные из полной модели с s- или m-обрезкой;
  • Случайные подсети: элементы, случайно отобранные из полной модели, чтобы соответствовать хорошему размеру подсети;
  • Плохие подсети: элементы, которые не пережили обрезку, плюс несколько элементов, отобранных из оставшихся, чтобы соответствовать хорошему размеру подсети.

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

Мы действительно находим такие подсети в случае m-обрезки: обрезанные и повторно настроенные хорошие подсети достигают полной производительности модели в 8 из 9 задач GLUE (за исключением WNLI, где модель обычно не обучается). Эти результаты согласуются с одновременной работой на обрезке по величине BERT (Chen et al., 2020). Случайные и плохие подсети также обычно работают лучше при повторной настройке, но плохие подсети постоянно хуже случайных.

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

Однако для подсетей с s-обрезкой тенденция иная. Для большинства задач подсети с s-обрезкой достигают не совсем полной производительности модели, хотя для многих задач разница находится в пределах двух баллов. Однако случайные подсети могут быть повторно обучены почти так же, как и хорошие; это согласуется с наблюдением о том, что оценки важности для большинства параллельных проходов одинаково низкие. Что касается плохих подсетей, обратите внимание, что, поскольку мы оцениваем наборы GLUE для разработчиков, которые мы также используем, чтобы выбрать маски, плохие подсети являются наихудшим выбором элементов BERT для этих конкретных данных. Тем не менее даже они остаются легко обучаемыми и в среднем соответствуют базовому уровню biLSTM + GloVe GLUE.

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

Мы сделали из этого следующий вывод: можно сказать, что у s-обрезанного BERT нет проигрышных билетов. Это даёт не совсем полную производительность модели, но для большинства задач GLUE случайное подмножество полной модели работает почти так же хорошо, как подсеть, выбранная по оценкам важности. Это свидетельствует о том, что либо большинство компонентов BERT избыточны (и в этом случае большинство случайных подмножеств по-прежнему будут содержать одну и ту же информацию), либо существуют реальные различия в информационном содержании различных компонентов, но оценки важности недостаточно чувствительны к ним.

Насколько лингвистически информативны хорошие подсети?


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

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

Типы паттернов самонаблюдения (Kovaleva et al., 2019)

Поскольку гетерогенный паттерн единственный, который потенциально может кодировать лингвистически интерпретируемые отношения, соотношение проходов самонаблюдения с такими паттернами даёт верхнюю границу интерпретируемых паттернов. Следуя, мы обучаем классификатор CNN на аннотированном вручную наборе из 400 карт самонаблюдения, представленном авторами. Мы также рассматриваем нормированные по весу карты самонаблюдения, которые должны снижать внимание к специальным токенам и для которых мы аннотируем ещё 600 образцов карт наблюдения. Затем мы кодируем 100 примеров из каждой задачи GLUE, генерируем карты наблюдения для каждого прохода BERT и используем наши обученные классификаторы, чтобы оценить, сколько паттернов каждого типа мы получаем. На аннотированных данных классификаторы дают F1 0,81 для необработанных карт наблюдения и 0,74 для карт наблюдения, нормированных по весу.

Мы наблюдаем, что для необработанных карт самонаблюдения супер-выжившие имеют больше блочных и вертикальных + диагональных паттернов, но количество гетерогенных паттернов не увеличивается. В нормированном по весу состоянии соотношение диагональных паттернов уменьшается, но для большинства задач у супер-выживших остается 3040 % диагональных паттернов. В обоих условиях две задачи обнаружения перефразирования (MRPC и QQP) имеют заметное увеличение количества вертикальных паттернов наблюдения, что обычно указывает на внимание к SEP, CLS и пунктуации.

Распределение паттернов самонаблюдения в параллельных проходах супер-выживших. Соотношение потенциально интерпретируемых паттернов самонаблюдения (синий) существенно не меняется в подсетях супер-выживших (слева) по сравнению с полным распределением моделей (справа) ни в исходном, ни в нормированном по весу внимании.

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

Заключение


Как наше исследование, так и параллельная работа (Chen et al., 2020) подтверждают, что гипотеза лотерейного билета верна при использовании обрезки по величине в BERT: хорошие подсети могут быть переобучены для достижения полной производительности модели.
Структурированная обрезка рассказала нам о другом: мы обнаружили, что обрезка большинства подсетей BERT этим методом приводит к аналогичной производительности между хорошими, случайными и плохими сетями и что ни одна из них не может достичь полной производительности исходной сети. Таким образом, можно сказать, что при структурированной обрезке BERT не имеет проигрышных билетов, даже если он не полностью выигрывает.

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

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

Единственное, что мы знаем наверняка, это то, что исследования в BERTology ещё далеки до завершения.

Использованная литература




image



Подробнее..

Как объединить 10 BERT-ов для задач общего понимания текста?

22.07.2020 16:08:14 | Автор: admin

Всем привет! В этом посте я расскажу о проекте, который выполнил совместно с командой Google Brain во время исследовательской стажировки в Цюрихе. Мы работали над моделью обработки естественного языка, которая решает задачи на общее понимание текста (задачи из набора GLUE: General Language Understanding Evaluation).


BERT-подобные модели мы комбинировали с помощью маршрутизирующих сетей и добились того, что при увеличении мощности скорость вывода почти не изменилась. Финальная модель объединяет 10 BERTlarge моделей и имеет более 3,4 миллиарда параметров. Подробности под катом!



Меня зовут Никита Сазанович, я учусь на 2-м курсе магистратуры Программирование и анализ данных в Питерской Вышке. В январе я поехал на 17-недельную стажировку в Google Brain (правда, физически находился в Цюрихе только 11 из них: из-за карантина последние 6 недель пришлось работать удаленно). Мой проект был связан с обработкой естестественного языка с использованием маршрутизирующих сетей а это новое понятие в машинном обучении, с которым мы далее и разберемся.


Начнем издалека


Задачи обработки естественного языка (Natural Language Processing, NLP) включают в себя машинный перевод, распознавание текста, анализ тональности текстов и др. В этой статье мы поговорим про задачи из набора GLUE. Они были разработаны экспертами машинного обучения, чтобы оценивать, насколько модель способна к общему пониманию текста (откуда и название набора: General Language Understanding Evaluation).


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


Рассмотрим одну из них: Quora Question Pairs, или QQP. Как ясно из названия, нужно будет что-то сказать про пару вопросов из сайта Quora. Вопросы необходимо сравнить и сообщить, семантически эквивалентны ли они / является ли один дубликатом другого. Сразу приведу два примера:


1) Вопросы "What are natural numbers?" и "What is a least natural number?" не являются дубликатами.


2) А вопросы "How do you start a bakery?" и "How can one start a bakery business?" семантически эквивалентны.


То есть в этой задаче по тексту двух вопросов просят провести бинарную классификацию: разбить их на два класса. Задачу классификации в машинном обучении решают уже давно и научились это делать хорошо, но не в тех случаях, когда дело касается обработки естественного языка. Можно решить эту проблему, если привести текст к формату, на котором осуществлять классификацию более удобно. Например, преобразовать его в единый числовой вектор, который и послужит входом для классификации! Такой вектор называют представлением языка, а получением таких векторов занимается область обучения представлений языка, или language representation learning.


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


BERT: Теория


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


1) Входное предложение: "Jet makers feud over seat width with big orders at stake".


2) Разбиение на токены (где символ _ приписывается к токенам, с которых слова начинаются): "_J et _makers _fe ud _over _seat _width _with _big _orders _at _stake". Здесь можно видеть, что слов "Jet" и "feud" не оказалось целиком в словаре, поэтому они были разбиты на части, присутствующие в словаре.


В словаре WordPiece содержится несколько десятков тысяч токенов. Большинство слов, которые встречаются наиболее часто, он содержит целиком.


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


В 2017 году был представлен механизм внимания, который умеет учитывать контекст. Еще один плюс механизма в том, что зависимости в обученной модели легко интерпретировать для каждого входного текста. Рассмотрим пример на картинке снизу:



Если мы посмотрим на слово making в предложении It is in this spirit that a majority of American governments have passed new laws since 2009 making the registration or voting process more difficult, мы можем обратить внимание также на слова more difficult, laws, 2009: они помогают понять смысл. В предложении говорится о том, как с 2009 года правительства США принимали законы, которые делают процесс голосования сложнее. В таком контексте представление слова making в механизме внимания формируется в основном из представлений предыдущего слоя для слов making, more и difficult. Математически механизм внимания представляет собой блок модели, который отображает последовательность векторов токенов. При этом блок можно устроить таким образом, чтобы выходное представление каждого токена формировалось как взвешенная сумма всех представлений токенов с предыдущего слоя. В каком-то смысле у каждого слова есть ограниченное внимание, которое оно разделяет между всеми словами предыдущего слоя.


В той же статье авторы показали модель, которая состояла из нескольких последовательных блоков с механизмом внимания, и назвали ее Трансформер.


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


Вернемся к вопросу представления текста. Допустим, после каких-то преобразований мы получили последовательность векторов $z_1$, $z_2$, ..., $z_{n_i}$ для токенов текста $x_1$, $x_2$, ..., $x_{n_i}$. Как теперь проводить классификацию или регрессию на всем тексте? В BERT модели предлагают элегантное решение: к каждой последовательности токенов добавить токен $x_0$ и получить по нему представление $z_0$ описанным выше способом. Благодаря специальному устройству функции обучения оно будет представлять информацию, которая содержится во всем тексте. Для более подробного устройства можно обратиться к самой статье о BERT.


Ниже я расскажу о том, как эти BERT-подобные модели можно комбинировать с помощью нового для машинного обучения понятия маршрутизирующих сетей при решении набора задач GLUE. Под BERT-подобными моделями мы будет подразумевать BERTы, которые имеют разные гиперпараметры и/или обучены на отличном от оригинального датасете (примеры таких моделей).


Маршрутизирующие сети


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


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


Формулировать и обучать процесс маршрутизации можно по-разному. К примеру, в статье по ссылке для каждой возможности маршрутизации задачи через модуль модели использовалось распределение Бернулли, которое обучалось с помощью Gumbel Softmax. Ниже вы можете видеть пример такой модели с двумя задачами. Цветами отмечено, какое подмножество модулей используется для каждой из них: красным обозначены модули, которые вычисляются на маршруте для первой задачи, синим для второй, а фиолетовым для обеих. Если в одном слое таких модулей для одной задачи несколько, нужна агрегация результатов, например, усреднение. Наличие общих модулей и позволяет задачам совместно обучать модули, которые выгодно разделять.



Как видно на картинке, модули этой сети состоят из сверточных слоев (Conv 3x3, Conv 5x5, Conv 7x7). Значит, задачи относились к области компьютерного зрения. А что если в качестве таких модулей мы будем использовать BERT-подобные модели и попытаемся искать маршруты для задач из набора GLUE? Это и стало идеей для моего проекта.


Маршрутизация и процесс тренировки


На вход модель получает токенизированный текст (x) и числовой идентификатор задачи (t), который превращается в вектор представления задачи. Используя этот вектор, маршрутизатор выбирает набор модулей/экспертов для задачи, которым подается на вход токенизированный текст x. После обработки экспертами происходит агрегация результатов и получается представление текста. Затем представление направляется в небольшую сеть (отдельную для каждой задачи t), которая преобразует представление к ответу задачи (регрессии или классификации). Стоит также заметить, что для задач GLUE эксперты инициализируются предобученными моделями.



Представления задач моделируются как вектора размерности M (в экспериментах M было равно 10):


$v_t\ для\ t = [1, .., T],\ где\ T - число\ задач \\ v_t\in R^M,\ где\ M - размерность\ представлений$


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


$G(v) = Softmax(KeepTopK(H(v), k)) \\ KeepTopK(h, k)_i = \begin{cases} h_i & \text{если $h_i$ в k наибольших элементах в h} \\ 0 & \text{иначе} \end{cases} \\ G(v) \in R^N, где\ N - число\ экспертов$


Сами представления языка формируются как взвешенная сумма результатов экспертов, причем эксперту не нужно вычислять результат, если коэффициент равен нулю:


$x \in X_t\ для\ t = [1, .., T] \\ f(x, t) = \sum\limits_{i=1}^{M} G(v_t)_i E_i(x),\ где\ E_i - функция\ i{\text -}ого\ эксперта$


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


Далее под спойлером для любителей описаны технические подробности настройки этой модели. Для полноты картины расскажу про нее в нескольких словах. Лучший результат достигается, если использовать 10 BERT large экспертов, а не трех или одного (из-за затрат времени и ресурсов мы провели эксперименты только для 1, 3 и 10 экспертов). Оптимальное количество путей два. Оптимизировать выгодно стохастическим градиентным спуском с импульсом. При такой настройке модель имеет 3,4 миллиарда параметров и обучать ее пришлось на 24 тензорных процессорах Google.


Детали настройки модели

Процесс тренировки проходит параллельно на батчах из всех задач GLUE и требует какой-то агрегации между задачами. Один из вариантов линейная комбинация потерь $L_t$ каждой из задач:

$L_{total} = \sum\limits_{t=1}^{T} C(t) L_t$


В таблице далее представлены варианты агрегации и соответствующие им GLUE оценки, если в качестве экспертов брать одну модель BERTbase.


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

$L_{total} = \sum\limits_{t=1}^{T} \frac{1}{\mathcal{N}} |D_t|^p L_t$


то можно было достичь GLUE оценки в 80.06 при значении p=0.3. Я использую такую агрегацию функций потерь каждой из задач в дальнейших экспериментах по настройке модели.

Важным элементов при масштабировании модели является метод оптимизации, так как он увеличивает размер необходимой памяти, тем самым уменьшая мощность модели при фиксированном бюджете. Я проверил 6 оптимизаторов: Adam, Adam с weight decay (угасание весов к нулю), LAMB, LAMB с weight decay, стохастический градиентный спуск (SGD) и стохастический градиентный спуск с импульсом (SGDM). SGD практически не расходует дополнительной памяти, SGDM запоминает импульсы для каждой переменной, поэтому расходует x2 памяти, а остальные рассмотренные оптимизаторы расходуют x3 памяти. Результаты оптимизации маршрутизируемого BERT-а с одним BERTlarge экспертом можно видеть в таблице. SGDM достигает лучшего результата в исследуемом пространстве, при этом используя лишь в два раза больше памяти. Я использую его в финальной модели.



Рассматривая зависимость качества от числа BERTlarge экспертов и путей, я заметил, что качество улучшается при увеличении числа экспертов, а при увеличении количества путей не всегда. Лучший результат дало использование 10 экспертов и 2 путей.



В такой модели 10 x 340 миллионов = 3,4 миллиарда параметров, а ее обучение происходило на 24 TPUv2 (тензорных процессорах Google) с параллелизмом по данных равным 4 и параллелизмом модели равным 6. Параллелизм модели равен 6, так как 5 процессоров держат по 2 BERTlarge модели, а еще один отвечает за все сети задач после агрегации.


Анализ результатов


Для сравнения результатов в наборе GLUE был предложен способ комплексной оценки, который совмещает результаты на каждой из задач набора. Эта оценка лежит в диапазоне от 0 (все неверно) до 100 (идеальные ответы). Я сравнил маршрутизируемый BERT с опубликованными результатами мультизадачного обучения BAM! (оно основано на дистилляции) и настройкой одного BERTа под каждую задачу. Маршрутизируемый BERT достиг лучшей оценки общего понимания языка.


Интересны также различия между результатами на задачах. Например, выгоду при тренировке с маршрутизируемыми сетями получает задача RTE, которая имеет наименьший тренировочный набор (2,5 тысячи примеров). Сравните ее оценки в 1-й и 3-й строках. Эта выгода на задаче достигается засчет использования дополнительных знаний из других задач, тренировочный набор которых больше по размеру.



Еще один результат этой модели возможность исследовать отношения между задачами. Ниже представлен результат сокращения размерности векторов для представлений задач. Вектора, которые изначально находятся в 10-мерном пространстве (M=10), сокращены до векторов размера 2, т. е. точек. Это сделано при помощи метода t-SNE, который очень популярен для таких визуализаций и про который можно почитать в другом блоге на Хабре. Здесь каждая из задач располагается на плоскости, а расстояние между ними позволяет судить о том, насколько они близки с точки зрения маршрутизатора. Как и ожидалось, mnli-m и mnli-mm задачи с одним и тем же тренировочным набором располагаются близко. Так же близко расположены sst-2 и qqp, cola и rte пары, сходство которых отмечали и другие исследователи.



Итоги


В результате мы разобрались, как можно использовать маршрутизирующие сети для обучения представлений языка. С их помощью мы улучшили результат работы исходной модели с точки зрения оценки GLUE на 1,75 пункта и в качестве бонуса смогли визуализировать отношения между задачами набора. Важное свойство такого подхода сохранение скорости вывода в конечной модели. Было бы интересно продолжить работу над проектом, использовав разнородных экспертов с одинаковым интерфейсом (таких как ALBERT и RoBERTa), а также добавить к набору задачи предобучения представлений (таких как MLM BERT-а) для тренировки сети с нуля без использования предобученных моделей.


Код этой модели остался в Google, но могу сказать, что написан он был на любимом в компании TensorFlow.

Подробнее..

Модерация текста уроки этикета от Data Scientista

02.09.2020 20:13:34 | Автор: admin
Привет, Хабр!

С этой статьи мы начинаем публикацию серии статей про Data Science задачи, которые мы решаем в Центре Развития Финансовых Технологий Россельхозбанка.

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



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

Что делали?


В этой статье мы расскажем о том, как в рамках сотрудничества с Лабораторией МФТИ, специально созданной под задачи Банка, разработали инструмент, позволяющий с высокой точностью премодерировать текстовый контент.

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

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

Мы ожидаем, что разработанный нами алгоритм будет принимать на вход набор текстов и выдавать число от 0 до 1 степень или вероятность токсичности текста. Чем ближе это число к единице, тем токсичнее комментарий.

Надо отметить, что задача детектирования токсичных текстов совершенно не новая и является довольно популярной в англоязычном сегменте. Несколько лет назад похожая задача решалась в рамках соревнования Toxic Comment Classification Challenge на Kaggle. Для русского языка решение должно получаться аналогичным образом, но качество модели может оказаться ниже из-за того, что русский язык структурно сложнее английского.

В открытом доступе есть всего один размеченный русскоязычный датасет для поиска токсичности в тексте. Также нам удалось найти датасет для поиска оскорблений (частный случай токсичности). Плюс ко всему, мы собрали примеры объявлений с сельскохозяйственных порталов и разметили их как приемлемые (класс 0).

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

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

Как делали?


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

Общая схема




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

Теперь давайте рассмотрим каждую компоненту подробнее.

Наивный классификатор


Здесь все совсем просто: по словарю обсценной лексики довольно легко понять, содержится ли в тексте то или иное плохое слово или нет.

То есть на данном этапе можно даже обойтись без ML-модели как таковой и сразу отсеять тексты, в которых есть плохие слова. Но что, если в тексте таких словарных слов не используют, но текст, тем не менее, является неприемлемым для размещения на портале? Попробуем решить эту задачу с помощью логистической регрессии и BERTa.

Логистическая регрессия


Простейшая модель позволяет предсказывать значение, на основе имеющихся данных. Вектора текстов для данной модели получаются при помощи TF-IDF и TweetTokenizerа из nltk. Такая модель, как известно, позволяет оценить вероятность токсичности текста с помощью логистической функции. В нашей архитектуре логистическая регрессия страхует нейросеть.

Великий и ужасный BERT


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


Мы строили-строили и наконец построили!


Качество мы оценивали излюбленными метриками Accuracy, ROC-AUC и F1-мера. Итоговые метрики качества на отложенной выборке получились следующими:

Алгоритм / Метрика
Naive
BERT
LR
Naive BERT
Naive LR
Accuracy
0.854
0.901
0.865
0.909
0.879
ROC-AUC
0.782
0.960
0.921
0.963
0.939
F1-мера
0.722
0.840
0.800
0.855
0.824

Скорость работы: ~2800 текстов в минуту на GPU (GeForce 1080Ti) в случае отработки BERTа, как самого медленного алгоритма из представленных.

Как и ожидалось, c BERTом метрики получились чуть лучше, хоть и не сильно.

Какие мы сделали выводы


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

  1. Всегда нужно учитывать специфику задачи, касательно разметки текстов.
  2. Необходимо предусмотреть ручную модерацию текста, в случае, когда модель сомневается в своем решении. Вы же не хотите, чтобы неприемлемый контент в итоге присутствовал в вашем продукте.
  3. Также необходимо отправлять размеченные руками тексты из предыдущего пункта на дообучение. Таким образом можно маленькими шагами улучшить модель и уменьшить со временем количество работы при ручной модерации.
  4. Лучше использовать комплексный подход к решению задачи. Иногда даже самые простые модели на словарях уже дают неплохой результат.
  5. Выбирайте лучшую модель исходя из задачи. В нашем случае мы выбрали BERT, так как он лучше логистической регрессии реагирует на контекст.

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

В следующей статье мы поделимся своим опытом при премодерации изображений всё на той же площадке нашей экосистемы Своё Фермерство.
Подробнее..

Перевод Как обучать огромные модели машинного обучения на случайных GPU

11.01.2021 14:11:20 | Автор: admin
Вы можете спросить: почему эти полумагические модели машинного обучения работают так хорошо? Короткий ответ: эти модели чрезвычайно сложны и обучаются на огромном количестве данных. На самом деле, Lambda Labs недавно подсчитала, что для обучения GPT-3 на одном GPU потребовалось бы 4,6 миллиона долларов если бы такое было возможно.

Такие платформы, как PyTorch и Tensorflow, могут обучать эти огромные модели, потому что распределяют рабочую нагрузку по сотням (или тысячам) GPU одновременно. К сожалению, этим платформам требуется идентичность графических процессоров (они должны иметь одинаковую память и вычислительную производительность). Но многие организации не имеют тысячи одинаковых GPU. Малые и средние организации покупают разные компьютерные системы, что приводит к неоднородной инфраструктуре, которую нелегко адаптировать для вычисления больших моделей. В этих условиях обучение моделей даже среднего размера может занимать недели или даже месяцы. Если не принять меры, университеты и другие небольшие организации рискуют потерять конкурентоспособность в погоне за разработкой новых, лучших моделей машинного обучения. Но это можно исправить.

В этом посте представлена предыстория и практические шаги по обучению BERT с нуля в университете с использованием пакета HetSeq. Это адаптация популярного пакета PyTorch, которая предоставляет возможность обучать большие модели нейронных сетей на гетерогенной инфраструктуре.





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

Эксперименты показывают, что систему на базе BERT можно за день обучить с помощью более чем 8 GPU, большинство из которых нам пришлось позаимствовать в неработающих лабораториях. Прежде чем мы представим HetSeq, нужна небольшая предыстория.

Типовое обучение нейронной сети


def train(args):    # main components    dataset = Dataset()    dataloader = DataLoader(dataset)    model = Model()    loss_ = Loss()    optimizer = Optimizer(model.parameters())    # specify the GPU and transfer model to the GPU     device = Device()     model.to(device)    model.train()        # actual training loops    for epoch in range(1, Max_Epoch):        for (data, target) in dataloader:            data, target = data.to(device), target.to(device)   # **load input data and target to GPU**            optimizer.zero_grad()            output = model(data)    # **forward compute the output of model given input data**            loss = loss_(output, target)   # **forward process to compute the real loss function**            loss.backward()    # **backward process to obtain the**            optimizer.step()    # **update parameters** 

Обучение на одном GPU

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

Фактически процесс обучения состоит из четырёх отдельных этапов: (1) загрузка данных, (2) прямой проход, (3) обратный проход, (4) обновление.

1. Загрузка данных


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


Прямой проход с одним GPU

2. Прямой проход


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

3. Обратный проход


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


Параметры обновления с единственным GPU

4. Обновление


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

Краткое описание этапов обучения


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

Что делать, если у нас несколько GPU?


Поскольку пакеты данных независимы друг от друга, довольно просто распараллелить этот процесс, отправив разные пакеты данных на разные GPU. Затем, если мы сможем каким-то образом объединить вычисленные потери и синхронизировать обновлённые параметры модели, тогда получится сделать обучение намного быстрее.

def torch.nn.parallel.DistributedDataParallel(    module,  # pre-defined model    device_ids=None, # input device_ids    output_device=None,  # output device_ids, in our case, input device = output device = single GPU    dim=0,     broadcast_buffers=True, # set to False in our implementation    process_group=None, # Core part    bucket_cap_mb=25,     find_unused_parameters=False,     check_reduction=False)view raw

Класс параллельного распределения данных

Это не новая идея. В PyTorch мы используем для модели модуль torch.nn.parallel.DistributedDataParallel (DDP) вместо модуля torch.nn.Module. Каждый GPU это отдельный процесс, и связь между ними осуществляется с помощью стандартного IPC. Но это ещё не всё. Четыре шага требуют некоторой настройки.

1. Загрузка данных с помощью DDP


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

Это основная идея параллельного распределения данных (DDP): каждый GPU имеет идентичные параметры модели, но одновременно обрабатывает разные пакеты данных.


Прямой проход с несколькими GPU

2. Прямой проход с DDP


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

3. Обратный проход с DDP


Мы используем средние потери для получения градиентов параметров модели при обратном проходе. Прежде чем начать, необходимо сообщить о средних потерях на разные GPU, чтобы параметры модели могли оставаться синхронизированными. Как только одни и те же параметры на разных графических процессорах получают свои градиенты, выполняется синхронизация последних, чтобы они были одинаковы.


Синхронизация градиента

4. Обновление с DDP


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

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

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

def train_multiple_GPUs(args, device_id):    # main components    dataset = Dataset()    dataloader = DataLoader(dataset)    model = DDP(Model())    loss_ = Loss()    optimizer = Optimizer(model.parameters())    device = Device(device_id)     model.to(device)    model.train()        # actual training loops    for epoch in range(1, Max_Epoch):        for (data, target) in dataloader:            data, target = data.to(device), target.to(device)              optimizer.zero_grad()            model.synchronization()    #  parameter synchronization            output = model(data)                loss = loss_(output, target)            loss_average = average(loss)            loss.backward()            model.parameter.grad.average()            optimizer.step()

Обучение на нескольких GPU

Масштабирование несколько узлов с несколькими GPU


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

def torch.distributed.init_process_group(            backend=args.distributed_backend,    # 'nccl' is the best available backend for GPU            init_method=args.distributed_init_method,    # 'tcp' or shared file system            world_size=args.distributed_world_size,  # number of nodes in total            rank=args.distributed_rank, # index of current node        )

К счастью, тот же механизм, который используется для адресации процессоров на одном узле, можно распространить на несколько узлов. Вы можете просто установить индекс узла, то есть параметр rank в функции init_process_group глобально, чтобы каждый GPU имел уникальный идентификатор относительно всех узлов.

Коммуникация вот где возникают сложности



Внутриузловая и межузловая коммуникация

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

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

Когда родители заставляют вас делиться игрушками


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

  1. Некоторые игрушки имеют сложные инструкции. Распределённая параллельная обработка данных пакета (DDP) это боль, трудно понять её и заставить работать. Особенно верно это для большинства исследователей машинного обучения, которые не очень хорошо разбираются в особенностях распределённых вычислений. В дополнение к базовой настройке DDP мирный тренировочный запуск различных архитектур GPU на многих узлах требует тщательного разделения данных и изнурительного налаживания связи между GPU и узлами.
  2. С какими-то игрушками лучше играть лучше, чем с другими. В гетерогенной системе некоторые GPU работают быстрее других, а некоторые имеют больше памяти, чем у других. Это означает, что какие-то процессоры получают больше данных для обработки, чем другие, что прекрасно; но это также означает, что средние значения градиентов и обновления параметров должны тщательно взвешиваться.
  3. Родители не разрешают нам играть с какими-то игрушками. Большинство существующих распределённых обучающих платформ GPU требуют дополнительных пакетов, таких как Docker, OpenMPI и т. д. К сожалению, большинство компетентных администраторов кластеров не позволяют пользователям иметь административные привилегии, необходимые для настройки каждого узла, чтобы обучить модель.
  4. Какие-то игрушки плохо работают с другими. Пакеты глубокого обучения, такие как BERT и GPT2/3, разработанные крупными компаниями, как правило, имеют определённые форматы дизайна модели с несколькими логическими слоями, что затрудняет их использование и адаптацию к приложению.

Из-за этих проблем мы создали общую систему, которая охватывает все сложные части DDP: разделение данных, совместимость и настраиваемость, и развернули эту систему в Нотр-Даме.

Мы называем эту систему HetSeq. Она была адаптирована из популярного пакета PyTorch и обеспечивает возможность обучения больших моделей нейронных сетей в гетерогенной инфраструктуре. Её можно легко настроить через общую файловую систему без дополнительных пакетов и административных привилегий. Вот как обучать BERT с помощью HetSeq.

BERT в университете с HetSeq


Начнём с Anaconda. Создадим виртуальную среду и установим Python.

$ conda create --name hetseq$ conda activate hetseq$ conda install python=3.7.4


Затем мы установим пакеты и привязки HetSeq: загрузим HetSeq с GitHub, установим пакеты из requirements.txt, а также HetSeq и биндинги из setup.py.
$ git clone https://github.com/yifding/hetseq.git $ cd /path/to/hetseq $ pip install -r requirements.txt $ pip install --editable .

Последний шаг перед обучением это загрузка файлов данных BERT, включая корпус обучения, конфигурацию модели и словарь BPE отсюда. Загрузите DATA.zip, распакуйте его и поместите в каталог preprocessing/.

Обучение BERT с помощью HetSeq


Крутая вещь в HetSeq: она абстрагирует все детали о распределённой обработке. Таким образом, код обучения для 100 GPU почти такой же, как для одного! Давайте попробуем!

$DIST=/path/to/hetseq $python3 ${DIST}/train.py  \ $       --task bert   --data ${DIST}/preprocessing/test_128/ \ $       --dict ${DIST}/preprocessing/uncased_L-12_H-768_A-12/vocab.txt  \ $       --config_file ${DIST}/preprocessing/uncased_L-12_H-768_A-12/bert_config.json  \ $       --max-sentences 32  --fast-stat-sync --max-update 900000 --update-freq 4  \ $       --valid-subset test --num-workers 4 \ $       --warmup-updates 10000  --total-num-update 1000000 --lr 0.0001  \ $       --weight-decay 0.01 --distributed-world-size 1  \ $       --device-id 0 --save-dir bert_single_gpu

В этом случае предположим, что у нас есть два вычислительных узла.

На первом узле:

$DIST=/path/to/hetseq $python3 ${DIST}/train.py  \ $       --task bert   --data ${DIST}/preprocessing/test_128/ \ $       --dict ${DIST}/preprocessing/uncased_L-12_H-768_A-12/vocab.txt  \ $       --config_file ${DIST}/preprocessing/uncased_L-12_H-768_A-12/bert_config.json  \ $       --max-sentences 32  --fast-stat-sync --max-update 900000 --update-freq 4  \ $       --valid-subset test --num-workers 4 \ $       --warmup-updates 10000  --total-num-update 1000000 --lr 0.0001  \ $       --weight-decay 0.01 --save-dir bert_node2gpu4  \ $       --distributed-init-method tcp://10.00.123.456:11111 \ $       --distributed-world-size 8 --distributed-gpus 4 --distributed-rank 0

На втором узле:

$DIST=/path/to/hetseq $python3 ${DIST}/train.py  \ $       --task bert   --data ${DIST}/preprocessing/test_128/ \ $       --dict ${DIST}/preprocessing/uncased_L-12_H-768_A-12/vocab.txt  \ $       --config_file ${DIST}/preprocessing/uncased_L-12_H-768_A-12/bert_config.json  \ $       --max-sentences 32  --fast-stat-sync --max-update 900000 --update-freq 4  \ $       --valid-subset test --num-workers 4 \ $       --warmup-updates 10000  --total-num-update 1000000 --lr 0.0001  \ $       --weight-decay 0.01 --save-dir bert_node2gpu4  \ $       --distributed-init-method tcp://10.00.123.456:11111 \ $       --distributed-world-size 8 --distributed-gpus 4 --distributed-rank 4

Два блока кода работают на двух разных узлах. Адрес TCP/IP должен быть установлен как один из IP-адресов узла. Как только они будут запущены, вы сможете наблюдать за выполнением кода на 8 процессорах и 2 разных узлах!

Так насколько хорошо это работает? Мы провели несколько экспериментов (подробности тут) над различными однородными (гомогенными, hom) и неоднородными (гетерогенными, het) установками.

nodes GPUs training_time speed_up
1 4 7.19day 1.00
2(het) 8 4.19day 1.72
2(hom) 8 4.26day 1.69
4(het) 16 2.23day 3.22
4(hom) 16 2.19day 3.28
8(het) 32 1.21day 5.94

В общей сложности мы смогли управлять 32 GPU в 8 неоднородных узлах, сокращая время обучения языковой модели BERT с семи дней до примерно одного дня.

Под капотом HetSeq



Структура пакета HetSeq

Пакет HetSeq содержит три основных модуля, показанных на рисунке слева: train.py, task.py и controller.py для координации основных компонентов, показанных справа. Модуль train.py инициализирует распределённую систему и её различные компоненты.

Модуль task.py определяет функции модели, набора данных, загрузчика данных и оптимизатора; он также выполняет функции прямого и обратного распространения. Модуль controller.py действует как главный контроллер обучения. Он работает как модель, оптимизатор и планировщик скорости обучения; загружает и сохраняет чекпоинты, сообщает о потере и обновляет параметры.
Но я хочу обучить не BERT!

Но я хочу обучить не BERT!


Нет проблем. Вы можете использовать HetSeq с любой другой моделью. Но вам нужно определить новую задачу с соответствующей моделью, набором данных, оптимизатором. и планировщиком скорости обучения. Есть пример MNIST со всеми расширенными классами. Предварительно определённые оптимизаторы, планировщики скорости обучения, наборы данных и модели могут быть повторно использованы в других приложениях. Для получения дополнительной информации ознакомьтесь с пакетом HetSeq и документацией.

image



Подробнее..

Поиск по синонимам контролируем процесс или доверяемся нейросетям

28.01.2021 10:04:30 | Автор: admin
image

Первое что нужно сделать при разработке поисковых, диалоговых и прочих систем, основанных на natural language processing это научиться разбирать тексты пользовательских запросов и находить в них сущности рабочей модели. Задача нахождения стандартных сущностей (geo, date, money и т.д.) в целом уже решена, остается лишь выбрать подходящий NER компонент и воспользоваться его функционалом. Если же вам нужно найти элемент, характерный для вашей конкретной модели или вы нуждаетесь в улучшенном качестве поиска стандартного элемента, придется создать свой собственный NER компонент или обучить какой-то уже существующий под свои цели.

Если вы работаете с системами вроде Alexa или Google Dialogflow процесс обучения сводится к созданию простейшей конфигурации. Для каждой сущности модели вы должны создать список синонимов. Далее в дело вступают нейронные сети. Это быстро, просто, очень удобно, все заработает сразу. Из минусов отсутствует контроль за настройками нейронных сетей, а также одна общая для данных систем проблема вероятностный характер поиска. Все эти минусы могут быть совершенно не важны для вашей модели, особенно если в ней ищется одна-две принципиально отличающиеся друг от друга сущности. Но если элементов модели достаточно много, а особенно если они в чем-то пересекаются, проблема становится более значимой.

Если вы проектируете собственную систему, обучаете и настраиваете поисковые компоненты, например от Apache OpenNlp, Stanford NLP, Google Language API, Spacy или Apache NlpCraft для поиска собственных элементов, забот, разумеется, несколько больше, но и контроль над такой системой заметно выше.

Ниже поговорим о том, как нейронные сети используются при поиске сущностей в проекте Apache NlpCraft. Для начала вкратце опишем все возможности поиска в системе.

Поиск пользовательских сущностей в Apache NlpCraft

При построении систем на базе Apache NlpCraft вы можете использовать следующие возможности по поиску собственных элементов:
  • Встроенные компоненты поиска, основанные на конфигурации синонимов элементов. Пример описания элементов моделей, основанных на синонимах, Synonym DSL т.д. приведены в ознакомительной статье о проекте.
  • Использование любого из вышеупомянутых внешних компонентов, интеграция с ними уже предусмотрена, вы просто подключаете их в конфигурации.
  • Применение составных сущностей. Суть в возможности построения новых NER компонентов на основе уже существующих. Подробнее тут.
  • Самый низкоуровневый вариант программирование и подключение в систему своего собственного парсера. Данная задача сводится к имплементации интерфейса и добавлении его в систему через IoC. На входе реализуемого компонента есть все для написания логики поиска сущностей в запросе: сам запрос и его NLP представление, модель и все уже найденные в тексте запроса другими компонентами сущности. Эта имплементация место для подключения нейросетей, использования собственных алгоритмов, интеграции с любыми внешними системами и т.д., то есть точка полного контроля над поиском.

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

Ниже представлен фрагмент конфигурации модели умный дом (подробнее о макросах и synonym DSL можно прочесть по ссылке).
macros: - name: "<ACTION>"   macro: "{turn|switch|dial|control|let|set|get|put}" - name: "<ENTIRE_OPT>"   macro: "{entire|full|whole|total|*}" - name: "<LIGHT>"   macro: "{all|*} {it|them|light|illumination|lamp|lamplight}"...- id: "ls:on" description: "Light switch ON action." synonyms:   - "<ACTION> {on|up|*} <LIGHT> {on|up|*}"   - "<LIGHT> {on|up}"

Элемент ls:on описан очень компактно, при этом данное описание содержит в себе более 3000 синонимов. Вот их малая часть: set lamp, light on, control lamp, put them, switch it all Синонимы конфигурируются в весьма сжатом виде, при этом вполне читаемы.

Несколько замечаний:
  • Разумеется, при работе с поиском по синонимам учитываются начальные формы слов (леммы, стеммы), стоп-слова текста запроса, конфигурируется поддержка прерывистости многословных синонимов и т.д. и т.п.
  • Часть сгенерированных синонимов не будет иметь практического смысла, это вполне ожидаемая плата за компактность записи. Если использование памяти станет узким местом (тут речь должна идти о миллионах и более вариантов синонимов на сущность), стоит задуматься об оптимизации. Вы получите все необходимые warnings при старте системы.

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

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

Расширение списка синонимов

Первое очевидное направление это в ручном режиме отслеживать логи и анализировать неотвеченные вопросы.

Второе посмотреть в словаре синонимов, что может быть достаточно полезно для очевидных случаев. Один их самых известных словарей wordnet.

image

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

Помимо этого, разработчики Apache NlpCraft добавили в проект инструмент sugsyn, предлагающий, в процессе использования, дополнительные синонимы для элементов модели.

Компонент sugsyn работает стандартным образом через REST API, взаимодействуя с дополнительным сервером, поставляемым в бинарных релизах ContextWordServer.

Описание ContextWordServer

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

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

В целом данный подход работал удовлетворительно, но контекст слов учитывался недостаточно хорошо, даже при больших значениях N для n-граммов. Тогда было предложено использование Bert для решения задачи masked language modeling (поиск наиболее подходящих слов, которые можно подставить вместо маски в предложение). В предложении, которое передавал пользователь, маскировалось целевое слово, и выдача Bert являлась ответом. Недостатком использования одного лишь Bert также было получение не совсем удовлетворительного списка слов, подходящих по контексту использования, но не являющихся близкими синонимами заданного.

Решением этой проблемы стало комбинирование двух методов. Теперь, выдача Bert отфильтровывается, выкидывая слова с векторным расстоянием до целевого слова выше определенного порога.

Далее, по результатам экспериментов, word2vec был заменен на fasttext (логический наследник word2vec), показывающий лучшие результаты. Была использована готовая модель, предобученная на статьях из Wikipedia, а модель Bert была заменена на улучшенную модель Roberta, смотри ссылку на предобученную модель.

Итоговый алгоритм не требует использования именно fasttext или Roberta в качестве составных частей. Обе подсистемы могут быть заменены альтернативными, способными решить схожие задачи. Кроме того, для лучшего результата предобученной модели могут быть fine-tuned, либо обучены с нуля.

Описание инструмента sugsyn

Работа с sugsyn, удобней всего осуществляется через CLI. Требуется скачать последнюю версию бинарного релиза, использование NlpCraft через maven central в данном случае будет недостаточно.

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

Пример. Пусть некий элемент какой-то модели сконфигурирован с помощью двух синонимов: ping и buzz (сокращенный вариант модели, взятой из примера с будильником), и пусть единственный интент модели содержит два примера: Ping me in 3 minutes и In an hour and 15mins, buzz me. Тогда sugsyn пошлет на ContextWordServer 4 запроса:
  • text=ping me in 3 minutes, index=0
  • text=buzz me in 3 minutes, index=0
  • text=in an hour and 15mins, ping me, index=6
  • text=in an hour and 15mins, buzz me, index=6

Это означает следующее для каждого предложения (поле text) предложи мне какие-нибудь дополнительные подходящие слова, кроме уже имеющихся слов в позиции index. ContextWordServer вернет несколько вариантов, отсортированных по итоговому весу (комбинации результатов обеих моделей, влияние каждой модели может быть сконфигурировано), далее отсортированных по повторяемости.

Использование инструмента sugsyn

Приступим к работе
  1. Запускам ContextWordServer, то есть сервер с готовыми, предобученными моделями.
    > cd ~/apache/incubator-nlpcraft/nlpcraft/src/main/python/ctxword
    > ./bin/start_server.sh

    Обратите внимание на то, что ContextWordServer должен быть предварительно проинсталирован и для успешной работы ему требуется python версий 3.6 3.8. См. install_dependencies.sh для linux и mac или мануал по установке для windows. Имейте в виду, что процесс инсталляции влечет за собой скачивание файлов моделей существенных размеров, будьте внимательны.
  2. Запускаем CLI, стартуем в нем server и probe с подготовленной моделью, подробности см. в разделе Quick Start. Для начальных экспериментов можно подготовить свою собственную модель или воспользоваться уже имеющимися в поставке примерами.
  3. Используем команду sugsyn, с одним обязательным параметром идентификатором модели, которая должна быть уже запущена в probe. Второй, необязательный параметр значение минимального коэффициента достоверности результата, поговорим о нем ниже.

image

Все описанное выше расписано шаг за шагом в мануале по ссылке.

Получение результатов для разных моделей

Начнем с примера по прогнозу погоды. Элемент wt:phen сконфигурирован с помощью множества синонимов среди которых rain, storm, sun, sunshine, cloud, dry и т.д., а элемент wt:fcast с помощью future, forecast, prognosis, prediction и т.д.

Вот часть ответа sugsyn на запрос со значением коэффициента minScore = 0.
> sugsyn --mdlId=nlpcraft.weather.ex --minScore=0

"wt:phen": [   { "score": 1.00000, "synonym": "flooding" },   ...   { "score": 0.55013,  "synonym": "freezing" },   ...   { "score": 0.09613, "synonym": "stop"},   { "score": 0.09520, "synonym": "crash" },   { "score": 0.09207, "synonym": "radar" },   ..."wt:fcast": [   { "score": 1.00000, "synonym": "outlook" },   { "score": 0.69549, "synonym": "news" },   { "score": 0.68009, "synonym": "trend" },   ...   { "score": 0.04898, "synonym": "where" },   { "score": 0.04848, "synonym": "classification" },   { "score": 0.04826, "synonym": "the" },   ...

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

Посмотрим, что будет предложено в качестве дополнительных синонимов для элементов примера умный дом. Для ls:loc, описывающего расположение элементов освещения (синонимы: kitchen, library, closet и т.д.), предложенные варианты с высокими значениями коэффициента, большим чем 0.5, тоже выглядят заслуживающими внимания:

"lc:loc": [   { "score": 1.00000, "synonym": "apartment" },   { "score": 0.96921, "synonym": "bed" },   { "score": 0.93816, "synonym": "area" },   { "score": 0.91766, "synonym": "hall" },   ...   { "score": 0.53512, "synonym": "attic" },   { "score": 0.51609, "synonym": "restroom" },   { "score": 0.51055, "synonym": "street" },   { "score": 0.48782, "synonym": "lounge" },   ...

Но около коэффициента 0.5 для нашей модели уже попадается откровенный мусор street.

Для элемента x:alarm модели будильник, с синонимами: ping, buzz, wake, call, hit и т.д. имеем следующий результат:

"x:alarm": [   { "score": 1.00000, "synonym": "ask" },   { "score": 0.94770, "synonym": "join" },   { "score": 0.73308, "synonym": "remember" },   ...   { "score": 0.51398, "synonym": "stop" },   { "score": 0.51369, "synonym": "kill" },   { "score": 0.50011, "synonym": "send" },   ... 

То есть для элементов данной модели, с понижением коэффициента качество предложенных синонимов снижается заметно быстрее.

Для элемента x:time модели текущее время (1, 2), с синонимами типа what time, clock, date time, date and time и т.д. имеем следующий результат:
"x:time": [   { "score": 1.00000, "synonym": "night" },   { "score": 0.92325, "synonym": "year" },   { "score": 0.58671, "synonym": "place" },   { "score": 0.55458, "synonym": "month" },   { "score": 0.54937, "synonym": "events" },   { "score": 0.54466, "synonym": "pictures"},   ...    

Качество предложенных синонимов оказалось неудовлетворительным даже при высоких коэффициентах.

Оценка результатов

Перечислим факторы, от которых зависит качество синонимов, предлагаемых sugsyn для поиска в тексте элементов модели:
  • Количество синонимов, определенных пользователем в конфигурации элементов.
  • Количество и качество примеров запросов к интентам. Под качеством понимается естественность и распространенность добавленных примеров. Спросите гугл который час, и число полученных результатов будет примерно 2 630 000. Спросите час который, результатов будет примерно 136 000. Текст первого запроса более качественный, и для примера он подойдет лучше.
  • Самое главное и непредсказуемое качество зависит от типа самого элемента и типа его модели.

Иными словами, даже при прочих равных условиях, таких как достаточное количество заранее сконфигурированных синонимов и примеров использования, для некоторых видов сущностей нейронная сеть предложит более качественный набор синонимов, а для некоторых менее качественный, и это зависит от природы самих сущностей и моделей. То есть для достижения сопоставимого уровня качества поиска, выбирая из списка предлагаемых к использованию синонимов, для разных элементов и разных моделей мы должны использовать разные значения минимального коэффициента достоверности предлагаемых вариантов. В целом это вполне объяснимо, так как даже одни и те же слова в разных смысловых контекстах могут быть заменены несколько разными наборами слов заменителей. Предобученная модель, используемая по умолчанию с ContectWordServer может быть адаптирована для одних типов сущностей лучше чем для других, однако перенастройка модели может и не улучшить итоговый результат. Так как Apache NlpCraft это opensource решение, вы всегда можете изменить все настройки модели, как параметры, так и саму модель с учетом специфики вашей предметной области. К примеру, для специфичной, изолированной области, имеет смысл обучить модель bert с нуля, поскольку данных об этой области в стандартной модели может оказаться недостаточно.

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

Заключение

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

Machine Learning news

22.02.2021 20:07:34 | Автор: admin

Дисклеймер:

Здесь я собираю новости абсолютно субъективно.

Часть новостей - новости только для меня и могли появиться довольно давно. Просто я заметил их только сейчас.

Я сопровождаю новость своим комментарием, в котором излагаю причину, почему эта новость интересна мне.

  1. Похоже, что Transformers from Hugginface

Подробнее..

Как мы анализируем предпочтения пользователей виртуальных ассистентов Салют

18.03.2021 10:09:11 | Автор: admin
Приветствую всех! Меня зовут Ибрагим, я работаю в SberDevices и занимаюсь машинным обучением. Сегодня я расскажу о том, как мы находим и анализируем интересы и предпочтения пользователей наших виртуальных ассистентов Салют.

Также поделюсь видео с моего недавнего выступления на онлайн-конференции Применение ML в Digital-продуктах, которую проводили коллеги из AGIMA и Epoch8.


В этом посте мы разберём следующее:

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

Вступление


Работая над виртуальными ассистентами, нам часто необходимо обучать специфические модели-классификаторы, которые решают свою узкую задачу. У таких задач есть несколько особенностей:

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

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

Как мы используем BERT для задач NLU


Для начала поговорим немного об обработке естественного языка в контексте задач его понимания (natural-language understanding).

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

Для перевода слов и предложений в векторы используются разные подходы, но наиболее успешные нейронные сети на базе архитектуры трансформеров. По доброй традиции языковые модели на базе трансформеров называют иногда как маппетов, персонажей Улицы Сезам.
В свое время мы взяли модель от Google под названием BERT, обучили ее для русского языка и доработали под свои собственные задачи.



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



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

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

Находим первичные данные для нашей задачи


Переходим непосредственно к нашей задаче. Определение интересов и предпочтений пользователей на базе диалогов с виртуальным ассистентом это стандартная задача мультиклассовой классификации, когда для каждой реплики необходимо проставить один из классов. В диалоговом домене часто подобные задачи несут в себе определенные подводные камни. Например, большинство значащих, полезных классов в совокупности могут составлять лишь малую часть всего датасета (к примеру, не больше 1%). При этом 99% всех логов общения будут отнесены к классу, который можно назвать Другое или Нейтральное это всё, что не относится к вашей задаче. Поэтому подход, когда мы просто берем кусок датасета и отправляем его на разметку, может быть не самым рациональным. Имеет смысл сначала обучить модель, которая нам поможет достать часть датасета, несущую полезную для решения нашей задачи информацию. Потом проанализировать эту часть, понять, какие там есть классы, распределение между ними, сформулировать задание по разметке и сформировать конечный датасет для обучения необходимой нам модели.

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



Или же можно поискать дополнительные полезные источники информации. Этим способом воспользовались и мы. Помните, в детстве в журналах были такие разделы, где люди искали себе друзей по переписке? Они писали: Хей, меня зовут Ибрагим, я слушаю Blink-182, катаюсь на скейте. Давайте меняться напульсниками!. Мы нашли датасет подобных анкеточных писем, где не было личных данных или индексов, но предложения, реплики, где люди рассказывали о своих интересах, там присутствовали. Таким образом мы получили первую пару сотен реплик о том, где люди рассказывают что-то о себе, о каких-то своих предпочтениях.

Обогащаем датасет с помощью парафраз


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

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

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


Векторы, в которые мы кодируем наше предложение, по своей сути являются точками в признаковом пространстве. Что это значит? Это значит, что предложения, схожие по смыслу или по какому-то другому признаку, скорее всего, будут располагаться рядом. Например, предложения Мне нравится группа Metallica. и Я обожаю слушать тяжелую музыку. будут располагаться где-то рядом друг с другом. Это значит, что мы можем попробовать найти похожие по смыслу или синонимичные предложения к размеченным примерам, которые у нас уже есть. Такие предложения называют парафразами. Можно для каждого исходного предложения, для которого нам известен его класс, провести быстрый поиск ближайших соседей. Для этого можно воспользоваться библиотеками FAISS от Facebook, ScaNN от Google или другими и найти парафразы с определенным порогом по расстоянию. Таким образом можно обогатить изначальный датасет. И, условно, если у нас была пара сотен реплик, теперь мы можем получить пару тысяч реплик или предложений, где люди что-то рассказывали о своих интересах и предпочтениях.

Получаем полезную часть большого датасета


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



Итак, мы получили пару десятков тысяч предложений. Теперь нам нужно составить задание на разметку. Для этого определяем, какие здесь могут быть классы интересов и предпочтений человека. Но для начала хорошо бы провести кластеризацию. Что это такое?

Кластеризуем данные, чтобы определить возможные будущие классы


Предложения, которые представлены точками в признаковом пространстве, могут образовывать группы, объединенные конкретным признаком. К примеру, группой может являться набор предложений, где люди рассказывают о любимой музыке, о любимых сериалах или книге. Поэтому можно взять все предложения, векторизовать их с помощью BERT, понизить размерность с помощью UMAP (потому что исходная размерность векторов BERT это 1024, если мы говорим про large модель). И затем кластеризовать полученные векторы с пониженной размерностью алгоритмом HDBSCAN. Таким образом можно получить группы и просмотреть глазами случайные предложения в них, чтобы понять, о чем люди рассказывают в диалогах. Теперь можно подумать, какие могут быть классы, подходящие под нашу задачу, и какое между этими классами распределение.



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

Немного о разметке данных


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

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

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

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

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

Предложения, в которых модель была уверена, но при этом ее предсказания не совпадают с проставленной разметчиком меткой, можно отправить на доразметку. Условно, дать задание: Выберите один из двух классов: либо представленный моделью, либо разметчиком. Переразметив всего 5% исходного датасета, можно здорово повысить его чистоту, а значит и качество работы будущей модели. Либо, если вы уверены в результатах работы модели, вы можете с ее помощью проставить автоматические теги.

Недавно Google анонсировал алгоритм TracIn. Он оценивает то, какой вклад вносит каждый конкретный семпл в обучающей выборке в предсказание каждого конкретного семпла в тестовой выборке. Таким образом можно оценить, как влияет каждый семпл на точность работы модели на своём классе. Получается, если пример с высокой степенью ухудшает точность на собственном классе, то, возможно, это либо пример с неправильной разметкой, либо это достаточно редкий пример для самого класса. И в том, и в другом случае можно доразметить пример.

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

Внедрение модели и оценка метрик


Теперь нужно внедрять саму модель. Здесь мы активно используем практики MLOps. Во-первых, мы активно версионируем все наши модели не только с датасетом и кодом, но и между собой. Для этого мы используем DVC, потому что особенно важно, когда у вас двухступенчатая архитектура, версионировать модели между собой, чтобы была консистентность и между большой моделью-векторизатором (в нашем случае BERT), и между маленькими нейронными сетями, которые решают свои собственные задачи.

Пайплайны обучения мы стараемся обернуть в Jenkins jobs, чтобы можно было запускать их по одной кнопке. И делаем это мы не только для того, чтобы автоматизировать, но и для того, чтобы уменьшить процент ошибки, человеческого фактора. Чем меньше вам нужно самому что-то делать, тем меньше шанс, что на одном из этапов вы ошибётесь.

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

Итоги


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

собрать первичный датасет с корректной разметкой;

обогатить его с помощью поиска ближайших соседей;

построить первую модель простой бинарной классификации (поможет нам вычленить максимально полезный участок датасета);

кластеризовать данные и оценить полученные классы и распределения;

обучить конечную модель (завернув всё в пайплайны, версионировав);

оценить результаты по метрикам.



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

***
Оставлю здесь ссылки по теме:

пост про то, как мы обучали BERT и как сделали его устойчивым для парафраз;
лекция моего коллеги для Sberloga о том, какие трюки мы использовали, чтобы сделать нашу модель лучше;
одна из итераций модели Bert-large для русского языка, которую мы используем, выложена в open source и доступна любому;
рассказ о том, как мы с коллегами из Сбера обучили и выложили в открытый доступ русскоязычную модель GPT-3.
Подробнее..

Сегментация потоков документов используем BERT

05.10.2020 16:20:50 | Автор: admin

Вы наверняка знакомы с ситуацией, когда при обращении в какую-либо крупную организацию приходится подавать целый пакет документов, точнее пакет их сканов. И это в век цифры! Теперь посмотрите на это глазами второй стороны и представьте, что у вас миллионы таких заявок со сканами, и они не содержат информации о границах документов. Апокалипсис? Всё придётся сегментировать вручную? К счастью, существуют алгоритмы автоматической сегментации потоков многостраничных документов. Здесь мы расскажем о новом подходе в сегментации с использованием модели BERT.


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


В классификации документов модель BERT (Bidirectional Encoder Representations for Transformers) уже применялась ранее. Но для задачи сегментации, насколько нам известно, это первая работа с использованием этой языковой модели.



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


Как это работает


Cегментация потоков документов (Page Stream Segmentation PSS) и сопутствующая задача классификации (Document Image Classification DIC) исследовались многими авторами. В работе Wiedemann, Heyer (2019) сделан обзор многих таких исследований, и среди них выделены два подхода к PSS и DIC: с помощью системы правил (Rule-Based Systems RBS) и с применением машинного обучения.


Системы RBS (Karpinski and Belaid, 2016; Hamdi at el. 2017) подразумевают выделение из распознанного текста с помощью регулярных выражений специальных дескрипторов, определяющих границы документов в потоке. Дескрипторами могут быть приветственные фразы, названия частотных сущностей, номера страниц, layout-признаки: размеры шрифтов, расположение сущностей на странице и др. RBS может оказаться довольно эффективным для однородных (homogeneous) датасетов с хорошим качеством сканов и определённой структурой документов, встречающихся, в частности, в бизнес-документации (счета, накладные, письма и т.п.). Но для RBS необходимо составлять вручную правила для выделения дескрипторов, что является несомненным минусом на датасетах с сильно разрозненными тематиками (heterogeneous datasets).


Подходы с применением машинного обучения (Rusinol at el. 2014; Daher, Belaid, 2014; Agin at el. 2015) и глубокого машинного обучения (Harley at el. 2015; Noce at el. 2016; Gallo at el. 2016; Wiedemann, Heyer, 2019) кажутся более привлекательными, поскольку не требуют глубокого погружения в суть текстов документов, как в RBS. Обучение в этих подходах в основном проводилось на текстовых и визуальных признаках и их комбинациях. Также применялось объединение (fusion) отдельных моделей на текстовых и визуальных признаках, когда одна модель может уточнить результат другой модели и в итоге улучшить общий результат.


В работе Harley at el. (2015) для классификации документов из датасета RVL-CDIP, введённого в этой же работе, используются глубокие свёрточные нейросети CNN на визуальных признаках. В работах Noce at el. (2016) и Gallo at el. (2016) для классификации документов применяются нейросети и трансфер-лёрнинг. В работе Gallo at el. (2016) классификация (DIC) строится только на визуальных признаках, но для повышения качества используются признаки соседних страниц. При этом автоматически решается задача сегментации (PSS): если предсказанный класс текущей страницы отличается от класса предыдущей, значит, начался новый документ. Стоит отметить, что сегментация (PSS) на основе классификации (DIC) имеет большой недостаток: она не разделяет документы одного и того же класса. Если в датасете сильно доминирует какой-либо класс, то сегментация (PSS) на основе классификации (DIC) практически бесполезна, поскольку уже разделённые потоки одного класса необходимо повторно разделять.


В работах Daher, Belaid (2014), Agin at el. (2015), Hamdi at el. (2018), Wiedemann, Heyer (2019) для нахождения границ документов в потоках довольно эффективно используется бинарная классификация: для каждой пары соседних страниц из потока модель предсказывает, является ли следующая страница в паре продолжением документа (SD Same Document) или начался новый документ (ND New Document). В работе Wiedemann, Heyer (2019) задача PSS решается с помощью бинарной классификации (SD/ND) с использованием комбинации текстовых и визуальных признаков и с применением глубоких нейросетей.


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


Идея использования модели BERT в задаче сегментации


Модели машинного обучения на основе BERT получили большую популярность, поскольку с их помощью были улучшены, и порой существенно, оценки многих задач NLP (Natural Language Processing).


Модель BERT сначала предобучают на широких корпусах текстов, а затем используют для решения конкретных задач, в том числе и на небольших датасетах. Во время предобучения модель решает две задачи: MLM (Masked Language Model) и NSP (Next Sentence Prediction). В задаче MLM случайно метится (маскируется) определённая доля токенов (слов или частей слов) входной последовательности, и задача состоит в том, чтобы восстановить значения токенов, которые были замаскированы. Задача NSP это бинарная классификация на парах предложений (или спанов текстов), когда нужно предсказать, является ли второе предложение (или спан текста) логичным продолжением первого. При решении конкретных задач предобученный BERT используют для трансфер лёрнинга, извлекая признаки из текста. В случае файн-тюнинга модель BERT делают составной частью специализированной модели, и его вес меняется вместе с весом этой модели. Более подробно о принципах построения этой модели мы рассказывали в нашем предыдущем посте о классификации документов.


Касательно нашей задачи: зачастую начало текста текущей страницы многостраничного документа является логичным продолжением конца текста предыдущей страницы и модель BERT, предобученная на задаче NSP, может улавливать сложные контекстные зависимости этих кусков текстов. Мы предполагаем, что сможем извлекать с помощью BERT сильные текстовые признаки на парах страниц для бинарной классификации (SD/ND).


Генерация входов модели


Мы будем решать задачу сегментации PSS на нашем закрытом датасете (Documents for Credit Dataset DCD), составленном из документов, предоставляемых компаниями для получения кредита в Банке ВТБ.


DCD был накоплен за продолжительный период. Сканирование документов проводилось потоками, как правило, один поток это набор документов от одной компании. Потоки сегментировались в полуавтоматическом режиме. DCD включает около 63 тыс. уже сегментированных одностраничных и многостраничных документов, суммарно около 232 тыс. страниц.


Бизнес-подразделениями банка были выделены около 300 категорий документов. Из них 10 базовых категорий: договор аренды, выписка из реестра участников, устав компании, свидетельство о постановке на учет в налоговом органе, вопросник для юридических лиц, паспорт РФ, лист записи ЕГРЮЛ, свидетельство о государственной регистрации юридического лица, приказы/распоряжения, решения/протоколы, а другие менее значимые документы отнесем к категории Иное.


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


  • Каждый поток должен содержать по одному документу из каждой базовой категории.
  • Каждый поток должен содержать три документа из категории Иное.
  • К 2% потоков из каждой выборки добавляются ещё по два документа из каждого базового класса.
  • 81% одно- и многостраничных документов датасета использовались для генерации потоков Train, 9% для генерации потоков Dev, и 10% для генерации потоков Test.
  • Для формирования потока отдельные документы внутри потока перемешиваются случайным образом с сохранением порядка страниц внутри документа.

Согласно этим правилам мы сгенерировали 10000 потоков для Train, 2000 потоков для Dev, 2000 потоков для Test.


Потоки из Train мы случайным образом перемешали, выставили потоки друг за другом и получили один длинный поток, в котором пары соседних страниц (вернее, извлечённые из них признаки) и их метки (Same Document или New Document) будут, соответственно, входами и целевыми метками нашей будущей модели бинарной классификации. Аналогично из потоков получаем входы и целевые метки для Dev и Test.


Таблица 1. Количественные показатели датасета DCD
Document lengths (pages) Train Test Dev
1 24953 3075 2752
2 10170 1251 1135
3 3680 452 422
4 2549 310 279
5 1857 221 187
6 1246 165 153
7 895 116 105
8 912 89 98
9 968 120 92
>=10 4453 536 515
Single-page documents 24953 (48%) 3075 (49%) 2752 (48%)
Multi-page documents 26730 (52%) 3260 (51%) 2986 (52%)
Total documents 51683 6335 5738
Total pages 188504 22553 21022
# new document (gen. pairs) 133539 (49%) 26879 (62%) 26879 (64%)
# same document (gen. pairs) 136817 (51%) 16218 (38%) 15284 (36%)

Наш подход


Для решения задачи сегментации PSS мы будем использовать бинарную классификацию SD (Same Document) и ND (New Document), описанную выше во введении. В качестве признаков наша модель получает эмбеддинг пары соседних страниц, составленный из визуальных эмбеддингов каждой из страниц, и одного общего текстового эмбеддинга, полученного сразу для пары. Число пар страниц по каждой выборке Train/Dev/Test можно посмотреть в таблице 1.


Визуальный эмбеддинг каждой страницы вектор длины 512 мы получаем как выход предпоследнего слоя CNN ResNet34, He at al. (2015).


Текстовый эмбеддинг, общий для пары страниц, получаем с помощью модели RuBERT (Russian, cased, 12-layer, 768-hidden, 12-heads, 180M parameters) от DeepPavlov. Для этого на вход модели подаем вектор из 512 токенов следующего вида: на первом месте CLS-токен, потом N (информационных) токенов, соответствующих спану текста конца первой страницы из пары, далее (разделяющий) SEP-токен, потом M (информационных) токенов, соответствующих спану текста начала второй страницы из пары, и потом снова SEP-токен. Суммарное число информационных токенов, которое можно разместить во входном векторе, не более 509: N + M <= 509. Мы хотим как можно эффективнее использовать возможности модели BERT, поэтому стремимся максимально заполнить входной вектор модели токенами.



Схема получения текстовых признаков для пары страниц. Ti,j токен с номером i в тексте страницы j. Для удобства отображения отсчёт токенов страницы 1 идёт с конца.


Поскольку RuBERT предобучен на задачу NSP, то CLS-эмбеддинг (вектор длины 768) должен содержать в себе наиболее полную информацию, является ли второй текст логическим продолжением первого. Его и возьмём в качестве общего эмбеддинга для пары страниц.


Бейслайн
Итак, для каждой пары страниц два визуальных эмбеддинга (два вектора длины 512) и один текстовый эмбеддинг (вектор длины 768) объединяются в один общий визуально-текстовый эмбеддинг (вектор длины 1792). Далее на таких эмбеддингах строится бинарная классификация SD (Same Document) / ND (New Document) на основе MLP (Multi Layer Perceptron) с одним скрытым слоем нейронов длины 896, dropuout 0.3. Это наш бейслайн.



Общая схема модели


Основная модель
Следующим шагом мы провели дообучение (further-pretraining) модели RuBERT на обеих задачах MLM и NSP на нашем датасете DCD. Повторно сняли визуально-текстовые признаки, как в бейслайн, и на них построили бинарную классификацию на основе модели MLP с одним скрытым слоем нейронов длины 896 и dropout 0.3. В итоге получили основную модель улучшенного качества.


Результаты


Таблица 2. Результаты бейслайн модели на Test
Число пар Accuracy Kappa
43097 0.9669 0.9294
Пары хотя бы c одним одностр. док-м 19188 0.9771 -
Пары с обеими страницами из многостр. док-тов 23909 0.9587 0.9072

Таблица 3. Результаты основной модели на Test
Число пар Accuracy Kappa
43097 0.9819 0.9615
Пары хотя бы c одним одностр. док-м 19188 0.9898 -
Пары c обеими страницами из многостр. док-тов 23909 0.9756 0.9450

Даже без дообучения модель BERT даёт приемлемое качество 0.9669. А после дообучения на нашем датасете, как и ожидалось, качество ещё немного улучшилось до 0.9819, при этом существенно увеличилась kappa.


Заключение


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

Подробнее..

Перевод ALBERT облегченный BERT для самообучения языковым представлениям

24.10.2020 12:06:33 | Автор: admin

С тех пор как в 2018 году был представлен BERT, исследования в области обработки естественного языка охвачены новой парадигмой: использованием больших объемов существующего текста для предварительного обучения параметров модели на основе самообучения (self-supervision), не требующего разметки данных. Таким образом, вместо того, чтобы обучать модель для обработки естественного языка (NLP) с нуля, можно взять предобученную модель, уже имеющую некоторое знание о языке. Однако, для успешного применения этого нового подхода в NLP исследователю необходимо иметь некоторое представление о том, что же именно способствует языковому обучению модели: высота нейронной сети (т.е. количество слоев), ее ширина (размер представлений скрытых слоев), критерий обученности для самообучения или что-то совсем иное?


В статье ALBERT: облегченный BERT для самообучения языковым представлениям, принятой на ICLR 2020, была представлена обновленная версия BERTа, которая показывает более высокие результаты в 12 задачах обработки языка, включая соревнование Stanford Question Answering Dataset (SQuAD v2.0) и бенчмарк RACE для понимания текстов из экзаменов SAT. ALBERT выпускается в качестве открытого решения поверх TensorFlow и включает в себя несколько готовых к использованию предобученных языковых моделей.


Что повышает качество NLP моделей?


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


Ключом к оптимизации модели, заложенным в архитектуру ALBERT, является более эффективное распределение ее ресурсов. Входные эмбеддинги (слова, суб-токены и т.д.) выучивают векторные представления, независимые от контекста: например, представление слова bank. Эмбеддинги скрытых слоев, напротив, должны уточнять значения этих векторных представлений в зависимости от конкретного контекста: например, вектор bank как финансового учреждения или как берега реки.


Это достигается путем факторизации параметризации эмбеддингов: матрица эмбеддингов разделяется между векторами входного слоя с относительно небольшой размерностью (например, 128), в то время как вектора скрытого слоя используют бОльшие размерности (768, как в случае с BERT'ом, и больше). Только с помощью этого шага, при прочих равных, ALBERT на 80% снижает количество параметров проекционного блока ценой лишь незначительного падения производительности 80.3 балла вместо 80.4 для SQuAD2.0 и 67.9 вместо 68.2 для RACE.


Другое важное изменение в архитектуре ALBERT связано с исследованием избыточности. Архитектуры нейронных сетей на основе Трансформера (такие как BERT, XLNet и RoBERTa) полагаются на независимость слоев, расположенных друг над другом. Однако было замечено, что зачастую нейросеть выучивается выполнять схожие операции на разных уровнях, используя различные параметры сети. Эта возможная избыточность устраняется в ALBERT с помощью обмена параметрами между слоями, и, таким образом, один и тот же слой применяется друг к другу. И хотя такой подход немного снижает точность (accuracy), более компактный размер самой модели оправдывает потерю в качестве. Подобный обмен обеспечивает снижение параметров для блока с механизмом внимания внимания на 90% (общее снижение на 70%), что при применении в дополнение к факторизации параметризации эмбеддингов приводит к небольшому снижению показателей: до 80.0 (-0.3) для SQuAD2.0 и до 64.0 (-3.9 балла) для RACE.


Внедрение двух представленных изменений рождает модель ALBERT-base, которая имеет всего 12 миллионов параметров, что на 89% меньше базовой модели BERT, но при этом обеспечивает достойное качество в рассмотренных бенчмарках. Вместе с тем подобное уменьшение количества параметров дает возможность и дальнейшего масштабирования. Если объем памяти позволяет, можно увеличить размер эмбеддингов скрытого слоя в 10-20 раз. При размере скрытого слоя 4096 конфигурация ALBERT-xxlarge обеспечивает как общее снижение параметров на 30% по сравнению с моделью BERT-large, так и, что более важно, значительный прирост качества: +4.2 для SQuAD2.0 (88.1 по сравнению с 83.9) и +8.5 для RACE (82.3 по сравнению с 73.8).


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


Показатели оптимизированной модели на наборе данных RACE


Чтобы оценить способность модели понимать язык, можно провести тест на понимание прочитанного (например, схожий с SAT Reading Test). Крупнейший общедоступный ресурс для этой цели набор данных RACE (2017 г.). То, как компьютер справляется с этим испытанием, хорошо отражает достижения в области языкового моделирования последних лет: модель, предварительно обученная только на контекстно-независимых представлениях слов, получает низкие баллы в этом тесте (45.9; крайний левый столбик), в то время как BERT, получивший контекстно-зависимое знание языка, справляется достаточно хорошо 72.0 балла. Усовершенствованные модели BERT, такие как XLNet и RoBERTa, установили планку еще выше в диапазоне 8283 баллов. Конфигурация ALBERT-xxlarge, упомянутая выше, дает оценку RACE в том же диапазоне (82.3) при обучении на наборе данных базового BERT'a (Википедия и Книги). Однако при обучении на том же расширенном наборе данных, что и XLNet и RoBERTa, она значительно превосходит все существующие на сегодняшний день подходы и устанавливает новую оценку в 89.4.


image1


Показатели моделей в бенчмарке RACE (задача на понимание текстов из экзаменов SAT). Оценка для случайного предсказания составляет 25.0. Максимально возможный балл 95.0.


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


Авторы


Подробнее..
Категории: Машинное обучение , Nlp , Bert , Albert

Перевод Измерение гендерных корреляций в предобученных NLP-моделях

18.11.2020 20:10:57 | Автор: admin

За последние несколько лет были сделаны значительные успехи в области обработки естественного языка (NLP), где такие модели, как BERT, ALBERT, ELECTRA и XLNet достигли поразительной точности (accuracy) в различных задачах. Во время предварительного обучения (pre-training) на основе обширного корпуса текстов (например, Википедии) формируются векторные представления, которые получают путем маскирования слов и попыток их предсказать (т.н. маскированное языковое моделирование). Получившиеся представления кодируют большой объем информации о языке и отношениях между понятиями, например, между хирургом и скальпелем. Далее начинается второй этап обучения тонкая настройка (fine-tuning) на котором модель использует заточенные под определенную задачу данные для того, чтобы с помощью общих предобученных представлений научиться выполнять конкретные задачи вроде классификации. Учитывая широкое использования подобных моделей в разных NLP задачах, критически важно понимать, какая информация в них содержится и как любые выученные отношения влияют на результаты модели в ее приложениях, чтобы обеспечить их соответствие Принципам искусственного интеллекта (ИИ).


В статье Измерение гендерных корреляций в предобученных NLP-моделях представляется исследование модели BERT и его облегченного собрата ALBERT в поисках отношений, связанных с гендером, и формулируется ряд лучших практик для использования предобученных языковых моделей. Авторы представляют экспериментальные результаты в виде публичных весов модели и исследовательского набора данных, чтобы продемонстрировать применение лучших практик и предоставить основу для дальнейшего изучения параметров, выходящего за рамки данной работы. Также авторы планируют выложить набор весов Zari, в котором снижено число гендерных корреляций, но сохранено высокое качество на стандартных задачах NLP.


Измерение корреляций


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



Классическая академическая формулировка этого задания тест OntoNotes (Hovy et al., 2006). На этих данных авторы оценивали с помощью F1-меры, насколько точно модель справляется с разрешением кореференции (как в Tenney et al. 2019). Так как OntoNotes представляет только одно распределение данных, авторы также рассмотрели бенчмарк WinoGender, который предоставляет дополнительный набор сбалансированных данных, составленный для нахождения случаев, когда ассоциативные связи модели между гендером и профессией способствуют неправильному разрешению кореференции. Высокие (близкие к 1) значения метрики WinoGender означают, что модель основывается на нормативных ассоциациях между полом и профессией (т.е. относит слово nurse к человеку женского пола, а не мужского). Когда предсказание модели не имеет никакой устойчивой корреляции пола и профессии, метрика равна нулю, что означает, что модель предсказывает на основе какой-то другой информации, например структуры или семантики предложения.



Метрики BERT и ALBERT на заданиях OntoNotes (точность) и WinoGender (гендерные корреляции). Низкие значения метрики WinoGender означают, что модель в своих предсказаниях в первую очередь руководствуется корреляциями, отличными от гендерных.


Настоящее исследование демонстрирует, что ни большая модель (Large) BERT, ни общедоступная модель ALBERT не достигают нулевого значения на примерах из WinoGender, несмотря на впечатляющие (близкие к 100%) показатели точности (accuracy) на задании OntoNotes. По меньшей мере отчасти это можно объяснить тем, что модель руководствуется преимущественно гендерными корреляциями в своих предсказаниях. Это неудивительно: существует ряд ключей к пониманию текста, и общая модель может воспринимать некоторые или даже все из них. К этому следует отнестись внимательно, т.к. крайне нежелательно, чтобы модель делала предсказания, основываясь преимущественно на гендерных корреляциях, а не на свидетельствах, встреченных в тексте на входе модели.


Лучшие практики


Возможное влияние нежелательных корреляций на результат работы модели в прикладных задачах ставит перед авторами вопрос: что можно предпринять при разработке NLP-моделей для снижения риска подобного влияния?


  • Измеряйте нежелательные корреляции: Качество модели может быть измерено с помощью метрик точности, но они оценивают результаты только в одной плоскости, особенно если тестовые данные из того же распределения, что и данные для обучения. Например, веса BERT и ALBERT всего на 1% отличаются по метрике точности, однако на целых 26% по степени использования гендерных корреляций для разрешения кореференции. Эта разница может иметь большое значения в некоторых задачах: так, выбор модели с наименьшим значением метрики WinoGender может быть более предпочтителен в приложениях, где есть тексты о людях, профессии которых могут не соответствовать исторически сложившимся социальным нормам, таких, как, например, медбрат (male nurse).


  • Будьте осторожны при внесении на первый взгляд безобидных изменений в конфигурацию: Процесс обучения нейронных сетей регулируется множеством гиперпараметров, которые обычно подбираются для наилучшего достижения целей обучения. И хотя выбор конфигурации обычно кажется безобидным, авторы обнаружили, что он может значительно влиять на гендерные корреляции, как в лучшую, так и в худшую сторону. Это справедливо, например, в случае с дропаут-регуляризацией (dropout regularization), которая используется для снижения переобучения больших моделей: при увеличении показателя дропаута (dropout rate) в предварительном обучении BERT и ALBERT, наблюдается значительное снижение показателя гендерных корреляций даже после тонкой настройки. Это означает, что простым изменением конфигурации можно снизить риск нежелательных корреляций, однако это также демонстрирует, что нужно внимательно относиться к любым изменениям в модели.




  • Используйте возможности для снижения нежелательных последствий: Еще одним следствием возможного неожиданного влияния дропаута на гендерные корреляции является возможность использования универсальных методов для уменьшения непреднамеренных корреляций: так, в ходе своего исследования авторы выяснили, что увеличение показателя дропаута позволило модели лучше справляться с примерами WinoGender без уточнения вручную каких-либо параметров задачи или изменения этапа тонкой настройки. К сожалению, на OntoNotes с увеличением показателя дропаута точность начинает падать (что можно наблюдать в результатах BERT'а), однако сама возможность снижения нежелательных последствий на этапе предварительного обучения, когда изменения в конфигурации могут привести к улучшению модели без необходимости внесения каких-либо дополнительных изменений для решения конкретных задач, кажется очень перспективной. Авторы рассмотрели аугментацию контрфактическими данными как еще одну стратегию уменьшения нежелательных последствий с различными условиями (см. статью).

Что дальше


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


Авторы


Подробнее..

Перевод Разбираем XLNet

15.01.2021 18:06:16 | Автор: admin

Введение


XLNet новейшая и самая крупная модель, появившаяся в активно развивающейся сфере обработки естественного языка (Natural Language Processing, NLP). Статья о XLNet объединяет современные достижения в NLP и инновационный подход к решению задачи языкового моделирования. Обученная на огромном корпусе, модель достигает выдающихся результатов в NLP-задачах бенчмарка GLUE.


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


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


Языковое моделирование


Языковое моделирование заключается в подсчете распределения совместной вероятности для последовательности токенов (слов), и зачастую достигается путем факторизации совместного распределения на распределение условной вероятности одного токена с учетом других токенов в последовательности. Например, дана последовательность: "New", "York", "is", "a", "city". Вероятность слова New модель подсчитает как $inline$Pr(\text{"New"} | \text{"is"}, \text{"a"}, \text{"city"})$inline$, т.е. вероятность того, что токен "New" находится в той же последовательности, что и токены "is", "a" и "city" (см. рис. 1).


Заметим, что обычно языковая модель принимает текстовую последовательность в $T$ токенов, $\mathbf{x} = [x_1, x_2,\ldots, x_T]$, и подсчитывает вероятность появления некоторых токенов $\mathbf{x}^{\prime}$ в последовательности при известных $\mathbf{x}^{\prime\prime}$: $Pr(\mathbf{x}^{\prime} | \mathbf{x}^{\prime\prime})$, где $\mathbf{x}^{\prime}$ and $\mathbf{x}^{\prime\prime}$ непересекающиеся подмножества $\mathbf{x}$.


xlnet_figure1


Рис. 1. Языковая модель. Модель это функция, которая принимает на вход несколько контекстных токенов и выдает на выходе вероятность каждого токена в словаре. Толстыми линиями обозначены более информативные контекстные слова и более вероятные слова из словаря.


Зачем кому-то могла понадобиться модель, которая может подсчитывать вероятность слова в последовательности? На самом деле, особо никому нет до этого дела. Однако модель, содержащая достаточно информации для того, чтобы предсказывать последующие слова в предложении, может быть применена в других более полезных задачах; например, ее можно использовать для определения, кто был упомянут в тексте, какое действие было описано или какую тональность имел текст. Таким образом, с помощью языкового моделирования модели предварительно обучаются и затем тонко настраиваются для решения более практических задач.


Стоя на плечах моделей-гигантов


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


Далее нам нужно построить отношения между векторизованными токенами в последовательности. Долгое время признанным фаворитом для решения этой задачи была архитектура LSTM, которая строит отношения между смежными токенами (напр., модель ELMo), однако сейчас наилучшие результаты показывают модели Трансформера (напр., модель BERT). Архитектура Трансформера позволяет объединять несмежные токены, и, таким образом, генерировать более высокоуровневую информацию с помощью механизма внимания. Это помогает модели легче выстраивать более отдаленные отношения в тексте, чем подходы на основе LSTM.


У Трансформеров есть один недостаток: они работают с последовательностями фиксированной длины. Но что, если знание того, что "New" должно появиться в предложении "____ York is a city", также требует, чтобы модель прочитала что-то об Эмпайр-стейт-билдинг в предыдущем предложении? Transformer-XL решает эту проблему, позволяя текущей последовательности видеть информацию из предыдущих последовательностей. Именно на этой архитектуре строится XLNet.


Цель обучения XL


Основной вклад XLNet это не архитектура, а модифицированная цель обучения языковой модели, которая должна выучить условные распределения для всех перестановок токенов в последовательности. Прежде чем углубиться в детали этой цели, давайте вернемся к модели BERT и объясним такой выбор XLNet.


В бывшей SOTA-модели (BERT) целью обучения было восстановление маскированных слов в предложении: так, для каждого предложения в корпусе некоторые токены заменяются универсальным токеном [mask]. Задача модели восстановить изначальные токены.


xlnet_figure2


Рис. 2. Изображение модели BERT. На входе модели контекстные токены, некоторые из которых маскированы. Обращая внимание на правильные токены контекста, модель узнает, что наиболее вероятным словом в маскированной позиции будет "boat".


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


Языковая модель должна кодировать как можно больше информации и нюансов из текста. Модель BERT пытается восстановить маскированные слова в предложении "The [mask] was beached on the riverside" (рисунок 2) ("[mask] была выброшена на берег реки"). Здесь могут встречаться такие слова, как "лодка" или "каноэ". BERT может знать это, потому что лодка может быть выброшена на берег, и ее часто можно найти на берегу реки. Но для BERT'а вовсе необязательно знать это про лодку, достаточно костыля вроде упоминания "берег реки", чтобы сделать вывод, что "лодка" является маскированным токеном.


Более того, BERT предсказывает маскированные токены независимо, поэтому не узнает, как они влияют друг на друга. Если бы пример был "The [mask] was [mask] on the riverside" ("[mask] была [mask] на берег реки"), то BERT мог выдать высокие вероятности не только для таких корректных пар, как ("лодка", "выброшена") и ("парад", "виднелся"), но и для пары ("парад", "выброшен").


Такие подходы, как BERT и ELMo, стали в свое время SOTA за счет включения в предсказание левого и правого контекстов. XLNet пошла еще дальше: модель предназначена для предсказания каждого слова в последовательности, используя любую комбинацию других слов в этой последовательности. XLNet могут попросить предсказать, какое слово может следовать за "The" в нашем предложении. Вероятно, много слов, но "лодка" более вероятна, чем "они", потому что модель уже кое-что узнала о лодке (в основном, что это не местоимение). Затем модель могут попросить предсказать второе слово, учитывая, что последующие слова "была" и "выброшена". И затем ее могут попросить предсказать четвертое слово, учитывая, что третье "был", пятое "на" и седьмое "берег реки.


xlnet_figure3


Рис. 3. Изображение модели XLNet. Задача рассчитать, что лодка является вероятным токеном для многих различных контекстов, взятых из последовательности.


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


На практике модель XLNet делает выборку из всех возможных перестановок, так что ей не удается просмотреть каждое отдельное отношение. Также, она не использует очень маленькие контексты, поскольку они мешают обучению. После применения этих практических эвристик XLNet стала больше походить на BERT.


В следующих нескольких разделах будут рассмотрены более сложные аспекты статьи.


Перестановки


Для последовательности $\mathbf{x}$ авторегрессионная (auto-regressive, AR) модель
подсчитывает вероятность $Pr(x_i | x_{<i})$. В языковом моделировании, это вероятность токена $x_{i}$ в предложении при условии, что токены $x_{<i}$ предшествуют ему. Эти обуславливающие слова называют контекстом. Подобная модель ассиметрична и не получает информацию о всех отношениях между токенами в корпусе.


Авторегрессионные модели, такие как ELMo, позволяют также учиться отношениям между токеном и последующими токенами. Цель AR в этом случае может рассматриваться как $Pr(x_i) = Pr(x_i | x_{>i})$. Это авторегрессия для обратной последовательности. Но зачем останавливаться? Ведь могут существовать отношения, интересные для задачи обучения, как между двумя ближайшими токенами $Pr(x_i) = Pr(x_i | x_{i-1}, x_{i+1})$, так и вообще для любой комбинации токенов $Pr(x_i) = Pr(x_i | x_{i-1}, x_{i+2}, x_{i-3})$.


XLNet предлагает в качестве цели обучения получить представление над всеми такими перестановками. Возьмем, например, последовательность $inline$\mathbf{x} = ["This", "is", "a", "sentence"]$inline$, где $T=4$. Получится набор из всех 4! перестановок $\mathcal{Z} = \{[1, 2, 3, 4], [1, 2, 4, 3],. . ., [4, 3, 2, 1]\}$. Модель XLNet авторегрессионна для всех таких перестановок: она может посчитать вероятность токена $x_i$, учитывая предыдущие токены $x_{<i}$ для любого порядка $\mathbf{z}$ из $\mathcal{Z}$.


Например, можно вычислить вероятность третьего элемента с учетом двух предыдущих из любой перестановки. Три перестановки $[1, 2, 3, 4]$, $[1, 2, 4, 3]$ и $[4, 3, 2, 1]$ будут соответствовать $inline$Pr("a", | "This", "is")$inline$, $inline$Pr("sentence" | "This", "is")$inline$ и $inline$Pr("is" | "sentence", "a")$inline$. Схожим образом вероятность второго элемента с учетом первого можно выразить как $inline$Pr("is" | "This")$inline$, $inline$Pr("is" | "This")$inline$ и $inline$Pr("a" | "sentence")$inline$. Если же рассматривать все 4 позиции и все 4! перестановок, то модель будет учитывать все возможные зависимости.


Эти идеи включены в следующую формулу из статьи:


$\hat{\boldsymbol\theta} = \mathop{\rm argmax}_{\boldsymbol\theta}\left[\mathbb{E}_{\mathbf{z}\sim\mathcal{Z}}\left[\sum_{t=1}^{T} \log \left[Pr(x_{z[t]}|x_{z[<t]}) \right] \right]\right]$


Описанный критерий ищет параметры модели $\boldsymbol\theta$, обеспечивающие максимальную вероятность токенов $x_{z[t]}$ в последовательности длиной $T$ с учетом предыдущих токенов $x_{z[<t]}$, где $z[t]$ это $t^{ый}$ элемент перестановки $z$ индексов токенов и $z[<t]$ предыдущие элементы перестановки. Сумма логарифмов вероятностей означает, что для любой одной перестановки модель авторегрессионна, поскольку она является произведением вероятности для каждого элемента в последовательности. Ожидается, что по всем перестановкам в $\mathcal{Z}$ модель будет обучена одинаково вычислять вероятности для любого токена в любом контексте.


Маска внимания


Но в текущем представлении модели чего-то не хватает: откуда она знает о порядке слов? Модель может вычислить $inline$Pr("This" | "is")$inline$, а также $inline$Pr("This" | "a")$inline$. В идеале она должна кое-что знать об относительном положении "This" и "is", а также "a". В противном случае модель просто бы решила, что все токены в последовательности с равной вероятностью находятся рядом друг с другом. Нам нужна модель, которая предсказывает
$inline$Pr("This" | "is", 2)$inline$ и $inline$Pr("This" | "a", 3)$inline$, а для этого она должна знать индексы токенов контекста.


Архитектура Трансформера решает эту проблему, добавляя позиционную информацию в эмбеддинги токенов. Цель обучения можно представить как $inline$Pr("This" | "is+2")$inline$. Но в случае, если токены предложений действительно будут перемешаны, подобный механизм сломается. И здесь на помощь приходят маски внимания. Когда модель вычисляет контекст, который является входом для вычисления вероятности, она всегда использует один и тот же порядок токенов и просто маскирует те токены, которые не находятся в рассматриваемом контексте (т.е. те, которые поступают впоследствии в перемешанном порядке).


В качестве конкретного примера рассмотрим перестановку $[3, 2, 4, 1]$. При вычислении вероятности первого элемента в этом порядке (т.е. токена 3) модель не имеет контекста, поскольку другие токены еще не были поданы. Таким образом, маска будет $[0, 0, 0, 0]$. Для второго элемента (токен 2) маска равна $[0, 0, 1, 0]$, поскольку его единственный контекст это токен 3. Следуя этой логике, третий и четвертый элементы (токены 4 и 1) имеют маски $[0, 1, 1, 0]$ и $[0, 1, 1, 1]$. Сложив все элементы в порядке токенов, получится матрица (как показано на рис. 2 статьи):


$\begin{bmatrix} 0& 1& 1& 1 \\ 0& 0& 1& 0\\ 0& 0& 0& 0 \\ 0& 1& 1& 0 \end{bmatrix}$


Можно также посмотреть на это с другой стороны: цель обучения будет содержать следующие условия, где подчеркивания представляют маскированные токены:


$inline$Pr("This"|\_\_\_,"is+2","a+3","sentence+4")$inline$


$inline$Pr("is"|\_\_\_,\_\_\_,"a+3",\_\_\_)$inline$


$inline$Pr("a"|\_\_\_,\_\_\_,\_\_\_,\_\_\_)$inline$


$inline$Pr("sentence"|\_\_\_,"is+2","a+3",\_\_\_)$inline$


Двухпотоковый механизм внутреннего внимания


Остается исправить одну ошибку: мы хотим, чтобы вероятность не только зависела от индексов токенов контекста, но и от индекса токена, вероятность которого вычисляется. Другими словами мы хотим вычислить $inline$Pr("This" | "1", "is+2")$inline$: вероятность "This" при условии, что это первый токен, а "is" второй. Но архитектура Трансформера кодирует позиционную информацию 1 и 2 внутри эмбеддинга для "This" и "is". Значит это должно выглядеть как $inline$Pr("This" | "This+1", "is+2")$inline$. К сожалению, модель теперь просто напросто знает, что токен "This" должен быть вероятен как часть предложения.


Решение этой проблемы двухпотоковый механизм внутреннего внимания. Каждая позиция токена $i$ имеет два связанных вектора на каждом слое внутреннего внимания $m$: $\mathbf{h}_i^m$ and $\mathbf{g}_i^m$. Векторы $\mathbf{h}$ принадлежат потоку содержания (content stream), а векторы $\mathbf{g}$ потоку запроса (query stream). Векторы потока содержания инициализируются эмбеддингами токенов, добавленными к позиционным эмбеддингам. Векторы потока запросов инициализируются общим вектором эмбеддинга $\mathbf{w}$, добавленного к позиционным эмбеддингам. Стоит отметить, что вектор $\mathbf{w}$ будет одним и тем же независимо от токена, и поэтому не может использоваться для различения токенов.


На каждом слое каждый вектор содержания $\mathbf{h}_i$ обновляется с использованием тех векторов $\mathbf{h}$, которые остаются немаскированными, и самим собой (эквивалентно демаскированию диагонали из матрицы, показанной в предыдущем разделе). Таким образом, $\mathbf{h}_3$ обновляется маской $[0,0,1,0]$, а вектор $\mathbf{h}_2$ обновляется маской $[0,1,1,0]$. Обновление использует векторы содержания в качестве запроса, ключа и значения.


Каждый вектор запроса $\mathbf{g}_i$, напротив, на каждом уровне обновляется с использованием немаскированных векторов содержания и самого себя. Обновление использует $\mathbf{g}_i$ в качестве запроса, а вектор $\mathbf{h}_j$ в качестве ключей и значений, где $j$ индекс немаскированного токена в контексте $i$.


На рисунке 4 показано, как подчитывается запрос $\mathbf{g}_4^m$ для 4-го токена в $m$-ом слое внутреннего внимания. Это показывает, что $\mathbf{g}_4^m$ представляет собой совокупность "is + 2", "a + 3" и позиции 4, что в точности соответствует контексту, необходимому для вычисления вероятности токена "sentence".


xlnet_figure4


Рис. 4. Двойной механизм внимания для подсчета $\mathbf{g}_4^m$ четвертого токена в $m$-ом слое внутреннего внимания. Стрелки указывают на передачу информацию от векторов. Пересечения линий и кругов указывают на подсчет и агрегацию операций запроса/ключа/значения механизма внутреннего внимания. Желтые линии обозначают обновления потока содержания для третьего символа (зависит только от себя самого) и второго символа (зависит от себя и от третьего символа). Голубые линии обозначают обновление потока запроса (зависит от себя, второго и третьего символа из потока содержания).


В продолжение предыдущей секции, цель обучения может быть сформулирована следующим образом, где $*$ обозначает позицию токена, для которого подсчитывается вероятность:


$inline$Pr("This"|*,"is+2","a+3","sentence+4")$inline$


$inline$Pr("is"|\_\_\_,*,"a+3",\_\_\_)$inline$


$inline$Pr("a"|\_\_\_,\_\_\_,*,\_\_\_)$inline$


$inline$Pr("sentence"|\_\_\_,"is+2","a+3",*)$inline$


Результаты


Работает ли все это? Краткий ответ да. Длинный ответ тоже да. Возможно, это не так уж и удивительно: XLNet опирается на предшествующие современные методы. Она была обучена на корпусе из 30 миллиардов слов (на порядок больше, чем тот, который использовался для обучения BERT'а, и был взят из более разнообразных источников), и это обучение потребовало значительно больше часов вычислительного времени, чем предыдущие модели:


Модель Объем вычислений
ULMFit 1 GPU-день
ELMo 40 GPU-дней
BERT 450 GPU-дней
XLNet 2000 GPU-дней

Таблица 1. Приблизительное время вычислений для обучения актуальных моделей NLP.


Вероятно, более интересно, что исследование абляции XLNet показывает: XLNet работает лучше, чем BERT при честном сравнении (рис. 5). То есть когда модель обучается на том же корпусе, что и BERT, с использованием тех же гиперпараметров и того же количества слоев, она неизменно превосходит BERT. Что еще более интересно, XLNet также превосходит Transformer-XL в честном сравнении. Transformer-XL можно рассматривать как отказ от цели перестановки AR. Постоянное улучшение данного показателя свидетельствует об эффективности этого метода.


Результаты абляции


xlnet_figure5


Рис. 5. Исследование абляции XLNet на четырех бенчмарках: RACE, SQuAD2.0 F1, MNLI mm и SST-2. Результаты сходны с результатами BERT на одном обучающем датасете. Различные столбцы представляют различные настройки обучения, описанные в части 3.7 статьи.


Что не может оценить исследование абляции, так это вклад двухпотокового механизма внутреннего внимания в улучшение производительности XLNet. Последний позволяет механизму внимания явно учитывать позицию целевого токена и вводить дополнительную скрытую емкость в виде векторов потока запросов. Хотя это довольно сложная часть архитектуры XLNet, вполне возможно, что такие модели, как BERT, также могут извлечь выгоду из этого механизма без использования той же цели обучения, что и XLNet.


Авторы


Подробнее..
Категории: Машинное обучение , Nlp , Bert , Xlnet

Как мы ИИ учили новости понимать

04.02.2021 14:12:29 | Автор: admin

Все мы хотим быть в курсе происходящего поэтому часть своего времени тратим на чтение новостей, и сейчас все чаще новости приходят не из новостных сайтов или газет, а из каки-то телеграм-каналов. В итоге, через какое-то время, оказывается, что ты подписан на десяток(а может и на десятки каналов), которые постоянно что-то пишут как следствие, тратится либо огромное количество времени на то, чтобы "что-то не пропустить". Но если посмотреть большинство из них пишут примерно об одном, просто по-разному. Так и пришла идея научить ИИ отбирать новости, которые действительно являются главными. Конечно, есть разные ТОП-ы, вроде Яндекс.Новостей или что-то вроде итогов дня от какого-то уважаемого СМИ, но везде есть нюансики. В этой статье я постараюсь описать эти нюансики и что у нас получилось, а что нет.

Нюансики и источники

Вообще новости очень субъективная вещь, каждый сам выбирает источники кому верить, а кому нет, именно поэтому очень часто получается достаточно однобокая картинка мира, если читать какое-то одно издание там есть редакционная политика, которая чаще всего топит "за определенную повестку". Да, раньше был прекрасный проект Яндекс.Новости, который сейчас тоже превратился в инструмент, где транслируется определенный пул новостей и это не проблема конкретного прокта, скорее это проблема того пула источников с которым они работают. Сразу забегая вперед у нас была аналогичная проблема, когда мы отбирали источники себе.

Чтобы побороть эту пресловутую однобокость мы для себя поставили задачу следующим образом:

  • У нас в качестве источников будут новостные телеграмм-каналы, которые оперативно следят за происходящим

  • Мы постарались отобрать телеграмм каналы с разной повесткой, как раз для того, чтобы уйти от однобокого освещения каких-либо новостей(да-да, по большому счету это тоже можно назвать редакционной политикой на этапе отбора, но придумать более объективный способ у нас не получилось)

  • Все отобранные источники равны, это значит, что канал с 100 тыс. подписчиками и канал с 10 тыс. подписчиками(но при этом уважаемого издания) с точки зрения авторитетности равны. Ну не умеет какое-то гос. СМИ в СММ, ну не игнорировать же его сообщения

Таким образом у нас получилось собрать порядка 100 изданий, который мы "читаем" и пытаемся собрать актуальную новостную картину дня. При этом для начала мы прошлись по рейтингу медиалогии для того, чтобы отобрать топовые таким образом у нас есть и, например, новости из телеграм-канала Известий, GQ, личного канала Ксении Собчак и т.д. Конечно мы посмотрели топовые каналы с огромным количеством подписчиков - типа канала Ивлеевой, но, если честно какой-то полезной информации мы там не нашли.

Собираем свой ТОП

Есть миллион разных вариантов, как можно собирать ТОП, особенно когда ты большой поисковик с кучей ресурсов, кучей перекрёстных данных, индексами цитирования, данными по просмотрам и т.д. Но у нас, очевидно всего этого нет и надо было как-то выкручиваться. В итоге пришлось придумать свою методику отбора сообщений из того, что есть. А было не много просто текст, количество просмотров сейчас и потенциальное количество просмотров(из статистики по каналу в целом)... и вообщем-то все. И да, еще надо не ошибиться то, что ты уже запостил "отпостить" нельзя(конечно технически можно, но тогда надо опять же садить человека, который будет следить и в общем-то теряется весь смысл). Короче, если ты выбрал какую-то новость и запостил помимо всего прочего надо следить за сюжетом и новые сообщения, которые добавляются в сюжет уже постить не надо, даже если очень хочется.

Таким образом перед собой мы поставили себе такую задачу чтобы обрабатывать весь этот поток данных:

  • У нас должна быть методика отбора новостей из разных каналов по принципу "похожести контекста", чтобы понимать что разные источники пишут одну и туже новость

  • У нас должна быть возможность отбирать "сообщения", которые бы максимально коротко и емко описывали новость т.е. чтобы в одном сообщении было как можно меньше "воды" и максимальное количество фактов

  • Новость должна быть "интересной" и эмоциональной т.е. мы должны как-то определить, что аудитория интересуется этой темой сейчас

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

  • определять похожесть текста(потом мы обошлись без нейронки)

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

  • уметь как-то понимать "будет" ли эта новость интересна читателям или нет

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

"Идеальная" нейросеть для NLP

Прочитав кучу статей про достижения трансформеров в решении задачи NLP, конечно же было решено сразу попробовать BERT, ведь с помощью одной обученной нейросети сразу решить все задачи. В интернете даже оказалось несколько обученных моделей на русском языке. Но не тут-то было. На самом деле мы попробовали несколько нейросетей и отказались от них по одной и тоже причине нейросеть, которая отлично себя показывает в MVP не всегда лучший вариант для работы в продуктиве:

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

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

В итоге, наш MVP с BERT умер в первый же день, когда мы попробовали обрабатывать 20 каналов обученная сеть искала криво(надо было тюнить), отдельный сервак, выделенный под работу BERT - отставал от новостей, т.е. количество сообщений приходивших для обработки росло быстрее, чем нейросеть могла их обрабатывать. Конечно можно было купить еще ресурсов, отбалансировать, но в этот момент мы поняли, что придется все начинать с нуля искать другую нейросеть, собирать свои датасеты и обучать(ну или тюнить).

Что перебрали и не выбрали:

  • BERT ресурсоемкая, медленная, сложно добавлять новые сущности NER в существующую модель, нужно достаточно большое количество ресурсов для обучения

  • Natasha очень крутой проект, если вам надо решать задачи NLP для русского языка: быстрая, точная, простой API, но без возможности тюнить самостоятельно. Т.е. если вам хватает функциональности "из коробки" отличное решение

  • Stanza достаточно популярный пакет готовых инструментов для решения NLP задач, наличием готовых моделей, относительно быстрый и точный

Но в итоге мы становились на Spacy, который на наш взгляд дал все, что нужно было нам:

  • достаточную скорость

  • точность и гибкость обучения

  • решение сразу нескольких NLP задач, используя один пакет: NER, лематизацию, анализ тональности текста, анализ зависимостей

  • небольшое потребление ресурсов(по сравнению с той же BERT)

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

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

Собираем датасет

Ни для кого не секрет, что если есть готовая модель и готовый датасет то вопрос обучения, это вопрос времени и ресурсов. И если посмотреть на тот же самый английский язык там все хорошо: есть куча готовых моделей на все случаи жизни. Нет модели окей, есть датасет, дополняй его и обучай или тюнингуй модель для своей задачи. У нас же проблема усугублялась тем, что при решении задачи NER нам было недостаточно стандартных PER, LOC, ORG сущностей, нам важно было добавить еще выделение "денег" и "дат" в разных форматах и формах, т.к. это тоже касается важных фактах в новостях.

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

В зависимости от решаемой задачи можно выбирать один из них или миксовать как-то. Но у всех у них есть одна проблема - они не содержат NER. Конечно можно посадить большое количество людей и разметить нужные вам тексты на нужные вам термины в этих текстах. Но, только если у вас есть ресурсы и время на разметку. У нас такой роскоши не было, и надо было как-то выкручиваться. Поэтому после недолгих поисков был найден еще один прекрасный проект Открытый корпус, который как раз и занимается тем, что собирает и выделяет набор сущностей в тексте. Да, конечно у проекта своя методология выделения сущностей(не совместимы с CONLLU), свои форматы выгружаемых текстов для которых пришлось писать свой парсер для приведения этого корпуса к формату CONLLU. Но, основной плюс этого всего был в том, что весь этот корпус собран вручную.

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

Эмоциональная окраска

Что может быть проще, думали мы и к тому моменту нашли уже несколько датасетов в которых все тексты разделялись на "позитивный" и "негативный". Но когда мы открыли и посмотрели на эти датасеты - нас ждало очередное разочарование:

  • все они в большей степени подходили для оценки комментариев, например для оценки товара, сервиса или продукта

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

  • когда мы говорим про новости зачастую очень сложно понять - а позитивная это новость или негативная, посмотрите, например, на актуальный ТОП сегодняшних новостей и ради интереса попробуйте отнести их к той или иной категории, а потом спросите хотя бы у 3-х друзей как они их отнесут

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

Отказываться было нельзя, поэтому решили собрать свой собственный датасет из "открытых данных". К открытым данным мы отнесли публичные старицы в Facebook(например themeduza, forbesrussia) новостных изданий и, внезапно, новости на государственном сайте ria.ru. И это стало нашим спасением если внимательно посмотреть на любую публикацию - внизу есть важная и нужная нам информация о среднестатистической реакции читателей на эту новость. О чудо! У нас есть - заголовки, короткий текст и полный текст новости, а главное набор реакций большого количества разных людей, реагирующей на эту информацию. После небольшого усложнения нашей инфраструктуры и ~полутора месяцев скрупулёзного сбора данных у нас появился нужный нам датасет.

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

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

Перенос в продуктив

Тут наверное немного надо еще рассказать про инфраструктуру собственно сколько ресурсов нужно для того, чтобы это все работало и не проседало при той нагрузке, которая у нас есть. А есть у нас есть примерно 4-5 тыс сообщений, которые надо распарсить, прогнать через нейронную сеть, которая должна обогатить каждое сообщение метаданными, а потом еще выбрать какое-то сообщение в качестве "главного".

Среднее количество сообщений в деньСреднее количество сообщений в день

И вся эта инфраструктура крутится на 4 GB RAM, 2 vCPUs со средней нагрузкой 8% на CPU, короче все очень экономичненько. Да, много сил и времени заняла тонкая настройка airflow, но это дало свои плоды(для понимания - airflow "из коробки" перманентно нагружал инстанс 16 GB RAM, 4 vCPUs в среднем на 32%). Очевидно, что использование более тяжелых моделей нейросетей требовало бы еще большего количество ресурсов. А в нашем случае, когда у нас сообщения анализируются порционно и все это происходит в рамках DAG-ов, которые каждый раз загружают и выгружают соответствующие модели это бы порушило архитектуру в целом.

ИнфраструктураИнфраструктура

Наконец настал "день X", когда мы собрали и запустили все компоненты в продуктив. На тот момент у нас было:

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

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

  "source": {      "id": 1115468824,      "username": "lentadnya",      "title": "Лента дня",      "participants": 47148    },    "text": "Россия, матушка, забери Донбасс домой: Маргарита Симоньян попросила присоединить Донбасс к России. Тут лучше не пересказывать, просто послушайте",    "views": 405,    "link": "https://t.me/lentadnya/16263",    "interesting": 0.12,    "reaction": {      "enjoyment": 0.04400996118783951,      "sadness": 0.0019097710028290749,      "disgust": 0.8650462031364441,      "anger": 0.08112426102161407,      "fear": 0.00790974497795105    },    "entities": [      "Россия",      "Маргарита Симоньян",      "Донбасс",      "России"    ],    "tags": [      "россия",      "маргарита симоньян",      "донбасс",      "россия"    ]

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

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

Проблема 2: Актуальность NER тут тоже происходит деградация модели. Конечно медленнее, чем для эмоций и интересов, но все равно точность просаживается. Пока эта проблема решается костылем. Костыль в нашем случае вылудит следующим образом - раз в неделю мы деваемы выборку по 100 рандомным сообщениям и вручную(да, к сожалению пока так) оцениваем на сколько точно происходит выявление NER и их лемматизация. Как только показатель падает меньше чем 85%. Происходит обучение модели на новых данных и снова контролируем этот показатель. Есть гипотеза обучить более тяжелую модель, например BERT в качестве "эталонной" и просто периодически сверяться на ней, но пока эта гипотеза только в проработке - если будет интересно, отдельно расскажем об этом как-нибудь.

Проблема 3: Дело в том, что в процессе анализа источников и выборки сообщения для формирования своего собственного рейтинга главных новостей, как я писал в начале, мы используем в том числе показатель, который показывает количество разных источников, которые написали сообщения в этом сюжете. Чтобы понять на сколько этот сюжет сейчас интересный. Ведь чем больше каналов пишут об этом - тем эта "новость" более важна и актуальная. Но мы столкнулись с тем, что в телеграмме есть "консорциумы", которые в определенный момент времени начинают форсить какое либо сообщение. Да, они не репостят одно и тоже сообщение(с этим было бы проще), но они в свойственной тому или иному каналу форсят одну и ту же мысль с указанием одинаковыми набором NER и эмоциональной окраской выводят "новость в топ". Не будем называть конкретные каналы, но в результате таких манипуляций внезапно мы сталкиваемся с картиной, которую мы видим, например в топе новостей у Яндекса. При этом "независимые" каналы, в случае какой-то важной новости реже "в унисон" как следствие. Новости "сеток" прорываются и в наш топ. Да, можно выкинуть соответствующие "сетки" и оставить только один канал из группы, но это противоречит концепции нашей внутренней цензуры, так что пока думаем как решить эту проблему. Если есть предложения пишите в комментарии.

Ну и кто дочитал до этого момента, я надеюсь будет интересно а как же выглядит наш топ: https://t.me/mygenda.

Ну и как говорят модные блоггеры: подписывайтесь, делитесь комментариями и задайте вопросы. Надеюсь это было интересно.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru