Project Pacmann-Recommender System for Movie | by Aldi Hutagalung | Apr, 2024


Artikel ini ditulis sebagai bagian dari final project kelas Recommender System dari Pacmann AI/ML Engineering

Github : Link

1.Introduction
Recommender Sytem pada dasarnya adalah sistem/model/algoritma yang dimaksudkan untuk memberikan saran item yang relevan kepada pengguna. Saran tersebut bisa berupa film, musik, dan masih banyak lagi. Secara umum, jika menyangkut hubungan antara pengguna dan penyedia layanan atau pembeli dan e-commerce, rekomendasi akan sangat dibutuhkan. Pada akhirnya, rekomendasi yang layak akan menjadi win-win solution yang menguntungkan kedua belah pihak karena pengguna lebih royal karena mendapatkan apa yang mereka inginkan dan penyedia layanan memperoleh keuntungan lebih.

2. Obyektif
Amazon, salah satu perusahaan paling terkenal di seluruh dunia telah menghabiskan lebih dari 10 tahun dalam mengembangkan sistem pemberi rekomendasi untuk kebutuhan mereka. Hasilnya, tambahan penjualan sekitar 20% dari rekomendasi pada tahun 2002.

Selain itu, Netflix mengadakan kompetisi pada tahun 2009 untuk meningkatkan akurasi sistem rekomendasi filmnya sebesar 10%, yang menunjukkan betapa pentingnya sistem rekomendasi bagi kesuksesan sebuah perusahaan. Saat ini, 35 persen dari apa yang dibeli konsumen di Amazon dan lebih dari setengah dari apa yang mereka tonton di Netflix berasal dari sistem rekomendasi.

Recommender system dapat menghemat biaya transaksi dan meningkatkan pendapatan perusahaan. Atas dasar itulah, pada proyek ini penulis mencoba menyusun recommender system untuk pemilihan film.

3. Workflow
Workflow dari project recommender ini dimulai dengan pendefinisian problem/obyektif, lalu pengumpulan data yang dalam hal ini diperoleh dari kaggle, lalu dilakukan preprocessing untuk pembersihan data. Selanjutnya akan dilakukan pemodelan dan hyperparameter tuning untuk meningkatkan performa dari model.

4. Dataset
Dataset yang digunakan diperoleh dari kaggle, yang bersumber dari www.themoviedb.org. File-file ini berisi metadata untuk seluruh 45.000 film yang tercantum dalam Kumpulan Data Full MovieLens. Kumpulan data ini terdiri dari film-film yang dirilis pada atau sebelum Juli 2017. Data mencakup pemeran, kru, kata kunci plot, anggaran, pendapatan, poster, tanggal rilis, bahasa, perusahaan produksi, negara, jumlah suara TMDB, dan rata-rata pilihan.

Kumpulan data ini juga memiliki file yang berisi 26 juta rating dari 270.000 pengguna untuk seluruh 45.000 film. Ratingnya dalam skala 1–5 dan diperoleh dari situs resmi GroupLens.

Fitur di dalam dataset adalah sebagai berikut :

Exploratory Data Analysis

Film didominasi oleh kategori Non Adult, sedangkan kata yang cukup umum muncul pada review filem antara lain adalah find, life, love, family

Dari sisi genre, yang popular adalah drama (22,83%) diikuti oleh comedy (14,9%), sedangkan thriller, romance dan action berbagi proporsi yang kurang lebih setara.

5. Methods
Recommender System yang digunakan terdiri atas dua yaitu content based dan menggunakan Deep Learning.

Weighted Rating

Orang menonton film bukan hanya karena melihat rating yang baik dari suatu filem, tapi juga dampak hype atau ketenaran dari suatu film, sehingga popularitas perlu untuk dimasukkan ke dalam pertimbangan,

Secara arbitrary untuk project ini penulis memilih bobot 40% untuk weighted average dan 60% untuk popularitas dengna pertimbangan bahwa kecenderungan orang untuk tidak ingin melewatkan filem yang sedang viral walaupun review ataupun ratingnya buruk.

Dalam dataset ini terdapat berbagai informasi yang penting seperti genre, overview dll. Kita akan mengekstrak informasi tersebut dalam bag of words yang dikombinasikan dengan weighted average untuk mendapatkan similarity dari film.

