# 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内负样本
* 困难负样本:被召回,但是被排序淘汰
* 错误:曝光、但是未点击的物品做召回的负样本

#### 线上召回
#### 离线存储:把物品向量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,供用户塔在线上计算用户向量

#### 问题:能否只做增量更新,不做全量更新?
* 小时级数据有偏;分钟级数据偏差更大
* 全量更新: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之间的整数

* 曝光物品集合大小为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. 多目标排序模型


#### 训练
* 困难:类别不平衡
* 每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)
将神经网络输出的向量做加权平均,然后用该向量去评估某个业务指标。


#### 极化现象
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 视频
* 图文笔记排序的主要依据:
点击、点赞、收藏、转发、评论......
* 视频排序的依据还有播放时长和完播
* 直接用回归拟合播放时长效果不好

#### 视频播放时长建模
* 把最后一个全连接层的输出记作$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)?

* 线上预估完播率,然后做调整:
$$
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不能获得用户地理定位,因此场景特征有缺失
* 提高特征覆盖率,可以让精排模型更准

## 粗排
| 粗排 | 精排 |
| ------------------ | ---------------- |
| 给几千篇笔记打分 | 给几百篇笔记打分 |
| 单次推理代价必须小 | 单次推理代价很大 |
| 预估的准确性不高 | 预估的准确性更高 |
#### 精排模型
* 前期融合:先对所有特征做concatenation,再输入神经网络
* 线上推理代价大:如果有n篇候选笔记,整个大模型要做n次推理
#### 双塔模型
* 后期融合:把用户、物品特征分别输入不同的神经网络,不对用户、物品特征做融合。
* 线上计算量小:
* 用户塔只需要做一次线上推理,计算用户表征a。
* 物品表征b事先存储在向量数据库中,物品塔在线上不做推理。
* 预估准确性不如精排模型。
### 1. 粗排的三塔模型


模型上层(全连接层+sigmoid)
* 有n个物品,模型上层需要做n次推理
* 粗排推理的大部分计算量在模型上层
#### 三塔模型的推理
* 从多个数据源取特征:
* 1个用户的画像、统计特征
* n个物品的画像、统计特征
* 用户塔:只做1次推理
* 物品塔:未命中缓存时需要做推理
* 交叉塔:必须做n次推理
* 上层网络做n次推理,给n个物品打分
## 交叉结构(Crossing)
### 1. Factorized Machine(FM)

* FM是线性模型的替代品,能用线性回归、逻辑回归的场景,都可以用FM。
* FM使用二阶交叉特征,表达能力比线性模型更强。
* 通过做近似$u_{ij}\approx v_i^Tv_j$,FM把二阶交叉权重的数量从$O(d^2)$降低到$O(kd)$
### 2. 深度交叉网络(DCN)
交叉层(Cross Layer)

交叉网络(Cross Network)

深度交叉网络(Deep & Cross Network)

### 3. LHUC网络结构
* LHUC(Learning Hidden Unit Contributions)起源于语音识别
* 快手将LHUC应用在推荐精排,称作PPNet

这里的神经网络都是【多个全连接层】-> 【Sigmoid X 2】
### 4. SENet & Bilinear Cross -> FiBiNet


#### SENet
* SENet对离散特征做field-wise加权
* Field:
* 用户ID Embedding是64维向量
* 64个元素算一个field,获得相同的权重
* 如果有m个fields,那么权重向量是m维
#### Field间特征交叉
* 向量内积(维度必须相同)
* 哈达玛乘积(维度必须相同)
* Bilinear cross(维度可以不同)


---
## 用户行为序列建模
### LastN特征
* LastN:用户最近的n次交互(点击、点赞等)的物品ID
* 对LastN物品ID做embedding,得到n个向量
* 把n个向量取平均,作为用户的一种特征
* 适用于召回双塔模型、粗排三塔模型、精排模型

### 1. DIN模型(精排)
* DIN用加权平均代替平均,即注意力机制。
* 权重:候选物品与用户LastN物品的相似度。

* 对于某候选物品,计算它与用户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
#### 基于图文内容的物品表征

