التوصية بالأفلام: الاسترجاع

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

غالبًا ما تتكون أنظمة التوصية في العالم الحقيقي من مرحلتين:

  1. مرحلة الاسترجاع مسؤولة عن اختيار مجموعة أولية من مئات المرشحين من بين جميع المرشحين المحتملين. الهدف الرئيسي من هذا النموذج هو التخلص بكفاءة من جميع المرشحين الذين لا يهتم بهم المستخدم. ولأن نموذج الاسترجاع قد يتعامل مع ملايين المرشحين ، يجب أن يكون فعالاً من الناحية الحسابية.
  2. تأخذ مرحلة الترتيب مخرجات نموذج الاسترجاع وتضبطها لتحديد أفضل مجموعة ممكنة من التوصيات. وتتمثل مهمتها في تضييق نطاق مجموعة العناصر التي قد يهتم بها المستخدم إلى قائمة مختصرة بالمرشحين المحتملين.

في هذا البرنامج التعليمي ، سنركز على المرحلة الأولى ، الاسترجاع. إذا كنت مهتما في المرحلة الترتيب، إلقاء نظرة على موقعنا على الترتيب التعليمي.

غالبًا ما تتكون نماذج الاسترجاع من نموذجين فرعيين:

  1. نموذج استعلام يحسب تمثيل الاستعلام (عادة متجه تضمين أبعاد ثابتة) باستخدام ميزات الاستعلام.
  2. نموذج مرشح يحسب تمثيل المرشح (متجه متساوي الحجم) باستخدام ميزات المرشح

يتم بعد ذلك مضاعفة مخرجات النموذجين معًا لإعطاء درجة تقارب بين استعلام ومرشح ، مع درجات أعلى تعبر عن تطابق أفضل بين المرشح والاستعلام.

في هذا البرنامج التعليمي ، سنقوم ببناء وتدريب مثل هذا النموذج المكون من برجين باستخدام مجموعة بيانات Movielens.

نحن سوف نذهب الئ:

  1. احصل على بياناتنا وقسمها إلى مجموعة تدريب واختبار.
  2. تطبيق نموذج استرجاع.
  3. تناسبها وتقييمها.
  4. قم بتصديره لتقديم خدمة فعالة عن طريق إنشاء مؤشر تقريبي لأقرب جيران (ANN).

مجموعة البيانات

وMovielens بيانات هو مجموعة بيانات الكلاسيكية من GroupLens بحث مجموعة في جامعة مينيسوتا. يحتوي على مجموعة من التصنيفات الممنوحة للأفلام من قبل مجموعة من المستخدمين ، وهو بمثابة العمود الفقري لأبحاث نظام التوصية.

يمكن معالجة البيانات بطريقتين:

  1. يمكن تفسيره على أنه يعبر عن الأفلام التي شاهدها المستخدمون (وصنفوها) والتي لم يشاهدوها. هذا شكل من أشكال التعليقات الضمنية ، حيث تخبرنا ساعات المستخدمين بالأشياء التي يفضلون رؤيتها والتي لا يفضلون رؤيتها.
  2. يمكن أيضًا أن يُنظر إليه على أنه يعبر عن مدى إعجاب المستخدمين بالأفلام التي شاهدوها. هذا شكل من أشكال التعليقات الصريحة: نظرًا لأن المستخدم شاهد فيلمًا ، يمكننا تحديد مدى إعجابه تقريبًا من خلال النظر في التقييم الذي قدموه.

في هذا البرنامج التعليمي ، نركز على نظام استرجاع: نموذج يتنبأ بمجموعة من الأفلام من الكتالوج يحتمل أن يشاهدها المستخدم. في كثير من الأحيان ، تكون البيانات الضمنية أكثر فائدة هنا ، ولذا سوف نتعامل مع Movielens كنظام ضمني. هذا يعني أن كل فيلم شاهده المستخدم هو مثال إيجابي ، وكل فيلم لم يشاهده هو مثال سلبي ضمني.

الواردات

دعنا أولاً نخرج وارداتنا من الطريق.

pip install -q tensorflow-recommenders
pip install -q --upgrade tensorflow-datasets
pip install -q scann
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 من Tensorflow مجموعات البيانات . تحميل movielens/100k_ratings تعطي tf.data.Dataset الكائن الذي يحتوي على البيانات التقييمات وتحميل movielens/100k_movies العوائد على tf.data.Dataset الكائن الذي يحتوي فقط على البيانات الأفلام.

