बहु-कार्य अनुशंसाकर्ता

TensorFlow.org पर देखें Google Colab में चलाएं GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

में बुनियादी पुनर्प्राप्ति ट्यूटोरियल हम सकारात्मक बातचीत संकेतों के रूप में फिल्म देखता है का उपयोग कर एक पुनर्प्राप्ति प्रणाली का निर्माण किया।

हालांकि, कई अनुप्रयोगों में, फीडबैक के कई समृद्ध स्रोत हैं, जिन पर ध्यान दिया जाना चाहिए। उदाहरण के लिए, एक ई-कॉमर्स साइट उत्पाद पृष्ठों (प्रचुर मात्रा में, लेकिन अपेक्षाकृत कम सिग्नल), छवि क्लिक, कार्ट में जोड़ने, और अंत में, खरीदारियों के लिए उपयोगकर्ता विज़िट रिकॉर्ड कर सकती है। यह समीक्षा और रिटर्न जैसे खरीद के बाद के संकेतों को भी रिकॉर्ड कर सकता है।

फीडबैक के इन सभी विभिन्न रूपों को एकीकृत करना उन प्रणालियों के निर्माण के लिए महत्वपूर्ण है जिन्हें उपयोगकर्ता उपयोग करना पसंद करते हैं, और जो समग्र प्रदर्शन की कीमत पर किसी एक मीट्रिक के लिए अनुकूलित नहीं होते हैं।

इसके अलावा, कई कार्यों के लिए एक संयुक्त मॉडल का निर्माण कई कार्य-विशिष्ट मॉडल बनाने की तुलना में बेहतर परिणाम दे सकता है। यह विशेष रूप से सच है जहां कुछ डेटा प्रचुर मात्रा में है (उदाहरण के लिए, क्लिक), और कुछ डेटा विरल है (खरीदारी, रिटर्न, मैन्युअल समीक्षा)। उन स्थितियों में, एक संयुक्त मॉडल के रूप में जाना जाता है एक घटना के माध्यम से प्रचुर मात्रा में काम से सीखा निरूपण का उपयोग करना विरल काम पर अपने पूर्वानुमानों को बेहतर बनाने में सक्षम हो सकता हस्तांतरण सीखने । उदाहरण के लिए, इस पत्र से पता चलता है कि एक मॉडल विरल उपयोगकर्ता सर्वेक्षण से स्पष्ट उपयोगकर्ता रेटिंग भविष्यवाणी काफी हद तक एक सहायक कार्य प्रचुर मात्रा में क्लिक लॉग डेटा का उपयोग करता है जोड़कर सुधार किया जा सकता।

इस ट्यूटोरियल में, हम Movielens के लिए एक बहुउद्देश्यीय अनुशंसाकर्ता का निर्माण करने जा रहे हैं, जिसमें निहित (मूवी घड़ियों) और स्पष्ट संकेतों (रेटिंग) दोनों का उपयोग किया जाएगा।

आयात

आइए पहले अपने आयात को रास्ते से हटा दें।

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

डेटासेट तैयार करना

हम Movielens 100K डेटासेट का उपयोग करने जा रहे हैं।

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

# Select the basic features.
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"])

और शब्दावली बनाने और डेटा को एक ट्रेन और एक परीक्षण सेट में विभाजित करने के लिए हमारी तैयारी दोहराएं:

# Randomly shuffle data and split between train and 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)

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

एक बहु-कार्य मॉडल

बहु-कार्य अनुशंसाकर्ताओं के दो महत्वपूर्ण भाग हैं:

  1. वे दो या दो से अधिक उद्देश्यों के लिए अनुकूलन करते हैं, और इसलिए दो या अधिक नुकसान होते हैं।
  2. वे कार्यों के बीच चर साझा करते हैं, जिससे स्थानांतरण सीखने की अनुमति मिलती है।

इस ट्यूटोरियल में, हम अपने मॉडल को पहले की तरह परिभाषित करेंगे, लेकिन एक कार्य करने के बजाय, हमारे पास दो कार्य होंगे: एक जो रेटिंग की भविष्यवाणी करता है, और दूसरा जो मूवी देखने की भविष्यवाणी करता है।

उपयोगकर्ता और मूवी मॉडल पहले की तरह हैं:

user_model = tf.keras.Sequential([
  tf.keras.layers.StringLookup(
      vocabulary=unique_user_ids, mask_token=None),
  # We add 1 to account for the unknown token.
  tf.keras.layers.Embedding(len(unique_user_ids) + 1, embedding_dimension)
])

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

हालाँकि, अब हमारे पास दो कार्य होंगे। पहला रेटिंग कार्य है:

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

इसका लक्ष्य रेटिंग का यथासंभव सटीक अनुमान लगाना है।

दूसरा पुनर्प्राप्ति कार्य है:

