O Dia da Comunidade de ML é dia 9 de novembro! Junte-nos para atualização de TensorFlow, JAX, e mais Saiba mais

Recomendando filmes: recuperação

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

Os sistemas de recomendação do mundo real costumam ser compostos de dois estágios:

  1. O estágio de recuperação é responsável por selecionar um conjunto inicial de centenas de candidatos de todos os candidatos possíveis. O principal objetivo desse modelo é eliminar com eficiência todos os candidatos nos quais o usuário não está interessado. Como o modelo de recuperação pode lidar com milhões de candidatos, ele deve ser computacionalmente eficiente.
  2. O estágio de classificação pega os resultados do modelo de recuperação e os ajusta para selecionar o melhor punhado possível de recomendações. Sua tarefa é restringir o conjunto de itens nos quais o usuário pode estar interessado em uma lista de prováveis ​​candidatos.

Neste tutorial, vamos nos concentrar no primeiro estágio, recuperação. Se você estiver interessado na fase de classificação, ter um olhar para o nosso ranking do tutorial.

Os modelos de recuperação costumam ser compostos por dois submodelos:

  1. Um modelo de consulta que computa a representação da consulta (normalmente um vetor de incorporação de dimensionalidade fixa) usando recursos de consulta.
  2. Um modelo candidato computando a representação candidata (um vetor de tamanho igual) usando os recursos candidatos

As saídas dos dois modelos são então multiplicadas juntas para fornecer uma pontuação de afinidade do candidato à consulta, com pontuações mais altas expressando uma melhor correspondência entre o candidato e a consulta.

Neste tutorial, vamos construir e treinar esse modelo de duas torres usando o conjunto de dados Movielens.

Estava indo para:

  1. Obtenha nossos dados e divida-os em um conjunto de treinamento e teste.
  2. Implemente um modelo de recuperação.
  3. Ajustar e avaliar.
  4. Exporte-o para um atendimento eficiente, construindo um índice aproximado de vizinhos mais próximos (ANN).

O conjunto de dados

Os Movielens conjunto de dados é um conjunto de dados clássico dos GroupLens Grupo de Pesquisa da Universidade de Minnesota. Ele contém um conjunto de classificações dadas a filmes por um conjunto de usuários e é um carro-chefe da pesquisa do sistema de recomendação.

Os dados podem ser tratados de duas maneiras:

  1. Pode ser interpretado como uma expressão de quais filmes os usuários assistiram (e avaliaram) e quais não. Esta é uma forma de feedback implícito, em que os relógios dos usuários nos dizem o que eles preferem ver e o que preferem não ver.
  2. Também pode ser visto como uma expressão do quanto os usuários gostaram dos filmes que assistiram. Esta é uma forma de feedback explícito: dado que um usuário assistiu a um filme, podemos dizer aproximadamente o quanto ele gostou olhando a classificação que deu.

Neste tutorial, estamos nos concentrando em um sistema de recuperação: um modelo que prevê um conjunto de filmes do catálogo que o usuário provavelmente assistirá. Freqüentemente, os dados implícitos são mais úteis aqui e, portanto, trataremos o Movielens como um sistema implícito. Isso significa que todo filme que um usuário assistiu é um exemplo positivo e todo filme que ele não viu é um exemplo negativo implícito.

Importações

Vamos primeiro tirar nossas importações do caminho.

pip install -q tensorflow-recommenders
pip install -q --upgrade tensorflow-datasets
pip install -q scann
import os
import pprint
import tempfile

from typing import Dict, Text

import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds
import tensorflow_recommenders as tfrs

Preparando o conjunto de dados

Vamos primeiro dar uma olhada nos dados.

Nós usamos o conjunto de dados MovieLens de Tensorflow conjuntos de dados . Carregando movielens/100k_ratings produz um tf.data.Dataset objeto contendo os dados de carga e classificações movielens/100k_movies rendimentos um tf.data.Dataset de objectos que contém apenas os dados de filmes.

Note-se que desde os MovieLens conjunto de dados não têm predefinidos splits, todos os dados estão sob train de divisão.

# Ratings data.
ratings = tfds.load("movielens/100k-ratings", split="train")
# Features of all the available movies.
movies = tfds.load("movielens/100k-movies", split="train")
2021-10-02 11:05:34.633747: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected

O conjunto de dados de classificações retorna um dicionário de id do filme, id do usuário, classificação atribuída, carimbo de data / hora, informações do filme e informações do usuário:

for x in ratings.take(1).as_numpy_iterator():
  pprint.pprint(x)
{'bucketized_user_age': 45.0,
 'movie_genres': array([7]),
 'movie_id': b'357',
 'movie_title': b"One Flew Over the Cuckoo's Nest (1975)",
 'raw_user_age': 46.0,
 'timestamp': 879024327,
 'user_gender': True,
 'user_id': b'138',
 'user_occupation_label': 4,
 'user_occupation_text': b'doctor',
 'user_rating': 4.0,
 'user_zip_code': b'53211'}
2021-10-02 11:05:35.718641: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

O conjunto de dados de filmes contém o id do filme, o título do filme e dados sobre os gêneros aos quais ele pertence. Observe que os gêneros são codificados com rótulos inteiros.

for x in movies.take(1).as_numpy_iterator():
  pprint.pprint(x)
{'movie_genres': array([4]),
 'movie_id': b'1681',
 'movie_title': b'You So Crazy (1994)'}
2021-10-02 11:05:35.893098: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

Neste exemplo, vamos nos concentrar nos dados de classificação. Outros tutoriais exploram como usar os dados de informações do filme para melhorar a qualidade do modelo.

Nós manter apenas o user_id , e movie_title campos no conjunto de dados.

ratings = ratings.map(lambda x: {
    "movie_title": x["movie_title"],
    "user_id": x["user_id"],
})
movies = movies.map(lambda x: x["movie_title"])

Para ajustar e avaliar o modelo, precisamos dividi-lo em um conjunto de treinamento e avaliação. Em um sistema de recomendação industrial, isso provavelmente seria feito por tempo: os dados até o momento $ T $ seriam usados ​​para prever interações após $ T $.

Neste exemplo simples, no entanto, vamos usar uma divisão aleatória, colocando 80% das classificações no conjunto de trem e 20% no conjunto de teste.

tf.random.set_seed(42)
shuffled = ratings.shuffle(100_000, seed=42, reshuffle_each_iteration=False)

train = shuffled.take(80_000)
test = shuffled.skip(80_000).take(20_000)

Também vamos descobrir IDs de usuário e títulos de filmes exclusivos presentes nos dados.

Isso é importante porque precisamos ser capazes de mapear os valores brutos de nossos recursos categóricos para inserir vetores em nossos modelos. Para fazer isso, precisamos de um vocabulário que mapeie um valor de recurso bruto para um inteiro em um intervalo contíguo: isso nos permite consultar os embeddings correspondentes em nossas tabelas de embedding.

movie_titles = movies.batch(1_000)
user_ids = ratings.batch(1_000_000).map(lambda x: x["user_id"])

unique_movie_titles = np.unique(np.concatenate(list(movie_titles)))
unique_user_ids = np.unique(np.concatenate(list(user_ids)))

unique_movie_titles[:10]
array([b"'Til There Was You (1997)", b'1-900 (1994)',
       b'101 Dalmatians (1996)', b'12 Angry Men (1957)', b'187 (1997)',
       b'2 Days in the Valley (1996)',
       b'20,000 Leagues Under the Sea (1954)',
       b'2001: A Space Odyssey (1968)',
       b'3 Ninjas: High Noon At Mega Mountain (1998)',
       b'39 Steps, The (1935)'], dtype=object)

Implementando um modelo

A escolha da arquitetura do nosso modelo é uma parte fundamental da modelagem.

Como estamos construindo um modelo de recuperação de duas torres, podemos construir cada torre separadamente e depois combiná-las no modelo final.

A torre de consulta

Vamos começar com a torre de consulta.

A primeira etapa é decidir sobre a dimensionalidade da consulta e representações candidatas:

embedding_dimension = 32

Valores mais altos corresponderão a modelos que podem ser mais precisos, mas também serão mais lentos para ajustar e mais propensos a sobreajuste.