ملاحظة أنه منذ MovieLens بيانات ليس لديه مسبقا الانقسامات، وجميع البيانات تحت train الانقسام.

# Ratings data.
ratings = tfds.load("movielens/100k-ratings", split="train")
# Features of all the available movies.
movies = tfds.load("movielens/100k-movies", split="train")
2021-10-02 11:05:34.633747: E tensorflow/stream_executor/cuda/cuda_driver.cc:271] failed call to cuInit: CUDA_ERROR_NO_DEVICE: no CUDA-capable device is detected

تعرض مجموعة بيانات التصنيفات قاموسًا لمعرف الفيلم ومعرف المستخدم والتصنيف المعين والطابع الزمني ومعلومات الفيلم ومعلومات المستخدم:

for x in ratings.take(1).as_numpy_iterator():
  pprint.pprint(x)
{'bucketized_user_age': 45.0,
 'movie_genres': array([7]),
 'movie_id': b'357',
 'movie_title': b"One Flew Over the Cuckoo's Nest (1975)",
 'raw_user_age': 46.0,
 'timestamp': 879024327,
 'user_gender': True,
 'user_id': b'138',
 'user_occupation_label': 4,
 'user_occupation_text': b'doctor',
 'user_rating': 4.0,
 'user_zip_code': b'53211'}
2021-10-02 11:05:35.718641: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

تحتوي مجموعة بيانات الأفلام على معرّف الفيلم وعنوان الفيلم وبيانات حول الأنواع التي تنتمي إليها. لاحظ أن الأنواع يتم ترميزها باستخدام تسميات عدد صحيح.

for x in movies.take(1).as_numpy_iterator():
  pprint.pprint(x)
{'movie_genres': array([4]),
 'movie_id': b'1681',
 'movie_title': b'You So Crazy (1994)'}
2021-10-02 11:05:35.893098: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

في هذا المثال ، سنركز على بيانات التصنيفات. تستكشف البرامج التعليمية الأخرى كيفية استخدام بيانات معلومات الفيلم لتحسين جودة النموذج.

نحن تبقي فقط على user_id ، و movie_title الحقول في ورقة العمل.

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

لتلائم النموذج وتقييمه ، نحتاج إلى تقسيمه إلى مجموعة تدريب وتقييم. في نظام المزكي الصناعي، على الأرجح أن يتم ذلك عن طريق الوقت: البيانات حتى وقت \(T\) ستستخدم للتنبؤ التفاعلات بعد \(T\).

ومع ذلك ، في هذا المثال البسيط ، دعنا نستخدم تقسيمًا عشوائيًا ، ونضع 80٪ من التصنيفات في مجموعة القطار ، و 20٪ في مجموعة الاختبار.

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

unique_movie_titles[:10]
array([b"'Til There Was You (1997)", b'1-900 (1994)',
       b'101 Dalmatians (1996)', b'12 Angry Men (1957)', b'187 (1997)',
       b'2 Days in the Valley (1996)',
       b'20,000 Leagues Under the Sea (1954)',
       b'2001: A Space Odyssey (1968)',
       b'3 Ninjas: High Noon At Mega Mountain (1998)',
       b'39 Steps, The (1935)'], dtype=object)

تنفيذ النموذج

يعد اختيار بنية نموذجنا جزءًا أساسيًا من النمذجة.

نظرًا لأننا نقوم ببناء نموذج استرجاع مكون من برجين ، فيمكننا بناء كل برج على حدة ثم دمجهما في النموذج النهائي.

برج الاستعلام

لنبدأ ببرج الاستعلام.

تتمثل الخطوة الأولى في تحديد بُعدية الاستعلام وتمثيلات المرشح:

embedding_dimension = 32

تتوافق القيم الأعلى مع النماذج التي قد تكون أكثر دقة ، ولكنها ستكون أيضًا أبطأ في الملاءمة وأكثر عرضة للتركيب.

والثاني هو تحديد النموذج نفسه. هنا، نحن ذاهبون إلى استخدام Keras تجهيزها طبقات لأول تحويل هويات المستخدمين إلى أعداد صحيحة، ومن ثم تحويل تلك إلى التضمينات المستخدم عن طريق Embedding طبقة. لاحظ أننا نستخدم قائمة معرفات المستخدم الفريدة التي قمنا بحسابها مسبقًا كمفردات:

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

