Яндекс нейронные сети – Искусственный интеллект в поиске. Как Яндекс научился применять нейронные сети, чтобы искать по смыслу, а не по словам

Содержание

как нейронные сети помогают поиску Яндекса — Блог Яндекса

2 ноября 2016, 11:00

Мы запустили новый поисковый алгоритм — «Палех». Он позволяет поиску Яндекса точнее понимать, о чём его спрашивают люди. Благодаря «Палеху» поиск лучше находит веб-страницы, которые соответствуют запросам не только по ключевым словам, но и по смыслу. За сопоставление смысла запросов и документов отвечает поисковая модель на основе нейронных сетей.

«Длинный хвост»

Каждый день поиск Яндекса отвечает примерно на 280 миллионов запросов. Какие-то из них, например [вконтакте], люди вводят в поисковую строку практически каждую секунду. Какие-то запросы уникальны — их задают один раз, и они, возможно, больше никогда не повторятся. Уникальных и просто редких запросов очень много — около ста миллионов в день.

График частотного распределения запросов в Яндексе часто представляют в виде птицы, у которой есть клюв, туловище и длинный хвост. Список самых распространённых запросов не особо велик, но их задают очень-очень часто — это «клюв» птички. Запросы средней частотности образуют «туловище». Низкочастотные запросы по отдельности встречаются чрезвычайно редко, но вместе составляют существенную часть поискового потока и поэтому складываются в «длинный хвост».

Новый алгоритм позволяет поиску Яндекса лучше отвечать на сложные запросы из «длинного хвоста». Такой хвост есть у сказочной Жар-птицы, которая часто появляется на палехской миниатюре. Поэтому мы дали алгоритму название «Палех».

Запросы из «длинного хвоста» очень разнообразны, но среди них можно выделить несколько групп. Например, одна из них — запросы от детей, которые пока не освоили язык общения с поиском и часто обращаются к нему как к живому собеседнику: [дорогой яндекс посоветуй пожалуйста новые интересные игры про фей для плантика]. Ещё одна группа — запросы от людей, которые хотят узнать название фильма или книги по запомнившемуся эпизоду: [фильм про человека который выращивал картошку на другой планете] («Марсианин») или [фильм где физики рассказывали даме про дейтерий] («Девять дней одного года»).

Особенность запросов из «длинного хвоста» в том, что обычно они более сложны для поисковой системы. Запросы из «клюва» задают многократно, и для них есть масса разнообразной пользовательской статистики. Чем больше знаний о запросах, страницах и действиях пользователей накопил поиск, тем лучше он находит релевантные результаты. В случае с редкими запросами поведенческой статистики может не быть — а значит, Яндексу гораздо труднее понять, какие сайты хорошо подходят для ответа, а какие не очень. Задача осложняется тем, что далеко не всегда на релевантной страничке встречаются слова из запроса — ведь один и тот же смысл в запросе и на странице может быть выражен совершенно по-разному.

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

Семантический вектор

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

В нашем случае мы имеем де

Искусственный интеллект в поиске. Как Яндекс научился применять нейронные сети, чтобы искать по смыслу, а не по словам

Сегодня мы анонсировали новый поисковый алгоритм «Палех». Он включает в себя все те улучшения, над которыми мы работали последнее время.

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

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

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

Искусственный интеллект или машинное обучение?

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

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

Эпоха наивного поиска

Сначала был просто поиск слов — инвертированный индекс. Потом страниц стало слишком много, их стало нужно ранжировать. Начали учитываться разные усложнения — частота слов, tf-idf.

Эпоха ссылок

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

Эпоха машинного обучения

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

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

Один из лучших алгоритмов машинного обучения изобрели в Яндексе — Матрикснет. Можно сказать, что ранжированию помогает коллективный разум пользователей и «мудрость толпы». Информация о сайтах и поведении людей преобразуется во множество факторов, каждый из которых используется Матрикснетом для построения формулы ранжирования. Фактически, формулу ранжирования пишет машина (получалось около 300 мегабайт).

Но у «классического» машинного обучения есть предел: оно работает только там, где очень много данных. Небольшой пример. Миллионы пользователей вводят запрос [вконтакте], чтобы найти один и тот же сайт. В данном случае их поведение является настолько сильным сигналом, что поиск не заставляет людей смотреть на выдачу, а подсказывает адрес сразу при вводе запроса.

Но люди сложнее, и хотят от поиска всё больше. Сейчас уже до 40% всех запросов уникальны, то есть не повторяются хотя бы дважды в течение всего периода наблюдений. Это значит, что у поиска нет данных о поведении пользователей в достаточном количестве, и Матрикснет лишается ценных факторов. Такие запросы в Яндексе называют «длинным хвостом», поскольку все вместе они составляют существенную долю обращений к нашему поиску.

Эпоха искусственного интеллекта

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

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

Как правило, низкочастотные и уникальные запросы довольно сложны для поиска – найти хороший ответ по ним заметно труднее. Как это сделать? У нас нет подсказок от пользователей (какой документ лучше, а какой — хуже), поэтому для решения поисковой задачи нужно научиться лучше понимать смысловое соответствие между двумя текстами: запросом и документом.

Легко сказать

Строго говоря, искусственные нейросети – это один из методов машинного обучения. Совсем недавно им была посвящена лекция в рамках Малого ШАДа. Нейронные сети показывают впечатляющие результаты в области анализа естественной информации — звука и образов. Это происходит уже несколько лет. Но почему их до сих пор не так активно применяли в поиске?

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

Несколько слов о том, как это работает в поиске по картинкам. Вы берёте изображение и с помощью нейронных сетей преобразуете его в вектор в N-мерном пространстве. Берете запрос (который может быть как в текстовом виде, так и в виде другой картинки) и делаете с ним то же самое. А потом сравниваете эти вектора. Чем ближе они друг к другу, тем больше картинка соответствует запросу.

