0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

算法的迭代:从传统CTR预估到LTR

Tensorflowers 来源:TensorFlow 作者:TensorFlow 2020-11-18 17:15 次阅读

前言

在当今互联网世界,推荐系统在内容分发领域扮演着至关重要的角色。如何尽可能的提升推荐系统的推荐效果,是每个推荐算法同学工作的核心目标。在爱奇艺海外推荐业务,引入 TensorFlow Ranking (TFR) 框架,并在此基础上进行了研究和改进,显著提升了推荐效果。本文将分享 TFR 框架在海外推荐业务中的实践和应用。

01 算法的迭代:从传统 CTR 预估到 LTR

长期以来,在推荐系统排序阶段广泛应用的 CTR 预估算法的研究重点在于,如何更加准确的估计一个用户对于一个 item 的点击概率。在这类算法中,我们将一组同时曝光在用户面前的 items,当做一个一个单独的个例看待,将用户的特征、环境特征和一个一个 item 的特征分别组合成为一条条训练数据,将用户对这个 item 的反馈(点击、未点击、播放时长等)作为训练数据的标签。这样看似合理的问题抽象其实并不能准确的表征推荐场景。

严格来讲,排序问题的本质(尤其是以瀑布流形式呈现的业务)并不是研究估计一个用户对于一个单独的 item 的点击概率,而是研究在一组 items 同时曝光的情况下,用户对这组 items 中哪个的点击概率更大的问题。

Learning-To-Rank (LTR) 算法正是为解决这个问题而出现的。LTR 算法在训练时采用 pairwise 或者 listwise 的方式组织训练数据,将一组同时曝光在用户面前的 items,两两 (pairwise) 或者多个 (listwise) items 和用户特征环境特征共同组成数据对,作为一条条的训练数据。相应的,在评估模型的指标上,LTR 算法更多采用 NDCG、ARP、MAP 等能够反映 items 顺序影响的指标。

同时,由于 LTR 算法的这种训练数据组织形式,使得这类算法在用户量相对不大的场景下,更容易取得比较好的效果。同样得益于这种数据组织形式,也很方便的实现更好的负样本采样。

注:关于推荐业务中采样和模型评估指标之间还有一个有趣的研究可以参考,2020 KDD Best Paper Award ,On Sampled Metrics for Item Recommendation

02 框架的设计:TensorFlow Ranking

TensorFlow Ranking (TFR) 是 TensorFlow 官方开发的 LTR 框架,旨在基于 TensorFlow 开发和整合 LTR 相关的技术,使开发人员可以更加方便的进行 LTR 算法的开发。

在实际使用过程中,可以体会到 TFR 框架为我们带来的收益。框架内抽象出了训练中不同层级的类,并开发了相关的 loss 函数,以方便我们进行 pairwise 和 listwise 的训练,同时整合了 arp、ndcg 等模型评估的 metrics,再结合 TensorFlow 高阶 api (Estimator),可以非常方便快捷的进行开发,而不用挣扎于各种实施上的细节。

如上图所示,蓝色框图中是在使用 TensorFlow Estimator 时,model_fn 参数内需要自己设计和开发的算法模型模块。在这个 model_fn 中,需要自行设计模型结构 (Scoring Function),然后用模型计算的 logit 和 label 来计算 Loss 和 Metrics,最后利用 Optimizer 来进行模型的优化。图中,红色虚曲线下方的部分为使用 TFR 框架的整个流程。

从图中可以看出,其实 TFR 框架主要是做了两方面的工作:

把原有 model_fn 中 Scoring Function 和 Loss、Metrics 的计算进行了拆分,然后将原有流程中我们自行实现的 Loss 和 Metrics 替换为 TFR 框架中的 LTR 相关的 Loss 和 Metrics。

为了配合 TFR 框架中的 LTR 相关的 Loss 和 Metrics 来实现 LTR 的训练,训练数据需要以 listwise 的形式组织。但由于需要使用原有 model_fn 中 Scoring Function,在数据输入的部分通过 LTR 框架中的数据转换函数来对模型输入的训练数据进行转化,使得以 listwise 形式组织的数据能够利用 Scoring Function 来计算 logit。

所以,在 TFR 框架中,从数据到模型训练完整的流程是:训练数据-->用户定义 feature_columns-->transform_fn 特征转换-->Scoring Function 计算 score-->ranking_head 的 loss_fn 计算 loss–->ranking_head 的 eval_metric_fns 计算评价指标–->optimizer 进行优化。

