今日のローカルTensorFlowEverywhereイベントの出欠確認!
このページは Cloud Translation API によって翻訳されました。
Switch to English

映画のおすすめ:検索

TensorFlow.orgで表示 GoogleColabで実行 GitHubでソースを表示ノートブックをダウンロード

実際のレコメンダーシステムは、多くの場合、次の2つの段階で構成されます。

  1. 検索段階では、考えられるすべての候補から数百の候補の初期セットを選択します。このモデルの主な目的は、ユーザーが関心のないすべての候補を効率的に取り除くことです。検索モデルは数百万の候補を処理する可能性があるため、計算効率が高くなければなりません。
  2. ランク付け段階では、検索モデルの出力を取得し、それらを微調整して、可能な限り最良の少数の推奨事項を選択します。そのタスクは、ユーザーが興味を持つ可能性のあるアイテムのセットを、可能性のある候補の候補リストに絞り込むことです。

このチュートリアルでは、最初の段階である検索に焦点を当てます。ランキング段階に興味がある場合は、ランキングチュートリアルをご覧ください。

多くの場合、検索モデルは2つのサブモデルで構成されます。

  1. クエリ機能を使用してクエリ表現(通常は固定次元の埋め込みベクトル)を計算するクエリモデル。
  2. 候補特徴を使用して候補表現(同じサイズのベクトル)を計算する候補モデル

次に、2つのモデルの出力が乗算されて、クエリ候補のアフィニティスコアが得られます。スコアが高いほど、候補とクエリの一致度が高くなります。

このチュートリアルでは、Movielensデータセットを使用して、このような2タワーモデルを構築およびトレーニングします。

に行っていました:

  1. データを取得して、トレーニングセットとテストセットに分割します。
  2. 検索モデルを実装します。
  3. 適合させて評価します。
  4. おおよその最近傍(ANN)インデックスを作成することにより、効率的なサービスのためにエクスポートします。

データセット

Movielensデータセットは、ミネソタ大学のGroupLens研究グループからの古典的なデータセットです。これには、一連のユーザーによって映画に与えられた一連の評価が含まれており、レコメンダーシステム研究の主力製品です。

データは2つの方法で処理できます。

  1. これは、ユーザーがどの映画を視聴(および評価)したか、どの映画を視聴しなかったかを表すものと解釈できます。これは暗黙のフィードバックの形式であり、ユーザーの時計は、ユーザーが見たいものと見たくないものを教えてくれます。
  2. また、ユーザーが視聴した映画をどれだけ気に入ったかを表すものとして見ることもできます。これは明示的なフィードバックの一形態です。ユーザーが映画を視聴した場合、ユーザーが付けた評価を見れば、ユーザーがどれだけ気に入ったかを大まかに知ることができます。

このチュートリアルでは、検索システムに焦点を当てています。これは、ユーザーが視聴する可能性のあるカタログから一連の映画を予測するモデルです。多くの場合、ここでは暗黙的なデータの方が便利なので、Movielensを暗黙的なシステムとして扱います。これは、ユーザーが見たすべての映画が良い例であり、ユーザーが見たことがないすべての映画が暗黙の悪い例であることを意味します。

輸入

まず、インポートを邪魔にならないようにしましょう。

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

データセットの準備

まず、データを見てみましょう。

私たちは、からMovieLensデータセットを使用Tensorflowデータセットを。ロードmovielens/100k_ratingstf.data.Dataset評価データとロード含むオブジェクトmovielens/100k_moviestf.data.Dataset映画だけのデータを含むオブジェクトを。

MovieLensデータセットには事前定義された分割がないため、すべてのデータがtrain分割されていることに注意してください。

# Ratings data.
ratings = tfds.load("movielens/100k-ratings", split="train")
# Features of all the available movies.
movies = tfds.load("movielens/100k-movies", split="train")
Downloading and preparing dataset movielens/100k-ratings/0.1.0 (download: 4.70 MiB, generated: 32.41 MiB, total: 37.10 MiB) to /home/kbuilder/tensorflow_datasets/movielens/100k-ratings/0.1.0...
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/movielens/100k-ratings/0.1.0.incompleteN2R8B5/movielens-train.tfrecord
Dataset movielens downloaded and prepared to /home/kbuilder/tensorflow_datasets/movielens/100k-ratings/0.1.0. Subsequent calls will reuse this data.
Downloading and preparing dataset movielens/100k-movies/0.1.0 (download: 4.70 MiB, generated: 150.35 KiB, total: 4.84 MiB) to /home/kbuilder/tensorflow_datasets/movielens/100k-movies/0.1.0...
Shuffling and writing examples to /home/kbuilder/tensorflow_datasets/movielens/100k-movies/0.1.0.incompleteH88HCK/movielens-train.tfrecord
Dataset movielens downloaded and prepared to /home/kbuilder/tensorflow_datasets/movielens/100k-movies/0.1.0. Subsequent calls will reuse this data.