Ок, если это работает в картинках, почему бы не применить эту же логику в web-поиске?

Дьявол в технологиях

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

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

Дальше — о том, что мы пробовали, как добились успеха и как смогли обучить то, что получилось.

DSSM

В 2013 году исследователи из Microsoft Research описали свой подход, который получил название Deep Structured Semantic Model.

На вход модели подаются тексты запросов и заголовков. Для уменьшения размеров модели, над ними производится операция, которую авторы называют word hashing. К тексту добавляются маркеры начала и конца, после чего он разбивается на буквенные триграммы. Например, для запроса [палех] мы получим триграммы [па, але, лех, ех]. Поскольку количество разных триграмм ограничено, то мы можем представить текст запроса в виде вектора размером в несколько десятков тысяч элементов (размер нашего алфавита в 3 степени). Соответствующие триграммам запроса элементы вектора будут равны 1, остальные — 0. По сути, мы отмечаем таким образом вхождение триграмм из текста в словарь, состоящий из всех известных триграмм. Если сравнить такие вектора, то можно узнать только о наличии одинаковых триграмм в запросе и заголовке, что не представляет особого интереса. Поэтому теперь их надо преобразовать в другие вектора, которые уже будут иметь нужные нам свойства семантической близости.

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

Мы в Яндексе также активно исследуем модели на основе искусственных нейронных сетей, поэтому заинтересовались моделью DSSM. Дальше мы расскажем о своих экспериментах в этой области.

Теория и практика

Характерное свойство алгоритмов, описываемых в научной литературе, состоит в том, что они не всегда работают «из коробки». Дело в том, что «академический» исследователь и исследователь из индустрии находятся в существенно разных условиях. В качестве отправной точки (baseline), с которой автор научной публикации сравнивает своё решение, должен выступать какой-то общеизвестный алгоритм — так обеспечивается воспроизводимость результатов. Исследователи берут результаты ранее опубликованного подхода, и показывают, как их можно превзойти. Например, авторы оригинального DSSM сравнивают свою модель по метрике NDCG с алгоритмами BM25 и LSA. В случае же с прикладным исследователем, который занимается качеством поиска в реальной поисковой машине, отправной точкой служит не один конкретный алгоритм, а всё ранжирование в целом. Цель разработчика Яндекса состоит не в том, чтобы обогнать BM25, а в том, чтобы добиться улучшения на фоне всего множества ранее внедренных факторов и моделей. Таким образом, baseline для исследователя в Яндексе чрезвычайно высок, и многие алгоритмы, обладающие научной новизной и показывающие хорошие результаты при «академическом» подходе, оказываются бесполезны на практике, поскольку не позволяют реально улучшить качество поиска.

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

Большой входной слой

В оригинальной модели DSSM входной слой представляет собой множество буквенных триграмм. Его размер равен 30 000. У подхода на основе триграмм есть несколько преимуществ. Во-первых, их относительно мало, поэтому работа с ними не требует больших ресурсов. Во-вторых, их применение упрощает выявление опечаток и ошибок в словах. Однако, наши эксперименты показали, что представление текстов в виде «мешка» триграмм заметно снижает выразительную силу сети. Поэтому мы радикально увеличили размер входного слоя, включив в него, помимо буквенных триграмм, ещё около 2 миллионов слов и словосочетаний. Таким образом, мы представляем тексты запроса и заголовка в виде совместного «мешка» слов, словесных биграмм и буквенных триграмм.

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

Тяжело в обучении: как нейронная сеть боролась сама с собой и научилась на своих ошибках

Обучение исходного DSSM состоит в демонстрации сети большого количества положительных и отрицательных примеров. Эти примеры берутся из поисковой выдачи (судя по всему, для этого использовался поисковик Bing). Положительными примерами служат заголовки кликнутых документов выдачи, отрицательными — заголовки документов, по которым не было клика. У этого подхода есть определённые недостатки. Дело в том, что отсутствие клика далеко не всегда свидетельствует о том, что документ нерелевантен. Справедливо и обратное утверждение — наличие клика не гарантирует релевантности документа. По сути, обучаясь описанным в исходной статье образом, мы стремимся предсказывать аттрактивность заголовков при условии того, что они будут присутствовать в выдаче. Это, конечно, тоже неплохо, но имеет достаточно косвенное отношение к нашей главной цели — научиться понимать семантическую близость.

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

Первая попытка

Сначала в качестве отрицательного примера просто возьмём заголовок случайного документа. Например, для запроса [палехская роспись] случайным заголовком может быть «Правила дорожного движения 2016 РФ». Разумеется, полностью исключить то, что случайно выбранный из миллиардов документ будет релевантен запросу, нельзя, но вероятность этого настолько мала, что ей можно пренебречь. Таким образом мы можем очень легко получать большое количество отрицательных примеров. Казалось бы, теперь мы можем научить нашу сеть именно тому, чему хочется — отличать хорошие документы, которые интересуют пользователей, от документов, не имеющих к запросу никакого отношения. К сожалению, обученная на таких примерах модель оказалась довольно слабой. Нейронная сеть – штука умная, и всегда найдет способ упростить себе работу. В данном случае, она просто начала выискивать одинаковые слова в запросах и заголовках: есть — хорошая пара, нет — плохая. Но это мы и сами умеем делать. Для нас важно, чтобы сеть научилась различать неочевидные закономерности.

Ещё одна попытка

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

Успех

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

Подобная схема обучения в научной литературе обычно называется hard negative mining. Также нельзя не отметить, что схожие по идее решения получили широкое распространение в научном сообществе для генерации реалистично выглядящих изображений, подобный класс моделей получил название Generative Adversarial Networks.

