Empfohlene Filme: Abruf

Auf TensorFlow.org ansehen In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Real-World-Recommender-Systeme bestehen oft aus zwei Phasen:

  1. Die Abrufphase ist für die Auswahl einer anfänglichen Gruppe von Hunderten von Kandidaten aus allen möglichen Kandidaten verantwortlich. Das Hauptziel dieses Modells besteht darin, alle Kandidaten, an denen der Benutzer nicht interessiert ist, effizient auszusortieren. Da das Retrieval-Modell mit Millionen von Kandidaten umgehen kann, muss es recheneffizient sein.
  2. Die Ranking-Phase nimmt die Ergebnisse des Retrieval-Modells und verfeinert sie, um die bestmögliche Handvoll Empfehlungen auszuwählen. Seine Aufgabe besteht darin, die Menge der Elemente, an denen der Benutzer interessiert sein könnte, auf eine Auswahlliste wahrscheinlicher Kandidaten einzugrenzen.

In diesem Tutorial konzentrieren wir uns auf die erste Phase, den Abruf. Wenn Sie in der Rangliste der Bühne interessiert sind, haben einen Blick auf unsere Ranking - Tutorial.

Retrieval-Modelle bestehen oft aus zwei Untermodellen:

  1. Ein Abfragemodell, das die Abfragedarstellung (normalerweise ein Einbettungsvektor mit fester Dimensionalität) unter Verwendung von Abfragefunktionen berechnet.
  2. Ein Kandidatenmodell, das die Kandidatendarstellung (einen Vektor gleicher Größe) unter Verwendung der Kandidatenmerkmale berechnet

Die Ausgaben der beiden Modelle werden dann miteinander multipliziert, um eine Affinitätsbewertung für den Abfragekandidaten zu erhalten, wobei höhere Bewertungen eine bessere Übereinstimmung zwischen dem Kandidaten und der Abfrage ausdrücken.

In diesem Tutorial erstellen und trainieren wir ein solches Zweiturmmodell mit dem Movielens-Dataset.

Wir werden:

  1. Holen Sie sich unsere Daten und teilen Sie sie in ein Trainings- und Testset auf.
  2. Implementieren Sie ein Abrufmodell.
  3. Passen und bewerten Sie es.
  4. Exportieren Sie es für eine effiziente Bereitstellung, indem Sie einen ungefähren Index der nächsten Nachbarn (ANN) erstellen.

Der Datensatz

Die Movielens - Dataset ein klassischer Datensatz aus dem ist GroupLens Forschungsgruppe an der Universität von Minnesota. Es enthält eine Reihe von Bewertungen für Filme von einer Reihe von Benutzern und ist ein Arbeitspferd der Empfehlungssystemforschung.

Die Daten können auf zwei Arten behandelt werden:

  1. Es kann so interpretiert werden, dass es ausdrückt, welche Filme die Benutzer gesehen (und bewertet) und welche nicht. Dies ist eine Form des impliziten Feedbacks, bei der die Uhren der Benutzer uns mitteilen, welche Dinge sie lieber sehen und welche nicht.
  2. Es kann auch als Ausdruck dafür angesehen werden, wie sehr die Benutzer die Filme, die sie sich angesehen haben, mochten. Dies ist eine Form des expliziten Feedbacks: Wenn ein Nutzer einen Film gesehen hat, können wir anhand der Bewertung, die er abgegeben hat, ungefähr sagen, wie gut ihm gefallen hat.

In diesem Tutorial konzentrieren wir uns auf ein Abrufsystem: ein Modell, das eine Reihe von Filmen aus dem Katalog vorhersagt, die der Benutzer wahrscheinlich sehen wird. Oft sind hier implizite Daten nützlicher, und deshalb behandeln wir Movielens als ein implizites System. Dies bedeutet, dass jeder Film, den ein Benutzer gesehen hat, ein positives Beispiel ist und jeder Film, den er nicht gesehen hat, ein implizites negatives Beispiel ist.

Importe

Lassen Sie uns zuerst unsere Importe aus dem Weg räumen.

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

Vorbereiten des Datensatzes

Schauen wir uns zunächst die Daten an.

Wir verwenden den Movielens - Datensatz aus Tensorflow Datensätze . Laden movielens/100k_ratings ergibt sich ein tf.data.Dataset Objekt , um die Bemessungsdaten und Laden enthält movielens/100k_movies Ausbeuten ein tf.data.Dataset Objekt enthält Daten nur die Filme.

Beachten Sie, dass die Movielens seit dataSet Splits sind nicht vorgegeben, sind alle Daten unter train Split.

# 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-08-24 11:23:07.684827: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected
2021-08-24 11:23:07.684881: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (kokoro-gcp-ubuntu-prod-1865084408): /proc/driver/nvidia/version does not exist
2021-08-24 11:23:07.686220: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.

