物品推荐系统中的挑战和解决方案

点击上方“AI公园”,关注公众号,选择加“星标“或“置顶”


作者:datarevenue

编译:ronghuaiyang

导读

如何处理没有见过的数据,优化响应时间,并频繁更新模型。

Challenges & Solutions for Production Recommendation Systems

https://www.datarevenue.com/en-blog/building-a-production-ready-recommendation-system

如何处理不可见的数据,优化响应时间,并频繁更新模型。

介绍

有很多关于训练和评估推荐系统的文章,但很少有文章解释该如何克服建立全面系统的挑战。

大多数库都不支持开箱即用的可扩展生产系统。这些挑战通常是:

  • 动态预测 — 当你的用户/物品维度非常大的时候,它可能是非常低效的 — 或者说不可能预先计算好所有的推荐。

  • 优化响应时间 — 当你动态创建预测时,检索它们所需的时间非常重要。

  • 频繁更新模型 — 当系统需要合并可用的新数据时,频繁更新模型是至关重要的。

  • 基于没见过数据进行预测 — 这意味着要处理没见过的用户或物品,并不断地更改特征。

这篇文章将告诉你如何在一个完整的生产环境中修改模型来扩展它的功能。

混合推荐模型能更好地应对现实世界的挑战

我们使用了LightFM模型,这是一个非常流行的python推荐库,它实现了一个混合模型。它最适合中小规模的推荐项目 — 不需要分布式的训练。

简要介绍不同的推荐方法

有两种基本的推荐方法:

协同过滤 模型只使用协同过滤的信息 — 用户和物品之间隐式或者显式的交互(比如看过的电影,评分,是不是喜欢)。没有使用任何实际物品的信息(如电影类别,流派等)。

协同过滤模型在小数据集上可以得到很高的准确率,但是不能处理未知的用户或者物品(冷启动问题)。

协同模型可以在数据少的情况下达到**的高精度,但无法处理未知的用户或项目(**冷启动问题)。

基于内容的 模型完全基于关于物品或用户的可用数据,完全忽略了用户与物品之间的交互。所以他们处理推荐的方式与协同过滤模型非常不同。

基于内容的模型通常:

  • 需要更多的训练数据(你需要为几乎每一个单独的用户/物品组合提供用户/物品样本),并且

  • 比协同过滤模型更难调优。

但是,与协同过滤模型相比,它们可以对未知的物品进行预测,并且通常具有更好的覆盖率。

混合推荐 — 像LightFM一样,将两种方法结合起来,克服了每种方法的各自的缺点。

可以处理新物品或新用户

当你将一个协同过滤模型部署到生产环境中时,你经常会遇到需要预测没有见过的用户或物品的问题 — 比如当一个新用户注册或访问你的网站,或者你的内容团队发布一篇新文章时。

通常,你必须至少等到下一个训练周期,或者等到用户与某个物品交互时,才能为这些用户提供建议。

但是,即使在这种情况下,混合模型也可以进行预测:它将简单地使用部分可用的特征来计算推荐。

混合模型还可以处理特征缺失

有时,一些用户和物品会缺少一些特征(仅仅是因为你还没有能够收集它们),如果你依赖于基于内容的模型,这就是一个问题。

混合推荐器适用于为用户(那些从训练中了解到的用户)包括新用户返回物品,只要你有关于他们的特征。这对于物品尤其有用,对于新用户也是如此(当用户第一次访问你的站点时,你可以询问他们对什么感兴趣)。

系统组件

在这个系统中假设物品的数量比用户要少得多,因为它总是检索所有物品的预测。但它可以作为更复杂推荐的基础。

系统的核心是一个flask app,它接收一个用户ID,然后返回和该用户相关的物品。它将(重新)加载LightFM模型,并查询一个针对物品和/或用户特征的redis实例。

我们将假设用户和物品的特征是存储和序列化在一个redis数据库中,并可以随时由flask的应用程序来检索。

所有应用程序都将通过docker容器部署为微服务。

LightFM如何进行预测

但是这个东西怎么工作呢?

