# Recommend **Repository Path**: lilongjiu/Recommend ## Basic Information - **Project Name**: Recommend - **Description**: 王树森,推荐系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2025-12-18 - **Last Updated**: 2025-12-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 推荐算法 ## 概览 * 召回:用多条通道,取回几千篇笔记 * 粗排:用小规模神经网络,给几千篇笔记打分,选出分数最高的几百篇 * 精排:用大规模神经网络,给几百篇笔记打分 * 重排:做多样性抽样、规则打散、插入广告和运营笔记 ## 召回 ### 1. 基于物品的协同过滤(ItemCF) 计算物品相似度: * 喜欢物品$i_1$的用户记作集合$W_1$ * 喜欢物品$i_2$的用户记作集合$W_2$ * 定义交集$V=W_1 \cap W_2$ * 两个物品的相似度: $sim(i_1,i_2)=\frac{|V|}{\sqrt{|W_1||W_2|}}$ $sim(i_1,i_2)=\frac{\Sigma_{v \in V}like(v,i_1)*like(v,i_2)}{\sqrt{\Sigma_{u_1\in W_1}like^2(u_1, i_1)}*{\sqrt{\Sigma_{u_2 \in W_2}like^2(u_2,i_2)}}}$ * 离线维护两个索引: * 用户->物品列表:用户最近交互过的n个物品 * 物品->物品列表:相似度最高的k个物品 * 线上做召回: * 利用两个索引,每次取回nk个物品 * 预估用户对每个物品的兴趣分数 $\Sigma_jlike(user,item_j)\times sim(item_j,item)$ * 返回分数最高的100个物品,作为召回结果 ### 2. Swing模型 * 用户$u_1$喜欢的物品记作集合$J_1$ * 用户$u_2$喜欢的物品记作集合$J_2$ * 定义两个用户的重合度: $overlap(u_1,u_2)=|J_1 \cap J_2|$ * 用户$u_1$和$u_2$的重合度高,则他们可能来自一个小圈子,要降低他们的权重 * 喜欢物品$i_1$的用户记作集合$W_1$ * 喜欢物品$i_2$的用户记作集合$W_2$ * 定义交集$V=W_1 \cap W_2$ * 两个物品的相似度: $sim(i_1,i_2)=\Sigma_{u_1 \in V}\Sigma_{u_2 \in V} \frac{1}{\alpha + overlap(u_1,u_2)}$ * Swing和ItemCF唯一区别在于物品相似度 * ItemCF:两个物品重合的用户比例高,则判定两个物品相似 * Swing:额外考虑重合的用户是否来自一个小圈子 * 同时喜欢两个物品的用户记作集合V * 对于V中的用户u1和u2,重合度记作overlap(u1,u2) * 两个用户重合度大,则可能来自一个小圈子,权重降低 * 用户$u_1$喜欢的物品记作集合$J_1$ * 用户$u_2$喜欢的物品记作集合$J_2$ * 定义交集$I=J_1 \cap J_2$ * 两个用户的相似度: $sim(u_1,u_2)=\frac{\Sigma_{l \in I} \frac{1}{log(1+n_l)}}{\sqrt{|J_1||J_2|}}$ $n_l$:喜欢物品$l$的用户数量,反映物品的热门程度 ### 3. 基于用户的协同过滤(UserCF) * 用户u1跟用户u2相似,而且u2喜欢某物品,那么u1也可能喜欢该物品 * 用户相似度: * 如果用户u1和u2喜欢的物品有很大的重叠,那么u1和u2相似 * 公式:$sim(u_1,u_2)=\frac{|J_1\cap J_2|}{\sqrt{J_1}\times\sqrt{J_2}}$ * 维护两个索引: * 用户->物品列表:用户近期交互过的n个物品 * 用户->用户列表:相似度最高的k个用户 * 线上做召回: * 利用两个索引,每次取回nk个物品 * 预估用户user对每个物品item的兴趣分数: $\Sigma_jsim(user,user_j)\times like(user_j, item)$ * 返回分数最高的100个物品,作文召回结果 ### 4. 矩阵补充模型(效果不好) 模型训练 * 把物品ID、用户ID做embedding,映射成向量 * 两个向量的内积作为用户u对物品i兴趣的预估 * 让拟合真实观测的兴趣分数,学习模型embedding层参数 线上召回 * 把用户向量a作为query,查找使得最大化物品i * 暴力枚举速度太慢。实践中使用近似最近邻查找。 ### 5. 双塔模型 用户塔、物品塔各输出一个向量。 两个向量的余弦相似度作为兴趣的预估值。 #### 模型训练 * Pointwise:独立看待每个正样本、负样本,做简单的二元分类 * Pairwise:每次取一个正样本、一个负样本 * Listwise:每次取一个正样本、多个负样本 * 正样本:用户点击的物品 * 负样本: * 没有被召回的? * 召回但是被粗排、精排淘汰的? * 曝光但是未点击的? #### 正负样本选择 召回的目标:**快速找到用户可能感兴趣的物品** * 全体物品(easy):绝大多数是用户根本不感兴趣的 * 被排序淘汰(hard):用户可能感兴趣,但是不够感兴趣 * 有曝光没点击(没用):用户感兴趣,可能碰巧没有点击 * 正样本:曝光而且有点击 * 简单负样本: * 全体物品 * batch内负样本 * 困难负样本:被召回,但是被排序淘汰 * 错误:曝光、但是未点击的物品做召回的负样本 ![](images/loss.png) #### 线上召回 #### 离线存储:把物品向量b存入向量数据库 1. 完成训练后,用物品塔计算每个物品的特征向量b 2. 把几亿个物品向量b存入向量数据库 3. 向量数据库建索引,以便加速最近邻查找 #### 线上召回:查找用户最感兴趣的k个物品 1. 给定用户ID和画像,线上用神经网络算用户向量a 2. 最近邻查找: * 把向量a作为query,调用向量数据库做最近邻查找 * 返回余弦相似度最大的k个物品,作为召回结果 ##### 事先存储物品向量b,线上现算用户向量a,why? * 每做一次召回,用到一个用户向量a,几亿物品向量b(线上算物品向量的代价过大) * 用户兴趣动态变化,而物品特征相对稳定。(可以离线存储用户向量,但不利于推荐效果) #### 模型更新:全量更新 vs 增量更新 全量更新:今天凌晨,用昨天全天的数据训练模型。(天级别) * 在昨天模型参数的基础上做训练。(不是随机初始化) * 用昨天的数据,训练1epoch,即每天数据只用一遍 * 发布新的**用户塔神经网络和物品向量**,供线上召回使用 * 全量更新对数据流、系统的要求比较低 增量更新:做online learning更新模型参数(几小时之内更新) * 用户兴趣会随时发生变化 * 实时收集线上数据,做流式处理,生成TFRecord文件 * 对模型做online learning,增量更新ID Embedding参数 * 发布用户ID Embedding,供用户塔在线上计算用户向量 ![](images/update.png) #### 问题:能否只做增量更新,不做全量更新? * 小时级数据有偏;分钟级数据偏差更大 * 全量更新:random shuffle一天的数据,做1epoch训练 * 增量更新:按照数据从早到晚的顺序,做1epoch训练 * 随机打乱优于按顺序排列数据,全量训练优于增量训练 ### 6. 双塔模型+自监督学习 #### 双塔模型的问题 * 推荐系统的头部效应严重 * 少部分物品占据大部分点击 * 大部分物品的点击次数不高 * 高点击物品的表征学得好,长尾物品的表征学得不好 * 自监督学习:做data augmentation,更好地学习长尾物品的向量表征 #### 纠偏 * 物品j被抽样到的概率: $$ p_j \propto 点击次数 $$ * 预估用户i对物品j的兴趣:cos(ai, bi) * 做训练的时候,把cos(ai, bi)替换为: $$ cos(a_i, b_j)-logp_j $$ #### 自监督学习 特征变换: * Random Mask * Dropout(仅对多值离散特征生效) * 互补特征(complementary) * Mask一组关联的特征 ### 7. Deep Retrieval * 经典的双塔模型把用户、物品表示为向量,线上做最近邻查找 * Deep Retrieval把物品表征为路径(path),线上查找用户最匹配的路径 **召回**:用户->路径->物品 * 给定用户特征x,用神经网络预估用户对路径path=[a,b,c]的兴趣,分数记作p(path|x) * 用beam search寻找分数p(path|x)最高的s条path * 利用索引“path->List”召回每条路径上的n个物品 * 一共召回 s x n个物品,对物品做初步排序,返回分数最高的若干物品 **训练**:同时学习**用户-路径**和**物品-路径**的关系 * 一个物品被表征为J条路径:path1, ..., pathj * 如果用户点击过物品,则更新神经网络参数,使分数增大: $$ \Sigma p(path_j|x) $$ * 如果用户对路径的兴趣分数$p(path|x)$较高,且用户点击过物品item,则item与path具有相关性 * 寻找与item最相关的j条path,且避免一条路径上物品过多 ### 8. 地理位置召回 经纬度+城市 -> 优质笔记列表 ### 9. 作者召回 * 关注作者召回: * 索引:用户 -> 关注的作者,作者 -> 发布的笔记 * 召回:用户 -> 关注的作者 -> 最新的笔记 * 有交互的作者召回 * 相似作者召回 ### 10. 缓存召回 **想法:复用前n次推荐精排的结果** * 背景: * 精排输出几百篇笔记,送入重排。 * 重排做多样性抽样,选出几十篇 * 精排结果一大半没有曝光,被浪费 * 精排前50,但是没有曝光的,缓存起来,作为一条召回通道 缓存大小固定,需要退场机制 * 一旦笔记成功曝光,就从缓存退场 * 如果超出缓存大小,就移除最先进入缓存的笔记 * 笔记最多被召回10次,达到10次就退场 * 每篇笔记最多保存3天,达到3天就退场 ### 11. 曝光过滤 & 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之间的整数 ![](images/bloom_filter.png) * 曝光物品集合大小为n,二进制向量维度为m,使用k个哈希函数 * Bloom filter误伤的概率为$\delta = (1 - exp(-\frac{kn}{m}))^k$ * n越大,向量中的1越多,误伤概率越大(未曝光物品的k个位置恰好都是1的概率大) * m越大,向量越长,越不容易发生哈希碰撞 * k太大,太小都不好,k有最优取值 * 设定可容忍的误伤概率为$\delta$,那么最优参数为: * $k=1.44*ln(\frac{1}{\delta}), m=2n*ln(\frac{1}{\delta})$ * 每往集合中添加一个物品,只需要把向量k个位置的元素置为1。(如果原本就是1,则不变) * Bloom filter只支持添加物品,不支持删除物品。从集合中移除物品,无法消除它对向量的影响。 * 每天都需要从物品集合中移除年龄大于1个月的物品。(超龄物品不可能被召回,没必要把它们记录在Bloom filter,降低n可以降低误伤率) ## 精排 #### 用户——笔记的交互 * 点击率 = 点击次数 / 曝光次数 * 点赞率 = 点赞次数 / 点击次数 * 收藏率 = 收藏次数 / 点击次数 * 转发率 = 转发次数 / 点击次数 #### 排序的依据 * 排序模型预估点击率、点赞率、收藏率、转发率等多种分数 * 融合这些预估分数(比如加权和) * 根据融合的分数做排序、截断 ### 1. 多目标排序模型 ![](images/multi_target.png) ![](images/muti_target2.png) #### 训练 * 困难:类别不平衡 * 每100次曝光,约有10次点击、90次无点击 * 每100次点击,约有10次收藏、90次无收藏 * 解决方案:负样本降采样 * 保留一小部分负样本 * 让正负样本数量平衡,节约计算 #### 预估值校准 * 正样本、负样本数量为$n_+$和$n_-$ * 对负样本做降采样,抛弃一部分负样本 * 使用$\alpha n_-$个负样本,$\alpha \in (0,1)$是采样率 * 由于负样本变少,预估点击率大于真实点击率 * 真实点击率:$p_{true}=\frac{n_+}{n_++n_-}$ * 预估点击率:$p_{pred}=\frac{n_+}{n_++\alpha n_-}$ * 校准公式:$p_{true}=\frac{\alpha p_{pred}}{(1-p_{pred})+\alpha p_{pred}}$ ### 2. Multi-gate Mixture-of-Experts(MMoE) 将神经网络输出的向量做加权平均,然后用该向量去评估某个业务指标。 ![](images/MMoE1.png) ![](images/MMoE2.png) #### 极化现象 Softmax输出值一个接近1,其余接近0 #### 解决极化问题 * 如果有n个“专家”,那么每个softmax的输入和输出都是n维向量 * 在训练时,对softmax的输出使用dropout(原因:如果发生极化现象的话,训练效果会非常差) * Softmax输出的n个数值被mask的概率都是10% * 每个“专家”被随机丢弃的概率都是10% ### 3. 融合预估分数 #### 简单的加权和 $$ p_{click} + w_1\cdot p_{like} + w_2 \cdot p_{collect} + ... $$ #### 点击率乘以其他项的加权和 $$ p_{click} \cdot (1 + w_1\cdot p_{like} + w_2\cdot p_{collect} + ...) $$ #### 海外某短视频APP的融分公式 $$ (1+w_1\cdot p_{time})^{\alpha_1} \cdot (1+w_2\cdot p_{like})^{\alpha_2} ... $$ #### 国内某短视频APP的融分公式 * 根据预估时长$p_{time}$,对n篇候选视频做排序 * 如果某视频排名第$r_{time}$,则它得分$\frac{1}{r_{time}^\alpha + \beta}$ * 对点击、点赞、转发、评论等预估分数 做类似处理 * 最终融合分数: $$ \frac{w_1}{r_{time}^{\alpha_1} + \beta_1} + \frac{w_2}{r_{click}^{\alpha_2} + \beta_2} + \frac{w_3}{r_{like}^{\alpha_3} + \beta_3} + ... $$ #### 某电商的融分公式 * 电商的转化流程: 曝光->点击->加购物车->付款 * 模型预估:$p_{click}、p_{cart}、p_{pay}$ * 最终融合分数:$p_{click}^{\alpha_1} \times p_{cart}^{\alpha_2} \times p_{pay}^{\alpha_3} \times price^{\alpha_4}$ ### 4. 视频播放建模 #### 视频播放时长 图文 vs 视频 * 图文笔记排序的主要依据: 点击、点赞、收藏、转发、评论...... * 视频排序的依据还有播放时长和完播 * 直接用回归拟合播放时长效果不好 ![](images/video.png) #### 视频播放时长建模 * 把最后一个全连接层的输出记作$z$。设$p=sigmoid(z)$ * 实际观测的播放时长记作$t$。(如果没有点击,则t=0) * 做训练:最小化交叉熵损失 $$ -(\frac{1}{1+t}\cdot logp + \frac{1}{1+t}\cdot log(1-p)) $$ * 做推理:把exp(z)作为播放时长的预估 * 把exp(z)作为融分公式中的一项 #### 视频完播 ##### 回归方法 * 视频长度10分钟,实际播放4分钟,则实际播放率为$y=0.4$ * 让预估播放率$p$拟合$y$: $$ loss=y\cdot logp+(1-y)\cdot log(1-p) $$ * 线上预估完播率,模型输出$p=0.73$,意思是预计播放73% ##### 二元分类方法 * 定义完播指标,比如完播80% * 视频长度10分钟,播放>8分钟作为正样本,播放<8分钟作为负样本 * 做二元分类训练模型:播放>80% vs 播放<80% * 线上预估完播率,模型输出$p=0.73$,意思是 $$ P(播放>80\%)=0.73 $$ ##### 不能直接把预估的完播率用到融分公式(why)? ![](images/video2.png) * 线上预估完播率,然后做调整: $$ p_{finish}=\frac{预估完播率}{f(视频长度)} $$ * 把$p_{finish}$作为融分公式中的一项 ## 排序模型的特征 #### 1. 用户画像(User Profile) * 用户ID(在召回、排序中做embedding) * 人口统计学属性:性别、年龄 * 账号信息:新老、活跃度... * 感兴趣的类目、关键词、品牌 #### 2. 物品画像(Item Profile) * 物品ID(在召回、排序中做embedding) * 发布时间(或者年龄) * GeoHash(经纬度编码)、所在城市 * 标题、类目、关键词、品牌.... * 字数、图片数、视频清晰度、标签数.... * 内容信息量、图片美学.... #### 3. 用户统计特征 * 用户最近30天(7天、1天、1小时)的曝光数、点击数、点赞数、收藏数... * 按照笔记图文/视频分桶。(比如最近7天,该用户对图文笔记的点击率、对视频笔记的点击率) * 按照笔记类目分桶。(比如最近30天,用户对美妆笔记的点击率、对美食笔记的点击率、对科技数码笔记的点击率) #### 4. 笔记统计特征 * 笔记最近30天(7天、1天、1小时)的曝光数、点击数、点赞数、收藏数... * 按照用户性别分桶、按照用户年龄分桶...... * 作者特征: * 发布笔记数 * 粉丝数 * 消费指标(曝光数、点击数、点赞数、收藏数) #### 5. 场景特征(Context) * 用户定位GeoHash(经纬度编码)、城市。 * 当前时刻(分段,做embedding)。 * 是否是周末、是否是节假日。 * 手机品牌、手机型号、操作系统。 #### 6. 特征处理 * 离散特征:做embedding。 * 用户ID、笔记ID、作者ID。 * 类目、关键词、城市、手机品牌。 * 连续特征:做分桶,变成离散特征。 * 年龄、笔记字数、视频长度。 * 连续特征:其他变换。 * 曝光数、点击数、点赞数等数值做$log(1+x)$。 * 转化为点击率、点赞率等值,并做平滑。 #### 7. 特征覆盖率 * 很多特征无法覆盖100%样本 * 例:很多用户不填年龄,因此用户年龄特征的覆盖率远小于100% * 例:很多用户设置隐私权限,APP不能获得用户地理定位,因此场景特征有缺失 * 提高特征覆盖率,可以让精排模型更准 ![](images/Data_server.png) ## 粗排 | 粗排 | 精排 | | ------------------ | ---------------- | | 给几千篇笔记打分 | 给几百篇笔记打分 | | 单次推理代价必须小 | 单次推理代价很大 | | 预估的准确性不高 | 预估的准确性更高 | #### 精排模型 * 前期融合:先对所有特征做concatenation,再输入神经网络 * 线上推理代价大:如果有n篇候选笔记,整个大模型要做n次推理 #### 双塔模型 * 后期融合:把用户、物品特征分别输入不同的神经网络,不对用户、物品特征做融合。 * 线上计算量小: * 用户塔只需要做一次线上推理,计算用户表征a。 * 物品表征b事先存储在向量数据库中,物品塔在线上不做推理。 * 预估准确性不如精排模型。 ### 1. 粗排的三塔模型 ![](images/Rough_ranking.png) ![](images/Rough_ranking2.png) 模型上层(全连接层+sigmoid) * 有n个物品,模型上层需要做n次推理 * 粗排推理的大部分计算量在模型上层 #### 三塔模型的推理 * 从多个数据源取特征: * 1个用户的画像、统计特征 * n个物品的画像、统计特征 * 用户塔:只做1次推理 * 物品塔:未命中缓存时需要做推理 * 交叉塔:必须做n次推理 * 上层网络做n次推理,给n个物品打分 ## 交叉结构(Crossing) ### 1. Factorized Machine(FM) ![](images/FM.png) * FM是线性模型的替代品,能用线性回归、逻辑回归的场景,都可以用FM。 * FM使用二阶交叉特征,表达能力比线性模型更强。 * 通过做近似$u_{ij}\approx v_i^Tv_j$,FM把二阶交叉权重的数量从$O(d^2)$降低到$O(kd)$ ### 2. 深度交叉网络(DCN) 交叉层(Cross Layer) ![](images/Cross_layer.png) 交叉网络(Cross Network) ![](images/Cross_network.png) 深度交叉网络(Deep & Cross Network) ![](images/DCN.png) ### 3. LHUC网络结构 * LHUC(Learning Hidden Unit Contributions)起源于语音识别 * 快手将LHUC应用在推荐精排,称作PPNet ![](images/LHUC.png) 这里的神经网络都是【多个全连接层】-> 【Sigmoid X 2】 ### 4. SENet & Bilinear Cross -> FiBiNet ![](images/SENet.png) ![](images/SENet2.png) #### SENet * SENet对离散特征做field-wise加权 * Field: * 用户ID Embedding是64维向量 * 64个元素算一个field,获得相同的权重 * 如果有m个fields,那么权重向量是m维 #### Field间特征交叉 * 向量内积(维度必须相同) * 哈达玛乘积(维度必须相同) * Bilinear cross(维度可以不同) ![](images/Bilinear_cross.png) ![](images/FiBiNet.png) --- ## 用户行为序列建模 ### LastN特征 * LastN:用户最近的n次交互(点击、点赞等)的物品ID * 对LastN物品ID做embedding,得到n个向量 * 把n个向量取平均,作为用户的一种特征 * 适用于召回双塔模型、粗排三塔模型、精排模型 ![](images/LastN.png) ### 1. DIN模型(精排) * DIN用加权平均代替平均,即注意力机制。 * 权重:候选物品与用户LastN物品的相似度。 ![](images/DIN.png) * 对于某候选物品,计算它与用户LastN物品的相似度。 * 以相似度为权重,求用户LastN物品向量的加权和,结果是一个向量。 * 把得到的向量作为一种用户特征,输入排序模型,预估(用户、候选物品)的点击率、点赞率等指标。 * 本质是注意力机制(attention) #### 简单平均 vs 注意力机制 * 简单平均和**注意力机制**都适用于精排模型。 * 简单平均适用于双塔模型、三塔模型。 * 简单平均只需要用到LastN,属于用户自身的特征。 * 把LastN向量的平均作为用户塔的输入。 * **注意力机制**不适用于双塔模型、三塔模型。 * **注意力机制**需要用到LastN + 候选物品。 * 用户塔看不到候选物品,不能把**注意力机制**用在用户塔。 #### DIN模型缺点 * 注意力层的计算量$\propto n$(用户行为序列的长度) * 只能记录最近几百个物品,否则计算量太大 * 缺点:关注短期兴趣、遗忘长期兴趣 ### 2. SIM模型 * 保留用户长期行为记录,n的大小可以是几千。 * 对于每个候选物品,在用户LastN记录中做快速查找,找到k个相似物品。 * 把LastN变成TopK,然后输入到注意力层。 * SIM模型减小计算量(从n降到k)。 #### 第一步:查找 * 方法一:Hard Search * 根据候选物品的类目,保留LastN物品中类目相同的。 * 简单,快速,无需训练 * 方法二:Soft Search * 把物品做embedding,变成向量。 * 把候选物品向量作为query,做k近邻查找,保留LastN物品中最接近的k个 * 效果更好,编程实现更复杂 #### 第二步:注意力机制 为什么SIM使用时间信息? * DIN的序列短,记录用户近期行为 * SIM的序列长,记录用户长期行为 * 时间越久远,重要性越低 #### 结论 * 长序列(长期兴趣)优于短序列(近期兴趣)。 * 注意力机制优于简单平均。 * Soft search还是hard search?取决于工程基建。 * 使用时间信息有提升。 ## 推荐系统中的多样性 ### 1. 物品相似性的度量 #### 基于物品属性标签 * 物品属性标签:类目、品牌、关键词...... * 根据一级类目、二级类目、品牌计算相似度 * 物品i:美妆、彩妆、香奈儿 * 物品j:美妆、香水、香奈儿 * 相似度:sim1(i,j)=1, sim2(i,j)=0, sim3(i,j)=1 #### 基于图文内容的物品表征 ![](images/characterization.png) * CLIP是当前公认最有效的预训练方法 * 思想:对于图片——文本二元组,预测图文是否匹配 * 优势:无需人工标注。 * 负样本:batch内负样本 ### 2. 提升多样性的方法(让曝光的物品尽量不相似) * 给定n个候选物品,**排序模型**打分 $$ reward_1,...,reward_n $$ * **后处理:**从n个候选物品中选出k个,既要它们的总分高,也需要它们有多样性 * 精排后处理称为**重排** #### 1)Maximal Marginal Relevance(MMR) ![](images/MMR.png) 1. 已选中的物品$S$初始化为空集,未选中的物品$R$初始化为全集$\{1,...,n\}$ 2. 选择精排分数$reward_i$最高的物品,从集合$R$移到$S$ 3. 做$k-1$轮循环: a. 计算集合$R$中所有物品的分数$\{MR_i\}_{i \in R}$ b. 选出分数最高的物品,将其从$R$移到$S$ #### 滑动窗口 * 离得远的物品可以相似,近的不行 * 已选中的物品越多(即集合$S$越大),越难找出物品$i \in R$,使得$i$与$S$中的物品都不相似,MMR算法失效 * 解决方案:设置一个滑动窗口$W$,比如最近选中的10个物品,用$W$代替MMR公式中的$S$ ![](images/window.png) #### 重排的规则(规则优先级高于多样性算法) ##### 规则:最多连续出现k篇某种笔记 * 小红书推荐系统的物品分为图文笔记、视频笔记 ##### 规则:每k篇笔记最多出现1篇某种笔记(运营推广笔记) ##### 规则:前t篇笔记最多出现k篇某种笔记 * 排名前t篇笔记最容易被看到,对用户体验最重要 * 小红书推荐系统有带电商卡片的笔记,过多可能会影响体验 #### MMR + 重排规则 * MMR每一轮选出一个物品 * 重排结合MMR与规则,在满足规则的前提下最大化MR * 每一轮先用规则排除掉$R$中的物品,得到子集$R'$ * MMR公式中的$R$替换成子集$R'$,选中的物品符合规则 #### 2)DPP ##### 数学基础 多样性越好,体积越大,而行列式和体积平方等价,所以可以用行列式来衡量多样性 ![](images/math.png) ![](images/DPP.png) ![](images/DPP2.png) ![](images/DPP3.png) ##### Hulu的快速算法 每一轮循环,基于上一轮算出的$A_s = LL^T$,快速求出$A_{s\cup\{i\}}$ ##### DPP也可以和滑动窗口和规则约束结合 ## 物品冷启动 研究UGC(User Generate Content)的物品冷启动 * 小红书上用户新发布的笔记 * B站上用户新上传的视频 * 今日头条上作者新发布的文章 为什么要特殊对待新笔记? * 新笔记缺少与用户的交互,导致推荐的难度大、效果差 * 扶持新发布、低曝光的笔记,可以增强作者发布意愿 优化冷启动的目标 1. 精准推荐:克服冷启动的困难,把新笔记推荐给合适的用户,不引起用户反感 2. 激励发布:流量向低曝光新笔记倾斜,激励作者发布 3. 挖掘高潜:通过初期小流量的试探,找到高质量的笔记,给与流量倾斜 ### 1. 评价指标 #### 作者侧指标 * **发布渗透率**=当日发布人数/日活人数,发布一篇或以上,就算一个发布人数 * **人均发布量**=当日发布笔记数/日活人数 * 发布渗透率、人均发布量反映出作者的发布积极性 * 冷启的重要优化目标是促进发布,增大内容池 * 新笔记获得的曝光越多,首次曝光和交互出现得越早,作者发布积极性越高 #### 用户侧指标 **新笔记的消费指标** * 新笔记的点击率、交互率 * 问题:曝光的基尼系数很大 * 少数头部新笔记占据了大部分的曝光 * 分别考察高曝光、低曝光新笔记 * 高曝光:比如>1000次曝光 * 低曝光:比如<1000次曝光 **大盘消费指标** * 大盘的消费时长、日活、月活 * 大力扶持低曝光新笔记会发生什么? * 作者侧发布指标变好 * 用户侧大盘消费指标变差 #### 内容侧指标 高热笔记占比 * 高热笔记:前30天获得1000+次点击 * 高热笔记占比越高,说明冷启动阶段挖掘优质笔记的能力越强 ### 2. 冷启动的优化点 * 优化全链路(包括召回和排序) * 流量调控(流量怎么在新物品、老物品中分配) ### 3. 冷启动召回(给新笔记单独的召回通道) 冷启动召回的困难 * 缺少用户交互,还没学好笔记ID embedding,导致双塔模型效果不好 * 缺少用户交互,导致ItemCF不适用 #### 1)改进双塔模型 **改进方案1:新笔记使用default embedding** * 物品塔做ID embedding时,让所有新笔记共享一个ID,而不是用自己真正的ID * Default embedding:共享的ID对应的embedding向量 * 到下次模型训练的时候,新笔记才有自己的ID embedding向量 **改进方案2:利用相似笔记embedding向量** * 查找top k内容最相似的高曝笔记 * 把k个高曝笔记的embedding向量取平均,作为新笔记的embedding #### 2)基于类目、关键词召回 用户画像:感兴趣的**类目**、**关键词** 类目->笔记列表(按时间倒排) 关键词->笔记列表(按时间倒排) **缺点1:只对刚刚发布的新笔记有效** * 取回某类目/关键词下最新的k篇笔记 * 发布几小时之后,就再没有机会被召回 **缺点2:弱个性化,不够精准** #### 3)聚类召回 基本思想 * 如果用户喜欢一篇笔记,那么他会喜欢内容相似的笔记 * 事先训练一个神经网络,基于笔记的类目和图文内容,把笔记映射到向量 * 对笔记向量做聚类,划分为1000cluster,记录每个cluster的中心方向。(K-means聚类,用余弦相似度) 聚类索引 * 一篇新笔记发布之后,用神经网络把它映射到一个特征向量 * 从1000个向量(对应1000个cluster)中找到最相似的向量,作为新笔记的cluster * 索引: cluster -> 笔记ID列表(按时间倒排) 线上召回 * 给定用户ID,找到它的last-n交互的笔记列表,把这些笔记作为种子笔记 * 把每篇种子笔记映射到向量,寻找最相似的cluster * 从每个cluster列表中,取回最新的m篇笔记 * 最多取回mn篇新笔记 ![](images/cluster.png) ![](images/cluster2.png) ##### <种子笔记,正样本> 方法一:人工标注二元组的相似度 方法二:算法自动选正样本 * 筛选条件: * 只用高曝光笔记作为二元组(因为有充足的用户交互信息) * 两篇笔记有相同的二级类目,比如都是“菜谱教程” * 用ItemCF的物品相似度来选正样本 ##### <种子笔记,负样本> 从全体笔记中**随机选出**满足条件的: * 字数较多(神经网络提取的文本信息有效) * 笔记质量高,避免图文无关 ##### 聚类召回总结 * 基本思想:根据用户的点赞、收藏、转发记录、推荐内容相似的笔记 * 线下训练:多模态神经网络把图文内容映射到向量 * 线上服务: 用户喜欢的笔记 -> 特征向量 -> 最近的Cluster -> 新笔记 #### 4)Look-Alike人群扩散召回 * 点击、点赞、收藏、转发——用户对笔记可能感兴趣 * 把有交互的用户作为新笔记的种子用户 * 用look-alike在相似用户中扩散 新笔记对应一个**特征向量**,他是**有交互的用户**的向量的**平均**。每当有用户交互该物品,更新笔记的特征向量。 线上召回时将用户向量作为query,寻找最近邻的特征向量对应的笔记 ### 4. 冷启动——流量调控 #### 扶持新笔记的目的 目的1:促进发布,增大内容池 * 新笔记获得的曝光越多,作者创作积极性越高 * 反映在发布渗透率、人均发布量 目的2:挖掘优质笔记 * 做探索,让每篇新笔记都能获得足够曝光 * 挖掘的能力反映在高热笔记占比 #### 流量调控技术的发展 1. 在推荐结果中强插新笔记 2. 对新笔记的排序分数做提权(boost) 3. 通过提权,对新笔记做保量 4. 差异化保量(依据内容好坏) #### 新笔记提权 干涉**粗排**、**重排**环节,给新笔记提权 优点:容易实现,投入产出比好 缺点: * 曝光量对提权系数很敏感 * 很难精确控制曝光量,容易过度曝光和不充分曝光 #### 新笔记保量 * 保量:不论笔记质量高低,都保证24小时获得100次曝光 * 在原有提权系数的基础上,乘以额外的提权系数 ![image-20250216195156810](images/dynamic_weight.png) 保量的难点: **保量的成功率远低于100%** * 很多笔记在24小时达不到100次曝光 * 召回、排序存在不足 * 提权系数调得不好 **线上环境变化会导致保量失败** * 新增召回通道、升级排序模型、改变重排打散规则 * 线上环境变化后,需要调整提权系数 **给新笔记分数boost越多,对新笔记越有利?** 好处:分数提升越多,曝光次数越多 坏处:把笔记推荐给不太合适的受众 * 点击率、点赞率等指标会偏低 * 长期会受推荐系统打压,难以成长为热门笔记 **差异化保量** 普通保量:不论新笔记质量高低,都做扶持,在前24小时给100次曝光 差异化保量:不同笔记有不同保量目标,普通笔记保100次曝光,内容优质的笔记保100-500次曝光(内容质量、作者质量) ### 冷启动AB测试 #### 总结 * 冷启的AB测试需要观测**作者发布指标**和**用户消费指标** * 各种AB测试的方案都有缺点 * 设计方案的时候,问自己几个问题: * 实验组、对照组新笔记会不会抢流量? * 新笔记、老笔记怎么抢流量? * 同时隔离笔记、用户,会不会让内容池变小? * 如果对新笔记做保量,会发生什么? ## 涨指标的方法 * 日活用户数(DAU)和留存是最核心的指标 * 目前工业界最常用LT7和LT30衡量留存 * 其他核心指标:用户使用时长、总阅读数(即总点击数)、总曝光数。这些指标的重要性低于DAU和留存 * 时长增长,LT通常会增长 * 时长增长,阅读数、曝光数可能会下降 * 非核心指标:点击率、交互率、等等 * 对于UGC平台,发布量和发布渗透率也是核心指标 方法: * 改进召回模型,添加新的召回模型 * 改进粗排和精排模型 * 提升召回、粗排、精排中的多样性 * 特殊对待新用户、低活用户等特殊人群 * 利用关注、转发、评论这三种交互行为 ### 1. 涨指标方法——召回 召回模型 & 召回通道 * 推荐系统有几十条召回通道,它们的召回总量是固定的。总量越大,指标越好,粗排计算量越大 * 双塔模型和item-to-item是最重要的两类召回模型,占据召回的大部分配额 * 有很多小众的模型,占据的配额很少。在召回总量不变的前提下,添加某些召回模型可以提升核心指标 * 有很多内容池,比如30天物品、一天物品、6小时物品、新用户优质内容池、分人群内容池 * 同一个模型可以用于多个内容池,得到多条召回通道 #### 1)改进双塔模型 ##### 方向1:优化正样本、负样本 * 简单正样本:有点击的(用户、物品)二元组 * 简单负样本:随机组合的(用户、物品)二元组 * 困难负样本:排序靠后的(用户、物品)二元组 ##### 方向2:改进神经网络结构 * Baseline:用户塔、物品塔分别是全连接网络,各输出一个向量,分别作为用户、物品的表征。 * 改进:用户塔、物品塔分别用DCN代替全连接网络 * 改进:在用户塔中使用用户行为序列(last-n) * 改进:使用多向量模型代替单向量模型(标准的双塔模型也叫单向量模型) ##### 方向3:改进模型的训练方法 * Baseline:做二分类,让模型学会区分正样本和负样本 * 改进:结合二分类、batch内负采样(对于batch内负采样,需要做纠偏) * 改进:使用自监督学习方法,让冷门物品的embedding学得更好 #### 2)Item-to-Item(I2I) I2I是一大类模型,基于相似物品做召回 U2I2I 如何计算物品相似度? * 方法1:ItemCF及其变体 * 一些用户同时喜欢物品i1和i2,则认为i1和i2相似 * ItemCF、Online ItemCF、Swing、Online Swing都是基于相同的思想 * 线上同时使用上述4种I2I模型,各分配一定的配额 * 基于物品向量表征,计算向量相似度(双塔模型、图神经网络均可计算物品向量表征) U2U2I (user->user->item) U2A2I (user->author->item) U2A2A2I (user->author->author->item) ### 2. 涨指标的方法——排序模型 #### 1)精排模型的改进 ![image-20250216213127699](images/base.png) **精排模型:基座** * 基座的输入包括离散特征和连续特征,输出一个向量,作为多目标预估的输入 * 改进1:基座加宽加深,计算量更大,预测更准确 * 改进2:做自动的特征交叉,比如bilinear和LHUC * 改进3:特征工程,比如添加统计特征、多模态内容特征 **精排模型:多目标预估** * 基于基座输出的向量,同时预估点击率等多个目标 * 改进1:增加新的预估目标,并把预估结果加入融合公式 * 改进2:MMoE、PLE等结构可能有效,但往往无效 * 改进3:纠正position bias可能有效,也可能无效 #### 2)粗排模型的改进 * 粗排的打分量比精排大10倍,因此粗排模型必须够快 * 简单模型:多向量双塔模型,同时预估点击率等多个目标 * 复杂模型:三塔模型效果好,但工程实现难度较大 ##### 粗精排一致性建模 * 蒸馏精排训练粗排,让粗排与精排更一致 * 方法1:pointwise蒸馏 * 方法2:pairwise或listwise蒸馏 * 给定k个候选物品,按照精排预估做排序 * 做learning to rank(LTR),让粗排拟合物品的序 * 例如: * 对于物品i和j,精排预估点击率为pi>pj * LTR鼓励粗排预估点击率满足qi>qj,否则有惩罚 * LTR通常使用pairwise logistic loss * 优点:粗精排一致性建模可以提升核心指标 * 缺点:如果精排出bug,精排预估值p有偏,会污染粗排训练数据 ### 3. 涨指标的方法——用户行为序列建模 * 最简单的方法是对物品向量取平均,作为一种用户特征 * DIN使用注意力机制,对物品向量做加权平均 * 工业界目前沿用着SIM的方向发展。先用类目等属性筛选物品,然后用DIN对物品向量做加权平均 * 改进1:增加序列长度,让预测更准确,但是会增加计算成本和推理时间 * 改进2:筛选的方法,比如用类目、物品向量表征聚类 * 离线用多模态神经网络提取物品内容特征,将物品表征为向量 * 离线将物品向量聚为1000类,每个物品有一个聚类序号 * 线上排序时,用户行为序列中有n=1000000个物品。某候选物品的聚类序号是70,对n个物品做筛选,只保留聚类序号为70的物品。n个物品中只有数千个被保留下来 * 同时有好几种筛选方法,取筛选结果的并集 * 改进3:对用户行为序列中的物品,使用ID以外的一些特征 * 概括:沿着SIM的方向发展,让原始的序列尽量长,然后做筛选降低序列长度,最后将筛选结果输入DIN ### 4. 涨指标的方法——在线学习(增量更新) * 线上有m个模型,其中1个是holdout,1个事推全的模型,m-2个测试的新模型 * 每套在线学习的机器成本都很大,因此m数量很小,制约模型开发迭代的效率 * 在线学习对指标的提升巨大,但是会制约模型开发迭代的效率 ### 5. 涨指标的方法——老汤模型 * 用每天新产生的数据对模型做1epoch的训练 * 久而久之,老模型训练得非常好,很难被超过 * 对模型做改进,重新训练,很难追上老模型... * 问题1:如何快速判断新模型结构是否优于老模型?(不需要追上线上的老模型,只需要判断新老模型谁的结构更优) * 对于新、老模型结构,都随机初始化模型全连接层 * Embedding层可以是随机初始化,也可以是复用老模型训练好的参数 * 用n天的数据训练新老模型(从旧到新,训练1epoch) * 如果新模型显著优于老模型,新模型很可能更优 * 只是比较新老模型结构谁更好,而非真正追平老模型 * 问题2:如何更快追平、超过线上的老模型?(只有几十天的数据,新模型就能追上训练上百天的老模型) * 方法1:尽可能多地复用老模型训练好的Embedding层,避免随机初始化embedding层。(Embedding层是对用户、物品特点的“记忆”,比全连接层学得慢) * 方法2:用老模型做teacher,蒸馏新模型。(用户真实行为是y,老模型的预测是p,用$\frac{y+p}{2}$作为训练新模型的目标) ### 6. 涨指标的方法——提升多样性 #### 粗排+精排 * 常用MMR、DPP等方法计算多样性分数,精排使用滑动窗口,粗排不使用滑动窗口 * 精排决定最终曝光,曝光页面上邻近的物品相似度应该小,所以计算精排多样性要使用滑动窗口 * 粗排要考虑整体的多样性,而非一个滑动窗口中的多样性 * 除了多样性分数,精排还使用打散策略增加多样性 * 类目:当前选中物品i,之后5个位置不允许跟i的二级类目相同 * 多模态:事先计算物品多模态内容向量表征,将全库物品聚为1000类;在精排阶段,如果当前选中物品i,之后10个位置不允许跟i同属一个聚类 #### 召回 ##### 双塔模型:添加噪声 * 用户塔将用户特征作为输入,输出用户的向量表征;然后做ANN检索,召回向量相似度高的物品 * 线上做召回时(在计算出用户向量之后,在做ANN检索之前),往用户向量中添加随机噪声 * 用户的兴趣越窄(比如用户最近交互的n个物品只覆盖少数几个类目),则添加的噪声越强 * 添加噪声使得召回的物品更多样,可以提升推荐系统核心指标 ##### 双塔模型:抽样用户行为序列 * 用户最近交互的n个物品(用户行为序列)是用户塔的输入 * 保留最近的r个物品(r<item->item)中的第一个item是指用户最近交互的n个物品之一,在U2I2I中叫作种子物品 * n个物品覆盖的类目数较少,且类目不平衡 * 做非均匀随机抽样,从n个物品中选出t个,让类目平衡 * 用抽样得到的t个物品(代替原本的n个物品)作为U2I2I的种子物品 * 一方面,类目更平衡,多样性更好。另一方面,n可以更大,覆盖的类目更多 ##### 流量探索 * 每个用户曝光的物品中有2%是非个性化的,用作兴趣探索 * 维护一个精选内容池,其中物品均为交互率指标高的优质物品。(内容池可以分人群,比如30-40岁男性内容池) * 从精选内容池中随机抽样几个物品,跳过排序,直接插入最终排序结果 * 兴趣探索在短期内负向影响核心指标,但长期会产生正向影响 ### 7. 涨指标的方法——特殊对待特殊人群 1. 新用户、低活用户的行为很少,个性化推荐不准确 2. 新用户、低活用户容易流失,要想办法促使他们留存 3. 特殊用户的行为(比如点击率、交互率)不同于主流用户,基于全体用户行为训练出的模型在特殊用户人群上有偏 方法: 1. 构造特殊内容池,用于特殊用户人群的召回 * 根据物品获得的交互次数、交互率选择优质物品 * 做因果推断,判断物品对人群留存率的贡献,根据贡献值选物品 2. 使用特殊排序策略,保护特殊用户 * 大模型+小模型 * 融合多个experts,类似MMoE * 大模型预估之后,用小模型做校准 3. 使用特殊的排序模型,消除模型预估的偏差 ### 8. 涨指标的方法——利用交互行为 #### 关注量对留存的价值 * 对于一位用户,他关注的作者越多,则平台对他的吸引力越强 * 用户留存率(r)与他关注的作者数量(f)正相关 如何利用关注关系提升用户留存? * 方法1:用排序策略提升关注量 * 对于用户u,模型预估候选物品i的关注率为pi * 设用户u已经关注了f个作者 * 我们定义单调递减函数w(f),用户已经关注的作者越多,则w(f)越小 * 在排序融分公式中添加w(f)*pi,用于促关注。(如果f小且pi大,则w(f)\*pi给物品带来很大加分) * 方法2:构造促关注内容池和召回通道 * 这个内容池中物品的关注率高,可以促关注 * 如果用户关注的作者数f较小,则对该用户使用该内容池 * 召回配额可以固定,也可以与f负相关 #### 关注量(粉丝数)对发布的价值 * 用排序策略帮助低粉新作者涨粉 * 某作者a的粉丝数为$f_a$ * 作者a发布的物品i可能被推荐给用户u,模型预估关注率为$p_{ui}$ * 我们定义单调递减函数$w(f_a)$作为权重;作者a的粉丝越多,则$w(f_a)$越小 #### 隐式关注关系 * 召回通道U2A2I: user->author->item * 显式关注关系:用户u关注了作者a,将a发布的物品推荐给u * 隐式关注关系:用户u喜欢看作者a发布的物品,但是u没有关注a * 隐式关注的作者数量远大于显式关注。挖掘隐式关注关系,构造U2A2I召回通道,可以提升推荐系统核心指标。 #### 促转发(分享回流) KOL建模 * 目标:在不损害点击和其他交互的前提下,尽量多吸引站外流量 * 什么样的用户的转发可以吸引大量站外流量? * 答案:其他平台的Key Opinion Leader(KOL) * 用户u是我们站内的KOL,但他不是其他平台的KOL,他的转发价值大吗? * 用户v在我们站内没有粉丝,但他是其他平台的KOL,他的转发价值大吗? * 如何判断本平台的用户是不是其他平台的KOL? * 该用户历史上的转发能带来多少站外流量 * 识别出的站外KOL之后,该如何用于排序和召回? * 方法1:排序融分公式中添加额外的一项$k_u \cdot p_{ui}$,KOL的$k_u$较高 * 方法2:构造促转发内容池和召回通道,对站外KOL生效 #### 评论促发布 * UGC平台将作者发布量、发布率作为核心指标,希望作者发布 * 关注、评论等交互可以提升作者发布积极性 * 如果新发布物品尚未获得很多评论,则给预估评论率提权,让物品尽快获得评论 * 排序融分公式中添加额外的一项$w_i \cdot p_i$ * $w_i$:权重,与物品i已有的评论数量负相关 * $p_i$:为用户推荐物品i,模型预估的评论率 #### 评论的留存价值 * 有的用户喜欢留评论,喜欢跟作者、评论区用户互动 * 给这样的用户添加促评论的内容池,让他们更多机会参与讨论 * 有利于提升这些用户的留存 * 有的用户常留高质量评论(评论的点赞量高) * 高质量评论对作者、其他用户的留存有贡献。(作者、其他用户觉得这样的评论有趣或者有帮助) * 用排序和召回策略鼓励这些用户多留评论