Film önerme: sıralama

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Not defterini indir

Gerçek dünya tavsiye sistemleri genellikle iki aşamadan oluşur:

  1. Geri alma aşaması, olası tüm adaylar arasından yüzlerce adaydan oluşan bir başlangıç ​​kümesinin seçilmesinden sorumludur. Bu modelin temel amacı, kullanıcının ilgilenmediği tüm adayları verimli bir şekilde ayıklamaktır. Alma modeli milyonlarca adayla ilgilenebileceğinden, hesaplama açısından verimli olmalıdır.
  2. Sıralama aşaması, erişim modelinin çıktılarını alır ve mümkün olan en iyi avuç tavsiyeyi seçmek için bunları ince ayarlar. Görevi, kullanıcının ilgilenebileceği öğe kümesini olası adayların kısa bir listesine daraltmaktır.

İkinci aşama olan sıralamaya odaklanacağız. Eğer alma aşamasında ilgilenen varsa, bizim de bir göz alma öğretici.

Bu eğitimde şunları yapacağız:

  1. Verilerimizi alın ve bir eğitim ve test setine bölün.
  2. Bir sıralama modeli uygulayın.
  3. Sığdırın ve değerlendirin.

ithalat

Önce ithalatımızı aradan çıkaralım.

pip install -q tensorflow-recommenders
pip install -q --upgrade tensorflow-datasets
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

Veri kümesinin hazırlanması

Biz aynı verileri kullanacağız alma öğretici. Bu sefer reytingleri de tutacağız: bunlar tahmin etmeye çalıştığımız hedefler.

ratings = tfds.load("movielens/100k-ratings", split="train")

ratings = ratings.map(lambda x: {
    "movie_title": x["movie_title"],
    "user_id": x["user_id"],
    "user_rating": x["user_rating"]
})
2021-10-02 11:04:25.388548: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected

Daha önce olduğu gibi, derecelendirmelerin %80'ini tren setine ve %20'sini test setine koyarak verileri böleceğiz.

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)

Verilerde bulunan benzersiz kullanıcı kimliklerini ve film adlarını da bulalım.

Bu önemlidir çünkü kategorik özelliklerimizin ham değerlerini modellerimizde vektörleri gömmek için eşleştirebilmemiz gerekir. Bunu yapmak için, ham özellik değerini bitişik bir aralıktaki bir tamsayıya eşleyen bir kelime dağarcığına ihtiyacımız var: bu, gömme tablolarımızda karşılık gelen gömmelere bakmamızı sağlar.

movie_titles = ratings.batch(1_000_000).map(lambda x: x["movie_title"])
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)))

Bir modelin uygulanması

Mimari

Sıralama modelleri, alma modelleriyle aynı verimlilik kısıtlamalarıyla karşı karşıya değildir ve bu nedenle, mimari seçimlerimizde biraz daha özgürlüğe sahibiz.

Birden çok yığılmış yoğun katmandan oluşan bir model, görevleri sıralamak için nispeten yaygın bir mimaridir. Aşağıdaki gibi uygulayabiliriz:

class RankingModel(tf.keras.Model):

  def __init__(self):
    super().__init__()
    embedding_dimension = 32

    # Compute embeddings for users.
    self.user_embeddings = tf.keras.Sequential([
      tf.keras.layers.StringLookup(
        vocabulary=unique_user_ids, mask_token=None),
      tf.keras.layers.Embedding(len(unique_user_ids) + 1, embedding_dimension)
    ])

    # Compute embeddings for movies.
    self.movie_embeddings = 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)
    ])

    # Compute predictions.
    self.ratings = tf.keras.Sequential([
      # Learn multiple dense layers.
      tf.keras.layers.Dense(256, activation="relu"),
      tf.keras.layers.Dense(64, activation="relu"),
      # Make rating predictions in the final layer.
      tf.keras.layers.Dense(1)
  ])

  def call(self, inputs):

    user_id, movie_title = inputs

    user_embedding = self.user_embeddings(user_id)
    movie_embedding = self.movie_embeddings(movie_title)

    return self.ratings(tf.concat([user_embedding, movie_embedding], axis=1))

Bu model, kullanıcı kimliklerini ve film adlarını alır ve tahmini bir derecelendirme verir:

RankingModel()((["42"], ["One Flew Over the Cuckoo's Nest (1975)"]))
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ['42']
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ['42']
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ["One Flew Over the Cuckoo's Nest (1975)"]
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ["One Flew Over the Cuckoo's Nest (1975)"]
Consider rewriting this model with the Functional API.
<tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.03740937]], dtype=float32)>

Kayıp ve metrikler

Bir sonraki bileşen, modelimizi eğitmek için kullanılan kayıptır. TFRS'nin bunu kolaylaştıracak birkaç kayıp katmanı ve görevi vardır.

Bu durumda, biz faydalanmak edeceğiz Ranking birlikte kayıp fonksiyonu ve metrik hesaplama demetleri bir kolaylık sarıcı: Görev nesnesi.

Biz bunu birlikte kullanacağız MeanSquaredError derecelendirme tahmin etmek amacıyla Keras kaybı.

task = tfrs.tasks.Ranking(
  loss = tf.keras.losses.MeanSquaredError(),
  metrics=[tf.keras.metrics.RootMeanSquaredError()]
)

Görevin kendisi, doğru ve tahmin edilen argümanları alan ve hesaplanan kaybı döndüren bir Keras katmanıdır. Bunu, modelin eğitim döngüsünü uygulamak için kullanacağız.

