推荐系统中的排序技术

4,204 阅读6分钟

在工业应用中,推荐系统通常可分为两部分,召回和排序。

召回阶段对应的是之前几篇文章所讲的各种推荐算法,比如据资料所载,Spotify至少使用了三种算法来生成其广受赞誉的Discover Weekly歌单,包括:

  1. 矩阵分解来学习集体智慧;
  2. NLP处理音乐评论文章与报道;
  3. 对音频使用卷积神经网络进行分析。

这些算法各有特点,音频分析显然可以用于解决冷启动问题,NLP处理音乐评论更是可以学得专业人士的领域知识,它们各自独立运行给出自己的结果,由于独立,算法数目可增可减,亦可各自独立迭代变化。

这个过程会从几千万item中筛选出几百或者上千的候选集,然后在排序阶段选出30首歌曲给到每位用户。这个排序可理解为一个函数,F(user, item, context),输入为用户、物品、环境,输出一个0到1之间的分数,取分数最高的几首。这一过程通常称为CTR预估。

这篇文章来说一下该“函数”的常见形式及基本运作方式。

LR

最简单的是逻辑回归(Logistic Regression),一个广义线性模型。

拿某user的用户画像(一个向量)比如[3, 1],拼接上某item的物品画像比如[4, 0],再加上代表context的向量[0, 1, 1]后得到[3, 1, 4, 0, 0, 1, 1],若该user曾与该item发生过联系则label为1,这些加起来是一个正样本,同时可以将用户“跳过”的item或热门的却没有与用户产生过联系的item作为负样本,label为0,拟合如下方程:

y = \frac{1}{1 + e ^ {- (w ^ {T}x + w_0)}}

其中x即为上述向量,w是与x每个元素相对应的权重,b为截距。其损失函数为:

loss =\sum_{(x, y) \in D}-y \log \left(y^{\prime}\right)-(1-y) \log \left(1-y^{\prime}\right)

其中y为样本的label0或1,y^{\prime}是根据模型预测的0到1之间的数字。

通过降低此损失函数来拟合训练样本来完成模型的训练,利用模型对新的数据进行预测即完成了打分。训练过程参考sklearn的LogisticRegression很容易完成。

传统的LR只能在线下批量处理大量数据,无法有效处理大规模的在线数据流。模型更新可能要一天甚至更多,不够及时。而Google在2013提出了Follow The Regularized Leader(FTRL),一种在线逻辑回归算法。该方法对逻辑回归的目标函数进行了修改,加上各种系统工程上的调优,使得该模型的参数可以在每一个线上数据点进行动态更新。
可以在网上找到不少FTRL的开源实现比如libftrl-python

FM | FFM

FM与FFM分别是Factorization Machine与Field-aware Factorization Machine的简称。

LR作为广义线性模型对特征向量与label之间的非线性关系会很苦手。这时便需要进行特征组合,比如使用线性模型来预测各种近似长方形形状的面积,两个特征为长x_1与宽x_2,那么显然并不能学到一个很好的模型,此时增加一个新的特征x_3=x_1 * x_2,便可以得到很好的效果。

在实际应用中,特征向量的维度是很高的,很难像上例中直接看到这种有意义的组合,考虑所有特征两两组合则线性回归方程变为:

y(\mathbf{x})=w_{0}+\sum_{i=1}^{n} w_{i} x_{i}+\sum_{i=1}^{n} \sum_{j=i+1}^{n} w_{i j} x_{i} x_{j}

除了原本特征的i个权重外还要学习各特征组合情况对应的权重,对于参数w_{ij}的训练,需要大量x_ix_j都不为0的样本,然而由于one-hot编码等原因带来的稀疏性使得这个要求无法达成,那么训练样本不足便会导致w_{ij}的不准确,从而影响模型的质量。