tfrs.tasks.Retrieval(
    metrics=tfrs.metrics.FactorizedTopK(
        candidates=movies.batch(128)
    )
)

पहले की तरह, इस टास्क का लक्ष्य यह अनुमान लगाना है कि उपयोगकर्ता कौन सी फिल्में देखेगा या नहीं देखेगा।

एक साथ रखते हुए

हम इसे एक मॉडल वर्ग में एक साथ रखते हैं।

यहां नया घटक यह है कि - चूंकि हमारे पास दो कार्य और दो नुकसान हैं - हमें यह तय करने की आवश्यकता है कि प्रत्येक नुकसान कितना महत्वपूर्ण है। हम प्रत्येक नुकसान को वजन देकर और इन वजनों को हाइपरपैरामीटर मानकर ऐसा कर सकते हैं। यदि हम रेटिंग कार्य के लिए एक बड़ा नुकसान भार निर्दिष्ट करते हैं, तो हमारा मॉडल रेटिंग की भविष्यवाणी पर ध्यान केंद्रित करने जा रहा है (लेकिन फिर भी पुनर्प्राप्ति कार्य से कुछ जानकारी का उपयोग करें); यदि हम पुनर्प्राप्ति कार्य के लिए एक बड़ा नुकसान भार निर्दिष्ट करते हैं, तो यह इसके बजाय पुनर्प्राप्ति पर ध्यान केंद्रित करेगा।

class MovielensModel(tfrs.models.Model):

  def __init__(self, rating_weight: float, retrieval_weight: float) -> None:
    # We take the loss weights in the constructor: this allows us to instantiate
    # several model objects with different loss weights.

    super().__init__()

    embedding_dimension = 32

    # User and movie models.
    self.movie_model: tf.keras.layers.Layer = 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)
    ])
    self.user_model: tf.keras.layers.Layer = 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)
    ])

    # A small model to take in user and movie embeddings and predict ratings.
    # We can make this as complicated as we want as long as we output a scalar
    # as our prediction.
    self.rating_model = tf.keras.Sequential([
        tf.keras.layers.Dense(256, activation="relu"),
        tf.keras.layers.Dense(128, activation="relu"),
        tf.keras.layers.Dense(1),
    ])

    # The tasks.
    self.rating_task: tf.keras.layers.Layer = tfrs.tasks.Ranking(
        loss=tf.keras.losses.MeanSquaredError(),
        metrics=[tf.keras.metrics.RootMeanSquaredError()],
    )
    self.retrieval_task: tf.keras.layers.Layer = tfrs.tasks.Retrieval(
        metrics=tfrs.metrics.FactorizedTopK(
            candidates=movies.batch(128).map(self.movie_model)
        )
    )

    # The loss weights.
    self.rating_weight = rating_weight
    self.retrieval_weight = retrieval_weight

  def call(self, features: Dict[Text, tf.Tensor]) -> 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.
    movie_embeddings = self.movie_model(features["movie_title"])

    return (
        user_embeddings,
        movie_embeddings,
        # We apply the multi-layered rating model to a concatentation of
        # user and movie embeddings.
        self.rating_model(
            tf.concat([user_embeddings, movie_embeddings], axis=1)
        ),
    )

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

    ratings = features.pop("user_rating")

    user_embeddings, movie_embeddings, rating_predictions = self(features)

    # We compute the loss for each task.
    rating_loss = self.rating_task(
        labels=ratings,
        predictions=rating_predictions,
    )
    retrieval_loss = self.retrieval_task(user_embeddings, movie_embeddings)

    # And combine them using the loss weights.
    return (self.rating_weight * rating_loss
            + self.retrieval_weight * retrieval_loss)

रेटिंग-विशेष मॉडल

हमारे द्वारा असाइन किए गए वज़न के आधार पर, मॉडल कार्यों के एक अलग संतुलन को एन्कोड करेगा। आइए एक ऐसे मॉडल से शुरू करें जो केवल रेटिंग पर विचार करता है।

model = MovielensModel(rating_weight=1.0, retrieval_weight=0.0)
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))
cached_train = train.shuffle(100_000).batch(8192).cache()
cached_test = test.batch(4096).cache()
model.fit(cached_train, epochs=3)
metrics = model.evaluate(cached_test, return_dict=True)

