【推荐系统】特征拼接和工程实践

一、特征工程

通过idea或者问题 设计实验,并设计对应的指标进行度量,分析实验结果,做出下一步的决策。 而随着技术的进步,越来越多的公司使用人工智能提供服务,因而在解决和优化问题时,数据科学家&算法工程师在实验环节的工作可能就变成这样:
在这里插入图片描述
一个不太正确的理解是: 当确定一个业务优化目标后(label),通过数据分析,假设这些拥有x属性特征的样本有一种关联(模型),那么模型训练的过程就是 拟合 y = F(x) 这个函数的过程。 其中,怎么选择和处理特征的过程,可以理解为特征工程。

训练模型的准确度,极大的依赖于输入的 特征和label。

常见的特征处理,有归一化,离散化,交叉等等

二、特征工程难点

1. 特征穿越

特征穿越是特征工程中常见也是非常重要的一种情况: 训练数据集中错误的包含了未来的信息。
在这里插入图片描述
如上图所示,假设用户在 p1 时间点进入系统,系统推荐了一批视频。 那么后续这条数据作为样本时,其特征只能使用p1时间点的特征,对应到图中,F1,F2,F3 在p1节点的特征,分别是7,3,8。 若F1,F2,F3在构建样本时的特征取的p1时间点后的值,则可以认为是发生了特征穿越,因为对于该样本而言,p1时间点后的特征对它来说就是属于未来的信息。

3.2 特征在线/离线一致性

另一个难点是特征处理一致性问题,也称为 Training-Serving skew。 一般情况下,算法工程师都是离线整理数据,处理特征,训练模型,离线指标ready后再上线小流量实验。在基建不完善的情况下,有可能会出现:同一条数据,离线训练和在线推理的特征处理结果不一致。 举个例子极端的例子: city=shenzhen这个字符串,离线数据样本处理时可能使用spark计算,计算hash值假设为1001,在线rank计算shenzhen哈希值可能使用语言不一样,hash算法也不一样,导致同样一个字符串可能算出不同的值。

在这里插入图片描述
当然特征工程还有其他一些考量,比如离线处理效率,在线计算延迟等等,但是特征穿越 和特征一致性更像是保证模型正确性的基础条件。 因为穿越和一致性问题会导致离线训练指标和正确性奇高,但到了在线时可能效果就不好了,这些差异性会极大的阻碍算法工程师的实验迭代速度,也影响了业务的“增长飞轮”。

四、常见方案对比

特征工程,在国内外大厂都有比较多的方案和思路,通过调研整理,大的方向分为两种:

  1. 特征日志快照(国内大厂偏好方案)

  2. feature store (国外uber,amazon,airbnb等)

    扫描二维码关注公众号,回复: 15215527 查看本文章

4.1 特征日志快照

如何解决穿越问题

在predict阶段就将当下特征值,请求上下文,reqid等通过日志的方式上报,方便后续样本的拼接构造。这种日志快照上报的方式,是当前各大厂的主流方案,包括网易,美团,腾讯信息流,字节,阿里部分团队等。

在这里插入图片描述
大致的流程为:

  1. 当用户请求发生时,rank通过请求特征服务,计算/转换完毕后请求模型推理服务,将打分结果返回上游engine引擎,同时该请求当下的特征值异步上报到kafka队列。

  2. 客户端在接收到engine推荐结果后,把用户的曝光点击行为也上传到行为kafka,再由后续样本joiner程序负责将特征与label拼接起来,送入模型训练以及推理上线,形成闭环。

通过预测时的特征日志上报,离线拼接时只需要简单的拼接上对应请求的行为或者label,因此能够避免上文提到的特征穿越问题。

如何解决特征计算一致性

在特征计算一致性上,由于各家的技术栈和侧重点不同,在具体的方案细节上也有比较大的出入,但整体的方向大致如下: 1. 计算内嵌入模型 2. 在线/离线 lib化 3. 完全抽取后上报 每种方案都有一定的适应场景和优缺点。

【计算内嵌入模型方式】

通过将特征计算逻辑内嵌到模型内,这样子离线训练在在线predict时可以输入原始数据,由模型来保证train/serving的一致性。 举个例子: 比如在tensorflow 中允许用户自定义算子,我们可以借助这个功能,在op里面实现数据解析+ 实现特征计算(log/max/min/bucket/cross/hash/等),离线在线都加载这个library保证一致。

