Listesel 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

Gelen temel sıralama öğretici , biz kullanıcı / film çiftleri için derecelendirme tahmin edebilecek bir model eğitimli. Model, tahmin edilen derecelendirmelerin ortalama kare hatasını en aza indirecek şekilde eğitildi.

Ancak, modelin tahminlerini tek tek filmler üzerinde optimize etmek, sıralama modellerini eğitmek için mutlaka en iyi yöntem değildir. Skorları büyük bir doğrulukla tahmin etmek için sıralama modellerine ihtiyacımız yok. Bunun yerine, modelin kullanıcının tercih sıralamasıyla eşleşen sıralı bir öğe listesi oluşturma becerisine daha fazla önem veriyoruz.

Modelin tahminlerini tek tek sorgu/öğe çiftleri üzerinde optimize etmek yerine, modelin bir bütün olarak liste sıralamasını optimize edebiliriz. Bu yöntem sıralaması listwise denir.

Bu eğitimde, liste bazında sıralama modelleri oluşturmak için TensorFlow Önerilerini kullanacağız. Bunu yapmak için, biz sağladığı kayıpları ve ölçümleri sıralamasında kullanımı yapacak TensorFlow Sıralaması odaklanır, bir TensorFlow paketi rütbesine öğrenme .

ön elemeler

TensorFlow Sıralaması sizin çalışma ortamında mevcut değilse, aşağıdakileri kullanarak yükleyebilirsiniz pip :

pip install -q tensorflow-recommenders
pip install -q --upgrade tensorflow-datasets
pip install -q tensorflow-ranking

Daha sonra gerekli tüm paketleri içe aktarabiliriz:

import pprint

import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/pkg_resources/__init__.py:119: PkgResourcesDeprecationWarning: 0.18ubuntu0.18.04.1 is an invalid version and will not be supported in a future release
  PkgResourcesDeprecationWarning,
import tensorflow_ranking as tfr
import tensorflow_recommenders as tfrs
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_addons/utils/ensure_tf_install.py:67: UserWarning: Tensorflow Addons supports using Python ops for all Tensorflow versions above or equal to 2.4.0 and strictly below 2.7.0 (nightly versions are not supported). 
 The versions of TensorFlow you are currently using is 2.7.0 and is not supported. 
Some things might work, some things might not.
If you were to encounter a bug, do not file an issue.
If you want to make sure you're using a tested and supported configuration, either change the TensorFlow version or the TensorFlow Addons's version. 
You can find the compatibility matrix in TensorFlow Addon's readme:
https://github.com/tensorflow/addons
  UserWarning,

MovieLens 100K veri setini kullanmaya devam edeceğiz. Daha önce olduğu gibi, bu eğitim için veri kümelerini yüklüyoruz ve yalnızca kullanıcı kimliği, film başlığı ve kullanıcı derecelendirmesi özelliklerini koruyoruz. Ayrıca kelime dağarcığımızı hazırlamak için biraz temizlik yapıyoruz.

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

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

unique_movie_titles = np.unique(np.concatenate(list(movies.batch(1000))))
unique_user_ids = np.unique(np.concatenate(list(ratings.batch(1_000).map(
    lambda x: x["user_id"]))))

Veri ön işleme

Ancak MovieLens veri setini doğrudan liste optimizasyonu için kullanamayız. Liste bazında optimizasyon gerçekleştirmek için, her kullanıcının derecelendirdiği filmlerin listesine erişmemiz gerekir, ancak MovieLens 100K veri kümesindeki her örnek yalnızca tek bir filmin derecelendirmesini içerir.

Bunu aşmak için veri kümesini, her örneğin bir kullanıcı kimliği ve o kullanıcı tarafından derecelendirilen filmlerin bir listesini içerecek şekilde dönüştürüyoruz. Listedeki bazı filmler diğerlerinden daha üst sıralarda yer alacak; modelimizin amacı bu sıralamaya uygun tahminler yapmak olacaktır.

Bunu yapmak için, kullandığımız tfrs.examples.movielens.movielens_to_listwise yardımcı işlevi. MovieLens 100K veri kümesini alır ve yukarıda tartışıldığı gibi liste örneklerini içeren bir veri kümesi oluşturur. Uygulama detayları bulunabilir kaynak kodu .

tf.random.set_seed(42)

# Split between train and tests sets, as before.
shuffled = ratings.shuffle(100_000, seed=42, reshuffle_each_iteration=False)

