Привет! Меня зовут Алексей Мельников, я продакт в KION (онлайн-кинотеатр от МТС Digital), занимаюсь фичами, связанными с искусственным интеллектом.
Весной мы писали о фиче пропуска титров. Судя по карме, статья хабровчанам понравилась и это мотивировало нас на написание серии материалов, посвященных другой фиче – автоплею фильмов. Ниже я расскажу, как и зачем мы реализовали эту фичу и что у нее под капотом.
Autoplay позволяет не бросать еще «теплого» зрителя во время просмотра и предлагать ему новый фильм сразу после окончания предыдущего. Система рекомендаций сама подбирает контент, наиболее похожий на тот, что смотрит зритель. Новый фильм запускается в автоматическом режиме при наступлении титров, если пользователь бездействует.
Когда начинаются титры – мы уводим их в pip в левый нижний угол экрана и на бэке показываем постер следующего похожего фильма. В правой нижней части экрана показываем кнопки Следующий фильм и Смотреть титры. И если пользователь бездействует n секунд (этот параметр настраивается) – включаем следующий похожий фильм. Как это выглядит – показываю ниже:
![Дизайн функции автоплей в онлайн кинотеатре Kion Дизайн функции автоплей в онлайн кинотеатре Kion](https://webcf.waybackmachine.org/web/20221106072848/https://habrastorage.org/getpro/habr/upload_files/a8d/9f1/2c3/a8d9f12c36fdfc4d1cd60e524055e6c2.png)
![Анимация фичи автоплей Анимация фичи автоплей](https://webcf.waybackmachine.org/web/20221106072848/https://habrastorage.org/getpro/habr/upload_files/562/7c1/4a7/5627c14a70cba954f5052e01a122879f.gif)
Почему мы внедрили эту фичу?
Предпосылок для создания Autoplay было две:
мы созрели с точки зрения бэка и научились работать с i2i – item to item, подробно об этом ниже;
мы боремся не только с конкурентами, но и за внимание зрителя, который в момент окончания фильма решает, чем ему заняться дальше. Поспать? Погулять? Или посмотреть еще один фильм? Autoplay как раз подталкивает зрителя к дальнейшему просмотру.
А что под капотом?
Об этом подробно рассказывают Глеб Волохов, ведущий ML-разработчик KION и Светлана Захарова, ведущий MLOps KION:
Для стабильной и надежной работы ML-решений в продакшене необходимы:
полное версионирование моделей;
возможность быстро откатиться до какой-то конкретной версии модели (например, предыдущей);
контроль и хранение истории онлайн и оффлайн – метрик качества;
полная повторяемость пайплайнов в любой момент времени;
удобство и простота разработки для датасаентистов, а также их независимость от бэкенд разработчиков.
Также очень желательно максимально исключить человеческий фактор на всех этапах деплоя.
При построении системы, отвечающей всем нашим требованиям, в качестве центрального компонента был выбран MLFlow. Используя все возможности MLFlow, мы построили полностью автоматический пайплайн, в котором присутствуют следующие компоненты:
MLFlow – центральный компонент, отвечающий за отслеживание экспериментов, метрик, регистрацию моделей, а также, после небольшой доработки, выступающий инициатором автоматической раскатки моделей;
Gitlab репозиторий c dvc (mldatasets) – этот репозиторий используется для хранения датасетов для обучения и их версионирования;
Vanga – микросервис для моделей, обеспечивающий унифицированное API для работы с моделями;
MLTrainer – микросервис, который запускает модели учиться, принимает решение о раскатке и раскатывает новую версию модели в продакшен;
Ailflow – распространенное решение для выстраивания etl-процессов, в нашем случае даги периодически собирают датасеты для обучения и складывают в соответствующий репозиторий, анализируют нужно ли какую-то из моделей поучить и в случае успеха инициируют запуск нашего MLTrainer;
Telegram-чат – используется для информирования.
![Схема взаимодейсвия компонентов Схема взаимодейсвия компонентов](https://webcf.waybackmachine.org/web/20221106072848/https://habrastorage.org/getpro/habr/upload_files/b83/fec/6cd/b83fec6cd2a0b16c4353bdec476e6fd4.jpeg)
Остановимся на каждом из компонентов подробнее:
MLFlow
В MLFlow используется бэкенд – postgres 14.0, хранилище для артефактов – S3. Для того, чтобы обеспечить дальнейшую автоматическую раскатку зарегистрированных в MLFlow моделей, на таблицу в БД postgres, отвечающую за регистрацию моделей, были повешены сигналы, которые отлавливаются специальным сервисом. В зависимости от того, в какое состояние с точки зрения MLFlow переходит зарегистрированная модель, – вешаются хуки.
Например, при переходе из состояния 'None' в состояние 'Staging' происходит валидация входных параметров и дальнейшая раскатка микросервиса, отвечающего за API к этой модели. При переходе в состояние 'Archived' модель прекращает свою работу в продакшен контуре. Все действия дублируются ботом в наш служебный чат. В том числе, если в процессе раскатки не прошла какая-то валидация, информация об ошибке будет отправлена в чатик, а модель будет автоматически возвращена в состояние 'None'.
Каждая модель оформляется в виде MLFlow-проекта и имеет два обязательных эндпоинта: train и test. Train – эндпоинт, необходимый для автоматического переобучения модели на новых данных. В качестве обязательных входных аргументов эндпоинт принимает версию датасета из репозитория mldatasets.
Это необходимо для динамического влияния на версию данных, на которых мы хотим обучить нашу модель. Test – также принимает версию датасета и считает оффлайн-метрики, которые отслеживаются в MLFlow. Основываясь на метриках, наш автоматический тренер принимает решение, нужно ли новую версию модели выкатывать в продакшен.
Каждая модель представляет собой набор кода и вспомогательной информации, необходимой датасаентистам. Все для работы хранится в отдельном репозитории, каждая модель в своей ветке. Такой подход к организации работы дал нам следующее:
в любой момент мы можем откатиться на предыдущую версию;
в процессе трекинга наших экспериментов в MLFlow регистрируется и версия коммита, что позволяет на всех этапах отслеживать, что версия модели и версия кода консистентны;
в разных компонентах нашей архитектуры код, необходимый для работы с моделью, подключается как сабмодуль, а версия переключается по информации из MLFlow.
Так мы сделали из MLFlow-сервера единое место для хранения информации о моделях, которое не только любому клиенту может эту информацию предоставить, но и выступает инициатором выкатки и валидации входных данных: полноты и корректности для дальнейшего деплоя.
Mldatasets
Mldatasets – это gitlab-репозиторий с dvc, для которого настроен в s3 bucket с expire – 30 дней. Для каждого проекта своя ветка, а датасеты собираются в него по расписанию дагами из airflow. Даги собирают данные из различных источников (clickhouse, mongo и так далее), предобрабатывают, агрегируют и помещают в нужную ветку. Так появляется единая точка входа для получения датасетов, они единообразны и уже предобработаны. Также получаем жесткую версионированность, что для нас критически важно.
Использование такого репозитория позволяет нам точно знать, на каких датасетах училась какая модель, и, в случае необходимости, где угодно повторить обучение или проанализировать состояние датасетов.
Vanga
Это микросервис, обеспечивающий унифицированное API для взаимодействия с моделями. Микросервис написан на fastapi, обертка на модель подключается как сабмодуль, необходимая версия для каждой конкретной модели берется из MLFlow вместе с некоторой необходимой для раскатки мета-информацией. Например, можно задать вот что: назначение модели (как i2i), персонализацию витрины, включен или выключен режим автотренировки моделей.
В рамках CI запускаются тесты и прочие проверки. Инициатором раскатки выступает хук, повешенный на MLFlow при переводе зарегистрированной в MLFlow модели из состояния 'None' в состояние 'Staging'. В случае неудачного прохождения тестов модель также автоматически переводится в состояние 'None', а сообщение с текстом об ошибке направляется в соответствующий чат.
Airflow
Бэкенд, который отдает для нашего кинотеатра рекомендации i2i забирает их из redis. Наполняется redis дагом, логика работы которого следующая:
узнать, какие модели для i2i находятся в состоянии 'Production' с соответствующей мета-информацией (куда делать запрос);
получить рекомендации от соответствующего экземпляра микросервиса Vanga;
сохранить в Redis.
Также именно даг по расписанию проверяет, есть ли претенденты на обучение, смотрит, кто из моделей еще не учился на актуальной версии датасетов и запускает mltrainer.
MLTrainer
Компонент, отвечающий за переобучение моделей, принятие решений о выкатке новой версии модели и перевод текущей версии в архив. Сервис развернут на собственных мощностях МТС Медиа, оборудованных видеокартами Nvidia Tesla V100.
MLTrainer запускает для модели эндпоинт train, затем test, собирает оффлайн метрики после текущего обучения и предыдущих N обучений активной модели, принимая решение нужно ли текущую версию модели перевести в 'Archived' и раскатить новую версию модели в продакшен. При проседании оффлайн метрик модель не катится в продакшен, а разработчик получает уведомление об этом с ссылкой на run в MLflow.
Вся необходимая документация для работы датасаентистов оформлена при помощи Vuepress, что позволяет быстро найти информацию для работы.
Основной стек: MLFlow, Gitlab CI/CD, Fastapi, TensorFlow, Postgres, S3, Vuepress
Каким был фидбэк от юзеров?
Занимательным. Например, мы обнаружили, что некоторые пользователи, смотрят нон-стопом фильмы на смартфонах. Как мы это выяснили? У нас после просмотра 3 фильмов подряд всплывает сообщение:
![Вопрос по окончании просмотра 3 фильмов подряд Вопрос по окончании просмотра 3 фильмов подряд](https://webcf.waybackmachine.org/web/20221106072848/https://habrastorage.org/getpro/habr/upload_files/704/50b/9f5/70450b9f5c0f14642b7f2a6bad8f57c5.png)
И пользователи нажимают смотреть далее. Кстати, этот скрин сделал один из наших разработчиков во время путешествия, когда сам смотрел фильмы подряд без перерыва.
С точки зрения цифр мы получили следующие результаты:
![Результаты АБ теста по автоплей фильмов, TVTU - Total View Time by User Результаты АБ теста по автоплей фильмов, TVTU - Total View Time by User](https://webcf.waybackmachine.org/web/20221106072848/https://habrastorage.org/getpro/habr/upload_files/eca/21f/122/eca21f12222448ff46968e6934949c8f.png)
После внедрения фичи мы увеличили один из наших ключевых показателей Total View Time Unique – количество минут смотрения в среднем на одного юзера. А еще мы увеличили среднюю длину сессии.
При этом количество зрителей, которые досматривают рекомендованный контент, находится в пределах 30-40%.
Что дальше?
В будущем мы планируем протестировать гипотезу о том, что пользователю нужен выбор: несколько вариантов контента, которые он может смотреть.
![Развитие фичи автоплей Развитие фичи автоплей](https://webcf.waybackmachine.org/web/20221106072848/https://habrastorage.org/getpro/habr/upload_files/0bb/30d/ea0/0bb30dea0bbd09671572f9ae74113bb4.png)
![Развитие фичи Развитие фичи](https://webcf.waybackmachine.org/web/20221106072848/https://habrastorage.org/getpro/habr/upload_files/a54/cce/51a/a54cce51ac8557ec3afacf5d1a6c3f98.png)
Идея такая – давать ленту с контентом в виде рекомендаций похожих фильмов в момент появления титров.
Кроме того мы планируем улучшать качество модели i2i и рекомендовать не только фильмы, но и сериалы.
Спасибо за внимание! Увидимся в KION!)