在这里插入图片描述
但这种方式跟训练平台的耦合还是有点重,在大厂内,这可能会涉及到多个团队之间的配合。 比如像字节训练引擎是一个中台团队,他们会单独迭代训练平台,包括ps,训练,推理性能优化等等。 但是特征计算由于差异性很大,灵活性极高,需求变化非常频繁,因而在职能上大多由每个业务自己负责。从整体效率上考虑,这种内嵌的方式会使得两个团队也有一定的对接和耦合,从调研结果来看这也不是目前的主流方案。

但是在定义label方面,内嵌还是具有挺多优势的,这个等下个系列,样本工程实践上再做进一步的分享。

【在线/离线lib化】
另一种保证计算一致性的方式是lib化。 在线推理和离线训练则通过 原始特征 + lib + 配置文件 保证一致性。
在这里插入图片描述
【在线请求】: rank 服务通过so方式加在lib库,通过配置文件进行特征计算,同时上报原始特征

【离线样本】: 样本处理(java)接受rank侧的原始特征后,以jni方式调用lib库,处理完后进行模型训练 特征一致性 = lib 一致 + 配置文件一致 PS: lib库除了支持常规算子外,为了满足在线低延迟的要求,一般也会做DAG + 并行计算等等优化。

这种设计的初衷是希望通过上报一份原始特征,算法同学可以配置不同的特征算子,灵活改变特征的计算方式,达到快速迭代模型的目的。 但毕竟处理逻辑还是分散的,算法同学的触点变多了,效率可能会有影响。因此需要工程架构上不仅流程要打通,还得实现好用的工具,pipeline化,也是个不小的挑战。 而且由于上报的是原始特征,存储压力变大,每个模型的计算逻辑变化,也得重新生成一份样本,也变相增加了存储。

【完全抽取后上报】
最后一种,也是目前大多数公司采取的一种方案,比如腾讯&字节的部分团队。 依旧使用特征lib库进行计算,但是lib只作用于在线阶段,同时在特征上报时,只上报需要用到的全量计算抽取(transform,也常指可以直接用来进入模型训练的数据格式)后的特征(包括实验的和全量的特征)

在这里插入图片描述
抽取后的特征跟原始特征的区别是:

  1. 原始特征一般是明文化,计算抽取后的特征一般都是hash之后的

  2. 原始特征更大,计算抽取后特征更小

  3. 模型一般会上报所有抽取后特征,每个场景随着实验推进,特征会越报越多

  4. 模型实验迭代时,共用一份上报特征,节约一定存储

这种设计通过牺牲离线特征计算的灵活性,一定程度上简化了架构的复杂性,有舍有得。

小结

在这里插入图片描述
以上都有一些缺点,除此之外,日志快照整体方案也有一些别的难点:

  1. 新增特征需要等待问题

  2. 日志快照存储大问题

在进行一些新数据源的特征实验时,往往需要回溯重跑模型,大部分情况下需要重跑过去7天以上的数据,在日志快照方案下,就需要先上线新特征,同时将其dump上报到特征kafka,等待样本joiner拼接,并积累等待n天后,才可以重跑,因此新特征的实验周期相对较长。

虽然可以通过 离线特征回填的方式,把历史数据去拼上待实验的特征,从而降低整个等待的周期,但是回填训练后模型需要上线,并且开启小流量实验,整个期间的特征穿越依旧会比较难保证。

另一个是随着场景的深入,特征会越加越多(上特征肯定比下特征要容易多了),整条链路的带宽,存储压力都会比较大。比如在线服务rank侧 每个请求dump很大的包,带宽io问题,kafka存储压力问题,以及后续的实时flink样本 状态大可能带来的一些稳定性问题,也都是一些不小的工程挑战。

4.2 feature store

相比于当下主流的日志快照方案,feature store的显得更像是一个特征+样本工程的全流程解决方案,在最近这两年也越来越火,比如

  • 开源的feast,
  • 亚马逊 aws 上的SageMaker
  • 商业解决方案tecton
  • 阿里的实时推荐方案中 hologres 也有点类似