نموذج بسيط مثل هذا يتوافق تماما مع الكلاسيكية إلى عوامل مصفوفة النهج. مع تحديد فئة فرعية من tf.keras.Model لهذا نموذج بسيط قد يكون مبالغة، فإننا يمكن أن تمتد بسهولة إلى نموذج معقد بشكل تعسفي باستخدام مكونات Keras القياسية، طالما نعود إلى 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.metrics.FactorizedTopK متري. يحتوي المقياس على حجة واحدة مطلوبة: مجموعة بيانات المرشحين التي يتم استخدامها كعناصر سلبية ضمنية للتقييم.

في حالتنا، وهذا هو movies بيانات، وتحويلها إلى التضمينات عبر نموذج فيلم لدينا:

metrics = tfrs.metrics.FactorizedTopK(
  candidates=movies.batch(128).map(movie_model)
)

خسارة

المكون التالي هو الخسارة المستخدمة لتدريب نموذجنا. يحتوي TFRS على العديد من طبقات ومهام الخسارة لتسهيل ذلك.

في هذه الحالة، فإننا سوف الاستفادة من Retrieval كائن مهمة: راحة المجمع أن حزم معا وظيفة الخسارة وحساب متري:

task = tfrs.tasks.Retrieval(
  metrics=metrics
)

المهمة نفسها عبارة عن طبقة Keras تأخذ الاستعلام والضمانات المرشحة كوسائط ، وتعيد الخسارة المحسوبة: سنستخدم ذلك لتنفيذ حلقة التدريب الخاصة بالنموذج.

النموذج الكامل

يمكننا الآن وضع كل ذلك معًا في نموذج. معدلات الخصوبة الكلية الكشف عن فئة الطراز الأساسي ( tfrs.models.Model ) الذي يبسط نماذج بناء: كل ما عليك القيام به هو لإعداد المكونات في __init__ الطريقة، وتنفيذ compute_loss طريقة، مع الأخذ في ملامح الخام وإرجاع قيمة الخسارة .

سيهتم النموذج الأساسي بعد ذلك بإنشاء حلقة التدريب المناسبة لتناسب نموذجنا.

class MovielensModel(tfrs.Model):

  def __init__(self, user_model, movie_model):
    super().__init__()
    self.movie_model: tf.keras.Model = movie_model
    self.user_model: tf.keras.Model = user_model
    self.task: tf.keras.layers.Layer = task

  def compute_loss(self, features: Dict[Text, tf.Tensor], training=False) -> 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,
    # getting embeddings back.
    positive_movie_embeddings = self.movie_model(features["movie_title"])

    # The task computes the loss and the metrics.
    return self.task(user_embeddings, positive_movie_embeddings)

و tfrs.Model الفئة الأساسية هي فئة ببساطة الراحة: فهو يسمح لنا لحساب كل من الخسائر التدريب والاختبار باستخدام نفس الأسلوب.

تحت الغطاء ، لا يزال نموذج Keras عاديًا. هل يمكن تحقيق نفس الأداء الوظيفي عن طريق وراثة من tf.keras.Model وتجاوز train_step و test_step وظائف (انظر دليل لمزيد من التفاصيل):

class NoBaseClassMovielensModel(tf.keras.Model):

  def __init__(self, user_model, movie_model):
    super().__init__()
    self.movie_model: tf.keras.Model = movie_model
    self.user_model: tf.keras.Model = user_model
    self.task: tf.keras.layers.Layer = task

  def train_step(self, features: Dict[Text, tf.Tensor]) -> tf.Tensor:

    # Set up a gradient tape to record gradients.
    with tf.GradientTape() as tape:

      # Loss computation.
      user_embeddings = self.user_model(features["user_id"])
      positive_movie_embeddings = self.movie_model(features["movie_title"])
      loss = self.task(user_embeddings, positive_movie_embeddings)

      # Handle regularization losses as well.
      regularization_loss = sum(self.losses)

      total_loss = loss + regularization_loss

    gradients = tape.gradient(total_loss, self.trainable_variables)
    self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))

    metrics = {metric.name: metric.result() for metric in self.metrics}
    metrics["loss"] = loss
    metrics["regularization_loss"] = regularization_loss
    metrics["total_loss"] = total_loss

    return metrics

  def test_step(self, features: Dict[Text, tf.Tensor]) -> tf.Tensor:

    # Loss computation.
    user_embeddings = self.user_model(features["user_id"])
    positive_movie_embeddings = self.movie_model(features["movie_title"])
    loss = self.task(user_embeddings, positive_movie_embeddings)

    # Handle regularization losses as well.
    regularization_loss = sum(self.losses)

    total_loss = loss + regularization_loss

    metrics = {metric.name: metric.result() for metric in self.metrics}
    metrics["loss"] = loss
    metrics["regularization_loss"] = regularization_loss
    metrics["total_loss"] = total_loss

    return metrics

