¡El Día de la Comunidad de ML es el 9 de noviembre! Únase a nosotros para recibir actualizaciones de TensorFlow, JAX, y más Más información

Recomendar películas: recuperación

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Los sistemas de recomendación del mundo real a menudo se componen de dos etapas:

  1. La etapa de recuperación es responsable de seleccionar un conjunto inicial de cientos de candidatos entre todos los posibles candidatos. El objetivo principal de este modelo es eliminar de manera eficiente a todos los candidatos en los que el usuario no está interesado. Debido a que el modelo de recuperación puede estar tratando con millones de candidatos, tiene que ser computacionalmente eficiente.
  2. La etapa de clasificación toma los resultados del modelo de recuperación y los ajusta para seleccionar el mejor puñado de recomendaciones posibles. Su tarea es reducir el conjunto de elementos que pueden interesar al usuario a una lista corta de posibles candidatos.

En este tutorial, nos centraremos en la primera etapa, la recuperación. Si usted está interesado en la fase de clasificación, echar un vistazo a nuestra clasificación tutorial.

Los modelos de recuperación a menudo se componen de dos submodelos:

  1. Un modelo de consulta que calcula la representación de la consulta (normalmente un vector de incorporación de dimensionalidad fija) mediante funciones de consulta.
  2. Un modelo candidato que calcula la representación candidata (un vector de igual tamaño) utilizando las características candidatas

A continuación, los resultados de los dos modelos se multiplican para obtener una puntuación de afinidad de candidato de consulta, y las puntuaciones más altas expresan una mejor coincidencia entre el candidato y la consulta.

En este tutorial, vamos a construir y entrenar un modelo de dos torres usando el conjunto de datos Movielens.

Iremos a:

  1. Obtenga nuestros datos y divídalos en un conjunto de prueba y entrenamiento.
  2. Implemente un modelo de recuperación.
  3. Ajústelo y evalúelo.
  4. Exportarlo para un servicio eficiente mediante la construcción de un índice aproximado de vecinos más cercanos (ANN).

El conjunto de datos

Los Movielens conjunto de datos es un conjunto de datos clásico de los GroupLens grupo de investigación de la Universidad de Minnesota. Contiene un conjunto de calificaciones otorgadas a las películas por un conjunto de usuarios y es un caballo de batalla de la investigación del sistema de recomendación.

Los datos se pueden tratar de dos formas:

  1. Puede interpretarse en el sentido de que expresa qué películas vieron (y calificaron) los usuarios y cuáles no. Esta es una forma de retroalimentación implícita, donde los relojes de los usuarios nos dicen qué cosas prefieren ver y cuáles prefieren no ver.
  2. También puede verse como una expresión de cuánto les gustaron a los usuarios las películas que vieron. Esta es una forma de retroalimentación explícita: dado que un usuario vio una película, podemos decir aproximadamente cuánto le gustó al observar la calificación que ha otorgado.

En este tutorial, nos enfocamos en un sistema de recuperación: un modelo que predice un conjunto de películas del catálogo que el usuario probablemente verá. A menudo, los datos implícitos son más útiles aquí, por lo que vamos a tratar Movielens como un sistema implícito. Esto significa que cada película que un usuario vio es un ejemplo positivo y cada película que no ha visto es un ejemplo negativo implícito.

Importaciones

Primero saquemos nuestras importaciones del camino.

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 el conjunto de datos

Primero echemos un vistazo a los datos.

Usamos el conjunto de datos de MovieLens Tensorflow conjuntos de datos . Cargando movielens/100k_ratings produce un tf.data.Dataset objeto que contiene los datos de notas y de carga movielens/100k_movies rendimientos un tf.data.Dataset objeto que contiene sólo los datos de películas.

Tenga en cuenta que desde los MovieLens conjunto de datos no se ha predefinido divisiones, todos los datos están bajo train de división.

# 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

El conjunto de datos de calificaciones devuelve un diccionario de la identificación de la película, la identificación del usuario, la calificación asignada, la marca de tiempo, la información de la película y la información del usuario:

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.

El conjunto de datos de películas contiene la identificación de la película, el título de la película y los datos sobre los géneros a los que pertenece. Tenga en cuenta que los géneros están codificados con etiquetas de números enteros.

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.

En este ejemplo, nos centraremos en los datos de calificaciones. Otros tutoriales exploran cómo utilizar los datos de información de la película para mejorar la calidad del modelo.

Mantenemos sólo el user_id y movie_title campos del conjunto de datos.

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 y evaluar el modelo, necesitamos dividirlo en un conjunto de capacitación y evaluación. En un sistema de recomendación industrial, lo más probable es que esto se haga por tiempo: los datos hasta el momento $ T $ se usarían para predecir interacciones después de $ T $.

Sin embargo, en este ejemplo simple, usemos una división aleatoria, colocando el 80% de las calificaciones en el conjunto de trenes y el 20% en el conjunto de prueba.

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)

También averigüemos identificadores de usuario únicos y títulos de películas presentes en los datos.