Das Bewertungs-Dataset gibt ein Wörterbuch mit Film-ID, Benutzer-ID, zugewiesener Bewertung, Zeitstempel, Filminformationen und Benutzerinformationen zurück:

for x in ratings.take(1).as_numpy_iterator():
  pprint.pprint(x)
2021-08-24 11:23:08.510902: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2)
{'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-08-24 11:23:08.793892: 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.

Der Filmdatensatz enthält die Film-ID, den Filmtitel und Daten zu den Genres, zu denen er gehört. Beachten Sie, dass die Genres mit ganzzahligen Labels codiert sind.

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-08-24 11:23:09.008985: 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 diesem Beispiel konzentrieren wir uns auf die Bewertungsdaten. In anderen Tutorials wird erläutert, wie auch die Filminformationsdaten verwendet werden, um die Modellqualität zu verbessern.

Wir halten nur die user_id und movie_title Felder im Datensatz.

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

Um das Modell anzupassen und zu evaluieren, müssen wir es in ein Trainings- und Evaluierungsset aufteilen. In einem industriellen Empfehlungssystem würde dies höchstwahrscheinlich nach Zeit erfolgen: Die Daten bis zum Zeitpunkt $T$ würden verwendet, um Interaktionen nach $T$ vorherzusagen.

In diesem einfachen Beispiel verwenden wir jedoch eine zufällige Aufteilung, bei der 80 % der Bewertungen in den Zugsatz und 20 % in den Testsatz gelegt werden.

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)

Lassen Sie uns auch die in den Daten vorhandenen eindeutigen Benutzer-IDs und Filmtitel herausfinden.

Dies ist wichtig, da wir in der Lage sein müssen, die Rohwerte unserer kategorialen Merkmale den Einbettungsvektoren in unseren Modellen zuzuordnen. Dazu benötigen wir ein Vokabular, das einen rohen Merkmalswert auf eine ganze Zahl in einem zusammenhängenden Bereich abbildet: Dies ermöglicht es uns, die entsprechenden Einbettungen in unseren Einbettungstabellen nachzuschlagen.

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)

Ein Modell implementieren

Die Wahl der Architektur unseres Modells ist ein wichtiger Teil der Modellierung.

Da wir ein Zweiturm-Retrieval-Modell bauen, können wir jeden Turm separat bauen und sie dann im endgültigen Modell kombinieren.

Der Abfrageturm

Beginnen wir mit dem Abfrageturm.

Der erste Schritt besteht darin, über die Dimensionalität der Abfrage und der Kandidatendarstellungen zu entscheiden:

embedding_dimension = 32

Höhere Werte entsprechen Modellen, die möglicherweise genauer sind, aber auch langsamer angepasst werden und anfälliger für Überanpassung sind.

Die zweite besteht darin, das Modell selbst zu definieren. Hier werden wir Keras Vorverarbeitung Schichten erste Konvertit Benutzer - IDs auf ganze Zahlen verwenden, und dann diejenigen Benutzer Einbettungen über eine konvertieren Embedding Schicht. Beachten Sie, dass wir die zuvor berechnete Liste eindeutiger Benutzer-IDs als Vokabular verwenden:

user_model = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.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)
])

Ein einfaches Modell wie dies entspricht genau einem klassischen Matrix - Faktorisierung Ansatz. Bei der Definition einer Unterklasse von tf.keras.Model könnte für dieses einfache Modell zu viel des Guten, können wir es leicht zu einem beliebig komplexen Modell erweitern Standard Keras Komponenten, solange wir eine Rückkehr embedding_dimension -weite Ausgang am Ende.

Der Kandidatenturm

Dasselbe können wir mit dem Kandidatenturm machen.

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

Messwerte

In unseren Trainingsdaten haben wir positive (Benutzer, Film) Paare. Um herauszufinden, wie gut unser Modell ist, müssen wir den Affinitätswert, den das Modell für dieses Paar berechnet, mit den Werten aller anderen möglichen Kandidaten vergleichen: Wenn der Wert für das positive Paar höher ist als für alle anderen Kandidaten, wird unser Modell ist sehr genau.

Um dies zu tun, können wir die Verwendung tfrs.metrics.FactorizedTopK Metrik. Die Metrik hat ein erforderliches Argument: den Datensatz der Kandidaten, die als implizite Negative für die Bewertung verwendet werden.

In unserem Fall , dass das ist movies - Datensatz, umgewandelt in Einbettungen über unseren Film Modell:

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

Verlust

Die nächste Komponente ist der Verlust, der zum Trainieren unseres Modells verwendet wird. TFRS hat mehrere Verlustschichten und Aufgaben, um dies zu vereinfachen.