train = shuffled.take(80_000)
test = shuffled.skip(80_000).take(20_000)

# We sample 50 lists for each user for the training data. For each list we
# sample 5 movies from the movies the user rated.
train = tfrs.examples.movielens.sample_listwise(
    train,
    num_list_per_user=50,
    num_examples_per_list=5,
    seed=42
)
test = tfrs.examples.movielens.sample_listwise(
    test,
    num_list_per_user=1,
    num_examples_per_list=5,
    seed=42
)

Eğitim verilerinden bir örnek inceleyebiliriz. Örnek, bir kullanıcı kimliğini, 10 film kimliğinin bir listesini ve bunların kullanıcı tarafından derecelendirilmesini içerir.

for example in train.take(1):
  pprint.pprint(example)
{'movie_title': <tf.Tensor: shape=(5,), dtype=string, numpy=
array([b'Postman, The (1997)', b'Liar Liar (1997)', b'Contact (1997)',
       b'Welcome To Sarajevo (1997)',
       b'I Know What You Did Last Summer (1997)'], dtype=object)>,
 'user_id': <tf.Tensor: shape=(), dtype=string, numpy=b'681'>,
 'user_rating': <tf.Tensor: shape=(5,), dtype=float32, numpy=array([4., 5., 1., 4., 1.], dtype=float32)>}

Model tanımı

Aynı modeli üç farklı kayıpla eğiteceğiz:

  • ortalama kare hatası,
  • ikili menteşe kaybı ve
  • listwise ListMLE kaybı.

Bu üç kayıp noktasal, ikili ve listesel optimizasyona karşılık gelir.

Kullandığımız modeli değerlendirmek normalize kümülatif kazanç (NDCG) indirimli . NDCG, her adayın gerçek derecelendirmesinin ağırlıklı bir toplamını alarak tahmin edilen bir sıralamayı ölçer. Modele göre alt sıralarda yer alan filmlerin reytingleri daha fazla indirimli olacaktır. Sonuç olarak, yüksek puan alan filmleri en üstte sıralayan iyi bir model, yüksek bir NDCG sonucuna sahip olacaktır. Bu metrik, her adayın sıralanmış konumunu dikkate aldığından, liste bazında bir metriktir.

class RankingModel(tfrs.Model):

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

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

    # Compute embeddings for movies.
    self.movie_embeddings = tf.keras.Sequential([
      tf.keras.layers.StringLookup(
        vocabulary=unique_movie_titles),
      tf.keras.layers.Embedding(len(unique_movie_titles) + 2, embedding_dimension)
    ])

    # Compute predictions.
    self.score_model = 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)
    ])

    self.task = tfrs.tasks.Ranking(
      loss=loss,
      metrics=[
        tfr.keras.metrics.NDCGMetric(name="ndcg_metric"),
        tf.keras.metrics.RootMeanSquaredError()
      ]
    )

  def call(self, features):
    # We first convert the id features into embeddings.
    # User embeddings are a [batch_size, embedding_dim] tensor.
    user_embeddings = self.user_embeddings(features["user_id"])

    # Movie embeddings are a [batch_size, num_movies_in_list, embedding_dim]
    # tensor.
    movie_embeddings = self.movie_embeddings(features["movie_title"])

    # We want to concatenate user embeddings with movie emebeddings to pass
    # them into the ranking model. To do so, we need to reshape the user
    # embeddings to match the shape of movie embeddings.
    list_length = features["movie_title"].shape[1]
    user_embedding_repeated = tf.repeat(
        tf.expand_dims(user_embeddings, 1), [list_length], axis=1)

    # Once reshaped, we concatenate and pass into the dense layers to generate
    # predictions.
    concatenated_embeddings = tf.concat(
        [user_embedding_repeated, movie_embeddings], 2)

    return self.score_model(concatenated_embeddings)

  def compute_loss(self, features, training=False):
    labels = features.pop("user_rating")

    scores = self(features)

    return self.task(
        labels=labels,
        predictions=tf.squeeze(scores, axis=-1),
    )

Modelleri eğitmek

Artık üç modelin her birini eğitebiliriz.

epochs = 30

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

Ortalama kare hata modeli

Bu model modele çok benzer temel sıralama öğretici . Modeli, gerçek derecelendirmeler ile tahmin edilen derecelendirmeler arasındaki ortalama karesel hatayı en aza indirecek şekilde eğitiriz. Bu nedenle bu kayıp her film için ayrı ayrı hesaplanır ve eğitim noktasaldır.

