欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家!
LinkedIn Feed 排名
1. 问题陈述
设计一个个性化的LinkedIn Feed,以最大化用户的长期参与度。衡量参与度的一种方法是用户频率,即每个用户的参与次数,但在实践中这非常困难。另一种方法是衡量点击概率或点击率(CTR)。
在LinkedIn这样的社交媒体平台上,“Feed”指的是向用户显示的内容的不断更新的流。
在LinkedIn Feed上,有五种主要的活动类型:
- 连接
- 信息
- 个人资料
- 观点
- 特定站点
直观上,不同的活动有非常不同的点击率。这在构建模型和生成训练数据时非常重要。
类别 | 示例 |
---|---|
连接 | 成员连接、关注成员/公司、成员加入群组 |
信息 | 成员或公司分享文章/图片/消息 |
个人资料 | 成员更新个人资料,例如照片、职位变动等 |
观点 | 成员点赞或评论文章、图片、职位变动等 |
特定站点 | LinkedIn特有的活动,例如成员为成员点赞等 |
2. 指标设计和要求
指标
离线指标
-
点击率 (CTR):Feed收到的点击次数除以Feed显示的次数。
-
公式:
C T R = 点击次数 显示次数 CTR = \frac{\text{点击次数}}{\text{显示次数}} CTR=显示次数点击次数
-
-
最大化CTR可以形式化为训练一个有监督的二分类模型。对于离线指标,我们归一化交叉熵和AUC。
-
归一化交叉熵 (NCE):帮助模型对背景CTR不太敏感。
- 公式:
N C E = − 1 N ∑ i = 1 n ( 1 + y i 2 log ( p i ) + 1 − y i 2 log ( 1 − p i ) ) − ( p log ( p ) + ( 1 − p ) log ( 1 − p ) ) NCE = \frac{-\frac{1}{N} \sum\limits_{i=1}^{n} \left( \frac{1 + y_i}{2} \log(p_i) + \frac{1 - y_i}{2} \log(1 - p_i) \right)}{ - \left( p \log(p) + (1 - p) \log(1 - p) \right)} NCE=−(plog(p)+(1−p)log(1−p))−N1i=1∑n(21+yilog(pi)+21−yilog(1−pi))
N:样本总数。
y i y_i yi:第 ( i ) 个样本的实际标签。如果项目被点击,则 ( y_i ) 为 1,否则为 0。
p i p_i pi:第 ( i ) 个项目被点击的预测概率。
归一化项:
− ( p log ( p ) + ( 1 − p ) log ( 1 − p ) ) - \left( p \log(p) + (1 - p) \log(1 - p) \right) −(plog(p)+(1−p)log(1−p))
p p p:背景CTR(项目被点击的平均概率)。
这个项是具有平均值 p p p 的伯努利分布的熵。它规范了交叉熵损失,以考虑点击的固有可能性(背景CTR)。
交叉熵归一化:
- 确保模型的性能不受固有点击率高或低的项目的过度影响。
- 使模型在不同类型的项目上更加健壮和通用。
AUC:
- 提供一个全面的指标来评估模型区分点击和未点击项目的能力。
- 对于点击次数可能远小于未点击次数的不平衡数据集特别有用。
背景CTR指的是在数据集中或特定数据子集中观察到的平均点击率(CTR)。它反映了所有项目在不考虑各个项目特征的情况下的固有点击可能性。例如,如果平台的总体CTR为0.02,这意味着平均有2%的显示项目被点击。
在线指标
- 对于非平稳数据,离线指标通常不是性能的良好指标。在线指标需要反映模型部署后用户的参与度,即转化率(点击次数与Feed数量的比率)。
要求
训练
- 处理大量数据:理想情况下,模型在分布式环境中进行训练。
- 在线数据分布变化:每天多次增量地重新训练模型,以应对数据分布的变化。
- 个性化:支持高度个性化,因为不同用户对Feed的消费方式和风格不同。
- 数据新鲜度:避免在用户的主页Feed上显示重复的Feed。
推断
- 可扩展性:处理大量用户活动并支持3亿用户。
- 延迟:Feed排名需要在50毫秒内返回,整个过程在200毫秒内完成。
- 数据新鲜度:确保Feed排名知道用户是否已经看到某个特定活动,以避免显示重复的活动。
总结
类型 | 期望目标 |
---|---|
指标 | 合理的归一化交叉熵 |
训练 | 高吞吐量,能够每天多次重新训练 |
支持高度个性化 | |
推断 | 延迟从100毫秒到200毫秒 |
提供高水平的数据新鲜度,避免多次显示相同的Feed |
3. 模型
特征工程
特征 | 特征工程 | 描述 |
---|---|---|
用户档案:职位、行业、人口统计等 | 低基数:使用独热编码。高基数:使用嵌入。 | |
用户之间的连接强度 | 由用户之间的相似性表示。我们还可以使用嵌入来表示用户,并测量距离向量。 | |
活动年龄 | 根据点击目标的敏感度,将其视为连续特征或分箱值。 | |
活动特征: | 活动类型、标签、媒体等。使用活动嵌入并测量活动与用户之间的相似性。 | |
交叉特征 | 组合多个特征。 |
用户档案:对人口统计进行独热编码,因为它的基数较低(例如,年龄组)。由于可能存在高基数(许多唯一的职位和行业),对职位和行业进行嵌入。
用户之间的连接强度:例如,如果用户A经常与用户B互动(点赞帖子、评论、消息),则连接强度较高。
活动年龄:例如,活动的年龄(例如帖子或更新)可以表示为自创建以来的天数。如果点击行为对活动的新鲜度敏感,则可以将其视为连续变量。或者,可以将其分箱为“少于一天”,“1-3天”,“4-7天”等,以简化模型。示例:一个帖子创建于2天前。特征工程:1. 将年龄视为连续特征:年龄=2 2. 或者,将年龄分箱:年龄箱=“1-3天”。
活动特征:例如,活动可以包括分享文章、更新个人资料图片或点赞帖子。每种活动类型都可以嵌入到一个向量空间中。如果用户经常参与与“数据科学”相关的文章,可以使用这些嵌入来衡量新数据科学相关活动与用户兴趣的相似性。
交叉特征:交叉特征是多个基本特征的组合,以捕获它们之间的交互。例如,结合“用户行业”和“活动类型”,以查看技术行业的用户是否比其他行业更喜欢信息活动(如文章分享)。
训练数据
在构建任何机器学习模型之前,我们需要收集训练数据。目标是收集不同类型帖子的数据,同时改善用户体验。以下是我们可以收集训练数据的一些方法:
- 按时间顺序排名:此方法按时间顺序对每个帖子进行排名。使用这种方法收集点击/未点击数据。这里的权衡是用户对前几个帖子的关注导致的服务偏差。此外,由于不同的活动(如职位变动)相比于LinkedIn上的其他活动很少发生,因此存在数据稀疏问题。
- 随机呈现:此方法按随机顺序对帖子进行排名。这可能会导致糟糕的用户体验。它也无法解决稀疏性问题,因为缺乏有关稀有活动的训练数据。
- 使用Feed排名算法:这将对前几个Feed进行排名。在顶部Feed中,你可以随机排列。然后,使用点击数据进行数据收集。这种方法提供了一些随机性,有助于模型学习和探索更多活动。
基于此分析,我们将使用算法生成训练数据,以便后续训练机器学习模型。
我们可以通过选择一段数据时间来开始使用数据进行训练:上个月、过去6个月等。在实践中,我们希望在训练时间和模型准确性之间找到平衡。我们还对负面数据进行下采样以处理不平衡数据。
模型选择
我们可以使用概率稀疏线性分类器(逻辑回归)。由于其计算效率高,这是一种流行的方法,适用于稀疏特征。
由于数据量大,我们需要使用分布式训练:Spark中的逻辑回归或交替方向乘子法(ADMM)。
我们也可以在分布式环境中使用深度学习。我们可以从全连接层开始,在最终层应用Sigmoid激活函数。由于CTR通常非常小(小于1%),我们需要重新采样训练数据集以使数据不那么不平衡。重要的是保持验证集和测试集不变,以准确估计模型性能。
逻辑回归可以有效处理稀疏向量,因为它只需要计算非零特征的加权和。
为什么逻辑回归是线性分类器
线性决策边界
特征的线性组合
逻辑回归使用输入特征的线性组合进行预测。这意味着输入特征与结果的对数几率之间的关系是线性的。
决策边界
决策边界是在特征空间中的直线(或更高维空间中的超平面),分隔不同的类别。
Apache Spark:Spark是一种强大的大数据处理和机器学习工具。它支持分布式计算,这意味着它可以通过在机器集群上分发数据和计算来处理大数据集。Spark中的逻辑回归:Spark的MLlib库包括可以分布式运行的逻辑回归实现。这使得在非常大的数据集上进行高效训练成为可能。
交替方向乘子法(ADMM):这是一种用于通过将复杂问题分解为更小的子问题来解决复杂问题的优化算法。每个子问题都可以独立解决,使ADMM适用于分布式计算环境。逻辑回归中的应用:ADMM可以用于并行优化逻辑回归模型参数,提高效率和可扩展性。
保持验证集和测试集不变意味着在对训练数据进行更改(如重新采样以解决类别不平衡)时不应修改这些数据集。以下是对其含义及其重要性的详细解释:
评估
一种方法是将数据分为训练数据和验证数据。另一种方法是重放评估以避免偏差的离线评估。我们使用直到时间 t t t 的数据来训练模型。我们使用时间 t + 1 t+1 t+1 的测试数据,并在推断过程中根据我们的模型重新排序它们的排名。如果在正确位置有准确的点击预测,则记录匹配。总匹配数将视为总点击数。
在评估期间,我们还将评估我们的训练数据集应有多大,以及我们应多频繁地重新训练模型,以及许多其他超参数。
重放评估是一种通过使用历史数据模拟模型在现实世界场景中的表现来评估模型性能的方法。使用过去的数据评估模型,将历史互动视为实时发生。通过使用历史数据模拟实时预测,重放评估提供了模型在生产中的性能的更准确衡量。
位置匹配:意味着模型根据其预测的点击概率最高(或其他特定排名)的项目与用户实际点击的项目相同。
4. 计算与估计
假设
- 3亿月活跃用户
- 平均每个用户每次访问看到40个活动。每个用户每月访问10次。
- 我们有 12 ∗ 1 0 10 12 * 10^{10} 12∗1010 或1200亿次观察/样本。
数据大小
- 假设点击率约为1%(1个月)。我们收集了10亿个正标签和约1100亿个负标签。这是一个巨大的数据集。
- 通常,我们可以假设对于每个数据点,我们收集数百个特征。为了简化,每行存储需要500字节。
- 在一个月内,我们需要1200亿行。总大小: 500 ∗ 120 ∗ 1 0 9 = 60 ∗ 1 0 12 500 * 120 * 10^{9} = 60 * 10^{12} 500∗120∗109=60∗1012 字节 = 60 TB。为了节省成本,我们可以在数据湖中保留最近6个月或1年的数据,并将旧数据存档在冷存储中。
规模
- 支持3亿用户
5. 高级设计
Feed 排序高级设计
-
特征存储 是特征值存储。在推理过程中,我们需要低延迟(<10ms)访问特征值以进行评分。特征存储的示例包括 MySQL Cluster、Redis 和 DynamoDB。
-
项目存储 存储用户生成的所有活动。它还存储相应用户的模型。一个目标是保持一致的用户体验,即对任何特定用户使用相同的 Feed 排序方法。项目存储为相应用户提供正确的模型。
让我们检查系统的流程:
-
客户端向应用服务器发送 Feed 请求
-
应用服务器向 Feed 检索服务发送 Feed 请求
-
Feed 检索服务从项目存储中选择最相关的 Feed
-
Feed 检索服务向 Feed 排序服务发送 Feed 排序请求
-
Feed 排序服务获取最新的机器学习模型,从特征存储中获取正确的特征
-
Feed 排序服务为每个 Feed 打分并返回给 Feed 检索服务和应用服务器。应用服务器按排名对 Feed 进行排序并返回给客户端
系统流程
- 用户访问 LinkedIn 首页并向应用服务器请求 Feed。应用服务器向 Feed 服务发送 Feed 请求。
- Feed 服务从模型库获取最新模型,从特征存储中获取正确的特征,并从项目存储中获取所有 Feed。Feed 服务将为模型提供特征以获取预测。
- 模型返回按点击率可能性排序的推荐 Feed。
6. 扩展设计
- 扩展 Feed 服务模块,因为它代表了检索服务和排序服务。这提供了更好的可视化。
- 扩展应用服务器,并在应用服务器前放置负载均衡器以平衡负载。
7. 总结
- 我们学习了如何构建机器学习模型来排序 Feed。具有自定义损失函数的二元分类模型可以使模型对背景点击率不太敏感。
- 我们学习了如何创建生成机器学习模型训练数据的流程。
- 我们学习了如何通过扩展应用服务器和 Feed 服务来扩展训练和推理。
附录
逻辑回归数值示例
假设一个简单的逻辑回归模型,具有以下权重( θ \theta θ)和输入特征( x x x):
- 权重: θ = [ θ 0 , θ 1 , θ 2 , θ 3 , θ 4 ] \theta = [\theta_0, \theta_1, \theta_2, \theta_3, \theta_4] θ=[θ0,θ1,θ2,θ3,θ4]
- 特征向量: x = [ 1 , 0 , 0 , 3 , 0 ] x = [1, 0, 0, 3, 0] x=[1,0,0,3,0]
这里, θ 0 \theta_0 θ0 是截距项,其他 θ i \theta_i θi 值是特征的权重。特征向量 x x x 是稀疏的,具有许多零值。
逻辑回归计算
逻辑回归模型计算线性组合 z z z 如下:
z = θ 0 × 1 + θ 1 × x 1 + θ 2 × x 2 + θ 3 × x 3 + θ 4 × x 4 z = \theta_0 \times 1 + \theta_1 \times x_1 + \theta_2 \times x_2 + \theta_3 \times x_3 + \theta_4 \times x_4 z=θ0×1+θ1×x1+θ2×x2+θ3×x3+θ4×x4
将我们的示例中的值代入:
z = θ 0 × 1 + θ 1 × 0 + θ 2 × 0 + θ 3 × 3 + θ 4 × 0 z = \theta_0 \times 1 + \theta_1 \times 0 + \theta_2 \times 0 + \theta_3 \times 3 + \theta_4 \times 0 z=θ0×1+θ1×0+θ2×0+θ3×3+θ4×0
简化计算
因为任何数乘以零都为零,我们可以忽略特征值为零的项:
z = θ 0 × 1 + θ 3 × 3 z = \theta_0 \times 1 + \theta_3 \times 3 z=θ0×1+θ3×3
因此,计算简化为:
z = θ 0 + 3 θ 3 z = \theta_0 + 3\theta_3 z=θ0+3θ3
参考资料:
- Machine learning System Design from educative