当前位置: 首页 > 科技观察

网易云音乐算法平台研发专家黄斌:网易云音乐在线估价系统的实践与思考

时间:2023-03-22 01:33:05 科技观察

作者|黄斌专家做了主题演讲《网易云音乐在线预估系统的实践与思考》,从技术研发的角度分享了他在如何构建高性能、易用、功能丰富的评估系统方面的实践和思考。演讲内容整理如下,希望对大家有所启发。整体系统架构首先我们来看一个整个预估系统的架构,如下图所示:系统整体架构中间的PredictServer是预估系统的核心组件,包括查询组件、特征处理组件、模型计算组件。左侧监控系统用于监控网络服务,保证系统网络畅通。右侧的PushServer用于模型推送,将最新的模型推送到在线预测系统中进行预测。目标是构建一个高性能、易于使用且功能丰富的估算系统。HPC如何提升计算性能?我们常见的计算性能问题有哪些,我将从三个方面来阐述。特征处理在一般的方案中,我们的特征计算和模型计算是部署在不同的进程中,这会导致大量的特征被跨服务和跨语言传递,会带来多个编解码器和内存副本,导致相对大的性能开销。模型更新我们知道,当模型更新时,会有大量的申请和发布。但是在一些常见的方案中,它并没有自带模型预热方案,这会导致模型更新过程中的耗时抖动比较高,无法支持模型的实时更新。通用计算调度框架采用同步机制,并发不足,CPU利用率低,无法满足高并发计算需求。那么,我们如何解决估算系统中的这些性能瓶颈呢?1.机器学习库的无缝集成我们为什么要做这样的事情?因为在传统的方案中,我们都知道特征处理和模型计算是部署在不同的进程中,这会带来更具体的跨网传输、序列化、反序列化、频繁的内存申请和释放。特别是当推荐场景的特征量特别大时,这会带来更明显的性能开销。下图中,上方的流程图展示了总体方案中的具体情况。为了通过无缝集成计算机学习库来解决上述问题,我们将高性能计算学习框架集成到估计系统中。这样做的好处是我们可以保证特征处理和模型计算可以部署在同一个进程中。以指针的形式实现对特征的操作,避免了序列化、反序列化和网络传输的开销,从而在特征计算和特征处理方面带来更好的计算性能提升。这是无缝集成的机器学习带。福利来了2.架构设计考虑首先,整个系统采用全异步架构设计。异步架构的优点是外部调用是非阻塞和等待的,所以异步机制可以保证在CPU负载很高的情况下,比如60%到70,仍然保持网络服务的耗时稳定性%。二、内存访问优化。内存访问优化主要是基于服务器的NUMA架构,我们采用绑定核心的方式运行。这样就可以解决之前NUMA架构中远程内存访问的问题,从而提高我们服务的计算性能。第三,并行计算。我们将计算任务切分,采用多线程并发的方式进行计算,可以大大减少服务时间消耗,提高资源利用率。架构设计注意事项以上是我们在估算系统的系统架构注意事项时的做法。3.多级缓存多级缓存主要用在特征查询阶段和初级阶段。我们封装的缓存机制,一方面可以减少查询的外部调用,另一方面也可以减少特征提取带来的重复无效计算。通过缓存,可以大大提高查询和抽取的效率。特别是在查询阶段,我们根据特征的重要程度和特征的量级封装了多种组件,如同步查询、异步查询、特征批量导入等。第一种是同步查询,主要适用于一些重要的特征。当然,同步查询的性能并没有那么高效。二是异步查询,主要针对“艾特维度”的一些特点。这些特性可能不是那么重要,所以可以使用这种异步查询的方式。三是特征批量导入,主要适用于特征规模不是特别大的特征数据。我们将这些特征批量导入到流程中,实现特征的本地化查询,性能非常高效。多级缓存4.模型计算优化介绍完缓存机制,我们再来看看模型计算的行为优化。对于模型计算,我们主要从三个方面进行优化:模型输入优化、模型加载优化、内核优化。模型输入优化在模型输入方面,大家都知道TFServering使用的是Example的输入。Example输入会包括Example的构造,Example的序列化和反序列化,模型内部调用ParseExample,会比较耗时。在下图中,我们看到了【优化前】的截图,展示了优化前模型的统计情况。我们可以看到,解析一个比较长的ParseExample是需要时间的,而且在ParseExample解析完成之前,其他op是无法进行并行调度的。为了解决模型树的性能问题,我们在评估系统中封装了一个高性能的模型输入方案。通过新的方案,我们可以实现零拷贝的特征输入,从而减少这个Example的构建和解析耗时。在下图中,我们看到【优化后】截图显示了模型计算优化后的数据统计。我们可以看到没有ParseExample解析耗时,只有ParseExample解析耗时。模型计算优化模型加载优化介绍完模型输入优化,我们再来看看模型加载的优化。Tensorflow的模型加载是一种懒加载模式。模型内部加载完成后,不会预热模型,而是等到网络官方请求过来后,再预热模型,这样会导致模型先加载后加载。会出现严重的耗时抖动。为了解决这个问题,我们在预估系统中实现了模型自动预热功能,实现了新旧模型的热切换,同时也实现了旧模型的异步卸载和内存释放。这样,通过对这些模型加载的一些优化方法,实现了模型的分钟级更新能力。内核优化接下来,我们看一下模型内核的优化。目前我们主要是在Tensorflow内核上做一些内核同步优化,我们会根据模型调整ops之间和ops内的一些线程池。以上是我们在模型计算方面的一些性能优化尝试。介绍完上面的性能优化方案,我们来看看最终的性能优化结果。性能优化结果这里我们使用预估系统和一般方案的系统进行对比。我们可以看到,当预估系统的CPU占用率达到80%时,整个服务的计算耗时和超时率非常稳定,非常低。通过对比,我们可以得出结论,新方案(预估系统)在计算和处理方面的性能提升了一倍,CPU提取能力更强,服务时间消耗更低。由于我们对系统的优化,我们可以为业务算法提供更多的模型复杂度计算和更多的候选集计算。上图中给出了一个例子。候选集从之前的300个候选集扩大到1000个候选集。同时,我们增加了模型的计算复杂度,使用了一些更复杂的特征,在多个业务中带来了比较。效果好提升。以上就是预估系统性能优化的介绍和性能优化的结果。如何提高开发效率1.系统分层设计系统采用分层架构设计。我们将整个估算系统分为三层,分为底层架构层、中间模板层和上层结构层。底层架构层主要提供异步机制、任务队列、并发调度、网络通信等。中间模板层主要提供与模型计算相关的组件,包括查询管理、缓存管理、模型加载管理、模型计算管理等。上层接口层主要提供Highlevel接口,业务只需要实现这一层接口即可,大大减少代码开发。通过系统的分层架构设计,底层和中间层的代码可以在不同业务之间完全复用,开发只需要专注于顶层少量代码的开发。同时,我们也在进一步思考,有没有办法进一步减少上层接口层的代码开发?让我们详细介绍一下。2.通用查询封装通过基于动态pb技术对特征查询和特征分析形成的通用解进行封装,可以实现特征查询、分析、Cache全过程。如下图所示,我们可以通过几行配置实现一个复杂的查询逻辑。同时,查询封装提高了查询效率。3、特征计算包特征计算可以说是整个估算系统中代码开发最复杂的模块,那么什么是特征计算呢?特征计算包括离线过程和在线过程。离线过程其实就是离线样本,通过处理得到离线训练平台需要的一些格式,比如TFRecocd的格式。在线过程主要是对在线请求做一些特征计算,通过处理得到在线预测平台需要的一些格式。离线过程和在线过程对于特征处理的计算逻辑其实是完全一样的。但是由于离线过程和在线过程使用的计算平台不同,使用的语言不同,需要开发多套代码来实现特征计算,所以存在以下三个问题。难以保证一致性的根本原因是离线训练和在线预测难以统一特征处理逻辑。一方面会影响算法的效果,另一方面会导致开发过程中一次性验证成本比较高。效率低如果要增加一个新功能,需要开发多套代码,涉及离线和在线流程,导致开发效率非常低。重用很困难。主要原因是框架缺乏对复用性的支持,导致不同业务之间的特征计算复用非常困难。以上是特征计算框架中的一些问题。为了解决这些问题,我们将按照以下四个思路逐步解决。首先,我们提出了算子的概念,将特征计算抽象为算子包。其次,在对算子进行封装之后,我们构建一个算子库,可以提供算子在业务之间的复用性。然后,我们定义了一种基于算子的特征计算描述语言DSL。通过这种描述语言,我们可以完成特征计算的配置表达。最后,如前所述,由于线上流程和线下流程存在多套逻辑,会导致逻辑不一致,所以我们需要解决一次性特征的问题。以上四点就是我们如何封装特征计算框架。算子抽象要实现算子抽象,首先要实现数据协议的统一。我们使用动态pb技术,根据特征的原始数据信息,根据统一的数据对任意特征进行处理,为我们的算子封装提供了数据基础。接下来我们对特征处理过程进行采样封装,将特征计算过程抽象为解析、计算、组装、异常处理,并统一计算过程API,实现算子抽象。建立算子库将算子抽象出来后,我们就可以创建算子库了。算子库分为平台通用算子库和业务自定义算子库。平台的通用算子库主要是实现公司层面的复用。业务自定义算子库主要针对业务的一些自定义场景和特性,实现集团内的复用。通过对算子的封装和算子库的构建,实现特征计算的多场景复用,提高开发效率。计算描述语言DSL特征计算的配置表达式是指定义特征计算表达式的配置语言DSL。通过配置语言,可以实现运算符的多层嵌套表达,实现四种运算等。下图中的第一个截图展示了配置语言的具体语法。通过特征计算的配置语言,我们能带来什么好处?首先,我们可以通过配置完成整个特征计算,从而提高开发效率。其次,我们可以通过发布特征计算的配置表达式来实现特征计算的热更新。第三,训练和预测使用相同的特征计算配置,实现线上线下一致性。这就是特征计算表达式的好处。FeatureConsistency如前所述,特征计算分为离线过程和在线过程。由于线下线上多平台原因,逻辑计算不一致。为了解决这个问题,我们在特征计算框架中实现了特征计算框架的跨平台运行能力。核心逻辑采用C++开发,对外暴露C++接口和Java接口。在打包构建过程中,可以一键实现C++so库和jar包,保证特征计算可以运行在线计算C++平台和离线Spark平台或Flink平台,特征的表达计算可以保证特征计算。实现线上线下逻辑的一致性。以上就是特征计算的具体情况。让我们来看看到目前为止特征计算取得的一些成果。我们现在已经积累了120个算子,特征计算的DSL语言可以实现配置,完成整个特征计算。通过我们提供的跨平台运行能力,实现线上线下逻辑不一致的问题。下图截图显示,只需少量配置,即可实现整个特征计算过程,大大提高了特征计算的开发效率。以上介绍了我们对开发效率提升的探索。总的来说,我们可以通过系统的分层设计来提高代码的复用性,通过对查询、抽取、模型计算的封装,实现可配置的开发流程。4.模型计算封装模型计算也是封装的形式。通过配置表达式的形式,实现了模型的加载、模型的输入结构、模型的计算等,用几行配置就实现了整个模型计算的表达过程。实时模型实现让我们看一下模型的实时实现。一、实时项目背景我们为什么要做这样一个模型实时项目?主要原因是传统的推荐系统是每天更新用户推荐结果的系统。它的实时性很差,不能满足这种实时性要求高的场景,比如我们的直播场景,或者其他实时性要求。高场景。另一个原因是传统的样本制作方法存在特征交叉的问题。什么是特征遍历?下图是特征遍历的根本原因,因为在拼接样本的过程中,我们在“T-1”时刻使用模型估计结构,在“T”时刻与特征进行拼接,所以会出现问题的特征交叉。特征交叉会极大地影响线网推荐的效果。为了解决实时性问题和样本遍历问题,我们在估计系统中实现了这样一个实时模型解决方案。2.实时解决方案介绍从三个维度对模型的实时解决方案进行说明。样本实时生成模型增量训练估计系统实时样本实时生成。基于在线预估系统,我们将预估系统的特征实时实现到Kafka,并以RACEID的形式关联起来,保证样本秒级落地,解决特征问题穿越。模型增量训练。通过秒级放置样本,我们可以修改训练模块,实现模型的增量训练,进而实现模型的分钟级更新。实时预报系统。通过模型的分钟级导出,我们通过模型推送服务PushServer将最新的模型推送到在线预估系统,使得现场预估系统能够使用最新的模型进行预测。总的来说,实时模型方案是实现秒级放置样本,分钟级训练,分钟级在线更新模型。我们目前的模型实时解决方案已经在多个场景中实现。通过实时模型解决方案,在业务上有比较好的提升。上图主要展示了模型实时解的具体实验数据。我们可以看到增量训练,训练周期越短越好。通过具体数据我们知道,15分钟的效果远大于2小时、10小时、1天的效果。目前的模型实时解决方案已经有了一套标准化的接入流程,可以为业务批量带来更好的效果。以上分别从估算系统如何提高计算性能、如何提高开发效率、如何通过工程手段改进项目算法三个方面进行了探索和尝试。整个估价系统的平台价值,或者说整个估价系统的平台宗旨,可以用三个词来概括,即“快、好、省”。“快”指的是前面介绍的应用构建。我们希望通过不断的应用建设,让业务迭代更加高效。“好”是希望通过工程化的手段,比如实时模型的解决方案,通过特征计算实现线上线下逻辑一致性的解决方案,能够给业务带来更好的效果。“省”就是用更高性能的估计系统来节省更多的计算资源,节约计算成本。未来,我们将继续朝着这三个目标努力。以上就是我对云音乐评价系统的介绍,我的分享到这里就结束了,谢谢大家!