* CLIP是当前公认最有效的预训练方法
* 思想:对于图片——文本二元组,预测图文是否匹配
* 优势:无需人工标注。
* 负样本:batch内负样本
### 2. 提升多样性的方法(让曝光的物品尽量不相似)
* 给定n个候选物品,**排序模型**打分
$$
reward_1,...,reward_n
$$
* **后处理:**从n个候选物品中选出k个,既要它们的总分高,也需要它们有多样性
* 精排后处理称为**重排**
#### 1)Maximal Marginal Relevance(MMR)

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$

#### 重排的规则(规则优先级高于多样性算法)
##### 规则:最多连续出现k篇某种笔记
* 小红书推荐系统的物品分为图文笔记、视频笔记
##### 规则:每k篇笔记最多出现1篇某种笔记(运营推广笔记)
##### 规则:前t篇笔记最多出现k篇某种笔记
* 排名前t篇笔记最容易被看到,对用户体验最重要
* 小红书推荐系统有带电商卡片的笔记,过多可能会影响体验
#### MMR + 重排规则
* MMR每一轮选出一个物品
* 重排结合MMR与规则,在满足规则的前提下最大化MR
* 每一轮先用规则排除掉$R$中的物品,得到子集$R'$
* MMR公式中的$R$替换成子集$R'$,选中的物品符合规则
#### 2)DPP
##### 数学基础
多样性越好,体积越大,而行列式和体积平方等价,所以可以用行列式来衡量多样性




##### 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篇新笔记


##### <种子笔记,正样本>
方法一:人工标注二元组的相似度
方法二:算法自动选正样本
* 筛选条件:
* 只用高曝光笔记作为二元组(因为有充足的用户交互信息)
* 两篇笔记有相同的二级类目,比如都是“菜谱教程”
* 用ItemCF的物品相似度来选正样本
##### <种子笔记,负样本>
从全体笔记中**随机选出**满足条件的:
* 字数较多(神经网络提取的文本信息有效)
* 笔记质量高,避免图文无关
##### 聚类召回总结
* 基本思想:根据用户的点赞、收藏、转发记录、推荐内容相似的笔记
* 线下训练:多模态神经网络把图文内容映射到向量
* 线上服务:
用户喜欢的笔记 -> 特征向量 -> 最近的Cluster -> 新笔记
#### 4)Look-Alike人群扩散召回
* 点击、点赞、收藏、转发——用户对笔记可能感兴趣
* 把有交互的用户作为新笔记的种子用户
* 用look-alike在相似用户中扩散
新笔记对应一个**特征向量**,他是**有交互的用户**的向量的**平均**。每当有用户交互该物品,更新笔记的特征向量。
线上召回时将用户向量作为query,寻找最近邻的特征向量对应的笔记
### 4. 冷启动——流量调控
#### 扶持新笔记的目的
目的1:促进发布,增大内容池
* 新笔记获得的曝光越多,作者创作积极性越高
* 反映在发布渗透率、人均发布量
目的2:挖掘优质笔记
* 做探索,让每篇新笔记都能获得足够曝光
* 挖掘的能力反映在高热笔记占比
#### 流量调控技术的发展
1. 在推荐结果中强插新笔记
2. 对新笔记的排序分数做提权(boost)
3. 通过提权,对新笔记做保量
4. 差异化保量(依据内容好坏)
#### 新笔记提权
干涉**粗排**、**重排**环节,给新笔记提权
优点:容易实现,投入产出比好
缺点:
* 曝光量对提权系数很敏感
* 很难精确控制曝光量,容易过度曝光和不充分曝光
#### 新笔记保量
* 保量:不论笔记质量高低,都保证24小时获得100次曝光
* 在原有提权系数的基础上,乘以额外的提权系数

保量的难点:
**保量的成功率远低于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)精排模型的改进

**精排模型:基座**
* 基座的输入包括离散特征和连续特征,输出一个向量,作为多目标预估的输入
* 改进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,模型预估的评论率
#### 评论的留存价值
* 有的用户喜欢留评论,喜欢跟作者、评论区用户互动
* 给这样的用户添加促评论的内容池,让他们更多机会参与讨论
* 有利于提升这些用户的留存
* 有的用户常留高质量评论(评论的点赞量高)
* 高质量评论对作者、其他用户的留存有贡献。(作者、其他用户觉得这样的评论有趣或者有帮助)
* 用排序和召回策略鼓励这些用户多留评论