从使用层面看,TFR 框架就是做了上面两件事,看起来似乎并不复杂。但是从框架开发的角度上看,为了实现上述流程,TFR 框架内在 losses.py 和 metrics.py 中开发了多个 LTR 相关的 Loss 和 Metrics,在 data.py 内实现了读取和解析以 listwise 形式组织数据的 tfrecords 文件的工具,还在 feature.py 中开发了兼容 TensorFlow 特征转换函数的特征处理工具。最后通过 head.py 和 model.py 中的类对上述功能进行了层层封窗和抽象,并与 TensorFlow Estimator 很好的结合起来。

具体一些来看,代码组织上,TFR 框架主要这样实现的:

第一:

tfr 通过 tfr.model.make_groupwise_ranking_fn 来对 Estimator 的 model_fn 进行了整体的封装。我们原有的基于 TensorFlow 的开发,在 Estimator 的 model_fn 这个参数内需要定义包括 Loss、Metrics 在内的完整的模型函数,但是在tfr这里就不需要了,make_groupwise_ranking_fn 会整体返回一个 Estimator 接收的 model_fn。

第二:

tfr.model.make_groupwise_ranking_fn 函数的第一个参数 group_score_fn,这里是需要传入我们设计和开发的模型结构 (Scoring Function),但是这个模型是之前我们提到的,只需要计算出 logit 的模型。

第三:

tfr.model.make_groupwise_ranking_fn 函数的第三个参数 transform_fn,对应调用 feature.py 中开发了兼容 TensorFlow 特征转换函数来对以 listwise 形式组织的数据(由 data.py 中的工具读取进来的 Dataset)进行转换,确保输入 Scoring Function 的数据格式正确。

第四:

tfr.model.make_groupwise_ranking_fn 函数的第四个参数 ranking_head,对应调用了 tfr.head.create_ranking_head 函数,里面的三个参数分别定义了 loss、metrics 和 optimizer。loss 和 metrics 分别从 TFR 的 losses.py 和 metrics.py 中选择我们需要的,而 optimizer 还是使用 TensorFlow 中的 optimizer。

以上就是 TFR 框架的整体架构,其实这个框架整体设计和代码实现,还是非常优雅和巧妙的。

03 遇到的问题和实践

TFR 框架的精巧设计和实现解决了我们基于 TensorFlow 做 LTR 算法中的 80% 到 90% 的问题。但是作为一个 2019 年才发布第一个版本的框架,TFR 还是存在一些待优化的地方。