Esto es importante porque necesitamos poder mapear los valores brutos de nuestras características categóricas para incrustar vectores en nuestros modelos. Para hacer eso, necesitamos un vocabulario que asigne un valor de característica sin procesar a un número entero en un rango contiguo: esto nos permite buscar las incrustaciones correspondientes en nuestras tablas de incrustaciones.

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 un modelo

La elección de la arquitectura de nuestro modelo es una parte clave del modelado.

Debido a que estamos construyendo un modelo de recuperación de dos torres, podemos construir cada torre por separado y luego combinarlas en el modelo final.

La torre de consultas

Comencemos con la torre de consultas.

El primer paso es decidir sobre la dimensionalidad de la consulta y las representaciones candidatas:

embedding_dimension = 32

Los valores más altos corresponderán a modelos que pueden ser más precisos, pero también serán más lentos de ajustar y más propensos a sobreajustarse.

El segundo es definir el modelo en sí. A continuación, vamos a utilizar Keras de pre-procesamiento capas a los identificadores de usuario primer convertido a números enteros, y luego convertirlas a inclusiones de usuario a través de una Embedding capa. Tenga en cuenta que usamos la lista de identificadores de usuario únicos que calculamos anteriormente como vocabulario:

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)
])

Un modelo simple como esto corresponde exactamente a un clásico matriz de factorización enfoque. Al definir una subclase de tf.keras.Model de este sencillo modelo podría ser una exageración, podemos extender fácilmente a un modelo arbitrariamente compleja con componentes estándar Keras, siempre y cuando volvemos un embedding_dimension de salida de ancho en el extremo.

La torre candidata

Podemos hacer lo mismo con la 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étrica

En nuestros datos de entrenamiento tenemos pares positivos (usuario, película). Para averiguar qué tan bueno es nuestro modelo, necesitamos comparar la puntuación de afinidad que el modelo calcula para este par con las puntuaciones de todos los demás candidatos posibles: si la puntuación del par positivo es más alta que la de todos los demás candidatos, nuestro modelo es muy preciso.

Para ello, podemos utilizar el tfrs.metrics.FactorizedTopK métrica. La métrica tiene un argumento obligatorio: el conjunto de datos de candidatos que se utilizan como negativos implícitos para la evaluación.

En nuestro caso, esa es la movies conjunto de datos, convertida en inmersiones a través de nuestro modelo de película:

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

Pérdida

El siguiente componente es la pérdida utilizada para entrenar nuestro modelo. TFRS tiene varias capas de pérdidas y tareas para facilitar esta tarea.

En este caso, vamos a hacer uso de la Retrieval objeto de tarea: una conveniencia envoltorio que los paquetes juntos la función de pérdida y cálculo métrico:

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

La tarea en sí es una capa de Keras que toma la consulta y las incrustaciones de candidatos como argumentos, y devuelve la pérdida calculada: la usaremos para implementar el ciclo de entrenamiento del modelo.

El modelo completo

Ahora podemos ponerlo todo junto en un modelo. TfRs expone una clase de modelo de base ( tfrs.models.Model ) que simplifica la construcción de modelos: todo lo que tenemos que hacer es configurar los componentes en el __init__ método, y aplicar el compute_loss método, disfruta de las características primas y devolver un valor de pérdida .

El modelo base se encargará de crear el ciclo de entrenamiento apropiado para ajustarse a nuestro 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)

El tfrs.Model clase base es una clase simple conveniencia: que nos permite calcular tanto las pérdidas de entrenamiento y prueba utilizando el mismo método.

Bajo el capó, sigue siendo un modelo sencillo de Keras. Se podía conseguir la misma funcionalidad heredando de tf.keras.Model y sustituyendo los train_step y test_step funciones (véase la guía para más detalles):

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

En estos tutoriales, sin embargo, nos ceñimos a usar el tfrs.Model clase base para mantener nuestro enfoque en el modelado y el resumen un poco de la plancha de caldera.

Ajuste y evaluación

Después de definir el modelo, podemos usar rutinas estándar de ajuste y evaluación de Keras para ajustar y evaluar el modelo.

Primero creemos una instancia del modelo.

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

Luego, mezcle, agrupe y almacene en caché los datos de capacitación y evaluación.

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

Luego entrena el 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>

Si desea supervisar el proceso de formación con TensorBoard, se puede añadir una devolución de llamada a la función de ajuste TensorBoard () y luego empezar a usar TensorBoard %tensorboard --logdir logs/fit . Por favor refiérase a la documentación TensorBoard para más detalles.

A medida que el modelo se entrena, la pérdida disminuye y se actualiza un conjunto de métricas de recuperación top-k. Estos nos dicen si el verdadero positivo está en el top-k elementos recuperados de todo el conjunto de candidatos. Por ejemplo, una métrica de precisión categórica de 0,2 entre los 5 primeros nos diría que, en promedio, el verdadero positivo está entre los 5 elementos recuperados con mayor frecuencia el 20% del tiempo.