feature store 的整体设计思路类似,都是流批特征一体管理 + online/offline 存储 + 统一的sdk/api 数据获取。

以商业化的tecton为例子:
在这里插入图片描述
feature store 核心的功能: 1. 保证在线/离线的一致性 2. 避免特征穿越 3. 提供特征注册&发现&监控等一整套配置工具 4. 提供离线数据分析

我们依旧从核心关注的两个点== 特征一致性 和 特征穿越==上看看feature store方案是如何设计和考量的。(不同产品细节上有些出入,我按照自己的理解稍微合并了下)

【特征一致性】

feast & tecton & sagemarker 的设计思想都是类似 feature as code 的方式,每一个特征都是一段python代码,每段python都指明了数据源的来源,特征计算的逻辑。

在这里插入图片描述
定义完特征后,feature store 会管理好这些特征pipeline,并写入存储。 存储主要分为 online&offline

【online store】: 提供高性能低延迟在线请求,一般情况下是类redis等kv 系统,只保存最新版本的特征数据。

【offline store】: 提供多版本能力,供离线样本构造。

在这里插入图片描述

online &offline store 可以理解为主副本,保持同步。(一般在数据导入环节,会同时更新online &offline store,或者online store更新完后再同步变更给 offline store)

通过统一的python 特征定义代码,转化为对应的在线查询(api/sdk查询) & 离线查询(sql查询),1次代码,多地使用。

【特征穿越】
由于offline store(比如hudi)存储了特征每个时间点的变更和版本,因此在做特征回填或者label拼接时,可以拿到predict时间当下的各个特征的版本,feature store 也会提供数据pipeline来保证特征版本的准确性:
在这里插入图片描述
核心思想是: 对于每条样本,返回该时间戳内各个特征的最新版本。 point in time join 的实现,也可以参考下 feast spark join的版本: https://www.hopsworks.ai/post/a-spark-join-operator-for-point-in-time-correct-joins

小结:

整体来讲,feature store 的设计更加完备,旨在解决特征工程+样本领域内全流程的问题,因而整体的架构和工程设计相对日志快照方案更加复杂。但是随着深度学习的发展和普及,这些配套设施一定会越来越完善,尽管复杂,但会变得像基础设施一样,对上层应用透明化。了解这些设计方案的区别和演变,也有利于我们在使用过程中更方便的debug,甚至在一些差异性变化的业务场景,能够有能力去进行底层的改造,满足业务需求。

五、小结

特征工程某种程度涵盖了搜广推的大部分数据链路流程,不同的业务,诉求,会使得链路有非常多的设计组合。 比如小业务可能更多想要更快,迭代效率更高,那么当然希望整体的推荐链路更多,写一份py代码就可以保证一致性&特征穿越,即使因此付出点额外的存储也无所谓。 像业务量级大了之后,就不得不考虑存储成本,在线请求的延迟,性能。模型&特征也不得不更加精细化,相应的就带来更加复杂的特征&数据&版本等管理。

另外不同的团队,职能分工也导致设计上的差异,比如像外国公司facebook amazon貌似会有比较清晰的 数据&算法&工程 分工。数据同学写sql&python,算法同学写模型,工程同学负责在线部署,国内有些公司这些职责都集一人之身,提倡从头撸到尾,因此在对应的工程架构和流程上也有比较大的区别。这可能也是目前并没有所谓的大一统的架构的原因吧。

Reference

https://developer.aliyun.com/article/785005
https://aws.amazon.com/cn/blogs/machine-learning/understanding-the-key-capabilities-of-amazon-sagemaker-feature-store/
实时增量学习在云音乐直播推荐系统中的工程实践
https://tech.meituan.com/2022/07/06/largescaledeeplearningmodel-engineeringpractice-in-mtwaimaiad.html
https://www.infoq.com/presentations/michelangelo-palette-uber/
https://www.6aiq.com/article/16511048724321 什么是特征工程
GitHub项目地址:https://github.com/tensorflow/recommenders-addons
Dynamic Embedding方案(RFC)链接:https://github.com/tensorflow/recommenders-addons/blob/master/rfcs/20200424-sparse-domain-isolation.md
推荐算法工程专栏-tx

猜你喜欢

转载自blog.csdn.net/qq_35812205/article/details/130858341