美团外卖特征平台的建设与实践
1 背景
美团外卖业务种类繁多、场景丰富,根据业务特点可分为推荐、广告、搜索三大业务线以及数个子业务线,比如商家推荐、菜品推荐、列表广告、外卖搜索等等,满足了数亿用户对外卖服务的全方面需求。而在每条业务线的背后,都涉及用户、商家、平台三方面利益的平衡:用户需要精准的展现结果;商家需要尽可能多的曝光和转化;平台需要营收的最大化,而算法策略通过模型机制的优化迭代,合理地维护这三方面的利益平衡,促进生态良性发展。
随着业务的发展,外卖算法模型也在不断演进迭代中。从之前简单的线性模型、树模型,到现在复杂的深度学习模型,预估效果也变得愈发精准。这一切除了受益于模型参数的不断调优,也受益于外卖算法平台对算力增长的工程化支撑。外卖算法平台通过统一算法工程框架,解决了模型&特征迭代的系统性问题,极大地提升了外卖算法的迭代效率。
根据功能不同,外卖算法平台可划分为三部分:模型服务、模型训练和特征平台。其中,模型服务用于提供在线模型预估,模型训练用于提供模型的训练产出,特征平台则提供特征和样本的数据支撑。本文将重点阐述外卖特征平台在建设过程中遇到的挑战以及优化思路。
诚然,业界对特征系统的研究较为广泛,比如微信FeatureKV存储系统聚焦于解决特征数据快速同步问题,腾讯广告特征工程聚焦于解决机器学习平台中Pre-Trainer方面的问题,美团酒旅在线特征系统聚焦于解决高并发情形下的特征存取和生产调度问题,而外卖特征平台则聚焦于提供从样本生成->特征生产->特征计算的一站式链路,用于解决特征的快速迭代问题。
随着外卖业务的发展,特征体量也在快速增长,外卖平台面对的挑战和压力也不断增大。目前,平台已接入特征配置近万个,特征维度近50种,日处理特征数据量几十TB,日处理特征千亿量级,日调度任务数量达数百个。面对海量的数据资源,平台如何做到特征的快速迭代、特征的高效计算以及样本的配置化生成?下文将分享美团外卖在平台建设过程中的一些思考和优化思路,希望能对大家有所帮助或启发。
2 特征框架演进
2.1 旧框架的不足
外卖业务发展初期,为了提升策略迭代效率,算法同学通过积累和提炼,整理出一套通用的特征生产框架,该框架由三部分组成:特征统计、特征推送和特征获取加载。如下图所示:
特征统计:基于基础数据表,框架支持统计多个时段内特定维度的总量、分布等统计类特征。 特征推送:框架支持将Hive表里的记录映射成Domain对象,并将序列化后的结果写入KV存储。 特征获取加载:框架支持在线从KV存储读取Domain对象,并将反序列化后的结果供模型预估使用。
该框架应用在外卖多条业务线中,为算法策略的迭代提供了有力支撑。但随着外卖业务的发展,业务线的增多,数据体量的增大,该框架逐渐暴露以下三点不足:
特征迭代成本高:框架缺乏配置化管理,新特征上线需要同时改动离线侧和在线侧代码,迭代周期较长。 特征复用困难:外卖不同业务线间存在相似场景,使特征的复用成为可能,但框架缺乏对复用能力的很好支撑,导致资源浪费、特征价值无法充分发挥。 平台化能力缺失:框架提供了特征读写的底层开发能力,但缺乏对特征迭代完整周期的平台化追踪和管理能力。
2.2 新平台的优势
针对旧框架的不足,我们在2018年中旬开始着手搭建新版的特征平台,经过不断的摸索、实践和优化,平台功能逐渐完备,使特征迭代能力更上一层台阶。
特征平台框架由三部分组成:训练样本生成(离线)、特征生产(近线)以及特征获取计算(在线),如下图所示:
训练样本生成:离线侧,平台提供统一配置化的训练样本生成能力,为模型的效果验证提供数据支撑。 特征生产:近线侧,平台提供面对海量特征数据的加工、调度、存储、同步能力,保证特征数据在线快速生效。 特征获取计算:在线侧,平台提供高可用的特征获取能力和高性能的特征计算能力,灵活支撑多种复杂模型的特征需求。
目前,外卖特征平台已接入外卖多条业务线,涵盖数十个场景,为业务的策略迭代提供平台化支持。其中,平台的优势在于两点:
业务提效:通过特征配置化管理能力、特征&算子&解决方案复用能力以及离线在线打通能力,提升了特征迭代效率,降低了业务的接入成本,助力业务快速拿到结果。 业务赋能:平台以统一的标准建立特征效果评估体系,有助于特征在业务间的借鉴和流通,最大程度发挥出特征的价值。
3 特征平台建设
3.1 特征生产:海量特征的生产能力
特征同步的方式有多种,业界常见做法是通过开发MR任务/Spark任务/使用同步组件,从多个数据源读取多个字段,并将聚合的结果同步至KV存储。这种做法实现简单,但存在以下问题:
特征重复拉取:同一特征被不同任务使用时,会导致特征被重复拉取,造成资源浪费。 缺乏全局调度:同步任务间彼此隔离,相互独立,缺乏多任务的全局调度管理机制,无法进行特征复用、增量更新、全局限流等操作,影响特征的同步速度。 存储方式不够灵活健壮:新特征存储时,涉及到上下游代码/文件的改动,迭代成本高,特征数据异常时,需长时间重导旧数据,回滚效率较低。
围绕上述几点问题,本文将从三个方面进行特征生产核心机制的介绍:
特征语义机制:用于解决平台从数百个数据源进行特征拉取和转化的效率问题。 特征多任务调度机制:用于解决海量特征数据的快速同步问题。 特征存储机制:用于解决特征存储在配置化和可靠性方面的问题。
3.1.1 特征语义
特征平台目前已接入上游Hive表数百个、特征配置近万个,其中大部分特征都需天级别的更新。那平台如何从上游高效地拉取特征呢?直观想法是从特征配置和上游Hive表两个角度进行考虑:
特征配置角度:平台根据每个特征配置,单独启动任务进行特征拉取。
优点:控制灵活。 缺点:每个特征都会启动各自的拉取任务,执行效率低且耗费资源。
上游Hive表角度:Hive表中多个特征字段,统一放至同一任务中拉取。
优点:任务数量可控,资源占用低。 缺点:任务逻辑耦合较重,新增特征时需感知Hive表其它字段拉取逻辑,导致接入成本高。
上述两种方案都存在各自问题,不能很好满足业务需求。因此,特征平台结合两个方案的优点,并经过探索分析,提出了特征语义的概念:
特征语义:由特征配置中的上游Hive表、特征维度、特征过滤条件、特征聚合条件四个字段提取合并而成,本质就是相同的查询条件,比如:Select KeyInHive,f1,f2 From HiveSrc Where Condition Group by Group,此时该四个字段配置相同,可将F1、F2两个特征的获取过程可合并为一个SQL语句进行查询,从而减少整体查询次数。另外,平台将语义合并过程做成自动化透明化,接入方只需关心新增特征的拉取逻辑,无需感知同表其它字段,从而降低接入成本。
特征平台对特征语义的处理分为两个阶段:语义抽取和语义合并,如下图所示:
语义抽取:平台解析特征配置,构建SQL语法树,通过支持多种形式判同逻辑(比如交换律、等效替换等规则),生成可唯一化表达的SQL语句。 语义合并:如果不同特征对应的语义相同,平台会将其抽取过程进行合并,比如:Select KeyInHive, Extract1 as f1, Extract2 as f2 From HiveSrc Where Condition Group by Group,其中Extract即特征的抽取逻辑,f1和f2的抽取逻辑可进行合并,并将最终抽取到的特征数据落地至特征共享表中存储,供多业务方使用。
3.1.2 特征多任务调度
为了保证每天数十TB数据量的快速同步,特征平台首先按照特征的处理流程:获取、聚合和同步,分别制定了特征语义任务、特征聚合任务和特征同步任务:
特征语义任务:用于将特征数据从数据源拉取解析,并落地至特征共享表中。 特征聚合任务:用于不同业务线(租户)按照自身需求,从特征共享表中获取特定特征并聚合,生成全量快照以及增量数据。 特征同步任务:用于将增量数据(天级)和全量数据(定期)同步至KV存储中。
同时,特征平台搭建了多任务调度机制,将不同类型的任务进行调度串联,以提升特征同步的时效性,如下图所示:
任务调度器:按照任务执行顺序,循环检测上游任务状态,保证任务的有序执行。 特征语义任务调度:当上游Hive表就绪后,执行语义任务。 上游监测:通过上游任务调度接口实时获取上游Hive表就绪状态,就绪即拉取,保证特征拉取的时效性。 语义优先级:每个语义都会设置优先级,高优先级语义对应的特征会被优先聚合和同步,保证重要特征的及时更新。 队列优选:平台会获取多个队列的实时状态,并优先选择可用资源最多的队列执行语义任务,提升任务执行效率。 特征复用:特征的价值在于复用,特征只需接入平台一次,就可在不同业务间流通,是一种业务赋能的体现。 特征统一存储在特征共享表中,供下游不同业务方按需读取,灵活使用。 特征的统一接入复用,避免相同数据的重复计算和存储,节省资源开销。 特征聚合任务调度:当上游语义任务就绪后,执行聚合任务。 多租户机制:多租户是平台面向多业务接入的基础,业务以租户为单位进行特征管理,并为平台分摊计算资源和存储资源。 特征分组:特征分组将相同维度下的多个特征进行聚合,以减少特征Key的数量,避免大量Key读写对KV存储性能造成的影响。 全量快照:平台通过天级别聚合的方式生成特征全量快照,一方面便于增量数据探查,另一方面也避免历史数据的丢失。 增量探查:通过将最新特征数据与全量快照的数值对比,探查出发生变化的特征,便于后续增量同步。 特征补偿:因就绪延迟而未被当天同步的特征,可跨天进行补偿同步,避免出现特征跨天丢失的问题。 特征同步任务调度:当上游聚合任务就绪后,执行同步任务。 增量同步:将经全量快照探查到的增量数据,同步写入KV存储,大大降低数据写入量,提升同步效率。 全量刷新:KV存储中的数据由于过期时间限制,需定期进行全量刷新,避免出现特征过期导致的数据丢失问题。 全局限流:通过监测同步任务的并行度以及KV存储状态指标,实时调整全局同步速度,在保证KV存储稳定性前提下,充分利用可用资源来提升特征同步效率。
3.1.3 特征存储
3.1.3.1 特征动态序列化
特征数据通过聚合处理后,需存储到HDFS/KV系统中,用于后续任务/服务的使用。数据的存储会涉及到存储格式的选型,业界常见的存储格式有JSON、Object、Protobuf等,其中JSON配置灵活,Object支持自定义结构,Protobuf编码性能好且压缩比高。由于特征平台支持的数据类型较为固定,但对序列化反序列化性能以及数据压缩效果有较高要求,因此选择Protobuf作为特征存储格式。
Protobuf的常规使用方式是通过Proto文件维护特征配置。新增特征需编辑Proto文件,并编译生成新版本JAR包,在离线&在线同时发布更新后,才能生产解析新增特征,导致迭代成本较高。Protobuf也提供了动态自描述和反射机制,帮助生产侧和消费侧动态适配消息格式的变更,避免静态编译带来的JAR包升级成本,但代价是空间成本和性能成本均高于静态编译方式,不适用于高性能、低时延的线上场景。
针对该问题,特征平台从特征元数据管理的角度,设计了一种基于Protobuf的特征动态序列化机制,在不影响读写性能前提下,做到对新增特征读写的完全配置化。
为方便阐述,先概述下Protobuf编码格式。如下图所示,Protobuf按“键-值”形式序列化每个属性,其中键标识了该属性的序号和类型。可以看出,从原理上,序列化主要要依赖键中定义的字段序号和类型。
因此,特征平台通过从元数据管理接口查询元数据,来替换常规的Proto文件配置方式,去动态填充和解析键中定义的字段序号和类型,以完成序列化和反序列化,如下图所示:
特征序列化:通过查询特征元数据,获取特征的序号和类型,将特征序号填充至键的序号属性中,并根据特征类型决定键的类型属性以及特征值的填充方式。 特征反序列化:解析键的属性,获取特征序号,通过查询特征元数据,获取对应的特征类型,并根据特征类型决定特征值的解析方式(定长/变长)。
3.1.3.2 特征多版本
特征数据存储于KV系统中,为在线服务提供特征的实时查询。业界常见的特征在线存储方式有两种:单一版本存储和多版本存储。
单一版本存储即覆盖更新,用新数据直接覆盖旧数据,实现简单,对物理存储占用较少,但在数据异常的时候无法快速回滚。 多版本存储相比前者,增加了版本概念,每一份数据都对应特定版本,虽然物理存储占用较多,但在数据异常的时候可通过版本切换的方式快速回滚,保证线上稳定性。
因此,特征平台选择特征多版本作为线上数据存储方式。
传统的多版本方式是通过全量数据的切换实现,即每天在全量数据写入后再进行版本切换。然而,特征平台存在增量和全量两种更新方式,不能简单复用全量的切换方式,需考虑增量和全量的依赖关系。因此,特征平台设计了一种适用于增量&全量两种更新方式下的版本切换方式(如下图所示)。该方式以全量数据为基础,白天进行增量更新,版本保持不变,在增量更新结束后,定期进行全量更新(重写),并进行版本切换。
3.2 特征获取计算:高性能的特征获取计算能力
特征获取计算为模型服务、业务系统、离线训练提供特征的实时获取能力和高性能的计算能力,是特征平台能力输出的重要途径。
旧框架中,特征处理分散在业务系统中,与业务逻辑耦合严重,随着模型规模增长和业务系统的架构升级,特征处理性能逐渐成为瓶颈,主要存在以下问题:
需要代码开发:特征处理的代码冗长,一方面会造成易增难改的现象,另一方面相同逻辑代码重复拷贝较多,也会造成复用性逐渐变差,代码质量就会持续恶化。 潜在性能风险:大量实验同时进行,每次处理特征并集,性能会互相拖累。 一致性难以保证:离线训练样本和在线预估对特征的处理逻辑难以统一。
因此,我们在新平台建设中,将特征处理逻辑抽象成独立模块,并对模块的职责边界做了清晰设定:通过提供统一API的方式,只负责特征的获取和计算,而不关心业务流程上下文。在新的特征获取和计算模块设计中,我们主要关注以下两个方面:
易用性:特征处理配置的易用性会影响到使用方的迭代效率,如果新增特征或更改特征计算逻辑需要代码改动,势必会拖慢迭代效率。 性能:特征处理过程需要实时处理大量特征的拉取和计算逻辑,其效率会直接影响到上游服务的整体性能。
围绕以上两点,本文将从下述两个方面分别介绍特征获取计算部分:
模型特征自描述MFDL:将特征计算流程配置化,提升特征使用的易用性。 特征获取流程:统一特征获取流程,解决特征获取的性能问题。
3.2.1 模型特征自描述MFDL
模型特征处理是模型预处理的一部分,业界常用的做法有:
将特征处理逻辑和模型打包在一起,使用PMML或类似格式描述。优点是配置简洁;缺点是无法单独更新模型文件或特征配置。
将特征处理逻辑和模型隔离,特征处理部分使用单独的配置描述,比如JSON或CSV等格式。优点是特征处理配置和模型文件分离,便于分开迭代;缺点是可能会引起特征配置和模型加载不一致性的问题,增加系统复杂度。
考虑到对存量模型的兼容,我们定义了一套自有的配置格式,能独立于模型文件之外快速配置。基于对原有特征处理逻辑的梳理,我们将特征处理过程抽象成以下两个部分:
模型特征计算:主要用来描述特征的计算过程。这里区分了原始特征和模型特征:将从数据源直接获取到的特征称之为原始特征,将经过计算后输入给模型的特征称之为模型特征,这样就可以实现同一个原始特征经过不同的处理逻辑计算出不同的模型特征。
模型特征转换:将生成的模型特征根据配置转换成可以直接输入给模型的数据格式。由于模型特征计算的结果不能被模型直接使用,还需要经过一些转换逻辑的处理,比如转换成Tensor、Matrix等格式。
基于该两点,特征平台设计了MFDL(Model Feature Description Language)来完整的描述模型特征的生成流程,用配置化的方式描述模型特征计算和转换过程。其中,特征计算部分通过自定义的DSL来描述,而特征转换部分则针对不同类型的模型设计不同的配置项。通过将特征计算和转换分离,就可以很方便的扩展支持不同的机器学习框架或模型结构。
在MFDL流程中,特征计算DSL是模型处理的重点和难点。一套易用的特征计算规范需既要满足特征处理逻辑的差异性,又要便于使用和理解。经过对算法需求的了解和对业界做法的调研,我们开发了一套易用易读且符合编程习惯的特征表达式,并基于JavaCC实现了高性能的执行引擎,支持了以下特性:
特征类型:支持以下常用的特征数据结构: 单值类型(String/Long/Double):数值和文本类型特征。 Map类型:交叉或字典类型的特征。 List类型:Embedding或向量特征。 逻辑运算:支持常规的算术和逻辑运算,比如a>b?(a-b):0。 函数算子:逻辑运算只适合少量简单的处理逻辑,而更多复杂的逻辑通常需要通过函数算子来完成。业务方既可以根据自己的需求编写算子,也可快速复用平台定期收集整理的常用算子,以降低开发成本,提升模型迭代效率。
特征计算DSL举例如下所示:
基于规范化的DSL,一方面可以让执行引擎在执行阶段做一些主动优化,包括向量化计算、并行计算等,另一方面也有助于使用方将精力聚焦于特征计算的业务逻辑,而不用关心实现细节,既降低了使用门槛,也避免了误操作对线上稳定性造成的影响。
由于MFDL是独立于模型文件之外的配置,因此特征更新迭代时只需要将新的配置推送到服务器上,经过加载和预测后即可生效,实现了特征处理的热更新,提升了迭代效率。同时,MFDL也是离线训练时使用的特征配置文件,结合统一的算子逻辑,保证了离线训练样本/在线预估特征处理的一致性。在系统中,只需要在离线训练时配置一次,训练完成后即可一键推送到线上服务,安全高效。
下面是一个TF模型的MFDL配置示例:
3.2.2 特征获取流程
MFDL中使用到的特征数据,需在特征计算之前从KV存储进行统一获取。为了提升特征获取效率,平台会对多个特征数据源异步并行获取,并针对不同的数据源,使用不同的手段进行优化,比如RPC聚合等。特征获取的基本流程如下图所示:
在特征生产章节已经提到,特征数据是按分组进行聚合存储。特征获取在每次访问KV存储时,都会读取整个分组下所有的特征数据,一个分组下特征数量的多少将会直接影响到在线特征获取的性能。因此,我们在特征分组分配方面进行了相关优化,既保证了特征获取的高效性,又保证了线上服务的稳定性。
3.2.2.1 智能分组
特征以分组的形式进行聚合,用于特征的写入和读取。起初,特征是以固定分组的形式进行组织管理,即不同业务线的特征会被人工聚合到同一分组中,这种方式实现简单,但却暴露出以下两点问题:
特征读取性能差:线上需要读取解析多个业务线聚合后的特征大Value,而每个业务线只会用到其中部分特征,导致计算资源浪费、读取性能变差。 影响KV集群稳定性:特征大Value被高频读取,一方面会将集群的网卡带宽打满,另一方面大Value不会被读取至内存,只能磁盘查找,影响集群查询性能(特定KV存储场景)。
因此,特征平台设计了智能分组,打破之前固定分组的形式,通过合理机制进行特征分组的动态调整,保证特征聚合的合理性和有效性。如下图所示,平台打通了线上线下链路,线上用于上报业务线所用的特征状态,线下则通过收集分析线上特征,从全局视角对特征所属分组进行智能化的整合、迁移、反馈和管理。同时,基于存储和性能的折中考虑,平台建立了两种分组类型:业务分组和公共分组:
业务分组:用于聚合每个业务线各自用到的专属特征,保证特征获取的有效性。如果特征被多业务共用,若仍存储在各自业务分组,会导致存储资源浪费,需迁移至公共分组(存储角度)。 公共分组:用于聚合多业务线同时用到的特征,节省存储资源开销,但分组增多会带来KV存储读写量增大,因此公共分组数量需控制在合理范围内(性能角度)。
通过特征在两种分组间的动态迁移以及对线上的实时反馈,保证各业务对特征所拉即所用,提升特征读取性能,保证KV集群稳定性。
3.2.2.2 分组合并
智能分组可以有效的提升特征获取效率,但同时也引入了一个问题:在智能分组过程中,特征在分组迁移阶段,会出现一个特征同时存在于多个分组的情况,造成特征在多个分组重复获取的问题,增加对KV存储的访问压力。为了优化特征获取效率,在特征获取之前需要对特征分组进行合并,将特征尽量放在同一个分组中进行获取,从而减少访问KV存储的次数,提升特征获取性能。
如下图所示,经过分组合并,将特征获取的分组个数由4个(最坏情况)减少到2个,从而对KV存储访问量降低一半。
3.3 训练样本构建:统一配置化的一致性训练样本生成能力
3.3.1 现状分析
训练样本是特征工程连接算法模型的一个关键环节,训练样本构建的本质是一个数据加工过程,而这份数据如何做到“能用”(数据质量要准确可信)、“易用”(生产过程要灵活高效)、“好用”(通过平台能力为业务赋能)对于算法模型迭代的效率和效果至关重要。
在特征平台统一建设之前,外卖策略团队在训练样本构建流程上主要遇到几个问题:
重复性开发:缺少体系化的平台系统,依赖一些简单工具或定制化开发Hive/Spark任务,与业务耦合性较高,在流程复用、运维成本、性能调优等方面都表现较差。 灵活性不足:样本构建流程复杂,包括但不限数据预处理、特征抽取、特征样本拼接、特征验证,以及数据格式转换(如TFRecord)等,已有工具在配置化、扩展性上很难满足需求,使用成本较高。 一致性较差:线上、线下在配置文件、算子上使用不统一,导致在线预测样本与离线训练样本的特征值不一致,模型训练正向效果难保障。
3.3.2 配置化流程
平台化建设最重要的流程之一是“如何进行流程抽象”,业界有一些机器学习平台的做法是平台提供较细粒度的组件,让用户自行选择组件、配置依赖关系,最终生成一张样本构建的DAG图。
对于用户而言,这样看似是提高了流程编排的自由度,但深入了解算法同学实际工作场景后发现,算法模型迭代过程中,大部分的样本生产流程都比较固定,反而让用户每次都去找组件、配组件属性、指定关系依赖这样的操作,会给算法同学带来额外的负担,所以我们尝试了一种新的思路来优化这个问题:模板化 + 配置化,即平台提供一个基准的模板流程,该流程中的每一个节点都抽象为一个或一类组件,用户基于该模板,通过简单配置即可生成自己样本构建流程,如下图所示:
整个流程模板包括三个部分:输入(Input)、转化(Transform)、输出(Output), 其中包含的组件有:Label数据预处理、实验特征抽取、特征样本关联、特征矩阵生成、特征格式转换、特征统计分析、数据写出,组件主要功能:
Label数据预处理:支持通过自定义Hive/Spark SQL方式抽取Label数据,平台也内置了一些UDF(如URL Decode、MD5/Murmur Hash 等),通过自定义SQL+UDF方式灵活满足各种数据预处理的需求。在数据源方面,支持如下类型: 一致性特征样本:指线上模型预测时,会将一次预测请求中使用到的特征及Label相关字段收集、加工、拼接,为离线训练提供基础的样本数据,推荐使用,可更好保障一致性。 自定义:不使用算法平台提供的一致性特征样本数据源,通过自定义方式抽取Label数据。 父训练样本:可依赖之前或其他同学生产的训练样本结果,只需要简单修改特征或采样等配置,即可实现对原数据微调,快速生成新的训练数据,提高执行效率。 实验特征抽取:线下训练如果需要调研一些新特征(即在一致性特征样本中不存在)效果,可以通过特征补录方式加入新的特征集。 特征样本关联:将Label数据与补录的实验特征根据唯一标识(如:poi_id)进行关联。 特征矩阵生成:根据用户定义的特征MFDL配置文件,将每一个样本需要的特征集计算合并,生成特征矩阵,得到训练样本中间表。 特征格式转换:基于训练样本中间表,根据不同模型类型,将数据转换为不同格式的文件(如:CSV/TFRecord)。 特征统计分析:辅助功能,基于训练样本中间表,对特征统计分析,包括均值、方差、最大/最小值、分位数、空值率等多种统计维度,输出统计分析报告。 数据写出:将不同中间结果,写出到Hive表/HDFS等存储介质。
上面提到,整个流程是模板化,模板中的多数环节都可以通过配置选择开启或关闭,所以整个流程也支持从中间的某个环节开始执行,灵活满足各类数据生成需求。
3.3.3 一致性保障
(1)为什么会不一致?
上文还提到了一个关键的问题:一致性较差。先来看下为什么会不一致?
上图展示了在离线训练和在线预测两条链路中构建样本的方式,最终导致离线、在线特征值Diff的原因主要有三点:
特征配置文件不一致:在线侧、离线侧对特征计算、编排等配置描述未统一,靠人工较难保障一致性。 特征更新时机不一致:特征一般是覆盖更新,特征抽取、计算、同步等流程较长,由于数据源更新、重刷、特征计算任务失败等诸多不确定因素,在线、离线在不同的更新时机下,数据口径不一致。 特征算子定义不一致:从数据源抽取出来的原始特征一般都需要经过二次运算,线上、线下算子不统一。
(2)如何保证一致性?
明确了问题所在,我们通过如下方案来解决一致性问题:
打通线上线下配置
线下生成训练样本时,用户先定义特征MFDL配置文件,在模型训练后,通过平台一键打包功能,将MFDL配置文件以及训练输出的模型文件,打包、上传到模型管理平台,通过一定的版本管理及加载策略,将模型动态加载到线上服务,从而实现线上、线下配置一体化。
提供一致性特征样本
通过实时收集在线Serving输出的特征快照,经过一定的规则处理,将结果数据输出到Hive表,作为离线训练样本的基础数据源,提供一致性特征样本,保障在线、离线数据口径一致。
统一特征算子库
上文提到可以通过特征补录方式添加新的实验特征,补录特征如果涉及到算子二次加工,平台既提供基础的算子库,也支持自定义算子,通过算子库共用保持线上、线下计算口径一致。
3.3.4 为业务赋能
从特征生产,到特征获取计算,再到生成训练样本,特征平台的能力不断得到延展,逐步和离线训练流程、在线预测服务形成一个紧密协作的整体。在特征平台的能力边界上,我们也在不断的思考和探索,希望能除了为业务提供稳定、可靠、易用的特征数据之外,还能从特征的视角出发,更好的建设特征生命周期闭环,通过平台化的能力反哺业务,为业务赋能。在上文特征生产章节,提到了特征平台一个重要能力:特征复用,这也是特征平台为业务赋能最主要的一点。
特征复用需要解决两个问题:
特征快速发现:当前特征平台有上万特征,需要通过平台化的能力,让高质量的特征快速被用户发现,另外,特征的“高质量”如何度量,也需要有统一的评价标准来支撑。 特征快速使用:对于用户发现并筛选出的目标特征,平台需要能够以较低的配置成本、计算资源快速支持使用(参考上文3.1.2 小节“特征复用”)。
本小节重点介绍如何帮助用户快速发现特征,主要包括两个方面:主动检索和被动推荐,如下图所示:
首先,用户可以通过主动检索,从特征仓库筛选出目标特征候选集,然后结合特征画像来进一步筛选,得到特征初选集,最后通过离线实验流程、在线ABTest,结合模型效果,评估筛选出最终的结果集。其中特征画像主要包括以下评价指标: 特征复用度:通过查看该特征在各业务、各模型的引用次数,帮助用户直观判断该特征的价值。 特征标注信息:通过查看该特征在其他业务离线、在线效果的标注信息,帮助用户判断该特征的正负向效果。 数据质量评估:平台通过离线统计任务,按天粒度对特征进行统计分析,包括特征的就绪时间、空值率、均值、方差、最大/小值、分位点统计等,生成特征评估报告,帮助用户判断该特征是否可靠。 其次,平台根据特征的评价体系,将表现较好的Top特征筛选出来,通过排行榜展现、消息推送方式触达用户,帮助用户挖掘高分特征。
为业务赋能是一个长期探索和实践的过程,未来我们还会继续尝试在深度学习场景中,建立每个特征对模型贡献度的评价体系,并通过自动化的方式打通模型在线上、线下的评估效果,通过智能化的方式挖掘特征价值。
4 总结与展望
本文分别从特征框架演进、特征生产、特征获取计算以及训练样本生成四个方面介绍了特征平台在建设与实践中的思考和优化思路。经过两年的摸索建设和实践,外卖特征平台已经建立起完善的架构体系、一站式的服务流程,为外卖业务的算法迭代提供了有力支撑。
未来,外卖特征平台将继续推进从离线->近线->在线的全链路优化工作,在计算性能、资源开销、能力扩展、合作共建等方面持续投入人力探索和建设,并在更多更具挑战的业务场景中发挥平台的价值。同时,平台将继续和模型服务和模型训练紧密结合,共建端到端算法闭环,助力外卖业务蓬勃发展。
5 作者简介
英亮、陈龙、刘磊、亚劼、乐彬等,美团外卖算法平台工程师。
推荐阅读: