This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
<audio id="audio" title="19 | 深度学习在推荐系统中的应用有哪些?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/b2/ae/b2b0e5f86a39d77c62a043c460129cae.mp3"></audio>
时至今日,深度学习已经不是一个新名词了,由于它的出现,计算机视觉、自然语言理解等领域的从业者都过上了好日子,错误率大幅度降低。
尤其是那些不断号称端到端的建模方式,让还在埋头于特征工程的推荐系统从业者们跃跃欲试,想赶紧引入深度学习大显身手。
经过这些年学界和业界的不断尝试,深度学习在推荐系统中已经有了很多成功的应用。
所以我在这个专栏里面理应本着实用落地的原则给你介绍一下,到底深度学习在推荐系统中有些什么应用,以及到底是怎么回事?
## 深度学习与推荐系统
深度学习也就是深度神经网络,并不是一个全新的概念,而是枯木逢春;所以它才能在计算力成本下降、效率提升、数据量陡增的今天得以焕发光彩,原来的浅层模型可以逐渐深入,挖掘出事物背后的更多规律和特征。
因此,深度学习的原理在这里并不做过多涉及,如果需要了解,你可以去专攻一下深度学习。
我在这里仅仅用简单的语言力图消除一些概念上的陌生感,在有了一些直观的认识后,直接进入到应用阶段,看看它可以帮助你做什么事。
你还记得矩阵分解吗?矩阵分解是把原来用户和物品之间的大矩阵,分解成了两个小矩阵相乘。这两个小矩阵小在哪?
原始的矩阵中,表示每个用户的向量是物品,表示每个物品的向量是用户,两者向量的维度都特别高不说,还特别稀疏,分解后用户向量和物品向量不但维度变得特别小,而且变稠密了。
业界还把这个稠密的向量叫做隐因子,意图直观说明它的物理意义:用户背后的偏好因子,物品背后的主题因子。
实际上,你完全可以把矩阵分解看成是一种浅层神经网络,只有一层,它的示意图如下。
<img src="https://static001.geekbang.org/resource/image/ec/2b/ec43cc5ebd70e85d3abe02fe58d0712b.png" alt="" />
这个示意图表示了一个用户Ui评分过的物品有I2和I4分解后的矩阵隐因子数量是2用户Ui的隐因子向量就是[w1, w2]物品I2的隐因子向量是[w3, w5]物品I4的隐因子向量是[w4, w6]。
可以把矩阵分解看成是一个拥有一个隐藏层的神经网络,得到的隐因子向量就是神经网络的连接权重参数。
在前面的专栏中,我第一次提到深度学习时,还建议你把逻辑回归看成一个没有隐藏层的神经网络。因此,深度学习,也就是深度神经网络并不是那么神秘,只是深。这个“深”代表了事物的某些本质属性。
这种对本质属性的挖掘,有两个好处。
<li>
可以更加高效且真实地反映出事物本身的样子。对比一下,一张图片用原始的像素点表示,不但占用空间大,而且还不能反应图片更高级的特征,如线条、明暗、色彩,而后者则可以通过一系列的卷积网络学习而得。
</li>
<li>
可以更加高效真实地反映出用户和物品之间的连接。对比一下,以用户历史点击过的物品作为向量表示用户兴趣;用这些物品背后隐藏的因子表示用户兴趣,显然后者更高效更真实,因为它还考虑了物品本身的相似性,这些信息都压缩到隐因子向量中了,同时再得到物品的隐因子向量,就可以更加直接平滑地算出用户对物品的偏好程度。
</li>
这两个好处正是深度学习可以帮助推荐系统的地方。第一个叫做Embedding就是嵌入第二个叫做Predicting就是预测。
其实两者我在前面的内容都已经有涉及了矩阵分解得到的隐因子向量就是一种EmbeddingWord2vec也是一种EmbeddingWide&amp;Deep 则是用来预测的。关于第二种具体来说有几个方向深度神经网络的CTR预估深度协同过滤对时间序列的深度模型。
下面逐一带你认识。首先就是深度学习的第一种应用。
## 各种2vec
你还记得在内容推荐那一章里,我跟你提到过,对内容的挖掘怎么深入都不为过,越深入越好,很多时候甚至优于对排序模型的优化。
那里提到了Word2vec用于学习词嵌入向量。当把一个词表示成一个稠密的向量后就可以计算词的相似度进而可以计算句子的相似度也可以直接把这个稠密向量作为特征输入给高级的预测模型。
于是这个2vec的思想就被发扬光大了。首先还是在文本领域从Word2vec到Sentence2vec再到Doc2vec。其实思想都类似甚至会让你觉得有上当受骗的错觉。
简单介绍一下Word2vec。你知道Word2Vec最终是每个词都得到一个稠密向量十分类似矩阵分解得到的隐因子向量得到这个向量有两个训练方法。
先说第一个方法想象你拿着一个滑动窗口在一篇文档中从左往右滑动每一次都有N个词在这个窗口内每移动一下产生N-1条样本。
每条样本都是用窗口内一个词去预测窗口正中央那个词明明窗口内是N个词为什么只有N-1条样本呢因为正中央那个词不用预测它本身啊。这N-1条样本的输入特征是词的嵌入向量预测标签是窗口那个词。示意图如下所示。
<img src="https://static001.geekbang.org/resource/image/88/eb/88a75598553a0e4ba13b1f7281e6e3eb.png" alt="" />
图中把N-1个样本放在一起示意的无法看出隐藏层实际上输入时每个词可以用One-hot方式表示成一个向量这个向量长度是整个词表的长度并且只有当前词位置是1其他都是0。
隐藏层的神经元个数就是最终得到嵌入向量的维度数,最终得到的嵌入向量元素值,实际上就是输入层和隐藏层的连接权重。示意图如下。
<img src="https://static001.geekbang.org/resource/image/72/e9/72b1290345d26b4cd5743adc71a570e9.png" alt="" />
至于Word2vec的第二种训练方法则是把上述的N-1条样本颠倒顺序用窗口中央的词预测周围的词只是把输入和输出换个位置一样可以训练得到嵌入向量。
这里注意看上去Word2vec是构造了一个监督学习任务但实际上并不是为了得到一个预测模型在实际中用词预测词是为了得到词的嵌入向量Embedding本身就是目的。
我们沿着Word2vec这种学习嵌入向量的思路想既然词可以表示成一个稠密向量干这干那那不如来个Sentence2vec把一个句子表示成一个嵌入向量通常是把其包含的词嵌入向量加起来就完事了。
而Doc2vec则略微一点点不同说明一点多个句子构成一个段落所以这里的Doc其实就是段落。Doc2vec在窗口滑动过程中构建N-1条样本时还增加一条样本就是段落ID预测中央那个词相当于窗口滑动一次得到N条样本。
一个段落中有多少个滑动窗口就得到多少条关于段落ID的样本相当于这个段落中段落ID在共享嵌入向量。段落ID像个特殊的词一样也得到属于自己的嵌入向量也就是Doc2vec。
<img src="https://static001.geekbang.org/resource/image/7a/ad/7a3664b4b6533e5dcb9be136484870ad.png" alt="" />
理解了Word2vec之后它在推荐系统中的应用就有举一反三的应用。第一个就是Product2vec你看这名字就知道我要干嘛了就是给商品学习一个嵌入向量。
这简直就是照着词嵌入的做法来,把用户按照时间先后顺序加入到购物车的商品,看成一个一个的词,一个购物车中所有的商品就是一个文档;于是照猫画虎学出每个商品的嵌入向量,用于去做相关物品的推荐,或者作为基础特征加入到其他推荐排序模型中使用。
类似的如果是应用商场的App推荐也可以依计行事把用户的下载序列看成文档学习每个App的嵌入向量。
虽然这个嵌入学习得到的结果样子和矩阵分解得到隐因子向量一样但是机制不同可以两者都有拼接成一个更大的稠密向量去做你喜欢做的事比如CTR预估。
且慢各种2vec的做法其实还不算深度学习毕竟隐藏层才一层而已。如果要用更深的模型学习嵌入向量就是深度学习中的AutoEncoder。
它是一种输入和输出一模一样的神经网络这个神经网络就一个目的更加清楚地认识自己在这个优化目标指导下学到的网络连接权重都是不同的嵌入向量所以也叫做AutoEncoder自动编码器。
从输入数据逐层降维,相当于是一个对原始数据的编码过程,到最低维度那一层后开始逐层增加神经元,相当于是一个解码过程,解码输出要和原始数据越接近越好,相当于在大幅度压缩原始特征空间的前提下,压缩损失越小越好。
<img src="https://static001.geekbang.org/resource/image/83/00/83c77b82bc4e61f3064052700d54ff00.png" alt="" />
以上是深度学习如何通过学习更好地表达事物特征,帮助推荐系统取得更好效果的做法。
## YouTube视频推荐
以YouTube为例它们在自己的推荐系统大量用到了深度学习用于推荐更好的视频给用户。我来给你仔细描述一下具体到视频推荐场景深度学习可以在哪些地方用到。
首先Youtube把推荐的预测任务看成是一个多分类这个和之前常规的推荐系统要么预测行为要么预测评分的做法不太一样而是把候选物品当成多个类别预测用户下一个会观看哪个视频。
$$P(w_{t}=i | U,C) = \frac{e^{v_{i}u}}{\sum_{j\in{V}}{e^{v_{j}u}}}$$
这个公式中U是用户C是场景输入是视频的嵌入向量和用户的嵌入向量。这里就涉及了先要使用深度神经网络从用户历史反馈行为和场景信息中学习物品和用户的嵌入向量。整个推荐排序模型示意图如下。
<img src="https://static001.geekbang.org/resource/image/35/70/35ae8d34f0481ec0bbdf764883f2f570.png" alt="" />
看这个推荐模型示意图,就可以看到深度学习应用在了哪些地方。
1. 根据观看历史把视频变成了嵌入向量然后平均后作为输入特征之一这个和前面的Product2vec的思路一致把观看历史看成文档观看的视频看成词。
1. 搜索Query也变成了嵌入向量平均之后作为输入特征之二。
1. 人口统计学信息统统都嵌入了。
1. 还加入视频的年龄信息,也就是在预测时,视频上传多久了。
1. 所有这些不同的嵌入向量拼接成一个大的输入向量经过深度神经网络在输出层以Softmax作为输出函数预测下一个观看视频。
在模型训练时以Softmax作为输出层但是在实际线上预测服务时由于模型关心相对顺序所以并不需要真的去计算Softmax而是拿着用户的特征向量做近似的近邻搜索只生成最相近的一些推荐结果。
整个推荐系统非常好理解也比较好落地所有的模型都可以通过TensorFlow快速实现。
## 总结
通过观察YouTube的推荐系统中所用到的深度学习来看在排序方面深度神经网络已经崭露头角包括前面讲融合模型时专门讲到的Wide&amp;Deep模型也是深度学习在排序方面的贡献。
除此之外,深度学习更多发挥作用的地方是特征表达上,各种嵌入技术得以让物品、用户、关系等对象的特征化有更好的输出。
今天主要介绍了深度学习在推荐系统可以发挥哪些作用同时以YouTube为例介绍了国际大厂在这方面的落地情况。
从YouTube的推荐系统可以看出深度学习主要贡献在于特征表达学习和排序模型上。当然深度学习纵有千般好如果你的数据量少得可怜那么你也只能过过眼瘾很难真正落地执行。
给你留一个思考题我们一起交流。为什么YouTube排序模型训练时规规矩矩按照Softmax输出以交叉熵作为目标函数但在线上运行时却可以按近邻搜索去近似背后有什么考虑欢迎留言一起讨论。