Deep Learning
Tensorflow memiliki library TensorFlow Recommenders (TFRS) untuk membangun recommender system yang dibangun pada Keras dan memiliki learning curve yang landai. Arsitektur yang digunakan adalah adalah Dense Neural Network (DNN).

Ide dasar model pemeringkatan berbasis neural network adalah membuat penyematan untuk mewakili setiap pengguna dan film dengan memprediksi seberapa besar pengguna menggunakan rating pada setiap film. Berdasarkan ini kita bisa memprediksi film yang akan ditonton oleh pengguna berdasarkan rating yang terkait dengan data historis.

Ada dua part dari multi-task recommenders:
– Optimasi 1 atau 2 obyektif dengan 2 atau lebih losses
– Share variabel antar task dengan transfer learning

Dalam project ini ada 2 task yang dikerjakan recommender yaitu specialized rating task untuk memprediksi rating dan specialized retrieval task memprediksi film yang ditonton. Lalu akan dilakukan MultiTask untuk menggabungkan keduanya.

Untuk arsitektur awal dari Deep Learning digunakan Dense Layer dengan jumlah layer awal 256 dan fungsi aktivasi ReLu. Hyperparameter Tuning akan dilakukan terhadap 2 hal, yaitu pembobotan multitask dan arsitektur dari dense layer

