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

в 7:43, , рубрики: BERT, natural language processing, Блог компании Яндекс, заголовки новостей, искусственный интеллект, команда яндекс.новостей, машинное обучение, нейронные сети, нейросети, поисковые технологии

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

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

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

Задача

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

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

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

Инструменты

У Яндекса есть технология Спеллер для поиска и исправления ошибок. Благодаря библиотеке машинного обучения 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 подсвечивает его, если слова рассогласованы — то оба (и, возможно, зависимые от них).

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

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

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

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

Автор: Тимур Гаскаров

Источник



https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js