Разные цели

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

Профит

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

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







Заголовок страницы BM25 Нейронная модель
келлская книга википедия 0.91 0.92
ученые исследуют келлскую книгу вокруг света 0.88 0.85
book of kells wikipedia 0 0.81
ирландские иллюстрированные евангелия vii viii вв 0 0.58
икеа гипермаркеты товаров для дома и офиса ikea 0 0.09

Все факторы в Яндексе нормируются в интервал [0;1]. Вполне ожидаемо, что BM25 имеет высокие значения для заголовков, которые содержат слова запроса. И вполне предсказуемо, что этот фактор получает нулевое значение на заголовках, не имеющих общих слов с запросом. Теперь обратите внимание на то, как ведет себя нейронная модель. Она одинаково хорошо распознаёт связь запроса как с русскоязычным заголовком релевантной страницы из Википедии, так и с заголовком статьи на английском языке! Кроме того, кажется, что модель «увидела» связь запроса с заголовком, в котором не упоминается келлская книга, но есть близкое по смыслу словосочетание («ирландские евангелия»). Значение же модели для нерелевантного заголовка существенно ниже.

Теперь давайте посмотрим, как будут себя вести наши факторы, если мы переформулируем запрос, не меняя его смысла: [евангелие из келлса].







Заголовок страницы BM25 Нейронная модель
келлская книга википедия 0 0.85
ученые исследуют келлскую книгу вокруг света 0 0.78
book of kells wikipedia 0 0.71
ирландские иллюстрированные евангелия vii viii вв 0.33 0.84
икеа гипермаркеты товаров для дома и офиса ikea 0 0.10

Для BM25 переформулировка запроса превратилась в настоящую катастрофу — фактор стал нулевым на релевантных заголовках. А наша модель демонстрирует отличную устойчивость к переформулировке: релевантные заголовки по-прежнему имеют высокое значение фактора, а нерелевантный заголовок — низкое. Кажется, что именно такое поведение мы и ожидали от штуки, которая претендует на способность «понимать» семантику текста.

Ещё пример. Запрос [рассказ в котором раздавили бабочку].







Заголовок страницы BM25 Нейронная модель
фильм в котором раздавили бабочку 0.79 0.82
и грянул гром википедия 0 0.43
брэдбери рэй википедия 0 0.27
машина времени роман википедия 0 0.24
домашнее малиновое варенье рецепт заготовки на зиму 0 0.06

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

А что дальше?

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

Например, очевидно, что заголовок содержит неполную информацию о документе, и хорошо бы научиться строить модель по полному тексту (как оказалось, это не совсем тривиальная задача). Далее, можно представить себе модели, имеющие существенно более сложную архитектуру, нежели DSSM — есть основания предполагать, что таким образом мы сможем лучше обрабатывать некоторые конструкции естественных языков. Свою долгосрочную цель мы видим в создании моделей, способных «понимать» семантическое соответствие запросов и документов на уровне, сравнимом с уровнем человека. На пути к этой цели будет много сложностей — тем интереснее будет его пройти. Мы обещаем рассказывать о своей работе в этой области. Cледите за следующими публикациями.

Как Яндекс научил искусственный интеллект находить ошибки в новостях

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

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

Задача

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

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

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

Инструменты

У Яндекса есть технология Спеллер для поиска и исправления ошибок. Благодаря библиотеке машинного обучения CatBoost Спеллер может расшифровывать искажённые до неузнаваемости слова («адникасниеи» → «одноклассники») и учитывать контекст при поиске опечаток («скучать музыку» → «скачать музыку»). Может показаться, что Спеллер идеален для нашей задачи, но нет.

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

Ошибки в заголовках делают относительно грамотные люди, которые вряд ли напишут «Хамингуэль». А вот неверное согласование («рейс задержалась»), пропущенные слова («молодой человек пытался автомобиль») и лишние заглавные буквы («Президент Банка») — обычное дело. Наконец, бывает формально верное предложение «В Пскове отремонтирую улицу Горького», к которому нормальный опечаточник не придерётся (ну а вдруг это обещание автора?), — но это очевидно испорченный новостной заголовок. Кроме того, в Новостях задача ставилась не такая, как в Поиске: не исправить опечатки и ошибки, а обнаружить их.

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

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

Знакомство с BERT

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

Но есть вариант обойти эту проблему — с помощью обучения в два этапа. Сначала долго и дорого на огромном корпусе в миллиарды слов нейросеть учат структуре языка (это pre-training). Потом сеть быстро и дёшево подкручивают под конкретную задачу — например, для разделения отзывов на плохие и хорошие (это fine-tuning). Хватит каких-нибудь 10 тысяч примеров, размеченных в Толоке.

На этой идее и основана технология BERT (Bidirectional Encoder Representations from Transformers). Сама идея не нова и применялась раньше, но есть существенное отличие. Transformer — это такая архитектура нейросетки, которая позволяет учитывать весь контекст сразу, включая другой конец предложения и причастный оборот где-нибудь в середине. И в этом её отличие от предыдущих модных архитектур, которые учитывали контекст. Например, у нейросети LSTM длина контекста — в лучшем случае десятки слов, а тут все 200.

На GitHub доступен исходный код на TensorFlow и даже предобученная универсальная модель на 102 языка, от русского до волапюка. Бери, казалось бы, решение из коробки — и получай результат немедленно. Но нет.

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

Окей, предобучиться можно и самим — к счастью, русских текстов и опыта в машинном обучении у Яндекса хватает. Но есть нюанс. Обучаться надо год!

