笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值,找寻数据的秘密,笔者认为,数据的价值不仅仅只体现在企业中,个人也可以体会到数据的魅力,用技术力量探索行为密码,让大数据助跑每一个人,欢迎直筒们关注我的公众号,大家一起讨论数据中的那些有趣的事情。
我的公众号为:livandata
不知大家对推荐算法有没有一个系统的了解,推荐本身的逻辑很简单,就是需要找到用户喜欢的物品,然后呈现到用户的面前,这其实像是一个算法与用户的博弈,当用户到APP上的时候,留下一串足印,算法根据用户的足印和基本信息推断用户来这里想要做什么?或者说想要去什么地方?然后给他推荐他需要的东西。
推荐的基本结构基本上可以分成两类:
1)基于协同理论的推荐算法:
如上文,协同理论就是找到相似的用户/物品或者相似的标签,然后根据交易历史中用户和物品的交互情况进行推荐。算法在进行过程中遇到各种问题,程序员用各种方法来解决这些问题,久而久之,延伸出了现在各种复杂的协同推荐模式。
常见的问题有:
1.1)人工进行特征工程的问题:
1.2)运算量庞大的问题:
1.3)特征挖掘层次不足的问题:
1.4)如何使用社交链的问题:
2)基于模型分类的推荐算法:
推荐从模型的角度理解可以看作是对用户喜好的预测,即为一个二分类的预测模型,根据用户的行为预测用户对某个商品喜欢不喜欢,进而根据喜好进行推荐。
基于模型的推荐比较多的应用于点击率预测,用户是否会购买某个商品的预测,在主流思路中依然是以协同为主。
下面我们延续上文的讨论,在上面常见问题的基础上深化我们对协同推荐的理解:
1、运算量庞大的问题:
协同推荐的一个常见问题就是运算量的问题,每一次的迭代需要对全部的用户行为和商品信息进行复盘,计算出最新的相似系数。用户和商品量少的情况下还好说,可如果用户超过一亿,商品有上百万个呢?这一情况下UV矩阵就会非常大,每运算一次都需要耗费很大的资源,而且数据存在较多的稀疏的问题,几百万的商品,大部分用户点击的只有十几个,剩下的部分全都是零,极大的浪费运算资源。
所以,需要找寻一些方法来降低数据的运算,即常说的降维。
一提到降维这个词,有没有很熟悉,对:很多人想到PCA、SVD等等常规的降维方法,在推荐算法中也有对应的基于降维的推荐方式:
——基于矩阵分解的系统推荐:
基于矩阵的推荐算法是以SVD奇异值分解为基础进行的。
假设上图为用户的评分矩阵,经过上文的讲解,这个矩阵已经非常熟悉了吧,我们假设他现在有一亿行一亿列,那该如何降维呢?
我们在学习奇异值的时候,经常会听到一句话:前10%的奇异值之和占了全部奇异值之和的80%以上的比例。所以,我们只需要通过奇异值计算的方式找到前10%的奇异值k个,计算他对应的k个特征向量,即可大规模的降低上面UV矩阵的计算资源。
经过SVD的运算得到m*k的新的矩阵,我们就可以用这一矩阵替代UV矩阵进行相似度计算了。
基于新的低阶矩阵我们计算出用户的相似度/物品相似度,然后再对相似用户进行推荐,计算效率大大的提升。
这样运算有两个好处:
其一:减轻了线上存储和计算的压力;
其二:解决了矩阵稀疏的问题;
也有一个坏处:
SVD是减轻了UV矩阵的运算量,但是SVD自身的运算呢?
从一个矩阵拆分成三个矩阵,这本身就意味着巨大的运算量,所以,在平时工作中很少使用SVD,而是使用隐语义模型,隐语义模型与SVD不同,他把矩阵拆分成了两个矩阵。
——ALS模式下隐语义推荐算法:
ALS是交替最小二乘法,主要是用来优化最小损失函数的。
即根据用户评分矩阵A,用求最小损失函数的方法求解出两个分解的参数矩阵:
K即为隐含的因子个数。
对应的损失函数为:
Cij即为用户偏爱某个商品的置信程度,交互次数多的权重就会增加。
这里,协同过滤就成功转化成了一个优化问题。
通过ALS计算出用户因子矩阵P和物品因子矩阵Q。
虽然降低了运算量,但是对于大数据集,还是推荐使用spark进行计算。
ALS模式的优点在于能够有效的解决过拟合的问题,同时对算法的可扩展性也有所提高。
2、特征挖掘层次不足的问题:
虽然说矩阵分解的方法进行相似性计算已经非常成熟,但是,聪明的读者也已经发现,矩阵分解只是针对矩阵进行的一次运算,对特征的挖掘层次明显不足,而且,矩阵也没有用到用户和物品本身的特性。
而深度学习中的稀疏自编码模式可以有效的解决这两个问题:
——稀疏自编码模式下的推荐算法:
稀疏自编码是用神经网络的方式来压缩原始物品的特征向量,使物品的相似度运算能在较低纬度下进行。
如图所示即为稀疏自编码的网络结构,简单来讲,稀疏自编码就是一个hw,b(x) = x的函数,设定神经网络的输入值和输出值都是x,中间多个隐含层的节点数量小于输入和输出层的节点数量(输入和输出层的节点数量一样多),对网络进行训练,输出层使用softmax进行训练,得到最后的隐含层为输出矩阵V,这一矩阵V即为经过稀疏自编码之后得到的物品的低维矩阵。
通常情况下,隐含层会有多层,以保证输入层的数据得到充分的运算,也就解决了上面讲的特征挖掘层次不足的情况,同时网络输入的是物品的属性信息,所以,第二个问题也得以解决。
假设一个物品的特性为v1=(x1,x2,x3,x4,x5,x6),经过上面的模型运算之后,向量就会变成v1=(k1, k2, k3)。
在使用稀疏自编码进行运算时有两个比较常用的延伸思路,是在使用稀疏自编码进行数据降维时频繁使用的方法,如下:
1)添加随机因子:
如果直接将输入值看做输出层,有可能使输入层的数据直接穿透隐含层到达输出层,起不到准确训练的效果,此时可以在输入层中加入一些混淆因子,使输入和输出层不完全一致,即避免了数据穿透的问题。
随机因子应该是远远小于x的值,以保证搅乱一致性的同时不会引发x值变化。
2)用已知的X、Y值:
在多层隐含层的自编码模式中有一种典型的方法是:栈式自编码。
即已知X和Y的值,通过输入X,输出Y训练多层隐含层,然后得到最后一个隐含层,作为X的压缩向量。
还是刚才的假设:v1=(x1,x2,x3,x4,x5,x6),输出层的标签为Y=(y1、y2、y3),经过两层隐含层的计算得到v1 = (k1, k2, k3, k4),这一特征向量涵盖了输入端的物品的用户评分属性和输出端的物品分类标签属性,是一个综合性的向量。基于这样的数据进行物品相似度计算能获得较好的效果。
写到这里,大家有没有发现,稀疏自编码并没有用上面的评分表,而是使用了基于内容的一些思路,推荐的协同逻辑发生了变化。所以,推荐本身不是基于一个固定不变的思路进行优化的,有时会不停的跳跃,直到找到较好的方法。
3、如何使用社交链的问题:
不管什么样的APP都希望能够使用到社交网络的信息,因为社交网络本身就是一个计算良好的U-U矩阵,能够更准确的表示出用户的相似度。
社交网络主要有两种模式:兴趣图谱和社交图谱。
导致网络中会有三种常见的社交数据:
1)双向确认的社交数据,比如微信,A<——>B;
2)单向关注的社交数据,比如微博,A——>B;
3)基于社区的社交数据,比如知乎,A——>社区<——B;
在推荐算法中,社交网络最常用的用法还是与协同推荐结合使用,我们先看一个社交网络的图片:
从图中可以看出,B有两人关注(A,E),有一人是好友(F),B购买了两个物品(i1,i4)。上图为社交网络的一个完整的图形,我们的推荐也是基于这一图形进行的。
在社交网络下,计算好友相似度的几种方法:
1)对于用户u和v,可以使用共同好友比例计算相似度:
Out(u)是用户u指向其他好友的数量,|out(u)∩out(v)|是用户u和v共同指向好友的数量。
2)使用共同被关注的用户数量计算用户相似度:
In(u)是指用户被其他用户指向的数量。
3)用户u关注的用户中,有多大比例也关注了用户v:
这一公式含有了热门惩罚因子。
有了基于网络的数据,我们再结合前面提到的协同理论,会得到一个综合的用户相似度的分数:
基于上面的数据,我们可以再使用基于用户协同的推荐方法,计算得到推荐结果。
上面是基于社交网络最直接的计算方法,通过1、2两部分的描述,聪明的读者是不是会有一个疑问呢?
对的
运算量的问题、特征挖掘层次的问题。
基于社交网络的推荐自然也会遇到这两个问题,那么,该如何解决呢?
我们基于深度学习的思路,对这个问题进行了解答,主要是使用了network embedding的方法,计算出每个用户的一个坐标,用这个坐标表示用户在这个图中的位置,当进行用户相似度计算时,只需要通过这些坐标进行计算就可以了。
这个套路有没有很熟悉,没错,就是前面的降维,同样的思维又在社交网络的场景下重演了,不过依然有效,node2vec是network embedding中的一个常用方法,下面我们简单介绍一下,如有兴趣,可以百度一些论文,深度了解:
——node2vec在社交网络推荐中的应用:
这一方法主要分两个步骤:
1)对网络进行随机游走采样,将采到的节点和上下文形成组合(random walk),推荐场景下随机游走添加了p和q两个参数,以调节游走过程中是深度优先还是广度优先:
第一步:先选择t作为初始步,从t->v,在v的基础上确定下一步的节点;
第二步:计算t与v之间的距离d,并以这个距离来计算游走的概率a;
d=0,表示点往回走了,游走概率为1/p;
d>distincev-x的距离时,即接下来的点距离比上一步的距离近一点,则游走概率为1;
d<distincev-x的距离时,即接下来的点距离相对较远,游走概率为1/q;
如果p>max(1,q),则1/p最小,则往回游走的概率最小,则深度优先;
如果p<min(1,q),则1/p最大,则往回游走的概率最大,则广度优先;
第三步:游走步数达到N步时,游走停止,则结合上下文得出的序列便形成了。
如图:
上面图中,游走的路径为:A-a-B-c。
2)用词向量(word2vec)对上面的组合进行建模,得到网络节点表达向量,即用户向量:
将上面游走产生的用户序列添加到word2vec中,生成一个低维的用户向量,以此来确定用户的坐标。
word2vec有两种计算方式,主要是:Skip-gram和CBOW,如图可知两种的区别:
具体细节可以百度一下,展开的话估计又是一篇大文章了。
其实只要了解,这两种方法都是用神经网络的方式降维就可以了,就是一个高级的PCA而已。
比如:输入的是100维,输出的是20维。
4、人工进行特征推荐的问题:
上面我么详细讲解了推荐系统中常见的一些问题,以及对应的解决方案,但是,有没有人想更进一步呢?
必然是有的~
特征工程一直被称作是建模的基础,这一基础一直作为数据从业人员的水平衡量仪,肚子里有多少货,从特征工程中就可以知道了。
凡人都会有偏差,有没有方法能够尽可能的减少对人工特征工程的依赖呢?
~有~
通过对数据的深度了解,我们可以根据用户的特性采用一些模型组合的方式,尽量降低数据的人工特征工程过程,输入原始数据,比如: LR+DNN模型、DeepFM模型等,综合深度学习在特征方面的优势,采用模型融合方式尽可能的降低了对人工特征工程的依赖,但是在这里要说一点,这里只是减少了人工特征工程,工作中人工部分是必不可少的。
下面我们介绍一下基于深度学习的推荐算法思路:
——LR+DNN模型:
LR模型的优点:简单、可扩展、可解释性强,在低阶维度上效果比较明显;
LR模型的不足:对不在训练集中的特征不具备泛化能力;
DNN模型的优点:对未出现的特征存在一定的泛化能力,减轻特征工程的压力;
DNN模型的不足:很难学习低维的特征,另外,客户如果有明显的偏好,对其他项都不感兴趣时,模拟出来的效果不好,因为DNN会对0项的特征模拟出一些特征值,进行相应的推荐(这个是DNN泛化能力的体现);
为了解决特征工程时组合深度不够、人工特征工程过多的问题,大家研究出了将两个模型融合的方法:LR+DNN
一方面LR模型对低维度的特征有较好的拟合效果,另一方面DNN模型对高维度的特征有较好的拟合效果,同时兼顾了模型的广度和深度,结构如图:
从图片我们可以看出,左侧为LR模型,右侧为DNN模型,将这两个结构融合在一起,然后用统一的softmax函数进行输出,就能形成一个同时具有记忆能力和泛化能力的模型。
——DeepFM模型:
除了上面的LR+DNN模型,DeepFM模型也是一个被广泛应用的深度学习模型,这一模型的特点就是在学习user behavior背后的特征组合,从而最大化优化推荐效果。
DeepFM是用FM和DNN融合而成的模型,其特性与上面模型有一定的相似之处,我们先介绍一下FM:
FM是对LR的一次升级,通常情况下,我们使用LR模型是假设LR中各个元素都是独立的,比如x1和x2是相互独立的,然后再进行运算,但是实际上x1和x2有可能存在交叉影响,即x1*x2对y值是有影响的,因此需要将x1*x2考虑在模型中。为了解决特征交叉的问题,大家发明了FM+DNN的结构,也就是DeepFM模型:
感觉这张图已经被无数人引用,都已经不清楚了,不过这也说明了这个模型的重要性,左侧是FM模型,右侧是DNN模型,其对应的预测结果为:
这个模型的特点有两个:
其一:添加了Dense Embedding层,即两个模型共享同一套输入数据,这样保证了数据的统一,提高了训练效率,不需要额外的特征工程,进一步减少了人工干预;
其二:模型将输入数据分成多个field,在field的基础上进行模型训练,减少了训练的运算量。
我们介绍一下field思想:
对于离散的特征,我们通常的做法是采用全连接的方式输入,但是,问题在于如果特征过多,神经网络中的参数会指数级上升,导致模型运算量过大,甚至训练不成功。
如图:
One-hot输入:
50亿个参数,是不是有些恐怖?
所以,大家想到了用field的方式,将输入层进行一定程度上的组合隔离,组建一个个field,并将field输入到Dense层,使维度压缩到稠密向量中,如图:
这样就减少了输入数据的数量,避免全连接输入。
我们对模型进行一个细分了解:
其一:FM部分:
输入层的数据是one-hot之后的变量,每个x都会被分解成(0,0,0,0,1,0)样式的向量,将这些向量concat成一个向量,即可完成输入层输入。
Dense层中的数据是Vij,每个field中的向量(Vi*j-1,Vi*j……Vi*j+n)即为FM公式中的Vi。将输入层中每个x转化的one-hot向量分割成一个field,则每个field中都含有一个1,其他的元素都是0,x经过各个权重进入Dense层的过程,得到的是x*权重之和,而x此时只有一个1,其他都为0,所以,Dense中实际上是保留了1的权重,即为Vij。
FM层中,一阶求和的部分即为one-hot向量中1的求和,因此,可以看到图中输入层的数据直接输入到了FM部分,二阶部分是对<Vi*Vj>xi*xj的计算,由于x都是1,所以这一公式实际上是对权重向量<Vi*Vj>的运算,所以看到图中每两个field输入到一个乘运算节点中。
经过上面一阶和二阶的运算,我们可以确定出FM的模型了,然后将FM的运算结果输入到sigmoid函数中。
上面即为FM部分的讲解,下面我们了解一下深度部分。
其二:深度部分:
输入层的变化就不做描述了,和FM层是一致的,这也是这个模型的优势——共享输入。
经过Dense embedding之后,输入数据变成了Vij表示的稠密向量,将这个稠密向量输入到DNN的隐含层即可获取高维度融合的特征模型。
上面的描述大家是否清楚了呢?
经过上面的描述,大家是不是对推荐系统有一个深入的了解呢?
笔者在学习这部分内容的时候了解到,模型的构建过程中,如何建模用户时序行为并将这些行为和要排序的item相关联,是建模过程中的难点,用户的每一次操作都是有目的的,多次的操作行为会产生一定的时序,这个时序信息会不会给模型带来正向的影响呢?我想这是肯定的。
在通过深度学习进行推荐时,形成embedding的过程需要将用户操作的上下文作为特征信息填入其中,就是这个目的,比如用户的观看历史数据、用户搜索历史数据等,这样的思路就是添加上下文信息到用户向量中,以完善用户的向量信息。
u=f_DNN(user_info, context_info)
训练中常用的模式有:
从图中我们可以看出,模型的训练需要融合尽量多的特征数据。
好了,就写到这里吧~
算法本身还是有很多值得挖掘的东西的,笔者会尽力的将自己的思考结论逐步的分享出来,希望有机会与大家一起讨论。