在分享 TFR 框架上的实践前,首先介绍一下 TFR 框架的版本情况,目前 TFR 框架发布的版本中,0.1.x 版本支持 TensorFlow 1.X 版本,而 0.2.x 和 0.3.x 版本都只支持 TensorFlow 2.X 版本。考虑到 TensorFlow 2.X 版本还存在一些不确定性(如前段时间爆出使用 Keras 功能 API 创建的模型自定义层中的权重无法进行梯度更新的问题。

(https://github.com/tensorflow/tensorflow/issues/40638),目前大量的算法开发人员其实还在用 TensorFlow 1.X 版本。我们目前也在使用 TensorFlow 1.X 版本,所以本文介绍的内容,描述的问题和给出的解决方案,都是基于 TensorFlow 1.14 版本,对应最新的 TFR 0.1.6 版本。

我们最开始使用 TFR 框架是 2019 年年中的时候,当时 TFR 框架的最新版本是 0.1.3。在使用的过程中,我们发现这个版本无法支持 sparse/embedding features。但是推荐的特征中,稀疏特征是不可或缺的一部分,并且可能大部分特征都是稀疏的,所以我们不得不放弃使用。但是很快,在稍后发布的 0.1.4 版本中这个问题就得到了解决。

我们正式开始使用 TFR 框架是从 0.1.4 版本开始的。但是到目前最新的 0.1.6 版本,还是有两个我们不得不用的特性还是没有在 TFR 0.1.x 版本上得到支持:

训练过程中无法实施正则化

如前所述,TFR 框架通过 make_groupwise_ranking_fn 来对 Estimator 的 model_fn 进行了整体的封装。

我们自己设计和开发的模型 (Scoring Function),定义了网络,输入输出节点,最后只需要输出一个 logit。这个和传统 TensorFlow Estimator 下 model_fn 模型开发不一样,传统的模型不仅仅要输出一个 logit,模型里面还需要定义如何计算 loss,怎样优化等内容。但是 TFR 框架将这部分内容已经进行了封装和整合,所以这里的 score_fn 就不需要这些了。这就带来一个问题,原来的模型设计中,我们可以直接拿出网络中需要正则化的参数,放在 loss 的计算中进行优化就可以了。但是使用 TFR 框架后,由于模型的设计和正向的计算在我们自己设计的模型函数中,而 loss 的计算在 TFR 框架内(ranking_head 中的 loss_fn)进行,这样就没办法加入正则化项了。

已经有人提出了这个issue(https://github.com/tensorflow/ranking/issues/52),但是也没有很好的解决方案。

当我们使用比较复杂的网络时,正则化是我们优化过程中必不可少的一环。不加入正则化项进行优化,将无法避免的陷入到严重的过拟合中,如下图所示:

为了能够方便的利用 TFR 框架其他功能,我们深入 TFR 框架源码中试图解决正则化问题。正如上面分析,TFR 框架无法实施正则化的原因在于,模型 (Scoring Function) 是我们自己设计和开发的,但是 loss 的计算是 TFR 框架帮我们封装好的。所以解决这个问题的核心就是如何在我们自己开发的模型中取出需要正则化的参数并传递给 TFR 框架中计算 loss 的部分就可以了。在 TFR 框架中,我们的模型计算好的 logit,是通过 ranking_head 的 create_estimator_spec 方法,把 logit,labels 与 TFR 框架中定义的 loss 函数整合一起,来完成整个优化过程的。而在 0.1.5 版本的 TFR 框架中,这个 create_estimator_spec 方法其实已经支持传入 regularization_losses 了(估计未来版本一定会支持),而由于初始化 ranking_model 对象(我们的 Scoring Function)。

GroupwiseRankingModel 不支持我们拿到自己模型的正则化项,所以才无法实现。

理论上,只要我们重写 TFR 源码中 _GroupwiseRankingModel 类的 compute_logits 方法,就能够让 TFR 支持正则化了。具体的代码上如何处理可以参考这里(如何解决 TensorFlow Ranking 框架中的正则化问题)。在加入正则化项后,跟上图同样的模型训练时就没有那么严重的过拟合现象了:

特征输入不支持 Sequence Features

前边介绍过,在 TFR 框架中,模型输入的特征分为 context_features 和 example_features,分别对应于一次请求公共的特征(上下文特征、用户特征等)和 item 独有的特征。以 listwise 形式组织的数据(一般是由 data.py 中的工具读取 tfrecords 文件生成的 Dataset)需要经过 TFR 的特征转换函数 (_transform_fn) 转换后,再送入到我们的模型 (Scoring Function) 中。

而目前的特征转换函数 (_transform_fn) 只支持 numeric_column、categorical_column 等经典类型特征的转换,尚不支持 sequence_categorical_column 类型特征的转换。要解决的 TFR 无法支持 SequenceFeatures 问题,主要是对 transform_fn 特征转换这一步进行调整。

在 transform_fn 中,特征转换时用到的 tfr.feature.encode_listwise_features 和 tfr.feature.encode_pointwise_features 函数都在 feature.py 中定义。

这两个函数的作用是在 listwise 或者 pointwise 模式下利用用户定义的 feature columns 生成输入模型的 dense tensors。这两个函数都是调用 encode_features 函数来具体执行 feature columns 生成输入模型的 dense tensors,而 encode_features 函数只支持 numeric_column、categorical_column 等经典类型特征的转换,尚不支持 sequence_categorical_column 类型特征的转换。通过这里的分析,我们可以看到特征转换的过程全部是在 feature.py 中完成的,因此,解决 TFR 框架支持 SequenceFeatures 的问题核心思路就是修改 feature.py 中的几个涉及特征转换的函数,使这些函数能够实现 sequence_categorical_column 类型特征的转换。

我们用到的 sequence_categorical_column 类型特征都在 context_features 中,所以我们的思路是,在处理特征的转换时,我先将 sequence_categorical_column 从其中拿出来,处理完经典特征的转换后,单独增加一段处理 sequence_categorical_column 转换的代码。待转换完成后,再合并回 context_features 中,最终仍然保持 context_features 和 example_features 两部分输入到模型中。具体的代码上如何处理可以参考这里。(让 TensorFlow Ranking 框架支持 SequenceFeatures)

以上两个问题的解决方案都涉及到 TFR 框架对源码的修改。稍有不慎很容易引起稳定性兼容性问题以及意想不到的 bug。为了尽量保障代码的稳定可靠,我们主要考虑了两个主要的代码组织原则:

第一,尽量缩小代码改动的范围,所有的改动都在尽可能少的几个函数内完成,不涉及 TFR 框架的其他模块代码。

第二,对于不涉及上述两个问题的项目要做到完全的兼容。对于不使用 feature columns 的项目或者不使用正则化(应该很少),保证原有逻辑和计算结果不变。

04 实验:LTR 模型和原生模型的效果对比

究竟 TFR 框架训练的 LTR 排序模型对比同样网络结构的原生模型,能够带来多大的效果提升呢,我们也专门做了线上实验来分析。选取了一个业务场景,取出三个流量组分别做以下模型:

BaseB:没有排序服务,为每个召回渠道配置优先级,系统按照优先级给出推荐结果。

Ranking:TensorFlow 原生 Estimator 开发的排序算法。

TfrRankingB:基于TFR框架开发的 LTR 排序算法。

其中,TfrRankingB 相比较于 Ranking,模型结构完全一致,也就是采用同一个 Scoring Function,训练数据集也完全一致。但是由于 TfrRankingB 采用 TFR 框架训练的 LTR 模型,模型优化上有以下几处不同:

以上的几处不同是模型训练方式和评估指标上的不同,这也正是采用 TFR 框架带给我们的。而训练数据和模型本身,包括正则化项在内,TfrRankingB 和 Ranking 是完全一样。两个模型训练后,与 BaseB 一起在线上真实流量环境下测试完整 4 天,其中 day_1 和 day_2 为平日,day_3 和 day_4 是休息日。线上实验考查用户的 CTR(点击率)、UCTR(用户点击率)和 LPLAY(长播放占比),效果如下:

考虑到业务保密性,我们对横纵坐标的具体取值不做展示。但是结论显而易见:

在 CTR 和 UCTR 指标上,TfrRankingB 显著优于 Ranking,Ranking 显著优于 BaseB。

在 LPLAY 指标上,TfrRankingB 优于 Ranking,Ranking 优于 BaseB。

总结

使用 TFR 框架后,可以非常方便的基于 TensorFlow 开发 LTR 模型或者将现有模型改造为 LTR 模型。同时,TFR 框架的模块设计、代码逻辑都非常巧妙,诸如高内聚低耦合等大家常常挂在嘴边的规范也实实在在的落在了代码上。在接下来的工作中,逐步将现有的 TensorFlow 1.X 版本升级到 2.X 版本,并观察 TFR 框架对 TensorFlow 2.X 的支持情况。

责任编辑:lq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4456

    浏览量

    90757
  • CTR
    CTR
    +关注

    关注

    0

    文章

    34

    浏览量

    14000
  • tensorflow
    +关注

    关注

    13

    文章

    313

    浏览量

    60242

原文标题:案例分享 | TensorFlow Ranking 框架在爱奇艺海外推荐业务中的实践与应用

文章出处:【微信号:tensorflowers,微信公众号:Tensorflowers】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    HFSS不能使用迭代求解

    新手小白提问,如图,设置的是迭代求解,运行时转为直接求解导致内存不够,请大神解答为什么不能用迭代求解啊
    发表于 03-27 14:24

    求助,如何在Micrium uc探针中导出REF_BGT60LTR11AIP_M0雷达原始数据?

    我刚刚从 REF BGT60LTR11AIP M0 开始。那么官方的数据包只有一个基于 Micrium 的 GUI 界面,而这个 GUI 界面只有数据图表,没有导出数据开关。 右边的excel
    发表于 01-26 06:11

    为什么无法读取BGT60LTR11AIP Radar Shield2Go板的SPI数据?

    我有一块BGT60LTR11AIP Radar Shield2Go板,试图通过PSOC4 MCU的模拟SPI读取数据。 我已经将评估板设置为SPI模式,为使用官方库代码,MCU采用了模拟SPI方式读取,但是一直无法读到数据。 附件是项目,有人能帮我吗?
    发表于 01-23 06:20

    为什么无法通过SPI读取BGT60LTR11AIP数据?

    嗨,我有一个BGT60LTR11AIP Radar Shield2Go板,并尝试通过PSOC4 MCU的SPI读取数据,但我无法获得它。 我已经将主板设置为 SPI 模式并使用了官方库代码。 附件是项目,有人能帮我吗?
    发表于 01-19 07:54

    如何加速HBM仿真迭代优化?

    如何加速HBM仿真迭代优化?
    的头像 发表于 11-29 16:13 251次阅读
    如何加速HBM仿真<b class='flag-5'>迭代</b>优化?

    python牛顿迭代

    牛顿迭代法是一种数值计算方法,用于求解方程的数值近似解。它是以英国科学家艾萨克·牛顿的名字命名的,最初由牛顿在17世纪末提出。牛顿迭代法基于一个简单的原理:一条曲线的切线近似代替这条曲线,在切线
    的头像 发表于 11-21 15:06 467次阅读

    RISC-V架构芯片出货超过10亿颗

    RISC-V 开放式架构自2014 年8 月推出以来,已获显著进步。采RISC-V 架构的芯片出货超过10 亿颗,预估到2030 年有160 亿颗RISC-V 架构芯片出货。
    的头像 发表于 11-16 15:10 547次阅读
    RISC-V架构芯片出货超过10亿颗

    LPC800系列32位MCU,面向传统8位和16位MCU的迭代和升级

    LPC800是NXP(恩智浦)从2012年开始陆续开发面世的以ArmCortex-M0+为核心的32位MCU系列,定位是面向传统的8位和16位MCU的迭代和升级,因此其配置特点十分鲜明。首先是迎合
    的头像 发表于 09-26 18:01 446次阅读
    LPC800系列32位MCU,面向<b class='flag-5'>传统</b>8位和16位MCU的<b class='flag-5'>迭代</b>和升级

    什么是光耦合器的CTR?光耦合器电路设计示例

    CTR 也就是电流传输比,是集电极与正向电流的比率,用%表示:CTR = ( Ic / If ) x 100%集电极电流是流向光耦合器晶体管侧集电极的电流,另一方面,正向电流是流向光耦合器二极管侧的电流。
    发表于 09-16 12:37 4587次阅读
    什么是光耦合器的<b class='flag-5'>CTR</b>?光耦合器电路设计示例

    迭代模式在UVM中的应用有哪些

    行为型设计模式数量较多,上一篇介绍了模板模式和策略模式,下面对迭代模式进行介绍,挖掘其在UVM中的应用。
    的头像 发表于 08-14 17:15 386次阅读
    <b class='flag-5'>迭代</b>模式在UVM中的应用有哪些

    Python中的迭代器介绍 迭代器在scoreboard中的应用有哪些?

    Iterator Design Pattern: 对容器 (聚合类,集合数据等) 的遍历操作从容器中拆分出来,放到迭代器中,实现迭代操作的解耦。
    的头像 发表于 08-08 09:41 399次阅读
    Python中的<b class='flag-5'>迭代</b>器介绍 <b class='flag-5'>迭代</b>器在scoreboard中的应用有哪些?

    粒子群算法的MATLAB实现(1)

    粒子群算法(Particle Swarm Optimization,PSO)属于进化算法的一种,和模拟退火算法相似,它也是从随机解出发,通过迭代寻找最优解。
    的头像 发表于 07-21 15:25 1095次阅读
    粒子群<b class='flag-5'>算法</b>的MATLAB实现(1)

    C++入门之通用算法

    C++ 是一种强大的编程语言,它提供了许多通用算法,可以用于各种容器类型。这些算法是通过迭代器来操作容器中的元素,因此它们是通用的,可以用于不同类型的容器。在本篇博客中,我们将详细介绍 C++ 的通用
    的头像 发表于 05-17 09:40 417次阅读

    迭代不同WIFI连接的正确方法是什么?

    迭代不同WIFI连接的正确方法?
    发表于 05-04 06:46

    SPFA 算法:实现原理及其应用

    Integer.MAX_VALUE 来使),并将起点s的距离初始化为0。同时,我们还需要将起点s入队。 2.迭代 每次队列中取出一个顶点u,遍历所有u出发的边,对于边(u,v)(其中v为
    发表于 04-29 12:43