評価データセットは、映画ID、ユーザーID、割り当てられた評価、タイムスタンプ、映画情報、およびユーザー情報の辞書を返します。

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'}

映画データセットには、映画ID、映画タイトル、およびそれが属するジャンルに関するデータが含まれています。ジャンルは整数ラベルでエンコードされていることに注意してください。

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)'}

この例では、評価データに焦点を当てます。他のチュートリアルでは、映画情報データを使用してモデルの品質を向上させる方法についても説明します。

データセットには、 user_idフィールドとmovie_titleフィールドのみが保持されuser_id

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

モデルを適合させて評価するには、モデルをトレーニングと評価のセットに分割する必要があります。産業用レコメンダーシステムでは、これは時間によって行われる可能性が最も高くなります。$ T $までのデータは、$ T $以降の相互作用を予測するために使用されます。

ただし、この簡単な例では、ランダム分割を使用して、評価の80%をトレインセットに入れ、20%をテストセットに入れてみましょう。

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)

また、データに存在する一意のユーザーIDと映画のタイトルを把握しましょう。

これは重要です。なぜなら、カテゴリの特徴の生の値をモデルの埋め込みベクトルにマッピングできる必要があるからです。これを行うには、生の特徴値を連続した範囲の整数にマップする語彙が必要です。これにより、埋め込みテーブルで対応する埋め込みを検索できます。

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)

モデルの実装

モデルのアーキテクチャを選択することは、モデリングの重要な部分です。

2タワーの検索モデルを構築しているため、各タワーを個別に構築してから、それらを組み合わせて最終モデルにすることができます。

クエリタワー

クエリタワーから始めましょう。

最初のステップは、クエリと候補表現の次元を決定することです。

embedding_dimension = 32

値が高いほど、より正確なモデルに対応しますが、適合が遅くなり、過剰適合しやすくなります。

2つ目は、モデル自体を定義することです。ここでは、Keras前処理レイヤーを使用して、最初にユーザーIDを整数に変換し、次にそれらをEmbeddingレイヤーを介してユーザー埋め込みに変換します。以前に計算した一意のユーザーIDのリストを語彙として使用することに注意してください。

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

このような単純なモデルは、古典的な行列因数分解アプローチに正確に対応しています。この単純なモデルのtf.keras.Modelサブクラスを定義するのはやり過ぎかもしれませんが、最後にembedding_dimension全体の出力を返す限り、標準のKerasコンポーネントを使用して任意の複雑なモデルに簡単に拡張できます。

候補タワー

候補タワーでも同じことができます。

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

指標

トレーニングデータには、ポジティブ(ユーザー、映画)のペアがあります。モデルがどれほど優れているかを理解するには、モデルがこのペアに対して計算するアフィニティスコアを、他のすべての可能な候補のスコアと比較する必要があります。正のペアのスコアが他のすべての候補のスコアよりも高い場合、モデル非常に正確です。

これを行うには、 tfrs.metrics.FactorizedTopKメトリックを使用できます。メトリックには、1つの必須の引数があります。それは、評価の暗黙のネガとして使用される候補のデータセットです。

私たちの場合、それはmoviesデータセットであり、映画モデルを介して埋め込みに変換されます。

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

損失

次の要素は、モデルのトレーニングに使用される損失です。 TFRSには、これを簡単にするためのいくつかの損失レイヤーとタスクがあります。

この例では、 Retrievalタスクオブジェクトを使用します。これは、損失関数とメトリック計算をバンドルする便利なラッパーです。

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

タスク自体は、クエリと候補の埋め込みを引数として受け取り、計算された損失を返すKerasレイヤーです。これを使用して、モデルのトレーニングループを実装します。

フルモデル

これで、すべてを1つのモデルにまとめることができます。 TFRSは、ベースモデルクラス(公開しtfrs.models.Model buldingモデルを合理化):私たちが行う必要があるのは、中にコンポーネントを設定することです__init__メソッド、および実装compute_loss方法を、生の機能に取って、損失の値を返します。

次に、基本モデルが、モデルに適合する適切なトレーニングループの作成を処理します。

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)

tfrs.Model基本クラスは単純に便利なクラスです。同じメソッドを使用してトレーニングとテストの両方の損失を計算できます。

