Personnalisation des directives de produit Big Data avec Vowpal Wabbit

Salut Je m'appelle Nikita Uchetelev. Je représente Lamoda Research & Development. Nous sommes plus de 20 personnes, et nous travaillons sur diverses recommandations sur le site et dans les applications, nous développons une recherche, nous déterminons le tri des marchandises dans les catalogues, nous offrons la possibilité de tester AB de diverses fonctionnalités, et nous soutenons également plusieurs développements internes comme un système pour prévoir l'élasticité de la demande et optimiser la logistique de livraison.


image


L'une des principales directions de développement de l'ensemble de l'entreprise pour les années à venir est la personnalisation de nos produits et services. De telles initiatives sont testées et mises en œuvre partout - de la compilation de sélections de produits personnels au choix d'un représentant des ventes spécifique qui vous livrera nos produits. Dans le cadre du processus de personnalisation des produits de R&D, j'agis en tant que chef d'équipe et dans cet article, je veux parler de la plate-forme que moi et mon équipe avons conçue et développée au cours de la dernière année, ainsi que des premiers produits de R&D personnalisés qui sont actuellement soumis à des tests AB.


Idéologie des recommandations de produits


L'attribut de toute boutique en ligne familière à tout le monde est la page produit. Il donne généralement une description détaillée, plusieurs grandes photos, des avis clients, le bouton «Ajouter au panier» et d'autres éléments de navigation familiers. Au bas de ces pages se trouve une ou plusieurs étagères avec d'autres produits appelés «Produits connexes», «Acheter avec ce produit» ou autre chose. Chaque étagère a son propre but.


Par exemple, une étagère avec des produits similaires est conçue pour donner à l'utilisateur une variété supplémentaire de produits dans le contexte actuel de son choix. Cela peut être utile s'il n'y a pas de taille d'utilisateur dans le stock, ou s'il est au stade de la sélection et veut le même produit, mais «avec des boutons nacrés». Dans le même temps, l'étagère éloigne l'acheteur de la page du produit, sur laquelle il ne peut plus revenir, et par conséquent ne pas l'acheter.


Il existe une deuxième étagère sur le site Web et dans les applications Lamoda, que nous appelons l' étagère des recommandations croisées . Il est situé immédiatement sous l'étagère avec des produits similaires, et nous essayons de placer sur celui-ci des produits différents qui se trouvent le plus souvent dans les paniers d'achat avec la référence actuelle (Stock Keeping Unit ou, plus simplement, article). Ainsi, par exemple, les pantalons et les chaussures sont recommandés pour les vestes, les foulards et les chapeaux pour les chandails. Il existe un groupe de produits bon marché qui sont achetés le plus souvent. En règle générale, ce sont des chaussettes et des sous-vêtements, donc ils peuvent souvent être vus sur cette étagère.


Cette technique de vente est similaire à la vente incitative . Nous essayons de vendre de gros produits complémentaires, à condition que l'utilisateur aime le produit actuel. Dans le même temps, c'est l'un des rares endroits où les clients peuvent se familiariser avec notre gamme. Par exemple, pour voir une marque ou une sous-catégorie, dont ils ne connaissaient pas la présence auparavant. Nous l'appelons inspiration et découverte - lorsque nous incitons les clients à faire de nouveaux achats et à nous dire quelle est notre gamme, nous affichons des prix et des remises.
image


Historiquement, le remplissage de ces étagères est calculé hors ligne (avec une marge, dans le cas où certains produits sont en rupture de stock avant le prochain calcul) ainsi que le tri par une métrique de similitude ou une conversion conditionnelle. Ainsi, tous les utilisateurs y voient approximativement la même chose pendant la journée. Nous avons décidé de commencer des expériences de personnalisation précisément à partir de ces étagères, car sur les pages produits, nous avons suffisamment de trafic pour mener des expériences de qualité. D'un point de vue technique, cela s'est avéré être l'un des endroits les plus pratiques pour la mise en œuvre dans notre infrastructure (marqué en rouge sur le schéma).
image


L'idée est la suivante : nous formons un modèle qui peut attribuer aux paires «utilisateur + produit» la probabilité de conversion ou simplement un clic, puis les afficher sur l'étagère de gauche à droite dans l'ordre décroissant de cette probabilité. Étant donné que sur le premier écran du carrousel, seules 4 à 6 références sont affichées, en fonction de la résolution de l'écran, et au total, nous pouvons les calculer, par exemple jusqu'à des centaines, une «profondeur» de personnalisation tout à fait acceptable est atteinte.


Nous résolvons le problème depuis la fin