这篇LightFM论文:(https://arxiv.org/pdf/1507.08439.pdf)对于学术读者来说信息量很大,但是对于不太熟悉这个领域的人来说可能有点简略。我将在下面更简单地概述LightFM模型的预测的过程。

公式说明:

  • 小写字母表示向量,大写字母表示矩阵。

  • 下标u为单个用户,U为所有用户的集合。

  • 物品以相同的方式引用。

这里的命名大部分与LightFM论文一致。

模型的组成

LightFM结合了协同过滤和基于内容的方法。你可能会说它为两种方法中的每一种建模一个组件。这两个都是必要的,可以从推荐系统中得到我们想要的属性。

协同过滤部分

协作过滤部分允许你在没有任何特征或特征不能提供信息的情况下使用协同过滤算法。最先进的协同过滤算法是通过矩阵分解实现的。他们估计了两个潜在的(未观察到的)矩阵表示,当它们彼此相乘时,将重现训练期间模型看到的每个物品和用户的交互矩阵。当然,误差项可以允许一些噪声和避免过拟合。

打个简单的比方:试着因式分解12。我们可以用2和6,3和4,1和12等等。矩阵也是类似的。

我们称这些矩阵为潜在表示,因为它们是我们交互数据的压缩形式。

基于内容的部分

基于内容的部分允许你在没有交互数据的时候获得预测。

LightFM通过将用户和物品特征与潜在表示关联起来,从而合并了这些特征。假设特征和潜在表示是线性相关的。所以在向量形式中:

为用户的潜在表示, 为单个用户特征的行向量, 为估计的物品的嵌入, 为用户emedding的偏差。(为了简单起见,我们将从现在开始忽略它们。)

看起来很像线性回归,对吧?除了 是一个矩阵,其他都是向量。实际上,这实际上执行了多个回归:每个模型组件一个。同样,对于物品也是类似的。

在训练中,利用梯度下降算法估计用户嵌入和物品嵌入。嵌入矩阵中的每一行都是一个特征。嵌入矩阵的列称为分量。列的数量被设置为一个模型超参数,我们从现在开始将其称为d

上面的图概括了为所有用户和所有物品进行预测的这个过程。因此,在步骤I中,我们将尺寸为的用户特征矩阵与尺寸为的 嵌入矩阵相乘。同样的方法也适用于物品特征与物品嵌入的第二次乘法。由步骤I得到两个尺寸为和 的矩阵。因此,每个用户/物品都表示为大小为d的潜向量。

现在你可以很容易地获得一个单一用户的所有表示与以下条件:

是用户潜在表示的行向量, 是所有物品的潜在表示的矩阵。

使用指示矩阵对协同过滤模型进行退化

LightFM可以只生成具有协同过滤信息的模型。它使用了一个非常有效的技巧:如果根本不使用用户或物品特征,模型将接受一个大小分别为 的单位矩阵。这是非常有效的,因为它随后学习d向量 — 每个用户一个。这样,模型就可以最终退化成最佳的纯协同过滤方法。你可以将这些组件看作是用户的模型记忆,以及在训练中已经看到的物品。

你还可以强迫模型退回到协同过滤模式 — 即使你有特征:你可以通过向其添加一个单位矩阵来修改特征矩阵。有时你需要这个来让你的模型收敛。然而,这通常意味着你的特征太过嘈杂或者没有携带足够的信息,以至于模型本身无法收敛。

最后,使用这种技巧增加了将模型投入生产所需的工作:在训练期间,用户的索引用于检索相应特征/单位矩阵的正确行 — 而这些信息在生产环境中可能不再可用,另外,LightFM模型将这个责任推卸给了用户。

有趣的事实

在欧几里得空间中,仅使用指示特征就可以获得的相似物品/用户的潜在表示(就协同过滤信息而言)是接近的。该模型基于协同过滤信息对它们进行估计。因此,你可以使用它们来查找物品或用户之间的相似性。

动态地重新创建指示器和特征

现在让我们实现一个模型,该模型可以回到协同过滤模式,跟踪IDs,从而能够重构正确的特征和指示器。

我们将聚焦在实现一个完整的方法。这是相当复杂的,因为同时,它应该能够在大多数情况下给出预测。我们将继承LightFM类并添加一个特殊的predict_online方法,该方法将在生产期间使用。

这样,我们仍然可以使用LightFM的cythonised预测函数,避免分别处理用户和物品ID的映射。

它应可以满足下列要求:

  1. 如果在训练过程中看到过用户/物品,则重构其指示特征

  2. 不管某个用户的数据是什么,都要进行在线预测

  3. 尽可能快地做出预测

ID映射

为了达到第一个要求,你必须在训练中使用同样的类。你还需要调整你的子类,使它在训练期间只接受稀疏矩阵,SparseFrame对象,因此创建并保存ID映射。

重构特征

为了实现第二个需求,你需要在每次请求传入时检查可用数据。有16种情况你必须处理:

IVVIIIXII的情况下,我们简单地返回我们的基线预测。对于XIIIXVI的情况,我们无法作出任何预测,因为我们对这些物品了解不够。

总结一下:我们基本上想要创建一个行向量,其中包含用户特征,如果它们是可用的。否则在相应的下标上都是0。如果用户在训练的时候见过,它还在正确的索引上包含了用户的指示特征。

物品特征与用户特征类似,只是我们希望它们能够很容易地放到内存中,以便进行缓存。你可以考虑根据你的使用情况使用不同的缓存策略(如TTLCache),或者根本不使用缓存。

我们还希望支持添加指示器,或者只将它们添加到用户或物品特征中,这可能会使实现更加复杂。尽管如此,我们还是尽量保持简单。

下面是上述方法的示例实现。这个实现应该能够正确处理到VIII的所有情况。但是可能不是所有的项目用例都实现了,因为我们的应用程序不需要它。因此,预测没有项目特征的已知项目是不可能的,但它应该很容易添加。

本文的第二部分使用这个类,将它连接到一个redis数据库,并使用flask动态地提供它的预测。我们还将向你展示如何使用从flask应用程序内部启动的后台线程在不停机的情况下更新模型。

代码链接:https://gist.github.com/kayibal/16340660d1d85b9ea1872a5d9be0f383

—END—

英文原文:https://www.datarevenue.com/en-blog/building-a-production-ready-recommendation-system

请长按或扫描二维码关注本公众号

喜欢的话,请给我个好看吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值