内部的には、それはまだプレーンなKerasモデルです。あなたは、から継承して同じ機能を実現できtf.keras.Modelとオーバーライドtrain_steptest_step (参照機能をガイド詳細を):

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

ただし、これらのチュートリアルでは、 tfrs.Model基本クラスを使用して、モデリングに重点を置き、定型文の一部を抽象化することに固執しています。

フィッティングと評価

モデルを定義した後、標準のKerasフィッティングおよび評価ルーチンを使用してモデルをフィッティングおよび評価できます。

まず、モデルをインスタンス化します。

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

次に、トレーニングデータと評価データをシャッフル、バッチ処理、およびキャッシュします。

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

次に、モデルをトレーニングします。

model.fit(cached_train, epochs=3)
Epoch 1/3
WARNING:tensorflow:The dtype of the source tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32

WARNING:tensorflow:The dtype of the source tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32

WARNING:tensorflow:Gradients do not exist for variables ['counter:0'] when minimizing the loss.

WARNING:tensorflow:Gradients do not exist for variables ['counter:0'] when minimizing the loss.

WARNING:tensorflow:The dtype of the source tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32

WARNING:tensorflow:The dtype of the source tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32

WARNING:tensorflow:Gradients do not exist for variables ['counter:0'] when minimizing the loss.

WARNING:tensorflow:Gradients do not exist for variables ['counter:0'] when minimizing the loss.

10/10 [==============================] - 2s 238ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0011 - factorized_top_k/top_5_categorical_accuracy: 0.0090 - factorized_top_k/top_10_categorical_accuracy: 0.0190 - factorized_top_k/top_50_categorical_accuracy: 0.0961 - factorized_top_k/top_100_categorical_accuracy: 0.1735 - loss: 69885.1072 - regularization_loss: 0.0000e+00 - total_loss: 69885.1072
Epoch 2/3
10/10 [==============================] - 2s 224ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0028 - factorized_top_k/top_5_categorical_accuracy: 0.0187 - factorized_top_k/top_10_categorical_accuracy: 0.0374 - factorized_top_k/top_50_categorical_accuracy: 0.1686 - factorized_top_k/top_100_categorical_accuracy: 0.2919 - loss: 67523.3707 - regularization_loss: 0.0000e+00 - total_loss: 67523.3707
Epoch 3/3
10/10 [==============================] - 2s 219ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0035 - factorized_top_k/top_5_categorical_accuracy: 0.0222 - factorized_top_k/top_10_categorical_accuracy: 0.0457 - factorized_top_k/top_50_categorical_accuracy: 0.1877 - factorized_top_k/top_100_categorical_accuracy: 0.3158 - loss: 66302.9609 - regularization_loss: 0.0000e+00 - total_loss: 66302.9609

<tensorflow.python.keras.callbacks.History at 0x7f04c679ca20>

モデルがトレーニングするにつれて、損失は減少し、上位k個の検索メトリックのセットが更新されます。これらは、真陽性が候補セット全体から取得された上位k個のアイテムにあるかどうかを示します。たとえば、上位5つのカテゴリ精度メトリック0.2は、平均して、20%の確率で上位5つの取得済みアイテムに真陽性があることを示しています。

この例では、トレーニング中および評価中にメトリックを評価することに注意してください。候補セットが大きい場合、これは非常に遅くなる可能性があるため、トレーニングではメトリック計算をオフにし、評価でのみ実行するのが賢明な場合があります。

最後に、テストセットでモデルを評価できます。

model.evaluate(cached_test, return_dict=True)
5/5 [==============================] - 1s 118ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0010 - factorized_top_k/top_5_categorical_accuracy: 0.0097 - factorized_top_k/top_10_categorical_accuracy: 0.0226 - factorized_top_k/top_50_categorical_accuracy: 0.1244 - factorized_top_k/top_100_categorical_accuracy: 0.2327 - loss: 31079.0628 - regularization_loss: 0.0000e+00 - total_loss: 31079.0628

{'factorized_top_k/top_1_categorical_accuracy': 0.0010000000474974513,
 'factorized_top_k/top_5_categorical_accuracy': 0.009650000371038914,
 'factorized_top_k/top_10_categorical_accuracy': 0.022600000724196434,
 'factorized_top_k/top_50_categorical_accuracy': 0.12439999729394913,
 'factorized_top_k/top_100_categorical_accuracy': 0.23270000517368317,
 'loss': 28244.76953125,
 'regularization_loss': 0,
 'total_loss': 28244.76953125}