Tenga en cuenta que, en este ejemplo, evaluamos las métricas durante el entrenamiento y la evaluación. Debido a que esto puede ser bastante lento con conjuntos de candidatos grandes, puede ser prudente desactivar el cálculo de métricas en el entrenamiento y solo ejecutarlo en evaluación.

Finalmente, podemos evaluar nuestro modelo en el conjunto de prueba:

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}

El rendimiento del conjunto de pruebas es mucho peor que el rendimiento del entrenamiento. Esto se debe a dos factores:

  1. Es probable que nuestro modelo funcione mejor con los datos que ha visto, simplemente porque puede memorizarlos. Este fenómeno de sobreajuste es especialmente fuerte cuando los modelos tienen muchos parámetros. Puede estar mediado por la regularización del modelo y el uso de funciones de usuario y película que ayudan al modelo a generalizar mejor a los datos invisibles.
  2. El modelo vuelve a recomendar algunas de las películas que ya vieron los usuarios. Estos relojes positivos conocidos pueden desplazar las películas de prueba fuera de las principales recomendaciones de K.

El segundo fenómeno se puede abordar excluyendo las películas vistas anteriormente de las recomendaciones de la prueba. Este enfoque es relativamente común en la literatura sobre sistemas de recomendación, pero no lo seguimos en estos tutoriales. Si no es importante recomendar relojes anteriores, deberíamos esperar que los modelos adecuadamente especificados aprendan este comportamiento automáticamente a partir del historial de usuarios anteriores y la información contextual. Además, a menudo es apropiado recomendar el mismo artículo varias veces (por ejemplo, una serie de televisión de hoja perenne o un artículo comprado con regularidad).

Haciendo predicciones

Ahora que tenemos un modelo, nos gustaría poder hacer predicciones. Podemos utilizar el tfrs.layers.factorized_top_k.BruteForce capa para hacer esto.

# 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)']

Por supuesto, la BruteForce capa va a ser demasiado lento para servir a un modelo con muchos candidatos posibles. Las siguientes secciones muestran cómo acelerar esto mediante el uso de un índice de recuperación aproximado.

Modelo de servicio

Una vez entrenado el modelo, necesitamos una forma de implementarlo.

En un modelo de recuperación de dos torres, el servicio tiene dos componentes:

  • un modelo de consulta de servicio, que incorpora las características de la consulta y las transforma en una incrustación de consultas, y
  • un modelo de candidato en activo. En la mayoría de los casos, esto toma la forma de un índice de vecinos más cercanos aproximados (ANN) que permite una rápida búsqueda aproximada de candidatos en respuesta a una consulta producida por el modelo de consulta.

En TFRS, ambos componentes se pueden empaquetar en un solo modelo exportable, lo que nos brinda un modelo que toma la identificación del usuario sin procesar y devuelve los títulos de las mejores películas para ese usuario. Esto se hace a través de exportar el modelo a un SavedModel formato, lo que hace posible servir usando TensorFlow Servir .

Para implementar un modelo de este tipo, simplemente exportar el BruteForce capa que hemos creado anteriormente:

# 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)']

También podemos exportar un índice de recuperación aproximado para acelerar las predicciones. Esto hará posible que surjan recomendaciones de manera eficiente de conjuntos de decenas de millones de candidatos.

Para ello, podemos utilizar el scann paquete. Esta es una dependencia opcional del TGF, y nos instala por separado al principio de este tutorial llamando !pip install -q scann .

Una vez instalado podemos usar el TGF ScaNN capa:

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 capa realizar búsquedas aproximadas: esto hace que la recuperación ligeramente menos precisa, pero las órdenes de magnitud más rápido en 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)']

Exportarlo para servir es tan fácil como la exportación de la BruteForce de la capa:

# 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 obtener más información sobre el uso y puesta a punto modelos de recuperación rápida aproximadas, echar un vistazo a nuestra ración eficiente tutorial.

Recomendación de artículo a artículo

En este modelo, creamos un modelo de película de usuario. Sin embargo, para algunas aplicaciones (por ejemplo, páginas de detalles de productos) es común realizar recomendaciones de artículo a artículo (por ejemplo, película a película o producto a producto).

Los modelos de entrenamiento como este seguirían el mismo patrón que se muestra en este tutorial, pero con diferentes datos de entrenamiento. Aquí, teníamos un usuario y una torre de películas, y usamos pares (usuario, película) para entrenarlos. En un modelo de elemento a elemento, tendríamos dos torres de elementos (para la consulta y el elemento candidato) y entrenaremos el modelo utilizando pares (elemento de consulta, elemento candidato). Estos podrían construirse a partir de clics en las páginas de detalles del producto.

Próximos pasos

Con esto concluye el tutorial de recuperación.

Para ampliar lo que se presenta aquí, eche un vistazo a:

  1. Aprendizaje de modelos multitarea: optimización conjunta para calificaciones y clics.
  2. Uso de metadatos de películas: creación de un modelo de película más complejo para aliviar el inicio en frío.