Дело в том, что BERT заточена под тензорные процессоры Google (TPU), поэтому из коробки умеет работать только с одной видеокарточкой (GPU). И распараллелить в лоб с помощью какого-нибудь horovod нельзя: перебрасывать с карты на карту 400 мегабайт данных на каждом шаге очень дорого, распараллеливание станет бессмысленным. Что делать?

Оптимизация

Начали искать любые идеи и решения, способные значительно ускорить дело. В первую очередь обратили внимание на то, что каждое число в нашей модели занимало 32 бита памяти (стандартный float для чисел в компьютере). Вроде бы мало, но когда у вас 100 миллионов весов, то это критично. Такая точность нам не везде была нужна, поэтому мы решили частично перевести числа в 16-битный формат (это то, что называется mixed precision training).

Попутно с помощью множества напильников и костылей прикрутили XLA-компиляцию, опираясь на тогда ещё сырой коммит NVIDIA. Благодаря этому наши карточки NVIDIA Tesla V100 (небольшой сервер из них стоит как квартира в недорогом районе Москвы) смогли в полной мере раскрыть свой потенциал за счёт 16-битной арифметики на Tensor Cores.

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

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

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

Обучение

Собрать правильный датасет — обычно самая трудная часть работы. Сначала мы учили классификатор на трёх миллионах заголовков, размеченных толокерами. Вроде бы много, но только 30 тысяч из них — с опечатками. Где взять ещё примеров?

Мы решили поглядеть, какие заголовки исправляют сами СМИ. Таких за всю историю Яндекс.Новостей набралось больше 2 миллионов. Бинго! Хотя радоваться было рано.

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

Качество

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

В нашем предыдущем подходе на базе DSSM мы уже добились точности 95% (то есть 5% ложноположительных вердиктов). Это уже достаточно высокий показатель. Поэтому мы решили сохранить такой же уровень точности и посмотреть, как с помощью новой модели изменится полнота. И она подскочила с 21 до 78%. И это определённо успех.

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

Нейросеть с фломастером

Принято считать, что нейросеть — это такой чёрный ящик. Мы подаём что-то на вход и получаем что-то на выходе. А почему и как — загадка.

Это ограничение призваны обойти интерпретируемые нейронные сети. BERT — одна из них. Её интерпретируемость заключается в механизме attention. Грубо говоря, в каждом слое нейросетки мы повторяем один и тот же приём: смотрим на соседние слова с разным «вниманием» и учитываем взаимодействие с ними. Например, когда нейросеть обрабатывает местоимение «он», то «внимательно смотрит» на существительное, к которому «он» относится.

Картинка ниже показывает разными оттенками красного, на какие слова «смотрит» токен, который накапливает информацию обо всём заголовке для финального слоя-классификатора. Если опечатка в слове — attention подсвечивает его, если слова рассогласованы — то оба (и, возможно, зависимые от них).

В этом месте, кстати, можно разглядеть возможности нейросетей в полный рост. Ни на одном этапе обучения наша модель не знает, где именно находится опечатка в примере: она знает только, что весь заголовок неправильный. И всё равно она выучивает, что «школа на 1224 мест» писать неправильно из-за несогласованного числительного, — и подсвечивает конкретно цифру 4.

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

Полезные ссылки для тех, кто хочет углубиться в тему

«Нейронные сети» — Яндекс.Знатоки

Для того, чтобы нейросеть работала, ее нужно обучить на датасете.

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

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

Итак, как работает прямое распространение?

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

Как работает обратное распространение ошибки?

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

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

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

«Как работает нейросеть?» – Яндекс.Кью

Для того, чтобы нейросеть работала, ее нужно обучить на датасете.

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

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

Итак, как работает прямое распространение?

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

Как работает обратное распространение ошибки?

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

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

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

как научить нейронную сеть светской беседе. Лекция в Яндексе / Яндекс corporate blog / Habr

Хороший виртуальный ассистент должен не только решать задачи пользователя, но и разумно отвечать на вопрос «Как дела?». Реплик без явной цели очень много, и заготовить ответ на каждую проблематично. Neural Conversational Models — сравнительно новый способ создания диалоговых систем для свободного общения. Его основа — сети, обученные на больших корпусах диалогов из интернета. Борис hr0nix Янгель рассказывает, чем хороши такие модели и как их нужно строить.

Под катом — расшифровка и основная часть слайдов.


Спасибо, что пришли. Меня зовут Боря Янгель, я в Яндексе занимаюсь применением deep learning к текстам на естественном языке и диалоговыми системами. Я сегодня вам хочу рассказать про Neural Conversational Models. Это сравнительно новая область исследований в deep learning, задача которой — научиться разрабатывать нейронные сети, которые с собеседником разговаривают на некоторые общие темы, то есть ведут то, что можно условно назвать светской беседой. Говорят «Привет», обсуждают, как у тебя дела, ужасную погоду или фильм, который ты недавно посмотрел. И сегодня я хочу рассказать, что в этой области уже было сделано, что можно делать на практике, пользуясь результатами, и какие остались проблемы, которые только предстоит решить.

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

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

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

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

Как их можно делать?

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


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


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

Чтобы решать такую задачу с помощью deep learning, нам хорошо бы иметь корпус с диалогами. Этот корпус лучше бы был большим, потому что deep learning с маленькими текстовыми корпусами — сами, наверное, знаете, как он работает. Хорошо бы, чтобы диалоги были на нужные нам темы. То есть если мы хотим сделать бота, который будет обсуждать с вами ваши чувства или говорить о погоде, то такие диалоги должны быть в диалоговом корпусе. Поэтому корпус диалогов со службой поддержки интернет-провайдера нам в решении проблемы вряд ли подойдет.

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

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

В литературе, то есть в статьях про Neural Conversational Models, очень любят два датасета.


