Film consigliati: recupero

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza la fonte su GitHub Scarica taccuino

I sistemi di raccomandazione del mondo reale sono spesso composti da due fasi:

  1. La fase di recupero è responsabile della selezione di una serie iniziale di centinaia di candidati tra tutti i possibili candidati. L'obiettivo principale di questo modello è eliminare in modo efficiente tutti i candidati a cui l'utente non è interessato. Poiché il modello di recupero può avere a che fare con milioni di candidati, deve essere efficiente dal punto di vista computazionale.
  2. La fase di classificazione prende i risultati del modello di recupero e li perfeziona per selezionare la migliore manciata possibile di raccomandazioni. Il suo compito è restringere l'insieme di elementi a cui l'utente potrebbe essere interessato a una rosa di probabili candidati.

In questo tutorial, ci concentreremo sulla prima fase, il recupero. Se siete interessati nella fase di classifica, dare un'occhiata alla nostra classifica tutorial.

I modelli di recupero sono spesso composti da due sottomodelli:

  1. Un modello di query che calcola la rappresentazione della query (normalmente un vettore di incorporamento a dimensionalità fissa) utilizzando le funzionalità di query.
  2. Un modello candidato che calcola la rappresentazione candidata (un vettore di uguale dimensione) utilizzando le caratteristiche candidate

Gli output dei due modelli vengono quindi moltiplicati insieme per fornire un punteggio di affinità query-candidato, con punteggi più alti che esprimono una migliore corrispondenza tra il candidato e la query.

In questo tutorial, costruiremo e addestreremo un tale modello a due torri utilizzando il set di dati Movielens.

Stava andando a:

  1. Ottieni i nostri dati e dividili in un set di allenamento e test.
  2. Implementare un modello di recupero.
  3. Adattalo e valutalo.
  4. Esportalo per un servizio efficiente costruendo un indice approssimativo dei vicini più vicini (ANN).

Il set di dati

I MovieLens set di dati è un insieme di dati classica dai GroupLens Gruppo di ricerca presso l'Università del Minnesota. Contiene una serie di valutazioni date ai film da un insieme di utenti ed è un cavallo di battaglia della ricerca del sistema di raccomandazione.

I dati possono essere trattati in due modi:

  1. Può essere interpretato come l'espressione di quali film gli utenti hanno guardato (e valutato) e quali no. Questa è una forma di feedback implicito, in cui gli orologi degli utenti ci dicono quali cose preferiscono vedere e quali preferirebbero non vedere.
  2. Può anche essere visto come l'espressione di quanto agli utenti siano piaciuti i film che hanno visto. Questa è una forma di feedback esplicito: dato che un utente ha visto un film, possiamo dire approssimativamente quanto gli è piaciuto guardando il voto che ha dato.

In questo tutorial, ci concentriamo su un sistema di recupero: un modello che prevede una serie di film dal catalogo che è probabile che l'utente guardi. Spesso i dati impliciti sono più utili qui, quindi tratteremo Movielens come un sistema implicito. Ciò significa che ogni film che un utente ha visto è un esempio positivo e ogni film che non ha visto è un implicito esempio negativo.

Importazioni

Per prima cosa togliamo di mezzo le nostre importazioni.

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

Preparazione del set di dati

Diamo prima un'occhiata ai dati.

Usiamo il set di dati da MovieLens tensorflow dataset . Caricamento movielens/100k_ratings produce un tf.data.Dataset oggetto che contiene i dati di rating e di carico movielens/100k_movies rese un tf.data.Dataset oggetto che contiene solo i dati di film.

Nota che, poiché le MovieLens set di dati non sono predefiniti divisioni, tutti i dati sono sotto train spaccato.

# 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

Il set di dati delle valutazioni restituisce un dizionario di ID film, ID utente, valutazione assegnata, timestamp, informazioni sul film e informazioni sull'utente:

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.

Il set di dati dei film contiene l'ID del film, il titolo del film e i dati sui generi a cui appartiene. Nota che i generi sono codificati con etichette intere.

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.

In questo esempio, ci concentreremo sui dati delle valutazioni. Altri tutorial esplorano come utilizzare anche i dati delle informazioni sul film per migliorare la qualità del modello.

Teniamo solo user_id , e movie_title campi nel set di dati.

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

Per adattare e valutare il modello, dobbiamo dividerlo in un insieme di formazione e valutazione. In un sistema di raccomandazione industriale, questo sarebbe molto probabilmente essere fatto da tempo: i dati fino al tempo \(T\) sarebbe stato usato per predire le interazioni dopo \(T\).

In questo semplice esempio, tuttavia, utilizziamo una suddivisione casuale, inserendo l'80% delle valutazioni nel set di treni e il 20% nel set di test.

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)

Scopriamo anche gli ID utente univoci e i titoli dei film presenti nei dati.

