В этой статье я расскажу о проблеме «холодного старта» контента. Если вам интересно узнать, как мы рекомендуем контент, который недавно добавился в каталог и не успел набрать фидбэк от пользователей — добро пожаловать под кат.

Статья будет содержать воспроизводимый пример кода на языке Python с использованием Keras.
Холодный старт контента: постановка проблемы
Как работают рекомендации? Примерно следующим образом:

Мы используем для рекомендаций следующий пайплайн:
- загружаем статистику просмотров контента в виде матрицы user-content
- применяем волшебную коробку машинного обучения
- на выходе из коробки у каждой единицы каталога появляются фичи
- фичи контента используем для рекомендаций
Все этапы пайплайна обучения модели холодного старта можно найти в этом репозитории github.com/ivi-ru/hydra
Фичи контента мы получаем с помощью библиотеки implicit следующим образом
import implicit import numpy as np from scipy.sparse import load_npz # загружаем матриц user-item user_item_views_coo = load_npz('/srv/data/user_item_interactions.npz') als_params = { 'factors': 40, 'regularization': 0.1, 'num_threads': 3, 'iterations': 5} print('Начинаем обучение ALS-модели') als_model = implicit.als.AlternatingLeastSquares(**als_params) als_model.fit(user_item_views_coo.T) als_factors = als_model.item_factors print('ALS-модель обучена, факторы контента ', als_factors.shape) als_factors_filename = '/srv/data/fair_als_factors.npy' np.save(als_factors_filename, als_factors,allow_pickle=True) print('Сохранили факторы контента в', als_factors_filename)
Как рекомендовать контент, который вышел на сервисе совсем недавно? У такого контента будут отсутствовать просмотры (или просмотров будет очень мало) — это значит, что в выхлопе волшебной коробки машинного обучения не будет фичей по такому контенту и он не будет появляться в рекомендациях у пользователей. Фичи, которые мы получаем на основе взаимодействий пользователь-контент, кстати, называются коллаборативными.
Таким образом, мы приходим к проблеме холодного старта: как нам рекомендовать контент, по которому нет фидбэка от пользователей? Можно, к примеру, подмешивать новый контент в выдачу случайным образом и ждать, пока не наберутся «органические» просмотры.
Другой вариант — построить модель, которая умеет предсказывать фичи «холодного» контента.
Мы решили пойти по второму пути и вот куда пришли
Cold Start 1.0
Решить проблему холодного старта нам помогают контентные фичи, которые о новом контенте известны заранее, например
- персоны: режиссёр, сценарист, актёрский состав
- жанр контента: боевик, комедия и т.д.
- категория: художественный фильм, мультфильм, документалка
- редакторские тэги
Редакторские тэги — это краткое описание контента в виде конечного (обычно несколько сотен) набора характеристик. Ниже приведён набор тэгов контента «Бобры-зомби»

В первом приближении мы решали задачу холодного старта следующим образом:
- для каждого «холодного» контента натйти максимально похожий на него по тэгам
- взять коллаборативные фичи похожего контента
- коллаборативные фичи холодного контента — это среднее по фичам его «горячих» соседей
for row in new_items_neighbors: neighbors_als_indices = row.neighbors_ids[:self.cold_start_neighbors_count] neighbors_average_factors = item_factors[neighbors_als_indices].mean(axis=0) # сохраняем результат усреднения в матрицу фичей ALS item_factors[row.new_item_als_index] = neighbors_average_factors

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

Код прототипа модели доступен в репозитории ivi, нейросеть для холодного старта выглядит следующим образом:
def _get_model(self, dims: List[int]) -> Sequential: model = Sequential() model.add( Dense( units=dims[1], activation='linear', input_dim=dims[0], kernel_initializer=WeightInitializer.custom_normal, bias_initializer='zeros' ) ) model.compile( loss=lambda y_true, y_pred: K.sum(K.square(y_pred - y_true), axis=-1), optimizer=optimizers.Adam(lr=self.learning_rate, decay=self.decay) ) return model
С какими сложностями столкнулись при реализации этого эксперимента?
- обучать сеть оказалось довольно тяжело: фичи закодированы one-hot, и сеть плохо обучается из-за большой размерности входного слоя. Пришлось проводить тщательный отбор фичей, в итоге используем только категории, жанры, а из редакторских тэгов выбираем самые «важные» с помощью tf-idf
- беда с установкой Keras с помощью менеджера пакетов pipenv: python окружение не собиралось, пришлось допиливать сторонний пакет maxvolpy, с которым не подружился Keras
Результаты эксперимента
В итоге мы запилили новый функционал чуть меньше, чему за пару спринтов, разработчик затратил около 100чч — а ведь это первый опыт использования нейросетей в продакшне на нашем проекте. Это время распределилось следующим образом:
- 60 чч на чтение статей и разработку прототипа
- 30 чч на интеграцию прототипа в кодовую базу проекта
- 10 чч на деплой новой модели — затащить Keras в python окружение оказалось не так просто из-за наших специфических зависимостей (вроде maxvolpy)
Мы получили простор для дальнейших экспериментов — использование нейронных сетей позволяет обучаться не только на редакторских тэгах, но и на других фичах: картинках, сценариях, пользовательских комментариях, видеоряде и т.д.
ссылка на оригинал статьи https://habr.com/ru/company/ivi/blog/478694/
Добавить комментарий