tam model

Şimdi hepsini bir modelde birleştirebiliriz. TFRS bir temel modeli sınıfını (açığa tfrs.models.Model bulding modeller kolaylaştırır): Yapmamız gereken tüm bileşenleri kurmaktır __init__ yöntemi ve uygulama compute_loss ham özellikleri alıp bir kayıp değerini döndüren yöntem .

Temel model daha sonra modelimize uyacak uygun eğitim döngüsünü oluşturmaya özen gösterecektir.

class MovielensModel(tfrs.models.Model):

  def __init__(self):
    super().__init__()
    self.ranking_model: tf.keras.Model = RankingModel()
    self.task: tf.keras.layers.Layer = tfrs.tasks.Ranking(
      loss = tf.keras.losses.MeanSquaredError(),
      metrics=[tf.keras.metrics.RootMeanSquaredError()]
    )

  def call(self, features: Dict[str, tf.Tensor]) -> tf.Tensor:
    return self.ranking_model(
        (features["user_id"], features["movie_title"]))

  def compute_loss(self, features: Dict[Text, tf.Tensor], training=False) -> tf.Tensor:
    labels = features.pop("user_rating")

    rating_predictions = self(features)

    # The task computes the loss and the metrics.
    return self.task(labels=labels, predictions=rating_predictions)

Takma ve değerlendirme

Modeli tanımladıktan sonra, modeli sığdırmak ve değerlendirmek için standart Keras uydurma ve değerlendirme rutinlerini kullanabiliriz.

Önce modeli somutlaştıralım.

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

Ardından eğitim ve değerlendirme verilerini karıştırın, gruplayın ve önbelleğe alın.

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

Ardından modeli eğitin:

model.fit(cached_train, epochs=3)
Epoch 1/3
10/10 [==============================] - 2s 26ms/step - root_mean_squared_error: 2.1718 - loss: 4.3303 - regularization_loss: 0.0000e+00 - total_loss: 4.3303
Epoch 2/3
10/10 [==============================] - 0s 8ms/step - root_mean_squared_error: 1.1227 - loss: 1.2602 - regularization_loss: 0.0000e+00 - total_loss: 1.2602
Epoch 3/3
10/10 [==============================] - 0s 8ms/step - root_mean_squared_error: 1.1162 - loss: 1.2456 - regularization_loss: 0.0000e+00 - total_loss: 1.2456
<keras.callbacks.History at 0x7f28389eaa90>

Model ilerledikçe, kayıp düşüyor ve RMSE metriği gelişiyor.

Son olarak test setinde modelimizi değerlendirebiliriz:

model.evaluate(cached_test, return_dict=True)
5/5 [==============================] - 2s 14ms/step - root_mean_squared_error: 1.1108 - loss: 1.2287 - regularization_loss: 0.0000e+00 - total_loss: 1.2287
{'root_mean_squared_error': 1.1108061075210571,
 'loss': 1.2062578201293945,
 'regularization_loss': 0,
 'total_loss': 1.2062578201293945}

RMSE metriği ne kadar düşükse, modelimiz derecelendirmeleri tahmin etmede o kadar doğru olur.

Sıralama modelini test etme

Şimdi, bir dizi film için tahminleri hesaplayarak sıralama modelini test edebilir ve ardından bu filmleri tahminlere göre sıralayabiliriz:

test_ratings = {}
test_movie_titles = ["M*A*S*H (1970)", "Dances with Wolves (1990)", "Speed (1994)"]
for movie_title in test_movie_titles:
  test_ratings[movie_title] = model({
      "user_id": np.array(["42"]),
      "movie_title": np.array([movie_title])
  })

print("Ratings:")
for title, score in sorted(test_ratings.items(), key=lambda x: x[1], reverse=True):
  print(f"{title}: {score}")
Ratings:
M*A*S*H (1970): [[3.584712]]
Dances with Wolves (1990): [[3.551556]]
Speed (1994): [[3.5215874]]

Sunum için dışa aktarılıyor

Model, hizmet için kolayca dışa aktarılabilir:

tf.saved_model.save(model, "export")
2021-10-02 11:04:38.235611: 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 ranking_1_layer_call_and_return_conditional_losses, ranking_1_layer_call_fn, ranking_1_layer_call_fn, ranking_1_layer_call_and_return_conditional_losses, ranking_1_layer_call_and_return_conditional_losses while saving (showing 5 of 5). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: export/assets
INFO:tensorflow:Assets written to: export/assets

Şimdi onu geri yükleyebilir ve tahminler yapabiliriz:

loaded = tf.saved_model.load("export")

loaded({"user_id": np.array(["42"]), "movie_title": ["Speed (1994)"]}).numpy()
array([[3.5215874]], dtype=float32)

Sonraki adımlar

Yukarıdaki model bize bir sıralama sistemi oluşturmaya yönelik iyi bir başlangıç ​​sağlıyor.

Tabii ki pratik bir sıralama sistemi yapmak çok daha fazla çaba gerektiriyor.

Çoğu durumda, bir sıralama modeli, yalnızca kullanıcı ve aday tanımlayıcıları yerine daha fazla özellik kullanılarak önemli ölçüde geliştirilebilir. Bunun nasıl yapılacağını görmek için, bir göz tarafında özellikleri öğretici.

Optimize etmeye değer hedeflerin dikkatli bir şekilde anlaşılması da gereklidir. Birden çok hedefi optimize eden bir tavsiye eden oluşturmaya başlamak için, bizim de bir göz çoklu görev öğretici.