mse_model = RankingModel(tf.keras.losses.MeanSquaredError())
mse_model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))
mse_model.fit(cached_train, epochs=epochs, verbose=False)
<keras.callbacks.History at 0x7f64791a5d10>

İkili menteşe kaybı modeli

Model, ikili menteşe kaybını en aza indirerek, yüksek dereceli bir öğe ile düşük dereceli bir öğe için modelin tahminleri arasındaki farkı maksimize etmeye çalışır: bu fark ne kadar büyükse, model kaybı o kadar düşük olur. Bununla birlikte, fark yeterince büyük olduğunda, kayıp sıfır olur ve modelin bu özel çifti daha fazla optimize etmesini durdurur ve yanlış sıralanmış diğer çiftlere odaklanmasına izin verir.

Bu kayıp, tek tek filmler için değil, daha çok film çiftleri için hesaplanır. Dolayısıyla bu kaybı kullanan eğitim ikilidir.

hinge_model = RankingModel(tfr.keras.losses.PairwiseHingeLoss())
hinge_model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))
hinge_model.fit(cached_train, epochs=epochs, verbose=False)
<keras.callbacks.History at 0x7f647914f190>

Listesel model

ListMLE TensorFlow Sıralaması ifade den kaybı maksimum olabilirlik tahmini sıralar. ListMLE kaybını hesaplamak için, önce optimum bir sıralama oluşturmak için kullanıcı derecelendirmelerini kullanırız. Daha sonra, tahmin edilen puanları kullanarak, her adayın optimal sıralamada altındaki herhangi bir öğe tarafından üst sıralarda yer alma olasılığını hesaplıyoruz. Model, yüksek puan alan adayların düşük puan alan adaylar tarafından sıralanmamasını sağlamak için bu olasılığı en aza indirmeye çalışır. Sen kağıt bölümünde 2.2'de ListMLE ayrıntıları hakkında daha fazla bilgi edinebilirsiniz pozisyonu farkında ListMLE: Aşamaları Öğrenme Süreci .

Olasılık, optimal sıralamada bir adaya ve onun altındaki tüm adaylara göre hesaplandığından, kaybın ikili değil, liste şeklinde olduğunu unutmayın. Bu nedenle eğitim, liste optimizasyonunu kullanır.

listwise_model = RankingModel(tfr.keras.losses.ListMLELoss())
listwise_model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))
listwise_model.fit(cached_train, epochs=epochs, verbose=False)
<keras.callbacks.History at 0x7f647b35f350>

modelleri karşılaştırma

mse_model_result = mse_model.evaluate(cached_test, return_dict=True)
print("NDCG of the MSE Model: {:.4f}".format(mse_model_result["ndcg_metric"]))
1/1 [==============================] - 0s 405ms/step - ndcg_metric: 0.9053 - root_mean_squared_error: 0.9671 - loss: 0.9354 - regularization_loss: 0.0000e+00 - total_loss: 0.9354
NDCG of the MSE Model: 0.9053
hinge_model_result = hinge_model.evaluate(cached_test, return_dict=True)
print("NDCG of the pairwise hinge loss model: {:.4f}".format(hinge_model_result["ndcg_metric"]))
1/1 [==============================] - 0s 457ms/step - ndcg_metric: 0.9058 - root_mean_squared_error: 3.8330 - loss: 1.0180 - regularization_loss: 0.0000e+00 - total_loss: 1.0180
NDCG of the pairwise hinge loss model: 0.9058
listwise_model_result = listwise_model.evaluate(cached_test, return_dict=True)
print("NDCG of the ListMLE model: {:.4f}".format(listwise_model_result["ndcg_metric"]))
1/1 [==============================] - 0s 432ms/step - ndcg_metric: 0.9071 - root_mean_squared_error: 2.7224 - loss: 4.5401 - regularization_loss: 0.0000e+00 - total_loss: 4.5401
NDCG of the ListMLE model: 0.9071

Üç modelden ListMLE kullanılarak eğitilen model en yüksek NDCG metriğine sahiptir. Bu sonuç, sıralama modellerini eğitmek için liste bazında optimizasyonun nasıl kullanılabileceğini ve noktasal veya ikili biçimde optimize edilmiş modellerden daha iyi performans gösteren modeller üretebileceğini gösterir.