Passons à la partie technique. Nous avons des limitations sur le temps de réponse de l'API. Par exemple, dans les applications, le futur service devra être à temps pour être responsable de 100 ms. Pendant ce temps, vous devez accéder à différentes bases de données pour les données utilisateur et produit, organiser une centaine d'exemples sous charge jusqu'à 100 QPS au pic. Cela nous amène à la nécessité d'utiliser des cadres d'apprentissage machine inférieurs à la milliseconde. L'un des plus célèbres est Vowpal Wabbit.


Un domaine d'application typique pour ce cadre est l'adtech, à savoir la prédiction du CTR d'une publicité lors de l'optimisation d'une offre pour une enchère RTB. D'un point de vue mathématique, nous pouvons poser un problème similaire. Supposons que nous voulons prédire la probabilité d'un clic en entraînant un modèle sur les affichages de produits. La charge sur le modèle jusqu'à 10k QPS est comparable aux indicateurs publicitaires et justifie, en général, la nécessité de ne se limiter qu'aux algorithmes linéaires au stade du prototypage et du MVP.


Voyons maintenant quelles données utilisateur peuvent contenir le signal dont nous avons besoin et distinguons bien les utilisateurs. Étant donné que nous parlons de recommandations de produits et de la page de produit que l'utilisateur visite, il est très probable qu'il soit au stade de la sélection. Il a en tête une certaine image de «chaussures parfaites» avec laquelle il compare tous les biens qui attirent son attention. Laissez-le d'abord aller au catalogue des produits de la catégorie souhaitée et commencez la recherche en cliquant sur tout ce qui ressemble plus ou moins à sa présentation. Ainsi, l'utilisateur réserve une «trace numérique» des produits visualisés. Sur la base de l'unité sur ce parcours, nous ferons une personnalisation.


Représentations vectorielles d'objets


Tous les produits diffèrent entre eux avec des valeurs tabulaires de certains attributs: couleur, matériaux, tissus, type d'impression, longueur de manche, présence d'une capuche, hauteur de talon, etc. En conséquence, il est possible de coder toute trace numérique avec des fractions d'occurrence de chacune des valeurs de ces attributs. Supposons que nous ayons des produits en trois couleurs et trois marques que vous pouvez voir et mettre dans le panier. Ensuite, en prenant l'historique des actions d'un utilisateur, il peut faire correspondre un vecteur de la forme suivante:
image


Dans ce cas, l'utilisateur a regardé 10 produits: 5 or, 2 noirs et 3 rouges. Et il a ajouté 2 rouges et 2 noirs au panier, il n'a pas ajouté d'or. De même avec les marques A, B et C, ainsi qu'avec toutes les valeurs d'attribut. En outre, un tel vecteur peut être concaténé avec un vecteur codé à chaud de valeurs d'attribut pour un produit particulier.


Ainsi, nous pouvons vectoriser un événement spécifique. Un utilisateur qui, dans le cadre de la session en cours, a examiné un certain nombre de produits avec une distribution de couleurs donnée, se prépare à voir un nouveau produit, par exemple le rouge. À l'aide de données historiques sur les impressions et les clics, vous pouvez créer un modèle qui prédirait la probabilité d'un clic sur un produit rouge, à condition qu'il ait une distribution de couleurs existante pour les produits précédemment consultés.


Si vous regardez l'espace dans lequel nous avons appris à afficher des cliques historiques, vous pouvez voir qu'une partie est occupée par un sous-espace binaire et l'autre est matérielle, et elles ne sont pas connectées les unes aux autres. Notre modèle linéaire dans ce cas est une combinaison linéaire (somme pondérée) des coordonnées des points dans cet espace. Si elle apprend de tels exemples, elle apprendra simplement les probabilités a priori. Par exemple, le poids devant la coordonnée correspondant à la couleur rouge des marchandises sera une valeur directement proportionnelle au CTR des marchandises rouges. Ainsi, les coordonnées spécifiques des utilisateurs seront pondérées par les caractéristiques de fréquence des clics des différents utilisateurs pour tous les produits du catalogue. Mais ce n'est pas tout à fait ce que nous aimerions.


Les caractéristiques polynomiales viennent à la rescousse - le résultat de la multiplication de toutes les quantités binaires avec toutes les vraies. Le framework Vowpal Wabbit dispose d'un outil puissant pour générer des fonctionnalités de puissance à partir d'espaces de noms. Essayons de composer une chaîne au format vw pour notre exemple, en répartissant les fonctionnalités des utilisateurs et des produits dans différents espaces de noms.


|user_color :0.5 :0.2 :0.3 |product_color  

Maintenant, si pendant l'entraînement nous ajoutons le commutateur -q pu , de telles caractéristiques quadratiques non nulles apparaîtront:


 user_color^ * product_color^ = 0.5 user_color^ * product_color^ = 0.2 user_color^ * product_color^ = 0.3 