テストセットのパフォーマンスは、トレーニングのパフォーマンスよりもはるかに劣ります。これは2つの要因によるものです。

  1. 私たちのモデルは、それを記憶できるという理由だけで、それが見たデータに対してより良いパフォーマンスを発揮する可能性があります。この過剰適合現象は、モデルに多くのパラメーターがある場合に特に強くなります。これは、モデルの正則化と、モデルが見えないデータに一般化するのに役立つユーザーおよびムービー機能の使用によって仲介できます。
  2. このモデルは、ユーザーがすでに視聴した映画の一部を再推奨しています。これらの既知のポジティブな時計は、トップKの推奨事項からテスト映画を混雑させる可能性があります。

2番目の現象は、以前に見た映画をテストの推奨事項から除外することで対処できます。このアプローチは、レコメンダーシステムの文献では比較的一般的ですが、これらのチュートリアルでは従いません。過去の時計を推奨しないことが重要な場合は、適切に指定されたモデルが過去のユーザー履歴とコンテキスト情報からこの動作を自動的に学習することを期待する必要があります。さらに、同じアイテムを複数回推奨することが適切な場合がよくあります(たとえば、常緑のTVシリーズまたは定期的に購入するアイテム)。

予測をする

モデルができたので、予測できるようにしたいと思います。これを行うには、 tfrs.layers.factorized_top_k.BruteForceレイヤーを使用できます。

# 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(movies.batch(100).map(model.movie_model), movies)

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

もちろん、 BruteForceレイヤーは遅すぎて、多くの候補を含むモデルを提供できません。次のセクションでは、近似検索インデックスを使用してこれを高速化する方法を示します。

モデルサービング

モデルがトレーニングされたら、それをデプロイする方法が必要です。

2タワー検索モデルでは、サービングには2つのコンポーネントがあります。

  • サービングクエリモデル、クエリの機能を取り入れてクエリ埋め込みに変換し、
  • サービング候補モデル。これは、ほとんどの場合、クエリモデルによって生成されたクエリに応答して候補の高速近似ルックアップを可能にする近似最近傍(ANN)インデックスの形式を取ります。

TFRSでは、両方のコンポーネントを1つのエクスポート可能なモデルにパッケージ化して、生のユーザーIDを取得し、そのユーザーのトップ映画のタイトルを返すモデルを提供できます。これは、モデルをSavedModel形式にエクスポートすることでSavedModelます。これにより、 SavedModelを使用してサービスを提供できます。

このようなモデルをデプロイするには、上記で作成したBruteForceレイヤーをエクスポートするだけです。

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

  # Save the index.
  index.save(path)

  # Load it back; can also be done in TensorFlow Serving.
  loaded = tf.keras.models.load_model(path)

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

  print(f"Recommendations: {titles[0][:3]}")
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

INFO:tensorflow:Assets written to: /tmp/tmp6r6itle7/model/assets

INFO:tensorflow:Assets written to: /tmp/tmp6r6itle7/model/assets

WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.

WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.

Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

予測を高速化するために、近似検索インデックスをエクスポートすることもできます。これにより、数千万の候補者のセットからの推奨事項を効率的に表示することが可能になります。

そのために、 scannパッケージを使用できます。これはTFRSのオプションの依存関係であり、このチュートリアルの最初に!pip install -q scann呼び出して個別に!pip install -q scann

インストールしたら、TFRSScaNN ScaNN使用できます。

scann_index = tfrs.layers.factorized_top_k.ScaNN(model.user_model)
scann_index.index(movies.batch(100).map(model.movie_model), movies)
<tensorflow_recommenders.layers.factorized_top_k.ScaNN at 0x7f04c6617dd8>

このレイヤーはおおよそのルックアップを実行します。これにより、取得の精度がわずかに低下しますが、大きな候補セットでは桁違いに高速になります。

# Get recommendations.
_, titles = scann_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)']

提供のためにエクスポートするのは、 BruteForceレイヤーをエクスポートするのとBruteForce簡単です。

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

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

  # Load it back; can also be done in TensorFlow Serving.
  loaded = tf.keras.models.load_model(path)

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

  print(f"Recommendations: {titles[0][:3]}")
INFO:tensorflow:Assets written to: /tmp/tmpduzk4yez/model/assets

INFO:tensorflow:Assets written to: /tmp/tmpduzk4yez/model/assets

WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.

WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.

Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

高速近似検索モデルの使用と調整の詳細については、効率的なサービングチュートリアルをご覧ください。

次のステップ

これで検索チュートリアルは終了です。

ここに示されている内容を拡張するには、以下を参照してください。

  1. マルチタスクモデルの学習:評価とクリックを共同で最適化します。
  2. 映画のメタデータの使用:コールドスタートを軽減するためのより複雑な映画モデルの構築。