TensorFlow 推荐器简介
2020 年 9 月 23 日
发布者:Maciej Kula 和 James Chen,Google Brain

从推荐电影或餐厅到协调时尚配饰以及突出显示博客文章和新闻文章,推荐系统是机器学习的重要应用,展现新发现并帮助用户找到他们喜欢的东西。

在 Google,我们过去几年一直在探索新的深度学习技术,通过多任务学习强化学习更好的用户表示 以及 公平性目标 提供更好的推荐。这些和其他进步使我们能够极大地改进我们的推荐。

今天,我们很高兴地宣布推出 **TensorFlow 推荐器 (TFRS)**,这是一个开源 TensorFlow 包,使构建、评估和提供复杂的推荐模型变得容易。

TFRS 基于 TensorFlow 2.x,使您可以

TFRS 基于 TensorFlow 2.x 和 Keras,使其立即熟悉且易于使用。它在设计上是模块化的(因此您可以轻松地自定义各个层和指标),但仍然形成一个凝聚整体(因此各个组件可以很好地协同工作)。在整个 TFRS 设计过程中,我们一直强调灵活性和易用性:默认设置应合理;常见任务应直观且易于实现;更复杂或自定义的推荐任务应是可能的。

TensorFlow 推荐器是开源的,并在Github 上可用。我们的目标是使其成为一个不断发展的平台,灵活到足以进行学术研究,并且高度可扩展到足以构建网络规模的推荐系统。我们还计划扩展其在多任务学习特征交叉建模自监督学习 以及最先进的有效近似最近邻计算 方面的功能。

示例:构建电影推荐器

要了解如何使用 TensorFlow 推荐器,让我们从一个简单的示例开始。首先,使用 pip 安装 TFRS

!pip install tensorflow_recommenders

然后,我们可以使用MovieLens 数据集 训练一个用于电影推荐的简单模型。此数据集包含有关用户观看的电影以及用户对观看的电影给出的评分的信息。

我们将使用此数据集构建一个模型来预测用户观看的哪些电影以及哪些电影没有观看。对于这种任务,一种常见且有效的模式是所谓的双塔模型:一个神经网络,其中两个子模型分别学习查询和候选者的表示。给定查询-候选者对的得分只是这两个塔的输出的点积。

这种模型架构非常灵活。输入可以是任何内容:查询侧的用户 ID、搜索查询或时间戳;候选者侧的电影标题、描述、提要、主演演员列表。

在此示例中,我们将保持简单,并坚持使用用户 ID 作为查询塔,以及电影标题作为候选者塔。

首先,让我们准备数据。数据可以在TensorFlow 数据集 中获得。

import tensorflow as tf
 
import tensorflow_datasets as tfds
import tensorflow_recommenders as tfrs
# Ratings data.
ratings = tfds.load("movie_lens/100k-ratings", split="train")
# Features of all the available movies.
movies = tfds.load("movie_lens/100k-movies", split="train")

在数据集中的所有可用特征中,最有用的是用户 ID 和电影标题。虽然 TFRS 可以使用任意丰富的特征,但为了保持简单,我们只使用这些特征。

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

当只使用用户 ID 和电影标题时,我们简单的双塔模型与典型的矩阵分解 模型非常相似。为了构建它,我们需要以下内容

  • 一个用户塔,将用户 ID 转换为用户嵌入(高维向量表示)。
  • 一个电影塔,将电影标题转换为电影嵌入。
  • 一个损失函数,最大化我们观察到的观看的预测用户-电影亲和力,并最小化未发生的观看的亲和力。

TFRS 和 Keras 提供了许多构建块来实现这一点。我们可以从创建一个模型类开始。在 __init__ 方法中,我们设置了一些超参数以及模型的主要组件。

class TwoTowerMovielensModel(tfrs.Model):
  """MovieLens prediction model."""
 
  def __init__(self):
    # The `__init__` method sets up the model architecture.
    super().__init__()
 
    # How large the representation vectors are for inputs: larger vectors make
    # for a more expressive model but may cause over-fitting.
    embedding_dim = 32
    num_unique_users = 1000
    num_unique_movies = 1700
    eval_batch_size = 128