Первый из них — Open Subtitles. Это просто субтитры из огромного числа американских фильмов и сериалов. Какие плюсы этого датасета? В нем очень много жизненных диалогов, прямо таких, которые нам нужны, потому что это фильмы, сериалы, там люди часто говорят друг другу: «Привет! Как дела?», обсуждают какие-то жизненные вопросы. Но поскольку это фильмы и сериалы, то здесь же кроется и минус датасета. Там много фантастики, много фэнтези, которое аккуратно нужно вычищать, и много довольно своеобразных диалогов. Я помню, первая модель, которую мы обучили на Open Subtitles, она к месту и не к месту очень много про вампиров почему-то говорила. На вопрос «Откуда ты?» иногда отвечала: «Я, мать твою, из ФБР». Кажется, что не каждый захочет, чтобы его диалоговый продукт вел себя таким образом.

Это не единственная проблема датасета с субтитрами. Он как сформирован? Надеюсь, многие из вас знают, что такое srt-файлы. Фактически авторы датасета просто взяли srt-файлы этих фильмов и сериалов, все реплики оттуда и записали в огромный текстовый файл. Вообще говоря, в srt-файлах ничего не понятно о том, кто какую реплику говорит и где заканчивается один диалог и начинается другой. Можно пользоваться разными эвристиками: например, предполагать, что две последовательные реплики всегда говорят разные спикеры, или, например, что если между репликами прошло больше 10 секунд, то это разные диалоги. Но подобные предположения выполняются в 70% случаев, и это создает много шума в датасете.

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

Мораль какая? С субтитрами нужно быть осторожным. На них, наверное, можно предобучать модели, но учить до конца с учетом всех этих минусов я не советую.

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

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

Мы это выяснили следующим образом. Мы обучили какую-то модель на Твиттере в первый раз и задали ей несколько простых вопросов типа «Ты где?» и «Сколько тебе лет?».


В общем, на вопрос «Ты где?» единственный цензурный ответ был «В школе», а все остальные отличались разве что знаками препинания. Но ответ на вопрос «Сколько тебе лет?» окончательно расставил все на свои места. Поэтому тут мораль какая? Если хотите учить диалоговые системы на этом датасете, то проблему школьников как-то надо решить. Например, надо пофильтровать датасет. Ваша модель будет разговаривать как часть спикеров — нужно оставить только нужную часть или воспользоваться одним из методов кластеризации спикеров, про которую я чуть дальше поговорю.

Эти два датасета любят в научной литературе. А если вы собираетесь делать что-то на практике, то вы во многом ограничены разве что своей фантазией и названием компании, на которую вы работаете. Например, если вы Facebook, то вам повезло иметь свой мессенджер, где огромное количество диалогов как раз на те темы, которые нас интересуют. Если вы не Facebook, у вас все еще есть какие-то возможности. Например, можно достать данные из публичных чатов в Telegram, в Slack, в каких-то IRC-каналах, можно распарсить какие-то форумы, поскрепить какие-то комментарии в социальных сетях. Можно скачать сценарии фильмов, которые на самом деле следуют некоторому формату, который в принципе можно распарсить автоматически — и даже понять, где там кончается одна сцена, где кончается другая и кто автор конкретной реплики. Наконец, можно какие-то транскрипты телепередач найти в интернете, и я на самом деле уверен, что я перечислил только малую часть всевозможных источников для диалогового корпуса.


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

Сперва поговорим про первый подход — порождающий.


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

Итак, рекуррентные сети — это такая нейросетевая архитектура для работы с последовательностями произвольной длины. Работает она следующим образом.

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

На самом деле такими формулами обновления никто не пользуется, потому что если обучать такие нейронные сети, возникает очень много неприятных проблем. Пользуются более продвинутыми архитектурами. Например, LSTM (Long short-term memory) и GRU (Gated recurrent units). Дальше, когда мы будем говорить «рекуррентная сеть», мы будем предполагать что-то более продвинутое, чем простые рекуррентные сети.


Порождающий подход. О нашей задаче генерации реплики в диалоге по контексту можно думать как о задаче генерации строки по строке. То есть представим, что мы возьмем весь контекст, все предыдущие сказанные реплики, и просто сконкатенируем их, разделяя реплики разных спикеров некоторым специальным символом. Получается задача генерации строки по строке, а такие задачи неплохо изучены в машинном обучении, в частности — в машинном переводе. И стандартная архитектура в машинном переводе — так называемая sequence-to-sequence. И state of the art в машинном переводе — это все еще модификация подхода sequence-to-sequence. Он был предложен Суцкевером в 2014 году, а позже как раз адаптирован его соавторами для нашей задачи, Neural Conversational Models.

Что такое sequence-to-sequence? Это рекуррентная архитектура encoder-decoder, то есть это две рекуррентных сети: encoder и decoder. Encoder прочитывает исходную строку и генерирует некоторое ее конденсированное представление. Это конденсированное представление подается на вход декодеру, который уже должен сгенерировать выходную строку или для каждой выходной строки сказать, какая же у нее вероятность в этом условном распределении, которое мы пытаемся смоделировать.


Выглядит это следующим образом. Желтенькое — сеть encoder. Допустим, у нас есть диалог двух спикеров из двух реплик «Привет» и «Здаров», для которого мы хотим сгенерировать ответ. Реплики спикеров мы разделим специальным символом end-of-sentense, eos. На самом деле не всегда разделяют предложение, но исторически его называют именно так. Каждое слово мы сперва погрузим в некоторое векторное пространство, сделаем то, что называется vector embedding. Затем этот вектор для каждого слова мы подадим на вход сети encoder, и последнее состояние сети encoder после того, как она обработает последнее слово, как раз и будет нашим конденсированным представлением контекста, которое мы подадим на вход в decoder. Мы можем, например, инициализировать первое скрытое состояние сети decoder этим вектором или, в качестве альтернативы, например, подать его на каждый timestamp вместе со словами. Сеть decoder на каждом шаге генерирует очередное слово реплики и на вход получает предыдущее слово, которое она сгенерировала. Это позволяет действительно лучше моделировать условное распределение. Почему? Я не хочу вдаваться сейчас в детали.

Генерирует decoder все до тех пор, пока не сгенерирует токен end-of-sentence. Это значит, что «Все, хватит». А на вход на первом шаге decoder, как правило, тоже получает токен end-of-sentence. И непонятно, что ему на вход нужно подать.


Обычно такие архитектуры обучаются с помощью обучения maximum likelihood. То есть мы берем условное распределение на ответы при известных нам контекстах в обучающей выборке и пытаемся сделать известные нам ответы как можно более вероятными. То есть максимизируем, допустим, логарифм такой вероятности по параметрам нейронной сети. А когда нам нужно сгенерировать реплику, у нас параметры нейронной сети уже известны, потому что мы их обучили и зафиксировали. И мы просто максимизируем условное распределение по ответу или сэмплируем из него. На самом деле точно его промаксимизировать нельзя, поэтому приходится пользоваться некоторыми приближенными методами. Например, есть метод стохастического поиска максимума в таких архитектурах encoder-decoder. Называется beam search. Что это такое, я тоже сейчас рассказать не успею, но ответ на данный вопрос легко найти в интернете.

Все модификации этой архитектуры, которые были придуманы для машинного перевода, можно попробовать применить и для Neural Conversational Models. Например, encoder и decoder, как правило, многослойные. Они работают лучше, чем однослойная архитектура. Как я уже сказал, это, скорее всего, LSTM- или GRU-сети, а не обычные RNN.

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

Потом в машинном переводе есть такой трюк, прием, который называется attention. Его идея примерно в следующем. Каждый раз, когда ваш декодер генерирует очередное слово, вы можете еще дополнительно посмотреть на все слова или на скрытое представление на каждом timestamp в encoder и как-то их взвесить согласно тому, что вам сейчас нужно. Например, для генерации очередного слова вам нужно найти какой-нибудь следующий предлог во входной последовательности или понять, какая именованная сущность там определялась. Механизм attention помогает это сделать, и он немного помогает в Neural Conversational Models, но на самом деле намного меньше, чем в машинном переводе. Кажется, так происходит потому, что в машинном переводе в большинстве случаев для перевода очередного слова нужно посмотреть на одно слово в исходной последовательности. А при генерации реплики нужно посмотреть на много слов. И возможно, здесь будут работать лучше какие-то приемы, аналогичные тем, которые используются в memory networks. Типа multi-hole potential.

На самом деле того, что я вам сейчас рассказал, уже достаточно для создания некой Neural Conversational Model — при условии, что у вас есть данные. И она как-то будет разговаривать. Не могу сказать, что прямо очень плохо, но если вы будете с ней говорить, вы неизбежно столкнетесь с рядом проблем.

Первая проблема, которую вы увидите, — так называемая проблема слишком «общих» реплик. Это известная проблема модели encoder-decoder sequence-to-sequence, которая заключается в следующем. Такие модели склонны генерировать некие очень общие короткие по длине фразы, которые подходят к большому числу контекстов. Например, «Я не знаю», «Окей», «Я не могу сказать» и т. д. Почему так происходит? Можно, например, почитать статью, где авторы попытались формализовать некоторым образом это явление и показали, что в таких архитектурах оно будет происходить неизбежно.

В литературе про Neural Conversational Models предложен ряд решений или, я бы сказал, «костылей» для решения этой проблемы. Все они основаны на том, что мы по-прежнему обучаем модели в режиме максимизации правдоподобия, но когда генерируем реплику, то максимизируем не правдоподобие, а некоторый модифицированный функционал, который в себе это правдоподобие содержит.


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

Что это значит на практике? Вот было такое выражение, которое мы максимизировали по ответу. А теперь давайте добавим к нему такой член. Это некий коэффициент, умноженный на априорную вероятность ответа. На самом деле это некое обобщение взаимной информации между ответом и контекстом. Такой коэффициент равен единице — получается как раз взаимная информация. Если он равен нулю, то получается исходный функционал. Но он может принимать этот параметр и промежуточные значения, чтобы вам можно было что-нибудь настроить в своем методе.

Какой у этого выражения смысл? Если мы его будем максимизировать, то теперь мы ищем не только уместный ответ при условии контекста, но и пенализируем ответы с большой априорной вероятностью. То есть, грубо говоря, пенализируем те ответы, которые часто встречаются в обучающем корпусе и которые можно сказать по поводу и без повода — как раз эти «Привет», «Как дела» и т. д.

Чтобы этим методом воспользоваться, вам теперь нужно не только обучить модель sequence-to-sequence, которая выдает указанную вероятность, но и обучить некоторую языковую модель на всевозможных ответах — чтобы получить эту вероятность. То есть возникает минус — нужно две модели.


Есть альтернативный способ переписать этот функционал, а точнее — записать другой функционал, который равен предыдущему с точностью до константы. Он факторизован немножко по-другому. Здесь все еще есть наша условная вероятность ответа при условии контекста, а еще есть вероятность контекста при условии ответа. Это можно проинтерпретировать следующим образом. Мы хотим не только ответы, уместные в данном контексте, но и такие ответы, по которым легко восстановить исходный контекст. То есть если ответ слишком общий, «Окей» или «Я не знаю», то совершенно непонятно, в каком контексте это было сказано. И такие ответы мы хотим штрафовать. Чтобы таким приемом воспользоваться, вам нужна и модель sequence-to-sequence, которая ответ генерирует по контексту, и модель sequence-to-sequence, которая контекст генерирует по ответу. То есть вам всё ещё нужны две модели.

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

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


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

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

Вот одно из решений, которое было предложено в литературе, в статье «A Persona-Based Neural Conversation Model»: давайте мы каждому спикеру дополнительно сопоставим вектор в некотором латентном пространстве спикеров. Так же, как мы слова погружаем в латентное пространство, мы и этот вектор будем подавать на вход декодеру в надежде, что при обучении мы туда запишем какую-то информацию, которая нужна, чтобы генерировать ответы от имени данного спикера. То есть, грубо говоря, запишем туда его пол, возраст, какие-то лексические особенности и т. д. И тут же у нас появится некий инструмент контроля поведения модели. Другими словами, мы компоненты этого вектора потом как-то сможем настраивать и, возможно, добиваться от сети желаемого поведения.


Но выглядит это в архитектуре sequence-to-sequence примерно следующим образом: все как раньше, только тут добавляется еще один вектор, который подается на каждый timestamp декодера. Например — конкатинируется с этим embedding-вектором слова.

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


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


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


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

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

Тут идея такая: вместо того, чтобы генерировать ответ с помощью какого-то вероятностного распределения, мы будем ранжировать ответы из некоторого пула согласно функции уместности ответа при условии контекста, которую мы обучим. Какие плюсы у такого подхода? Вы полностью контролируете пул ответов. Вы можете исключить грамматически некорректные ответы или ответы с обсценной лексикой, например. Тогда вы их никогда не сгенерируете, и вы меньше рискуете, чем при использовании порождающей модели, о которой я говорил раньше. Обучение таких архитектур происходит на порядки быстрее, и меньше проявляется проблема общих ответов — потому что она, скорее, свойственна архитектурам sequence-to-sequence encoder-decoder.

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


Как обычно устроены ранжирующие модели? Примерно следующим образом. Есть две сети, которые тут уже называются — и та сеть, и другая — encoder. Задача одной сети — получить некоторое конденсированное векторное представление контекста, другой — векторное представление ответа. Дальше уместность контекста при условии ответа считается с помощью некоторой функции сравнения двух векторов, но и получается в итоге некоторое число, которое говорит об уместности. Такая архитектура стала популярной после статьи Microsoft Research про DSSM, Deep Structure Semantic Models, в 2013 году. И впоследствии указанная архитектура тоже была не раз адаптирована во множестве разных статей для Neural Conversational Models.

Сети encoder, в принципе, могут быть любыми, если они по набору слов могут получить вектор. Например, это тоже могут быть рекуррентные сети — как и в архитектурах sequence-to-sequence. Или можно пойти более простым путем: это могут быть полносвязанные сети поверх усредненных эмбединговых слов. Тоже на удивление неплохо работает.

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

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

Где брать отрицательные примеры? Классический подход — random sampling, когда вы просто берете случайные реплики в вашем датасете, говорите, что с большой вероятностью они неуместны и на это предположение опираетесь. Есть чуть более нетривиальный подход, который называется hard negative mining. Там идея такая: вы выбираете случайные реплики, но потом из случайных выбираете те, на которых сейчас модель сильнее всего ошибается.

С недавних пор в веб-ранжировании Яндекса существует алгоритм «Палех». Он во многом опирается на аналогичную архитектуру, и в статье на Хабрахабре написано, как этот hard negative mining может работать.

Теперь у вас есть положительные и отрицательные примеры. Что со всем этим делать? Нужна какая-то функция штрафа. Как правило, поступают очень просто: берут выходы этой функции Sim, которая является скалярным произведением или косинусным расстоянием, прогоняют через softmax и получают вероятностное распределение на ваш положительный пример и сколько-то отрицательных примеров, которые вы нагенерировали. А потом, как и в порождающих моделях, просто пользуются кроссэнтропийным лоссом, то есть хотят, чтобы вероятность правильного ответа была большой по сравнению с вероятностью неправильных. Есть всякие модификации на основе tripletloss. Это что-то типа подходов max margin, когда вы хотите, чтобы уместность вашего ответа при условии контакта была больше, чем уместность случайного ответа при условии контекста на некоторый margin, как в SVN. Про это тоже в интернете можно много всего интересного найти.

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

Каким же способом пользоваться тогда? Сейчас State of the art, если можно так сказать, подход — использовать краудсорсинг, то есть брать условный mechanical turk, и спрашивать у тёркеров: «Уместен ли данный ответ в данном контексте? Оцените по шкале от 0 до 5». Или: «Какой из данных ответов более уместен в этом контексте?». Если вы посмотрите литературу, в конечном итоге всем приходится сравнивать модели именно так.


А что лучше: порождающие или ранжирующие модели? Вот мы взяли некоторую модель, которую обучили сами на Твиттере sequence-to-sequence, взяли ранжирующую DSSM-подобную модель и дальше на нашей краудсорсинговой платформе попросили работников оценить уместность каждого ответа при данном контексте, поставить одну из трех меток: bad, neutral или good. Bad значит, что ответ синтаксически некорректен, абсолютно неуместен или, например, содержит обсценную лексику. Neutral значит, что он уместен, но является общим и неинтересным. А good — что это синтаксически корректный и уместный ответ. И еще мы попросили людей сгенерировать сколько-то ответов, чтобы у нас был некий baseline, к которому можно стремиться. Вот какие получились цифры.

Что интересно, у людей есть 10% плохих ответов. Почему так происходит? Оказывается, в большинстве случаев люди пытались пошутить, но работники на краудсорсинговой платформе их шутку не поняли. Там, по-моему, в пуле был вопрос: «Какой главный ответ на все?». Ответ был «42», и видимо, никто не понял, что это значит. Там 9 из 10 — bad.

