重排打散论文¶
小红书21年的论文,Sliding Spectrum Decomposition,引用30次,当成关于重排环节打散算法的文献综述看一下。
-
打散是做什么的:
- 排序环节预估的用户对物品的分数,但是展示给用户是一次性展示多条的,一屏可能10来条,需要让这个列表尽可能丰富,不要全是类似的内容,也就是把pointwise rank变成listwise rank的过程。
-
打散不是什么:
- 不是用于提高推荐意外度的,要提高意外度,还是需要从点估计入手建模,例如之前看的PURS。
- 打散算法:
- 一种是纯规则的,比如,要求列表中的物品标签不同,发博者不同等;业界常见rerank/policy模块
- 不依赖规则的,使用物品之间的相似度定义,或者物品向量,算法包括MMR,DDP,以及小红书SSD,在保证选的物品预估总分数尽量高的条件下,尽量去打散
论文阅读顺序
- 学习一下MMR,DPP的概念,以及与推荐/信息检索的应用关联
- 看行业先驱Hulu,Youtube和小红书分别是怎么应用的
1、MMR¶
Maximal Marginal Relevance(极大边缘相关),CMU的98年论文,3000次引用,就2页超简洁,喜欢。从搜索引擎问题就提出了效用等于相关度加意外度了,那时还没有embedding定义,都是similarity的概念。
A new document ranking method is one where each document in the ranked list is selected according to a combined criterion of query relevance and novelty of information. The latter measures the degree of dissimilarity between the document being considered and previ- ously selected ones already in the ranked list. A document has high marginal relevance if it is both relevant to the query and contains minimal similarity to previously selected documents.
从公式中就可以看出,假设推荐系统中,用户已有兴趣是selected的,候选的物料将和每一个已有兴趣计算相似度,并用max做聚合作为最大相似度,从效用中减去这个相似度惩罚项,就是带意外度的分数了。和我们做法如出一辙,区别是,我们的聚合函数是topkpooling。
里面的\(\text{Sim}^1(D_i, Q)\),\(Q\)对应推荐系统的user,\(D_i\)对应候选的item。
总结说,这个方法应用在结果重排序(reordering)上效果不错。
2、DPP¶
Determinantal Point Process,1975年量子物理中的方程,概率图模型,粒子之间相互排斥,或者说是聚类模型的反模型(Dirichlet过程的反过程),类间距离最大,引导出的效果。参考的是宾大老师2013年的一个导论,巨长有120页,但很严谨。
In mathematics, a Determinantal Point Process is a stochastic point process, the probability distribution of which is characterized as a determinant of some function.
DPP can also serve as a model for general repulsive phenomena
The essential characteristic of a DPP is that these binary variables are negatively correlated; that is, the inclusion of one item makes the inclusion of other items less likely. The strengths of these negative correlations are derived from a kernel matrix that defines a global measure of similarity between pairs of items, so that more similar items are less likely to co-occur. As a result, DPPs assign higher probability to sets of items that are diverse
2.1 定义¶
2.1.1 代数定义¶
数学表达式,\(Y\)是\(N\)个元素集合\(\{i_1, ..., i_N\}\)的一种选取结果,记为\(\{0, 1\}^N\), 总共有\(2^N\)种取值方法。举例来说,\(N=4\)时,\(\bold{Y} = [0,1,0,1]\)表示4个元素中取了2个元素是\(\{i_2, i_4\}\)。
DPP模型是说,这个子集取值的概率\(P\)与给定的一个Kernel(相似度)矩阵的行列式成正比,Kernel矩阵\(L\)形如一个协方差矩阵,是实对称的就行。
例如,
分母项是概率的归一化项,是可以公式算出的(不想很多概率图模型中无法获得),很漂亮的理论,
按照这种概率定义的话,假设第一个已经抽出来是\(\{i_2\}\),再抽一个元素的构成序列,那最可能就是\(\{i_2, i_1\}\)。DPP的理论说,这样定义的概率,抽样的子集具有一个性质,那就是diversity最大,子集间最正交,生成的子空间体积最大。比如与\(i_2\)最不相关的就是\(i_1\),\(N=2\)时可以直接看出这个结论。
2.1.2 几何解释¶
行列式还不好理解,换一种等价理解。假设\(\{\vec{v_1}, \vec{v_2}, \vec{v_3}, \vec{v_4}\}\)对应这四个元素的embedding向量,\(L\)是embedding的内积矩阵,那么有,
也就是,行列式的值,等于embedding向量张成的体积的平方,如图所示,
DPP概率最大的取法,对应的就是,能张成体积最大的\(k\)个embedding。相似/平行的向量不会被选中,因为概率会变成是0。
2.1.3 SVD解释¶
如果对\(L = X^tX\)的特征embedding矩阵\(X\)做SVD分解,那么
这个表示的好处是,如果推荐中有物品向量\(X\),则不用显式构建\(L\),减少一次乘法运算。小红书的SSD是基于此思路(但没调用SVD),直接在\(X\)矩阵中做Gram-Smidt正交化,选择张成体积最大的方向,不构建\(L\),减少了时间复杂度。
2.2 质量和多样性分解¶
DPP叠加item的质量分,选出最优解,这个是推荐系统Rerank中最终的目标,也能转化为DPP问题,
in most practical situations we want diversity to be balanced against some underlying preferences for different items in Y. In this section, we propose a decomposition of the DPP that more directly illustrates the tension between diversity and a per-item measure of quality.
注意上面提过的矩阵\(L\),其实对角线不一定是1,比如我们修改对角线的值
这种情况下,DPP问题仍然成立,只是此时,最优解就不止取决于off-diag的位置了,很大程度上取决于\(\Vert v_i \Vert\)了
此时,\(\{i_2, i_3\}\)成为新的最优解,因为\(\vec{v_3}\)的模长大。推而广之,我们把向量写成,\(\vec{v_i}=\Vert v_i \Vert \cdot \vec{u_i}\),其中\(\vec{u_i}\)是单位向量,衡量向量之间的相似度,\(\Vert v \Vert \in{\R^+}\)作为推荐系统的打分值。DPP建模的概率模型就是推荐系统平衡质量和多样性的算法了。推荐系统计算出每个item的得分,\(\{q_i\}_N\),然后算出item的embedding经过normalized的矩阵\(\{\vec{u_i}\}_N\),就可以放到DPP中了,
the first term increases with the quality of the selected items, and the second term increases with the diversity of the selected items. We will refer to \(q\) as the quality model and \(S\) as the diversity model. Without the diversity model, we would choose high-quality items, but we would tend to choose similar high-quality items over and over. Without the quality model, we would get a very diverse set, but we might fail to include the most important items in Y, focusing instead on low-quality outliers. By combining the two models we can achieve a more balanced result.
当然,推荐系统中一般还是用加法的方式(或者说取个对数)来组合,变成下面的来最大化,
2.3 k-DPP¶
从所有item中选出k个组成集合,每种组合的概率服从
这个模型更符合推荐系统/搜索引擎,返回top=K而不是任意数量的情况。好像上面Fast MAP DPP的文章就不知怎么就不区分了,实际是解决kDPP问题。
2.4 训练¶
这个DPP是需要同时训练quality+diversity的,理论上不能单独训练两个部分,然后只用于inference,文章给出了实际测试数据,证明这个观点。
2.4.1 例子¶
输入是一行行的文本,特征是这一行与整段之间的关系,位置,代词数等,输出是该行是否可以作为摘要。相似度用每行的tf-idf作为embedding(所以这里是没有参数,不更新的)。用DPP来打散结果使得摘要的几行\(\{i_1, ..., i_k\}\)可以不重复。
对比项,
- LR是在训练阶段只拟合pointwise的分数,在inference阶段加入相似度,用MMR/DPP来输出打散效果
- DPP-GREEDY是训练阶段拟合listwise的分数和diversity,再inference的效果
结论
- 可以看到MMR和DPP只在inference阶段使用,效果差距不大
- 训练时增加diversity才是提升利器(但由于diversity里没有参数,我的推测是quality里参数学到了一些diversity的bias)
2.4.2 联合训练¶
关键问题:联合训练到底是学到了什么,会让效果变化?
假设我们的数据是\(D = \{X^t, Y^t\}_{t=1}^{T}\),是独立同分布的样本,\((X, Y) \in \mathcal{X} \times 2^{\mathcal{Y}(X)}\)。
例如,在上面的例子中,\(Y_1 = \{i_1, i_3, i_5\} = [1, 0, 1, 0, 1, 0, ...]\),表示第一个文档的摘要是第1,3,5行。\(X\)是输入特征,比如这一行与整段之间的关系,位置,代词数,或者干脆就是特征向量embedding,\(\theta\)是待学习的模型参数,例如,\(\sigma(W\vec{x}+b)\)中的\(W, b\)。\(L\)的参数化表达类似,
其中\(f(W, \vec{x}_1, \vec{x}_2)\)是相似度度量,比如可以是带参数的内积,
或者是RBF核,参数只有一个\(\sigma\)
如果考虑到质量分数是外部传入的,不是联合训练,可能就是下面这种形式,
或者干脆就是一个神经网络,所谓Deep-DPP,
总之,相似度矩阵是含参数\(\theta = W\)的。
样本\((X, Y)\)的出现的概率,根据DPP的定义,
从\(\theta\)的角度来看,就是likelihood,记为花体的\(\mathcal{L(\theta)}\)。假设我们观察到样本之后,就可以计算likelihood,那个MLE的参数取值就是我们要求解的。希望找到使得log-likelihood最大的\(\theta\)
\(L_Y\)还是表示在\(L\)矩阵中的子矩阵。
还是拿一个实际推荐的例子,比如用户一次曝光列表是\([i_1, ..., i_N]\),点击与否是\([y_1, ..., y_N], y_i\in\{0,1\}\),总共点击了\(k\)个,排序模型给出的点估计分数是\([q_1, ..., q_N]\),\(L\)矩阵是一个参数化的\(N \times N\)矩阵,例如上面的\(W\)内积,\(L_Y\)就是限定到\(k\)个点击项的子矩阵。总共\(T\)个用户样本。求解最小化的negative-likelihood就行了,torch之类可以自动化优化参数,迭代出最优解。
为什么联合训练\(q(\theta)\)和\(S(\theta)\)比较不常规,因为还是和点估计的优化loglikelihood不太一样的,点估计只需要优化,
其中\(y_t\)取值是0或1,对应正负样本。优化NLLLoss
或者CrossEntropy
就是我们的点估计,参考链接。DPP的目标看起来和点估计完全不同,不方便直接在里面增加某些东西就转换。因此,推荐系统(如Youtube/Hulu/小红书)大多选择的方案都是,点估计预测出分数,再用DPP的likelihood训练DPP的参数,或者干脆不训练。
反思
这些真的有什么价值吗?感觉能从这里学到的信息不多,学不到 探索兴趣(毕竟点估计的高分可能仍然信息茧房),主要就是 打散用途 了,其实参数也没啥作用。 Youtube和Hulu上线的都是只有一两个超参数(\(\sigma, \lambda\)这种),用grid-search定一下就完事了,间接佐证。小红书则没有训练环节。
2.5 预测¶
推断问题最重要,假设我们拿到相似矩阵\(L\),如何求解概率最大的那个\(k\)个元素组合呢?暴力肯定不行,有\(2^k\)个要算的\(k\)阶行列式。DPP的推断有多项式时间的解法。
如果说训练是优化MLE问题,那推断就是求解最大化下面概率的MAP问题,找到满足\(|Y| = k\)的取值。
分母在MAP时不用管,不含变量,等价于寻找
2.5.1 DDPy¶
DDPy,python工具包,这个博客中提供了一个使用案例,应用kDPP来打散bert输出的文本向量
行业中用到的预测算法,放到下一小节来介绍。
3、行业应用¶
3.1 Fast MAP DPP¶
Fast Greedy MAP Inference for Determinantal Point Process to Improve Recommendation Diversity,18年Hulu的论文,提到了一个快速求解算法,作者提供有python代码地址。
主要结论¶
- 推荐系统应用时,还是先用点估计预估分数,再根据content/cf计算物品的相似矩阵,应用DPP进行推断,不是直接DPP参与计算(从上一个小节的结果看,和MRR相比,应该优势不是很明显)
- 预估分数作为物品向量的模长,归一化的embedding作为物品向量的方向,协方差矩阵就是L,放到DPP算法就行了(如果不是embedding的方法定义协方差矩阵S,也一样,归一化后乘以预估分数)
- 效果上,DPP略微优于MMR,速度慢一倍,不算太多
代码,
拼接预估分数scores
和方向feature_vectors
>>> item_size = 1000
>>> feature_dimension = 128
>>> max_length = 100
>>> scores = np.exp(0.01 * np.random.randn(item_size) + 0.2)
"""
array([1.21330817, 1.20529658, 1.21159419, ..., 1.20534054, 1.21771803, 1.22833931])
"""
>>> feature_vectors = np.random.randn(item_size, feature_dimension)
... feature_vectors /= np.linalg.norm(feature_vectors, axis=1, keepdims=True)
>>> similarities = np.dot(feature_vectors, feature_vectors.T)
"""
array([[ 1. , -0.21014162, 0.05271664, ..., 0.14214882,
-0.1305412 , 0.02171695],
[-0.21014162, 1. , -0.22181668, ..., 0.01195213,
0.06769682, 0.07769662],
[ 0.05271664, -0.22181668, 1. , ..., -0.11289664,
0.00528457, 0.01085495],
...,
[ 0.14214882, 0.01195213, -0.11289664, ..., 1. ,
-0.07640866, 0.01530099],
[-0.1305412 , 0.06769682, 0.00528457, ..., -0.07640866,
1. , -0.09066212],
[ 0.02171695, 0.07769662, 0.01085495, ..., 0.01530099,
-0.09066212, 1. ]])
"""
>>> kernel_matrix = scores.reshape((item_size, 1)) * similarities * scores.reshape((1, item_size))
"""
array([[ 1.47211671, -0.30731031, 0.07749541, ..., 0.20788547,
-0.19287034, 0.03236594],
[-0.30731031, 1.45273985, -0.32392562, ..., 0.01736397,
0.09935939, 0.11503086],
[ 0.07749541, -0.32392562, 1.46796048, ..., -0.16487241,
0.00779675, 0.01615486],
...,
[ 0.20788547, 0.01736397, -0.16487241, ..., 1.45284582,
-0.11214995, 0.02265414],
[-0.19287034, 0.09935939, 0.00779675, ..., -0.11214995,
1.48283719, -0.13560976],
[ 0.03236594, 0.11503086, 0.01615486, ..., 0.02265414,
-0.13560976, 1.50881745]])
"""
>>> scores[0] * scores[1] * similarities[0, 1]
"""
-0.30731031
"""
>>> result = dpp(kernel_matrix, max_length)
>>> result[:10]
"""
[244, 975, 202, 727, 276, 449, 541, 876, 463, 135]
algorithm running time: 4.3824e-03
"""
预估算法,输入\(L\)矩阵kernel_matrix
,需要的item个数,返回item的索引,
def dpp(kernel_matrix, max_length, epsilon=1E-10):
"""
Our proposed fast implementation of the greedy algorithm
:param kernel_matrix: 2-d array
:param max_length: positive int
:param epsilon: small positive scalar
:return: list
"""
item_size = kernel_matrix.shape[0]
cis = np.zeros((max_length, item_size)) # (100, 1000)
di2s = np.copy(np.diag(kernel_matrix)) # 对角线,也就是item的分数平方
selected_items = list()
selected_item = np.argmax(di2s) # 第一次选分数最高的
selected_items.append(selected_item)
while len(selected_items) < max_length:
k = len(selected_items) - 1
ci_optimal = cis[:k, selected_item]
di_optimal = math.sqrt(di2s[selected_item])
elements = kernel_matrix[selected_item, :] # (1000, 1)
eis = (elements - np.dot(ci_optimal, cis[:k, :])) / di_optimal # (1000, 1)
cis[k, :] = eis
di2s -= np.square(eis)
di2s[selected_item] = -np.inf
selected_item = np.argmax(di2s)
if di2s[selected_item] < epsilon:
break
selected_items.append(selected_item)
return selected_items
对应算法描述
还有个滑动窗口版本,还是选\(k\)个元素,但是只需要相邻window个元素内部距离最大。虽然放松了要求,但这个版本运行时间还会再长一点。
3.2 Youtube DPP¶
Practical Diversified Recommendations on YouTube with Determinantal Point Processes,Google的18年的论文,130次引用,讲的是比上面华人作者清楚多了,但是没代码。
首先,关注的问题还是,联合训练DPP,还是作为点估计+距离+预测?文章的选择仍然是后者,
Implementing a DPP-based solution in a mature recommendation system is non-trivial. First, the training methods for DPPs are significantly different from those used in typical recommender systems. Second, integrating the DPP optimization with existing recommenders is complex. One option would be to retool the entire infrastructure in terms of set-wise recommendations, but that would discard the large investment in, and the sophistication of, the existing pointwise estimators. Instead, we use DPPs on top of existing infrastructure as a last-layer model. This allows the various underlying system components to evolve independently
More specifically, for a large-scale recommendation system, we build a DPP using two inputs:
1) pointwise estimators from a deep neural network built for recommendations, which gives us a high-precision estimate of item quality \(q_i\) , and 2) pairwise item distances \(D_{ij}\) computed in a sparse semantic embedding space. From these inputs, we construct a DPP and apply it to the top \(n\) items in a feed.
主要结论¶
- Policy层就是微博的rerank层,加各种规则,博主打散,领域打散这种。文章把DPP加在了ranking和policy中间。
- 训练DPP的输入格式,一条数据是一个曝光的list,以及点击了哪些,是一个标准的listwise估计问题
- 曝光列表可能存在partial-label bias,就是推荐出来的可能已经是比较相关的list了,正负样本从里面出的话,可能会忽略那些没曝光的完全不相干的样本。
- 针对这个问题,本文说一般在推荐系统中用\(\epsilon\)-greedy策略,来给用户多曝光一些的方式来解决。
- Window的方式预估:
- \(N\)个样本中,先取出\(k\)个结果,然后再从\(N-k\)中再选\(k\)个,如此把整个\(N\)元素排列出来。
- 原因是用户感知重复还是对两个比较近的有感觉,如果离得比较远了就没事,这样也能充分利用点估计高分项
- 与Hulu不同的是,Hulu是sliding window,没有割裂感。
- listwise比pointwise优势就是因为,用户看了A之后,不太可能又看一个相似的B,因此,重排是提高整体list的点击率。多样性不单单是作为一个正则化的用途。
- 预估算法没有代码,只是说是一种贪心MAP,近似算法。
- 最后,文章上线的只是最原始的RBF核的DPP,
- 没有上Deep版本因为发现有些辅助目标下降了;
- 而RBF核的DPP用到的embedding只是tf-idf,因为它发现各种NLP/CV/音频embedding效果都不如直接用文本词。感觉真是有点无语哈哈,可能18年的NLP确实不够用。
3.3 小红书 SSD¶
最后回来看小红书这篇,文章有点杂糅,关心的主要问题是,
- 是否涉及训练:没有,Ranking提供的\(N=600\)个quality分数,和物品向量,输出\(T=80\)个打散的结果。只涉及了DPP的推断。
- 窗口:
- 一直在说,别的算法窗口之间可能重复,但扩大了窗口size不就一样么?看论文里实现时,下一个窗口还要减去上一个窗口的向量,似乎也和一个大窗口没啥区别。
- SVD/Singular Spectrum Analysis (SSA):概念引入,主要解决窗口的问题吧,没看懂。
- 物品向量:content-based的特征,相似物品内积作为目标,相似物品是共现较多的A,B,负例是共现但次数不多的C,D(也就是hard triplet),比较常规了。放到DPP里时,所有物品向量补了一位1,没有理论支持。
- 算法:为了让物品向量的张成体积最大,不断在剩余物品向量上,进行Gram-Smidt正交化操作,也就是说,每一次把剩余的物品向量都减去之前选出来向量的分向量,看垂直的部分哪个比较大,和分数融合一下,谁大选谁。
花体的\(\mathcal{T(v_j)}\)表示\(v_j\)减去之前\(I_{1:t}\)向量,剩余的正交分向量。
大就是下面的操作,然后里面的\(V\)小红书在实际操作中固定是1,不更新。
- 时间复杂度比Hulu(仅仅是)快一点,7ms,省了一个矩阵乘法,但算法确实看起来是更简单了。
- 有个观点是说,相关度加意外度,相当于是用mean是相关度,方差是意外度的一个gauss,等价于优化目标中方差是正则项,所以这个方式相当于是把效用的上界能拉高,也就不是一个trade-off的感觉了。
参考链接¶
- 为什么普通人「出圈」,都在小红书?,机器之心报道
- 小红书推荐系统全解析:去中心化内容分发,DataFun