Рекомендации фильмов: поиск

Посмотреть на TensorFlow.org Запускаем в Google Colab Посмотреть исходный код на GitHub Скачать блокнот

Реальные рекомендательные системы часто состоят из двух этапов:

  1. Этап поиска отвечает за выбор первоначального набора из сотен кандидатов из всех возможных кандидатов. Основная цель этой модели - эффективно отсеять всех кандидатов, которые не интересуют пользователя. Поскольку модель поиска может иметь дело с миллионами кандидатов, она должна быть эффективной с вычислительной точки зрения.
  2. Этап ранжирования берет выходные данные модели поиска и настраивает их, чтобы выбрать лучшую из возможных рекомендаций. Его задача - сузить набор элементов, которые могут быть интересны пользователю, до короткого списка вероятных кандидатов.

В этом уроке мы сосредоточимся на первом этапе - извлечении. Если вы заинтересованы в рейтинге стадии, взгляните на нашем рейтинге учебника.

Модели извлечения часто состоят из двух подмоделей:

  1. Модель запроса, вычисляющая представление запроса (обычно вектор встраивания с фиксированной размерностью) с использованием функций запроса.
  2. Модель-кандидат, вычисляющая представление-кандидат (вектор одинакового размера) с использованием функций-кандидатов.

Затем выходные данные двух моделей умножаются вместе, чтобы получить оценку сродства запроса-кандидата, причем более высокие оценки выражают лучшее соответствие между кандидатом и запросом.

В этом руководстве мы собираемся построить и обучить такую ​​модель с двумя башнями, используя набор данных Movielens.

Собирались:

  1. Получите наши данные и разделите их на набор для обучения и тестирования.
  2. Реализуйте модель поиска.
  3. Подгоните и оцените.
  4. Экспортируйте его для эффективного обслуживания, построив приблизительный индекс ближайших соседей (ИНС).

Набор данных

В 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 Datasets . Загрузка 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 Preprocessing слои сначала преобразовать идентификаторы пользователей в целые числа, а затем преобразовать те пользователь вложений через 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 обратный вызов функции Fit () , а затем начать TensorBoard используя %tensorboard --logdir logs/fit . Пожалуйста , обратитесь к TensorBoard документации для получения более подробной информации.

По мере обучения модели потери падают, и обновляется набор топ-k показателей поиска. Они говорят нам, есть ли истинный положительный результат в k самых популярных элементах из всего набора кандидатов. Например, показатель категориальной точности 0,2 в топ-5 говорит нам о том, что в среднем истинный положительный результат находится в 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. Модель повторно рекомендует некоторые из уже просмотренных пользователями фильмов. Эти заведомо положительные часы могут вытеснить тестовые фильмы из лучших рекомендаций К.

Со вторым явлением можно бороться, исключив просмотренные ранее фильмы из рекомендаций по тестированию. Этот подход относительно распространен в литературе по рекомендательным системам, но мы не следуем ему в этих руководствах. Если не рекомендовать предыдущие наблюдения важно, мы должны ожидать, что правильно заданные модели будут учиться этому поведению автоматически на основе прошлой истории пользователей и контекстной информации. Кроме того, часто уместно рекомендовать один и тот же товар несколько раз (например, вечнозеленый сериал или регулярно приобретаемый товар).

Делать прогнозы

Теперь, когда у нас есть модель, мы хотели бы делать прогнозы. Мы можем использовать 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 слой будет слишком медленно , чтобы служить модель с большим количеством возможных кандидатов. В следующих разделах показано, как это ускорить с помощью приблизительного индекса поиска.

Модель сервировки

После обучения модели нам нужен способ ее развертывания.

В модели извлечения с двумя башнями обслуживание состоит из двух компонентов:

  • модель обслуживающего запроса, учитывающая особенности запроса и преобразующая их во встраивание запроса, и
  • действующая модель кандидата. Чаще всего это принимает форму индекса приблизительных ближайших соседей (ИНС), который позволяет быстро приближенно искать кандидатов в ответ на запрос, созданный моделью запроса.

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

Этот слой будет выполнять приближенный Lookups: это делает ПОИСКОВУЮ чуть менее точны, но на несколько порядков быстрее на больших наборах кандидатов.

# 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. Использование метаданных фильма: создание более сложной модели фильма для облегчения холодного старта.