Questo è importante perché dobbiamo essere in grado di mappare i valori grezzi delle nostre caratteristiche categoriche per incorporare i vettori nei nostri modelli. Per fare ciò, abbiamo bisogno di un vocabolario che associ un valore di caratteristica non elaborato a un numero intero in un intervallo contiguo: questo ci consente di cercare gli incorporamenti corrispondenti nelle nostre tabelle di incorporamento.

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)

Implementazione di un modello

La scelta dell'architettura del nostro modello è una parte fondamentale della modellazione.

Poiché stiamo costruendo un modello di recupero a due torri, possiamo costruire ciascuna torre separatamente e quindi combinarle nel modello finale.

La torre delle domande

Iniziamo con la torre delle query.

Il primo passo è decidere sulla dimensionalità della query e delle rappresentazioni candidate:

embedding_dimension = 32

Valori più alti corrisponderanno a modelli che potrebbero essere più accurati, ma saranno anche più lenti da montare e più inclini al sovradattamento.

Il secondo è definire il modello stesso. Qui, stiamo andando a utilizzare Keras strati preprocessamento primo convertito ID utente a numeri interi, e poi convertire coloro ai embeddings utente tramite un Embedding strato. Nota che usiamo l'elenco di ID utente univoci che abbiamo calcolato in precedenza come vocabolario:

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 modello semplice come questo corrisponde esattamente a un classico fattorizzazione matrice approccio. Definendo una sottoclasse di tf.keras.Model per questo semplice modello potrebbe essere eccessivo, possiamo facilmente estendere a un modello arbitrariamente complesso con componenti standard KERAS, fintanto che restituiscono un embedding_dimension uscita -wide alla fine.

La torre candidata

Possiamo fare lo stesso 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)
])

Metrica

Nei nostri dati di allenamento abbiamo coppie positive (utente, film). Per capire quanto è buono il nostro modello, dobbiamo confrontare il punteggio di affinità che il modello calcola per questa coppia con i punteggi di tutti gli altri possibili candidati: se il punteggio per la coppia positiva è superiore a quello di tutti gli altri candidati, il nostro modello è molto preciso.

Per fare questo, siamo in grado di utilizzare il tfrs.metrics.FactorizedTopK metrica. La metrica ha un argomento obbligatorio: il set di dati dei candidati che vengono utilizzati come negativi impliciti per la valutazione.

Nel nostro caso, questo è il movies insieme di dati, convertito in incastri tramite il nostro modello di film:

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

Perdita

Il componente successivo è la perdita utilizzata per addestrare il nostro modello. TFRS ha diversi livelli di perdita e attività per renderlo facile.

In questo caso, faremo uso del Retrieval dell'oggetto attività: una convenienza wrapper che bundle insieme la funzione di perdita e computo metrico:

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

L'attività stessa è un livello Keras che accetta la query e gli incorporamenti candidati come argomenti e restituisce la perdita calcolata: la useremo per implementare il ciclo di addestramento del modello.

Il modello completo

Ora possiamo mettere tutto insieme in un modello. TFRs espone una classe del modello di base ( tfrs.models.Model ), che semplifica la costruzione di modelli: tutto quello che dobbiamo fare è impostare i componenti del __init__ metodo, e implementare il compute_loss metodo, prendendo le caratteristiche prime e restituire un valore di perdita .

Il modello base si occuperà quindi di creare il ciclo di addestramento appropriato per adattarsi al nostro modello.

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)

Il tfrs.Model classe base è una classe semplice convenienza: permette di calcolare sia le perdite di formazione e di prova con lo stesso metodo.

Sotto il cofano, è ancora un semplice modello Keras. Si potrebbe ottenere la stessa funzionalità ereditando da tf.keras.Model e ridefinendo le train_step e test_step funzioni (vedi la guida per i dettagli):

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

In queste esercitazioni, tuttavia, ci atteniamo ad utilizzare il tfrs.Model classe base per mantenere la nostra attenzione sulla modellazione e astrarre alcuni dei boilerplate.

Adattamento e valutazione

Dopo aver definito il modello, possiamo utilizzare le routine di adattamento e valutazione standard di Keras per adattare e valutare il modello.

Istanziamo prima il modello.

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

Quindi mescola, raggruppa e memorizza nella cache i dati di formazione e valutazione.

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

Quindi addestrare il modello:

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 si desidera monitorare il processo di formazione con TensorBoard, è possibile aggiungere un callback TensorBoard alla funzione in forma () e poi iniziare a utilizzare TensorBoard %tensorboard --logdir logs/fit . Si prega di fare riferimento alla documentazione di TensorBoard per maggiori dettagli.

Man mano che il modello si allena, la perdita diminuisce e viene aggiornato un insieme di metriche di recupero top-k. Questi ci dicono se il vero positivo è tra i primi k elementi recuperati dall'intero insieme di candidati. Ad esempio, una metrica di accuratezza categoriale tra i primi 5 di 0,2 ci direbbe che, in media, il vero positivo è tra i primi 5 elementi recuperati il ​​20% delle volte.