A segunda é definir o próprio modelo. Aqui, nós estamos indo para usar Keras camadas de pré-processamento para IDs de usuário primeiro convertido em números inteiros, e depois converter aqueles a embeddings usuário através de uma Embedding camada. Observe que usamos a lista de IDs de usuário exclusivos que calculamos anteriormente como um vocabulário:

user_model = tf.keras.Sequential([
  tf.keras.layers.StringLookup(
      vocabulary=unique_user_ids, mask_token=None),
  # We add an additional embedding to account for unknown tokens.
  tf.keras.layers.Embedding(len(unique_user_ids) + 1, embedding_dimension)
])

Um modelo simples como isto corresponde exatamente a um clássico fatoração matriz de abordagem. Ao definir uma subclasse de tf.keras.Model para este modelo simples pode ser um exagero, podemos facilmente estendê-la a um modelo arbitrariamente complexa usando componentes padrão Keras, contanto que nós retornar um embedding_dimension saída -wide no final.

A torre candidata

Podemos fazer o mesmo com a torre candidata.

movie_model = tf.keras.Sequential([
  tf.keras.layers.StringLookup(
      vocabulary=unique_movie_titles, mask_token=None),
  tf.keras.layers.Embedding(len(unique_movie_titles) + 1, embedding_dimension)
])

Métricas

Em nossos dados de treinamento, temos pares positivos (usuário, filme). Para descobrir o quão bom é nosso modelo, precisamos comparar a pontuação de afinidade que o modelo calcula para este par com as pontuações de todos os outros candidatos possíveis: se a pontuação do par positivo for maior do que para todos os outros candidatos, nosso modelo é altamente preciso.

Para fazer isso, podemos usar o tfrs.metrics.FactorizedTopK métrica. A métrica tem um argumento obrigatório: o conjunto de dados de candidatos que são usados ​​como negativos implícitos para avaliação.

No nosso caso, essa é a movies conjunto de dados, convertido em embeddings através do nosso modelo de filme:

metrics = tfrs.metrics.FactorizedTopK(
  candidates=movies.batch(128).map(movie_model)
)

Perda

O próximo componente é a perda usada para treinar nosso modelo. O TFRS tem várias camadas de perda e tarefas para tornar isso fácil.

Neste caso, vamos fazer uso do Retrieval objeto de tarefa: a conveniência de invólucro que agrupa a função de perda e de cálculo da métrica:

task = tfrs.tasks.Retrieval(
  metrics=metrics
)

A tarefa em si é uma camada Keras que recebe a consulta e os embeddings candidatos como argumentos e retorna a perda calculada: usaremos isso para implementar o loop de treinamento do modelo.

O modelo completo

Agora podemos colocar tudo junto em um modelo. TFRS expõe uma classe de modelo base ( tfrs.models.Model ), que agiliza a construção de modelos: tudo o que precisamos fazer é configurar os componentes no __init__ método, e implementar o compute_loss método, tendo em recursos brutos e retornar um valor de perda .

O modelo básico se encarregará de criar o loop de treinamento apropriado para se ajustar ao nosso modelo.

class MovielensModel(tfrs.Model):

  def __init__(self, user_model, movie_model):
    super().__init__()
    self.movie_model: tf.keras.Model = movie_model
    self.user_model: tf.keras.Model = user_model
    self.task: tf.keras.layers.Layer = task

  def compute_loss(self, features: Dict[Text, tf.Tensor], training=False) -> tf.Tensor:
    # We pick out the user features and pass them into the user model.
    user_embeddings = self.user_model(features["user_id"])
    # And pick out the movie features and pass them into the movie model,
    # getting embeddings back.
    positive_movie_embeddings = self.movie_model(features["movie_title"])

    # The task computes the loss and the metrics.
    return self.task(user_embeddings, positive_movie_embeddings)

O tfrs.Model classe base é uma classe simplesmente conveniência: ela nos permite calcular as perdas de treinamento e teste usando o mesmo método.

Sob o capô, ainda é um modelo Keras simples. Você pode obter a mesma funcionalidade por herança de tf.keras.Model e substituindo os train_step e test_step funções (ver o guia para mais detalhes):

