mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-19 23:53:47 +08:00
del
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
<audio id="audio" title="28 | 业界经典:YouTube深度学习推荐系统的经典架构长什么样?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/61/61/61d588cff12fd6709a50bf1cb0340c61.mp3"></audio>
|
||||
|
||||
你好,我是王喆。今天我们一起来开启前沿拓展篇的学习。
|
||||
|
||||
如果你是跟着课程安排学到这里的,我可以很自信地说,你几乎已经掌握了推荐系统的全部重点知识。从数据特征的处理,模型构建,到模型的评估和上线,再到推荐服务器的实现,你的知识广度已经覆盖了推荐系统领域的全部要点。但要想成为一名合格的推荐工程师,我们还需要做两件事情,一件是追踪前沿,另一件是融会贯通。
|
||||
|
||||
因此,在这一篇中,我会通过详细讲解几个一线大厂的推荐系统解决方案,来帮你追踪行业的热点、创新点。它们既包括一些推荐模型的业界实现,如YouTube和Pinterest的推荐模型,也包括推荐系统的工程落地方案,如Flink的经典应用和美团对于强化学习的落地方案。最后,我还会对算法工程师的所需能力做一个全面的总结。
|
||||
|
||||
今天,我们今天先来学习YouTube的经典深度学习推荐系统架构。YouTube这套深度学习解决方案,已经经典到可以成为一个业界标杆式的方案了,也是我在国内外和同学、同事们交流、讨论的时候经常会提到的方案。
|
||||
|
||||
话不多说,我们正式开始今天的学习吧!
|
||||
|
||||
## YouTube推荐系统架构
|
||||
|
||||
提起YouTube,我想你肯定不会陌生,作为全球最大的视频分享网站,YouTube平台中几乎所有的视频都来自UGC(User Generated Content,用户原创内容),这样的内容产生模式有两个特点:
|
||||
|
||||
- 一是其商业模式不同于Netflix,以及国内的腾讯视频、爱奇艺这样的流媒体,这些流媒体的大部分内容都是采购或自制的电影、剧集等头部内容,而YouTube的内容都是用户上传的自制视频,种类风格繁多,头部效应没那么明显;
|
||||
- 二是由于YouTube的视频基数巨大,用户难以发现喜欢的内容。
|
||||
|
||||
这样的内容特点简直就是深度学习推荐系统最适合扎根的土壤,所以YouTube也是最早落地深度学习的一线公司。那YouTube的深度学习推荐系统架构长什么样呢?
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/47/05/47c0fa06ffc18912b027fe920ac30905.jpg" alt="" title="图1 YouTube推荐系统整体架构">
|
||||
|
||||
上图就是YouTube在2016年发布的推荐系统架构。我们可以看到,为了对海量的视频进行快速、准确的排序,YouTube也采用了经典的召回层+排序层的推荐系统架构。
|
||||
|
||||
**它的推荐过程可以分成二级。第一级是用候选集生成模型(Candidate Generation Model)完成候选视频的快速筛选,在这一步,候选视频集合由百万降低到几百量级,这就相当于经典推荐系统架构中的召回层。第二级是用排序模型(Ranking Model)完成几百个候选视频的精排,这相当于经典推荐系统架构中的排序层。**
|
||||
|
||||
无论是候选集生成模型还是排序模型,YouTube都采用了深度学习的解决方案。下面,就让我们详细讲讲这两个深度学习模型是如何构建起来的。
|
||||
|
||||
## 候选集生成模型
|
||||
|
||||
首先,是用于视频召回的候选集生成模型,它的模型架构如下图所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/69/cf/6968873184cf93194aa476398c2e35cf.jpg" alt="" title="图2 YouTube候选集生成模型架构">
|
||||
|
||||
我们一起自下而上地好好看一看这个模型的结构。
|
||||
|
||||
最底层是它的输入层,输入的特征包括用户历史观看视频的Embedding向量,以及搜索词的Embedding向量。对于这些Embedding特征,YouTube是利用用户的观看序列和搜索序列,采用了类似Item2vec的预训练方式生成的。
|
||||
|
||||
当然,我们也完全可以采用Embedding跟模型在一起End2End训练的方式来训练模型。至于预训练和End2End训练这两种方式孰优孰劣,我们也探讨过很多次了,你可以自己再深入思考一下。
|
||||
|
||||
除了视频和搜索词Embedding向量,特征向量中还包括用户的地理位置Embedding、年龄、性别等特征。这里我们需要注意的是,对于样本年龄这个特征,YouTube不仅使用了原始特征值,还把经过平方处理的特征值也作为一个新的特征输入模型。
|
||||
|
||||
这个操作其实是为了挖掘特征非线性的特性,当然,这种对连续型特征的处理方式不仅限于平方,其他诸如开方、Log、指数等操作都可以用于挖掘特征的非线性特性。具体使用哪个,需要我们根据实际的效果而定。
|
||||
|
||||
确定好了特征,跟我们之前实践过的深度学习模型一样,这些特征会在concat层中连接起来,输入到上层的ReLU神经网络进行训练。
|
||||
|
||||
三层ReLU神经网络过后,YouTube又使用了softmax函数作为输出层。值得一提的是,**这里的输出层不是要预测用户会不会点击这个视频,而是要预测用户会点击哪个视频**,这就跟我们之前实现过的深度推荐模型不一样了。
|
||||
|
||||
比如说,YouTube上有100万个视频,因为输出层要预测用户会点击哪个视频,所以这里的sofmax就有100万个输出。因此,这个候选集生成模型的最终输出,就是一个在所有候选视频上的概率分布。为什么要这么做呢?它其实是为了更好、更快地进行线上服务,这一点我们等会再详细讲。
|
||||
|
||||
总的来讲,YouTube推荐系统的候选集生成模型,是一个标准的利用了Embedding预训练特征的深度推荐模型,它遵循我们之前实现的Embedding MLP模型的架构,只是在最后的输出层有所区别。
|
||||
|
||||
## 候选集生成模型独特的线上服务方法
|
||||
|
||||
好,现在我们就详细说一说,为什么候选集生成模型要用“视频ID”这个标签,来代替“用户会不会点击视频”这个标签作为预测目标。事实上,这跟候选集生成模型独特的线上服务方式紧密相关。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e9/69/e9a20bc7260296e09078509e3f42df69.jpg" alt="" title="图3 模型服务部分示意图">
|
||||
|
||||
细心的同学可能已经留意到,架构图左上角的模型服务(Serving)方法与模型训练方法完全不同。在候选集生成模型的线上服务过程中,YouTube并没有直接采用训练时的模型进行预测,而是采用了一种最近邻搜索的方法,我们曾经在[第12讲](https://time.geekbang.org/column/article/301739)详细讲过基于Embedding的最近邻搜索方法,不记得的同学可以先去回顾一下。
|
||||
|
||||
具体来说,在模型服务过程中,网络结构比较复杂,如果我们对每次推荐请求都端到端地运行一遍模型,处理一遍候选集,那模型的参数数量就会巨大,整个推断过程的开销也会非常大。
|
||||
|
||||
** 因此,在通过“候选集生成模型”得到用户和视频的Embedding后,我们再通过Embedding最近邻搜索的方法,就可以提高模型服务的效率了。这样一来,我们甚至不用把模型推断的逻辑搬上服务器,只需要将用户Embedding和视频Embedding存到特征数据库就行了。**再加上可以使用局部敏感哈希这类快速Embedding查找方法,这对于百万量级规模的候选集生成过程的效率提升是巨大的。
|
||||
|
||||
那么问题又来了,这里的用户Embedding和视频Embedding到底是从哪里来的呢?这个问题的答案就是,候选集生成模型为什么要用视频ID作为多分类输出的答案了。我们再仔细看一下图2的架构,架构图中从softmax向模型服务模块画了个箭头,用于代表视频Embedding向量的生成。
|
||||
|
||||
由于最后的输出层是softmax,而这个softmax层的参数本质上就是一个m x n维的矩阵,其中m指的是最后一层红色的ReLU层的维度m,n指的是分类的总数,也就是YouTube所有视频的总数n。因此,视频Embedding就是这个m x n维矩阵的各列向量。
|
||||
|
||||
这样的Embedding生成方法其实和word2vec中词向量的生成方法是相同的,你也可以参考[第6讲](https://time.geekbang.org/column/article/295939)的内容来理解它。
|
||||
|
||||
清楚了视频Embedding的生成原理,用户Embedding的生成就非常好理解了,因为输入的特征向量全部都是用户相关的特征,一个物品和场景特征都没有,所以在使用某用户u的特征向量作为模型输入时,最后一层ReLU层的输出向量就可以当作该用户u的Embedding向量。
|
||||
|
||||
在模型训练完成后,逐个输入所有用户的特征向量到模型中,YouTube就可以得到所有用户的Embedding向量,之后就可以把它们预存到线上的特征数据库中了。
|
||||
|
||||
在预测某用户的视频候选集时,YouTube要先从特征数据库中拿到该用户的Embedding向量,再在视频Embedding向量空间中,利用局部敏感哈希等方法搜索该用户Embedding向量的K近邻,这样就可以快速得到k个候选视频集合。这就是整个候选集生成模型的训练原理和服务过程。
|
||||
|
||||
到这里,你一定已经体会到了咱们前沿拓展篇案例分析的作用,通过一个YouTube候选集生成模型的原理分析,我们就已经把第6讲的Embedding、[第10讲](https://time.geekbang.org/column/article/299326)的特征数据库、第12讲的局部敏感哈希,以及[第17讲](https://time.geekbang.org/column/article/309846)的Embedding MLP模型都回顾了一遍。
|
||||
|
||||
如果你喜欢这种通过学习业界实践方案,把知识串联起来的方式,可以给我留言反馈,我也会在之后的课程中多采用这样的方式。
|
||||
|
||||
## 排序模型
|
||||
|
||||
通过候选集生成模型,YouTube已经得到了几百个候选视频的集合了,下一步就是利用排序模型进行精排序。下图就是YouTube深度学习排序模型的架构,我们一起来看一看。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/28/1a/28e0acbb64760670ee94d015025da81a.jpg" alt="" title="图3 YouTube的深度学习排序模型的架构">
|
||||
|
||||
第一眼看上去,你可能会认为排序模型的网络结构与候选集生成模型没有太大区别,在模型结构上确实是这样的,它们都遵循Embedding MLP的模型架构。但是我们来看其中的细节,特别是输入层和输出层的部分,它们跟候选集生成模型还是有很大不同的,这就是我们要重点关注的。
|
||||
|
||||
我们先看输入层,相比于候选集生成模型需要对几百万候选集进行粗筛,排序模型只需对几百个候选视频进行排序,因此可以引入更多特征进行精排。具体来说,YouTube的输入层从左至右引入的特征依次是:
|
||||
|
||||
1. impression video ID embedding:当前候选视频的Embedding;
|
||||
1. watched video IDs average embedding:用户观看过的最后N个视频Embedding的平均值;
|
||||
1. language embedding:用户语言的Embedding和当前候选视频语言的Embedding;
|
||||
1. time since last watch:表示用户上次观看同频道视频距今的时间;
|
||||
1. #previous impressions:该视频已经被曝光给该用户的次数;
|
||||
|
||||
上面5个特征中,前3个Embedding特征的含义很好理解,我就不细说了。第4个特征和第5个特征,因为很好地引入了YouTube工程师对用户行为的观察,所以我来重点解释一下。
|
||||
|
||||
第4个特征 **time since last watch**说的是用户观看同类视频的间隔时间。如果从用户的角度出发,假如某用户刚看过“DOTA比赛经典回顾”这个频道的视频,那他很大概率会继续看这个频道的其他视频,该特征就可以很好地捕捉到这一用户行为。
|
||||
|
||||
第5个特征**#previous impressions** 说的是这个视频已经曝光给用户的次数。我们试想如果一个视频已经曝光给了用户10次,用户都没有点击,那我们就应该清楚,用户对这个视频很可能不感兴趣。所以**#previous impressions** 这个特征的引入就可以很好地捕捉到用户这样的行为习惯,避免让同一个视频对同一用户进行持续的无效曝光,尽量增加用户看到新视频的可能性。
|
||||
|
||||
把这5类特征连接起来之后,需要再经过三层ReLU网络进行充分的特征交叉,然后就到了输出层。这里我们要重点注意,排序模型的输出层与候选集生成模型又有所不同。不同主要有两点:**一是候选集生成模型选择了softmax作为其输出层,而排序模型选择了weighted logistic regression(加权逻辑回归)作为模型输出层;二是候选集生成模型预测的是用户会点击“哪个视频”,排序模型预测的是用户“要不要点击当前视频”。**
|
||||
|
||||
那么问题来了,YouTube为什么要这么做呢?
|
||||
|
||||
其实,排序模型采用不同输出层的根本原因就在于,YouTube想要更精确地预测用户的观看时长,因为观看时长才是YouTube最看中的商业指标,而使用Weighted LR作为输出层,就可以实现这样的目标。
|
||||
|
||||
这是怎么做到的呢?在Weighted LR的训练中,我们需要为每个样本设置一个权重,权重的大小,代表了这个样本的重要程度。为了能够预估观看时长,YouTube将正样本的权重设置为用户观看这个视频的时长,然后再用Weighted LR进行训练,就可以让模型学到用户观看时长的信息。
|
||||
|
||||
这是因为观看时长长的样本更加重要,严格一点来说,就是观看时长长的样本被模型预测的为正样本的概率更高,这个概率与观看时长成正比,这就是使用Weighted LR来学习观看时长信息的基本原理。
|
||||
|
||||
最后,我们再聊一聊排序模型的模型服务方法。我刚才讲过了,候选集生成模型是可以直接利用用户Embedding和视频Embedding进行快速最近邻搜索的。那排序模型还能这样做吗?
|
||||
|
||||
这就不可以了,原因有两点:一是因为我们的输入向量中同时包含了用户和视频的特征,不再只是单纯的用户特征。这样一来,用户x物品特征的组合过多,就无法通过预存的方式保存所有模型结果;二是因为排序模型的输出层不再是预测视频ID,所以我们也无法拿到视频Embedding。因此对于排序模型,我们必须使用TensorFlow Serving等模型服务平台,来进行模型的线上推断。
|
||||
|
||||
到这里,我们就讲完了YouTube推荐模型的全部细节。如果你有任何疑惑的地方,可以在留言区提问,同时我也建议你多看几遍这节课的内容,因为这个解决方案真的是太经典了。
|
||||
|
||||
## 小结
|
||||
|
||||
好了,这节课的内容讲完了,我们再总结一下YouTube推荐系统的重点知识。
|
||||
|
||||
YouTube推荐系统的架构是一个典型的召回层加排序层的架构,其中候选集生成模型负责从百万候选集中召回几百个候选视频,排序模型负责几百个候选视频的精排,最终选出几十个推荐给用户。
|
||||
|
||||
候选集生成模型是一个典型的Embedding MLP的架构,我们要注意的是它的输出层,它是一个多分类的输出层,预测的是用户点击了“哪个”视频。在候选集生成模型的serving过程中,需要从输出层提取出视频Embedding,从最后一层ReLU层得到用户Embedding,然后利用最近邻搜索快速得到候选集。
|
||||
|
||||
排序模型同样是一个Embedding MLP的架构,不同的是,它的输入层包含了更多的用户和视频的特征,输出层采用了Weighted LR作为输出层,并且使用观看时长作为正样本权重,让模型能够预测出观看时长,这更接近YouTube要达成的商业目标。
|
||||
|
||||
好了,这些关键知识点,我也总结在了下面的表格中,希望它能帮助你加深记忆。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/60/2e/60509d00835ac95ayya3bdeb17f0532e.jpeg" alt="">
|
||||
|
||||
在这节课结束前,关于YouTube的推荐模型我还想多说几句。事实上,YouTube的推荐系统论文中还包含了更多的细节,业界真正好的论文并不多,YouTube的这篇《Deep Neural Networks for YouTube Recommendations》绝对是不可多得的一篇,我甚至推荐大家逐句来读,抓住每一个细节。
|
||||
|
||||
当然,你也可以在我的书《深度学习推荐系统》中的相应章节找到更多的实现细节。这些内容让我曾经受益匪浅,相信也会对你有所帮助。
|
||||
|
||||
## 课后思考
|
||||
|
||||
YouTube的排序模型和候选集生成模型,都使用了平均池化这一操作,来把用户的历史观看视频整合起来。你能想到更好的方法来改进这个操作吗?
|
||||
|
||||
期待在留言区看到你的思考和总结,我们下节课见!
|
||||
123
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/29 | 图神经网络:Pinterest是如何应用图神经网络的?.md
Normal file
123
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/29 | 图神经网络:Pinterest是如何应用图神经网络的?.md
Normal file
@@ -0,0 +1,123 @@
|
||||
<audio id="audio" title="29 | 图神经网络:Pinterest是如何应用图神经网络的?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d7/ae/d72b01f17b2e18bbd2bab18e291e05ae.mp3"></audio>
|
||||
|
||||
你好,我是王喆。
|
||||
|
||||
互联网中到处都是图结构的数据,比如我们熟悉的社交网络,最近流行的知识图谱等等,这些数据中包含着大量的关系信息,这对推荐系统来说是非常有帮助的。
|
||||
|
||||
为了能更好地利用这些信息进行推荐,各大巨头可谓尝试了各种办法,比如我们之前学过的DeepWalk、Node2Vec这些非常实用的Graph Embedding方法。但是技术的发展永无止境,最近两年,GNN(Graph Nerual Netwrok,图神经网络)毫无疑问是最火热、最流行的基于图结构数据的建模方法。严格一点来说,图神经网络指的就是可以直接处理图结构数据的神经网络模型。
|
||||
|
||||
在诸多GNN的解决方案中,著名的社交电商巨头Pinterest对于GraphSAGE的实现和落地又是最为成功的,在业界的影响力也最大。所以,这节课我们就学一学GraphSAGE的技术细节,看一看Pinterest是如何利用图神经网络进行商品推荐的。
|
||||
|
||||
## 搭桥还是平推?技术途径上的抉择
|
||||
|
||||
在正式开始GraphSAGE的讲解之前,我想先给你讲一讲DeepWalk、Node2vec这些Graph Embedding方法和GNN之间的关系,这有助于我们理解GNN的原理。
|
||||
|
||||
我们这里简单回顾一下DeepWalk和Node2vec算法的基本流程,如下面的图1所示。它们在面对像图1b这样的图数据的时候,其实没有直接处理图结构的数据,而是走了一个取巧的方式,先把图结构数据通过随机游走采样,转换成了序列数据,然后再 用诸如Word2vec这类序列数据Embedding的方法生成最终的Graph Embedding。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/1f/ed/1f28172c62e1b5991644cf62453fd0ed.jpeg" alt="" title="图1 基于随机游走的Graph Embedding算法">
|
||||
|
||||
我把这类Graph Embedding的方法归类为基于随机游走的间接性Graph Embedding方法。它其实代表了我们在解决一类技术问题时的思路,**就是面对一个复杂问题时,我们不直接解决它,而是“搭一座桥”,通过这座桥把这个复杂问题转换成一个简单问题,因为对于简单问题,我们有非常丰富的处理手段。这样一来,这个复杂问题也就能简单地解决了。**显然,基于随机游走的Graph Embedding方法就是这样一种“搭桥”的解决方案。
|
||||
|
||||
但搭桥的过程中难免会损失一些有用的信息,比如用随机游走对图数据进行抽样的时候,虽然我们得到的序列数据中还包含了图结构的信息,但却破坏了这些信息原始的结构。
|
||||
|
||||
正因为这样,很多研究者、工程师不满足于这样搭桥的方式,而是希望造一台“推土机”,把这个问题平推过去,直接解决它。GNN就是这样一种平推解决图结构数据问题的方法,它直接输入图结构的数据,产生节点的Embedding或者推荐结果。当然,不同研究者打造这台推土机的方式各不相同,我们今天要重点介绍的GraphSAGE,就是其中最著名的一台,也最具参考价值。
|
||||
|
||||
## GraphSAGE的主要步骤
|
||||
|
||||
下面,我们就来详细讲一讲GraphSAGE的细节。GraphSAGE的全称叫做Graph Sample and Aggregate,翻译过来叫“图采样和聚集方法”。其实这个名称就很好地解释了它运行的过程,就是先“采样”、再“聚集”。
|
||||
|
||||
这时候问题又来了,这里的“采样”还是随机游走的采样吗?要是还通过采样才能得到样本,我们造的还能是“推土机”吗,不就又变成搭桥的方式了吗?别着急,等我讲完GraphSAGE的细节,你就明白了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/c1/25/c1d474d94b5d1dd56591ef55d58d5d25.jpeg" alt="" title="图2 GraphSAGE的主要过程 [br](出自论文 Inductive Representation Learning on Large Graphs)">
|
||||
|
||||
GraphSAGE的过程如上图所示,主要可以分为3步:
|
||||
|
||||
1. 在整体的图数据上,从某一个中心节点开始采样,得到一个k阶的子图,示意图中给出的示例是一个二阶子图;
|
||||
1. 有了这个二阶子图,我们可以先利用GNN把二阶的邻接点聚合成一阶的邻接点(图1-2中绿色的部分),再把一阶的邻接点聚合成这个中心节点(图1-2中蓝色的部分);
|
||||
1. 有了聚合好的这个中心节点的Embedding,我们就可以去完成一个预测任务,比如这个中心节点的标签是被点击的电影,那我们就可以让这个GNN完成一个点击率预估任务。
|
||||
|
||||
这就是GraphSAGE的主要步骤,你看了之后可能还是觉得有点抽象。那接下来,我们再结合下图3推荐电影的例子,来看一看GraphSAGE是怎么工作的。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/2c/b3/2c4791fe07870eef1d4bcb6abe71e9b3.jpeg" alt="" title="图3 GraphSAGE示例">
|
||||
|
||||
首先,我们要利用MovieLens的数据得到电影间的关系图,这个关系图可以是用用户行为生成(这个方法我们在[第7讲](https://time.geekbang.org/column/article/296672)中讲过),它也可以是像生成知识图谱一样来生成,比如,两部电影拥有同一个演员就可以建立一条边,拥有相同的风格也可以建立一条边,规则我们可以自己定。
|
||||
|
||||
在这个由电影作为节点的关系图上,我们随机选择一个中心节点。比如,我们选择了玩具总动员(Toy Story)作为中心节点,这时再向外进行二阶的邻接点采样,就能生成一个树形的样本。
|
||||
|
||||
经过多次采样之后,我们会拥有一批这样的子图样本。这时,我们就可以把这些样本输入GNN中进行训练了。GNN的结构我会在下一小节详细来讲,这里我们只要清楚,这个GNN既可以预测中心节点的标签,比如点击或未点击,也可以单纯训练中心节点的Embedding就够了。
|
||||
|
||||
总的来说,**GraphSAGE的主要步骤就是三个“抽样-聚合-预测”**。
|
||||
|
||||
## GraphSAGE的模型结构
|
||||
|
||||
现在,我们关注的重点就变成了GraphSAGE的模型结构到底怎么样?它到底是怎么把一个k阶的子图放到GNN中去训练,然后生成中心节点的Embedding的呢?接下来,我就结合GraphSAGE的模型结构来和你详细讲一讲。
|
||||
|
||||
这里,我们还是以二阶的GraphSAGE为例,因为超过二阶的结构只是进一步延伸这个模型,没有更多特别的地方,所以我们理解二阶的模型结构就足够了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e8/c0/e8d640076241bd415da8b782f8c256c0.jpg" alt="" title="图4 GraphSAGE的模型结构">
|
||||
|
||||
上图中处理的样本是一个以点A为中心节点的二阶子图,从左到右我们可以看到,点A的一阶邻接点包括点B、点C和点D,从点B、C、D再扩散一阶,可以看到点B的邻接点是点A和点C,点C的邻接点是A、B、E、F,而点D的邻接点是点A。
|
||||
|
||||
清楚了样本的结构,我们再从右到左来看一看GraphSAGE的训练过程。这个GNN的输入是二阶邻接点的Embedding,二阶邻接点的Embedding通过一个叫CONVOLVE的操作生成了一阶邻接点的Embedding,然后一阶邻接点的Embedding再通过这个CONVOLVE的操作生成了目标中心节点的Embedding,至此完成了整个训练。
|
||||
|
||||
这个过程实现的关键就在于这个叫CONVOLVE的操作,那它到底是什么呢?
|
||||
|
||||
CONVOLVE的中文名你肯定不会陌生,就是卷积。但这里的卷积并不是严格意义上的数学卷积运算,而是一个由Aggregate操作和Concat操作组成的复杂操作。这里,我们要重点关注图4中间的部分,它放大了CONVOLVE操作的细节。
|
||||
|
||||
**这个CONVOLVE操作是由两个步骤组成的:第一步叫Aggregate操作,就是图4中gamma符号代表的操作,它把点A的三个邻接点Embedding进行了聚合,生成了一个Embedding hN(A);第二步,我们再把hN(A)与点A上一轮训练中的Embedding hA连接起来,然后通过一个全联接层生成点A新的Embedding。**
|
||||
|
||||
第二步实现起来很简单,但第一步中的Aggregate操作到底是什么呢?搞清楚这个,我们就搞清楚了GraphSAGE的所有细节。
|
||||
|
||||
事实上,Aggregate操作我们也不陌生,它其实就是把多个Embedding聚合成一个Embedding的操作,我们在推荐模型篇中也讲过很多次了。比如,我们最开始使用的Average Pooling,在DIN中使用过的Attention机制,在序列模型中讲过的基于GRU的方法,以及可以把这些Embedding聚合起来的MLP等等。Aggregate操作非常多,如果你要问具体用哪个,我还是那句老话,**实践决定最终结构**。
|
||||
|
||||
到这里,我们就抽丝剥茧地讲清楚了GraphSAGE的每个模型细节。如果你还有疑惑,再回头多看几遍GraphSAGE的模型结构图,结合我刚才的讲解,相信不难理解。
|
||||
|
||||
## GraphSAGE的预测目标
|
||||
|
||||
不过,在讲GraphSAGE的主要步骤的时候,我们还留下了一个“小尾巴”没有讲,就是说GraphSAGE既可以预测中心节点的标签,比如点击或未点击,又可以单纯地生成中心节点的Embedding。要知道预测样本标签这个事情是一个典型的有监督学习任务,而生成节点的Embedding又是一个无监督学习任务。
|
||||
|
||||
那GraphSAGE是怎么做到既可以进行有监督学习,又能进行无监督学习的呢?要想让GraphSAGE做到这一点,关键就看你怎么设计它的输出层了。
|
||||
|
||||
我们先来说说有监督的情况,为了预测中心节点附带的标签,比如这个标签是点击或未点击,我们就需要让GraphSAGE的输出层是一个Logistic Regression这样的二分类模型,这个输出层的输入,就是我们之前通过GNN学到的中心节点Embedding,输出当然就是预测标签的概率了。这样,GraphSAGE就可以完成有监督学习的任务了。
|
||||
|
||||
而对于无监督学习,那就更简单了。这是因为,我们的输出层就完全可以仿照[第6讲](https://time.geekbang.org/column/article/295939)中Word2vec输出层的设计,用一个softmax当作输出层,预测的是每个点的ID。这样一来,每个点ID对应的softmax输出层向量就是这个点的Embedding,这就和word2vec的原理完全一致了。如果你仔细学了YouTube的候选集生成模型的话,就会知道这和视频向量的生成方式也是一样的。
|
||||
|
||||
## GraphSAGE在Pinterest推荐系统中的应用
|
||||
|
||||
GraphSAGE我们讲了这么多,那Pinterest到底是怎么在它的推荐系统中应用GNN的呢?我这就来讲一讲。
|
||||
|
||||
由于GraphSAGE是Pinterest和斯坦福大学联合提出的,所以Pinterest对于GNN的应用也是直接在GraphSAGE的基础上进行的,只是给这个GNN取了个换汤不换药的新名字,PinSAGE。
|
||||
|
||||
Pinterest这个网站的主要功能是为用户提供各种商品的浏览、推荐、收藏的服务,那么所谓的Pin这个动作,其实就是你收藏了一个商品到自己的收藏夹。因此,所有的Pin操作就连接起了用户、商品和收藏夹,共同构成了一个它们之间的关系图。PinSAGE就是在这个图上训练并得到每个商品的Embedding的。
|
||||
|
||||
而PinSAGE Embedding的具体应用场景,其实跟我们[14讲](https://time.geekbang.org/column/article/303641)中实现的功能一样,就是商品的相似推荐。只不过之前业界更多地使用Item2vec、DeepWalk这些方法,来生成用于相似推荐的物品Embedding,在GNN流行起来之后,大家就开始尝试使用GNN生成的物品Embedding进行相似推荐。
|
||||
|
||||
那么,PinSAGE在Pinterest场景下的效果到底怎么样呢?Pinterest给出了一些例子如图5所示,我们可以判断一下。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/9c/84/9c694cc8c041c237e541d64d9e370684.jpg" alt="" title="图5 PinSAGE在Pinterest上应用的例子">
|
||||
|
||||
我们先看图5左边的例子,因为它给出的是一个种子发芽的图片,我们就推测它应该是一个卖绿植或者绿植种子的商家。接下来,我们再来判断左边通过四种不同算法找到的相似图片是不是合理。其中,PinSAGE是Pinterest实际用于推荐系统中的算法,其他三个Visual、Annot、Pixie都是效果测试中的对比算法。
|
||||
|
||||
我们看到通过第一个算法Visual找到的图片,虽然看上去和原来的图片比较相似,但前两个图片居然都是食品照片,这显然不相关。第二个算法Annot中的树木,以及第三个算法Pixie中的辣椒和西兰花,显然都跟绿植种子有很遥远的差距。相比之下,PinSAGE找到的图片就很合理了,它找到的全都是种子发芽或者培育绿植的图片,这就非常合乎用户的逻辑了。
|
||||
|
||||
要知道,在PinSAGE应用的构成中,它没有直接分析图片内容,而只是把图片当作一个节点,利用节点和周围节点的关系生成的图片Embedding。因此,这个例子可以说明,PinSAGE某种程度上理解了图片的语义信息,而这些语义信息正是埋藏在Pinterest的商品关系图中。可见,PinSAGE起到了多么神奇的数据挖掘的作用。
|
||||
|
||||
## 小结
|
||||
|
||||
这节课,我们讲解了图神经网络的经典方法GraphSAGE,我们抽丝剥茧地把GraphSAGE的细节全部剖开了。关于GraphSAGE,我们重点要记住它的特点和主要步骤。
|
||||
|
||||
首先,GraphSAGE是目前来说最经典的GNN解决方案。因此,它具有GNN最显著的特点,那就是它可以直接处理图数据,不需要把图数据转换成更简单的序列数据,再用序列数据Embedding方法进行处理。
|
||||
|
||||
其次,GraphSAGE的主要步骤是三步“采样-聚合-预测”。其中,采样是指在整体图数据上随机确定中心节点,采样k阶子图样本。聚合是指利用GNN把k阶子图样本聚合成中心节点Embedding。预测是指利用GNN做有监督的标签预测或者直接生成节点Embedding。
|
||||
|
||||
在这三步之中,重点在于聚合的GNN结构,它使用CONVOLVE操作把邻接点Embedding聚合起来,跟中心节点上一轮的Embedding连接后,利用全连接层生成新的Embedding。
|
||||
|
||||
为了方便你及时回顾,我也把这节课中的重要知识点总结了下面的表格中,你可以看看。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/13/b9/1300b834c6c356e8fbbe17d69d1b1db9.jpeg" alt="">
|
||||
|
||||
## 课后思考
|
||||
|
||||
使用GraphSAGE是为了生成每个节点的Embedding,那我们有没有办法在GraphSAGE中加入物品的其他特征,如物品的价格、种类等等特征,让最终生成的物品Embedding中包含这些物品特征的信息呢?
|
||||
|
||||
期待在留言区看到你对GraphSAGE的思考,我们下节课见!
|
||||
@@ -0,0 +1,139 @@
|
||||
<audio id="audio" title="30 | 流处理平台:Flink是如何快速识别用户兴趣,实现实时推荐的?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/49/62/49693d204eb1b2104b6501a892617562.mp3"></audio>
|
||||
|
||||
你好,我是王喆。
|
||||
|
||||
刚刚结束的2020年双11活动,让技术圈出现了一个非常劲爆的新闻,就是阿里基于Flink,实现了数据的批流一体处理,每秒能够处理40亿条的巨量数据。这也是业界首次在这么大规模的数据洪峰之上,实现数据流的实时处理。
|
||||
|
||||
也正是因为实时数据流处理功能的实现,让阿里的推荐系统引擎能够在双11期间做出更快速的反应,实时抓住用户的兴趣,给出更准确的推荐。
|
||||
|
||||
这节课,我就带你揭开阿里使用流处理平台Flink的面纱,来重点解决这3个问题:
|
||||
|
||||
- 为什么说实时性是影响推荐系统效果的关键因素?
|
||||
- 到底什么是批流一体的数据处理体系?
|
||||
- 业界流行的Flink到底是怎么实现数据流处理的?
|
||||
|
||||
## 为什么实时性是影响推荐系统效果的关键因素?
|
||||
|
||||
周星驰的电影《功夫》里有一句著名的台词“天下武功,无坚不摧,唯快不破”。如果说推荐模型的架构是那把“无坚不摧”的“玄铁重剑”,那么推荐系统的实时性就是“唯快不破”的“柳叶飞刀”。那这把柳叶飞刀到底是怎么发挥作用的呢?我说个切身的场景你就明白了。
|
||||
|
||||
假设,你正在手机上刷抖音,你刚刚看了一个精彩的足球进球视频,感觉意犹未尽,还想看更多这样的视频。这个时候,抖音的推荐系统肯定不会让你失望,它很快会接收到“你观看了精彩进球视频”的信号,快速地抓到你的兴趣点,然后,它会迅速做出反馈,给你推送更多类似的视频。
|
||||
|
||||
那我们也可以试想一下,如果抖音的推荐系统实时性不够的话,会发生什么呢?可能是你看完了精彩进球的视频之后,推荐系统还跟什么都没发生一样,依然按部就班地给你推荐一些原本就设定好的不相关视频。如果是这样的话,抖音又怎么能让你欲罢不能,刷了又想刷呢?
|
||||
|
||||
这个例子就充分说明了,**推荐系统只有拥有实时抓住用户新兴趣点的能力,才能让你的用户“离不开你”**。
|
||||
|
||||
## 什么是批流一体的数据处理体系?
|
||||
|
||||
那作为推荐系统工程师,我们就要思考,到底怎样才能实现用户兴趣的快速提取呢?这就不得不提到推荐系统的数据体系。
|
||||
|
||||
我们之前讲的数据处理,无论是数据的预处理,还是特征工程,大部分是在Spark平台上完成的。Spark平台的特点是,它处理的数据都是已经落盘的数据。也就是说,这些数据要么是在硬盘上,要么是在分布式的文件系统上,然后才会被批量地载入到Spark平台上进行运算处理,这种批量处理大数据的架构就叫做批处理大数据架构。它的整体结构图如图1所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/15/78/153c832b255ce750537698fc5866a878.jpg" alt="" title="图1 传统批处理大数据架构">
|
||||
|
||||
但批处理架构的特点就是慢,数据从产生到落盘,再到被Spark平台重新读取处理,往往要经历几十分钟甚至几小时的延迟。如果推荐系统是建立在这样的数据处理架构上,还有可能实时地抓住用户的新兴趣点吗?肯定是没有希望了。
|
||||
|
||||
那怎么办呢?我们能不能在数据产生之后就立马处理它,而不是等到它落盘后再重新处理它呢?当然是可以的,这种在数据产生后就直接对数据流进行处理的架构,就叫做流处理大数据架构。
|
||||
|
||||
我们从图2的流处理架构示意图中可以看到,它和批处理大数据架构相比,不仅用流处理平台替换掉了分布式批处理Map Reduce计算平台,而且在数据源与计算平台之间,也不再有存储系统这一层。这就大大提高了数据处理的速度,让数据的延迟可以降低到几分钟级别,甚至一分钟以内,这也让实时推荐成为了可能。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/dc/b1/dc38fbc4e98fc348a3a6bd58d2bc51b1.jpg" alt="" title="图2 流处理大数据架构">
|
||||
|
||||
但是,流处理平台也不是十全十美的。由于流处理平台是对数据流进行直接处理,它没有办法进行长时间段的历史数据的全量处理,这就让流处理平台无法应用在历史特征的提取,模型的训练样本生成这样非常重要的领域。
|
||||
|
||||
那是不是说,根本就没有能够同时具有批处理、流处理优势的解决方案吗?当然是有的,这就是我们在一开始说的,批流一体的大数据架构,其中最有代表性的就是Flink。
|
||||
|
||||
如下图3所示,**批流一体的大数据架构最重要的特点,就是在流处理架构的基础上添加了数据重播的功能**。
|
||||
|
||||
我们怎么理解这个数据重播功能呢?它指的是在数据落盘之后,还可以利用流处理平台同样的代码,进行落盘数据的处理,这就相当于进行了一遍重播。这样不就实现了离线环境下的数据批处理了吗?而且由于流处理和批处理使用的是一套代码,因此完美保证了代码维护的一致性,是近乎完美的数据流解决方案。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/7c/7b/7c6a35831867bfyy3140b619616d7c7b.jpg" alt="" title="图3 批流一体大数据架构">
|
||||
|
||||
既然批流一体的大数据架构这么完美,为什么我们很少听说有实现这套方案的公司呢?以我个人的实践经验来看,这主要是因为它实现起来有下面两个难点。
|
||||
|
||||
- 大批成熟的互联网公司已经在Spark等批处理平台上,构建起了整套的数据体系,要想完全迁移到批流一体的数据体系上,有着非常沉重的技术负担。
|
||||
- 批流一体的解决方案还很理想化,因为我们在实际处理特征的时候,很难让批处理和流处理完全共享一套代码。
|
||||
|
||||
比如,我们在流处理中可以很方便地计算出点击量、曝光量这类方便累计的指标,但如果遇到比较复杂的特征,像是用户过去一个月的平均访问时长,用户观看视频的进度百分比等等,这些指标就很难在流处理中计算得到了。这是因为计算这类特征所需的数据时间跨度大,计算复杂,流处理难以实现。
|
||||
|
||||
因此,**在对待流处理平台时,我们的态度应该是,取其所长**。更具体点来说就是,在需要实时计算的地方发挥它的长处,但也没有必要过于理想主义,强调一切应用都应该批流一体,这反而会为我们增加过多的技术负担。
|
||||
|
||||
## Flink是如何处理数据流的?
|
||||
|
||||
现在,我们已经清楚流处理平台的特点和优势了,但Flink平台到底是怎么进行流数据处理的呢?
|
||||
|
||||
我们先来认识Flink中两个最重要的概念,数据流(DataStream)和窗口(Window)。数据流其实就是消息队列,从网站、APP这些客户端中产生的数据,被发送到服务器端的时候,就是一个数据消息队列,而流处理平台就是要对这个消息队列进行实时处理。
|
||||
|
||||
就像下图4所示的那样,上面是来自三个用户的数据,其中一个一个紫色的点就是一条条数据,所有紫色的点按时间排列就形成了一个消息队列。
|
||||
|
||||
[<img src="https://static001.geekbang.org/resource/image/21/15/2151181244e9b21b03029333294f9515.jpg" alt="" title="图4 数据流和窗口">](https://ci.apache.org/projects/flink/flink-docs-stable/dev/stream/operators/windows.html)
|
||||
|
||||
知道了什么是消息队列,Flink会怎么处理这个消息队列里的数据呢?答案很简单,就是随着时间的流失,按照时间窗口来依次处理每个时间窗口内的数据。
|
||||
|
||||
比如图4中的数据流就被分割成了5个时间窗口,每个窗口的长度假设是5分钟,这意味着每积攒够5分钟的数据,Flink就会把缓存在内存中的这5分钟数据进行一次批处理。这样,我们就可以算出数据流中涉及物品的最新CTR,并且根据用户最新点击的物品来更新用户的兴趣向量,记录特定物品曝光给用户的次数等等。
|
||||
|
||||
除了上面例子中的固定窗口以外,Flink还提供了多种不同的窗口类型,滑动窗口(Sliding Window)也是我们经常会用到的。
|
||||
|
||||
滑动窗口的特点是在两个窗口之间留有重叠的部分,Flink在移动窗口的时候,不是移动window size这个长度,而是移动window slide这个长度,window slide的长度要小于window size。因此,窗口内部的数据不仅包含了数据流中新进入的window slide长度的数据,还包含了上一个窗口的老数据,这部分数据的长度是window size-window slide。
|
||||
|
||||
[<img src="https://static001.geekbang.org/resource/image/eb/10/eb6af5fcb0ff8088f31f2bc5776eae10.jpg" alt="" title="图5 Flink中的滑动窗口">](https://ci.apache.org/projects/flink/flink-docs-stable/dev/stream/operators/windows.html)
|
||||
|
||||
那滑动窗口这种方式有什么用呢?它最典型的用处就是做一些数据的JOIN操作。比如我们往往需要通过JOIN连接一个物品的曝光数据和点击数据,以此来计算CTR,但是你要知道,曝光数据肯定是在点击数据之前到达Flink的。
|
||||
|
||||
那如果在分窗的时候,恰好把曝光数据和点击数据分割在了两个窗口怎么办呢?那点击数据就不可能找到相应的曝光数据了。这个时候,只要我们使用滑动窗口,这个问题就迎刃而解了。因为两个窗口重叠的部分给我们留了足够的余量来进行数据JOIN,避免数据的遗漏。
|
||||
|
||||
事实上,除了固定窗口和滑动窗口,Flink还提供了更丰富的窗口操作,比如基于会话的Session Window,全局性的Global Window。除此之外,Flink还具有数据流JOIN,状态保存特性state等众多非常有价值的操作,想继续学习的同学可以在课后参考Flink的[官方文档](https://ci.apache.org/projects/flink/flink-docs-release-1.12/) 。我们这节课,只要清楚Flink的核心概念数据流和时间窗口就可以了,因为它反映了流处理平台最核心的特点。
|
||||
|
||||
## Flink数据流处理实践
|
||||
|
||||
接下来,就又到了实践的环节。我们要继续在SparrowRecsys项目上利用Flink实现一个特征更新的应用。因为没有真实的数据流环境,所以我们利用MoviesLens的ratings表来模拟一个用户评分的数据流,然后基于这个数据流,利用Flink的时间窗口操作,来实时地提取出用户最近的评分电影,以此来反映用户的兴趣。
|
||||
|
||||
下面就是SparrowRecsys中相关的代码(详细代码:com.sparrowrecsys.nearline.flink.RealTimeFeature)。你可以看到,我首先定义了一个评分的数据流ratingStream,然后在处理ratingStream的时候,是把userId作为key进行处理。
|
||||
|
||||
接着,我又利用到了两个函数timeWindow和reduce。利用timeWindow函数,我们可以把处理的时间窗口设置成1s,再利用reduce函数,把每个时间窗口到期时触发的操作设置好。
|
||||
|
||||
在完成了reduce操作后,我们再触发addSink函数中添加的操作,进行数据存储、特征更新等操作。
|
||||
|
||||
```
|
||||
DataStream<Rating> ratingStream = inputStream.map(Rating::new);
|
||||
ratingStream.keyBy(rating -> rating.userId)
|
||||
.timeWindow(Time.seconds(1))
|
||||
.reduce(
|
||||
(ReduceFunction<Rating>) (rating, t1) -> {
|
||||
if (rating.timestamp.compareTo(t1.timestamp) > 0){
|
||||
return rating;
|
||||
}else{
|
||||
return t1;
|
||||
}
|
||||
}
|
||||
).addSink(new SinkFunction<Rating>() {
|
||||
@Override
|
||||
public void invoke(Rating value, Context context) {
|
||||
System.out.println("userId:" + value.userId + "\tlatestMovieId:" + value.latestMovieId);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
```
|
||||
|
||||
看完了这些操作之后,你知道我们应该怎么把用户最近的高分电影评价历史,实时反映到推荐结果上了吗?其实很简单,我们的用户Embedding是通过平均用户的高分电影Embedding得到的,我们只需要在得到新的高分电影后,实时地更新用户Embedding就可以了,然后在推荐过程中,用户的推荐列表自然会发生实时的变化。这就是SparrowRecsys基于Flink的实时推荐过程。
|
||||
|
||||
## 小结
|
||||
|
||||
这节课我们讲了流处理平台Flink特点,并且通过Flink的实践清楚了,利用流处理平台提高推荐系统实时性的方法。
|
||||
|
||||
Flink是最具代表性的批流一体的大数据平台。它的特点就是,让批处理和流处理共用一套代码,从而既能批量处理已落盘的数据,又能直接处理实时数据流。从理论上来说,是近乎完美的数据流解决方案。
|
||||
|
||||
而Flink提高推荐系统实时性的原理可以理解为是,用户数据进入数据流,也就是数据消息队列后,会被分割成一定时长的时间窗口,之后Flink会按照顺序来依次处理每个时间窗口内的数据,计算出推荐系统需要的特征。这个处理是直接在实时数据流上进行的,所以相比原来基于Spark的批处理过程,实时性有了大幅提高。
|
||||
|
||||
为了方便你复习,我把这节课的核心概念总结在了下面的表格里,希望你能记住它们。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ba/b1/baff4cbda249a76a7204c023ce5cc6b1.jpeg" alt="">
|
||||
|
||||
至于Flink的实时性实践,我们要记住,利用Flink我们可以实时地获取到用户刚刚评价过的电影,然后通过实时更新用户Embedding,就可以实现SparrowRecsys的实时推荐了。
|
||||
|
||||
## 课后思考
|
||||
|
||||
1. 你觉得实时性是不是对所有推荐系统都非常重要?比如对于抖音、快手这类短视频应用,还有优酷、Netflix这类长视频应用,实时性对哪个更重要一些?为什么?
|
||||
1. Flink要加强的往往是数据的实时性,特征的实时性,你觉得模型训练的实时性重要吗?模型训练的实时性发挥的作用和特征实时性有什么不同呢?
|
||||
|
||||
期待在留言区看到你对Flink的思考和疑惑,我们下节课见!
|
||||
127
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/31|模型迭代:阿里巴巴是如何迭代更新推荐模型的?.md
Normal file
127
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/31|模型迭代:阿里巴巴是如何迭代更新推荐模型的?.md
Normal file
@@ -0,0 +1,127 @@
|
||||
<audio id="audio" title="31|模型迭代:阿里巴巴是如何迭代更新推荐模型的?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/94/82/94872ff602a25716eab48yya10823782.mp3"></audio>
|
||||
|
||||
你好,我是王喆。
|
||||
|
||||
前两天,我问了我团队中推荐工程师们一个问题,“你们觉得在推荐系统领域工作,最大的挑战是什么?”。有的人说是模型调参,有的人说是工程落地,有的人说是找到下一步改进的思路。那现在听到这个问题的你,认为会是什么呢?
|
||||
|
||||
其实,刚才的这些回答都很好。不过,我的想法和大家稍有不同,我认为工作中最大的挑战就是,**不断地优化整个推荐系统的架构,做到持续的效果提升和高质量的模型迭代**。这是因为,从我们成为一名算法工程师的第一天开始就在不断面临挑战,不仅要跟别人赛跑,也要跟自己赛跑,而超越过去的自己往往是最难的。
|
||||
|
||||
那这节课,我就以阿里妈妈团队的经验为例,带你看一看业界一线的团队是如何实现模型的持续迭代创新,做到好上加好的。在学习这节课的时候,我再给你一点小建议,不要纠结于每个模型的细节,而是要多体会阿里的工程师是如何定位创新点的。
|
||||
|
||||
## 阿里妈妈推荐系统的应用场景
|
||||
|
||||
阿里妈妈是阿里巴巴集团的营销广告团队,他们负责了阿里大部分广告推荐系统的工作。下图1就是一个阿里妈妈典型的广告推荐场景。
|
||||
|
||||
这是我在手机淘宝上搜索了“篮球鞋”之后,App给我推荐的一个商品列表。其中,第一个搜索结果的左上角带着HOT标识,左下角还有一个比较隐蔽的灰色“广告”标识。那带有这两个标志的,就是阿里妈妈广告推荐系统推荐的商品啦。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/4c/4a/4c798d74bc1b57bf34cd4c8a6c2c0e4a.jpeg" alt="" title="图1 阿里妈妈广告推荐的场景">
|
||||
|
||||
如果让你来构建这个广告推荐模型,你觉得应该考虑的关键点是什么?
|
||||
|
||||
我们可以重点从它的商业目标来思考。阿里妈妈的广告大部分是按照CPC(Cost Per Click)付费的,也就是按照点击效果付费的,所以构建这个模型最重要的一点就是要准确预测每个广告商品的点击率,这样才能把高点击率的商品个性化地推荐给特定的用户,让整个广告系统的收益更高。
|
||||
|
||||
因此,模型怎么预测出用户爱点击的广告种类就是重中之重了。那预测广告就一定要分析和利用用户的历史行为,因为这些历史行为之中包含了用户最真实的购买兴趣。
|
||||
|
||||
而阿里妈妈推荐模型的主要进化和迭代的方向,也是围绕着用户历史行为的处理展开的。下面,我们就来一起看一看阿里妈妈深度推荐模型的进化过程。
|
||||
|
||||
## 阿里妈妈深度推荐模型的进化过程
|
||||
|
||||
阿里妈妈深度推荐模型的起点被称为Base Model,它是一个基础版本的模型结构,就是我们之前讲过的Embedding MLP的结构,它的结构如图2所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/55/1a/554381f409e804e94cd903451d42cd1a.jpg" alt="" title="图2 Base Model的架构和用户历史行为样例">
|
||||
|
||||
Base Model的输入特征包括用户特征、广告特征、场景特征等等,我们最需要关注的,就是它处理用户行为特征的原理,也就是图中彩色的部分。
|
||||
|
||||
Base Model使用了SUM Pooling层将用户的所有历史购买商品Embedding进行了加和。这样一来,Base Model就会一视同仁、不分重点地把用户的历史行为都加起来,形成一个固定的用户兴趣向量。
|
||||
|
||||
比如说,如果一位女性用户购买过连衣裙、奶粉、婴儿车,她的兴趣向量就是全部商品Embedding的平均。
|
||||
|
||||
这当然是一种很粗糙的历史行为处理方式,自然就成为了阿里的工程师需要重点改进的方向。那具体该怎么改进呢?我们在[第21讲](https://time.geekbang.org/column/article/313736)中讲过,就是使用注意力机制来计算每个历史行为和当前要预测的候选广告物品之间的关系,关系紧密的权重大,关系疏远的权重低。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/16/67/16c234b41538b5cd11be2ce56a450467.jpg" alt="" title="图3 DIN的模型架构和相应的用户历史行为样例">
|
||||
|
||||
这样一来,如果我们要预测这位用户购买另一套女装时的CTR,在历史行为中,购买连衣裙这类商品的权重就会高,而购买奶粉这类不相关商品的权重就会低,就像图3中商品下面的进度条一样。
|
||||
|
||||
那通过这个例子我们又一次证明了,引入注意力机制是非常符合我们购买习惯的一种模型改进方式。
|
||||
|
||||
但是,模型的改进到这里就结束了吗?当然不是,我们虽然引入了注意力机制,但还没有考虑商品的购买时间啊。
|
||||
|
||||
举个例子来说,你前一天在天猫上买了一个键盘,今天你又在天猫上闲逛。那对推荐系统来说,是你前一天的购买经历比较重要,还是一年前的更重要呢?当然是前一天的,因为很可能因为你前一天购买了键盘,所以今天购买鼠标或者其他电脑周边的概率变大了,而这些连续事件之间的相关性,对模型来说是非常有用的知识。
|
||||
|
||||
于是,DIN模型就进一步进化到了DIEN模型。图4就很好地展示了DIEN的模型结构和它对应的用户历史行为样例。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/9f/ac/9fa4fc593f266fe55b5fda2b5f7927ac.jpg" alt="" title="图4 DIEN的模型架构和相应的用户历史行为样例">
|
||||
|
||||
其实,本质上所有的用户历史行为都是序列式的,时间维度是天然附着在每个历史商品之上的属性。既然我们在之前的模型中把这个属性丢掉了,就一定存在着信息的浪费和知识的丢失。因此在改进模型时,这自然成为了一个突破点。
|
||||
|
||||
DIEN正是在模型中加入了一个三层的序列模型结构,来处理用户的历史行为序列,进而抽取出用户的购买兴趣演化序列,最后预测出用户当前的购买兴趣。但是这次改进之后,模型的迭代之路似乎变得越来越难了,似乎算法工程师们把该想到的都想到了。
|
||||
|
||||
算法工程师这条职业道路确实是这样的,它是一个自己跟自己较劲的过程,上一轮大幅提高的优化效果,反而可能会成为这一轮改进的阻碍。这个时候,我们很可能会陷入阶段性的怀疑状态,怀疑自己还能不能找到更好的改进点。
|
||||
|
||||
这种自我怀疑是正常的,但更重要的是,我们能不能在阶段性的怀疑过后,重新开始冷静地分析问题,找到还没有利用过的信息资源,或者补上之前的某个技术短板,从而在现有系统中“扣出”下一个增长点。
|
||||
|
||||
这也是我们要从阿里工程师的工作中学习和借鉴的,下面,我们就来看看他们是怎么继续优化模型的。
|
||||
|
||||
2019年,阿里的工程师们提出了新的模型改进思路,也就是多通道兴趣记忆网络MIMN。因为他们发现,DIEN虽然存在着序列模型的结构,但所有的历史行为都是在一条线上演化的,而事实上,用户的兴趣演化过程完全可以多条并行。这该怎么理解呢?
|
||||
|
||||
我们还以样例中的这位女性用户为例,她购买女装的兴趣演化路径,完全可以跟购买婴儿物品的演化路径平行,她的兴趣向量也可以是多个,而不仅仅局限于一个。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f9/a0/f97e680938097f7e9b4c3f1dfdc460a0.jpg" alt="" title="图5 MIMN的模型架构和相应的用户历史行为样例">
|
||||
|
||||
正是基于这样的模型改进动机,MIMN相比于DIEN加入了多条平行的兴趣演化路径,最终为Embedding MLP的主模型提供了多个课选择的兴趣向量。当然,具体选择哪个,我们还是要根据当前兴趣与目标广告商品之间的注意力得分而定。通过引入兴趣演化的多通道,MIMN进一步加强了模型的表达能力,让模型挖掘数据价值的能力更强。
|
||||
|
||||
说了这么多,这几个模型到底有没有提升阿里妈妈推荐系统的效果呢?我们来看一看表1的离线评估结果。从中我们可以看到,阿里采用了ROC AUC作为评估指标,正如期望的那样,随着模型的一步步改进,模型的效果在淘宝数据集和亚马逊数据集上都逐渐增强。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/yy/cd/yycfdb9a682a37fa93c0b22fe2c9dbcd.jpeg" alt="" title="表1 离线评估结果">
|
||||
|
||||
当然,我建议所有论文中的实验效果你都应该辩证地来看,可以作为一个参考值,但不能全部相信。因为就像我常说的在,**模型结构不存在最优,只要你的数据、业务特点和阿里不一样,就不能假设这个模型在你的场景下具有同样的效果,所以根据自己的数据特点来改进模型才最重要**。
|
||||
|
||||
## 阿里妈妈的其他创新点
|
||||
|
||||
这个时候,有的同学可能会问了,阿里妈妈的同学们只是瞄着用户历史这个点去优化吗?感觉这一点的优化空间早晚会穷尽啊。我要说这个观察角度太好了,作为一名算法工程师,技术的格局和全面的视野都是非常重要的,技术的空间那么大,我们不能只盯着一个点去改进,要适当地跳出局限你的空间,去找到其他的技术短板。这样一来,我们往往会发现更好的迭代方向。
|
||||
|
||||
所以,阿里的工程师们除了对用户历史进行挖掘,也针对商品图片信息进行了建模,也就是所谓的 DICM(Deep Image CTR Model)。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/23/bc/23a5ce459ab84b0ce0e736ede5ed9ebc.jpg" alt="" title="图6 DICM的模型架构">
|
||||
|
||||
图6中DICM的模型结构很好理解,它还是采用了Embedding MLP的主模型架构,只不过引入了用户历史购买过的商品的图片信息,以及当前广告商品的图片信息。这些商品图片还是以Embedding的形式表示,然后输入后续MLP层进行处理。
|
||||
|
||||
因为要引入图片信息,所以在MLP层之前,还需要利用一个预训练好的CV模型来生成这些图片的Embedding表达。简单来说,就是一个预训练图片Embedding+MLP的模型结构。
|
||||
|
||||
除此之外,阿里团队还在很多方向上都做了研究。比如说,同时处理CTR预估和CVR预估问题的多目标优化模型ESMM([Entire Space Multi-Task Model](https://arxiv.org/pdf/1804.07931.pdf)),基于用户会话进行会话内推荐的DSIN([Deep Session Interest Network](https://arxiv.org/pdf/1905.06482.pdf) ),可以在线快速排序的轻量级深度推荐模型COLD(Computing power cost-aware Online and Lightweight Deep pre-ranking system)等等。
|
||||
|
||||
我们可以用百花齐放来形容阿里团队的发展过程。你如果感兴趣,可以按照我提供的论文地址来进一步追踪学习。
|
||||
|
||||
## 我们能学到什么?
|
||||
|
||||
到这里,我带你从业务方面梳理了,业界一线团队进行模型迭代的过程。那我们到底能从阿里妈妈团队学到或者说借鉴到什么呢?为了帮助你彻底梳理清楚,我把阿里妈妈模型的发展过程分为横向和纵向这两个维度绘制了在下面。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e1/c5/e1d01c75d10543ebde10f658d73dd2c5.jpg" alt="" title="图7 阿里妈妈推荐模型的发展过程">
|
||||
|
||||
横向的维度是推荐主模型的发展过程,从基础的深度模型一路走来,沿着挖掘用户行为信息的思路不断深化,我把这种发展思路叫做模型的深化演进思路。
|
||||
|
||||
但是深化演进的过程是一个不断挑战自己的过程,虽然我们说数据中埋藏着无穷无尽的宝藏,不可能让我们挖完,但是挖掘的难度一直在不断加大。
|
||||
|
||||
就像刚开始通过用深度学习模型替代传统机器学习模型,我们能取得10%这个量级的收益,加入注意力机制,加入序列模型这样大的结构改进,我们能取得1%-3%这个量级的收益,到后来,更加复杂的改进,可能只能取得0.5%甚至更低的收益。这个时候,我们就需要把视野拓宽,从其他角度看待推荐问题,找到新的切入点。
|
||||
|
||||
这方面,阿里给我们做了很好的示范。比如图7纵向的发展过程就是阿里团队对于一些独立问题的解决方法:多目标、多模态,包括我们之前提到的可以进行实时服务和在线学习在COLD模型。这些都是独立的技术点,但是它们对于推荐效果的提高可能丝毫不弱于主排序模型的改进。这种从不同角度改进推荐模型的思路,我称之为广度扩展。
|
||||
|
||||
推荐系统是一个非常复杂的系统,系统中成百上千个不同的模块共同围成了这个系统,它最终的效果也是由这几百上千个模块共同决定的。在通往资深推荐工程师的路上,你的任务是敏锐地发现这些模块中的短板,而不是总盯着最长的那块木板改进,只有高效地解决短板问题,我们才能取得最大的收益。这也是我们这门课为什么一直强调要系统性地建立知识体系的原因。
|
||||
|
||||
## 小结
|
||||
|
||||
今天,我带你总结了阿里妈妈团队推荐模型的发展过程。我们可以从两个维度来看阿里广告推荐模型的演进。
|
||||
|
||||
首先是深化演进这个迭代思路上,阿里妈妈对用户的历史行为进行了深入理解和不断挖掘,这让阿里妈妈模型从最初的Embedding MLP结构,到引入了注意力机制的DIN,序列模型的DIEN,再到能够利用多通道序列模型学习出用户多个兴趣向量的MIMN,整个发展是一脉相承的。
|
||||
|
||||
其次,阿里妈妈还一直在践行“广度拓展”的模型迭代思路,从多目标、多模态,以及在线学习等多个角度改进推荐模型,实现了推荐系统的整体效果的提高。
|
||||
|
||||
最后,我把阿里妈妈模型演进过程中所有改进模型的特点,都总结在了下面,希望可以帮助你加深印象。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8c/83/8c39dea9f734fd6d1933b1ffb1c73183.jpeg" alt="">
|
||||
|
||||
## 课后思考
|
||||
|
||||
最后的最后,我希望咱们再来做一个开放型的练习:如果我让你在MIMN的基础上进一步改进模型,你觉得还有什么可供挖掘的用户行为信息吗?或者说还有什么方式能够进一步利用好用户行为信息吗?
|
||||
|
||||
期待在留言区看到你的创意和思考,我们下节课见!
|
||||
128
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/32 | 强化学习案例:美团是如何在推荐系统中落地强化学习的?.md
Normal file
128
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/32 | 强化学习案例:美团是如何在推荐系统中落地强化学习的?.md
Normal file
@@ -0,0 +1,128 @@
|
||||
<audio id="audio" title="32 | 强化学习案例:美团是如何在推荐系统中落地强化学习的?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/6f/ce/6f58283b91c57658a72035e0739417ce.mp3"></audio>
|
||||
|
||||
你好,我是王喆。今天我们来聊一聊美团的强化学习落地案例。
|
||||
|
||||
我们在[第22讲](https://time.geekbang.org/column/article/315254)中学过强化学习的基本原理、优点,以及微软的强化学习模型DRN,但我们也说了强化学习在推荐系统中落地会有一个难点:因为强化学习涉及模型训练、线上服务、数据收集、实时模型更新等几乎推荐系统的所有工程环节,所以强化学习整个落地过程的工程量非常大,需要工程和研究部门通力合作才能实现。
|
||||
|
||||
即使很难,但业界依然有成功落地强化学习的案例,典型的就是美团在“猜你喜欢”功能中的应用。美团曾在官方博客中详细介绍过这一[落地方案](https://tech.meituan.com/2018/11/15/reinforcement-learning-in-mt-recommend-system.html)的技术细节,我们这节课就借助这个方案,来好好学习一下强化学习的实践。我也希望你能通过这个案例,串联起我们学过的所有推荐系统知识。
|
||||
|
||||
## 美团的强化学习应用场景
|
||||
|
||||
“猜你喜欢”是美团这个团购App中流量最大的推荐展位,产品形态是信息流。从图1的App截图中你可以看到,“猜你喜欢”列表中推荐了用户可能喜欢的餐厅,用户可以通过下滑和翻页的方式实现与App的多轮交互,在这个过程中,用户还可能发生点击、购买等多种行为。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ce/dc/cef09f967937d6d0d7aeab3f26c8a0dc.jpg" alt="" title="图1 美团首页“猜你喜欢”场景">
|
||||
|
||||
强化学习的应用场景就藏在用户和美团App的多轮交互之中。如果推荐系统能够在用户每次翻页的时候都考虑到用户刚刚发生的行为,就能够提供实时性更强的推荐体验。图2是美团的同学统计的用户翻页次数的分布图,我们可以看到,多轮交互确实是美团App中非常常见的用户场景,这也说明强化学习还是非常有用武之地的。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/5a/4e/5ae0e505314b8856c88815f7c252f34e.jpg" alt="" title="图2 “猜你喜欢”展位用户翻页情况统计">
|
||||
|
||||
## 美团的强化学习建模方法
|
||||
|
||||
清楚了美团为什么要使用强化学习,我们就要开始思考强化学习是怎么应用到这样的场景之上的。
|
||||
|
||||
通过22讲的学习,我们知道了强化学习有六个要素,分别是:智能体、环境、行动、奖励、目标和状态。清楚这六个要素在“猜你喜欢”功能中的具体含义,以及建模过程,我们就能知道美团App是怎么应用强化学习了。
|
||||
|
||||
那接下来,我就带你依次看一看美团是怎么针对这六个要素进行建模的。
|
||||
|
||||
首先是“智能体”,它指的就是美团的推荐系统,这其中最重要的部分自然就是强化学习的模型,这个我们等会再详细讲。“环境”我们刚才介绍过了,指的是美团App这个“猜你喜欢”的推荐场景。“行动”也不难理解,就是推荐系统选出商铺的列表,然后推荐给用户这个动作。接下来的三个要素是整个系统的重点,就是“奖励”、“目标”和“状态”。下面,我们一一来看它们的具体含义。
|
||||
|
||||
“奖励”指的是推荐系统把推荐列表推送给用户之后,用户在这个列表之上的反馈。对于美团来说,“猜你喜欢”展位的核心优化指标是点击率和下单率,这里的奖励就可以被定义成推荐列表中物品的点击次数和下单次数的加权和。如下面的公式所示,其中的wc和wp分别是点击次数和下单次数的权重,这两个超参数可以根据你对它们的重视程度进行调整。
|
||||
|
||||
$$<br>
|
||||
r=w_{c} * \sum I_{c l i c k}+w_{p} * \sum I_{p a y}<br>
|
||||
$$
|
||||
|
||||
有了奖励的定义,那么整个强化学习过程的目标就很好定义了,就是多轮交互后的奖励期望之和最大,它的形式化表达如下所示:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/f4/b0/f40f64bd0157787b8a25e738c73225b0.jpeg" alt="">
|
||||
|
||||
你可以看到,公式中的k指的是交互的轮数,r指的是我们在上面定义的奖励函数,Gamma是一个0-1之间的损失系数。综合来看这个目标函数的含义就是,在状态s的基础上,采取动作a让之后k轮的奖励之和期望最大。在强化学习模型参数的更新过程中,美团就是根据这个目标函数,并且通过梯度下降的方式进行参数的更新。
|
||||
|
||||
然后是状态的定义,在推荐系统的强化学习模型中,状态实质上代表了用户的意图、兴趣和所处场景,所以它在整个搭建过程中非常重要。
|
||||
|
||||
那我们如何来表达这个要素呢?美团设计了图3所示的网络结构来提取状态的Embedding表达,这个状态Embedding就是当前推荐系统所处的状态。
|
||||
|
||||
**这个网络主要分为两个部分:第一个部分是把用户实时行为序列的Item Embedding作为输入(就是翻页前点击下单等动作对应的物品),使用一维CNN层学习用户实时意图的表达,也就是图中的彩色部分;另一部分是传统的特征工程,它使用了特征值组成的稠密向量来表示用户所处的时间、地点、场景,以及使用兴趣Embedding来代表更长时间周期内用户的行为习惯。**
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/86/62/8601398477b0463ef7da4ef02d529f62.jpg" alt="" title="图3 状态建模网络结构">
|
||||
|
||||
这里比较有意思的是第一个部分,它采用了单层CNN,也就是卷积神经网络来学习用户的实时意图表达,这是我们之前没有遇到过的处理手法。
|
||||
|
||||
那它是怎么做的呢?它首先把用户交互获得的Item Embedding组成了一个矩阵,然后在这个矩阵之上使用了两个不同尺度的卷积层,再对卷积层中的每个行向量进行池化操作,生成两个代表了用户实时意图的Embedding,把它们与第二部分的场景特征向量连接后,再经过全连接层,生成最终代表状态的State Embedding。
|
||||
|
||||
强化学习这6大要素是什么、怎么实现,我们已经搞清楚了,但我们之前还留了一个问题,就是智能体部分的强化学习模型的结构到底什么样。下面,我们就来解决这个疑问。图4就是这个强化学习模型的框图。
|
||||
|
||||
我们看到,这个模型跟强化学习模型DRN一样,都采用了DQN的模型框架,也都分成了两个部分,一个部分叫做Advantage函数部分A(s,a),它与状态、动作都相关,这里面的s就是状态,a就是动作,另一部分叫做Value Net,它只与状态相关。最终的模型输出得分Q(s,a) = V(s) + A(s,a),就是把这两部分的得分融合起来。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8b/a2/8b73738da62ce1b121782eb1d5d666a2.jpeg" alt="" title="图4 美团强化学习模型">
|
||||
|
||||
这个框图中的状态网络是预训练好的,也就是说在线上推荐的过程中,状态网络是不会进行在线学习的,那么强化学习动态学习的参数到底是什么呢?它学习的其实是V(s)和 A(s,a)这两部分的融合参数,以及跟Action相关的参数。
|
||||
|
||||
V(s)和A(s,a)这两个函数的具体细节,美团并没有披露,但是一种典型的做法就是采用便于学习的线性模型来构建这两个函数。比如,对于V(s)这部分来说,输入是状态Embedding向量,那么我们就可以使用一个LR的结构生成Value Net的得分。
|
||||
|
||||
同理,A(s,a)也一样,我们可以通过另一个LR结构把状态向量和动作相关的特征综合起来,生成一个Advantage函数得分。最后,我们再通过加权和的方式把Value Net得分和Advantage函数得分加起来。
|
||||
|
||||
总的来说,整个美团强化学习方案的执行过程可以分成4步:
|
||||
|
||||
<li>
|
||||
根据历史数据预训练State Embedding网络,初始化Value Net和Advantage函数的相关参数;
|
||||
</li>
|
||||
<li>
|
||||
在用户打开APP时,根据初始化模型来生成推荐列表;
|
||||
</li>
|
||||
<li>
|
||||
随着用户的不断交互,产生了一些实时的交互数据,这些数据经过State Embedding网络的在线推断过程,生成用户的实时State Embedding,从而实时地影响用户每一轮交互的结果;
|
||||
</li>
|
||||
<li>
|
||||
State Embedding网络不进行在线更新,Value Net和Advantage函数部分进行在线学习来更新相关参数,让强化学习框架具备实时学习的能力。
|
||||
</li>
|
||||
|
||||
以上就是美团强化学习方案的理论部分,但是我们知道,强化学习落地最难的地方在于工程与模型的紧密融合,那下面就让我们看一看美团是如何落地这套方案的。
|
||||
|
||||
## 美团强化学习的工程架构
|
||||
|
||||
图5就是美团强化学习方案相关的工程架构。从整体上看,它确实像一整个推荐系统的框图,跟我们的SparrowRecys项目一样,包含了线上(Online)部分、近线(Nearline)部分和离线(Offline)部分。其中的模块也非常复杂,包含了数据流、模型训练、模型服务、线上推荐等多个模块。
|
||||
|
||||
虽然它复杂,但你也不用着急,它里面每个模块之间都有很强的逻辑关系。接下来,你就和我随着数据的整体流向,一起来过一遍这整个架构图吧。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/53/d4/539624204ffb2b17f25yy50cf7bea5d4.jpg" alt="" title="图5 实时更新的强化学习框架">
|
||||
|
||||
我们从最上方的Log Collector开始,它收集了推荐系统产生的各种日志,包括曝光、点击、下单,以及与这些行为相关的特征。
|
||||
|
||||
这些数据经过消息缓存系统Kafka收集之后,会形成数据流来到Online Joiner模块,那么Online Joiner正是从Kafka的数据流中实时收集特征和用户反馈,处理成包含了特征和标签的样本,再分别把样本数据输出到下游的Kafka和离线的HDFS,来分别支持模型的在线和离线更新。
|
||||
|
||||
对于在线部分,Kafka中的数据继续流向了一个叫Experience Collector的模块。这个模块是对样本做进一步处理,主要是把离散开的一个个样本点做进一步的整合,生成App中展现的推荐列表,然后以列表的形式“喂”给模型进行训练。
|
||||
|
||||
到这里,数据流的部分我们就基本讲完了,熟悉Flink的同学肯定会说,这部分基于数据流的处理过程不就是Flink最擅长的吗?没错,Online Joiner、Experience Collector这些模块确实是最适合运行在Flink这类流处理平台之上。虽然美团没有具体透漏他们的流处理平台,但我们只需要知道这些近线的数据流操作都会运行在Flink、Spark Streaming这类流处理平台就可以了。
|
||||
|
||||
再说回到整个流程中,生成好的样本数据就来到了训练这一环节。美团使用了TensorFlow作为深度学习模型的训练平台。
|
||||
|
||||
当然,整个模型的训练也分为两部分。**一部分是离线的训练,刚才我们提到的State网络、Item Embedding等都是通过离线训练生成的。另一部分需要在线训练,比如Advantage和Value函数相关的参数,这部分并不是在TensorFlow中训练的,而是利用实时数据流中的样本进行在线学习,并实时调整相关参数值。**
|
||||
|
||||
虽然TensorFlow的深度模型部分是在离线预训练好的,但是深度学习模型的线上服务效率问题一直是工程的难点。那美团是怎么解决的呢?和我们的项目一样,美团同样采用了TensorFlow Serving作为模型服务的方式,但它进行了2点优化。
|
||||
|
||||
**首先是剥离State模型的Embedding层,它采取预训练的方式生成Item Embedding,减小模型的整体体积,方便上线。**这些预训练的Embedding会预存在内存数据库Tair中。Tair的具体使用方法你不用特别关心,只要知道它是类似Redis的Key-value内存数据库就可以了。
|
||||
|
||||
**其次是优化了模型更新过程。**你可以看到Version Controller的模块,它是负责深度学习模型的版本管理的,在训练好一个新的模型之后,就需要把新模型进行上线。
|
||||
|
||||
但是在模型上线的时候,TensorFlow Serving往往会在一两分钟内,产生响应时间骤然增加的现象,产生这种现象的原因主要有两点:一是TensorFlow Serving的模型加载和请求共用一个线程池,导致切换模型阻塞请求的处理;二是TensorFlow模型的计算图初始化要等到新模型接收第一次请求后才开始。
|
||||
|
||||
美团分别针对这两点进行了优化:**针对第一点,切分了模型加载部分和请求处理部分的线程池,使之互不干扰;针对第二点,采用了warm up,也就是预热初始化的方式进行解决,在真实请求到来之前,先用一些预热的请求让模型完成计算图加载的过程。**
|
||||
|
||||
到这里,我们就讲完了美团的整个强化学习解决方案,从数据流的产生,近线的数据处理,到离线的模型训练,在线的模型学习更新、模型服务,强化学习需要整个系统通盘配合,才能够完成落地。通过今天的讲解,我相信你对强化学习的落地难点应该有了更深刻的理解,如果之后遇到这样的考验,也希望你能好好利用这些内容。
|
||||
|
||||
## 小结
|
||||
|
||||
这节课我们一起学习了美团的强化学习方案。
|
||||
|
||||
在美团的建模方法中,我们要关注强化学习的六要素。其中,智能体指的是美团的强化学习推荐模型,环境是“猜你喜欢”这个推荐场景,行动指的是强化学习模型生成的推荐列表,奖励是由点击和下单共同组成的奖励函数,目标是最大化多轮交互过程的奖励综合,状态是由深度学习网络生成的状态Embedding。
|
||||
|
||||
在工程落地方案中,我们要清楚整个数据流的流向。推荐系统产生日志以后,它首先会被日志流系统Kafka收集,然后依次流经Online Joiner模块进行数据处理,生成训练样本,再由Experience Collector生成推荐列表样本,接着TensorFlow模型会根据列表样本进行离线训练,以及Advantage函数和Value函数利用相关参数进行在线学习,最后,等TensorFlow模型训练完成后通过TensorFlow Serving进行模型更新和服务。
|
||||
|
||||
同时,针对TensorFlow Serving延迟大,更新时效率低的特点,美团也采取了很多改进措施,比如剥离Embedding层、切分线程池,以及模型预热等等。
|
||||
|
||||
## 课后思考
|
||||
|
||||
你觉得我们在离线训练中使用的随机梯度下降之类的方法能用到在线学习上吗?除此之外,你还知道哪些在线学习的方法?
|
||||
|
||||
欢迎把你的经验和思考写在留言区,我们下节课见!
|
||||
129
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/33|技术权衡:解决方案这么多,哪个最合适?.md
Normal file
129
极客时间专栏/geek/深度学习推荐系统实战/前沿拓展篇/33|技术权衡:解决方案这么多,哪个最合适?.md
Normal file
@@ -0,0 +1,129 @@
|
||||
<audio id="audio" title="33|技术权衡:解决方案这么多,哪个最合适?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/75/17/757b0a1fa0aa32afc330d9687cd38317.mp3"></audio>
|
||||
|
||||
你好,我是王喆。
|
||||
|
||||
在实际的工作中,我们经常会面临一些技术上的抉择。比如说,在设计推荐系统的时候,我们是应该用模型A还是用模型B,是用TensorFlow还是用PyTorch,是用Redis还是用EVCache呢?从理论上来说,其实选择哪个方案都可以,但在工程落地中,不同的方案往往对系统整体的开销,整个团队的工作量,甚至最终的推荐效果都有着非常大的影响。
|
||||
|
||||
我想这也是很多算法工程师的困惑:在工程落地环节,解决方案这么多,我们到底该选哪个?
|
||||
|
||||
今天,我们就一起来探讨一下技术权衡的问题,看看能不能在理论知识和工程落地之间找到一条最优的路径。
|
||||
|
||||
## 工程师职责的本质
|
||||
|
||||
“工程”和“理论”之间的权衡是所有工程师都要考虑的问题,对这个问题的思考方式决定了你具备的是“工程思维”还是“研究思维”,抑或是“学生思维”。推荐系统是一个工程性极强,以技术落地为首要目标的领域,因此,“工程思维”对推荐系统工程师是最重要的。
|
||||
|
||||
事实上,无论是算法工程师,还是研发工程师,甚至是设计电动汽车、神舟飞船、长征火箭的工程师,他们的职责都相同,那就是**在现有实际条件的制约下,以工程完成和技术落地为目标,寻找并实现最优的解决方案。**这里面有一个词最关键,那就是“制约”。我们该怎么理解这个制约呢?
|
||||
|
||||
比如说,在机器学习的理论层面,一切事情都是理想化的,就像模型结构是精确定义的,训练过程是严格推导的,但在实际条件下,一个模型的训练过程会受算力条件、数据质量、工程时间限制等多重条件的制约。这也是我们不得不面临诸多选择和权衡的原因。
|
||||
|
||||
再比如说,我有些同学在航天领域工作,最近趁着嫦娥五号任务圆满完成的热点,我咨询了他们一个问题,说“咱们国家什么时候能实现载人登月啊?”他们这帮航天工程师的回答也很严谨,说“制约咱们国家载人登月的主要是火箭的运力问题,现在的长征五号火箭,近地轨道运载能力是25吨,美国阿波罗登月计划使用的土星五号火箭的轨道运载能力是140吨,整整差了5倍多。”
|
||||
|
||||
[<img src="https://static001.geekbang.org/resource/image/52/bb/5206160f389c023852a5980dafd095bb.jpeg" alt="" title="图1 土星五号和长征5号">](https://www.bilibili.com/video/av71595679/)
|
||||
|
||||
你看,所有的工程师都在受客观条件的制约,那怎么办呢?他们又讲了,要么就是一步步来,先攻克运载火箭技术,再像阿波罗计划一样,一发火箭把登月舱、返回舱、航天员等等一起送到月球;要么就是用现有的长征五号,发射四到五枚火箭,在太空中完成登月舱、返回舱、载人飞船的组装。
|
||||
|
||||
第一个计划的优势是一次性搞定,但周期长,需要等待火箭技术的攻克。第二个计划的优势是现在就可以着手开始做,但因为要发射四到五枚火箭,整个任务的容错率低,失败的风险大。
|
||||
|
||||
所以你看,航天工作者们发射火箭也成天抱怨运力不够,就像我们训练模型总说算力不够一样。那怎么办,日子就不过了吗?当然不是,我们工程师就是要在这样的制约条件下,又快又好地解决问题、完成任务,这就是你的职责所在。
|
||||
|
||||
那推荐系统中“现有实际条件的制约”都有什么呢?我们经常会遇到这3种:
|
||||
|
||||
- 软硬件环境的制约
|
||||
- 研发周期的制约
|
||||
- 实际业务逻辑和应用场景的制约
|
||||
|
||||
正是因为有这些制约的存在,一名工程师不可能像学术界的研究者一样不断尝试新的技术,做更多探索性的创新,也正是因为工程师永远以“技术落地”为目标,而不是炫耀自己的新模型、新技术是否走在业界前沿,所以在前沿理论和工程现实之间做权衡是一名工程师应该具有的基本素质。
|
||||
|
||||
那这个技术权衡具体该怎么做呢?下面,我就借用三个实际的案例帮助你体会一下。
|
||||
|
||||
## Redis容量和模型上线方式之间的权衡
|
||||
|
||||
对线上推荐系统来说,为了进行在线服务,需要将特征和模型参数存储到线上数据库或者线上服务器内存中。为了保证这两部分数据的实时性,很多公司采用内存数据库的方式实现,就像我们在第10讲中讲的一样,Redis这类内存数据库自然是主流的选择。
|
||||
|
||||
但Redis需要占用大量内存资源,而内存资源相比存储资源和计算资源又比较稀缺和昂贵的资源。因此,无论是AWS(Amazon Web Services,亚马逊网络服务平台)、阿里云,还是自建数据中心,实现Redis模块的成本都比较高,自然Redis的容量就成了制约推荐系统模型上线方式的关键因素。
|
||||
|
||||
在这个制约因素下,我们要考虑两方面的事情:
|
||||
|
||||
1. 模型的参数规模要尽量小。特别是对深度学习推荐系统而言,模型的参数量级较传统模型有了几个量级的提升,所以我们更应该着重考虑模型的参数规模;
|
||||
1. 因为要考虑线上预估延迟和特征存储空间有限的情况,所以线上预估所需的特征数量不能无限制地增加,要根据重要性做一定的删减。
|
||||
|
||||
因此,在实际上线推荐系统的时候,我们必然需要进行一定的取舍:**舍弃一些次要的要素,关注主要的矛盾**。具体怎么做呢?这里,我结合自己的经验,把整个取舍的思考过程做了梳理,一共可以分成四步,你可以作为参考。
|
||||
|
||||
首先,对于千万量级甚至更高量级的特征向量维度(理论上模型参数的数量级也在千万量级)来说,因为线上服务很难支持这种级别的数据量,所以我们在上线模型时关注模型的稀疏性和复杂度,通过舍弃一定的模型预测准确度来换取上线的速度和资源消耗。
|
||||
|
||||
明确了工程权衡的目标,我们就要思考怎么提高模型的稀疏性,降低模型的复杂度。提高稀疏性的常见方法是,加入L1正则化项,或者采用FTRL这类稀疏性强的训练方法让大部分参数归零,从而减少模型体积。
|
||||
|
||||
对于降低复杂度,我们可以通过减少神经网络的层数,以及每层内神经元的数量来实现。当然,这个方法只有在不明显降低模型效果的前提下,才是可行的工程策略。
|
||||
|
||||
在明确了多种备选方案之后,如果还是无法确定哪种技术效果更佳,我们就需要实现所有备选方案以及方案间的各种组合,进行离线和线上的效果测试。
|
||||
|
||||
最后,我们要根据测试数据确定最终的技术途径、技术方案,完成最终上线。
|
||||
|
||||
以上就是模型侧的“瘦身”方法,在线特征的“瘦身”方法当然也可以采用同样的思路。首先采用“主成分分析”等方法进行特征筛选,在不显著降低模型效果的前提下减少所用的特征。针对不好取舍的特征,进行离线评估和线上A/B测试,最终达到工程上可以接受的水平。
|
||||
|
||||
## 研发周期和平台迁移之间的权衡
|
||||
|
||||
除了硬件条件的限制,研发周期的制约同样是不可忽视的因素。这就需要工程师对于项目有整体的把控,以及对研发周期有预估。在产品迭代日益迅速的互联网领域,没人愿意成为拖累整个团队的最慢的一个环节。接下来,我就以一个平台迁移的例子,来给你讲一讲如何在研发周期的制约下完成技术决策。
|
||||
|
||||
比如,公司希望把机器学习平台从Spark MLlib整体迁移到TensorFlow上,毫无疑问,这是顺应深度学习浪潮的技术决策,是非常正确的决定。但由于Spark平台自身的特性,它的编程语言、模型训练方式都和TensorFlow有很大的差别,因此整个迁移必然要经历一个较长的研发周期。
|
||||
|
||||
我就经历过很多次公司产品和技术平台的大规模升级,很常见的情况是,在保证平台升级正常进行的同时,我们还需要兼顾日常的开发进度,去实现一些新的产品需求。这就是工程师需要做出权衡的时候了,也是最考验工程师架构能力的时候。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/57/b2/57b98830369yy8d95fe173a585046fb2.jpeg" alt="" title="图2 TensorFlow vs Spark">
|
||||
|
||||
在这样的情况下,一般来说有2种可行的技术方案:
|
||||
|
||||
1. 集中团队的力量完成Spark到TensorFlow的迁移,在新平台上进行新模型和新功能的研发。
|
||||
1. 让团队一部分成员利用成熟稳定的Spark平台,快速满足产品需求,为TensorFlow的迁移、调试、试运行留足充分的时间。同时,让另一部分成员全力完成TensorFlow的相关工作,尽量保证新平台的成熟和可靠。
|
||||
|
||||
不过,单纯从技术角度考虑,既然团队已经决定迁移到TensorFlow平台了,理论上就没必要再花时间利用Spark平台研发新模型,否则到时候还要进行二次开发。但是,再成熟的平台也需要整个团队磨合调试较长时间,绝不可能刚迁移TensorFlow就让它支持重要的业务逻辑。而且,技术平台的升级换代,应该作为技术团队的内部项目,最好对其他团队是透明的,不应该成为减缓对业务支持的直接理由。
|
||||
|
||||
因此,从工程进度和风险角度考虑,第2个技术途径更符合工程实际的需求。
|
||||
|
||||
## 冷启动等业务逻辑对推荐模型的制约
|
||||
|
||||
最后一类制约是来自业务逻辑,或者说应用场景的,最常见的如物品冷启动问题,这类业务问题往往制约了模型的更新和应用的方式。
|
||||
|
||||
之前,我们讲了很多种生成物品Embedding的方法,但在任何公司业务中,物品都不是一成不变的,就像视频网站要不断添加新视频,电商网站会不断加入新的商品。这个时候,新物品的Embedding该如何生成呢?
|
||||
|
||||
对于Item2vec、DeepWalk这类基于物品节点的Embedding模型来说,数据中必须包含新物品的ID,才能够生成它相应的Embedding。这就要求我们必须加快模型的更新速度,让模型尽快学习新物品的数据。这就是业务场景的特点在倒逼我们改进模型的实时性。这个时候,我们就又要思考改进Embedding模型实时性的方法了。
|
||||
|
||||
这里,我总结出了下面三个备选方案。
|
||||
|
||||
方案一:从模型训练pipeline的各个环节入手,看看哪些环节可以优化。比如,我们可以优化Spark数据预处理的过程,加快预处理速度,优化Embedding上线的过程,让Embedding从产生到上线的过程更紧凑。
|
||||
|
||||
方案二:从模型的复杂度入手,看一看能否在不显著伤及效果的前提下,通过降低模型的复杂度来降低训练时间,进而加快模型更新的速度。
|
||||
|
||||
方案三:跳出End2End训练Embedding模型的限制,看看能不能通过其他策略性的手段来生成临时性的新物品Embedding。
|
||||
|
||||
其中,前两个方案需要我们从细节入手来优化工程上的实现,而第三个则要求我们有更灵活的处理思路。这一点也是我想和你多聊一聊的。
|
||||
|
||||
我们在改进推荐系统的时候,不能总陷进机器学习的固定思维里,认为一定要用一些机器学习模型或者深度学习网络去解决问题,我把这样的思维叫做“技术洁癖”。我们应该清楚的是工程师的第一任务是解决问题,而不是搭一个精致好看的技术玩具,所以在推荐模型的基础上,用一些策略性的手段来修补一些边界情况,“bad case”是可以去尝试的。
|
||||
|
||||
回到这个物品Embedding冷启动的例子上,策略性地生成新物品的Embedding就是很好的补充方式,房屋短租行业的巨头Airbnb就给我们提供了一个很好的参考例子。
|
||||
|
||||
在Airbnb平台上,如果一个新的出租屋发布了,但模型还没有学到它的Embedding,Airbnb的推荐系统会怎么做呢?它会通过三个步骤生成新出租屋的Embedding。
|
||||
|
||||
第一步根据新房屋的属性,比如租金价格、房屋类型、面积、几房几厅等特征,来找到和它相似的一批房屋;第二步,在这些相似房屋中找到离它最近的三个;第三步,通过平均这三个最近房屋的Embedding来生成新房屋的Embedding。
|
||||
|
||||
就像图3展示的这样,颜色相近的点代表着Embedding非常接近的房屋,如果一个新房屋落在了图中的某个位置,Airbnb就可以根据它的地理位置和属性,找到相近的房屋并且给它涂上相似的颜色。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8d/2a/8df08c853314f54e20c6a02fc21f672a.jpeg" alt="" title="图3 Airbnb房屋聚类的例子">
|
||||
|
||||
所以我们经常会看到,一些推荐系统中的补充策略往往可以高效地解决一些推荐模型无法解决的棘手问题。
|
||||
|
||||
当然,在我们日常工作中技术间的权衡无时无刻不在发生,小到一个变量取什么名字好,一行代码应该怎么写,大到一个平台应该怎么重构,一个模型应该如何构建。我们这节课的例子当然无法囊括所有的情况,只是希望能帮助你建立起正确的进行技术权衡的思路,做到抓住主矛盾点,做出有利于主要目标的取舍。
|
||||
|
||||
## 小结
|
||||
|
||||
这节课,我们通过三个例子一起探讨了工程落地中技术权衡的问题,希望能帮助你进一步加深了对工程师思维本质的理解。
|
||||
|
||||
事实上,对任何领域来说,工程师思维的本质都是“**在现有实际条件的制约下,以工程完成和技术落地为目标,寻找并实现最优的解决方案**”。
|
||||
|
||||
在推荐系统领域,典型的制约条件有三类:“软硬件环境的制约”,“研发周期的制约”,以及“实际业务逻辑和应用场景的制约”。在这些制约条件下,我认为的技术方案间的权衡之道,就是“抓住主矛盾点,列出备选方案,通过分析对比,作出有利于主要目标的取舍。”
|
||||
|
||||
## 课后思考
|
||||
|
||||
这节课,我们提到了物品冷启动问题的解决方案,你觉得基于Embedding,还有哪些好的冷启动解决方案呢?如果让你来解决的话,在实践中你会作出哪些取舍,倾向于哪种选择呢?
|
||||
|
||||
期待在留言区看到你的分享和思考,我们下节课见!
|
||||
Reference in New Issue
Block a user