หนังแนะนำ : หาเรื่อง

ดูบน TensorFlow.org ทำงานใน Google Colab ดูแหล่งที่มาบน GitHub ดาวน์โหลดโน๊ตบุ๊ค

ระบบผู้แนะนำในโลกแห่งความเป็นจริงมักประกอบด้วยสองขั้นตอน:

  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

ชุดข้อมูลการให้คะแนนจะส่งคืนพจนานุกรมของ ID ภาพยนตร์, ID ผู้ใช้, การให้คะแนน, การประทับเวลา, ข้อมูลภาพยนตร์ และข้อมูลผู้ใช้:

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

เพื่อให้เหมาะสมและประเมินแบบจำลอง เราต้องแยกออกเป็นชุดฝึกอบรมและประเมินผล ในระบบ recommender อุตสาหกรรมนี้ส่วนใหญ่จะทำได้ตามเวลา: ข้อมูลถึงเวลา \(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)

มาคิดกันด้วย ID ผู้ใช้และชื่อภาพยนตร์ที่ไม่ซ้ำที่มีอยู่ในข้อมูล

นี่เป็นสิ่งสำคัญเพราะเราจำเป็นต้องสามารถแมปค่าดิบของคุณสมบัติตามหมวดหมู่ของเรากับการฝังเวกเตอร์ในแบบจำลองของเรา ในการทำเช่นนั้น เราจำเป็นต้องมีคำศัพท์ที่จับคู่ค่าคุณลักษณะดิบกับจำนวนเต็มในช่วงที่อยู่ติดกัน: ซึ่งช่วยให้เราสามารถค้นหาการฝังที่สอดคล้องกันในตารางการฝังของเรา

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 ชั้น preprocessing เพื่อรหัสผู้ใช้แปลงแรกจำนวนเต็มแล้วแปลงเหล่านั้นเพื่อ embeddings ผู้ใช้ผ่าน 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 สำหรับรูปแบบที่เรียบง่ายนี้อาจจะ overkill เราสามารถขยายไปยังรูปแบบที่ซับซ้อนโดยพลการโดยใช้ส่วนประกอบที่ 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 ชุด, แปลงเป็น embeddings ผ่านรูปแบบภาพยนตร์ของเรา:

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

การสูญเสีย

องค์ประกอบต่อไปคือการสูญเสียที่ใช้ในการฝึกแบบจำลองของเรา TFRS มีชั้นการสูญเสียและงานหลายอย่างเพื่อทำให้สิ่งนี้ง่ายขึ้น

ในกรณีนี้เราจะใช้ประโยชน์จาก Retrieval วัตถุงาน: ความสะดวกสบายเสื้อคลุมรวมกลุ่มที่ร่วมกันฟังก์ชั่นการสูญเสียและการคำนวณตัวชี้วัด:

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

ตัวงานเองเป็นเลเยอร์ Keras ที่ใช้การสืบค้นและการฝังตัวของตัวเลือกเป็นอาร์กิวเมนต์ และคืนค่าการสูญเสียที่คำนวณ: เราจะใช้สิ่งนั้นเพื่อใช้งานลูปการฝึกของโมเดล

ตัวเต็ม

ตอนนี้เราสามารถรวมทุกอย่างเข้าด้วยกันเป็นแบบจำลองได้ ฉบับที่ exposes ชั้นฐานแบบจำลอง ( 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 fitting มาตรฐานและรูทีนการประเมินเพื่อให้พอดีและประเมินโมเดล

มาสร้างอินสแตนซ์โมเดลกันก่อน

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 สำหรับรายละเอียดเพิ่มเติม

ในขณะที่รถไฟจำลอง การสูญเสียกำลังลดลงและมีการอัปเดตชุดเมตริกการดึงข้อมูลระดับบนสุด สิ่งเหล่านี้บอกเราว่าผลบวกที่แท้จริงอยู่ในรายการที่ดึงมาจาก top-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. แบบจำลองของเรามีแนวโน้มที่จะทำงานได้ดีขึ้นกับข้อมูลที่เห็น เพียงเพราะสามารถจดจำได้ ปรากฏการณ์ overfitting นี้มีความแข็งแกร่งเป็นพิเศษเมื่อแบบจำลองมีหลายพารามิเตอร์ มันสามารถเป็นสื่อกลางโดยการทำให้โมเดลเป็นมาตรฐานและการใช้คุณสมบัติผู้ใช้และภาพยนตร์ที่ช่วยให้โมเดลสรุปข้อมูลที่มองไม่เห็นได้ดีขึ้น
  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 ส่วนประกอบทั้งสองสามารถบรรจุเป็นโมเดลที่ส่งออกได้เพียงรูปแบบเดียว ทำให้เรามีโมเดลที่รับ ID ผู้ใช้ดิบและส่งคืนชื่อภาพยนตร์ยอดนิยมสำหรับผู้ใช้รายนั้น นี้จะกระทำผ่านการส่งออกรูปแบบไปยัง 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. การใช้เมตาดาต้าของภาพยนตร์: การสร้างโมเดลภาพยนตร์ที่ซับซ้อนมากขึ้นเพื่อบรรเทาการสตาร์ทแบบเย็น