לשמור את התאריך! קלט / פלט של Google חוזר 18-20 במאי הירשם עכשיו
דף זה תורגם על ידי Cloud Translation API.
Switch to English

המלצה על סרטים: דירוג

צפה ב- TensorFlow.org הפעל בגוגל קולאב צפה במקור ב- GitHub הורד מחברת

מערכות ממליצים בעולם האמיתי מורכבות לרוב משני שלבים:

  1. שלב האחזור אחראי לבחירת מערך ראשוני של מאות מועמדים מכל המועמדים האפשריים. המטרה העיקרית של מודל זה היא לחסל ביעילות את כל המועמדים שהמשתמש אינו מעוניין בהם. מכיוון שמודל השליפה עשוי להתמודד עם מיליוני מועמדים, עליו להיות יעיל מבחינה חישובית.
  2. שלב הדירוג לוקח את התפוקות של מודל האחזור ומכוון אותם בכדי לבחור את קומץ ההמלצות האפשרי. המשימה שלה היא לצמצם את מכלול הפריטים שהמשתמש עשוי להתעניין בהם לרשימה קצרה של מועמדים סבירים.

אנו מתמקדים בשלב השני, בדירוג. אם אתה מעוניין בשלב האחזור, עיין במדריך האחזור שלנו.

במדריך זה אנו הולכים:

  1. קבל את הנתונים שלנו ופצל אותם למערך אימונים ומבחנים.
  2. יישם מודל דירוג.
  3. התאם והערך אותו.

יבוא

בואו קודם נסתלק מהיבוא שלנו.

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

הכנת מערך הנתונים

אנו נשתמש באותם נתונים כמו מדריך האחזור . הפעם נשמור גם על הדירוגים: אלה היעדים שאנו מנסים לחזות.

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

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

כמו בעבר, נחלק את הנתונים על ידי הצבת 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 = ratings.batch(1_000_000).map(lambda x: x["movie_title"])
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)))

הטמעת מודל

ארכיטקטורה

מודלים לדירוג אינם נתקלים באותן מגבלות יעילות כמו שעושים מודלים לאחזור, ולכן יש לנו קצת יותר חופש בבחירת האדריכלות שלנו.

מודל המורכב ממספר שכבות צפופות מוערמות הוא ארכיטקטורה נפוצה יחסית לדירוג משימות. אנו יכולים ליישם זאת באופן הבא:

class RankingModel(tf.keras.Model):

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

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

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

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

  def call(self, inputs):

    user_id, movie_title = inputs

    user_embedding = self.user_embeddings(user_id)
    movie_embedding = self.movie_embeddings(movie_title)

    return self.ratings(tf.concat([user_embedding, movie_embedding], axis=1))

מודל זה לוקח מזהי משתמש וכותרות סרטים ומפיק דירוג צפוי:

RankingModel()((["42"], ["One Flew Over the Cuckoo's Nest (1975)"]))
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ['42']
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ['42']
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ["One Flew Over the Cuckoo's Nest (1975)"]
Consider rewriting this model with the Functional API.
WARNING:tensorflow:Layers in a Sequential model should only have a single input tensor, but we receive a <class 'list'> input: ["One Flew Over the Cuckoo's Nest (1975)"]
Consider rewriting this model with the Functional API.
<tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.03740937]], dtype=float32)>

אובדן ומדדים

המרכיב הבא הוא ההפסד המשמש להכשרת המודל שלנו. ל- TFRS מספר שכבות אובדן ומשימות כדי להקל על כך.

במקרה זה, נשתמש באובייקט המשימה Ranking : עטיפת נוחות שמאגדת יחד את פונקציית האובדן ואת החישוב המטרי.

נשתמש בו יחד עם MeanSquaredError של MeanSquaredError Keras על מנת לחזות את הדירוגים.

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

המשימה עצמה היא שכבת קרס שלוקחת נכון ונחזה כטיעונים ומחזירה את ההפסד המחושב. נשתמש בזה ליישום לולאת האימונים של המודל.

הדגם המלא

כעת נוכל לחבר את הכל למודל. TFRS חושף מחלקת מודלים בסיסית ( tfrs.models.Model ) המייעלת את המודלים tfrs.models.Model : כל שעלינו לעשות הוא להגדיר את הרכיבים בשיטת __init__ , וליישם את שיטת compute_loss , תוך שימוש בתכונות הגולמיות והחזרת ערך הפסד .

לאחר מכן מודל הבסיס ידאג ליצור את לולאת האימון המתאימה שתתאים למודל שלנו.

class MovielensModel(tfrs.models.Model):

  def __init__(self):
    super().__init__()
    self.ranking_model: tf.keras.Model = RankingModel()
    self.task: tf.keras.layers.Layer = tfrs.tasks.Ranking(
      loss = tf.keras.losses.MeanSquaredError(),
      metrics=[tf.keras.metrics.RootMeanSquaredError()]
    )

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

    # The task computes the loss and the metrics.
    return self.task(labels=features["user_rating"], predictions=rating_predictions)

התאמה והערכה

לאחר הגדרת המודל נוכל להשתמש בשגרת התאמה והערכה סטנדרטית של Keras כדי להתאים ולהעריך את המודל.

בואו נפתח תחילה את המודל.

model = MovielensModel()
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 [==============================] - 1s 24ms/step - root_mean_squared_error: 2.1718 - loss: 4.3303 - regularization_loss: 0.0000e+00 - total_loss: 4.3303
Epoch 2/3
10/10 [==============================] - 0s 8ms/step - root_mean_squared_error: 1.1227 - loss: 1.2602 - regularization_loss: 0.0000e+00 - total_loss: 1.2602
Epoch 3/3
10/10 [==============================] - 0s 8ms/step - root_mean_squared_error: 1.1162 - loss: 1.2456 - regularization_loss: 0.0000e+00 - total_loss: 1.2456
<tensorflow.python.keras.callbacks.History at 0x7fec089ded30>

ככל שהמודל מתאמן, ההפסד יורד ומדד ה- RMSE משתפר.

לבסוף, אנו יכולים להעריך את המודל שלנו על ערכת הבדיקות:

model.evaluate(cached_test, return_dict=True)
5/5 [==============================] - 1s 10ms/step - root_mean_squared_error: 1.1108 - loss: 1.2287 - regularization_loss: 0.0000e+00 - total_loss: 1.2287
{'root_mean_squared_error': 1.1108061075210571,
 'loss': 1.2062578201293945,
 'regularization_loss': 0,
 'total_loss': 1.2062578201293945}

ככל שמדד ה- RMSE נמוך יותר, כך המודל שלנו מדויק יותר בחיזוי דירוגים.

הצעדים הבאים

המודל לעיל נותן לנו התחלה ראויה לקראת בניית מערכת דירוגים.

כמובן שביצוע מערכת דירוג מעשית דורש הרבה יותר מאמץ.

ברוב המקרים ניתן לשפר באופן משמעותי מודל דירוג על ידי שימוש בתכונות רבות יותר ולא רק במזהי משתמשים ומועמדים. כדי לראות כיצד לעשות זאת, עיין במדריך תכונות הצד .

יש צורך בהבנה מדוקדקת של היעדים שכדאי לייעל. כדי להתחיל בבניית ממליץ המייעל אופטימיזציה של יעדים מרובים, עיין במדריך הרב- משימתי שלנו.