print(f"Retrieval top-100 accuracy: {metrics['factorized_top_k/top_100_categorical_accuracy']:.3f}.")
print(f"Ranking RMSE: {metrics['root_mean_squared_error']:.3f}.")
Epoch 1/3
10/10 [==============================] - 7s 331ms/step - root_mean_squared_error: 2.0903 - factorized_top_k/top_1_categorical_accuracy: 2.7500e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0024 - factorized_top_k/top_10_categorical_accuracy: 0.0054 - factorized_top_k/top_50_categorical_accuracy: 0.0294 - factorized_top_k/top_100_categorical_accuracy: 0.0589 - loss: 4.0315 - regularization_loss: 0.0000e+00 - total_loss: 4.0315
Epoch 2/3
10/10 [==============================] - 3s 321ms/step - root_mean_squared_error: 1.1531 - factorized_top_k/top_1_categorical_accuracy: 1.8750e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0024 - factorized_top_k/top_10_categorical_accuracy: 0.0054 - factorized_top_k/top_50_categorical_accuracy: 0.0297 - factorized_top_k/top_100_categorical_accuracy: 0.0591 - loss: 1.3189 - regularization_loss: 0.0000e+00 - total_loss: 1.3189
Epoch 3/3
10/10 [==============================] - 3s 316ms/step - root_mean_squared_error: 1.1198 - factorized_top_k/top_1_categorical_accuracy: 1.6250e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0025 - factorized_top_k/top_10_categorical_accuracy: 0.0055 - factorized_top_k/top_50_categorical_accuracy: 0.0300 - factorized_top_k/top_100_categorical_accuracy: 0.0597 - loss: 1.2479 - regularization_loss: 0.0000e+00 - total_loss: 1.2479
5/5 [==============================] - 3s 194ms/step - root_mean_squared_error: 1.1130 - factorized_top_k/top_1_categorical_accuracy: 4.5000e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0028 - factorized_top_k/top_10_categorical_accuracy: 0.0052 - factorized_top_k/top_50_categorical_accuracy: 0.0295 - factorized_top_k/top_100_categorical_accuracy: 0.0597 - loss: 1.2336 - regularization_loss: 0.0000e+00 - total_loss: 1.2336
Retrieval top-100 accuracy: 0.060.
Ranking RMSE: 1.113.

मॉडल रेटिंग की भविष्यवाणी करने पर ठीक है (लगभग 1.11 के आरएमएसई के साथ), लेकिन यह अनुमान लगाने में खराब प्रदर्शन करता है कि कौन सी फिल्में देखी जाएंगी या नहीं: 100 पर इसकी सटीकता केवल घड़ियों की भविष्यवाणी करने के लिए प्रशिक्षित मॉडल की तुलना में लगभग 4 गुना खराब है।

पुनर्प्राप्ति-विशिष्ट मॉडल

आइए अब एक ऐसे मॉडल का प्रयास करें जो केवल पुनर्प्राप्ति पर केंद्रित हो।

model = MovielensModel(rating_weight=0.0, retrieval_weight=1.0)
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))
model.fit(cached_train, epochs=3)
metrics = model.evaluate(cached_test, return_dict=True)

print(f"Retrieval top-100 accuracy: {metrics['factorized_top_k/top_100_categorical_accuracy']:.3f}.")
print(f"Ranking RMSE: {metrics['root_mean_squared_error']:.3f}.")
Epoch 1/3
10/10 [==============================] - 4s 313ms/step - root_mean_squared_error: 3.7238 - factorized_top_k/top_1_categorical_accuracy: 7.5000e-05 - factorized_top_k/top_5_categorical_accuracy: 0.0014 - factorized_top_k/top_10_categorical_accuracy: 0.0041 - factorized_top_k/top_50_categorical_accuracy: 0.0473 - factorized_top_k/top_100_categorical_accuracy: 0.1135 - loss: 69818.0298 - regularization_loss: 0.0000e+00 - total_loss: 69818.0298
Epoch 2/3
10/10 [==============================] - 3s 326ms/step - root_mean_squared_error: 3.7495 - factorized_top_k/top_1_categorical_accuracy: 0.0011 - factorized_top_k/top_5_categorical_accuracy: 0.0116 - factorized_top_k/top_10_categorical_accuracy: 0.0268 - factorized_top_k/top_50_categorical_accuracy: 0.1425 - factorized_top_k/top_100_categorical_accuracy: 0.2658 - loss: 67473.2884 - regularization_loss: 0.0000e+00 - total_loss: 67473.2884
Epoch 3/3
10/10 [==============================] - 3s 314ms/step - root_mean_squared_error: 3.7648 - factorized_top_k/top_1_categorical_accuracy: 0.0014 - factorized_top_k/top_5_categorical_accuracy: 0.0180 - factorized_top_k/top_10_categorical_accuracy: 0.0388 - factorized_top_k/top_50_categorical_accuracy: 0.1773 - factorized_top_k/top_100_categorical_accuracy: 0.3050 - loss: 66329.2543 - regularization_loss: 0.0000e+00 - total_loss: 66329.2543
5/5 [==============================] - 1s 193ms/step - root_mean_squared_error: 3.7730 - factorized_top_k/top_1_categorical_accuracy: 0.0012 - factorized_top_k/top_5_categorical_accuracy: 0.0097 - factorized_top_k/top_10_categorical_accuracy: 0.0218 - factorized_top_k/top_50_categorical_accuracy: 0.1253 - factorized_top_k/top_100_categorical_accuracy: 0.2352 - loss: 31085.0697 - regularization_loss: 0.0000e+00 - total_loss: 31085.0697
Retrieval top-100 accuracy: 0.235.
Ranking RMSE: 3.773.