Nota che, in questo esempio, valutiamo le metriche durante l'addestramento e la valutazione. Poiché questo può essere piuttosto lento con insiemi di candidati di grandi dimensioni, può essere prudente disattivare il calcolo della metrica durante l'addestramento ed eseguirlo solo durante la valutazione.

Infine, possiamo valutare il nostro modello sul test set:

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}

Le prestazioni del set di test sono molto peggiori delle prestazioni dell'allenamento. Ciò è dovuto a due fattori:

  1. È probabile che il nostro modello funzioni meglio sui dati che ha visto, semplicemente perché può memorizzarli. Questo fenomeno di sovradattamento è particolarmente forte quando i modelli hanno molti parametri. Può essere mediato dalla regolarizzazione del modello e dall'uso di funzionalità utente e film che aiutano il modello a generalizzare meglio i dati non visti.
  2. Il modello sta consigliando nuovamente alcuni dei film già visti dagli utenti. Questi orologi noti positivi possono escludere i film di prova dai migliori consigli K.

Il secondo fenomeno può essere affrontato escludendo i film visti in precedenza dalle raccomandazioni dei test. Questo approccio è relativamente comune nella letteratura sui sistemi di raccomandazione, ma non lo seguiamo in questi tutorial. Se non è importante consigliare gli orologi precedenti, dovremmo aspettarci che i modelli specificati in modo appropriato apprendano questo comportamento automaticamente dalla cronologia degli utenti passati e dalle informazioni contestuali. Inoltre, spesso è opportuno consigliare lo stesso articolo più volte (ad esempio, una serie TV sempreverde o un articolo acquistato regolarmente).

Fare previsioni

Ora che abbiamo un modello, vorremmo essere in grado di fare previsioni. Possiamo usare la tfrs.layers.factorized_top_k.BruteForce strato di fare questo.

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

Naturalmente, il BruteForce strato sta per essere troppo lento per servire un modello con molte possibili candidati. Le sezioni seguenti mostrano come velocizzare questa operazione utilizzando un indice di recupero approssimativo.

Servizio modello

Dopo che il modello è stato addestrato, abbiamo bisogno di un modo per distribuirlo.

In un modello di recupero a due torri, il servizio ha due componenti:

  • un modello di query di servizio, che include le caratteristiche della query e le trasforma in un incorporamento della query, e
  • un modello candidato al servizio. Questo spesso assume la forma di un indice approssimativo dei vicini più vicini (ANN) che consente una rapida ricerca approssimativa dei candidati in risposta a una query prodotta dal modello di query.

In TFRS, entrambi i componenti possono essere impacchettati in un unico modello esportabile, fornendoci un modello che prende l'ID utente non elaborato e restituisce i titoli dei film migliori per quell'utente. Questo viene fatto attraverso l'esportazione del modello a un SavedModel formato, che permette di servire con tensorflow servizio .

Per distribuire un modello come questo, abbiamo semplicemente esportiamo il BruteForce livello che abbiamo creato in precedenza:

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

Possiamo anche esportare un indice di recupero approssimativo per velocizzare le previsioni. Ciò consentirà di far emergere in modo efficiente raccomandazioni da insiemi di decine di milioni di candidati.

Per fare ciò, possiamo usare lo scann pacchetto. Si tratta di una dipendenza opzionale di TFRs, e abbiamo installato separatamente all'inizio di questo tutorial chiamando !pip install -q scann .

Una volta installato possiamo usare il TFRs ScaNN strato:

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>

Questo strato eseguirà ricerche approssimative: questo rende il recupero un po 'meno preciso, ma gli ordini di grandezza più veloce su grandi insiemi di candidati.

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

L'esportazione per servire è facile come esportare la BruteForce strato:

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

Per ulteriori informazioni sull'utilizzo e la messa a punto modelli di recupero rapido approssimati, dare un'occhiata al nostro efficiente servizio tutorial.

Raccomandazione da articolo a articolo

In questo modello, abbiamo creato un modello di film utente. Tuttavia, per alcune applicazioni (ad esempio, le pagine dei dettagli del prodotto) è comune eseguire consigli da articolo a articolo (ad esempio, da film a film o da prodotto a prodotto).

I modelli di addestramento come questo seguirebbero lo stesso modello mostrato in questo tutorial, ma con dati di addestramento diversi. Qui avevamo un utente e una torre di film e usavamo coppie (utente, film) per addestrarli. In un modello elemento-elemento, avremmo due torri di elementi (per la query e l'elemento candidato) e addestreremo il modello utilizzando le coppie (elemento query, elemento candidato). Questi potrebbero essere costruiti dai clic sulle pagine dei dettagli del prodotto.

Prossimi passi

Questo conclude il tutorial di recupero.

Per espandere ciò che viene presentato qui, dai un'occhiata a:

  1. Apprendimento dei modelli multi-task: ottimizzazione congiunta per valutazioni e clic.
  2. Utilizzo dei metadati del film: creazione di un modello di film più complesso per alleviare l'avvio a freddo.