Что тут можно видеть? Очевидно, до людей еще далеко. Ранжирующие модели работают лучше — хотя бы потому, что в пуле много более интересных ответов и такой моделью проще ответ сгенерировать. А модели sequence-to-sequence работают хуже, но не то чтобы сильно хуже. Зато, как вы помните, они могут генерировать ответ в любой ситуации, так что, возможно, моделями sequence-to-sequence надо пользоваться. Или нужно комбинировать sequence-to-sequence и ранжирующие модели в виде какого-то ансамбля.

В заключение повторю основные поинты своего доклада. В последние пару лет Neural Conversational Models — по-настоящему горячая область исследований в deep learning, одна из таких областей. Ей очень много занимаются, в том числе крупные компании: Facebook, Google. Там происходит много интересного. В принципе, какими-то ее плодами можно пользоваться уже сейчас, но не следует ожидать, что у вас сразу получится искусственный интеллект. Осталось очень-очень много проблем, которые предстоит решать. И если у вас есть значительный опыт работы с текстами на естественном языке, опыт работы с диалоговыми системами или с deep learning в этой области — скорее всего, мы найдем что вам предложить.

Если вам интересно, вы можете, например, мне написать. У меня все. Спасибо.

«Яндекс» выложил в открытый доступ альтернативу нейросетям

Интеграция
Инфраструктура


, Текст: Владимир Бахур


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

Гибкое использование числовых и нечисловых данных

«Яндекс» представил новый метод машинного обучения CatBoost и выложил в открытый доступ для всех желающих библиотеку CatBoost на GitHub по лицензии Apache License 2.0. Методика позволяет эффективно обучать модели на разнородных данных — таких как местонахождение пользователя, история операций и тип устройства.

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

«Яндекс много лет занимается машинным обучением, и CatBoost создавали лучшие специалисты в этой области. Выкладывая библиотеку CatBoost в открытый доступ, мы хотим внести свой вклад в развитие машинного обучения, — сказал Михаил Биленко, руководитель управления машинного интеллекта и исследований «Яндекса». — Надо сказать, что CatBoost — первый российский метод машинного обучения, который стал доступен в Open Source. Надеемся, что сообщество специалистов оценит его по достоинству и поможет сделать ещё лучше».

Как пояснили CNews в «Яндексе», методика CatBoost является наследником метода машинного обучения «Матрикcнет», который применяется почти во всех сервисах «Яндекса». По аналогии с «Матрикснет», CatBoost задействует механизм градиентного бустинга, который хорошо подходит для работы с разнородными данными.

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

Логотип проекта CatBoost

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

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

CatBoost можно запустить прямо из командной строки или воспользоваться удобным для пользователя API для Python или R с инструментами для анализа формул и визуализации обучения.

Как пояснили CNews в пресс-службе «Яндекса», CatBoost — результат долгой работы лучших специалистов компании, который вобрал в себя многолетний опыт компании в разработке ведущих решений в машинном обучении, таких как «Матрикснет». Выкладывая технологию в открытый доступ, «Яндекс» намерен обеспечить серьезный вклад в развитие машинного обучения и рассчитывает, что сообщество специалистов оценит алгоритм по достоинству и поможет сделать его еще лучше.

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

Сравнение алгоритмов машинного обучения (GitHub)

Разработчики также планируют развивать технологию внутри компании: сейчас над ней работает отдельная команда, которые занимается улучшением и внедрением в большее количество сервисов. С течением времени библиотека применений CatBoost будет расти. Поскольку технология выложена в открытый доступ, весь прогресс будет сразу же доступен всем пользователям. Учитывая количество и качество сервисов «Яндекса» и нетривиальные задачи, которые в них решаются, в компании уверены, что технология останется лидирующей в своем классе еще долгое время.

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

Наиболее эффективный с практической точки зрения способ — это подсчет «счетчиков», его активно используют соревнующиеся на Kaggle, и этот способ используется в победных решениях. В существующих открытых решениях такой способ не используется, а используются более простые методы, такие как one-hot-encoding, они работают обычно хуже. Например, такую предобработку можно использовать в алгоритме lightgbm. 

В CatBoost используется более интеллектуальная работа с категориальными факторами, где статистики по ним подсчитываются не заранее, а во время обучения, причем выбираются самые полезные статистики по данным и их комбинациям. One-hot encoding в CatBoost, конечно, тоже поддержан; для характеристик, у которых мало значений иногда такой способ дает плюс в качестве, пояснили в «Яндексе».

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

Практические приложения

CatBoost уже протестировали на сервисах «Яндекса». В рамках эксперимента он применялся для улучшения результатов поиска, ранжирования ленты рекомендаций «Яндекс.Дзен» и для расчета прогноза погоды в технологии «Метеум». Во всех случаях технология показала себя лучше «Матрикснета». 

В дальнейшем CatBoost будет работать и на других сервисах, отмечают в «Яндексе». Его использует также команда Yandex Data Factory — в своих решениях для промышленности, в частности для оптимизации расхода сырья и предсказания дефектов. 

CatBoost уже имеет опыт международного использования: этот метод машинного обучения был внедрен Европейским центром ядерных исследований (ЦЕРН) для объединения данных, полученных с разных частей детектора LHCb.

Данные, собранные в ходе эксперимента, обрабатываются для индивидуальных столкновений с помощью CatBoost со скоростью 40 миллионов в секунду. 

Доступность CatBoost

Для работы с CatBoost достаточно установить его на свой компьютер. Библиотека поддерживает операционные системы Linux, Windows и macOS и доступна на языках программирования Python и R. 

«Яндекс» разработал также программу визуализации CatBoost Viewer, которая позволяет следить за процессом обучения на графиках. Скачать CatBoost и CatBoost Viewer можно на GitHub. 

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *