O blog de filmes on-line da ivi possui vários artigos sobre a arquitetura do sistema de recomendação Hydra. No entanto, as recomendações não são apenas uma API externa, mas também algoritmos que vivem "ocultos" e implementam lógica de negócios bastante complexa.
Neste artigo, falarei sobre o problema do "início a frio" do conteúdo. Se você estiver interessado em aprender como recomendamos o conteúdo que foi adicionado recentemente ao catálogo e não conseguiu obter feedback dos usuários, bem-vindo ao gato.
O artigo conterá uma amostra reproduzível de código Python usando Keras.
Content Cold Start: Declaração do Problema
Como as recomendações funcionam? Aproximadamente da seguinte forma:
Usamos o seguinte pipeline para recomendações:
- carregar estatísticas de visualização de conteúdo na forma de matriz de conteúdo do usuário
- aplique a caixa mágica de aprendizado de máquina
- na saída da caixa para cada unidade dos recursos do catálogo
- usamos recursos de conteúdo para recomendações
Todas as etapas do pipeline de treinamento do modelo cold start podem ser encontradas neste repositório
github.com/ivi-ru/hydraObtemos recursos de conteúdo usando a biblioteca implícita da seguinte maneira
train_model.pyimport implicit import numpy as np from scipy.sparse import load_npz
Como recomendar o conteúdo lançado recentemente no serviço? Esse conteúdo não terá visualizações (ou haverá muito poucas visualizações) - isso significa que não haverá recursos para esse conteúdo na exaustão da caixa mágica do aprendizado de máquina e não aparecerá nas recomendações do usuário. Os recursos que obtemos com base nas interações de conteúdo do usuário, a propósito, são chamados de colaborativos.
Assim, chegamos ao problema de um começo a frio: como podemos recomendar conteúdo que não tem feedback do usuário? Você pode, por exemplo, misturar novo conteúdo em uma entrega aleatória e aguardar até que as visualizações "orgânicas" sejam reunidas.
Outra opção é criar um modelo que possa prever recursos de conteúdo "frio".
Decidimos seguir o segundo caminho e foi aí que viemos
Cold Start 1.0
Para resolver o problema de uma partida a frio, somos ajudados por recursos de conteúdo que são conhecidos antecipadamente sobre novos conteúdos, por exemplo
- Pessoas: diretor, roteirista, elenco
- gênero de conteúdo: ação, comédia etc.
- categoria: longa metragem, desenho animado, documentário
- tags do editor
Tags editoriais são uma breve descrição do conteúdo na forma de um conjunto finito (geralmente várias centenas) de características. Abaixo está um conjunto de tags de conteúdo do Beaver Zombie
Em uma primeira aproximação, resolvemos o problema de partida a frio da seguinte maneira:
- para cada conteúdo "frio", limpe o mais semelhante possível a ele por tags
- obtenha recursos colaborativos de conteúdo semelhante
- recursos colaborativos de conteúdo frio é a média dos recursos de seus vizinhos "quentes"
Em python, parece algo como isto 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)
De
alguma forma , esse método
funcionou , mas tinha duas desvantagens:
- extensibilidade fraca: é difícil adicionar, por exemplo, semelhança de pôsteres ao modelo
- ninguém garante a semelhança dos recursos do ALS para conteúdo semelhante em tags e, sem isso, o uso da média parece estranho
Percebemos que você não pode mais viver assim e criamos um modelo mais transparente e expansível.
Refatorando um modelo de partida a frio
Em vez de calcular os recursos de conteúdo do ALS usando heurísticas (como média), podemos treinar uma rede neural que preverá recursos de conteúdo colaborativo - por exemplo, por tags do editor. Um modelo semelhante já
apareceu no Habr aqui , e antes do Yandex, o
serviço de música do
Spotify falou sobre um modelo semelhante
O código do protótipo do modelo está disponível
no repositório ivi , a rede neural para uma partida a frio é a seguinte:
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
Que dificuldades você encontrou ao implementar esse experimento?
- Acabou sendo muito difícil treinar a rede: os recursos são codificados de uma só vez e a rede é mal treinada devido à grande dimensão da camada de entrada. Eu tive que realizar uma seleção cuidadosa de recursos, no final, usamos apenas categorias, gêneros e, nas tags do editor, selecionamos os mais "importantes" usando tf-idf
- o problema com a instalação do Keras usando o gerenciador de pacotes pipenv: python, o ambiente não estava indo, eu tive que terminar o pacote maxvolpy de terceiros que o Keras não fazia amizade
Resultados da Experiência
Como resultado, lavamos um pouco menos a nova funcionalidade, que por alguns sprints, o desenvolvedor passou cerca de 100 horas - e esta é a primeira experiência do uso de redes neurais na produção de nosso projeto. Este tempo foi distribuído da seguinte forma:
- 60 horas para leitura de artigos e desenvolvimento de protótipos
- 30 horas para integrar o protótipo na base de código do projeto
- 10 horas na implantação do novo modelo - arrastar Keras para o ambiente python não era tão simples devido às nossas dependências específicas (como maxvolpy)
Temos espaço para novas experiências - o uso de redes neurais permite que você aprenda não apenas nas tags do editor, mas também em outros recursos: imagens, scripts, comentários do usuário, filmagens etc.