class NoBaseClassMovielensModel(tf.keras.Model):

  def __init__(self, user_model, movie_model):
    super().__init__()
    self.movie_model: tf.keras.Model = movie_model
    self.user_model: tf.keras.Model = user_model
    self.task: tf.keras.layers.Layer = task

  def train_step(self, features: Dict[Text, tf.Tensor]) -> tf.Tensor:

    # Set up a gradient tape to record gradients.
    with tf.GradientTape() as tape:

      # Loss computation.
      user_embeddings = self.user_model(features["user_id"])
      positive_movie_embeddings = self.movie_model(features["movie_title"])
      loss = self.task(user_embeddings, positive_movie_embeddings)

      # Handle regularization losses as well.
      regularization_loss = sum(self.losses)

      total_loss = loss + regularization_loss

    gradients = tape.gradient(total_loss, self.trainable_variables)
    self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))

    metrics = {metric.name: metric.result() for metric in self.metrics}
    metrics["loss"] = loss
    metrics["regularization_loss"] = regularization_loss
    metrics["total_loss"] = total_loss

    return metrics

  def test_step(self, features: Dict[Text, tf.Tensor]) -> tf.Tensor:

    # Loss computation.
    user_embeddings = self.user_model(features["user_id"])
    positive_movie_embeddings = self.movie_model(features["movie_title"])
    loss = self.task(user_embeddings, positive_movie_embeddings)

    # Handle regularization losses as well.
    regularization_loss = sum(self.losses)

    total_loss = loss + regularization_loss

    metrics = {metric.name: metric.result() for metric in self.metrics}
    metrics["loss"] = loss
    metrics["regularization_loss"] = regularization_loss
    metrics["total_loss"] = total_loss

    return metrics

Nestes tutoriais, no entanto, nos ater ao uso do tfrs.Model classe base para manter nosso foco na modelagem e abstrair parte do clichê.

Ajustando e avaliando

Depois de definir o modelo, podemos usar rotinas de ajuste e avaliação Keras padrão para ajustar e avaliar o modelo.

Vamos primeiro instanciar o modelo.

model = MovielensModel(user_model, movie_model)
model.compile(optimizer=tf.keras.optimizers.Adagrad(learning_rate=0.1))

Em seguida, embaralhe, agrupe e armazene em cache os dados de treinamento e avaliação.

cached_train = train.shuffle(100_000).batch(8192).cache()
cached_test = test.batch(4096).cache()

Em seguida, treine o modelo:

model.fit(cached_train, epochs=3)
Epoch 1/3
10/10 [==============================] - 6s 302ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0011 - factorized_top_k/top_5_categorical_accuracy: 0.0094 - factorized_top_k/top_10_categorical_accuracy: 0.0203 - factorized_top_k/top_50_categorical_accuracy: 0.1001 - factorized_top_k/top_100_categorical_accuracy: 0.1772 - loss: 69885.1129 - regularization_loss: 0.0000e+00 - total_loss: 69885.1129
Epoch 2/3
10/10 [==============================] - 3s 286ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0029 - factorized_top_k/top_5_categorical_accuracy: 0.0186 - factorized_top_k/top_10_categorical_accuracy: 0.0376 - factorized_top_k/top_50_categorical_accuracy: 0.1689 - factorized_top_k/top_100_categorical_accuracy: 0.2923 - loss: 67523.3707 - regularization_loss: 0.0000e+00 - total_loss: 67523.3707
Epoch 3/3
10/10 [==============================] - 3s 269ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0036 - factorized_top_k/top_5_categorical_accuracy: 0.0224 - factorized_top_k/top_10_categorical_accuracy: 0.0459 - factorized_top_k/top_50_categorical_accuracy: 0.1880 - factorized_top_k/top_100_categorical_accuracy: 0.3162 - loss: 66302.9609 - regularization_loss: 0.0000e+00 - total_loss: 66302.9609
<keras.callbacks.History at 0x7f560e5ea090>

Se você deseja monitorar o processo de formação com TensorBoard, você pode adicionar um callback TensorBoard a função de ajuste () e, em seguida, iniciar TensorBoard usando %tensorboard --logdir logs/fit . Consulte a documentação TensorBoard para mais detalhes.

