Хабрахабр

Как запустить ML-прототип за один день. Доклад Яндекс.Такси

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

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

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

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

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

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

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

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

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

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

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

Мы примерно поняли критерий того, что мы эту проблему умеем решать. Мы сформулировали проблему. Первое, что приходит на ум: а давайте какие-нибудь такие проверенные и понятные точки посадки будем рекомендовать. Давайте теперь подумаем про то, как можно решить эту проблему. И мы знаем точно, что к выходам из этого торгового центра можно подъехать, и это некоторый ориентир, благодаря которому пользователь может найти водителя. Здесь на слайде изображен пример торгового центра «Европейский». Есть пример с «Азбукой вкуса» в каком-нибудь торговом центре. Это могут быть какие-нибудь организации. Это тоже некоторый ориентир для пользователя и водителя, про который мы знаем, что туда подъехать можно. По-моему, это «Ереван Плаза».

Условно, есть такие столбы в Шереметьево с номерами. Это могут быть ориентиры в аэропортах, о которых я говорил. Хорошее решение, но у него есть минус, что оно не очень масштабируемое. К ним удобно вызывать такси и садиться в машину. Именно здесь нам на помощь приходит то, что громко называют «искусственным интеллектом». У нас много стран, сотни городов, еще огромное число разных торговых центров, аэропортов, сложных развязок, незнакомых мест, для которых вручную эти точки сделать довольно сложно, и держать их в актуальном состоянии еще сложнее. Я предпочитаю называть это анализом данных или машинным обучением.

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

Это уже автоматически полученные точки для бизнес-центра «Аврора», в котором сейчас сидит наша команда Яндекс.Такси.

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

Во-первых, у нас есть GPS-данные наших пользователей и GPS-данные наших водителей. Какие данные у нас есть? Понятно, что у GPS большая погрешность, в районе 13-15 метров, но тем не менее, что-то есть. Когда они пользуются нашим приложением, мы знаем приблизительное местоположение пользователей. Можно предположить, что примерно в это время водитель дождался пользователя, пользователь сел в машину, и они поехали. Во-вторых, у нас есть информация, которая содержится в логах приложения, про то, когда водитель перешел из статуса «Ожидаю пользователя» в статус «Везу пользователя». И у нас есть дорожный граф. Примерно в этом месте была произведена посадка. д. Дорожный граф — это не только набор ребер, улиц, но и дополнительная метаинформация: шлагбаумы, информация про парковки, и т. На основе этих данных уже можно получить какие-то автоматические точки.

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

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

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

В основном вся подготовка данных у нас написана на Python, на Python stack: это стандартные NumPy, Pandas, Scikit-learn и т. Какие инструменты мы используем при подготовке данных? Данных у нас очень много. д. Очень много данных про GPS, про треки водителей, логи приложений, поэтому их нам нужно обрабатывать все-таки на кластере. У нас миллионы поездок в месяц. Для этого мы используем MapReduce нашей внутрияндексовской версии, который называется YT, и к нему есть библиотека, написанная на Python, которая позволяет какие-то маперы и редьюсеры запускать, и делать какие-то вычисления на большом кластере.

Это тоже внутрияндексовские разработки. Наконец, когда пайплайн готов, нам нужно его автоматизировать, чтобы была актуальность данных, и для этого мы используем такую вещь как Nirvana и Hitman. На самом деле, она умеет примерно любую программу запускать, быть отказоустойчивой, быть cross DC (00:14:53). Nirvana — это фреймворк по управлению вычислениями на кластере. и т. И в случае, если что-то падает, она умеет это перезапускать, создавать запуски по наступлению каких-нибудь событий. д.

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

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

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

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

Есть пользователи, у них есть приложение, а есть водители, у них тоже есть приложение, называется «Таксометр». Очень поверхностная схема выглядит так. Один из микросервисов — наш сервис, наша команда его делает, он называется ML as a Service, MLaaS. Эти приложения как-то общаются с бэкэндом, а бэкэнд представляет из себя набор микросервисов, которые между собой общаются — про это рассказывал Илья.

