Real Recommender System For Industry
推荐系统
基础
基本概念
转化流程
消费指标
- 点击率 = 点击次数 / 曝光次数
- 点赞率 = 点赞次数 / 点击次数
- 收藏率 = 收藏次数 / 点击次数
- 转发率 = 转发次数 / 点击次数
- 阅读完成率 = 滑动到底次数 / 点击次数 X
f
(笔记长度)
北极星指标
- 用户规模:
- 日活用户数(DAU)、月活用户数(MAU)。
- 消费:
- 人均使用推荐的时长、人均阅读笔记的数量。
- 发布:
- 发布渗透率、人均发布量。
实验流程
- 离线实验:收集历史数据,在历史数据上做训练、测试。算法没有部署到产品中,没有跟用户交互。
- 小流量 AB 测试:把算法部署到实际产品中,用户实际跟算法做交互。
- 全流量上线
推荐系统的链路
- 召回:从物品的数据库中快速取回一些物品,比如小红书有上亿篇笔记,当用户刷新小红书的时候,系统会同时调用几十条召回通道,每条召回通道取回几十到几百篇笔记,一共取回几千篇笔记。做完召回之后,接下来要从几千篇笔记中选出用户最感兴趣的。
- 粗排:用规模比较小的机器学习模型,给几千篇笔记逐一打分,按照分数做排序和截断,保留分数最高的几百篇笔记。
- 精排:用大规模的深度神经网络给几百篇笔记逐一打分,精排的分数反映出用户对笔记的兴趣,在精排之后可以做截断,也可以不做截断。
- 重排:根据精排分数和多样性分数做随机抽样,得到几十篇笔记,然后把相似内容打散,并且插入广告和运营内容。
召回通道:推荐系统有很多条召回通道,常见的包括协同过滤、双塔模型、关注的作者等。小红书的推荐系统有几十条召回通道,每条召回通道取回几十到几百篇笔记,这些召回通道一共会返回几千篇笔记。然后推荐系统会融合这些笔记,并写作去重和过滤,过滤的意思是排除掉用户不喜欢的作者、不喜欢的笔记、不喜欢的话题。
排序:用机器学习模型预估用户对笔记的兴趣,保留分数最高的笔记。如果直接用一个大规模的神经网络,逐一对几千篇笔记打分,花费的代价会很大。为了解决计算量的问题,通常把排序分为粗排和精排两步骤。粗排用比较简单的模型快速给几千篇笔记打分,保留分数最高的几百篇笔记。精排用一个较大的神经网络给几百篇笔记打分,不用做截断。精排模型比粗排模型大很多,用的特征也更多,所以精排模型打的分数更可靠。但是精排的计算量很大,先用粗排做筛选,然后才用精排,可以比较好的平衡计算量和准确性。做完粗排和精排得到几百篇笔记,每篇笔记有一个分数,表示用户对笔记的兴趣有多高,可以直接把笔记按照模型打的分数做排序,然后展示给用户。但此时的结果还存在一些不足,需要做一些调整,这一步叫做重排。重排主要是考虑多样性,要根据多样性做随机抽样,从几百篇笔记中选出几十篇,然后还要用规则把内容相似的笔记打散。稍后我会解释重排。重排的结果就是最终展示给用户的物品,比如把前 80 的物品展示给用户,其中包括笔记和广告。
粗排和精排模型:粗排和精排非常相似,唯一的区别就是精排模型更大,用的特征更多。模型的输入包括用户特征、候选物品的特征,还有统计特征。假如想要判断小王同学是否对某篇笔记感兴趣,就要把笔记的特征、小王的特征还有很多统计特征输入神经网络。神经网络会输出很多数值,比如点击率、点赞率、收藏率、转发率,这些数值都是神经网络对用户行为的预估,这些数值越大,说明用户对笔记越感兴趣。最后把多个预估值做融合,得到最终的分数,比如求加权和这个分数决定了笔记会不会被展示给用户,以及笔记展示的位置是靠前还是靠后。
重排:最重要的功能是多样性抽样,需要从几百篇笔记中选出几十篇笔记,常见的方法有 MMR 和DPP。抽样的时候有两个依据,一个依据是精排分数的大小,另一个依据是多样性。做完抽样之后会用规则打散相似内容,不能把内容过于相似的笔记排在相邻的位置上。举个例子,根据精排得到的分数,排前五的笔记全都是 NBA 的内容。即使用户是个篮球迷,他也未必希望看到同质化的内容。如果排第一的是 NBA 的笔记,那么接下来几个位置就不能放 NBA 的内容。相似的笔记会往后挪。重排的另一个目的是插入广告和运营推广的内容,还要根据生态的要求调整排序。
AB 测试
- 召回团队实现了一种 GNN 召回通道,离线实验结果正向。
- 下一步是做线上的小流量的 A/B 测试,考察新的召回通道对线上指标的影响。
- 模型中有一些参数,比如 GNN 的深度取值 ∈{1,2,3},需要用 A/B 测试选取最优参数
随机分桶
- 分 b = 10 个桶,每个桶中有 10% 的用户
- 首先用哈希函数把用户 ID 映射成某个区间内的整数,然后把这些整数均匀随机分成 b 个桶。
- 计算每个桶的业务指标,比如 DAU、人均使用推荐的时长、点击率等。
- 如果某个实验组指标显著优于对照组,则说明对应的策略有效,值得推全。推全的意思是把流量扩大到 100%,给所有用户都使用两层 GNN 召回通道。
分层实验
- 分层实验:召回、粗排、精排、重排、用户页面、广告,例如 GNN 召回通道属于召回层。
- 同层互斥:GNN 实验占了召回层的 4 个桶,其他召回实验只能用剩余的 6 个桶。
- 不同层正交:每一层独立随机对用户做分桶。每一层都可以独立用 100% 的用户做实验。
互斥 VS 正交
- 如果所有实验都正交,则可以同时做无数次实验。
- 同类的策略(例如精排模型的两种结构)天然互斥,对于一个用户,只能用其中一种。
- 同类的策略(例如添加两条召回通道)效果会相互增强(1 + 1 > 2)或相互抵消(1 + 1 < 2)。互斥可以避免同类策略相互干扰。
- 不同类型的策略(例如添加召回通道、优化粗排模型)通常不会相互干扰(1 + 1 = 2),可以作为正交的两层。
Holdout 机制
- 每个实验(召回、粗排、精排、重排)独立汇报对业务指标的提升。
- 公司考察一个部门(比如推荐系统)在一段时间内对业务指标总体的提升。
- 取 10% 的用户作为 holdout 桶,推荐系统使用剩余 90% 的用户做实验,两者互斥。
- 10% holdout 桶 VS 90% 实验桶的 diff(需要归一化)为整个部门的业务指标收益。
- 每个考核周期结束之后,清除 holdout 桶,让推全实验从 90% 用户扩大到 100% 用户。
- 重新随机划分用户,得到 holdout 桶和实验桶,开始下一轮考核周期。
- 新的 holdout 桶与实验桶各种业务指标的 diff 接近 0。
- 随着召回、粗排、精排、重排实验上线和推全,diff 会逐渐扩大。
反转实验
- 有的指标(点击、交互)立刻受到新策略影响,有的指标(留存)有滞后性,需要长期观测。
- 实验观测到显著收益后尽快推全新策略。目的是腾出桶供其他实验使用,或需要基于新策略做后续的开发。
- 用反转实验解决上述矛盾,既可以尽快推全,也可以长期观测实验指标。
- 在推全的新层中开一个旧策略的桶,长期观测实验指标。
召回
基于物品的协同过滤
物品相似度
- 两个物品的受众重合度越高,两个物品越相似。
- 例如:
- 喜欢《射雕英雄传》和《神雕侠侣》的读者重合度很高。
- 可以认为《射雕英雄传》和《神雕侠侣》相似。
计算物品的相似度
- 喜欢物品 i1 的用户记作集合 W1。
- 喜欢物品 i2 的用户记作集合 W2。
- 定义交集 V = W1 ∩ W2。
- 两个物品的相似度:
- 考虑喜欢的程度 like(user, item):
ItemCF
-
基本思想:
- 如果用户喜欢物品 item1,而且物品 item1 与 item2 相似,那么用户很可能喜欢物品 item2
-
预估用户对候选物品的兴趣:
-
计算两个物品的相似度:
- 把每个物品表示为一个稀疏向量,向量每个元素对应一个用户。
- 相似度 sim 就是两个向量夹角的余弦。
事先离线计算
建立“用户 -> 物品” 的索引
- 记录每个用户最近点击、交互过的物品 ID。
- 给定任意用户 ID,可以找到近期感兴趣的物品列表。
建立 “物品 -> 物品” 的索引
- 计算物品之间两两相似度。
- 对于每个物品,索引它最相似的 k 个物品。
- 给定任意物品 ID,可以快速找到它最相似的 k 个物品。
线上做召回
- 给定用户 ID,通过 “用户 -> 物品” 索引,找到用户近期感兴趣的物品列表(last-n)。
- 对于 last-n 列表中每个物品,通过 “物品 -> 物品” 的索引,找到 top-k 相似物品。
- 对于取回的相似物品(最多有 nk 个),用公式预估用户对物品的兴趣分数。
- 返回分数最高的 100 个物品,作为推荐结果。
索引的意义在于避免枚举所有的物品。
用索引,离线计算量大,线上计算量小。
Swing 模型
-
用户 u1 喜欢的物品记作集合 J1。
-
用户 u2 喜欢的物品记作集合 J2。
-
定义两个用户的重合度:
-
用户 u1 和 u2 的重合度高,则他们可能来自一个小圈子,要降低他们的权重。
-
两个物品相似度:
总结
- Swing 和 ItemCF 唯一的区别在于物品相似度。
- ItemCF:两个物品重合的用户比例高,则判定两个物品相似。
- Swing:额外考虑重合的用户是否来自一个小圈子。
- 同时喜欢两个物品的用户记作集合 V。
- 对于 V 中的用户 u1 和 u2,重合度记作 overlap(u1,u2)。
- 两个用户重合度大,则可能来自一个小圈子,权重降低。
基于用户的协同过滤
计算用户相似度
- 用户 u1 喜欢的物品记作集合 J1。
- 用户 u2 喜欢的物品记作集合 J2。
- 定义交集 I = J1 ∩ J2。
- 两个用户的相似度:
-
降低热门物品权重:
-
n_l:喜欢物品 l 的用户数量,反应物品的热门程度。
UserCF
-
基本思想:
- 如果用户 user1 跟用户 user2 相似,而且 user2 喜欢某物品,那么用户 user1 也可能喜欢该物品。
-
预估用户 user 对候选物品 item 的兴趣:
-
计算两个用户的相似度:
- 把每个用户表示为一个稀疏向量,向量每个元素对应一个物品。
事先离线计算
建立“用户 -> 物品” 的索引
- 记录每个用户最近点击、交互过的物品 ID。
- 给定任意用户 ID,可以找到近期感兴趣的物品列表。
建立 “用户 -> 用户” 的索引
- 对于每个用户,索引他最相似的 k 个用户。
- 给定任意物品 ID,可以快速找到他最相似的 k 个用户。
线上做召回
- 给定用户 ID,通过 “用户 -> 用户” 索引,找到 top-k 相似用户。
- 对于每个 top-k 相似用户,通过 “用户-> 物品” 的索引,找到用户近期感兴趣的物品列表(last-n)。
- 对于召回的 nk 个相似物品,用公式预估用户对每个物品的兴趣分数。
- 返回分数最高的 100 个物品,作为召回结果。
离散特征处理
离散特征
- 性别:男、女两种类别。
- 国籍:中国、美国、印度等 200 个国家。
- 英文单词:常见的英文单词有几万个。
- 物品 ID:小红书有几亿篇笔记,每篇笔记有一个 ID。
- 用户 ID:小红书有几亿个用户,每个用户有一个 ID。
- 建立字典:把类别映射成序号。
- 中国 -> 1
- 美国 -> 2
- 印度 -> 3
- 向量化:把序号映射成向量。
- One-hot 编码:把序号映射成高维稀疏向量。
- Embedding:把序号映射成低维度稠密向量。
One-hot 编码的局限
- 自然语言处理中,对单词做编码。
- 英文有几万个常见单词。
- 那么 one-hot 向量的维度是几万。
- 推荐系统中,对物品 ID 做编码。
- 小红书有几亿篇笔记。
- 那么 one-hot 向量的维度是几亿。
Embedding
- 参数数量:向量维度 X 类别数量。
- 设 embedding 得到的向量都是 4维的。
- 一共有 200 个国籍。
- 参数数量 = 4 X 200 = 800
- 编程实现:TensorFlow、PyTorch 提供 embedding 层。
- 参数以矩阵的形式保存,矩阵大小是 向量维度 X 类别数量。
- 输入是序号,比如 “美国” 的序号是 2。
- 输出是向量,比如 “美国” 对应参数矩阵的第 2 列。
总结
- 离散特征处理:one-hot 编码、embedding。
- 类别数量很大时,用 embedding。
- Word embedding。
- 用户 ID embedding。
- 物品 ID embedding。
矩阵补充
基本想法
- 用户 embedding 参数矩阵记作 A。第 u 号 用户对应矩阵第 u 列,记作向量 a_u。
- 物品 embedding 参数矩阵记作 B。第 i 号物品对应矩阵第 i 列,记作向量 b_i。
- 内积 <a_u, b_i> 是第 u 号用户对第 i 号物品兴趣的预估值。
- 训练模型的目的是学习矩阵 A 和 B,使得预估值拟合真实观测的兴趣分数。
数据集
- 数据集:(用户ID,物品ID,兴趣分数)的集合,记作 Ω = {(u,i,y)}。
- 数据集中的兴趣分数是系统记录的,比如:
- 曝光但是没有点击 -> 0 分。
- 点击、点赞、收藏、转发 -> 各算 1 分。
- 分数最低是 0,最高是 4。
训练
-
把用户ID、物品ID 映射成向量。
- 第 u 号用户 -> 向量 a_u。
- 第 i 号物品 -> 向量 b_i。
-
求解优化问题,得到参数 A 和 B。
模型存储
- 训练得到矩阵 A 和 B。
- A 的每一列对应一个用户。
- B 的每一列对应一个物品。
- 把矩阵 A 的列存储到 key-value 表。
- key 是用户 ID,value 是 A 的一列。
- 给定用户 ID,返回一个向量(用户的 embedding)。
- 矩阵 B 的存储和索引比较复杂。
线上召回
- 把用户向量 a 作为 query,查找使得 <a, b_i> 最大化的物品 i。
- 暴力枚举速度太慢。实践中用近似最近邻查找。
- Milvus、Faiss、HnswLib 等向量数据库支持近似最近邻查找。
总结
- 把物品ID、用户ID 做 embedding,映射成向量。
- 两个向量的内积 <a_u,b_i> 作为用户 u 对物品 i 兴趣的预估。
- 让 <a_u,b_i> 拟合真实观测的兴趣分数,学习模型的 embedding 层参数。
- 矩阵补充模型有很多缺点,效果不好。
双塔模型 - 模型结构、训练方法
训练
- Pointwise:独立看待每个正样本、负样本,做简单的二元分类。
- Pairwise:每次取一个正样本、一个负样本 [1]。
- Listwise:每次取一个正样本、多个负样本 [2]。
正负样本的选择
- 正样本:用户点击的物品。
- 负样本 [1, 2]:
- 没有被召回的?
- 召回但是被粗排、精排淘汰的?
- 曝光但是未点击的?
Pointwise 训练
- 把召回看作二元分类任务。
- 对于正样本,鼓励 cos(a, b) 接近 + 1。
- 对于负样本,鼓励 cos(a, b) 接近 - 1。
- 控制正负样本数量为 1:2 或者 1:3。
Pairwise 训练
-
如果 cos(a, b+) 大于 co(a, b-) + m,则没有损失。
-
否则,损失等于 cos(a, b-) + m - cos(a, b+)。
-
Triplet hinge loss:
-
Triplet logistic loss:
Listwise 训练
- 一条数据包含:
- 一个用户,特征向量记作 a。
- 一个正样本,特征向量记作 b+。
- 多个负样本,特征向量记作 b1-, …, bn-。
- 鼓励 cos(a, b+) 尽量大。
- 鼓励 cos(a, b1+), …, cos(a, bn+) 尽量小。
总结
- 用户塔、物品塔各输出一个向量。
- 两个向量的余弦相似度作为兴趣的预估值。
- 三种训练方式:
- Pointwise:每次用一个用户、一个物品(可正可负)。
- Pairwise:每次用一个用户、一个正样本、一个负样本。
- Listwise:每次用一个用户、一个正样本、多个负样本。
双塔模型 - 正负样本
正样本
- 正样本:曝光而且有点击率的用户-物品二元组(用户对物品感兴趣)。
- 问题:少部分物品占据大部分点击,导致正样本大多是热门物品。
- 解决方案:过采样冷门物品,或降采样热门物品。
- 过采样(up-sampling):一个样本出现多次。
- 降采样(down-sampling):一些样本被抛弃。
简单负样本:全体物品
均匀抽样:对冷门物品不公平
- 正样本大多是热门物品、
- 如果均匀抽样产生负样本,负样本大多是冷门物品。
非均抽采样:目的是打压热门物品
- 负样本抽样概率与热门程度(点击次数)正相关。
- 抽样概率 ∝**(点击次数)^ 0.75**
简单负样本:Batch内负样本
-
一个物品出现在 batch 内的概率 ∝(点击次数)。
-
物品成为负样本的概率本该是 ∝(点击次数)^ 0.75,但在这里是 ∝(点击次数)。
-
热门物品成为负样本的概率过大。
困难负样本
- 困难负样本:
- 被粗排淘汰的物品(比较困难)。
- 精排分数靠后的物品(非常困难)。
- 对正负样本做二元分类:
- 全体物品(简单)分类准确率高。
- 被粗排淘汰的物品(比较困难)容易分错。
- 精排分数靠后的物品(非常困难)更容易分错。
训练数据
- 混合几种负样本。
- 50% 的负样本是全体物品(简单负样本)。
- 50% 的负样本是没通过排序的物品(困难负样本)。
选择负样本的原理
召回的目标:快速找到用户可能感兴趣的物品。
- 全体物品(easy):绝大多数是用户根本不感兴趣的。
- 被排序淘汰(hard):用户可能感兴趣,但是不够感兴趣。
- 有曝光没点击(没用):用户感兴趣,可能碰巧没有点击。(可以作为排序的负样本,不能作为召回的负样本)
总结
- 正样本:曝光而且有点击。
- 简单负样本:
- 全体物品。
- batch 内负样本。
- 困难负样本:被召回,但是被排序淘汰。
- 错误:曝光、但是未点击的物品做召回的负样本。
双塔模型 - 线上服务、模型更新
召回
离线存储:把物品向量 b 存入向量数据库。
- 完成训练之后,用物品塔计算每个物品的特征向量 b。
- 把几亿个物品向量 b 存入向量数据库(比如 Milvus、Faiss、HnswLib)。
- 向量数据库建索引,以便加速最近邻查找。
线上召回:查找用户最感兴趣的 k 个物品。
- 给定用户ID 和画像,线上用神经网络算用户向量 a。
- 最近邻查找:
- 把向量 a 作为 query,调用向量数据库做最近邻查找。
- 返回余弦相似度最大的 k 个物品,作为召回结果。
事先存储物品向量 b,线上现算用户向量 a,why?
- 每做一次召回,用到一个用户向量 a,几亿物品向量 b。(线上算物品向量的代价过大)
- 用户兴趣动态变化,而物品特征相对稳定。(可以离线存储用户向量,但不利于推荐效果)
更新模型
全量更新:今天凌晨,用昨天的数据训练模型。
- 在昨天模型参数的基础上做训练。(不是随机初始化)
- 用昨天的数据,训练 1 epoch,即每天数据只用一遍。
- 发布新的 用户塔神经网络和物品向量,供线上召回使用。
- 全量更新对数据流、系统的要求比较低。
增量更新:做 online learning 更新模型参数。
- 用户兴趣会随时发生变化。
- 实时收集线上数据,做流式处理,生成 TFRecord 文件。
- 对模型做 online learning,增量更新 ID Embedding 参数。(不更新神经网络其他部分的参数)
- 发布用户 ID Embedding,供用户塔在线上计算用户向量。
能否只做增量更新,不做全量更新?
- 小时级数据有偏;分钟级数据偏差更大。
- 全量更新:random shuffle 一天的数据,做 1 epoch 训练。
- 增量更新:按照数据从早到晚的顺序,做 1 epoch 训练。
- 随机打乱优于按顺序排列数据,全量训练优于增量训练。
自监督模型
双塔模型的问题
- 推荐系统的头部效应严重:
- 少部分物品占据大部分点击。
- 大部分物品的点击次数不高。
- 高点击物品的表征学得好,长尾物品的表征学得不好。
- 自监督学习:做 data augmentation,更好地学习长尾物品的向量特征。
特征变换
Random Mask:
- 随机选一些离散特征(比如类目),把它们遮住。
- 例:
- 某物品的类目特征是 u = {数码,摄影}。
- Mask 后的类目特征是 u’ = {default}。
Dropout:
- 一个物品可以有多个类目,那么类目是一个多值离散特征。
- Dropout:随机丢弃特征中 50% 的值。
- 例:
- 某物品的类目特征是 u = {美妆,摄影}。
- Mask 后的类目特征是 u’ = {美妆}。
互补特征(complementary):
- 假设物品一共有 4 种特征:
- ID,类目,关键词,城市
- 随机分成两组:
- {ID,关键词} 和 {类目,城市}
- {ID,default,关键词,default} -> 物品表征
- {default,类目,default,城市} -> 物品表征
Mask 一组关联的特征:
-
p(u):某特征取值为 u 的概率。
-
p(u, v):某特征取值为 u,另一个特征取值为 v,同时发生的概率。
-
离线计算特征两两之间的关联,用互信息(mutual information)衡量:
-
好处:比 random mask、dropout、互补特征等方法效果更好。
-
坏处:方法复杂,实现的难度大,不容易维护。
训练模型
-
对点击做随机抽样,得到 n 对用户-物品二元组,作为一个 batch。
-
从全体物品中均匀抽样,得到 m 个物品,作为一个 batch。
-
做梯度下降,使得损失减少:
总结
- 双塔模型学不好低曝光物品的向量表征。
- 自监督学习:
- 对物品做随机特征变换。
- 特征向量 b_i’ 和 b_i’’ 相似度高(相同物品)。
- 特征向量 b_i’ 和 b_j’’ 相似度低(不同物品)。
- 实验效果:低曝光物品、新物品的推荐变得更准。
Deep Retrieval 召回
- 经典的双塔模型把用户、物品表示为向量,线上做最近邻查找。
- Deep Retrieval [1] 把物品表征为路径(path),线上查找用户最匹配的路径。
- Deep Retrieval 类似于阿里的 TDM [2]。
物品到路径的索引
索引:item -> List
- 一个物品对应多条路径。
- 用 3 个节点表示一条路径:path = [a, b, c]。
索引:path -> List
- 一条路径对应多个物品。
预估用户对路径的兴趣
-
用 3 个节点表示一条路径:path = [a,b,c]。
-
给定用户特征 x,预估用户对节点 a 的兴趣 p_1(a|x)。
-
给定 x 和 a,预估用户对节点 b 的兴趣 p_2(b|a;x)。
-
给定 x,a,b,预估用户对节点 c 的兴趣 p_3(c|a,b;x)。
-
预估用户对 path = [a,b,c] 兴趣:
线上召回
召回:用户 -> 路径 -> 物品
- 第一步:给定用户特征,用 beam search 召回一批路径。
- 第二步:利用索引 “path -> List
- ”,召回一批物品。
- 第三步:对物品做打分和排序,选出一个子集。
Beam Search
- 假设有 3 层,每层 K 个节点,那么一共有 K^3 条路径。
- 用神经网络给所有 K^3 条路径打分,计算量太大。
- 用 beam search,可以减少计算量。
- 需要设置超参数 beam size。
训练
同时学习神经网络参数和物品表征
- 神经网络 p(a,b,c|x) 预估用户对路径 [a,b,c] 的兴趣。
- 把一个物品表征为多条路径 {[a,b,c]},建立索引:
- item -> List
- path -> List
- item -> List
- 正样本(user, item): click(user, item) = 1。
学习物品表征
-
用户 user 对路径 path = [a,b,c] 的兴趣记作:
-
物品 item 与路径 path 的相关性:
-
根据 score(item, path) 选出 J 条路径作为 item 的表征。
-
损失函数(选择与 item 高度相关的 path):
-
正则项(避免过多的 item 集中在一条 path 上):
地理位置、作者、缓存召回
GeoHash 召回
-
用户可能对附近发生的事感兴趣。
-
GeoHash:对经纬度的编码,地图上一个长方形区域。
-
索引:GeoHash -> 优质笔记列表(按时间倒排)。
-
这条召回通道没有个性化。
同城召回
- 用户可能对同城发生的事感兴趣。
- 索引:城市 -> 优质笔记列表(按时间倒排)。
- 这条召回通道没有个性化。
关注作者召回
- 用户对关注的作者发布的笔记感兴趣。
- 索引:
- 用户 -> 关注的作者
- 作者 -> 发布的笔记
- 召回:
- 用户 -> 关注的作者 -> 最新的笔记
有交互的作者召回
- 如果用户对某笔记感兴趣(点赞、收藏、转发),那么用户可能对该作者的其他笔记感兴趣。
- 索引:用户 -> 有交互的作者
- 召回:用户 -> 有交互的作者 -> 最新的笔记
相似作者召回
- 如果用户喜欢某作者,那么用户喜欢相似的作者。
- 索引:作者 -> 相似作者(k 个作者)
- 召回:用户 -> 感兴趣的作者(n 个作者) -> 相似作者(nk 个作者)-> 最新的笔记(nk 篇笔记)
缓存召回
想法:复用前 n 次推荐精排的结果。
- 背景:
- 精排输出几百篇笔记,送入重排。
- 重排做多样性抽样,选出几十篇。
- 精排结果一大半没有曝光,被浪费。
- 精排前 50,但是没有曝光的,缓存起来,作为一条召回通道。
缓存大小固定,需要退场机制。
- 一旦笔记成功曝光,就从缓存退场。
- 如果超出缓存大小,就移除最先进入缓存的笔记。
- 笔记最多被召回 10 次,达到 10 次就退场。
- 每篇笔记最多保存 3 天,达到 3 天就退场。
总结
-
地理位置召回
- GeoHash 召回、同城召回。
-
作者召回:
- 关注的作者、有交互的作者、相似的作者。
-
缓存召回
曝光过滤 & Bloom Filter
曝光过滤问题
- 如果用户看过某个物品,则不再把该物品曝光给该用户。
- 对于每个用户,记录已经曝光给他的物品。(小红书只召回 1 个月以内的笔记,因此只需要记录每个用户最近 1 个月的曝光历史。)
- 对于每个召回的物品,判断它是否已经给该用户曝光过,排除掉曾经曝光过的物品。
- 一位用户看过 n 个物品,本次召回 r 个物品,如果暴力对比,需要 **O(nr)**的时间。
Bloom Filter
-
Bloom filter 判断一个物品 ID 是否在已曝光的物品集合中。
-
如果判断为 no,那么该物品一定不在集合中。
-
如果判断为 yes,那么该物品很可能在集合中。(可能误伤,错误判断未曝光物品为已曝光,将其过滤掉)
-
Bloom filter 把物品集合表征为一个 m 维二进制向量。
-
每个用户有一个曝光物品的集合,表征为一个向量,需要 m bit 的存储。
-
Bloom filter 有 k 个哈希函数,每个哈希函数把物品 ID 映射成介于 0 和 m - 1 之间的整数。
-
曝光物品集合大小为 n,二进制向量维度为 m,使用 k 个哈希函数。
-
Bloom filter 误伤的概率为:
- n 越大,向量中的 1 越多,误伤概率越大。(未曝光物品的 k 个位置恰好都是 1 的概率大)
- m 越大,向量越长,越不容易发生哈希碰撞。
- k 太大、大小都不好,k 有最优取值。
-
设定可容忍的误伤概率为 δ,那么最优参数为:
Bloom Filter 缺点
- Bloom filter 把物品的集合表示成一个二进制向量。
- 每往集合中添加一个物品,只需要把向量 k 个位置的元素置为 1。(如果原本就是 1,则不变)
- Bloom filter 只支持添加物品,不支持删除物品。从集合中移除物品,无法消除它对向量的影响。
- 每天都需要从物品集合中移除年龄大于 1 个月的物品。(超龄物品不可能被召回,没必要把它们记录在 Bloom filter,降低 n 可以降低误伤率)
排序
多目标排序模型
用户-笔记的交互
- 对于每篇笔记,系统记录:
- 曝光次数(number of impressions)
- 点击次数(number of clicks)
- 点赞次数(number of likes)
- 收藏次数(number of collects)
- 转发次数(number of shares)
排序的依据
- 排序模型预估点击率、点赞率、收藏率、转发率等多种分数。
- 融合这些预估分数。(比如加权和)
- 根据融合的分数做排序、截断。
训练
- 困难:类别不平衡
- 每 100 次曝光,约有 10 次点击、90 次无点击。
- 每 100 次点击,约有 10 次收藏、90 次无收藏。
- 解决方案:负样本降采样(down-sampling)
- 保留一小部分负样本。
- 让正负样本数量平衡,节约计算。
预估值校准
-
正样本、负样本数量为 n+ 和 n-。
-
对负样本做降采样,抛弃一部分负样本。
-
使用 α · n- 个负样本,α∈(0,1)是采样率。
-
由于负样本变少,预估点击率大于真实点击率。
-
真实点击率和预估点击率:
-
由上面两个等式可得校准公式:
Multi-gate Mixture-of-Experts(MMoE)
极化现象(Polarization)
解决极化问题
- 如果有 n 个 “专家”,那么每个 softmax 的输入和输出都是 n 维向量。
- 在训练时,对 softmax 的输出使用 dropout
- Softmax 输出的 n 个数值被 mask 的概率都是 10%。
- 每个 “专家” 被随机丢弃的概率都是 10%。
预估分数融合
融合预估分数
简单的加权和
点击率乘以其他项的加权和
短视频 APP 融分公式
-
根据预估时长 p_time,对 n 篇候选视频做排序。
-
最终融合分数:
电商的融分公式
-
电商的转换流程:
- 曝光 -> 点击 -> 加购物车 -> 付款
-
模型预估:p_click、p_cart、p_pay
-
最终融分公式:
视频播放建模
图文 VS 视频
-
图文笔记排序的主要依据:
- 点击、点赞、收藏、转发、评论 …
-
视频排序的依据还有播放时长和完播。
-
直接用回归拟合播放时长效果不好。建议用 YouTube 的时长建模。
视频播放时长
-
把最后一个全连接层的输出记作 z。设 p = sigmoid(z)。
-
实际观测的播放时长记作 t。(如果没有点击,则 t = 0)
-
做训练:最小化交叉熵损失
-
做推理:把 exp(z) 作为播放时长的预估。
-
把 exp(z) 作为融分公式中的一项。
视频完播
回归方法
-
例:视频长度 10 分钟,实际播放 4 分钟,则实际播放率为 y = 0.4。
-
让预估播放率 p 拟合 y:
-
线上预估完播率,模型输出 p = 0.73,意思是预计播放 73%。
二元分类方法
-
定义完播指标,比如完播 80%。
-
例:视频长度 10 分钟,播放 >8 分钟作为正样本,播放 < 8 分钟作为负样本。
-
做二元分类训练模型:播放 >8 分钟 vs 播放 < 8 分钟
-
线上预估完播率,模型输出 p = 0.73
-
线上预估完播率,然后做调整:
-
把 p_finish 作为融分公式中的一项。
排序模型的特征
用户画像(User Profile)
- 用户 ID(在召回、排序中做 embedding)。
- 人口统计学属性:性别、年龄。
- 账号信息:新老、活跃度 …
- 感兴趣的类目、关键词、品牌。
物品画像(Item Profile)
- 物品 ID(在召回、排序中做 embedding)。
- 发布时间(或者年龄)。
- GeoHash(经纬度编码)、所在城市。
- 标题、类目、关键词、品牌 …
- 字数、图片数、视频清晰度、标签数 …
- 内容信息量、图片美学 …
用户统计特征
- 用户最近 30 天(7天、1天、1小时)的曝光数、点击数、点赞率、收藏数 …
- 按照笔记图文/视频分桶。(比如最近 7 天,该用户对图文笔记的点赞率、对视频笔记的点击率)
- 按照笔记类目分桶。(比如最近 30 天,用户对美妆笔记的点击率、对美食笔记的点击率、对科技数据笔记的点击率)
笔记统计特征
- 笔记最近 30 天(7天、1天、1小时)的曝光数、点击数、点赞数、收藏数 …
- 按照用户性别分桶、按照用户年龄分桶 …
- 作者特征:
- 发布笔记数
- 粉丝数
- 消费指标(曝光数、点击数、点赞数、收藏数)
场景特征(Context)
- 用户定位 GeoHash(经纬度编码)、城市。
- 当前时刻(分段,做 embedding)。
- 是否是周末、是否是节假日。
- 收集品牌、手机型号、操作系统。
特征处理
- 离散特征:做 embedding。
- 用户 ID、笔记 ID、作者 ID。
- 类目、关键词、城市、收集品牌。
- 连续特征:做分桶,变成离散特征。
- 年龄、笔记字数、视频长度。
- 连续特征:其他变换。
- 曝光数、点击数、点赞数等数值做 log(1+x)。
- 转化为点击率、点击率等值,并做平滑。
特征覆盖率
- 很多特征无法覆盖 100% 样本。
- 例:很多用户不填年龄,因此用户年龄特征的覆盖率远小于 100%。
- 例:很多用户设置隐私权限,APP 不能获得用户地理定位,因此场景特征有缺失。
- 提高特征覆盖率,可以让精排模型更准。
数据服务
粗排模型
粗排 VS 精排
粗排
- 给几千篇笔记打分。
- 单次推理代价必须小。
- 预估的准确性不高。
精排
- 给几百篇笔记打分。
- 单次推理代价很大。
- 预估的准确性更高。
精排模型
- 前期融合:先对所有特征做 concatenation,再输入神经网络。
- 线上推理代价大:如果有 n 篇候选笔记,整个大模型要做 n 次推理。
双塔模型
- 后期融合:把用户、物品特征分别输入不同的神经网络,不对用户、物品特征做融合。
- 线上计算量小:
- 用户塔只需要做一次线上推理,计算用户表征 a。
- 物品表征 b 事先储存再向量数据库中,物品塔在线上不做推理。
- 预估准确性不如精排模型。
粗排的三塔模型
三塔模型的推理
- 从多个数据源取特征:
- 1 个用户的画像、统计特征。
- n 个物品的画像、统计特征。
- 用户塔:只做 1 次推理。
- 物品塔:未命中缓存时需要做推理。
- 交叉塔:必须做 n 次推理。
- 上层网络做 n 次推理,给 n 个物品打分。
特征交叉
因式分解机(FM)
线性模型
-
有 d 个特征,记作 x = [x_1, …, x_d]。
-
线性模型:
-
模型有 d + 1 个参数:w = [w_1, …, w_d] 和 b。
-
预测是特征的加权和。(只有加,没有乘)
二阶交叉特征
-
有 d 个特征,记作 x = [x_1, …, x_d]。
-
线性模型 + 二阶交叉特征:
-
模型有 O(d^2)个参数。
-
Factorized Machine(FM):
-
FM 模型有 O(kd)个参数。(k << d)
Factorized Machine
- FM 是线性模型的替代品,能用线性回归、逻辑回归的场景,都可以用 FM。
- FM 使用二阶交叉特征,表达能力比线性模型更强。
- 通过做近似 u_{ij} ≈ v_i^T v_j,FM 把二阶交叉权重的数量从 O(d^2) 降低到 O(d)。
深度交叉网络(DCN)
交叉层
Deep & Cross Network
LHUC(PPNet)
语音识别中的 LHUC
SENet 和 Bilinear 交叉
SENet
- SENet 对离散特征做 field-wise 加权。
- Field:
- 用户 ID Embedding 是 64 维向量。
- 64 个元素算一个 field,获得相同的权重。
- 如果有 m 个 fields,那么权重向量是 m 维。
Field 特征交叉
- 向量内积
- 哈达玛乘积
- Bilinear cross
FiBiNet
行为序列
用户历史行为序列建模
LastN 特征
- LastN:用户最近的 n 次交互(点击、点赞等)的物品 ID。
- 对 LastN 物品 ID 做 embedding,得到 n 个向量。
- 把 n 个向量取平均,作为用户的一种特征。
- 适用于召回双塔模型、粗排三塔模型、精排模型。
小红书的实践
DIN 模型(注意力机制)
DIN 模型
- DIN 用 加权平均代替平均,即注意力机制(attention)。
- 权重:候选物品与用户 LastN 物品的相似度。
-
对于某候选物品,计算它与用户 LastN 物品的相似度。
-
以相似度为权重,求用户 LastN 物品向量的加权和,结果是一个向量。
-
把得到的向量作为一种用户特征,输入排序模型,预估(用户,候选物品)的点击率、点赞率等指标。
-
本质是注意力机制(attention)
简单平均 VS 注意力机制
- 简单平均和注意力机制都适用于精排模型。
- 简单平均适用于双塔模型、三塔模型。
- 简单平均只需要用到 LastN,属于用户自身的特征。
- 把 LastN 向量的平均作为用户塔的输入。
- 注意力机制不适用于双塔模型、三塔模型。
- 注意力机制需要用到 LastN + 候选物品。
- 用户塔看不到候选物品,不能把注意力机制用在用户塔。
SIM 模型(长序列模型)
DIN 模型的特点
- 注意力层的计算量 ∝n(用户行为序列的长度)。
- 只能记录最近几百个物品,否则计算量太大。
- 缺点:关注短期兴趣,遗忘长期兴趣。
如何改进 DIN?
- 目标:保留用户长期行为序列(n 很大),而且计算量不会过大。
- 改进 DIN:
- DIN 对 LastN 向量做加权平均,权重是相似度。
- 如果某 LastN 物品于候选物品差异很大,则权重接近零。
- 快速排除掉与候选物品无关的 LastN 物品,降低注意力层的计算量。
SIM 模型
- 保留用户长期行为记录,n 的大小可以是几千。
- 对于每个候选物品,在用户 LastN 记录中做快速查找,找到 k 个相似物品。
- 把 LastN 变成 TopK,然后输入到注意力层。
- SIM 模型减小计算量(从 n 降到 k)。
第一步:查找
- 方法一:Hard Search
- 根据候选物品的类目,保留 LastN 物品中类目相同的。
- 简单,快速,无需训练。
- 方法二:Soft Search
- 把物品做 embedding,变成向量。
- 把候选物品向量作为 query,做 k 近邻查找,保留 LastN 物品中最接近的 k 个。
- 效果更好,编程实现更复杂。
第二步:注意力机制
使用时间信息
- 用户与某个 LastN 物品的交互时刻距今为 δ。
- 对 δ 做离散化,再做 embedding,变成向量 d。
- 把两个向量做 concatenation,表征一个 LastN 物品。
- 向量 x 是物品 embedding。
- 向量 d 是时间的 embedding。
为什么 SIM 使用时间信息?
- DIN 的序列短,记录用户近期行为。
- SIM 的序列长,记录用户长期行为。
- 时间越久远,重要性越低。
总结
- 长序列(长期兴趣)优于短序列(近期兴趣)。
- 注意力机制优于简单平均。
- Soft search 还是 hard search?取决于工程基建。
重排
推荐系统中的多样性
相似性的度量
- 基于物品属性标签
- 类目、品牌、关键词 …
- 基于物品向量表征
- 用于召回的双塔模型学到的物品向量(不好)。
- 基于内容的向量表征(好)。
基于物品属性标签
-
物品属性标签:类目、品牌、关键词 …
-
根据一级类目、二级类目、品牌计算相似度。
-
物品 i:美妆、彩妆、香奈儿。
-
物品 j:美妆、香水、香奈儿。
-
相似度:
-
基于图文内容的物品向量表征
- CLIP 是当前公认最有效的预训练方法。
- 思想:对于图片-文本二元组,预测图文是否匹配。
- 优势:无需人工标记。小红书的笔记天然包含图片 + 文字,大部分笔记图文相关。
- 一个 batch 内有 m 对正样本。
- 一张图片和 m - 1 条文本组成负样本。
- 这个 batch 内一共有 m(m - 1) 对负样本。
MMR 多样性算法
多样性
- 精排给 n 个候选物品打分,融合之后的分数为:reward_1, …, reward_n
- 把第 i 和 j 个物品的相似度记作 sim(i, j)。
- 从 n 个物品中选出 k 个,既要有高精排分数,也要有多样性。
-
计算集合 R 中每个物品 i 的 Marginal Relevance 分数:
-
Maximal Marginal Relevance(MMR):
MMR 多样性算法
-
已选中的物品 S 初始化为空集,未选中的物品 R 初始化为全集 {1, …, n}。
-
选择精排分数 reward_i 最高的物品,从集合 R 移到 S。
-
做 k - 1 轮循环:
a. 计算集合 R 中所有物品的分数 {MR_i}_{i ∈ R}。
b. 选出分数最高的物品,将其从 R 移到 S。
滑动窗口
- 已选中的物品越多(即集合 S 越大),越难找出物品 i ∈ R,使得 i 与 S 中的物品都不相似。
- 设 sim 的取值范围是 [0, 1]。当 S 很大时,多样性分数 max_{j ∈ S} sim(i, j) 总是等于 1,导致 MMR 算法失效。
- 解决方案:设置一个滑动窗口 W,比如最近选中的 10 个物品,用 W 代替 MMR 公式中的 S。
总结
-
标准 MMR:
-
用滑动窗口:
业务规则约束下的多样性算法
重排的规则
规则:最多连续出现 k 篇某种笔记
- 小红书推荐系统的物品分为图文笔记、视频笔记。
- 最多连续出现 k = 5 篇图文笔记,最多连续出现 k = 5 篇视频笔记。
- 如果排 i 到 i + 4 的全都是图文笔记,那么排在 i + 5 的必须是视频笔记。
规则:每 k 篇笔记最多出现 1 篇某种笔记
- 运营推广笔记的精排分会乘以大于 1 的系数(boost),帮助笔记获得更多曝光。
- 为了防止 boost 影响体验,限制每 k = 9 篇笔记最多出现 1 篇运营推广笔记。
- 如果排第 i 位的是运营推广笔记,那么排 i + 1 到 i + 8 的不能是运营推广笔记。
规则:前 t 篇笔记最多出现 k 篇某种笔记
- 排名前 t 篇笔记最容易被看到,对用户体验最重要。(小红书的 top 4 为首屏)
- 小红书推荐系统有带电商卡片的笔记,过多可能会影响体验。
- 前 t = 1 篇笔记最多出现 k = 0 篇带电商卡片的笔记。
- 前 t = 4 篇笔记最多出现 k = 1 篇带电商卡片的笔记。
MMR + 重排规则
- 重排结合 MMR 与规则,在满足规则的前提下最大化 MR。
- 每一轮先用规则排除掉 R 中的部分物品,得到子集 R’。
- MMR 公式中的 R 替换成 R’,选中的物品符合规则。
DPP 多样性算法
多样性问题
- 精排给 n 个物品打分:reward_1, …, reward_n。
- n 个物品的向量表征:v_1, …, v_n ∈ R^d。
- 从 n 个物品中选出 k 个物品,组成集合 S。
- 价值大:分数之和 Σj∈s reward_j 越大越好。
- 多样性好:S 中 k 个向量组成的超平形体 P(S) 的体积越大越好。
行列式点过程(DPP)
-
DPP 是一种传统的统计机器学习方法:
-
Hulu 的论文将 DPP 应用在推荐系统:
-
DPP 是个组合优化问题,从集合 {1, …, n} 中选出一个大小为 k 的子集 S。
-
用 S 表示已选中的物品,用 R 表示未选中的物品,贪心算法求解:
规则约束
-
贪心算法每轮从 R 中选出一个物品:
-
有很多规则约束,例如最多连续出 5 篇视频笔记(如果已经连续出了 5 篇视频笔记,下一篇必须是图文笔记)。
-
用规则排除掉 R 中的部分物品,得到子集 R’,然后求解:
物品冷启动
优化目标 & 评价指标
物品冷启动
研究 UGC 的物品冷启
- 小红书上用户新发布的笔记。
- B 站上用户新上传的视频。
- 今日头条上作者新发布的文章。
新笔记冷启动
为什么要特殊对待新笔记?
- 新笔记缺少与用户的交互,导致推荐的难度大、效果差。
- 扶持新发布、低曝光的笔记,可以增强作者发布意愿。
优化冷启的目标
- 精准推荐:克服冷启的困难,把新笔记推荐给合适的用户,不引起用户反感。
- 激励发布:流量向低曝光新笔记倾斜,激励作者发布。
- 挖掘高潜:通过初期小流量的试探,找到高质量的笔记,给与流量倾斜。
评价指标
- 作者侧指标:
- 发布渗透率、人均发布量。
- 用户侧指标:
- 新笔记指标:新笔记的点击率、交互率。
- 大盘指标:消费时长、日活、月活。
- 内容侧指标:
- 高热笔记占比。
作者侧指标
发布渗透率(penetration rate)
- 发布渗透率 = 当日发布人数 / 日活人数
- 发布一篇或以上,就算一个发布人数。
- 例:
- 当日发布人数 = 100万
- 日活人数 = 2000万
- 发布渗透率 = 100 / 200 = 5%
人均发布量
-
人均发布量 = 当日发布笔记数 / 日活人数
-
例:
- 每日发布笔记数 = 200万
- 日活人数 = 2000万
- 人居发布量 = 200 / 2000 = 0.1
-
发布渗透率、人均发布量反应出作者的发布积极性。
-
冷启的重要优化目标是促进发布,增大内容池。
-
新笔记获得的曝光越多,首次曝光和交互出现得越早,作者发布积极性越高。
用户侧指标
新笔记的消费指标
- 新笔记的点击率、交互率。
- 问题:曝光的基尼系数很大。
- 少数头部新笔记占据了大部分的曝光。
- 分别考察高曝光、低曝光新笔记。
- 高曝光:比如 > 1000 次曝光。
- 低曝光:比如 < 1000 次曝光。
大盘消费指标
- 大盘的消费时长、日活、月活。
- 大力扶持低曝光新笔记会发生什么?
- 作者侧发布指标变好。
- 用户侧大盘消费指标变差。
内容侧指标
高热笔记占比
- 高热笔记:前 30 天获得 1000+ 次点击。
- 高热笔记占比越高,说明冷启阶段挖掘优质笔记的能力越强。
冷启动的优化点
- 优化全链路(包括召回和排序)。
- 流量调控(流量怎么在新物品、老物品中分配)。
简单的召回通道
召回的依据
✔ 自带图片、文字、地点。
✔ 算法或人工标注的标签。
❌ 没有用户点击、点赞等信息。
❌ 没有笔记 ID embedding
冷启召回的困难
- 缺少用户交互,还没学好笔记 ID embedding,导致双塔模型效果不好。
- 缺少用户交互,导致 ItemCF 不适用。
召回通道
❌ ItemCF 召回(不适用)
❓ 双塔模型(改造后适用)
✔ 类目、关键词召回(适用)
✔ 聚类召回(适用)
✔ Look-Alike 召回(适用)
ID Embedding
改进方案1:新笔记使用 default embedding
- 物品塔做 ID embedding 时,让所有新笔记共享一个 ID,而不是用自己真正的 ID。
- Default embedding:共享的 ID 对应的 embedding 向量。
- 到下次模型训练的时候,新笔记才有自己的 ID embedding 向量。
改进方案2:利用相似笔记 embedding 向量
- 查找 top k 内容最相似的高曝笔记。
- 把 k 个高曝笔记的 embedding 向量取平均,作为新笔记的 embedding。
多个向量召回池
- 多个召回池,让新笔记有更多曝光机会。
- 1 小时新笔记
- 6 小时新笔记
- 24 小时新笔记
- 30 天笔记
- 共享同一个双塔模型,那么多个召回池不增加训练的代价。
用户画像
-
感兴趣的类目:
美食、科技数码、电影 …
-
感兴趣的关键词:
纽约、职场、搞笑、程序员、大学 …
基于类目
- 系统维护类目索引:
- 类目 -> 笔记列表(按时间倒排)
- 用类目索引做召回:
- 用户画像 -> 类目 -> 笔记列表
- 取回笔记列表上前 k 篇笔记(即最新的 k 篇)。
基于关键词
-
系统维护关键词索引:
- 关键词 -> 笔记列表(按时间倒排)
-
根据用户画像上的关键词做召回。
缺点
- 只对刚刚发布的新笔记有效。
- 取回某类目 / 关键词下最新的 k 篇笔记。
- 发布几小时之后,就再没有机会被召回。
- 弱个性化,不够精准。
聚类召回
聚类索引
- 一篇新笔记发布之后,用神经网络把它映射到一个特征向量。
- 从 1000 个向量(对应 1000 个 cluster)中找到最相似的向量,作为新笔记的 cluster。
- 索引:
- cluster -> 笔记 ID 列表(按时间倒排)
线上召回
- 给定用户 ID,找到他的 last-n 交互的笔记列表,把这些笔记作为种子笔记。
- 把每篇种子笔记映射到向量,寻找最相似的 cluster。(知道了用户对哪些 cluster 感兴趣)
- 从每个 cluster 的笔记列表中,取回最新的 m 篇笔记。
- 最多取回 mn 篇新笔记。
内容相似度
模型的训练
<种子笔记,正样本>
方法一:人工标注二元组的相似度
方法二:算法自动选正样本
-
筛选条件:
- 只用高曝光笔记作为二元组(因为有充足的用户交互信息)。
- 两篇笔记有相同的二级类目,比如都是 “菜谱教程”。
-
用 ItemCF 的物品相似度选正样本。
-
从全体笔记中随机选出满足条件的:
- 字数较多(神经网络提取的文本信息有效)。
- 笔记质量高,避免图文无关。
总结
- 基本思想:根据用户的点赞、收藏、转发记录,推荐内容相似的笔记。
- 线下训练:多模态神经网络把图文内容映射到向量。
- 线上服务:
- 用户喜欢的笔记 -> 特征向量 -> 最近的 Cluster -> 新笔记
Look-Alike 召回
- 点击、点赞、收藏、转发 —— 用户对笔记可能感兴趣。
- 把有交互的用户作为新笔记的种子用户。
- 用 look-alike 在相似用户中扩散。
流量调控
扶持新笔记的目的
- 促进发布,增大内容池。
- 新笔记获得的曝光越多,作者创作积极性越高。
- 反映在发布渗透率、人均发布量。
- 挖掘优质笔记。
- 做探索,让每篇新笔记都能获得足够曝光。
- 挖掘的能力反映在高热笔记占比。
工业界做法
- 假设推荐系统只分发年龄 < 30 天的笔记。
- 假设采用自然分发,新笔记(年龄 < 24小时)的曝光占比为 1 / 30。
- 扶持新笔记,让新笔记的曝光占比远大于 1 / 30。
流量调控技术的发展
- 在推荐结果中强插新笔记。
- 对新笔记的排序分数做提权(boost)。
- 通过提权,对新笔记做保量。
- 差异化保量。
新笔记提权
-
目标:让新笔记有更多机会曝光。
- 如果做自然分发,24 小时新笔记占比为 1/ 30。
- 做人为干涉,让新笔记占比大幅提升。
-
干涉粗排、重排环节,给新笔记提权。
-
优点:容易实现,投入产出比好。
-
缺点:
- 曝光量对提权系数很敏感。
- 很难精确控制曝光量,容易过度曝光和不充分曝光。
新笔记保量
-
保量:不论笔记质量高低,都保证 24 小时获得 100 次曝光。
-
在原有提权系数的基础上,乘以额外的提权的系数,比如:
动态提权保量
用下面四个值计算提权系数
- 目标时间:比如 24 小时。
- 目标曝光:比如 100 次。
- 发布时间:比如笔记已经发布 12 小时。
- 已有曝光:比如笔记已经获得 20 次曝光。
保量的难点
保量成功率远低于 100%
-
很多笔记在 24 小时达不到 100 次曝光。
-
召回、排序存在不足。
-
提权系数调得不好
线上环境变化会导致保量失败
- 线上环境变化:新增召回通道、升级排序模型、改变重排打散规则 …
- 线上环境变化后,需要调整提权系数。
差异化保量
- 保量:不论新笔记质量高低,都做扶持,在前 24 小时给 100 次曝光。
- 差异化保量:不同笔记有不同保量目标,普通笔记保 100 次曝光,内容优质的笔记保 100 ~ 500 次曝光。
- 基础保量:24 小时 100 次曝光。
- 内容质量:用模型评价内容质量高低,给予额外保量目标,上限是加 200 次曝光。
- 作者质量:根据作者历史上的笔记质量,给与额外保量目标,上限是加 200 次曝光。
- 一篇笔记最少有 100 次保量,最多有 500 次保量。
总结
- 流量调控:流量怎么在新老笔记之间分配。
- 扶持新笔记:单独的召回通道、在排序阶段提权。
- 保量:帮助新笔记在前 24 小时获得 100 次曝光。
- 差异化保量:根据内容质量、作者质量,决定保量目标。
冷启的 AB 测试
用户侧实验
缺点
- 限定:保量 100 次曝光。
- 假设:新笔记曝光越多,用户使用 APP 时长越低。
- 新策略:把新笔记排序时的权重增大两倍。
- 结果(只看用户消费指标):
- AB 测试的 diff 是负数(实验组不如对照组)。
- 如果推全,diff 会缩小(比如 -2% -> -1%)。
作者侧实验:方案一
缺点:新笔记之间会抢流量
- 设定:
- 新老笔记走各自队列,没有竞争。
- 重排分给新笔记 1 / 3 流量,分给老笔记 2 / 3 流量。
- 新策略:把新笔记的权重增大两倍。
- 结果(只看作者发布指标):
- AB 测试的 diff 是正数(实验组优于对照组)。
- 如果推全,diff 会消失(比如 2% -> 0)。
缺点:新笔记和老笔记抢流量
- 设定:新老笔记自由竞争。
- 新策略:把新笔记排序时的权重增大两倍。
- AB 测试时,50%新笔记(带策略)跟 100% 老笔记抢流量。
- 推全后,100% 新笔记(带策略)跟 100% 老笔记抢流量。
- AB 测试结果与推全结果有差异。
作者侧实验:方案二
方案二比方案一的优缺点
- 优点:新笔记的两个桶不抢流量,实验结果更可信。
- 相同:新笔记和老笔记抢流量,AB 测试结果与推全结果有差异。
- 缺点:新笔记池减小一半,对用户体验造成负面影响。
作者侧实验:方案三
总结
-
冷启的 AB 测试需要观测作者发布指标和用户消费指标。
-
各种 AB 测试的方案都有缺点。
-
设计方案的时候,问自己几个问题:
-
实验组、对照组新笔记会不会抢流量?
在进行新笔记的AB测试时,实验组和对照组的新笔记可能会出现流量竞争的情况。如果实验组的新笔记通过提权等策略获得更多曝光,可能会抢占对照组新笔记的流量,导致实验结果出现偏差。这种竞争可能使实验组的发布指标上升,而对照组的发布指标下降,从而产生差异。
-
新笔记、老笔记怎么抢流量?
在推荐系统中,新发布的笔记(新笔记)和已有的笔记(老笔记)在获取用户曝光时可能存在竞争关系。由于老笔记通常已积累一定的用户反馈数据,推荐系统更容易评估其质量,从而在排序中占据优势。相比之下,新笔记缺乏用户交互数据,可能在推荐中处于劣势,导致曝光机会减少。
-
同时隔离笔记、用户,会不会让内容池变小?
在AB测试中,同时对用户和笔记进行隔离,即将用户和新笔记分别分配到实验组和对照组,确实会导致每个组内的内容池缩小。具体而言,实验组用户只能访问实验组的新笔记,对照组用户只能访问对照组的新笔记。这种隔离方式减少了每个用户可接触的内容数量,可能影响推荐效果,进而降低用户体验。
-
如果对新笔记做保量,会发生什么?
实验结果偏差:在AB测试中,如果对实验组的新笔记进行保量,而对照组未实施相同策略,实验组的新笔记可能获得更多曝光,导致实验结果不准确。
流量竞争:新笔记的保量曝光可能与老笔记争夺用户注意力,影响老笔记的曝光机会,进而影响整体推荐效果。
用户体验影响:如果保量策略导致低质量的新笔记频繁曝光,可能降低用户体验,影响用户对平台的满意度。
-