Conforme o modelo treina, a perda diminui e um conjunto de métricas de recuperação top-k é atualizado. Eles nos dizem se o verdadeiro positivo está nos k primeiros itens recuperados de todo o conjunto de candidatos. Por exemplo, uma métrica de precisão categórica dos 5 primeiros de 0,2 nos diria que, em média, o verdadeiro positivo está nos 5 principais itens recuperados 20% do tempo.

Observe que, neste exemplo, avaliamos as métricas durante o treinamento, bem como a avaliação. Como isso pode ser muito lento com grandes conjuntos de candidatos, pode ser prudente desativar o cálculo da métrica no treinamento e executá-lo apenas na avaliação.

Finalmente, podemos avaliar nosso modelo no conjunto de teste:

model.evaluate(cached_test, return_dict=True)
5/5 [==============================] - 2s 149ms/step - factorized_top_k/top_1_categorical_accuracy: 7.5000e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0099 - factorized_top_k/top_10_categorical_accuracy: 0.0226 - factorized_top_k/top_50_categorical_accuracy: 0.1245 - factorized_top_k/top_100_categorical_accuracy: 0.2324 - loss: 31079.0635 - regularization_loss: 0.0000e+00 - total_loss: 31079.0635
{'factorized_top_k/top_1_categorical_accuracy': 0.000750000006519258,
 'factorized_top_k/top_5_categorical_accuracy': 0.009850000031292439,
 'factorized_top_k/top_10_categorical_accuracy': 0.02264999970793724,
 'factorized_top_k/top_50_categorical_accuracy': 0.12449999898672104,
 'factorized_top_k/top_100_categorical_accuracy': 0.23235000669956207,
 'loss': 28244.771484375,
 'regularization_loss': 0,
 'total_loss': 28244.771484375}

O desempenho do conjunto de teste é muito pior do que o desempenho do treinamento. Isso é devido a dois fatores:

  1. É provável que nosso modelo tenha um desempenho melhor com os dados que visualizou, simplesmente porque pode memorizá-los. Este fenômeno de overfitting é especialmente forte quando os modelos têm muitos parâmetros. Ele pode ser mediado pela regularização do modelo e uso de recursos do usuário e do filme que ajudam o modelo a generalizar melhor os dados invisíveis.
  2. A modelo está recomendando alguns dos filmes já vistos pelos usuários. Esses relógios positivos conhecidos podem excluir os filmes de teste das recomendações principais.

O segundo fenômeno pode ser resolvido excluindo filmes vistos anteriormente das recomendações de teste. Essa abordagem é relativamente comum na literatura de sistemas de recomendação, mas não a seguimos nesses tutoriais. Se não recomendar relógios anteriores for importante, devemos esperar que os modelos apropriadamente especificados aprendam esse comportamento automaticamente a partir do histórico do usuário anterior e das informações contextuais. Além disso, geralmente é apropriado recomendar o mesmo item várias vezes (por exemplo, uma série de TV permanente ou um item comprado regularmente).

Fazendo previsões

Agora que temos um modelo, gostaríamos de poder fazer previsões. Podemos usar o tfrs.layers.factorized_top_k.BruteForce camada para fazer isso.

# Create a model that takes in raw query features, and
index = tfrs.layers.factorized_top_k.BruteForce(model.user_model)
# recommends movies out of the entire movies dataset.
index.index_from_dataset(
  tf.data.Dataset.zip((movies.batch(100), movies.batch(100).map(model.movie_model)))
)

# Get recommendations.
_, titles = index(tf.constant(["42"]))
print(f"Recommendations for user 42: {titles[0, :3]}")
Recommendations for user 42: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

Claro, o BruteForce camada vai ser muito lento para servir um modelo com muitos candidatos possíveis. As seções a seguir mostram como acelerar isso usando um índice de recuperação aproximado.

Serviço de modelo

Depois que o modelo é treinado, precisamos encontrar uma maneira de implantá-lo.

Em um modelo de recuperação de duas torres, o serviço tem dois componentes:

  • um modelo de consulta de serviço, pegando recursos da consulta e transformando-os em uma incorporação de consulta e
  • um modelo de candidato a serviço. Na maioria das vezes, assume a forma de um índice de vizinhos mais próximos aproximados (ANN), que permite uma consulta rápida e aproximada de candidatos em resposta a uma consulta produzida pelo modelo de consulta.