हमें विपरीत परिणाम मिलता है: एक मॉडल जो पुनर्प्राप्ति पर अच्छा करता है, लेकिन रेटिंग की भविष्यवाणी करने में खराब है।

संयुक्त मॉडल

आइए अब एक मॉडल को प्रशिक्षित करें जो दोनों कार्यों को सकारात्मक भार प्रदान करता है।

model = MovielensModel(rating_weight=1.0, retrieval_weight=1.0)
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))
model.fit(cached_train, epochs=3)
metrics = model.evaluate(cached_test, return_dict=True)

print(f"Retrieval top-100 accuracy: {metrics['factorized_top_k/top_100_categorical_accuracy']:.3f}.")
print(f"Ranking RMSE: {metrics['root_mean_squared_error']:.3f}.")
Epoch 1/3
10/10 [==============================] - 4s 299ms/step - root_mean_squared_error: 2.5007 - factorized_top_k/top_1_categorical_accuracy: 3.7500e-05 - factorized_top_k/top_5_categorical_accuracy: 0.0014 - factorized_top_k/top_10_categorical_accuracy: 0.0043 - factorized_top_k/top_50_categorical_accuracy: 0.0450 - factorized_top_k/top_100_categorical_accuracy: 0.1102 - loss: 69811.8274 - regularization_loss: 0.0000e+00 - total_loss: 69811.8274
Epoch 2/3
10/10 [==============================] - 3s 312ms/step - root_mean_squared_error: 1.2097 - factorized_top_k/top_1_categorical_accuracy: 9.8750e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0110 - factorized_top_k/top_10_categorical_accuracy: 0.0255 - factorized_top_k/top_50_categorical_accuracy: 0.1385 - factorized_top_k/top_100_categorical_accuracy: 0.2605 - loss: 67481.2713 - regularization_loss: 0.0000e+00 - total_loss: 67481.2713
Epoch 3/3
10/10 [==============================] - 3s 305ms/step - root_mean_squared_error: 1.1200 - factorized_top_k/top_1_categorical_accuracy: 0.0011 - factorized_top_k/top_5_categorical_accuracy: 0.0175 - factorized_top_k/top_10_categorical_accuracy: 0.0380 - factorized_top_k/top_50_categorical_accuracy: 0.1758 - factorized_top_k/top_100_categorical_accuracy: 0.3040 - loss: 66297.9318 - regularization_loss: 0.0000e+00 - total_loss: 66297.9318
5/5 [==============================] - 1s 187ms/step - root_mean_squared_error: 1.1312 - factorized_top_k/top_1_categorical_accuracy: 9.5000e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0083 - factorized_top_k/top_10_categorical_accuracy: 0.0220 - factorized_top_k/top_50_categorical_accuracy: 0.1248 - factorized_top_k/top_100_categorical_accuracy: 0.2347 - loss: 31062.8206 - regularization_loss: 0.0000e+00 - total_loss: 31062.8206
Retrieval top-100 accuracy: 0.235.
Ranking RMSE: 1.131.

परिणाम एक मॉडल है जो प्रत्येक विशेष मॉडल के रूप में दोनों कार्यों पर मोटे तौर पर प्रदर्शन करता है।

भविष्यवाणी करना

हम प्रशिक्षित उपयोगकर्ता और मूवी एम्बेडिंग के साथ-साथ अनुमानित रेटिंग प्राप्त करने के लिए प्रशिक्षित मल्टीटास्क मॉडल का उपयोग कर सकते हैं:

trained_movie_embeddings, trained_user_embeddings, predicted_rating = model({
      "user_id": np.array(["42"]),
      "movie_title": np.array(["Dances with Wolves (1990)"])
  })
print("Predicted rating:")
print(predicted_rating)
Predicted rating:
tf.Tensor([[3.4021819]], shape=(1, 1), dtype=float32)

हालांकि यहां के परिणाम इस मामले में एक संयुक्त मॉडल से स्पष्ट सटीकता लाभ नहीं दिखाते हैं, बहु-कार्य सीखना सामान्य रूप से एक अत्यंत उपयोगी उपकरण है। हम बेहतर परिणामों की उम्मीद कर सकते हैं जब हम डेटा-प्रचुर मात्रा में कार्य (जैसे क्लिक) से ज्ञान को निकट से संबंधित डेटा-विरल कार्य (जैसे खरीद) में स्थानांतरित कर सकते हैं।