作者:Heorhii Skovorodnikov

深入研究TikTok令人惊叹的实时推荐系统的内部工作原理,了解是什么使它成为该领域最好的产品之一。

为什么TikTok的feed如此让人上瘾?秘诀在于他们的推荐引擎,这正是使TikTok成为最大的社交媒体平台之一的原因。

似乎feed可以读取你的思想,让你在应用程序中停留更长时间。最近,TikTok决定让每个人都知道一个秘密,并在一篇题为 “Monolith:带有无碰撞嵌入表的实时推荐系统[https://arxiv.org/pdf/2209.07663.pdf]” 的论文中发布了它的模型Monolith。

在线推荐系统是一种算法,用于根据用户的兴趣和喜好向用户提供个性化的建议。这些系统通常被在线零售商和媒体公司用于向用户推荐产品或内容。

在这篇文章中,我们将深入研究TikTok令人惊叹的推荐系统的内部工作原理,并了解是什么,让它成为该领域最好的系统之一.

目前的设计存在什么问题?

构建可扩展的实时推荐系统对于许多企业在其产品或网站中构建良好的体验至关重要。然而,目前的深度学习框架(TensorFlow或PyTorch)不能很好地用于实时生产场景。这是因为:

  • 在依赖动态稀疏特征的推荐系统中,基于静态参数和密集计算的模型更新并不适合较好的推荐性能。
  • 常见的方法是将批量训练阶段和服务阶段(在用户与产品交互期间)完全分开设计,防止模型与客户反馈实时交互。

TikTok的团队通过3个步骤解释了他们的解决方案:

  • 他们制作了一个无碰撞的嵌入表,同时通过添加可exponable embedding 和 frequency filtering(频率过滤)来进一步优化它,以减少其内存消耗,让其高效,并适合分发到用户;
  • 他们提供了一个可用于生产环境的,且具有高容错性在线训练架构;
  • 他们通过实验证明,系统的可靠性可以与实时学习来互相平衡;

听起来有点吓人吗? 不要担心,我们将通过对每个组件的拆解分析,在本文结束时,你将有信心地理解,为什么你可以在应用程序中浪费大量时间。准备好了吗? 我们要发车啦。

Embeddings and Hash maps

TikTok的研究人员观察到,对于推荐系统来说,数据大多是categorical(分散) 和sparse(稀疏)的

这意味着,如果我们使用像单词嵌入这样的ML方法嵌入数据,我们将无法通过推荐数据提供的独特特性数量来实现,相比之下,由于词汇量有限,语言模型可以做到这一点。

根据YouTube和Instagram推荐系统的实际经验,哈希技巧被认为是大规模推荐系统的最佳方法。让我们深入研究《Monolith》中所使用的细节。

那么HashMap呢?

哈希映射是一种数据结构,它允许通过一个特殊的哈希函数将数据片段快速映射到一个值。

哈希映射速度很快,被大型平台用于高效编码数据,那么单体应用如何使其更好呢? 哈希映射有一个固有的权衡,这个数据结构的原始设计称为碰撞(collision)。

当两个或多个数据通过哈希函数映射到相同的输出值时,就会发生冲突。当使用哈希函数索引数据时,这可能会导致问题,因为多个数据块将被映射到相同的位置。TikTok的团队开发了一个 cuckoo hashmap,来解决这个问题。

在 cuckoo hashmap 中,就像在标准hash map中一样,每个数据都被分配一个唯一的键,并且键被哈希以确定它在数组中的位置。如果该位置已经被另一段数据占据,则现有数据将被“踢出”(类似于现实生活中杜鹃对巢中蛋的行为),并且必须使用第二个哈希函数在数组中找到一个新的位置。这个过程将继续,直到所有数据都成功插入数组,或者直到达到最大迭代次数为止。上面给出了一个例子。这里两个哈希表T0和T1用于存储哈希数据。值A被散列并插入到T0中,但是由于B已经占据了这个位置,然后将其逐出,并试图将其插入到T1中,这个过程将重复,直到插入所有值或重新散列以避免循环插入。这个过程可以避免碰撞,对生产模型的性能有重要影响。

为了完成他们的embedding系统设计,研究人员添加了一些附加功能来进一步优化过程,特别是减少哈希所需要的内存需求:

  • 用于过滤hashmap中的id的概率过滤器。由于一个重要的观察是,在来自TikTok id的数据中,id是长尾分布的,热门id可能出现数百万次,而不受欢迎的id出现不超过10次,因此可以合理地假设它们不会影响最终的模型质量,因此可以清除。

  • 一个ID存在计时器,控制旧ID和过期ID的删除。这可能是由于用户不再活跃,或短视频过时。为这些id存储嵌入不能以任何方式帮助模型,因此清除内存是明智的。

在线训练

现在,由于我们已经了解了数据在模型中是如何表示的,我们需要了解如何训练和更新数据。Monolith在线训练的系统架构的总体示意图如下:

它看起来很复杂,但实际上,它都围绕着一个非常简单的过程,这个过程是更大架构的基础,推动了整个训练系统架构的核心。

TensorFlow的分布式Worker-ParameterServer(或简称PS)模型是以分布式方式训练机器学习模型的一种方式,其中多台机器(或一台机器上的进程)一起工作来训练模型,如下图所示:

在这个模型中,有两种类型的进程:工作进程和参数服务器进程。

  • 工作进程负责执行训练模型所需的计算,例如计算梯度或更新模型参数。
  • 参数服务器负责存储模型的当前状态,例如模型权重或偏差。

训练分为批量训练和在线训练两个阶段:

  • 批量训练阶段。 该阶段的工作原理如下:在每个训练步骤中,训练工作者从存储中读取一个小批量的训练样例,向PS请求参数,计算向前和向后传递,最后将更新后的参数推入训练PS。当需要修改模型架构并重新训练模型时,批量训练对于训练历史数据非常有用;

  • 在线训练阶段。 模型部署到在线服务后,训练不会停止,而是进入在线训练阶段。训练工作者不再从存储中读取小批量示例,而是实时地使用实时数据并更新训练PS,训练PS定期将其参数同步到服务PS,这将立即在用户端生效。

Streaming引擎

为了确保Monolith能够在批量训练和在线训练之间无缝切换,它使用了一个Streaming引擎组件:

为了收集实时用户反馈,研究团队使用Kafka队列,其中一个队列记录用户操作(点击,点赞等),另一个队列记录来自模型服务器的功能。然后使用Apache Flink joiner连接两个,这些打包的数据被转换成训练数据,然后由另一个Kafka队列读取,这些训练示例用于批处理训练和在线训练:

  • 在批量训练过程中,Kafka队列中的数据被转储到Hadoop分布式文件存储(HDFS)中,在积累了一定数量的训练数据后,再发送给训练工作者

    -在线训练的过程更简单:数据直接从Kafka队列中读取

训练操作完成后,PS收集参数,并根据选定的同步计划更新服务PS,而服务PS又更新用户端的模型。

在线 Joiner

Joiner 过程实际上有点复杂,我们应该注意一些事情:

内存缓存和KV(Key-Value)存储,是两个有助于稳定用户操作和来自服务器的功能之间的延迟的组件,这是因为它们都到达,而不考虑彼此的到达时间,因此需要缓存来正确地配对它们。但是如果用户需要很长时间才能完成一个操作呢? 那么缓存就不是一个好主意,因此一些值存储在磁盘上,以便再次配对。当用户操作日志到达时,它首先查找内存中的缓存,然后查找键值存储,以防缺少缓存。

还要注意最后一步,即 负例采样(Negative Sampling)。因为在训练过程中有积极和消极的例子。在推荐系统中,正例是用户喜欢或表现出兴趣的项目,而负例是用户不喜欢或表现出兴趣的项目。但是它们的数量可能是不平衡的,因此纠正数据集中的这种偏差是很重要的。

就是这样。你已经了解了Monolith中的所有组件。现在是最后一个部分,研究人员证明了在线学习的有效性。

实时学习

在这里,团队还比较了模型,在不同同步时间间隔下的性能,以验证其性能:

正如我们在上面看到的,在线训练,对于具有动态反馈的推荐系统拥有更好的性能,是至关重要的。

写在最后

感谢阅读我对TikTok实时推荐系统工作原理的深入研究。

我希望你觉得有趣,并学到了一点新的东西。

原文https://www.shaped.ai/blog/the-secret-sauce-of-tik-toks-recommendations

论文:Monolith:带有无碰撞嵌入表的实时推荐系统,https://arxiv.org/pdf/2209.07663.pdf

TikTok 推荐引擎强大的秘密的更多相关文章

  1. AI时代:推荐引擎正在塑造人类

    We shape our tools and afterwards our tools shape us. ------Marshall McLuhan 麦克卢汉说:"我们塑造了工具,反过来 ...

  2. 机器学习实战(Machine Learning in Action)学习笔记————10.奇异值分解(SVD)原理、基于协同过滤的推荐引擎、数据降维

    关键字:SVD.奇异值分解.降维.基于协同过滤的推荐引擎作者:米仓山下时间:2018-11-3机器学习实战(Machine Learning in Action,@author: Peter Harr ...

  3. 机器学习 101 Mahout 简介 建立一个推荐引擎 使用 Mahout 实现集群 使用 Mahout 实现内容分类 结束语 下载资源

      机器学习 101 Mahout 简介 建立一个推荐引擎 使用 Mahout 实现集群 使用 Mahout 实现内容分类 结束语 下载资源 相关主题   在信息时代,公司和个人的成功越来越依赖于迅速 ...

  4. 从源代码剖析Mahout推荐引擎

    转载自:http://blog.fens.me/mahout-recommend-engine/ Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, Hive, Pi ...

  5. 基于Azure构建PredictionIO和Spark的推荐引擎服务

    基于Azure构建PredictionIO和Spark的推荐引擎服务 1. 在Azure构建Ubuntu 16.04虚拟机 假设前提条件您已有 Azure 帐号,登陆 Azure https://po ...

  6. [转] 基于 Apache Mahout 构建社会化推荐引擎

    来源:http://www.ibm.com/developerworks/cn/java/j-lo-mahout/index.html 推荐引擎简介 推荐引擎利用特殊的信息过滤(IF,Informat ...

  7. 基于Spark ALS构建商品推荐引擎

    基于Spark ALS构建商品推荐引擎   一般来讲,推荐引擎试图对用户与某类物品之间的联系建模,其想法是预测人们可能喜好的物品并通过探索物品之间的联系来辅助这个过程,让用户能更快速.更准确的获得所需 ...

  8. JVM调优(这里主要是针对优化基于分布式Mahout的推荐引擎)

    优化推荐系统的JVM关键参数 -Xmx 设定Java允许使用的最大堆空间.例如-Xmx512m表示堆空间上限为512MB -server 现代JVM有两个重要标志:-client和-server,分别 ...

  9. 基于lucene实现自己的推荐引擎

    基于lucene实现自己的推荐引擎 推荐常用算法之-基于内容的推荐 推荐算法

  10. 转】从源代码剖析Mahout推荐引擎

    原博文出自于: http://blog.fens.me/mahout-recommend-engine/ 感谢! 从源代码剖析Mahout推荐引擎 Hadoop家族系列文章,主要介绍Hadoop家族产 ...

随机推荐

  1. Springboot配置多Redis源

    Springboot配置多Redis源 一.背景 因项目部署了新集群,某些缓存数据需要在旧的redis上取,就必须配置多个数据源动态获取相对应的源以兼容业务. 二.配置依赖 <dependenc ...

  2. Thrift RPC添加access log

    前言: 当我们在部署web服务的时候,web容器通常都会记录来自客户端的访问日志.而当我们使用Thrift RPC服务的时候,Thrift服务则不会给我们自动记录客户端的访问日志. 通过这篇文章,你可 ...

  3. DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead

    // 引入mongoose模块 const mongoose = require('mongoose'); // 链接数据库 mongoose.set('useCreateIndex', true)  ...

  4. input、print、字符串格式化输出

    1.使用input(), print()进行用户交互 """ 以前银行取钱只能拿着存折去柜台跟小姐姐交流才可以 你想干嘛 我想取钱 请输入密码 滴滴滴密码 想取多少钱 我 ...

  5. C# Log4net配置文件 总结

    前言 因为项目日志太杂乱而且很大,打开一个就卡死了,何况用户电脑也扛不住日志积累,要做一个日志记录器管理日志.但对里面的配置有一些不熟悉(毕竟都是复制粘贴的),所以记录一下各个项的作用.方便后续复习. ...

  6. 【Azure 云服务】为Azure云服务配置上自签名的SSL证书步骤

    问题描述 在使用Azure Cloud Service(云服务),默认的情况下都是使用的 HTTP 服务,通过 Visual Studio 2022 创建的默认 Cloud Service项目中,在S ...

  7. 【Markdown编辑器】语法规则

    一.Markdown介绍及工具推荐 1.介绍 Markdown是一种轻量级标记语言,它以纯文本形式(易读.易写.易更改)编写文档,并最终以HTML格式发布.Markdown也可以理解为将以MARKDO ...

  8. 《线段树学习笔记》 AC代码索引

    P3372 [模板]线段树 1 | LibreOJ#132. 树状数组 3 :区间修改,区间查询 #include <bits/stdc++.h> #define int long lon ...

  9. Linux的串口非标准波特率设置更改

    用的是全志的R528 SDK,Linux内核是5.4,新增加一个250000的非标准波特率 参考网络大神文档,实践并记录宝贵的经验. 方法: 1.修改内核的/include/uapi/asm-gene ...

  10. Solon Java Framework v1.12.2 发布

    一个更现代感的 Java 应用开发框架:更快.更小.更自由.没有 Spring,没有 Servlet,没有 JavaEE:独立的轻量生态.主框架仅 0.1 MB. @Controller public ...