No TFRS, ambos os componentes podem ser empacotados em um único modelo exportável, dando-nos um modelo que pega o ID do usuário bruto e retorna os títulos dos principais filmes desse usuário. Isto é feito através de exportar o modelo para um SavedModel formato, que torna possível para servir usando TensorFlow Servindo .

Para implantar um modelo como este, nós simplesmente exportar o BruteForce camada que criamos acima:

# Export the query model.
with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, "model")

  # Save the index.
  tf.saved_model.save(index, path)

  # Load it back; can also be done in TensorFlow Serving.
  loaded = tf.saved_model.load(path)

  # Pass a user id in, get top predicted movie titles back.
  scores, titles = loaded(["42"])

  print(f"Recommendations: {titles[0][:3]}")
2021-10-02 11:05:54.109254: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Found untraced functions such as query_with_exclusions while saving (showing 1 of 1). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: /tmp/tmp7otg6id7/model/assets
INFO:tensorflow:Assets written to: /tmp/tmp7otg6id7/model/assets
Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

Também podemos exportar um índice de recuperação aproximado para acelerar as previsões. Isso possibilitará obter recomendações de forma eficiente de conjuntos de dezenas de milhões de candidatos.

Para isso, podemos usar o scann pacote. Esta é uma dependência opcional de TFRS, e instalou-lo separadamente no início deste tutorial chamando !pip install -q scann .

Uma vez instalado, podemos usar o TFRS ScaNN camada:

scann_index = tfrs.layers.factorized_top_k.ScaNN(model.user_model)
scann_index.index_from_dataset(
  tf.data.Dataset.zip((movies.batch(100), movies.batch(100).map(model.movie_model)))
)
<tensorflow_recommenders.layers.factorized_top_k.ScaNN at 0x7f560caffc10>

Esta camada irá realizar pesquisas aproximados: Isso faz recuperação ligeiramente menos preciso, mas ordens de magnitude mais rápido em grandes conjuntos de candidatos.

# Get recommendations.
_, titles = scann_index(tf.constant(["42"]))
print(f"Recommendations for user 42: {titles[0, :3]}")
Recommendations for user 42: [b'Sleepless in Seattle (1993)' b'Father of the Bride Part II (1995)'
 b'Hunchback of Notre Dame, The (1996)']

Exportá-lo para servir é tão fácil como exportar o BruteForce camada:

# Export the query model.
with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, "model")

  # Save the index.
  tf.saved_model.save(
      index,
      path,
      options=tf.saved_model.SaveOptions(namespace_whitelist=["Scann"])
  )

  # Load it back; can also be done in TensorFlow Serving.
  loaded = tf.saved_model.load(path)

  # Pass a user id in, get top predicted movie titles back.
  scores, titles = loaded(["42"])

  print(f"Recommendations: {titles[0][:3]}")
WARNING:absl:Found untraced functions such as query_with_exclusions while saving (showing 1 of 1). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: /tmp/tmp_rde8grm/model/assets
INFO:tensorflow:Assets written to: /tmp/tmp_rde8grm/model/assets
Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

Para saber mais sobre como usar e ajuste modelos de recuperação rápida aproximados, ter um olhar para o nosso eficiente serviço tutorial.

Recomendação item a item

Neste modelo, criamos um modelo de filme do usuário. No entanto, para alguns aplicativos (por exemplo, páginas de detalhes do produto), é comum realizar recomendações item a item (por exemplo, filme a filme ou produto a produto).

Modelos de treinamento como este seguiriam o mesmo padrão mostrado neste tutorial, mas com dados de treinamento diferentes. Aqui, tínhamos um usuário e uma torre de filme e usamos pares (usuário, filme) para treiná-los. Em um modelo item a item, teríamos duas torres de item (para a consulta e o item candidato) e treinaríamos o modelo usando pares (item de consulta, item candidato). Eles podem ser construídos a partir de cliques nas páginas de detalhes do produto.

Próximos passos

Isso conclui o tutorial de recuperação.

Para expandir o que é apresentado aqui, dê uma olhada em:

  1. Modelos de aprendizagem multitarefa: otimização conjunta de classificações e cliques.
  2. Usando metadados de filme: construindo um modelo de filme mais complexo para aliviar a inicialização a frio.