Comme nous vous recommandons les derniers catalogues du cinéma en ligne ivi (+ code Python)

Le blog de films en ligne ivi contient de nombreux articles sur l'architecture du système de recommandation Hydra. Cependant, les recommandations ne sont pas seulement une API externe, mais aussi des algorithmes qui vivent «sous le capot» et mettent en œuvre une logique métier assez complexe.

Dans cet article, je parlerai du problème du "démarrage à froid" du contenu. Si vous souhaitez savoir comment nous recommandons le contenu qui a été récemment ajouté au catalogue et qui n'a pas réussi à obtenir des commentaires des utilisateurs, bienvenue sur cat.


L'article contiendra un exemple reproductible de code Python utilisant Keras.

Contenu Cold Start: problème


Comment fonctionnent les recommandations? À peu près comme suit:


Nous utilisons le pipeline suivant pour les recommandations:

  • charger des statistiques de vue de contenu sous la forme d'une matrice de contenu utilisateur
  • appliquer la boîte magique d'apprentissage automatique
  • à la sortie de la boîte pour chaque unité des fonctionnalités du catalogue apparaissent
  • nous utilisons des fonctionnalités de contenu pour des recommandations

Toutes les étapes du pipeline de formation du modèle de démarrage à froid peuvent être trouvées dans ce référentiel github.com/ivi-ru/hydra
Nous obtenons des fonctionnalités de contenu en utilisant la bibliothèque implicite comme suit

train_model.py
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) 


Comment recommander du contenu récemment sorti sur le service? Un tel contenu n'aura pas de vues (ou il y aura très peu de vues) - cela signifie qu'il n'y aura pas de fonctionnalités pour un tel contenu dans l'échappement de la boîte magique d'apprentissage automatique et il n'apparaîtra pas dans les recommandations des utilisateurs. Les fonctionnalités que nous obtenons en fonction des interactions utilisateur-contenu, en passant, sont appelées collaboratives.

Ainsi, nous arrivons au problème d'un démarrage à froid: comment pouvons-nous recommander un contenu qui n'a pas de commentaires des utilisateurs? Il est possible, par exemple, de mélanger du nouveau contenu dans une sortie aléatoire et d'attendre que les vues «organiques» soient rassemblées.

Une autre option consiste à construire un modèle capable de prédire les caractéristiques d'un contenu «froid».

Nous avons décidé d'aller dans la deuxième direction et c'est là que nous sommes venus

Cold Start 1.0


Pour résoudre le problème d'un démarrage à froid, nous sommes aidés par des fonctionnalités de contenu connues à l'avance sur les nouveaux contenus, par exemple

  • Personnes: réalisateur, scénariste, distribution
  • genre de contenu: action, comédie, etc.
  • catégorie: long métrage, dessin animé, documentaire
  • balises de l'éditeur

Les balises éditoriales sont une brève description du contenu sous la forme d'un ensemble fini (généralement plusieurs centaines) de caractéristiques. Vous trouverez ci-dessous un ensemble de balises de contenu Beaver Zombie


Dans une première approximation, nous avons résolu le problème de démarrage à froid comme suit:

  • pour chaque contenu "froid", essuyez-le le plus possible par des balises
  • prendre des fonctionnalités collaboratives de contenu similaire
  • les fonctionnalités collaboratives du contenu froid sont la moyenne des fonctionnalités de ses voisins "chauds"


En python, ça ressemble à ça
 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 



Cette méthode fonctionnait d'une manière ou d'une autre , mais elle avait deux inconvénients:

  • faible extensibilité: il est difficile d'ajouter, par exemple, la similitude des affiches au modèle
  • personne ne garantit la similitude des fonctionnalités ALS pour le contenu similaire dans les balises, et sans cela, l'utilisation de la moyenne semble étrange


Nous avons réalisé que vous ne pouvez plus vivre comme ça, et nous sommes arrivés avec un modèle plus transparent et extensible.

Refactorisation d'un modèle de démarrage à froid



Au lieu de calculer les fonctionnalités de contenu ALS à l'aide d'heuristiques (comme la moyenne), nous pouvons former un réseau de neurones qui prédira les fonctionnalités de contenu collaboratif - par exemple, par des balises d'éditeur. Un modèle similaire a déjà flashé sur Habr ici , et avant Yandex, le service de musique Spotify a parlé d'un modèle similaire


Le code prototype du modèle est disponible dans le référentiel ivi , le réseau neuronal pour un démarrage à froid est le suivant:

cold_start_model.py
 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 


Quelles difficultés avez-vous rencontrées lors de la mise en œuvre de cette expérience?

  • Il s'est avéré assez difficile de former le réseau: les fonctionnalités sont encodées à chaud, et le réseau est mal formé en raison de la grande dimension de la couche d'entrée. J'ai dû procéder à une sélection minutieuse des fonctionnalités, au final, nous utilisons uniquement des catégories, des genres et, à partir des balises de l'éditeur, nous sélectionnons les plus "importantes" à l'aide de tf-idf
  • le problème avec l'installation de Keras en utilisant le gestionnaire de paquets pipenv: python, l'environnement n'allait pas, j'ai dû terminer le paquet maxvolpy tiers avec lequel Keras ne s'était pas lié d' amitié

Résultats de l'expérience



En conséquence, nous avons un peu moins nettoyé la nouvelle fonctionnalité, ce qui a duré environ 100 heures au développeur, et c'est la première expérience d'utilisation de réseaux de neurones en production sur notre projet. Ce temps a été réparti comme suit:

  • 60 h pour la lecture d'articles et le développement de prototypes
  • 30 heures pour intégrer le prototype dans la base de code du projet
  • 10 heures sur le déploiement du nouveau modèle - faire glisser Keras dans un environnement python n'était pas si simple en raison de nos dépendances spécifiques (comme maxvolpy)

Nous avons de la place pour d'autres expériences - l'utilisation des réseaux de neurones vous permet d'apprendre non seulement sur les balises de l'éditeur, mais également sur d'autres fonctionnalités: images, scripts, commentaires des utilisateurs, séquences, etc.

Source: https://habr.com/ru/post/fr478694/


All Articles