深度学习笔记: 最详尽LinkedIn Feed 排名系统设计

欢迎收藏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)+(1p)log(1p))N1i=1n(21+yilog(pi)+21yilog(1pi))

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)+(1p)log(1p))

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天”。

活动特征:例如,活动可以包括分享文章、更新个人资料图片或点赞帖子。每种活动类型都可以嵌入到一个向量空间中。如果用户经常参与与“数据科学”相关的文章,可以使用这些嵌入来衡量新数据科学相关活动与用户兴趣的相似性。

交叉特征:交叉特征是多个基本特征的组合,以捕获它们之间的交互。例如,结合“用户行业”和“活动类型”,以查看技术行业的用户是否比其他行业更喜欢信息活动(如文章分享)。

训练数据

在构建任何机器学习模型之前,我们需要收集训练数据。目标是收集不同类型帖子的数据,同时改善用户体验。以下是我们可以收集训练数据的一些方法:

  1. 按时间顺序排名:此方法按时间顺序对每个帖子进行排名。使用这种方法收集点击/未点击数据。这里的权衡是用户对前几个帖子的关注导致的服务偏差。此外,由于不同的活动(如职位变动)相比于LinkedIn上的其他活动很少发生,因此存在数据稀疏问题。
  2. 随机呈现:此方法按随机顺序对帖子进行排名。这可能会导致糟糕的用户体验。它也无法解决稀疏性问题,因为缺乏有关稀有活动的训练数据。
  3. 使用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} 121010 或1200亿次观察/样本。

数据大小

  • 假设点击率约为1%(1个月)。我们收集了10亿个正标签和约1100亿个负标签。这是一个巨大的数据集。
  • 通常,我们可以假设对于每个数据点,我们收集数百个特征。为了简化,每行存储需要500字节。
  • 在一个月内,我们需要1200亿行。总大小: 500 ∗ 120 ∗ 1 0 9 = 60 ∗ 1 0 12 500 * 120 * 10^{9} = 60 * 10^{12} 500120109=601012 字节 = 60 TB。为了节省成本,我们可以在数据湖中保留最近6个月或1年的数据,并将旧数据存档在冷存储中。

规模

  • 支持3亿用户

5. 高级设计

Feed 排序高级设计

  • 特征存储 是特征值存储。在推理过程中,我们需要低延迟(<10ms)访问特征值以进行评分。特征存储的示例包括 MySQL Cluster、Redis 和 DynamoDB。

  • 项目存储 存储用户生成的所有活动。它还存储相应用户的模型。一个目标是保持一致的用户体验,即对任何特定用户使用相同的 Feed 排序方法。项目存储为相应用户提供正确的模型。

让我们检查系统的流程:

  1. 客户端向应用服务器发送 Feed 请求

  2. 应用服务器向 Feed 检索服务发送 Feed 请求

  3. Feed 检索服务从项目存储中选择最相关的 Feed

  4. Feed 检索服务向 Feed 排序服务发送 Feed 排序请求

  5. Feed 排序服务获取最新的机器学习模型,从特征存储中获取正确的特征

  6. Feed 排序服务为每个 Feed 打分并返回给 Feed 检索服务和应用服务器。应用服务器按排名对 Feed 进行排序并返回给客户端

系统流程
  1. 用户访问 LinkedIn 首页并向应用服务器请求 Feed。应用服务器向 Feed 服务发送 Feed 请求。
  2. Feed 服务从模型库获取最新模型,从特征存储中获取正确的特征,并从项目存储中获取所有 Feed。Feed 服务将为模型提供特征以获取预测。
  3. 模型返回按点击率可能性排序的推荐 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/23578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Typecho:简约而强大的开源PHP博客平台

Typecho&#xff1a;让博客写作回归本质- 精选真开源&#xff0c;释放新价值。 概览 Typecho是一个开源的PHP博客平台&#xff0c;以其简洁的界面和强大的功能&#xff0c;为博客作者提供了一个高效、易于管理的写作环境。它是一个轻量级、高性能的解决方案&#xff0c;适用于…

【WP|9】深入解析WordPress [add_shortcode]函数

add_shortcode 是 WordPress 中一个非常强大的函数&#xff0c;用于创建自定义的短代码&#xff08;shortcodes&#xff09;。短代码是一种简洁的方式&#xff0c;允许用户在内容中插入动态的、可重用的功能。通过 add_shortcode&#xff0c;开发者可以定义自己的短代码&#x…

【MMU】——MMU 相关的 CP15 寄存器

文章目录 MMU 相关的 CP15 寄存器C1(System Control Register)C2(Translation Table Base Control Register)C3(Domain Access Control Register)C5(Data Fault Status Register)C6(Data Fault Address Register)C9C10MMU 相关的 CP15 寄存器 寄存器作用寄存器 C1 中…

前端开发环境:Vue、Element Plus、Axios

目录 1. Vue简介 2. Element Plus简介 3. Axios简介 4. 创建Vue项目 4.1 Node.js安装 4.2 创建Vue项目 4.3 Vue项目的结构 4.4 安装Element-Plus 4.5 安装Axios 4.6 解决跨域问题 5. 应用实例 5.1 创建Vue组件 5.2 配置路由 5.3 配置根组件 5.4 启动前端应用服…

Vue 爷孙组件通讯之:Provide / Inject 详细介绍

