mirror of
https://github.com/openmlsys/openmlsys-zh.git
synced 2026-04-24 10:34:34 +08:00
Yao recsys dev (#438)
* add rec system * fix * add new figures * fix * update * fix * fix * fix
This commit is contained in:
111
chapter_recommender_system/case_study.md
Normal file
111
chapter_recommender_system/case_study.md
Normal file
@@ -0,0 +1,111 @@
|
||||
## 案例分析:支持在线模型更新的大型推荐系统
|
||||
下面我们分析一个新型的支持低延迟模型更新的推荐系统Ekko :cite:`280902`,从而引入实际部署推荐系统所需要考虑的系统设计知识。Ekko的核心思想是将训练服务器产生的梯度或模型更新立刻发送至所有参数服务器,绕过费时长达数分钟乃至数小时的保存模型检查点、验证模型检查点、广播模型检查点到所有推理数据中心的过程。如此一来,推理服务器每次都能从同一数据中心的参数服务器上读到最新的模型参数。我们将这样的模型更新方式称为在线更新,以区别于上一小节介绍的离线更新,如图 :numref:`online-update`所示。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`online-update`
|
||||
|
||||
### 系统设计挑战
|
||||
相比于离线更新,在线更新避免了费时的存储和验证模型检查点的步骤,然而也带来了新的问题和挑战:
|
||||
|
||||
#### 1. 通过广域网传输海量的模型更新
|
||||
|
||||
在训练数据中心内部,训练服务器通过局域网(LAN)向参数服务器发送模型更新的速度可达几百GB每秒,而不同数据中心之间的网络带宽往往只有数Gbps,而且所有数据中心的网络带宽需要优先满足推理服务的需求——接受用户的推理请求并返回推荐结果。因此留给模型同步的带宽更加有限。
|
||||
|
||||
如果从训练数据中心向所有其他数据中心广播参数更新,会导致训练数据中心成为影响同步速度的瓶颈。假设训练数据中心需要广播一个100GB的模型至5个推理数据中心,训练数据中心可用的带宽为5Gbps,则需要花费800秒时间,这离秒级模型更新的需求还差了两个数量级。
|
||||
|
||||
如果使用如图 :numref:`chain-replication`所示的链式复制 :cite:`186214`,虽然可以避免在训练数据中心出现瓶颈,但是这种方式的更新延迟很大程度上取决于链上最慢的一段网络,导致在广域网的场景下延迟极高。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`chain-replication`
|
||||
|
||||
#### 2. 防范网络拥塞影响推荐质量
|
||||
|
||||
模型跨地域更新的延迟很大程度上取决于网络状况,一旦网络繁忙出现拥塞,则整体更新延迟不可避免会上升,从而影响服务质量。而且采用在线更新的推荐系统更新流量也会有波峰,当模型更新流量波峰叠加网络拥塞,整体更新延迟更是雪上加霜。
|
||||
|
||||
#### 3. 防范有偏差的模型更新影响推荐质量
|
||||
|
||||
模型在线更新带来的一个问题是,不可能单独对每一条更新进行检查以确保其对服务质量不会产生负面影响。因此有偏差的模型更新可能被发送到推理集群中,从而直接影响在线服务质量。而且在大规模在线环境中,出现有偏差的模型更新的概率并不低。
|
||||
|
||||
图 :numref:`system-challenges`总结了在线更新会面临的系统挑战。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`system-challenges`
|
||||
|
||||
### 系统架构
|
||||
针对这些挑战,Ekko提出了如图 :numref:`ekko-overview`所总结的三个核心组件。概括来讲:
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`ekko-overview`
|
||||
|
||||
1. Ekko设计了一套**高性能的点对点(Peer-to-Peer,P2P)模型更新传播算法**,令参数服务器根据不同的网络带宽从同伴(peer)处以自适应的速率拉取模型更新,并且结合推荐模型的特点优化了拉取效率。
|
||||
2. Ekko设计了**服务质量有感的模型更新调度器**来发现那些会对服务质量产生重大影响的模型更新并且将其在点对点传播的过程中加速。
|
||||
3. Ekko设计了**推理模型状态管理器**来监控在线服务的质量并快速回滚被有害更新损害的模型状态以避免SLO(Service-Level Objectives)受到严重影响。
|
||||
|
||||
### 点对点模型更新传播算法
|
||||
Ekko需要支持上千台分布在数个相隔上千公里的数据中心内的参数服务器之间传播模型更新。然而一个超大规模深度学习推荐系统每秒钟可以生成几百GB的模型更新,而数据中心之前的网络带宽仅有100Mbps到1Gbps不等。如果采用已有参数服务器架构,例如Project Adam :cite:`ProjectAdam_186212`的两阶段提交协议,由训练数据中心向其他数据中心发送这些模型更新,不仅训练数据中心的带宽会成为瓶颈,而且整个系统的模型更新速度会受限于最慢的一条网络。同时Ekko的研究人员发现使用深度学习模型的推理服务器并不需要知道参数的更新过程,而仅需要知道参数的最新权重(状态)。有鉴于此,Ekko设计了基于状态的无日志同步算法,如图 :numref:`P2P-replication`所示,令参数服务器之间以自适应的速度相互拉取最新的模型更新。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`p2p-replication`
|
||||
|
||||
|
||||
为了实现点对点无日志同步算法,Ekko首先借鉴已有的版本向量(Version Vector)算法 :cite:`ConciseVV_10.1007/11561927_25,VectorSet_10.1145/1243418.1243427`,为每个参数(即每个键值对)赋予一个版本(Version)。版本可以记录参数的更新时间和地点。此外,Ekko在每个分片内设置一条版本向量(也称之为见闻,Knowledge),用来记录该分片的所有已知版本。通过对比版本号和版本向量,参数服务器可以在不发送参数本身的前提下从同伴处拉取更新的参数状态。对版本向量算法感兴趣的读者可以参考原论文了解细节。
|
||||
|
||||
然而Ekko的研究人员发现,即使使用了版本向量算法,从海量的模型参数中找出被更新的参数依然是非常慢的。为了加速找出被更新的参数的过程,Ekko利用了推荐模型的两个重要的特点。
|
||||
|
||||
1. **更新稀疏性:**虽然一个模型可以有数百GB甚至数TB的嵌入表,但是由于模型训练一般采用小批次的方式,因此每次训练服务器只会更新这一小批次中涉及到的那些嵌入项。从全局来看,一段时间内嵌入表中仅有一小部分参数的状态会被更新。
|
||||
2. **时间局部性:**推荐系统中的模型更新并不是均匀分布在所有参数上的,一些热门的物品和活跃用户所对应的嵌入项在一段时间内会被频繁更新,反之,冷门物品和非活跃用户所对应的嵌入项根本不会被涉及。
|
||||
|
||||
结合这两个特点,Ekko加速比较过程的核心理念是:尽量避免浪费时间去比较那些没有被更新的参数的版本。
|
||||
|
||||
具体来讲,Ekko首先在每个分片内设计了一个**模型更新缓存**,其中保存的是近期刚刚被更新的参数的指针。假设参数服务器A正在试图从参数服务器B中拉取模型更新,如果参数服务器A已经知道所有不在B的缓存中的模型更新,那么A仅需要和B的缓存中的那些参数做比较,就能得到所有自己可能不知道的模型更新。
|
||||
|
||||
除此之外,Ekko还利用以上两个特点,为每个分片添加了一个分片版本(Shard Version),从而可以通过仅仅发送一个64比特的分片向量过滤掉那些根本没有模型更新的分片。分片版本减小的通信量带来的同步速度的提升也是非常显著的,Ekko的消融实验显示分片版本可以将更新延迟从27.4秒降低至6秒。
|
||||
|
||||
考虑到跨地域的网络带宽资源十分紧张,而集群内部的网络带宽相对宽裕,Ekko令每个集群内部选举一个本地领导负责从训练数据中心拉取模型更新,而集群内部的其他参数服务器从本地领导处拉取模型更新。在应用了这个简单但高效的优化之后,Ekko可以更进一步将模型更新延迟从6秒降低至2.6秒。此外,由于Ekko支持非常灵活的通讯拓扑,也可以应用已有的覆盖网络(Network Overlay)技术来进一步更加细致地优化通讯。
|
||||
|
||||
### 模型更新调度器
|
||||
秒级模型更新的服务质量非常容易受到网络延迟的影响,而跨地域数据中心之间出现短暂的网络拥塞并不罕见。Ekko的设计者在实践中观察发现仅有一小部分关键的模型更新对服务质量具有决定性影响。为了最大程度保证在网络拥塞时的模型服务质量,Ekko会根据模型更新对服务质量的影响,赋予不同的优先级,并在点对点传播过程中优先发送这些关键更新。
|
||||
|
||||
具体来讲,Ekko的设计者提出了三种优先级指标来发现对服务质量具有决定性影响的模型更新:
|
||||
|
||||
1. **更新的时新性** 正如前文提到的,如果推荐模型的嵌入表中没有新用户或新物品所对应的嵌入项,那么该用户或物品完全无法受益于推荐模型带来的高服务质量。为了避免这种情况的发生,Ekko对新加入的嵌入项赋予最高优先级,使得这些嵌入项永远以最快的速度传播至所有推理服务集群。
|
||||
2. **更新的显著性** 已有的大量研究都表明,大梯度的模型更新对模型的准确度会产生更加显著的影响,因此Ekko根据更新的幅度\footnote{根据模型的训练方式不同,更新幅度可能是梯度或梯度$\times$学习率}赋予不同模型更新不同的优先值。又因为Ekko服务于多模型场景,不同模型的数据分布不同,Ekko对每个模型在后台分别抽样统计平均更新幅度,每个更新的优先值取决于更新幅度和该模型平均更新幅度的比值。
|
||||
3. **模型的重要性** 在在线服务的多个模型中,每个模型承载的推理流量并不相同,因此在网络拥塞的情况下,Ekko优先保证那些承载着大多数流量的模型的更新。具体来讲,每个更新根据其所属模型的流量比例决定优先值。
|
||||
|
||||
除了以上三种默认的优先级指标,Ekko也允许使用者自定义函数来根据模型自身情况使用其他指标。
|
||||
|
||||
|
||||
|
||||
如图 :numref:`model-update-scheduler`所示,对于每一条模型更新,Ekko根据公式 :eqref`priority`计算其总的优先值,然后和k\%分位阈值做比较,如果大于k\%分位阈值,则视为高优先级,否则为低优先级。K值由使用者设置,而k\%分位阈值采用已有算法根据历史优先值估计。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`model-update-scheduler`
|
||||
|
||||
$$
|
||||
p=(p_g+p_u) \times p_m
|
||||
$$
|
||||
:eqlabel:`priority`
|
||||
|
||||
具有高优先级的模型更新在后续点对点传播过程中会被加速,具体的传播算法见原论文的算法2。
|
||||
|
||||
Ekko的线上实验结果显示,当网络拥塞时,采用服务质量有感的模型更新调度器可以避免超过2\%的服务质量下滑。
|
||||
|
||||
### 模型状态管理器
|
||||
|
||||
为了防止有害的模型更新影响到在线服务质量,Ekko设计了推理模型状态管理器来监控推理模型的健康状态。其核心思想是设置一组基线模型,并从推理请求中分出不到1\%的流量给基线模型,从而可以得到基线模型的服务质量相关指标。如图 :numref:`model-state-manager`所示,推理模型状态管理器中的时序异常检测算法不断监控基线模型和在线模型的服务质量。模型质量的状态可能是健康、未定或者损害,由复制状态机维护。一旦确定在线模型处于损坏状态,首先将被损坏模型的流量切换至其他健康的替换模型上,然后在线回滚模型至健康的状态。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`model-state-manager`
|
||||
|
||||
|
||||
### 小结
|
||||
Ekko已经在生产环境中部署超过一年,服务超过10亿用户。Ekko成功将跨地域数据中心之间的模型平均更新延迟从分钟级别降低到了2.4秒,而在数据中心内部模型平均更新延迟可以低至0.7秒。秒级模型更新对于线上服务质量的提升十分明显,论文中的实验结果显示,仅仅加速多阶段推荐流水线中的一个排序模型,各项关键指标相比于分钟级模型更新就能够提升1.30\%-3.28\%。考虑到Ekko服务的用户规模,这种程度的提升是非常不平凡的,其所带来的收益也是非常可观的。
|
||||
|
||||
总而言之,Ekko提出了一种设计深度学习推荐系统的新思路,通过直接将模型更新发送到所有参数服务器这样一种在线更新的方式绕过了繁琐耗时的中间步骤,从而实现了秒级模型更新,显著提升了在线服务质量。针对在线更新可能带来的风险,Ekko设计了SLO保护机制,并且通过实验证明是行之有效的。这一小节简单介绍了工业界和学术界的前沿研究成果——Ekko的系统设计和背后的设计思想,希望能够给读者带来一些大型深度学习推荐系统设计的思考。受限于篇幅以及考虑到读者的阅读目标,本小节没有详细讨论Ekko的技术细节,如果读者对Ekko的技术设计细节感兴趣可以深入阅读原论文。
|
||||
@@ -1,10 +0,0 @@
|
||||
## 未来可以探索的方向
|
||||
|
||||
为了解决在线深度学习推荐系统的以上几点问题,研究人员也探索了几个潜在的方向。
|
||||
|
||||
- 云--边--端协同推荐系统。随着边缘设备的增加以及用户端设备性能逐渐增强,服务提供者可以通过将部分计算服务从云服务器下放至边缘服务器乃至用户的设备上来提高模型的反应速度。例如,有研究 :cite:`gong2020edgerec`探索了将模型的前几层下放至客户端上,并且利用用户的本地数据进行个性化训练以给出更加准确的推荐结果。当用户的兴趣发生改变时,客户端上的小模型可以实时地更新以响应用户的请求。除此之外,还可以借鉴联邦学习中的概念,例如有研究 :cite:`NEURIPS2020_a1d4c20b`探索了利用知识迁移的方法在云-端之间传递信息。在在线推荐系统中使用这种方法可以彻底解耦云上的大模型与客户端的小模型。
|
||||
|
||||
- 异构硬件多级存储。前文提到GPU显存无法装下完整的模型参数,一些现有的系统 :cite:`MLSYS2020_f7e6c855`为了充分利用GPU的计算优势,采用多级缓存的思想,将部分参数分级存储于显存、主存和固态硬盘上。在他们提出的这个分级系统中,主要解决了缓存策略和异构硬件的适配问题。然而在设计类似的存储系统时,还应该考虑到机器学习模型内在的一些访存特征以进一步优化。Kraken :cite:`9355295`这篇工作讨论了利用机器学习模型的特征对嵌入项的哈希表的存储进行优化的方法。此外,新型硬件的发展为解决大规模推荐模型的高效存储提供了新的可能。比如非易失存储可以作为主存的扩展,进一步提升系统可以支持的模型尺寸。然而目前还没有见到专门为在线机器学习优化的非易失存储系统。另外也有工作 :cite:`MLSYS2021_ec895663`讨论了利用FPGA加速嵌入表的访存并且相比于CPU服务器取得了非常显著的效果。
|
||||
|
||||
|
||||
- 内存高效的嵌入项存储与计算。除了系统上的设计,研究人员也在探索其他算法优化手段来压缩嵌入表的内存需求。直接使用低精度浮点数可以有效降低内存开销,但是还是会对模型的精度产生一定的影响。因此在在线推荐服务这种精度敏感的场景中并不适用。除此之外, :cite:`MLSYS2021_979d472a`利用低秩分解可以将一个大矩阵分解为两个小矩阵(向量)。这种方法可以在保留原矩阵大量信息的前提下显著减小内存开销。除了低秩分解外,还有其他 :cite:`10.1145/3394486.3403059`分解嵌入表的手段。还有研究 :cite:`ginart2021mixed`表明,没有必要为所有的项目都使用一样长的嵌入项,可以根据嵌入项的重要性动态决定其长度以节省内存开销。作为系统设计者,如何将层出不穷的算法优化手段高效地实现是需要考虑的问题。
|
||||
@@ -1,13 +1,17 @@
|
||||
# 深度学习推荐系统
|
||||
|
||||
推荐系统通过对用户特征、历史行为等数据的分析,为用户推荐可能感兴趣的内容、商品或者广告。在信息爆炸的时代,高效且准确的推荐结果极大地提升了在线服务的质量。近年来,基于深度学习的推荐模型由于可以高效地利用在线服务中产生的海量数据,被谷歌、脸书、阿里巴巴等各大公司广泛应用于生产环境中。本节主要介绍深度学习推荐系统在工业界的主流系统架构、问题以及可能的解决方案。
|
||||
推荐模型通过对用户特征、物品特征、用户-物品历史交互行为等数据的分析,为用户推荐可能感兴趣的内容、商品或者广告[^1]。在信息爆炸的时代,高效且准确的推荐结果能够极大地提升用户在使用服务时的体验。近年来,基于深度学习的推荐模型[^2] 由于可以高效地从海量数据中发掘用户的潜在兴趣,被谷歌、脸书、阿里巴巴等各大公司广泛应用于生产环境中。为了支持推荐模型的稳定高质量服务,人们围绕其搭建了一系列组件,这些组件和推荐模型共同构成了庞大而又精巧的深度学习推荐系统。本章主要介绍以深度学习模型为中心的推荐系统的基本组成、运行原理以及其在在线环境中面临的挑战和对应的解决方案。
|
||||
|
||||
```toc
|
||||
:maxdepth: 2
|
||||
|
||||
overview
|
||||
system_architecture
|
||||
system_problem
|
||||
future
|
||||
multi_stage_recommender_system
|
||||
model_update
|
||||
case_study
|
||||
summary
|
||||
```
|
||||
```
|
||||
|
||||
[^1]: 以下统称为“物品”
|
||||
|
||||
[^2]: 以下推荐模型特指基于深度学习的推荐模型
|
||||
44
chapter_recommender_system/model_update.md
Normal file
44
chapter_recommender_system/model_update.md
Normal file
@@ -0,0 +1,44 @@
|
||||
## 模型更新
|
||||
通过以上两节的学习,我们了解了推荐系统的基本组件和运行流程。然而在实际的生产环境中,因为种种原因,推荐系统必须经常性地对模型参数进行更新。在保证上亿在线用户的使用体验的前提下,更新超大规模推荐模型是极具挑战性的。本节首先介绍为何推荐系统需要持续更新模型参数,然后介绍一种主流的离线更新方法,以及一个支持在线更新的推荐系统。
|
||||
|
||||
### 持续更新模型的需求
|
||||
在学习过程中,我们用到的数据集通常都是静态的,例如ImageNet :cite:`russakovsky2015imagenet`,WikiText :cite:`merity2016pointer`。其中的数据分布通常是不变的,因此训练一个模型使其关键指标,如准确率(Accuracy)和困惑度(Perplexity),达到一定要求之后训练任务就结束了。然而在线服务中使用的推荐模型需要面临高度动态的场景。这里的动态主要指两个方面:
|
||||
|
||||
1. 推荐模型所服务的用户和所囊括的物品是在不断变化的,每时每刻都会有新的用户和新的物品。如图 :numref:`user-embedding-missing`所示,如果嵌入表中没有新用户所对应的嵌入项,那么推荐模型就很难服务于这个用户;同理如果新加入的物品没有在推荐模型的嵌入表中,如图 :numref:`content-embedding-missing`所示,就无法出现在推荐流水线中,从而导致不能被推荐给目标用户。
|
||||
2. 推荐模型所面临的用户兴趣是在不断变化的,如果推荐模型不能及时地改变权重以适应用户新的兴趣,那么推荐效果就会下降。例如在一个新闻推荐的应用中,每天的热点新闻都是不一样的,如果推荐模型总是推荐旧的热点,用户的点击率就会持续下降。
|
||||
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`user-embedding-missing`
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`content-embedding-missing`
|
||||
|
||||
|
||||
|
||||
以上问题虽然也可以通过人工制定的规则来处理,例如,在直接在推荐结果中加入新物品,或者基于统计的热点物品,但是这些规则只能在短时间内一定程度上缓解问题,而不能彻底解决问题,因为基于人工规则的推荐性能和推荐模型存在较大差距。
|
||||
|
||||
### 离线更新
|
||||
传统的推荐系统采用基于模型检查点的离线更新的方式,更新频率从每天到每小时不等,如图 :numref:`offline-update`所示。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`offline-update`
|
||||
|
||||
具体来讲,在训练一段时间之后,有如下步骤:
|
||||
|
||||
1. 从训练数据中心的参数服务器上保存一份模型检查点到磁盘中;
|
||||
2. 基于离线数据集对模型检查点进行验证,如果离线验证不通过则继续训练;
|
||||
3. 如果离线验证通过,则将检查点以广播的方式发送到所有的推理数据中心。
|
||||
|
||||
这一流程耗费的时间从数分钟到数小时不等。也有一些系统对保存和发送检查点的过程进行了优化,可以做到分钟级模型更新。
|
||||
|
||||
然而随着互联网服务的进一步发展,分钟级的模型更新间隔在一些场景下依然是远远不够的:
|
||||
|
||||
1. 一些应用非常看重其中物品的实时性。例如在短视频推荐场景下,内容创作者可能会根据实时热点创作视频,如果这些视频不能被及时推荐出去,等热点稍过观看量可能会远远不及预期。
|
||||
2. 无法获取用户特征或者特征有限的场景。近年来,随着用户隐私保护意识的增长和相关数据保护法规的完善,用户常常倾向于匿名使用应用,或者尽量少地提供非必要的数据。这就使得推荐系统需要在用户使用的这段极短的时间内时间内在线学习到用户的兴趣。
|
||||
3. 需要使用在线训练范式的场景。传统的推荐系统通常采用离线训练的方式,即累计一段时间(例如,一天)的训练数据来训练模型,并将训练好的模型在低峰期(例如,凌晨)上线。最近越来越多的研究和实践表明,增大训练频率可以有效提升推荐效果。将训练频率增加到最高的结果就是在线训练,即流式处理训练数据并送给模型,模型持续地基于在线样本调整参数,模型更新被即时用于服务于用户。模型更新作为在线训练的一个主要环节,必须要降低延迟以达到更好的训练效果。
|
||||
|
||||
在下一小节,我们将详细分析一个前沿的推荐系统是如何解决模型快速更新的问题的。
|
||||
88
chapter_recommender_system/multi_stage_recommender_system.md
Normal file
88
chapter_recommender_system/multi_stage_recommender_system.md
Normal file
@@ -0,0 +1,88 @@
|
||||
## 多阶段推荐系统
|
||||
推荐流水线的功能是根据用户请求推荐为其可能感兴趣的物品。具体来说,当用户需要使用推荐服务时向推理服务发送一个推荐请求,其中包括用户ID和当前的上下文特征(例如,用户刚刚浏览过的物品、浏览时长等),推荐流水线将该用户的特征和备选物品特征作为输入,进行计算后得出这名用户对各个备选物品的评分,并选出评分最高的(数十个到数百个)物品作为推荐结果返回。
|
||||
|
||||
一个推荐系统中通常会有多达数十亿的备选物品,如果用一个模型来计算用户对于每个备选物品的评分,必然会导致模型在准确度和速度上做取舍。换句话说,要么选择简单的模型牺牲准确度换取速度——导致用户对推荐结果毫无兴趣;要么选择复杂的模型牺牲速度换取准确度——导致用户因等待时间过长而离开。有鉴于此,现代推荐系统通常以如图 :numref:`recommender-pipeline`所示的流水线的形式部署多个推荐模型。在流水线的最前端,召回(Retrieval)阶段(通常使用结构较为简单、运行速度较快的模型)从所有备选物品中过滤出用户可能感兴趣的数千至数万个物品。接下来排序(Ranking)阶段(通常使用结构更为复杂、运行速度也更慢的模型)对选出的物品进行打分并排序,然后再根据业务场景为用户返回最高分的数十或数百个物品作为推荐结果。当排序模型过于复杂而不能在规定时间内处理所有被召回的物品时,排序阶段可以被进一步细分为:粗排(Pre-ranking),精排(Ranking)和重排(Re-ranking)三个阶段。
|
||||
|
||||
### 推荐流水线概述
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`recommender-pipeline`
|
||||
|
||||
下面几个小节详细将会详细介绍召回和排序阶段的常用模型、训练方法以及关键指标。
|
||||
|
||||
### 召回
|
||||
在召回阶段,模型以用户特征作为输入,从所有备选物品中粗略筛选出一部分用户可能感兴趣的物品作为输出。召回阶段的主要目的是将候选物品范围缩小,减轻下一阶段排序模型的运行负担。
|
||||
|
||||
#### 1. 双塔模型
|
||||
接下来以如图 :numref:`two-tower-model`所示双塔模型 :cite:`yi2019sampling`为例介绍召回的流程。双塔模型具有两个MLP,分别对用户特征和物品特征进行编码,称之为用户塔[^1] 和物品塔。对于输入数据,连续特征可以直接作为MLP的输入,而离散特征需要通过嵌入表映射为一个稠密向量再输入到MLP中。用户塔和物品塔对特征进行处理得到用户向量和物品向量用于表示不同用户或物品。双塔模型使用一个评分函数衡量用户向量和物品向量之间的相似度。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`two-tower-model`
|
||||
|
||||
#### 2. 训练
|
||||
|
||||
%关于如何训练这一模型,一个自然的想法是:每个用户都与所有的物品两两进行评分。然而如前文提及,训练数据集来自以往做出的推荐和用户反馈,同一名用户只可能对少数物品做出过反馈,因此数据集只包含用户与部分物品的互动。此外,召回阶段的备选物品通常很多,两两评分得到的分数矩阵会占用大量内存。所以在实际训练中,我们只选取用户点击了的(用户,物品)对,即正样本作为训练数据集,在训练过程中使用采样器对其他物品进行采样作为负样本。
|
||||
训练时,模型的输入为用户对历史推荐结果的反馈数据,即(用户,物品,标签)对,其中标签表示用户是否点击了物品。一般点击记为1,而未点击记为0。双塔模型使用正样本(即标签为1的样本)作为训练数据。然后使用一种可以纠正采样偏差的批次内采样器在批次内进行采样得到负样本,其算法细节在不是本节介绍的重点,感兴趣的读者可以深入研究原论文。模型输出的结果是用户点击不同物品的概率。训练时选用合适的损失函数使得正样本的预测结果尽可能接近1,而负样本的预测结果尽可能接近0。
|
||||
|
||||
#### 3. 推理
|
||||
|
||||
推理之前,首先使用训练好的模型计算出所有物品的物品向量并保存。这是因为物品的特征是相对稳定的,这样做可以减少推理时的计算开销,从而加快推理速度。而用户特征和用户的使用情况相关,因此当用户请求到达时,双塔模型使用用户塔对当前的用户特征进行计算,得到用户向量。然后使用训练时的评分函数作为相似度的衡量,使用这一用户的用户向量与所有备选物品的物品向量进行相似度搜索。选出相似度最高的一部分物品输出作为召回结果。
|
||||
|
||||
#### 4. 评估指标
|
||||
|
||||
召回模型的常见评估指标是在召回$k$个物品时的召回率(Recall@k),召回$k$个物品时的召回率定义如下:
|
||||
$$
|
||||
\text{Recall@k} = \frac{\text{TP}}{\min(\text{TP} + \text{FN}, k)}
|
||||
$$
|
||||
|
||||
其中,TP、FN分别是真阳性(即召回的$k$个物品中真实标签为1的)和假阴性(即没有被召回的物品中真实标签为1的)。换句话说,召回率衡量的是所有正样本中有多少被模型成功找到了。这里需要注意的是,因为最多只能召回$k$个物品,因此如果正样本数多于$k$,那么最好的情况下也只能找出$k$个。因此分母选择正样本数和$k$中较小的那一个。
|
||||
|
||||
|
||||
### 排序
|
||||
在排序阶段,模型结合用户和物品特征对召回得到的物品逐一打分。分数大小反映了该用户对物品感兴趣的概率。根据排序结果,选取评分最高的一部分物品向用户推荐。
|
||||
|
||||
当推荐模型所需要处理的备选物品越来越多,或者需要加入更为复杂的推荐逻辑和规则时,排序可以进一步细分为三个阶段:粗排、精排和重排:
|
||||
|
||||
1. 粗排在召回与精排之间对物品进行进一步筛选。当有海量的备选物品或者使用了多路召回来增加召回结果的多样性时,召回阶段输出的物品数量依然会非常多。如果全部输入精排模型,会导致精排的耗时极高。因此在推荐流水线中加入粗排阶段可以进一步减少需要被精排的物品。
|
||||
2. 精排是排序最重要的阶段。在精排阶段,模型应尽量准确地反映用户对不同物品的喜好程度。下文中的排序模型均指代精排模型。
|
||||
3. 重排阶段会根据一定的商业逻辑(例如,增加新物品的曝光率或者过滤掉用户已经购买过的物品、看过的视频等)和规则(打乱推荐的物品、减少相似物品推荐)对精排的结果进行进一步处理以从整体上提升推荐服务的质量,而不是仅仅关注单个物品的点击率。
|
||||
|
||||
#### 1. DLRM
|
||||
|
||||
接下来以DLRM :cite:`naumov2019deep`为例,介绍排序模型如何处理特征数据。如图 :numref:`dlrm-model`所示,DLRM包括嵌入表、两层MLP和一层交互层[^2]。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`dlrm-model`
|
||||
|
||||
和双塔模型类似,DLRM首先使用嵌入表将离散特征转化为对应的嵌入项(一条稠密向量),并将所有连续特征连接成一个向量输入底层MLP,处理得到与嵌入项维度相同的一个向量。底层MLP的输出和所有嵌入项一同送进交互层进行交互。
|
||||
|
||||
如图 :numref:`interaction`所示,交互层将所有特征(包括所有嵌入项和经过处理连续特征)进行点积(Dot production)操作,从而得到二阶交叉特征。由于交互层得到的交互特征是对称的,对角线是同一个特征与自己交互的结果,对角线以外的部分,每对不同特征的交互都出现了两次(例如,对于特征$p,q$,会得到$<p,q>, <q,p>$),所以只保留结果矩阵的下三角部分,并将这一部分拉平。拉平后的交叉结果和底层MLP的输出拼接起来,一起作为顶层MLP的输入,顶层MLP的进一步学习后,输出的评分代表用户点击该物品的概率
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`interaction`
|
||||
|
||||
#### 2. 训练方法
|
||||
|
||||
DLRM直接基于(用户,物品,标签)对进行训练。模型将用户和物品特征一起输入,进行交互处理预测出用户点击物品的概率。对于正样本应当令概率尽可能接近1,而负样本接近0。
|
||||
|
||||
#### 3. 训练评估指标
|
||||
|
||||
排序实际上可以被看作一个二分类问题,即将(用户,物品)分类为点击(标签为1)或不点击(标签为0),所以评估排序模型的方法与评估二分类模型类似。但是由于推荐系统数据集通常极度不平衡(正负样本比例悬殊),为了减少数据不平衡对指标的影响,排序模型的常用评估指标为AUC(Area Under Curve, 曲线下面积)和F1评分。
|
||||
其中,AUC是ROC(Receiver Operating Characteristic,受试者工作特征)曲线下的面积,ROC曲线是在选取不同分类阈值时的真阳性率-假阳性率曲线。通过计算AUC和ROC曲线,可以选取合适的分类阈值。如果预测概率大于分类阈值,则认为预测结果为1(点击);否则为0(不点击)。根据预测结果可以算出召回率(recall)和精确率(precision),然后根据公式 :eqref:`f1`计算F1评分。
|
||||
|
||||
$$
|
||||
F1 = 2 \times \frac{recall \times precision}{recall + precision}
|
||||
$$
|
||||
:eqlabel:`f1`
|
||||
|
||||
#### 4. 推理流程
|
||||
|
||||
推理时,首先将召回的物品的特征和相应的该用户的特征拼接起来,然后输入DLRM。根据模型的预测分数,选择概率最高的一部分物品输出。
|
||||
|
||||
[^1]: 原论文中的用户塔还使用了用户观看过的视频的特征作为种子特征。
|
||||
|
||||
[^2]: DLRM允许对模型结构进行定制化,本节以DLRM的默认代码实现为例进行简单介绍。
|
||||
@@ -1,38 +0,0 @@
|
||||
## 背景
|
||||
|
||||
为了方便本节的讨论,我们首先简单介绍一些推荐系统的基本概念,包括三部分:推荐模型的结构,推荐系统的架构,和评估推荐系统的关键指标。
|
||||
|
||||
### 推荐模型
|
||||
基于深度学习的推荐模型在过去几年受到了学术界和工业界的高度关注,得到了快速发展。目前主流的推荐模型 :cite:`10.1145/2988450.2988454,10.1145/3124749.3124754,ijcai2017-239,naumov2019deep`的基本结构可以总结如图 :numref:`ch10-recommendation-models`。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`ch10-recommendation-models`
|
||||
|
||||
|
||||
推荐模型以用户和内容的交互历史、用户属性、内容属性等特征作为输入,令输入特征进行充分相互作用,再将交互结果交由稠密深度神经网络来预测用户点击候选内容的可能性。为了加深读者的对推荐模型的理解,此处我们以Wide & Deep模型 :cite:`10.1145/2988450.2988454`作为例子,深入分析推荐模型的输入特征以及输入特征之间如何交互。由于推荐模型的设计不在本章的讨论范围内,所以下面的介绍中重点介绍模型的基本结构以方便理解推荐系统的设计。对Wide & Deep模型的设计理念、数据生成、数据预处理等细节感兴趣的读者可以自行阅读论文以进一步了解。
|
||||
|
||||
|
||||
Wide & Deep模型是一个设计简洁然而性能优异的模型,由谷歌(Google)在开发并应用于谷歌应用商店中,该模型在谷歌的实际生产环境中可以大幅提升应用的下载率。
|
||||
|
||||
|
||||
Wide & Deep模型的输入数据可以分为两类:连续特征(例如:用户年龄、用户已安装的应用数量、用户参与的会话数量等)和类别特征(例如:用户ID,用户性别属性、用户设备类型、应用ID等)。连续特征的值本身是具有实际意义的数字,可以直接参与后续模型的运算。而类别特征的值并不具有实际意义,所以需要使用嵌入表(Embedding table)将类别特征转化为数字向量,即嵌入项(Embedding item)。
|
||||
|
||||
|
||||
Wide & Deep模型对输入数据进行两部分处理:Wide部分和Deep部分。Wide部分计算用户已安装应用和候选应用的外积(Cross-product)。Deep部分将所有连续特征和类别特征的嵌入项拼接起来输入一个多层感知机(Multilayer perceptron)。Wide部分和Deep部分按照一定规则拼接然后得到最终的输出。
|
||||
|
||||
### 推荐系统
|
||||
|
||||
在实际的生产环境中,除了推荐模型本身,推荐系统通常包括:数据收集、数据处理、数据存储、模型训练、模型存储、模型评估、推理服务等多个子系统。如图 :numref:`ch10-abstract-recommendation-systems`所示,这些子系统之间分工协作、紧密配合,构成一个从用户反馈、到模型更新、再到新推荐结果生成的闭环。下一小节中将以英伟达(NVIDIA)公司的Merlin开源框架 :cite:`Merlin`为例,概括介绍推荐系统流水线上的组件,并重点介绍模型训练、推理子系统的结构。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`ch10-abstract-recommendation-systems`
|
||||
|
||||
### 关键指标
|
||||
|
||||
- **准确性:**
|
||||
深度学习模型给出的推荐结果的准确性是推荐系统需要关注的一个基本指标。然而不同于一般学术论文中使用的基准数据集,生产环境中推荐模型面对的是动态变化的数据分布。例如,每天的热点内容都不尽相同,而且每个用户的兴趣也会不断变化。为了保持模型的性能,推荐系统需要不断根据用户的反馈对已有模型进行更新。
|
||||
|
||||
- **可用性:**
|
||||
除了推荐准确性,对于在线服务的提供者而言,可用性是一个非常关键的指标。当用户需要一个推荐结果时,相比于给用户一个不完全准确的推荐,"无响应"的结果对于用户的体验伤害更大。因此,在某种程度上可以说系统可用性是比推荐结果的准确性更加关键的一个指标。然而这并不意味着准确性不重要,在一定的资源限制下,在线推荐系统的设计者必须谨慎地在准确性和可用性之间进行平衡。例如,使用更宽、更深、更复杂的神经网络模型可能会给出更加准确的推荐结果,但如果其推断延迟高于给定的阈值,那么这样的模型不能直接运用于生产环境中。
|
||||
@@ -1,18 +1,14 @@
|
||||
## 小结
|
||||
|
||||
推荐系统作为深度学习在工业界最成功的落地成果之一,极大地提升了用户的在线服务体验,并且为各大公司创造了可观的利润,然而也带来了许多系统层面的挑战亟待解决。本节简单介绍了典型的工业界推荐系统架构及其面临的挑战,并给出了潜在的解决方案的方向。在实际生产环境中,具体的系统设计方案需要根据不同推荐场景的需求而变化,不存在一种万能的解决方案。
|
||||
推荐系统作为深度学习在工业界最成功的落地成果之一,极大地提升了用户的在线使用体验,并且为各大公司创造了可观的利润,从而促使各大公司持续加大对推荐系统的投入。过去两年推荐模型的规模成指数增长,带来了许多系统层面的挑战亟待解决。在实际的生产环境中面临的问题与挑战是本章区区几千字难以概括的,因此工业级推荐系统的架构必然十分复杂,本章只能抛砖引玉地简单介绍一种典型的推荐系统组成的基本架构和运行过程,并介绍了推荐系统面临的持续更新模型的挑战和一种前沿的解决方案。面对实际生产环境,具体的系统设计方案需要根据不同推荐场景的需求而变化,不存在一种万能的解决方案。
|
||||
|
||||
## 扩展阅读
|
||||
|
||||
- 推荐模型:[Wide & Deep](https://arxiv.org/abs/1606.07792)
|
||||
|
||||
- 开源推荐系统框架:[Merlin](https://irsworkshop.github.io/2020/publications/paper_21_Oldridge_Merlin.pdf)
|
||||
- 消息队列介绍:[什么是消息队列](https://aws.amazon.com/message-queue/)
|
||||
|
||||
- 软硬件协同设计加速超大规模深度学习推荐系统训练:[ZionEX](https://arxiv.org/abs/2104.05158v5)
|
||||
|
||||
- 利用多级缓存支持超大规模深度学习推荐系统训练:[Distributed Hierarchical GPU Parameter Server for Massive Scale Deep Learning Ads Systems](https://arxiv.org/abs/2003.05622)
|
||||
|
||||
- 工业界机器学习系统的实践:[Hidden Technical Debt in Machine Learning Systems](https://papers.nips.cc/paper/2015/hash/86df7dcfd896fcaf2674f757a2463eba-Abstract.html)
|
||||
- 特征存储介绍:[什么是机器学习中的特征存储](https://www.featurestore.org/what-is-a-feature-store)
|
||||
|
||||
## 参考文献
|
||||
|
||||
|
||||
@@ -1,20 +1,68 @@
|
||||
## 主流系统架构
|
||||
## 系统基本组成
|
||||
|
||||
在实际的生产环境中,除了推荐模型本身,一个企业级推荐系统通常包括从用户反馈数据收集,到模型训练,再到服务用户请求的完整流水线(pipeline)。甚至从系统角度来看,推荐模型固然是系统的核心,然而其本身的代码仅占推荐系统的很小一部分,而围绕推荐模型所构建的其他基础设施占据了系统的绝大部分 :cite:`NIPS2015_86df7dcf`。
|
||||
推荐系统的核心模块是其中的推荐模型,其负责根据输入数据找出用户可能感兴趣的物品。为了支持推荐模型的持续、稳定、高质量运行,大型推荐系统还包括了围绕推荐模型搭建了的一系列其他模块。图 :numref:`ch10-recommendation-systems`展示了一个典型的推荐系统的基本组件。首先有一个消息队列接收从推荐服务的客户端上传的日志,其中包括了用户对于此前推荐结果的反馈,例如用户是否点击了推荐的物品。然后数据处理模块对日志中的原始数据进行处理。处理得到新的训练样本写入另一条消息队列中,由训练服务器读取并更新模型参数。主流的推荐模型主要由两部分构成:嵌入表和神经网络。在训练过程中,训练服务器从参数服务器拉取模型参数,计算梯度并将梯度上传回参数服务器,参数服务器聚合各个训练服务器的结果并更新参数。推理服务器负责处理用户请求,根据用户请求从参数服务器拉取对应的模型参数然后计算推荐结果。
|
||||
|
||||
|
||||
本节以英伟达公司的Merlin开源框架 :cite:`Merlin`为例,简单介绍推荐系统的完整流水线以及各个组件在其中的作用,关于Merlin特性的完整介绍请读者参考官方文档。
|
||||
Merlin是英伟达公司开发的一个开源推荐系统框架,帮助使用者构建高效的、基于GPU的推荐系统。Merlin提供三个主要开源组件:NVTabular :cite:`NVTabular`,HugeCTR :cite:`HugeCTR`和Triton :cite:`Triton`,分别对数据处理、模型训练核推理服务进行端到端加速。下面分别展开介绍流水线中的三个主要环节:
|
||||
|
||||
1. 数据处理:推荐系统首先从用户的推荐请求中记录用户的反馈数据(例如,用户是否对推荐结果做出了正向反应)到数据存储系统中。随后数据预处理系统对原始反馈数据进行格式化、清洗、重采样等操作生成训练数据。关于数据处理组件,本书在前面章节进行了详细介绍。在Merlin中,这一步骤由NVTabular负责。同时NVTabular还为多种模型训练框架提供了数据加载器(dataloader)。
|
||||
2. 模型训练:推荐模型每次迭代选择一批训练数据,拉取对应的嵌入项、并送入稠密神经网络,计算损失,然后反向传播计算梯度,最终更新嵌入表和稠密神经网络。正如上文提到的,嵌入表占据了推荐模型绝大部分存储而其更新具有显著的稀疏性,因此推荐系统通常采用上一章介绍的参数服务器架构来存储模型。具体来讲,所有参数被分布存储在一组参数服务器上,而训练服务器根据训练数据从参数服务器上拉取对应的嵌入项和所有稠密神经网络参数。训练服务器本地更新之后将本地梯度或新的参数发送回参数服务器以更新全局参数。全局参数更新可以选择全同步,半同步,或异步更新。为了提升训练的吞吐,可以在训练服务器上缓存一部分参数。HugeCTR为此提供了Embedding Training Cache和GPU embedding cache。为了避免训练服务器和参数服务器之间的通信限制训练吞吐率,一些公司也在探索单机多GPU训练超大规模推荐系统。然而正如前文提到的,即使是单个推荐模型的参数量(~100GB)也超出了目前最新的GPU显存。有鉴于此,脸书(Facebook)公司的定制训练平台 -- ZionEX :cite:`zionex`利用计算设备之间的高速链接将多台设备的存储共享起来可以单机训练TB级推荐模型。然而对于更大规模的模型或中小型企业、实验室,参数服务器架构依然是性价比最高的解决方案。
|
||||
3. 推理服务:类似地,推理服务器在接到一批用户的推荐请求后,从参数服务器拉去相应的嵌入项和稠密神经网络参数来响应用户的请求。推荐系统的推理服务对延迟十分敏感,例如脸书公司的DLRM :cite:`naumov2019deep`基准在MLPerf评测中的服务器延迟限定在30ms[^1]。因此如何在限定延迟(latency-bounded)的情况下尽可能提升吞吐(throughput)是推理服务面临的关键问题。在GPU推理场景下,常见的优化手段有:请求动态合批处理、核融合、低精度部署等 :cite:`10.1145/3437801.3441578,wang-etal-2021-lightseq`. Triton提供了请求调度的功能并且支持多种不同的机器学习框架作为后端。
|
||||
|
||||
|
||||
在工业界,为了提升系统在发生故障的情况下的可用性,以上介绍的各个组件在实际中部署中都应该具备基本的容灾和故障恢复能力。以推理服务为例,在线服务中的深度学习推荐模型通常都采用多副本分布式部署。同一个模型的多个副本通常会被部署在至少两个不同的地理区域内的多个数据中心中,如图 :numref:`ch10-recommendation-systems`所示,以应对大面积停电或者网络中断而导致整个地区的所有副本都不可用。除了容错方面的考虑,部署多个副本还有其他几点优势。首先,将模型部署在靠近用户的云服务器上可以提升响应速度。其次,部署多份副本也可以拓展模型推理服务的吞吐率。
|
||||
|
||||

|
||||

|
||||
:width:`800px`
|
||||
:label:`ch10-recommendation-systems`
|
||||
|
||||
以下各个小节详细介绍推荐系统工作流中的各个组件的功能和特点。
|
||||
|
||||
### 消息队列
|
||||
消息队列(Message Queue)是一种服务(Service)间异步通信的方式,常用于无服务(Serverless)或微服务(Microservices)架构中。
|
||||
|
||||
例如在推荐系统中,各个模块可以部署成一个个相对独立的微服务。客户端向服务器上报的日志(包含用户对推荐结果的反馈)由消息队列负责收集,然后数据处理服务从消息队列中读取原始日志,进行清洗、转化,得到的用户、物品特征存入特征存储中,而得到的训练样本再写入另一条消息队列中等待训练服务器使用。
|
||||
|
||||
消息队列带来的益处非常多,其中之一是允许消息的生产者(Producer),例如客户端的上报组件,和消息的消费者(Consumer),例如服务端的数据处理模块,可以以不同的速率生产消费数据。假设在推荐服务使用的高峰期,用户端产生了大量反馈,如果令数据处理模块直接接受数据,那么很可能因为处理速度跟不上产生速度而导致大量数据被丢弃。即使可以按最高峰的反馈量配置数据处理模块,那么也会导致大部分非高峰期时间资源是浪费的。而消息队列可以在高峰期将用户日志缓存起来,从而使得数据处理模块可以以一个较为恒定且经济的速度处理用户反馈。
|
||||
|
||||
作为分布式系统的重要基础组件,业界已经开发了许多成熟的消息队列系统,例如RabbitMQ,Kafka,Pulsar等。限于篇幅和主题,本节无法详细介绍消息队列的各个方面,感兴趣的读者可以参考这些开源系统的文档或者拓展阅读中给出的资料深入学习。
|
||||
|
||||
|
||||
### 特征存储
|
||||
特征存储是存储并组织特征的地方,被用于模型训练和推理服务中。
|
||||
|
||||
前文提到数据处理模块从消息队列中读取原始日志,例如日志中包含用户性别信息可能是“男”“女”,“未知”中的一种。这样的原始特征无法直接输入推荐模型中使用,因此数据处理模块对其进行简单的映射转化:“男” –> 0,“女”-> 1,“未知”-> 2。经过这样转化之后,性别特征就可以被数据处理模块或者推荐模型所使用。转化后的特征被存入特征存储中。一种典型的特征存储格式如图 :numref:`feature-store`所示,当训练或推理模块需要用到用户特征时,只需要知道用户ID就可以从特征存储中查询到所有需要的特征。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`feature-store`
|
||||
|
||||
使用特征存储的一个显著优势是复用数据处理模块的结果并减少存储冗余,即避免每个模块都要单独对原始数据进行加工处理并维护一个数据存储系统来保存可能会用到的特征。然而其带来的一个更大的益处是可以保证整个系统中的各个组件拥有一致的特征视图。设想一个极端场景,假如训练模块自己维护的数据库中性别“男”对应的值是1,而“女”对应0,而推理模块恰好相反,这样会导致模型推理得到灾难性的结果。
|
||||
|
||||
特征存储是机器学习系统中的重要基础组件,工业界有许多成熟的产品,例如SageMaker,Databricks等,也有许多优秀的开源系统,例如Hopsworks,Feast等。关于特征存储更加详细的介绍可以参考拓展阅读中提供的资料。
|
||||
|
||||
|
||||
### 稠密神经网络
|
||||
稠密神经网络(Dense Neural Network,DNN)是推荐模型的核心,负责探索各个特征之间隐含的联系从而为用户推荐出可能感兴趣的物品。一般在推荐系统中,简单的多层感知机(Multilayer Perceptron,MLP)模型就已经显示出了强大的效果并被应用在谷歌 :cite:`cheng2016wide`、Meta :cite:`naumov2019deep`等各大公司的推荐模型中。虽然MLP的大矩阵相乘操作属于计算密集型任务,对于计算能力要求很高,但是推荐模型中的MLP尺寸一般不超过数MB,对存储要求不高。
|
||||
|
||||
虽然MLP已经取得了不错的效果,在推荐系统领域,近年来应用各种新型深度神经网络的尝试从未止步,更加精巧复杂的网络结构层出不穷,近年来也有工作尝试应用Transformer模型完成推荐任务 :cite:`de2021transformers4rec`。在可以预见的未来,推荐模型中的稠密神经网络也必然会增长到数GB乃至TB。
|
||||
|
||||
### 嵌入表
|
||||
嵌入表是几乎所有推荐模型的共有组件,负责将无法直接参与计算的离散特征数据,例如:用户和物品ID、用户性别、物品类别等,转化为高维空间中的一条向量。推荐模型中的嵌入表的结构和自然语言处理模型中的类似,不同的是自然语言处理模型中的深度神经网络贡献了主要的参数量,而在推荐模型中,如图 :numref:`recommendation-models`所示,嵌入表贡献主要的参数量。这是因为,推荐系统中有大量的离散特征,而每个离散特征的每一种可能的取值都需要有对应的嵌入项。例如,性别特征的取值可能是“女”,“男”,“未知”,则需要三个嵌入项。假设每条嵌入项是一个64维的单精度浮点数向量,如果一个推荐系统服务一亿用户,那么仅仅对应的用户嵌入表(其中的每条嵌入项对应一个用户)的大小就有$4*64*10^8~=23.8$GB。除了用户嵌入表,还有商品嵌入表(其中的每条嵌入项对应一个商品),以及用户和商品的各项特征的嵌入表。总的嵌入表大小可以轻易达到几百GB甚至几十TB。
|
||||
而正如上文提到的,推荐系统中通常用的MLP模型尺寸较小。例如一个在Ali-CCP数据集 :cite:`ma2018entire`上训练的DLRM :cite:`naumov2019deep`的嵌入表大小超过1.44GB,而稠密神经网络仅有大约100KB。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`recommendation-models`
|
||||
|
||||
在推荐系统中,人们通常使用存算分离的参数服务器架构来服务推荐模型。尽管嵌入表占据了推荐模型的主要存储空间,但是其计算却是十分稀疏的。这是因为无论是在训练还是推理过程中,数据都是以小批次的形式依次计算。而在一个批次的计算过程中,只有涉及到的那些嵌入项才会被访问到。假设在一个服务一亿用户的推荐系统每次处理1000条用户的请求,那么一次只有大约十万分之一的嵌入项会被访问到。因此负责计算推荐结果的服务器(训练服务器或者推理服务器)根本没有必要存储所有的嵌入表。
|
||||
|
||||
|
||||
### 训练服务器
|
||||
因为深度学习推荐系统同时具有存储密集(嵌入表)和计算密集(深度神经网路)的特点,工业界通常使用参数服务器架构来支持超大规模推荐模型的训练和推理。参数服务器架构包含训练服务器、参数服务器和推理服务器。本书 :ref:`parameter_servers`章详细介绍了参数服务器架构,因此本节只重点介绍参数服务器架构具体在推荐系统中的功能。
|
||||
|
||||

|
||||
:width:`800px`
|
||||
:label:`parameter-server-in-recommendation`
|
||||
|
||||
在推荐系统中,训练服务器从消息队列中读取一个批次的数据,然后从参数服务器上拉取对应的嵌入项和深度神经网络,得出推荐结果、计算损失、进行反向传播得到梯度。参数服务器从所有训练服务器处收集梯度,聚合得到新的参数。这就完成了一轮模型训练。
|
||||
|
||||
由于参数服务器要聚合所有训练服务器的梯度,为了避免网络延迟导致的掉队者严重影响训练效率,通常一个模型的所有训练服务器位于同一个数据中心中。我们将这个数据中心称之为训练数据中心。
|
||||
|
||||
### 参数服务器
|
||||
在推荐系统中,参数服务器除了协调训练过程,还要负责支持模型推理。在模型推理过程中,推理服务器需要访问参数服务器上的模型参数以计算推荐结果。因此为了降低推理过程的延迟,通常会在推理服务器所在的数据中心(以下称之为推理数据中心)中的参数服务器上保存至少一份模型参数的副本,结构如图 :numref:`parameter-server-in-recommendation`所示。这种做法还有利于容灾——当一个数据中心因为某些原因被迫下线无法访问时,可以将用户请求重定向至其他的推理数据中心。
|
||||
|
||||
### 推理服务器
|
||||
推荐系统中的推理服务器负责从客户端接受用户的推荐请求,然后根据请求从参数服务器拉取模型参数,从特征存储中拉取用户和物品特征,然后计算推荐结果。本节为了方便理解,假设用户请求由一个推理服务器处理,实际上在大规模推荐系统中,推理结果由(多个推理服务器上的)多个模型组成的推荐流水线给出。具体的细节将会在下一节多阶段推荐系统中介绍。
|
||||
|
||||
[^1]: https://mlcommons.org/en/inference-datacenter-11/
|
||||
@@ -1,11 +0,0 @@
|
||||
## 现有解决方案及其存在的问题
|
||||
|
||||
在线服务系统的两个主要诉求:
|
||||
|
||||
- 大模型的高效存储。
|
||||
为了提升训练和推理的性能,通常推荐模型全部存储在内存中,然而纯内存存储对于内存的需求极高。推荐模型的输入中包含大量无法直接进行矩阵运算的类别数据,而由于每种类别数据包含的每种情况都需要一个单独的嵌入项来表示,而稠密深度神经网络的参数可以共享,在大规模推荐模型中,嵌入表占据了绝大部分内存 :cite:`MLSYS2021_979d472a,MLSYS2020_f7e6c855`。举例说明,假设一个推荐模型需要处理1亿条短视频内容,而每条短视频对应的嵌入项为一个64维的32位浮点数向量,那么仅该内容嵌入表就需要占据大约24GB内存。如果考虑到用户标识符等其他嵌入表,那么单个模型可以轻易占据近100GB内存。而在工业界生产环境中,TB级的推荐模型 :cite:`MLSYS2020_f7e6c855`也是非常常见的。此外,在线推荐系统中需要同时运行多个模型负责不同的服务,甚至同一个服务也会上线多个模型以供算法开发人员验证不同的模型结构或者训练策略,因此系统中通常会同时存在上百个超大模型。综上所述,在线推荐系统亟需既能拓展存储容量,又不会影响训练和推理性能的存储解决方案。
|
||||
|
||||
- 大模型的快速更新。
|
||||
在线服务系统所面对的环境是复杂多变的,因此其中的机器学习模型必须不断更新以应对新的数据分布。以一个短视频推荐系统为例,其面对的变化主要来自三点。首先,每时每刻都有大量的新视频上传,这些新视频的特征分布和模型训练时所见到的数据不同;其次,对于不断加入的新用户,模型难以直接给出最优的推荐结果;最后,全部用户和内容之间的交互在不断改变,表现为热点视频在持续变化。因此,为了应对以上变化,在线服务中不可能奢望仅仅训练一次模型就能够一劳永逸地解决问题。目前业界主流的做法是利用新产生的数据不断地增量式更新所部属的模型。在学术界和工业界大量的研究和实践 :cite:`10.1145/2020408.2020444,10.1145/2648584.2648589,10.1145/3267809.3267817,9355295`中都发现模型更新可以有效缓解概念漂移带来的危害,而且更新的频率越高,模型的性能越好。
|
||||
|
||||
在线推荐系统对跨地域地部署的大模型进行快速更新的需求在现有的系统中很难得到满足。一种最直观的解决方案是周期性地将训练服务器上的模型参数发给所有副本。然而这种方式面临着非常大的资源瓶颈。我们以网络开销为例进行分析。假设负责训练的参数服务器存储有100GB的参数,每10分钟将所有参数(在训练集群内部,模型更新的速度极快,10分钟足够将所有参数更新多次)发给其余2个副本。这就需要至少2.6Gbps的网络带宽。然而我们的分析只是最基本的情况,没有考虑网络传输的额外开销以及可能出现的失败重传,也没有考虑需要水平扩展至更多副本、更大模型、更高的更新频率的情况。为了缓解网络瓶颈,人们不得不选择以更慢的速度更新更大的模型,或者限制模型大小以追求更快的更新速度。简单的广播模型参数除了会有很大的资源瓶颈,还无法保证多副本之间的一致性。然而如果采用先前的数据库系统来保证一致性,只能使得资源开销更加严重,进一步限制系统的规模和效率。
|
||||
Reference in New Issue
Block a user