في هذه الدروس، ومع ذلك، ونحن نتمسك باستخدام tfrs.Model الفئة الأساسية للحفاظ على تركيزنا على النمذجة ومجردة بعيدا بعض النمطي.

التركيب والتقييم

بعد تحديد النموذج ، يمكننا استخدام إجراءات تركيب وتقييم Keras القياسية لملاءمة النموذج وتقييمه.

لنبدأ أولاً بإنشاء مثيل للنموذج.

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

ثم قم بتبديل بيانات التدريب والتقييم وتجميعها وتخزينها مؤقتًا.

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

ثم قم بتدريب النموذج:

model.fit(cached_train, epochs=3)
Epoch 1/3
10/10 [==============================] - 6s 302ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0011 - factorized_top_k/top_5_categorical_accuracy: 0.0094 - factorized_top_k/top_10_categorical_accuracy: 0.0203 - factorized_top_k/top_50_categorical_accuracy: 0.1001 - factorized_top_k/top_100_categorical_accuracy: 0.1772 - loss: 69885.1129 - regularization_loss: 0.0000e+00 - total_loss: 69885.1129
Epoch 2/3
10/10 [==============================] - 3s 286ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0029 - factorized_top_k/top_5_categorical_accuracy: 0.0186 - factorized_top_k/top_10_categorical_accuracy: 0.0376 - factorized_top_k/top_50_categorical_accuracy: 0.1689 - factorized_top_k/top_100_categorical_accuracy: 0.2923 - loss: 67523.3707 - regularization_loss: 0.0000e+00 - total_loss: 67523.3707
Epoch 3/3
10/10 [==============================] - 3s 269ms/step - factorized_top_k/top_1_categorical_accuracy: 0.0036 - factorized_top_k/top_5_categorical_accuracy: 0.0224 - factorized_top_k/top_10_categorical_accuracy: 0.0459 - factorized_top_k/top_50_categorical_accuracy: 0.1880 - factorized_top_k/top_100_categorical_accuracy: 0.3162 - loss: 66302.9609 - regularization_loss: 0.0000e+00 - total_loss: 66302.9609
<keras.callbacks.History at 0x7f560e5ea090>

إذا كنت ترغب في مراقبة عملية التدريب مع TensorBoard، يمكنك إضافة رد TensorBoard إلى وظيفة تناسب () ومن ثم البدء باستخدام TensorBoard %tensorboard --logdir logs/fit . يرجى الرجوع إلى وثائق TensorBoard لمزيد من التفاصيل.

بينما يتدرب النموذج ، تتراجع الخسارة ويتم تحديث مجموعة من مقاييس الاسترجاع أعلى k. يخبرنا هذا ما إذا كان الإيجابي الحقيقي موجودًا في العناصر المسترجعة من أعلى k من المجموعة المرشحة بأكملها. على سبيل المثال ، سيخبرنا مقياس الدقة الفئوية الأعلى -5 البالغ 0.2 أنه ، في المتوسط ​​، يكون الإيجابي الحقيقي في أعلى 5 عناصر مستردة بنسبة 20٪ من الوقت.

لاحظ أنه في هذا المثال ، نقوم بتقييم المقاييس أثناء التدريب وكذلك التقييم. نظرًا لأن هذا يمكن أن يكون بطيئًا جدًا مع مجموعات كبيرة من المرشحين ، فقد يكون من الحكمة إيقاف حساب القياس في التدريب وتشغيله فقط في التقييم.

أخيرًا ، يمكننا تقييم نموذجنا على مجموعة الاختبار:

model.evaluate(cached_test, return_dict=True)
5/5 [==============================] - 2s 149ms/step - factorized_top_k/top_1_categorical_accuracy: 7.5000e-04 - factorized_top_k/top_5_categorical_accuracy: 0.0099 - factorized_top_k/top_10_categorical_accuracy: 0.0226 - factorized_top_k/top_50_categorical_accuracy: 0.1245 - factorized_top_k/top_100_categorical_accuracy: 0.2324 - loss: 31079.0635 - regularization_loss: 0.0000e+00 - total_loss: 31079.0635
{'factorized_top_k/top_1_categorical_accuracy': 0.000750000006519258,
 'factorized_top_k/top_5_categorical_accuracy': 0.009850000031292439,
 'factorized_top_k/top_10_categorical_accuracy': 0.02264999970793724,
 'factorized_top_k/top_50_categorical_accuracy': 0.12449999898672104,
 'factorized_top_k/top_100_categorical_accuracy': 0.23235000669956207,
 'loss': 28244.771484375,
 'regularization_loss': 0,
 'total_loss': 28244.771484375}

أداء مجموعة الاختبار أسوأ بكثير من أداء التدريب. هذا يرجع إلى عاملين:

  1. من المرجح أن يعمل نموذجنا بشكل أفضل على البيانات التي شاهدها ، وذلك ببساطة لأنه يمكنه حفظها. تكون ظاهرة التجاوز هذه قوية بشكل خاص عندما تحتوي النماذج على العديد من المعلمات. يمكن التوسط من خلال تنظيم النموذج واستخدام ميزات المستخدم والأفلام التي تساعد النموذج على التعميم بشكل أفضل على البيانات غير المرئية.
  2. يعيد النموذج التوصية ببعض الأفلام التي شاهدها المستخدمون بالفعل. يمكن لهذه الساعات الإيجابية المعروفة أن تزاحم أفلام الاختبار خارج أفضل توصيات K.

يمكن معالجة الظاهرة الثانية من خلال استبعاد الأفلام التي سبق مشاهدتها من توصيات الاختبار. هذا النهج شائع نسبيًا في منشورات أنظمة التوصية ، لكننا لا نتبعه في هذه البرامج التعليمية. إذا كان عدم التوصية بالساعات الماضية أمرًا مهمًا ، فيجب أن نتوقع نماذج محددة بشكل مناسب لتعلم هذا السلوك تلقائيًا من سجل المستخدم السابق والمعلومات السياقية. بالإضافة إلى ذلك ، غالبًا ما يكون من المناسب التوصية بنفس العنصر عدة مرات (على سبيل المثال ، مسلسل تلفزيوني دائم الخضرة أو عنصر يتم شراؤه بانتظام).

يتنبأ

الآن بعد أن أصبح لدينا نموذج ، نود أن نكون قادرين على عمل تنبؤات. يمكننا استخدام tfrs.layers.factorized_top_k.BruteForce طبقة للقيام بذلك.

# 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(["42"]))
print(f"Recommendations for user 42: {titles[0, :3]}")
Recommendations for user 42: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

بطبيعة الحال، فإن BruteForce طبقة ستكون بطيئة جدا لخدمة نموذجا مع العديد من المرشحين المحتملين. توضح الأقسام التالية كيفية تسريع ذلك باستخدام فهرس استرجاع تقريبي.

خدمة نموذجية

بعد تدريب النموذج ، نحتاج إلى طريقة لنشره.

في نموذج الاسترجاع المكون من برجين ، تتكون الخدمة من عنصرين:

  • نموذج استعلام عرض ، يأخذ ميزات الاستعلام ويحولها إلى تضمين استعلام ، و
  • نموذج مرشح يخدم. غالبًا ما يتخذ هذا شكل فهرس أقرب جيران (ANN) التقريبي والذي يسمح بالبحث التقريبي السريع عن المرشحين استجابةً لاستعلام تم إنتاجه بواسطة نموذج الاستعلام.

في TFRS ، يمكن تجميع كلا المكونين في نموذج واحد قابل للتصدير ، مما يمنحنا نموذجًا يأخذ معرف المستخدم الأولي ويعيد عناوين أفضل الأفلام لهذا المستخدم. ويتم ذلك عن طريق تصدير نموذج ل SavedModel الشكل، مما يجعل من الممكن لخدمة باستخدام TensorFlow خدمة .

لنشر نموذج من هذا القبيل، ونحن ببساطة تصدير BruteForce طبقة أنشأنا أعلاه:

# Export the query model.
with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, "model")

  # Save the index.
  tf.saved_model.save(index, path)

  # Load it back; can also be done in TensorFlow Serving.
  loaded = tf.saved_model.load(path)

  # Pass a user id in, get top predicted movie titles back.
  scores, titles = loaded(["42"])

  print(f"Recommendations: {titles[0][:3]}")