Это опенсорсная библиотека, которая представляет из себя, грубо говоря, фреймворк для написания веб-сервера, который умеет get- и post-запросы, все стандартно. Всё, что про него нужно знать, — MLaaS написан на С++, на базе так называемого Fastcgi Daemon. У нас используется допиленная версия. Она когда-то в Яндексе написана, выложена в open source. Он умеет работать с моделями: применять их, хранить у себя и иногда обновлять, ходить в это замечательное облако, где модели регулярно обновляются, сохраняются, и скачивать их. Что умеет этот сервис?

Разумеется, этот сервис не изолирован, умееть ходить в какие-то дополнительные источники данных, базы данных, какие-то другие микросервисы. Каждой функциональности, например, этим точкам посадки — внутри мы называем их pickup points, — или, например, подсказкам точек Б, про которые Илья говорил и всё время ломал в предыдущем докладе, каждой такой функциональностью, где есть какое-то машинное обучение, соответствует handler, который хранит в себе логику получения запроса, генерации факторов машинного обучения, и применения моделей, и генерации ответа.

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

Я вам уже рассказал, что у нас есть подготовка данных, обучение, разные исследования, эксперименты, и всё это написано на Python Stack, а есть некоторый продакшен, который написан на C++, просто потому что у нас большие требования по эффективности и производительности. Но что мы имеем к текущему моменту? Когда живешь в такой экосистеме, возникают две проблемы.

Например, data scientist'у, который работает у нас в команде, пришла идея. В первую очередь, это проблема экспериментов. Он попробовал проверить свою гипотезу в офлайне, встроился в наш Python-процесс, посчитал, и действительно получается. Если запустить какой-нибудь алгоритм кластеризации или классификации чуть с другими параметрами, то можно добиться лучшего качества. Для этого ему приходится, условно, пять версий своего алгоритма, в которые он верит, которые в офлайне дают хорошее качество: реализовывать на C++ и проводить AB-эксперимент. И теперь он хочет AB-эксперимент, то есть части пользователей показать новый алгоритм и измерить некоторые метрики уже в онлайне: падает ли действительно время подачи, ожидания, растёт ли использование. То есть процесс экспериментирования занимает большое время из-за того, что, условно, два разных языка, две разных технологии. И после этого AB-эксперимента, возможно, все пять пойдут в утиль, то есть качество от них в онлайне окажется хуже, чем было в офлайне, то есть хуже, чем в продакшене.

А еще есть новые. Это для существующих фич. Не тратить на это два месяца разработки — желательно получить что-то за три недели. Когда-то эти pickup points тоже были идеями, которые хотелось быстро проверить. Сперва на Python написать извлечение фич, просто потому что это удобно — move fast, что называется. Создать такой прототип довольно трудоемко. Ты поэкспериментировал в своем ноутбуке, а теперь хочешь проверить на пользователях. На Python можно собрать любой прототип, есть много библиотек для анализа данных. Мы пришли к тому, что нам нужен какой-то дополнительный сервис, чтобы такие прототипы собирать довольно быстро — условно, за неделю или даже за день, — а также проводить AB-эксперименты. И сделать прототип получалось довольно тяжело.

Что он из себя представляет? Мы создали такой сервис, назвали его PyMLaaS. Архитектура довольно простая, такая же, как у MLaaS, но есть возможность в неё быстро впилить какой-нибудь прототип из своих офлайн-экспериментов. На самом деле, это полный аналог MLaaS, про который я до этого говорил, но написанный на Python на базе Flask, nginx и Gunicorn. Помимо этого мы устроили такое проксирование на уровне nginx, чтобы, условно, у нас была возможность часть нагрузки из MLaaS переправлять в PyMLaaS и тем самым экспериментировать.

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

Потому что, условно, есть фичи, которые требуют большой нагрузки, 1000 RPS, большие требования по памяти. Он нам так понравился, что возникла идея — а почему бы его всё время не использовать? Но для каких-то фич, для каких-то продуктов или сервисов, в которых нет таких больших требований по нагрузке, производительности, RPS и так далее, мы этот сервис вполне успешно используем. Хочется иметь довольно гибкую параллельность.

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

Польза от таких точек и рекомендаций удобных мест посадки вполне ощутима. Возвращаясь к задаче про pickup points — гипотеза оказалась верной. Сейчас примерно 30% всех поездок осуществляются из точки, которую мы рекомендуем. Время подачи автомобиля упало, время ожидания также упало. Большое спасибо за внимание.

Показать больше

Похожие публикации

Добавить комментарий

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

Кнопка «Наверх»