মাল্টি-টাস্ক সুপারিশকারীরা

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 এর RMSE সহ), কিন্তু কোন সিনেমা দেখা হবে বা দেখা হবে না তা ভবিষ্যদ্বাণী করতে খারাপভাবে পারফর্ম করে: 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)

যদিও এখানে ফলাফলগুলি এই ক্ষেত্রে যৌথ মডেল থেকে স্পষ্ট নির্ভুলতার সুবিধা দেখায় না, মাল্টি-টাস্ক লার্নিং সাধারণভাবে একটি অত্যন্ত দরকারী টুল। আমরা যখন ডেটা-প্রচুর টাস্ক (যেমন ক্লিক) থেকে একটি ঘনিষ্ঠভাবে সম্পর্কিত ডেটা-স্পার্স টাস্কে (যেমন কেনাকাটা) জ্ঞান স্থানান্তর করতে পারি তখন আমরা আরও ভাল ফলাফল আশা করতে পারি।