解决方案是使用矩阵分解。在推荐系统中会对user_item_matrix做分解,为user及item学得一个低维的向量来代表自已。那么此处的情况可以与之类比,将特征组合的所有权重表示为一个形状为(i * i)的矩阵,那么w_{ij}即为此矩阵第i行第j列的数值,将此高维度的矩阵进行分解,可以为每个特征得到一个关于权重的隐向量v_i,那么w_{i j}使用v_i点乘v_j即可得到。此时线性方程变为:

y(\mathbf{x})=w_{0}+\sum_{i=1}^{n} w_{i} x_{i}+\sum_{i=1}^{n} \sum_{j=i+1}^{n}\left\langle\mathbf{v}_{i}, \mathbf{v}_{j}\right\rangle x_{i} x_{j}

以上模型称为因子分解机(Factorization Machine),经过一些数学上的变换及处理,该模型可以在O(kn)的复杂度下进行训练和预测,是一种比较高效的模型。

在FM的基础上有人提出了Field-aware Factorization Machine。比如特征向量中有200多维来代表一个user的国家,country.ukcountry.us等等,那么这200多个特征可以认为是属于一个field,区别在为特征x_i学习隐向量时要为每一个field都学到一个相应的隐向量,特征组合权重w_{ij}根据x_i关于x_j所在field的隐向量乘以x_j关于x_i所属field的隐向量而得,线性方程变为:

y(\mathbf{x})=w_{0}+\sum_{i=1}^{n} w_{i} x_{i}+\sum_{i=1}^{n} \sum_{j=i+1}^{n}\left\langle\mathbf{v}_{{i}, f_{j}}, \mathbf{v}_{{j, f_{i}}}\right\rangle x_{i} x_{j}

该方法效果更好,而预测时间复杂度升至O(kn^2)。有开源库libffm的实现以供使用。

GBDT & LR

Facebook在广告CTR预估上的做法是使用梯度提升决策树(GBDT) & LR的方案。

思路是将原本要输入LR的特征向量,先经过GBDT筛选和组合,生成新的特征向量再送到LR中。如图所示:

GBDT作为集成模型,会使用多棵决策树,每棵树去拟合前一棵树的残差来得到很好的拟合效果。一个样本输入到一棵树中,会根据各节点的条件往下走到某个叶子节点,将此节点值置为1,其余置为0。比如训练使用了3棵决策树,每棵决策树有5个叶子节点,样本在各树分别落到了各树从左往右的第1,2,3个节点上,则得到三个one-hot编码为[1, 0, 0, 0, 0][0, 1, 0, 0, 0][0, 0, 1, 0, 0],拼接起来作为转换后的特征向量:[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0],输入到LR模型中得到分值。

此模型为Facebook的广告效果带来了明显的提升,在其发表的论文中,还讨论了各种工程上的实践与细节,包括GBDT与LR的更新频率,降采样的比例实践等,值得参考。实现GBDT可以使用开源的XGBoost包

Wide & Deep

Google在Google Play中对App的推荐排序使用了一种名为Wide & Deep的深宽模型。如下图:

Wide部分就是广义的线性模型,在原本的特征基础上适当加一些特征组合,Deep部分是一个前馈神经网络,可以对一些稀疏的特征学习到一个低维的稠密向量,将Wide与Deep的信息相加,依然使用Sigmond来预测函数,表示为:

P(Y=1 | \mathbf{x})=\sigma\left(\mathbf{w}\_{w i d e}^{T}[\mathbf{x}, \phi(\mathbf{x})]+\mathbf{w}\_{d e e p}^{T} a^{\left(l_{f}\right)}+b\right)

其中\sigma为Sigmond函数,W_{wide}^T是Wide部分的权重,\phi(\mathbf{x})表示Wide部分的组合特征,a^{\left(l_{f}\right)}为Deep网络最后一层输出,b是线性模型的偏重。

将两个模型放到一起联合训练(不同于集成训练需要将各模型单独训练再将结果汇合),互相弥补对方的不足(特征工程困难和可解释性差),该模型为Google Play的在线收益相较于纯Wide模型带来了3.9%的提升。实现可参考tensorflow/models项目。