View File

@@ -0,0 +1,151 @@
<audio id="audio" title="20 | 用RNN构建个性化音乐播单" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/8a/10/8ab8d1628502c5b54cbc68bc9d171210.mp3"></audio>
时间是一个客观存在的物理属性,很多数据都有时间属性,只不过大多时候都把它忽略掉了。前面讲到的绝大多数推荐算法,也都没有考虑“用户在产品上作出任何行为”都是有时间先后的。
正是认识到这一点有一些矩阵分解算法考虑了时间属性比如Time-SVD但是这种做法只是把时间作为一个独立特征加入到模型中仍然没有给时间一个正确的名分。
## 时间的重要性
时间属性反应在序列的先后上比如用户在视频网站上观看电视剧会先看第一集再看第二集股市数据先有昨天的再有今天的说“我订阅了《推荐系统36式》专栏”这句话时词语也有先后这种先后的关系就是时间序列。
具体到推荐系统领域,时间序列就是用户操作行为的先后。绝大数推荐算法都忽略操作的先后顺序,为什么要采取这样简化的做法呢?因为一方面的确也能取得不错的效果,另一方面是深度学习和推荐系统还迟迟没有相见。
在深度学习大火之后对时间序列建模被提上议事日程业界有很多尝试今天以Spotify的音乐推荐为例介绍循环神经网络在推荐系统中的应用。
## 循环神经网络
循环神经网络也常被简称为RNN是一种特殊的神经网络。再回顾一下神经网络的结构示意图如下
<img src="https://static001.geekbang.org/resource/image/61/c6/61177f813f5f493966f8f9beaa395dc6.png" alt="" />
普通神经网络有三个部分输入层x隐藏层h输出层o深度神经网络的区别就是隐藏层数量有很多具体多少算深这个可没有定论有几层的也有上百层的。
把输入层和隐藏层之间的关系表示成公式后就是:
$$h = F(Wx) $$
就是输入层x经过连接参数线性加权后再有激活函数F变换成非线性输出给输出层。
在输出层就是:
$$O = \phi(Vh) $$
隐藏层输出经过输出层的网络连接参数线性加权后再由输出函数变换成最终输出比如分类任务就是Softmax函数。
那循环神经网络和普通神经网络的区别在哪?
区别就在于普通神经网络的隐藏层参数只有输入x决定因为当神经网络在面对一条样本时这条样本是孤立的不考虑前一个样本是什么循环神经网络的隐藏层不只是受输入x影响还受上一个时刻的隐藏层参数影响。
我们把这个表示成示意图如下:<br />
<img src="https://static001.geekbang.org/resource/image/28/71/285fdbb62e517ddb2099d3b6c87f8371.png" alt="" />
解释一下这个示意图。在时刻t输入是xt而隐藏层的输出不再是只有输入层xt还有时刻t-1的隐藏层输出h(t-1),表示成公式就是:
$$h_{t} = F(Wx_{t} + Uh_{t-1})$$
对比这个公式和前面普通神经网络的隐藏层输出,就是在激活函数的输入处多了一个 $Uh_{t-1}$ 。别小看多这一个小东西,它背后的意义非凡。
我一直在传递一个观点隐藏层的东西包括矩阵分解和各种Embedding得到的隐因子是对很多表面纷繁复杂的现象所做的信息抽取和信息压缩。
那么上一个时刻得到的隐藏层,就是对时间序列上一个时刻的信息压缩,让它参与到这一个时刻的隐藏层建设上来,物理意义就是认为现在这个时刻的信息不只和现在的输入有关,还和上一个时刻的状态有关。这是时间序列本来的意义,也就是循环神经网络的意义。
## 播单生成
了解了循环神经网络原理之后,我再和你一起来看下它如何应用在推荐系统中的。
在网络音乐推荐中尤其是各类FM类App提倡的是一直听下去比如是你在做家务时你在开车时一首歌接着一首歌地播下去就很适合这些场景。
通常要做到这样的效果,有这么几种做法。
1. 电台音乐DJ手工编排播单然后一直播放下去传统广播电台都是这样的。
1. 用非时序数据离线计算出推荐集合,然后按照分数顺序逐一输出。
1. 利用循环神经网络,把音乐播单的生成看成是歌曲时间序列的生成,每一首歌的得到不但受用户当前的特征影响,还受上一首歌影响。
Spotify采用了第三种办法下面我就详细讲解这个推荐算法。
### 1.数据
个性化的播单生成不再是推荐一个一个独立的音乐而是推荐一个序列给用户。所用的数据就是已有播单或者用户的会话信息。其中用户会话信息的意思就是当一个用户在App上所做的一系列操作。
把这些数据,看成一个一个的文档,每一个音乐文件就是一个一个的词。听完什么再听什么,就像是语言中的词和词的关系。
### 2.建模
你可以把播单生成看成由若干步骤组成每一步吐出一个音乐来。这个吐出音乐的动作实际上是一个多分类问题类别数目就是总共可以选择的音乐数目如果有100万首歌可以选择那么就是一个100万分类任务。
这个分类任务计算输入是当前神经网络的隐藏状态然后每一首歌都得到一个线性加权值再由Softmax函数为每一首歌计算得到一个概率。表示如下
$$p(o_{ti} | h_{t}) = \frac{e^{v_{i}h}}{\sum_{j \in M}{e^{v_{j}h}}} $$
假如隐藏层有k个神经元也就是说h是一个k维向量输出层有m首歌可选所以是一个One-hot编码的向量也就是说一个m维向量只有真正输出那首歌i是1其他都是0那么输出层就有k乘以m个未知参数。
再往前计算隐藏层神经元输出时不但用到输入层的信息在这里输入层也是一首歌也有m首歌可以选择所以输入向量仍然是一个One-hot编码的向量。
除此之外每一个隐藏层神经元还依赖上一个时刻自己的输出值隐藏层神经元是k个一个k维向量。
按照隐藏层计算公式就是下面的样子。
$$h_{t} = F(Wx_{t} + Uh_{t-1})$$
W就是一个m乘以k的参数矩阵U就是一个k乘以k的参数矩阵。
如此一来,循环神经网络在预测时的计算过程就是:
当用户听完一首歌要预测下一首歌该推荐什么时输入就是一个One-hot编码的m维度向量用m乘以k形状的输入层参数矩阵乘以这个m向量然后用隐藏层之间的k乘k参数矩阵去乘以上一个隐藏状态向量两者都得到一个k维向量相加后经过非线性激活函数比如ReLU这样就得到当前时刻的隐藏层输出值。
再用当前时刻的隐藏层输出值经过k乘以m形状的输出层参数矩阵得到一个m维向量再用Softmax把这个m维向量归一化成概率值就是对下一首歌的预测可以挑选最大概率的若干首歌作为输出或者直接输出概率最高的那首歌直接播放。
这个计算过程示意图如下:
<img src="https://static001.geekbang.org/resource/image/79/28/79e67fc2dd3172dd1e331d6ebd5e9a28.png" alt="" />
一个播单生成模型的参数就是这么三大块。
1. 连接输入和隐藏之间的矩阵 $W_{m\times{k}}$
1. 连接上一个隐藏状态和当前隐藏状态的矩阵: $U_{k \times {k}}$
1. 连接隐藏层和输出层的矩阵 $V_{k\times{m}}$。
得到了这些参数,就得到了播单推荐模型,怎么得到呢?这里就再简要讲一下神经网络的参数如何训练得到。
你知道一个简单的逻辑回归模型参数如何训练得到吗?大致是这样几步:
1. 初始化参数;
1. 用当前的参数预测样本的类别概率;
1. 用预测的概率计算交叉熵;
1. 用交叉熵计算参数的梯度;
1. 用学习步长和梯度更新参数;
1. 迭代上述过程直到满足设置的条件。
神经网络的参数学习大致也是这个过程但略为复杂的地方就是第4步和第5步因为逻辑回归没有隐藏层神经网络有隐藏层。那怎么办呢我不打算讲解具体的做法我打算给你建立一个直观印象。
还记得下面这个函数对x求导是怎么计算的吗
$$f(x) = g(x)^2;$$
$$g(x) = e^x$$
函数f(x)是另一个函数gx的平方函数g(x)又是一个指数函数。那么要对f(x0求导就是一个链式规则先把g(x)看成个一个整体求导再乘以g(x)的求导结果:
$$f^{}(x) = 2g(x)e^{x} = 2e^{x}e^{x} = 2e^{2x}$$
你就需要记住一点:链式规则,一路求导下去。
现在回到神经网路的训练,这个方法有个高大上的名字,叫做误差方向传播。
实际上就是链式求导法则,因为要更新参数,就需要计算参数在当前取值时的梯度,要计算梯度就要求导,要求导就要从交叉熵函数开始,先对输出层参数求导计算梯度,更新输出层参数,接着链式下去,对输入层参数求导计算梯度,更新输入层参数。
交叉熵是模型的目标函数,训练模型的目的就是要最小化它,也就是“误差反向传播”的“误差”。
相信聪明如你已经在直观上理解了一个普通神经网络是怎么训练的了那么一个循环神经网络的参数训练有何不同呢唯一不同就是多了一个参数矩阵连接当前隐藏层和上一次隐藏层的参数矩阵U也是链式求导法则的传播路径也就是多了一些求导计算更新参数方式并没有什么不同。
## 总结
好了,今天介绍了如何使用循环神经网络推荐音乐播单,播单是一个时间序列,听完上一首歌会影响下一首歌。
循环神经网络和普通神经网络相比,就是在两个时刻的隐藏状态之间多了网络连接。看上去这个网络连接只与上一个时刻有关,事实上,上一个状态又与上上个状态有关,所以实际上任意一个时刻的状态是与此前所有的状态有关的。
今天的应用虽然是以播单推荐为例,但其实循环神经网络还可以应用在很多其他地方,你对循环神经网络的应用有任何问题都可以留言给我,我们一起讨论。
感谢你的收听,我们下期再见。
<img src="https://static001.geekbang.org/resource/image/10/50/1025014d381c4913aae6eaef553d7750.jpg" alt="" />