第一个主要组件是用户模型:一组描述如何将原始用户特征转换为数值用户表示的层。在这里,我们使用Keras 预处理层 将用户 ID 转换为整数索引,然后将这些索引映射到学习到的嵌入向量

 # Set up user and movie representations.
    self.user_model = tf.keras.Sequential([
      # We first turn the raw user ids into contiguous integers by looking them
      # up in a vocabulary.
      tf.keras.layers.experimental.preprocessing.StringLookup(
          max_tokens=num_unique_users),
      # We then map the result into embedding vectors.
      tf.keras.layers.Embedding(num_unique_users, embedding_dim)
    ])
电影模型看起来很相似,将电影标题转换为嵌入
self.movie_model = tf.keras.Sequential([
      tf.keras.layers.experimental.preprocessing.StringLookup(
          max_tokens=num_unique_movies),
      tf.keras.layers.Embedding(num_unique_movies, embedding_dim)
    ])

一旦我们有了用户模型和电影模型,我们都需要定义我们的目标及其评估指标。在 TFRS 中,我们可以通过 Retrieval 任务来做到这一点(使用批内 softmax 损失

# The `Task` objects has two purposes: (1) it computes the loss and (2)
    # keeps track of metrics.
    self.task = tfrs.tasks.Retrieval(
        # In this case, our metrics are top-k metrics: given a user and a known
        # watched movie, how highly would the model rank the true movie out of
        # all possible movies?
        metrics=tfrs.metrics.FactorizedTopK(
            candidates=movies.batch(eval_batch_size).map(self.movie_model)
        )
    )

我们使用 compute_loss 方法来描述模型应该如何训练。

def compute_loss(self, features, training=False):
    # The `compute_loss` method determines how loss is computed.
 
    # Compute user and item embeddings.
    user_embeddings = self.user_model(features["user_id"])
    movie_embeddings = self.movie_model(features["movie_title"])
 
    # Pass them into the task to get the resulting loss. The lower the loss is, the
    # better the model is at telling apart true watches from watches that did
    # not happen in the training data.
    return self.task(user_embeddings, movie_embeddings)
我们可以使用标准 Keras fit 调用来拟合此模型
model = MovielensModel()
model.compile(optimizer=tf.keras.optimizers.Adagrad(0.1))
 
model.fit(ratings.batch(4096), verbose=False)

为了对模型的推荐进行合理性检查,我们可以使用 TFRS BruteForce 层。BruteForce 层使用候选者的预计算表示进行索引,并允许我们通过计算所有可能候选者的查询-候选者得分来检索响应查询的顶级电影

index = tfrs.layers.ann.BruteForce(model.user_model)
index.index(movies.batch(100).map(model.movie_model), movies)
 
# Get recommendations.
_, titles = index(tf.constant(["42"]))
print(f"Recommendations for user 42: {titles[0, :3]}")

当然,BruteForce 层只适用于非常小的数据集。请参阅我们的完整教程,了解使用 TFRS 和 Annoy(一个近似最近邻库)的示例。

我们希望这让你对 TensorFlow 推荐器提供的内容有所了解。要了解更多信息,请查看我们的教程API 参考。如果你想参与塑造 TensorFlow 推荐系统的未来,请考虑贡献!我们还将很快宣布 TensorFlow 推荐特别兴趣小组,欢迎在嵌入学习和分布式训练和服务等主题上进行合作和贡献。敬请关注!

致谢

TensorFlow 推荐器是 Google 内部和外部许多人的共同努力的结果。我们感谢 Tiansheng Yao、Xinyang Yi、Ji Yang 对该库的核心贡献,以及 Lichan Hong 和 Ed Chi 的领导和指导。我们还感谢 Zhe Zhao、Derek Cheng、Sagar Jain、Alexandre Passos、Francois Chollet、Sandeep Gupta、Eric Ni 以及许多其他人对该项目的建议和支持。
下一篇文章
 Introducing TensorFlow Recommenders

发布者:Maciej Kula 和 James Chen,Google Brain从推荐电影或餐厅到协调时尚配饰以及突出显示博客文章和新闻文章,推荐系统是机器学习的重要应用,展现新发现并帮助用户找到他们喜欢的东西。在 Google,我们过去几年一直在探索新的深度学习技术来...