class MovieModel(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 = 64

# 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["userId"])
# And pick out the movie features and pass them into the movie model.
movie_embeddings = self.movie_model(features["original_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("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 = MovieModel(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()

def predict_movie(user, top_n=3):
# 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_from_dataset(
tf.data.Dataset.zip((movies.batch(100), movies.batch(100).map(model.movie_model)))
)

# Get recommendations.
_, titles = index(tf.constant([str(user)]))

print('Top {} recommendations for user {}:\n'.format(top_n, user))
for i, title in enumerate(titles[0, :top_n].numpy()):
print('{}. {}'.format(i+1, title.decode("utf-8")))

def predict_rating(user, movie):
trained_movie_embeddings, trained_user_embeddings, predicted_rating = model({
"userId": np.array([str(user)]),
"original_title": np.array([movie])
})
print("Predicted rating for {}: {}".format(movie, predicted_rating.numpy()[0][0]))

Metrics
Untuk mengevaluasi specialized rating task digunakan metric RMSE seperti kasus regresi, sedangkan untuk specialized retrieval task digunakan metric akurasi. Selain itu juga digunakan metrics dari FactorizedTopK yang melakukan asssesment akurasi dari kandidat top-k teratas. TFRS memberikan retrieval task yang menggabungkan loss function dan komputasi metrik untuk mempercepat evaluasi

# Get meta data for predicted movie
index = tfrs.layers.factorized_top_k.BruteForce(model.user_model)
# recommends movies out of the entire movies dataset.
index.index_from_dataset(
tf.data.Dataset.zip((movies.batch(100), movies.batch(100).map(model.movie_model)))
)

# Get recommendations.
_, titles = index(tf.constant(['123']))
pred_movies = pd.DataFrame({'original_title': [i.decode('utf-8') for i in titles[0,:5].numpy()]})

pred_df = pred_movies.merge(ratings_df[['original_title', 'genres', 'overview']], on='original_title', how='left')
pred_df = pred_df[~pred_df['original_title'].duplicated()]
pred_df.reset_index(drop=True, inplace=True)
pred_df.index = np.arange(1, len(pred_df)+1)

pred_df

6. Experiments/Results/Discussion
Hasil dari Content Base Recommender, model dapat merekomendasikan film dengan kesamaan yang mendekati, misal dalam contoh berikut untuk film Toy Story, model merekomendasikan film Toy Story 2 dan 3, serta finding nemo.

predict('Toy Story', similarity_weight=0.7, top_n=10)

Untuk Deep Learning Base Recommender, performa dari model untuk rating specialized task untuk RMSE cukup baik pada data train dan data set tapi tidak demikian halnya dengan akurasi.

model = MovieModel(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()

Retrieval top-100 accuracy: 0.003
Ranking RMSE: 1.080
Retrieval top-100 accuracy: 0.001
Ranking RMSE: 1.034

Selanjutnya untuk retrieval specialized task

model = MovieModel(rating_weight=0.0, retrieval_weight=1.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()

Retrieval top-100 accuracy: 0.477
Ranking RMSE: 3.827
Retrieval top-100 accuracy: 0.080
Ranking RMSE: 3.837

pada task ini dapat kita lihat bahwa akurasi meningkat jauh menjadi 0,478 pada train, sedangkan nilai RMSE meningkat (lebih buruk)dibandingkan rating specialized task. Namun pada data test nilai akurasi menurun jauh.

Selanjutnya untuk multi task dilakukan pengubahan bobot pada code di mana rating weight dan retrieval weight diset pada 1.0

model = MovieModel(rating_weight=1.0, retrieval_weight=1.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)

Retrieval top-100 accuracy: 0.478
Ranking RMSE: 1.194
Retrieval top-100 accuracy: 0.086
Ranking RMSE: 0.968

Hasilnya tidak terlalu berbeda dibandingkan dengan retrieval specilized task. Untuk mencari performa terbaik dilakukan hyperparameter tuning dengan 2 tipe tuning, yaitu terhadap proporsi bobot dari taks dan perubahan arsitektur dense layer berikut learning rate serta optimizer yang digunakan. Perubahan arsitektur meliputi perubahan jumlah layer, serta pergantian optimizer dari Ada ke Adam. Untuk learning rate digunakan exponential decay. Hasil dan konfigurasi dari hyperparameter tuning direkap dalam tabel berikut.

Akurasi terbaik terdapat pada Multitask dengan Hyperparameter tuning, namun akurasinya menurun jauh pada data test, demikian pula nilai RMSE. Jika kita bandingkan, maka performa model yang lebih baik ada pada Multitask tanpa hyperparameter tuning. Karena penurunan akurasi tidak sebesar pada Multitask dengan hyperparameter tuning, dan ada perbaikan nilai RMSE yang juga paling baik pada dataset jika dibandingkan yang lain.

Berikut adalah hasil prediksi dengan menggunakan model terbaik

predict_movie(123, 5)
Top 5 recommendations for user 123:

1. The Greatest Story Ever Told
2. Un long dimanche de fiançailles
3. Wolke 9
4. L'avventura
5. El otro lado de la cama

predict_rating(123, ' The Greatest Story Ever Told')
Predicted rating for  The Greatest Story Ever Told: 3.263742208480835
ratings_df[ratings_df['userId'] == '123']

7. Conclusion

  • Content Base Recommender dengan kombinasi rating dan cosine similarity dapat memberikan rekomendasi film yang memiliki kesamaan kepada pengguna
  • Deep Learning Based Recommender dengan Tensorflow menunjukkan akurasi yang baik untuk memprediksi rating yang diberikan user, namun akurasinya kurang untuk rekomendasi film.

8. Recommendation

  • Kebutuhan untuk personal recommender akan terus bertumbuh, TFRS dapat menjadi source yang penting untuk membangun sistem rekomendasi yang dapat meningkatkan user experience dan mendorong perkembangan bisnis. Namun demikian perlu upaya lain dalam bentuk hyperparameter tuning atau pemilihan fitur yang lebih tepat.
  • Menggunakan ScaNN (Scalable Nearest Neighbors) untuk mempercepat pencarian dan retrieval, dalam project ini tidak digunakan karena penulis menggunakan sistem operasi windows, sedangkan untuk saat ini ScaNN tidak tersedia untuk Windows.
  • Menggunakan alternatif model lain atau ensembel methods untuk recommender seperti K Neareast Neighbor juga dapat menjadi opsi, karena kerap kali tidak ada 1 model yang superior untuk semua kondisi/case.

References
1. TensorFlow Recommenders Documentation: https://www.tensorflow.org/recommenders
2. https://qymatix.de/en/recommendation-systems-nowadays/
3. https://medium.com/@jaayush12/streamlining-recommendation-systems-with-tensorflow-recommenders-tfrs-f77801d3f059
4. Pacmann AI https://pacmann.io/



Source link

Be the first to comment

Leave a Reply

Your email address will not be published.


*