Ainsi, le modèle recherche un signal non seulement sur la façon dont les utilisateurs cliquent avec une forte proportion de produits rouges consultés, mais aussi sur la façon dont ils cliquent sur les produits rouges. Le poids d'une telle caractéristique dans le modèle entraîné doit être positif et assez important.


Cette approche de l'ingénierie des fonctionnalités augmente considérablement la dimension de l'espace dans lequel la formation a lieu. Dans une situation où nous n'avons que 4 couleurs, la dimension de cet espace est de 8 (4 couleurs pour le produit et 4 pour l'utilisateur). Avec l'ajout de 16 attributs quadratiques, il passe à 24. En production, en plus des couleurs, nous utilisons 13 autres attributs des produits, y compris, par exemple, la marque. Par conséquent, la dimension totale de l'espace dans lequel nos modèles fonctionnent peut aller jusqu'à 3 millions d'entités. Dans le même temps, nous voulons maintenir le rapport du nombre d'exemples de formation à la dimension de l'espace au niveau de 1: 100. Pour ce faire, nous devons générer un total d'environ 300 millions d'observations.


Architecture de la plateforme de personnalisation


Nous stockons le flux de clics de nos utilisateurs dans Hadoop (Spark Streaming d'Apache Kafka vers une table Hive). Nous obtenons généralement environ 30 gigaoctets de données compressées par jour - c'est plus d'une centaine de types d'actions différents que les utilisateurs peuvent effectuer sur le site et dans les applications, y compris l'affichage de marchandises dans divers emplacements.


Aussi pour les étagères de recommandations, il y a des informations sur les produits qui ont été montrés et où le clic a été fait. Notre tâche pour chacun de ces clics dans le passé est de calculer l'état de l'utilisateur en termes de rapport des fractions des valeurs des attributs des produits visualisés au moment précédant ce clic. Ensuite, la concaténation de la paire de vecteurs «utilisateur» + «produit qui a été cliqué» donnera un exemple d'entraînement positif, et des paires similaires avec des produits montrés à côté dans l'étagère mais sans clics seront des exemples négatifs. Il est important que les produits soient présentés à proximité. Ensuite, nous pouvons être sûrs que l'utilisateur les a vus, mais n'a pas cliqué. En prime, avec une telle mécanique, nous pouvons contrôler le rapport des classes dans le problème.


Notre solution est l'agrégation quotidienne des données utilisateur à l'aide de Spark et le chargement incrémentiel de ces données dans HBase. Considérez la structure d'un tel agrégat.


Ainsi, l'objet principal de cette tâche est l'utilisateur. Des sessions lui sont associées, qui consistent en une séquence d'actions, chacune ayant certaines caractéristiques selon le type d'action. Par exemple, s'il s'agit d'une page de produit, le numéro d'article et la durée d'affichage du produit appartiennent aux attributs dont nous avons besoin. En guise de réserve pour l'avenir, nous écrivons immédiatement au journal la disponibilité des marchandises en stock et deux prix: celui de base et en tenant compte des stocks et des coupons personnels. Nous n'avons pas besoin d'impressions séparément, donc à la volée au moment de l'agrégation, elles sont attribuées aux clics et génèrent un nouveau type d'événement dans lequel, en plus du champ avec le numéro d'article du produit où le clic a été effectué, il existe également un tableau de plusieurs articles qui l'entourent au moment de l'affichage.


HBase est une base de données de colonnes versionnée avec une interface native pour se connecter à Spark pour le traitement par lots et avec la possibilité d'accéder aux données par clé. Une autre caractéristique de celui-ci est que HBase n'a pas le concept d'un circuit. Il ne peut stocker que des octets, ou plutôt des décalages, à l'intérieur de HFiles spéciaux qui sont adaptés à la structure de bloc HDFS.


Certains peuvent trouver controversé de choisir un référentiel, mais j'ai eu une bonne expérience de travail avec HBase dans des projets similaires. De plus, dans Lamoda, cette base de données est déjà activement utilisée, il ne nous coûte donc rien d'utiliser un système déjà déployé pour MVP. Nous n'utilisons pas de fonctionnalité de versioning pour le moment, mais l'accès aux clés semblait utile pour la possibilité de formation de modèle multithread dans le futur et l'organisation de l'architecture lambda pour le chargement de données et d'autres cas en temps réel.


Puisqu'il n'y a pas de schéma dans HBase, nous avons besoin de notre propre conteneur de données. Vous pouvez utiliser lambda x: json.dumps (x) .encode () , mais je voulais quelque chose de plus rapide. Une solution tout à fait standard consiste à utiliser des conteneurs protobuf. Étant donné que le développement de l'ensemble du projet est effectué en python, il est plus habituel pour moi d'utiliser la bibliothèque pyrobuf personnalisée d'AppNexus au lieu de celle officielle de Google. Par des repères, la performance de la fonctionnalité de base des protobuffs est plusieurs fois supérieure à l'original. Le schéma approximatif de notre protobuff est le suivant:


 enum Location { ru = 1; by = 2; ua = 3; kz = 4; special = 5; } enum Platform { desktop = 1; mobile = 2; a_phone = 3; a_tablet = 4; iphone = 5; ipad = 6; } message Action { enum ActionType { pageview = 1; quickview = 2; rec_click = 3; catalog_click = 4; fav_add = 5; cart_add = 6; order_submit = 7; } required uint64 ts = 1; required ActionType action_type = 2; optional string sku = 3; required bool is_office = 4; repeated string skus = 5; optional uint32 delta = 6; optional string sku_source = 7; optional bool stock = 8; optional uint32 base_price = 9; optional uint32 price = 10; optional string type = 11; } message Session { required string session_id = 1; repeated Action actions = 2; required uint64 session_start = 3; required uint64 session_end = 4; optional uint32 actions_count = 5; } message LID { required string uid = 1; repeated Session sessions = 2; required Location location = 3; required Platform platform = 4; optional uint32 sessions_count = 5; } 

Bref, il y a un objet «Utilisateur» (LID, Lamoda ID). À l'intérieur, il y a un tableau d'objets «Session», chacun étant un tableau d'objets «Action». Nous avons divisé les actions par type et les avons stockées dans différentes familles de colonnes, ce qui nous permet d'optimiser un peu la lecture lorsque nous n'avons besoin que d'événements de certains types (vues de produits, clics attribués sur différents types de recommandations, etc.).


Test


Pendant trois semaines, nous avons effectué un test AB sur le site de bureau lamoda.ru dans la conception suivante:


  • Contrôle: les recommandations de l'API se réfèrent au service de personnalisation, attendent le résultat, mais donnent la marchandise dans la commande d'origine, la même pour tout le monde.
  • Test: les produits sont affichés de gauche à droite dans l'ordre décroissant des prévisions de probabilité de clic.

La division en deux options est basée sur le LID de l'utilisateur - essentiellement par son cookie. Notre plateforme expérimentale garantit que les observations collectées dans deux versions sont indépendantes et uniformément réparties, et les changements métriques sont évalués avec un niveau de signification de 5% (valeur de p 0,05). En conséquence, nous avons reçu + 10% CTR de l'ensemble du plateau et une variation positive significative du chiffre d'affaires. La semaine dernière, nous avons déployé cette fonctionnalité à tous les utilisateurs du site.


Pour vérifier la personnalisation par vous-même, il suffit de regarder plusieurs produits différents puis de comparer le tri des recommandations sur l'une des étagères «Ils achètent ce produit» dans deux navigateurs différents ou d'utiliser le mode «Incognito». Bien sûr, si vous n'avez jamais visité notre site auparavant, il y a encore peu de données vous concernant sur la plateforme. Essayez de choisir une veste d'hiver et comparez à nouveau l'ordre des marchandises après un certain temps.


Du service à la plateforme


Nous avons donc une plate-forme complète - un ensemble d'outils logiciels qui regroupent les données et les stockent, ainsi qu'un cadre de vectorisation des objets métier à un moment arbitraire dans le passé, qui vous permet de créer des modèles de notation pour évaluer la probabilité de diverses actions. L'interférence du modèle est fournie par un service Web qui peut collecter des vecteurs pertinents à partir de diverses sources de données et les exécuter à travers le modèle. Il accepte le LID (identifiant utilisateur), la liste des SKU qui doivent être scannés et diverses informations supplémentaires, renvoyant la même liste de produits aux prévisions riches en clics. Voici un schéma de l'architecture conceptuelle de notre plateforme:
image


L'élément ML Core est un ensemble de machines virtuelles sur lesquelles les clients Hadoop et les travailleurs Airflow sont installés. Nous définissons la configuration, avec quels paramètres pour entraîner le modèle, où obtenir les données historiques, etc. En conséquence, le modèle est formé et publié en artificiel, et les informations sur le processus d'apprentissage et les métriques de qualité qui nous intéressent sont stockées dans le méta-référentiel.


Déjà en train de tester ou de préparer des tests du système de personnalisation des recommandations dans les listes de diffusion, sur les pages principales et sur l'étagère avec des recommandations pour des produits similaires, des segments similaires pour cibler la publicité interne et externe et bien plus encore.




C'était un article introductif. Dans d'autres publications, je peux me concentrer sur les aspects techniques de l'architecture et parler de son développement, ou, à l'inverse, élargir le composant produit plus largement et dire comment nous utilisons et évaluons le ML dans les tâches du produit. Écrivez dans les commentaires vos souhaits à ce sujet.

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


All Articles