背景 在父子组件传递数据时&#xff0c;通常使用的是 props 和 emit&#xff0c;父传子时&#xff0c;使用的是 props&#xff0c;如果是父组件传孙组件时&#xff0c;层层传递非常麻烦。 对于这种情况&#xff0c;我们可以使用一对 provide 和 inject。无论组件层次结构有多深…

在不受支持的 Mac 上安装 macOS Sonoma (OpenCore Legacy Patcher v1.5.0)

在不受支持的 Mac 上安装 macOS Sonoma (OpenCore Legacy Patcher v1.5.0) Install macOS on unsupported Macs 请访问原文链接&#xff1a;https://sysin.org/blog/install-macos-on-unsupported-mac/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主…

【leetcode--30.串联所有单词的子串】

有没有一样喜欢看示例的&#xff0c;&#xff0c;看题目就觉得很难懂。大致就是words要进行排列组合&#xff0c;返回s中所有包含这个排列组合的首标。 顺完逻辑蛮好懂的&#xff0c;应该不算困难题&#xff0c;只是不知道用什么模块实现。 class Solution:def findSubstring…

如何利用Varjo混合现实技术改变飞机维修训练方式

自2017年以来&#xff0c;总部位于休斯顿的HTX实验室一直在推进混合现实技术&#xff0c;与美国空军密切合作&#xff0c;通过其EMPACT平台提供可扩展的沉浸式飞机维护虚拟现实培训。 虚拟和混合现实对维修训练的好处&#xff1a; l 实践技能&#xff1a;提供一个非常接近真实场…

【C++题解】1074 - 小青蛙回来了

问题&#xff1a;1074 - 小青蛙回来了 类型&#xff1a;需要找规律的循环 题目描述&#xff1a; 关于小青蛙爬井的故事&#xff0c;你应该早就听过了&#xff1a;井深10 尺&#xff0c;小青蛙从井底向上爬&#xff0c;每个白天向上爬 3 尺&#xff0c;每个晚上又滑下来 2 尺&…

Java | Leetcode Java题解之第136题只出现一次的数字

题目&#xff1a; 题解&#xff1a; class Solution {public int singleNumber(int[] nums) {int single 0;for (int num : nums) {single ^ num;}return single;} }

App UI 风格,尽显魅力

精妙无比的App UI 风格

Eclipse添加C和C++编译成汇编文件的选项

在miscellaneous中添加assemble listing选项就可以生成汇编文件了

[自学记录09*]Unity Shader:在Unity里渲染一个黑洞

一、前言 记得很久很久以前&#xff0c;在ShaderToy上看过一个黑洞的效果&#xff0c;当时感觉太*8帅了&#xff0c;于是这几天就尝试自己弄了一个。 Gargantua With HDR Bloom (shadertoy.com) 下面是我自己实现的黑洞 可以看到还是略逊一筹&#xff08;感觉略逊百筹&#x…

07-指针的概念与引用,索引

指针的概念与引用&#xff0c;索引 一、内存地址 字节&#xff1a; 定义&#xff1a; 字节&#xff08;byte&#xff09;是内存容量的一个单位&#xff0c;一个字节包含8个位&#xff08;bit&#xff09;。 地址&#xff1a; 定义&#xff1a; 内存地址是系统为了方便区分…

DockerCompose中部署Jenkins(Docker Desktop在windows上数据卷映射)

场景 DockerJenkinsGiteeMaven项目配置jdk、maven、gitee等拉取代码并自动构建以及遇到的那些坑&#xff1a; DockerJenkinsGiteeMaven项目配置jdk、maven、gitee等拉取代码并自动构建以及遇到的那些坑_jenkins的安装以及集成jdkgitmaven 提示警告-CSDN博客 Windows10(家庭版…

c#vb代码互转工具

下载地址&#xff1a; https://download.csdn.net/download/wgxds/88979921

stm32中如何实现EXTI线 0 ~ 15与对应IO口的配置呢?

STM32的EXTI控制器支持19 个外部中断/ 事件请求。每个中断设有状态位&#xff0c;每个中断/ 事件都有独立的触发和屏蔽设置。 STM32的19个外部中断对应着19路中断线&#xff0c;分别是EXTI_Line0-EXTI_Line18&#xff1a; 线0~15&#xff1a;对应外部 IO口的输入中断。 线16&…

【MMU】——ARM 一级页表

文章目录 一级页表项即 entry 的格式如下 从上图可以看出 L1 页表项有四种可能类型 产生中止异常的故障条目。这可能是预取或数据中止、取决于访问类型。这实际上表示虚拟地址未映射 bit[1:0] = 00指向 L2 转换表的条目。这样就能将 1MB 的内存分页 bit[1:0] = 01。1MB 段转换…

STM32远程更新

1 IAP 概述 1.1 工作原理 在应用中编程&#xff08; IAP &#xff09;是一种在现场通过 MCU 的通信接口&#xff08;例如 UART,USB,CAN 和以太网 等&#xff09;进行固件升级的方式。 当启动微控制器时&#xff0c;您可以选择让它进入 IAP 模式以执行 IAP 代码&am…

04-240606Spark笔记

04-240606Spark笔记 1.行动算子-2 save相关算子: 格式: def saveAsTextFile(path: String): Unit def saveAsObjectFile(path: String): Unit def saveAsSequenceFile(path: String,codec: Option[Class[_ <: CompressionCodec]] None): Unit 例子: val rdd sc.makeR…