2021-10-02 11:05:54.109254: 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 query_with_exclusions while saving (showing 1 of 1). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: /tmp/tmp7otg6id7/model/assets
INFO:tensorflow:Assets written to: /tmp/tmp7otg6id7/model/assets
Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

يمكننا أيضًا تصدير فهرس استرجاع تقريبي لتسريع التنبؤات. هذا سيجعل من الممكن عرض التوصيات بكفاءة من مجموعات من عشرات الملايين من المرشحين.

للقيام بذلك، يمكننا استخدام scann الحزمة. هذا هو التبعية اختياري من معدلات الخصوبة الكلية، ونحن تثبيته بشكل منفصل في بداية هذا البرنامج التعليمي من خلال الدعوة !pip install -q scann .

وبمجرد تركيب يمكننا استخدام معدلات الخصوبة الكلية ScaNN طبقة:

scann_index = tfrs.layers.factorized_top_k.ScaNN(model.user_model)
scann_index.index_from_dataset(
  tf.data.Dataset.zip((movies.batch(100), movies.batch(100).map(model.movie_model)))
)
<tensorflow_recommenders.layers.factorized_top_k.ScaNN at 0x7f560caffc10>

وهذه الطبقة تؤدي عمليات البحث التقريبية: استرجاع هذا يجعل أقل بقليل دقيقة، ولكن أوامر من حجم أسرع على مجموعات مرشح كبيرة.

# Get recommendations.
_, titles = scann_index(tf.constant(["42"]))
print(f"Recommendations for user 42: {titles[0, :3]}")
Recommendations for user 42: [b'Sleepless in Seattle (1993)' b'Father of the Bride Part II (1995)'
 b'Hunchback of Notre Dame, The (1996)']

تصديره لخدمة سهلا كما هو تصدير BruteForce طبقة:

# Export the query model.
with tempfile.TemporaryDirectory() as tmp:
  path = os.path.join(tmp, "model")

  # Save the index.
  tf.saved_model.save(
      index,
      path,
      options=tf.saved_model.SaveOptions(namespace_whitelist=["Scann"])
  )

  # Load it back; can also be done in TensorFlow Serving.
  loaded = tf.saved_model.load(path)

  # Pass a user id in, get top predicted movie titles back.
  scores, titles = loaded(["42"])

  print(f"Recommendations: {titles[0][:3]}")
WARNING:absl:Found untraced functions such as query_with_exclusions while saving (showing 1 of 1). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: /tmp/tmp_rde8grm/model/assets
INFO:tensorflow:Assets written to: /tmp/tmp_rde8grm/model/assets
Recommendations: [b'Bridges of Madison County, The (1995)'
 b'Father of the Bride Part II (1995)' b'Rudy (1993)']

لمعرفة المزيد حول استخدام وضبط نماذج استرجاع التقريبية بسرعة، إلقاء نظرة على موقعنا على كفاءة خدمة البرنامج التعليمي.

توصية من عنصر إلى عنصر

في هذا النموذج ، أنشأنا نموذجًا لفيلم المستخدم. ومع ذلك ، بالنسبة لبعض التطبيقات (على سبيل المثال ، صفحات تفاصيل المنتج) من الشائع تنفيذ توصيات من عنصر إلى عنصر (على سبيل المثال ، فيلم إلى فيلم أو منتج إلى منتج).

تتبع نماذج التدريب مثل هذا النمط نفسه كما هو موضح في هذا البرنامج التعليمي ، ولكن مع بيانات تدريب مختلفة. هنا ، كان لدينا مستخدم وبرج فيلم ، واستخدمنا أزواج (مستخدم ، فيلم) لتدريبهم. في نموذج عنصر إلى عنصر ، سيكون لدينا برجان من العناصر (للاستعلام وعنصر المرشح) ، وندرب النموذج باستخدام أزواج (عنصر الاستعلام ، عنصر المرشح). يمكن إنشاء هذه من النقرات على صفحات تفاصيل المنتج.

الخطوات التالية

يختتم هذا البرنامج التعليمي الاسترجاع.

لتوسيع ما يتم تقديمه هنا ، ألق نظرة على:

  1. تعلم نماذج متعددة المهام: التحسين المشترك للتقييمات والنقرات.
  2. استخدام البيانات الوصفية للفيلم: بناء نموذج فيلم أكثر تعقيدًا للتخفيف من البداية الباردة.