In diesem Fall werden wir die Verwendung des machen Retrieval Bequemlichkeit Wrapper, Bündel zusammen die Verlustfunktion und Metrikberechnungs-: Task - Objekt:

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

Die Aufgabe selbst ist eine Keras-Schicht, die die Abfrage- und Kandidateneinbettungen als Argumente verwendet und den berechneten Verlust zurückgibt: Wir verwenden dies, um die Trainingsschleife des Modells zu implementieren.

Das vollständige Modell

Jetzt können wir alles zu einem Modell zusammenfügen. TFRS stellt eine Basismodell Klasse ( tfrs.models.Model ) , die Gebäudemodelle optimiert: alles , was wir tun müssen , um die Komponenten in der einzurichten __init__ Methode und implementieren die compute_loss Methode, in der Rohmerkmale nehmen und einen Verlustwertes Rückkehr .

Das Basismodell kümmert sich dann darum, die geeignete Trainingsschleife zu erstellen, die zu unserem Modell passt.

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)

Die tfrs.Model Basisklasse ist eine einfach Bequemlichkeit Klasse: es uns sowohl Trainings- und Test Verluste mit der gleichen Methode zu berechnen erlaubt.

Unter der Haube ist es immer noch ein schlichtes Keras-Modell. Sie könnten die gleiche Funktionalität durch Erben aus erreichen tf.keras.Model und Überschreiben der train_step und test_step Funktionen (siehe die Anleitung für weitere Details):

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 diesen Tutorials, jedoch halten wir die zur Verwendung von tfrs.Model Basisklasse unseren Fokus auf die Modellierung und abstrahieren einige der Textvorschlag zu halten.

Anpassen und auswerten

Nach der Definition des Modells können wir standardmäßige Keras-Anpassungs- und Bewertungsroutinen verwenden, um das Modell anzupassen und zu bewerten.

Lassen Sie uns zuerst das Modell instanziieren.

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

Anschließend werden die Trainings- und Bewertungsdaten gemischt, gestapelt und zwischengespeichert.

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

Trainieren Sie dann das Modell:

model.fit(cached_train, epochs=3)
Epoch 1/3
10/10 [==============================] - 6s 308ms/step - factorized_top_k/top_1_categorical_accuracy: 7.6250e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0072 - factorized_top_k/top_10_categorical_accuracy: 0.0167 - factorized_top_k/top_50_categorical_accuracy: 0.0915 - factorized_top_k/top_100_categorical_accuracy: 0.1698 - loss: 69885.1129 - regularization_loss: 0.0000e+00 - total_loss: 69885.1129
Epoch 2/3
10/10 [==============================] - 3s 287ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0028 - factorized_top_k/top_5_categorical_accuracy: 0.0184 - factorized_top_k/top_10_categorical_accuracy: 0.0375 - factorized_top_k/top_50_categorical_accuracy: 0.1682 - factorized_top_k/top_100_categorical_accuracy: 0.2917 - loss: 67523.3707 - regularization_loss: 0.0000e+00 - total_loss: 67523.3707
Epoch 3/3
10/10 [==============================] - 3s 280ms/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 0x7f95f02a2390>

Während der Modellzug sinkt, sinkt der Verlust und ein Satz von Top-k-Abrufmetriken wird aktualisiert. Diese sagen uns, ob sich das wahre Positiv in den Top-k der abgerufenen Elemente aus der gesamten Kandidatenmenge befindet. Eine Top-5-Kategorisierungs-Genauigkeitsmetrik von 0,2 würde uns beispielsweise sagen, dass das wahre Positive im Durchschnitt in 20 % der Fälle in den Top-5 der abgerufenen Elemente liegt.

Beachten Sie, dass wir in diesem Beispiel die Metriken sowohl während des Trainings als auch während der Bewertung auswerten. Da dies bei großen Kandidatenmengen recht langsam sein kann, kann es ratsam sein, die Metrikberechnung im Training auszuschalten und sie nur in der Auswertung auszuführen.

Schließlich können wir unser Modell auf dem Testset evaluieren:

model.evaluate(cached_test, return_dict=True)
5/5 [==============================] - 2s 155ms/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}

Die Leistung des Testsatzes ist viel schlechter als die Trainingsleistung. Dies ist auf zwei Faktoren zurückzuführen:

  1. Unser Modell schneidet wahrscheinlich besser mit den Daten ab, die es gesehen hat, einfach weil es sich diese merken kann. Dieses Überanpassungsphänomen ist besonders stark, wenn Modelle viele Parameter haben. Dies kann durch die Modellregularisierung und die Verwendung von Benutzer- und Filmfunktionen vermittelt werden, die dem Modell helfen, besser auf unsichtbare Daten zu generalisieren.
  2. Das Modell empfiehlt einige der bereits angesehenen Filme von Benutzern erneut. Diese bekannten positiven Uhren können Testfilme aus den Top-K-Empfehlungen verdrängen.

Dem zweiten Phänomen kann begegnet werden, indem zuvor gesehene Filme von Testempfehlungen ausgeschlossen werden. Dieser Ansatz ist in der Literatur zu Empfehlungssystemen relativ gebräuchlich, aber wir verfolgen ihn in diesen Tutorials nicht. Wenn es wichtig ist, vergangene Uhren nicht zu empfehlen, sollten wir erwarten, dass entsprechend spezifizierte Modelle dieses Verhalten automatisch aus der früheren Benutzerhistorie und den Kontextinformationen lernen. Darüber hinaus ist es oft angebracht, denselben Artikel mehrmals zu empfehlen (z. B. eine Evergreen-TV-Serie oder ein regelmäßig gekaufter Artikel).

Vorhersagen treffen

Da wir nun ein Modell haben, möchten wir Vorhersagen treffen können. Wir können die Verwendung tfrs.layers.factorized_top_k.BruteForce Schicht , dies zu tun.

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

Natürlich ist die BruteForce wird Schicht zu langsam sein , ein Modell mit vielen möglichen Kandidaten zu dienen. In den folgenden Abschnitten wird gezeigt, wie Sie dies mithilfe eines ungefähren Abrufindex beschleunigen können.

Modellzustellung

Nachdem das Modell trainiert wurde, benötigen wir eine Möglichkeit, es bereitzustellen.

In einem Abrufmodell mit zwei Türmen besteht die Bereitstellung aus zwei Komponenten:

  • ein Serving-Abfragemodell, das Funktionen der Abfrage aufnimmt und in eine Abfrageeinbettung umwandelt, und
  • ein dienendes Kandidatenmodell. Dies nimmt meistens die Form eines ungefähren Nächsten-Nachbarn-(ANN)-Index an, der ein schnelles ungefähres Nachschlagen von Kandidaten als Reaktion auf eine vom Abfragemodell erzeugte Abfrage ermöglicht.

In TFRS können beide Komponenten in einem einzigen exportierbaren Modell verpackt werden, wodurch wir ein Modell erhalten, das die rohe Benutzer-ID verwendet und die Titel der Top-Filme für diesen Benutzer zurückgibt. Dies wird über den Export , das Modell zu einem getan SavedModel Format, das es ermöglicht , dienen mit TensorFlow Serving .

Um ein Modell wie diese einsetzen, exportieren wir einfach die BruteForce Schicht wir oben erstellt:

# 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-08-24 11:23:28.077112: 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/tmprdeui3rt/model/assets
INFO:tensorflow:Assets written to: /tmp/tmprdeui3rt/model/assets
Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

Wir können auch einen ungefähren Abrufindex exportieren, um Vorhersagen zu beschleunigen. Dies wird es möglich machen, Empfehlungen aus Sätzen von mehreren zehn Millionen Kandidaten effizient hervorzubringen.

Um dies zu tun, können wir die Verwendung scann Paket. Dies ist eine optionale Abhängigkeit von TFRS, und wir sie separat am Anfang dieser Anleitung installiert durch den Aufruf !pip install -q scann .

Nach der Installation können wir die TFRS verwenden ScaNN Schicht:

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)))
)
2021-08-24 11:23:28.652143: I scann/partitioning/partitioner_factory_base.cc:71] Size of sampled dataset for training partition: 1682
2021-08-24 11:23:28.661092: I ./scann/partitioning/kmeans_tree_partitioner_utils.h:102] PartitionerFactory ran in 8.895297ms.
<tensorflow_recommenders.layers.factorized_top_k.ScaNN at 0x7f95375bfe10>

Diese Schicht wird ungefähre Lookups durchführen: Das macht Retrieval etwas weniger genau, aber um Größenordnungen schneller auf große Kandidatenmengen.

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

Exportieren es zum Servieren ist so einfach wie das Exportieren von BruteForce - Schicht:

# 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/tmpxlk0mik6/model/assets
INFO:tensorflow:Assets written to: /tmp/tmpxlk0mik6/model/assets
Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

Um mehr zu erfahren über die Verwendung und Tuning schnelle ungefähre Retrieval Modelle haben einen Blick auf unsere effizienten Portion Tutorial.

Nächste Schritte

Damit ist das Tutorial zum Abrufen abgeschlossen.

Um das, was hier präsentiert wird, zu erweitern, werfen Sie einen Blick auf:

  1. Multitask-Modelle lernen: Gemeinsam auf Bewertungen und Klicks optimieren.
  2. Verwenden von Filmmetadaten: Erstellen eines komplexeren Filmmodells, um Kaltstarts zu vermeiden.