最新CTR预测服务的GPU优化实践

news2024/12/23 15:37:06

CTR模型在互联网的搜索、推荐、广告等场景有着广泛的应用。近年来,随着深度神经网络的引入,CTR模型的推理对硬件算力的要求逐渐增加。本文介绍了美团在CTR模型优化的实践。通过分析模型结构特点,结合GPU硬件架构,我们设计了一系列流程对模型进行定制优化,达到了降低延迟、提高吞吐、节省成本的目标。

1 背景

CTR(Click-Through-Rate)即点击通过率,是指网络广告的点击到达率,即该广告的实际点击次数除以广告的展现量。为CTR指标服务的打分模型,一般称为CTR模型。我们可以将此概念进一步扩展到互联网应用中各种预估转化率的模型。CTR模型在推荐、搜索、广告等场景被广泛应用。相对于CV(计算机视觉)、NLP(自然语音处理)场景的模型,CTR模型的历史结构比较简单,计算量较小。美团的CTR模型一直沿用CPU推理的方式。随着近几年深度神经网络的引入,CTR模型结构逐渐趋于复杂,计算量也越来越大,CPU开始不能满足模型对于算力的需求。

而GPU拥有几千个计算核心,可以在单机内提供密集的并行计算能力,在CV、NLP等领域展示了强大的能力。通过CUDA[1]及相关API,英伟达建立了完整的GPU生态。基于此,美团基础研发平台通过一套方案将CTR模型部署到GPU上。单从模型预测阶段看,我们提供的基于英伟达T4的GPU深度优化方案,在相同成本约束下,对比CPU,提升了10倍的吞吐能力。同时,在典型的搜索精排场景中,从端到端的维度来看,整体吞吐能力提升了一倍以上。

除了提高吞吐、降低成本外,GPU方案还为CTR模型的应用带来了额外的可能。例如,在某搜索框自动补全的场景,由于天然的交互属性,时延要求非常苛刻,一般来说无法使用复杂的模型。而在GPU能力的加持下,某复杂模型的平均响应时间从15毫秒降低至6~7毫秒,已经达到了上线要求。

接下来,本文将与大家探讨美团机器学习平台提供的新一代CTR预测服务的GPU优化思路、效果、优势与不足,希望对从事相关工作的同学有所帮助或者启发。

2 CTR模型GPU推理的挑战

2.1 应用层的挑战

  1. CTR模型结构多变,包含大量业务相关的结构,同时新的SOTA模型也层出不穷,硬件供应商由于人力受限,会重点优化常用的经典结构,如ResNet。对于没有收敛的结构,官方没有端到端的优化工具可以支持。
  2. CTR模型中通常包含较大的Embedding表结构,要考虑到Embedding表存在显存放不下的情况。
  3. 在典型的推荐场景中,为了达到更快的POI曝光的目的,模型的时效性要求很高,在线模型服务需要提供增量更新模型的能力。

2.2 框架层的挑战

  1. 算子层面:目前主流的深度学习框架,如TensorFlow和PyTorch,可以说是深度学习第二代框架,它们首先要解决第一代框架Caffe的问题,Caffe有一个明显问题就是Layer的粒度过粗,导致那个时代的算法开发者都必须有“自己写自定义层”的能力。TensorFlow和PyTorch都把模型表达能力放在较高的优先级,导致算子粒度比较小,无论是对CPU还是GPU架构,都会带来很大的额外开销。
  2. 框架层面:TensorFlow和PyTorch本质都是训练框架,对算法开发者比较友好,但非部署友好。其中隐含了很多为了方便分布式训练做的设计,比如TensorFlow为了方便将Variable拆到不同的PS上,内置了Partitioned_Variable的设计。在基于GPU单机预测的场景下,这些结构也会带来额外的开销。

2.3 硬件层的挑战

第一,TensorFlow的算子粒度划分较细,导致一个模型通常由几千个算子构成,这些算子在GPU上的执行转变为对应的GPU kernel的执行。kernel是GPU上并行执行的函数。

GPU kernel大体上可以划分为传输数据、kernel启动、kernel计算等几个阶段,其中每个kernel的启动需要约10𝞵𝘀左右。大量的小算子导致每个kernel的执行时间很短,kernel启动的耗时占了大部分。相邻的kernel之间需要通过读写显存进行数据的传输,产生大量的访存开销。而GPU的访存吞吐远远低于计算吞吐,导致性能低下,GPU利用率并不高。

第二,GPU卡上包含多个计算单元,理论上,不同计算单元是可以跑不同kernel的,但实际上为了编程简单,CUDA默认假设在同一时刻一个Stream里跑同一个kernel。虽然可以通过多Stream的方式跑,但是多Steam之间又缺少细粒度的协同机制。

在经过充分调研与讨论后,我们决定第一期重点关注TensorFlow框架下如何解决常见CTR模型结构在英伟达GPU上执行效率不高的问题,我们先将问题收敛为以下两个子问题:

  1. 算子粒度过细,GPU执行效率低下。
  2. 模型结构多变,手工优化投入大,通用性差。

3 优化手段

为了解决上面的问题,我们对业界深度学习加速器进行了一些调研。业界比较成熟的推理优化方案主要是TensorRT/XLA/TVM。TensorRT采用手工优化,对一些定制的模型结构进行算子融合,并对计算密集型算子(如卷积)进行了高效调优。XLA是TensorFlow内置的编译优化工具,主要针对访存密集型结构,通过编译手段,实现算子的融合。TVM[2]具备较全面的优化能力,使用编译手段进行算子的融合,同时可以通过机器学习的方式实现计算密集型算子的自动调优。

经过广泛的调研和对比,我们最终选择了TVM作为优化工具。TVM通过编译手段,可以较好地应对多变的模型结构,解决了手工优化通用性差的问题。但TVM应用在业务模型也存在一系列问题:支持的算子数较少,而且目前对动态Shape的支持还不够好。针对这两个问题,我们将TVM和TensorFlow结合起来,结合CTR模型的结构特点与GPU的硬件特性,开发一系列流程,实现了对CTR模型的优化。

3.1 算子融合

通过将多个小算子融合为一个语义等价的大算子,可以有效减少GPU上的kernel数量。一方面,kernel数量减少直接降低了kernel发射的开销;另一方面,融合后的大kernel执行的计算量增加,避免了多个kernel间数据传输导致的频繁访存,提高了计算的访存比。

可以看到,上图中的左右等价结构,左侧的21个算子执行的运算,可以在1个等价算子中完成。反映到GPU的活动上,左侧至少有21个GPU kernel以及21次显存的读写,而右侧只需要执行1个kernel以及1次显存读写。对于每个融合后的算子,需要有对应的kernel实现。然而,模型的算子组合是无穷的,对每种融合后算子手工实现kernel是不现实的。TVM通过编译手段,可以自动进行算子的融合以及设备代码生成,避免了逐一手写kernel的负担。

3.1.1 TF-TVM自动切图优化

TensorFlow模型中,如果包含TVM不支持的算子,会导致无法执行TVM转换。我们的思路是将可以用TVM优化的部分切出来,转为TVM的engine,其他部分依然使用TensorFlow的算子。在XLA和TRT转换的时候也有类似问题,我们分析了TF-XLA和TF-TRT二者的实现:

  1. TF-XLA的实现方案,在Grappler[4]优化图之后,有一个POST_REWRITE_FOR_EXEC(通过这个关键字可以在源码中搜索到)阶段,在这个阶段,会执行三个针对Graph的Pass,分别是用来标记算子,封装子图,改写子图并构建LaunchOp。
  2. TF-TRT的实现方案,TF-TRT在Grappler中注册了一个优化器,在这个优化器中,找到连通子图,并将其替换为TRT Engine。

在最终方案实现上,我们参考了TF-TRT的设计。这个设计对比XLA的优势在于XLA切图方案与TensorFlow源码紧耦合,直接将XLA的三个Pass嵌入到了启动Session的主流程中。而切图策略,优化策略后续会有非常频繁的迭代,我们不希望与TensorFlow的源码太过耦合。我们扩展了TF-TVM的方案,在实际使用中我们把这个切图过程为一个独立流程。在模型部署或更新时,自动触发。

在推理阶段,优化过的子图使用TVM执行,其余的计算图使用TensorFlow原生实现执行,将两者结合共同完成模型的推理。由于TVM和TensorFlow的Runtime各自使用独立的内存管理,数据在不同框架间传输会导致额外的性能开销。为了降低这部分开销,我们打通了两个框架的底层数据结构,尽可能避免额外的数据拷贝。

3.1.2 计算图等价替换

TensorFlow模型中过多的不被TVM支持的算子会导致TF-TVM切图零碎,影响最终的优化效果。为了让TF-TVM切图尽量大且完整,以及让TVM优化过程中的融合力度更大,我们对模型中的一些复杂结构进行检测,替换为执行更高效或更易于融合的等价结构。

例如,TensorFlow原生EmbeddingLookup结构,为了支持分布式训练,会对Embedding表进行切分,产生DynamicPartition和ParallelDynamicStitch等动态算子。这些动态算子不被TVM支持,导致TF-TVM图切分过于细碎。为了让TF-TVM切图更完整,我们通过图替换,对这种结构进行修改,通过将Embedding分表提前合并,得到简化的EmbeddingLookup结构。

3.2 CPU-GPU数据传输优化

TVM优化后的子图被替换为一个节点,该节点在GPU上执行,通常有几十甚至几百个输入,该节点的前置输入(如Placeholder)通常是在CPU上执行,会涉及多次的CPU-GPU传输。频繁的小数据量传输,无法充分利用带宽。为了解决这个问题,我们对模型结构进行修改,在计算图中添加合并与拆分节点,控制切图的位置,减少数据传输的次数。

一种可能的合并方式是,对这些输入按相同的Shape和Dtype进行合并,后续进行拆分,将拆分节点切入TVM的子图一起优化。这种方式会导致一些问题,如部分子图的算子融合效果不佳;另一方面,GPU kernel函数的参数传递内存限制在4KB,对于TVM节点输入非常多的情况(如超过512个),会遇到生成代码不合法的情况。

3.3 高频子图手工优化

对于TVM无法支持的子图,我们对业务中高频使用的结构进行抽象,采用手写自定义算子的方式,进行了高效GPU实现。

例如,模型中有部分时序特征使用String类型输入,将输入的字符串转为补齐的数字Tensor,将int类型的Tensor作为下标进行Embedding操作。这部分子图的语义如图,以下简称SE结构(StringEmbedding):

这一部分结构,TensorFlow的原生实现只有基于CPU的版本,在数据量较大且并行度较高的情景下,性能下降严重,成为整个模型的瓶颈。为了优化这部分结构的性能,我们在GPU上实现了高效的等价操作。

如图所示,PadString算子在CPU端将多个字符串按最大长度进行补齐,拼接成一个内存连续的uint8类型Tensor,以便一次性传输到GPU。StringEmbedding接收到补齐后的字符串后,利用GPU并行计算的特性,协同大量线程完成字符串的切分与查表操作。在涉及规约求和、求前缀和等关键过程中,使用了GPU上的Reduce/Scan算法,编码过程使用warp_shuffle指令,不同线程通过寄存器交换数据,避免了频繁访存的开销,获得了很好的性能。

GPU Scan算法示意,一个8个元素的前缀和操作,只需要3个迭代周期。在一个有几十路类似操作的模型中,手工优化前后的GPU timeline对比如下图,可以看到H2D + StringEmbedding这部分结构的耗时有很大的缩减,从42毫秒缩减到1.83毫秒。

除了StringEmbedding结构,我们对StringSplit + ToNumber + SparseSegmentSqrt、多路并行StringEmbedding等结构都进行了高效融合实现,在优化流程中通过结构匹配进行相应的替换。

3.4 CPU-GPU分流

实际线上的RPC请求,每个请求内的样本数(下文称Batch)是在[1,MaxValue]范围内变化的,MaxValue受上游业务系统,其他基础系统能力等多方面因素制约,相对固定。如上图所示,以某个搜索服务为例,我们统计了线上的Batch数值分布,Batch=MaxValue的请求占比约45%,Batch=45占比7.4%,Batch=1占比2.3%。其余的Batch占比从0.5%到1%不等。对于GPU来说,提高单个请求的Batch能更好地利用硬件资源,发挥GPU的并行计算能力,表现出相对CPU更优的延迟和吞吐;当Batch较小时,GPU相对CPU的优势就不明显了(下图是我们测试同样的模型在固定压力下,CPU/GPU上延迟的变化)。

大部分请求都由GPU在做了,CPU资源有较多空余,我们将一些小Batch的碎请求放在CPU运行,这样可以让整个Worker的资源利用更加均衡,提高系统整体的性能。我们根据测试设定了一个Batch阈值,以及计算图在异构硬件上区别执行的判断逻辑:对于小Batch的情况,直接在CPU上执行计算图,只有Batch超过阈值的请求才会在GPU上推理。从线上的统计数据来看,整体流量的77%跑在GPU上,23%跑在CPU上。

在GPU的一系列优化策略和动作中,Batch大小是很重要的信息,不同Batch下优化出的kernel实现可能是不同的,以达到对应workload下最优的计算性能;由于线上的流量特点,发送到GPU的请求Batch分布比较细碎,如果我们针对每个Batch都优化一个模型的kernel实现显然是不够经济和通用的。因此,我们设计了一个Batch分桶策略,生成N个固定Batch的优化模型,在实际请求到来时找到Batch距离最近的一个Bucket,将请求向上Padding到对应的Batch计算,从而提高了GPU的利用效率。

4 压测性能分析

我们选取一个模型进行线上性能压测分析。

  • CPU模型测试环境为16核Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz,16G内存。
  • GPU模型测试环境为8核Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz,Tesla T4 GPU,16G内存。

下图对比了在不同的QPS下(x轴),GPU模型在各BatchSize下的推理时延(y轴)。GPU模型在BatchSize=128以下,推理耗时差异不明显,较大的BatchSize更有利于吞吐;对比BatchSize=256的GPU模型与BatchSize为25的CPU模型,在QPS低于64的情况下,二者推理耗时基本持平;QPS超过64的情况下,GPU的推理时延低于CPU。GPU的吞吐相比CPU提升了10倍。

同时,我们可以看到不同曲线的陡峭程度,CPU在QPS高出64后,时延会迅速上升,GPU则依然保持平稳,直到QPS超过128才会有明显上升,但仍旧比CPU更平稳。

5 整体架构

针对CTR模型的结构特点,我们抽象出了一套平台化的通用优化流程。通过对模型结构的分析,自动应用合适的优化策略,通过性能评估和一致性校验,保证模型的优化效果。

6 不足之处与未来规划

在易用性层面,目前的方案形式是提供了一套在线优化脚本,用户提交模型后,自动优化部署。由于涉及对计算图结构的分析、编辑以及TVM的编译等过程,目前的模型优化耗时较长,大部分模型优化耗时在20分钟左右。后续需要考虑加速TVM编译的效率。

在通用性层面,从我们的实际应用情况来看,TVM编译优化和高性能手写算子是最主要的收益来源。手工优化很考验开发同学对业务模型的理解和GPU编程的能力。编写一个高性能的融合算子已经不太容易,要做到有一定的迁移能力和扩展性则更有难度。

总的来说,CTR模型推理在GPU上未来需要考虑的问题还有很多。除了要基于业务理解提供更好的性能外,还要考虑模型规模巨大后无法完整放入显存的问题以及支持在线模型更新的问题。

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

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

相关文章

Zabbix历史数据与趋势数据问题详解

众所周知,历史数据(history)和趋势数据(trends)是Zabbix中存储收集到的数据的两种方式。官方文档显示,Zabbix历史数据是每分钟收集到的监控数据,趋势数据则是按小时统计计算后的平均数据&#x…

linux安装tomcat

目录 一、准备tomcat 法1 法2 二、上传tomcat到linux​ 三、解压tomcat 解压到当前目录 重命名文件夹 四、设置开放的服务或端口号或直接关闭防火墙 法1: 法2: 五、进入tomcat的bin目录,启动tomcat 进入tomcat的bin目录 启动tom…

LeetCode——Weekly Contest 321

这段时间经历了组会、开题、回家等等,这才发现周赛已经打到325场了,而我还没有写完321场的题解记录,真是汗颜啊。 LeetCode周赛第321场记录 这场周赛的题目相对比较简单一些,在此简单做个梳理: 这道题比较简单&#…

0xcdcdcdcd异常值引发C++程序崩溃问题的详细分析

目录 1、0xcccccccc、0xcdcdcdcd和0xfeeefeee等常见异常值的说明 2、由0xcdcdcdcd 异常值引发的内存访问违例问题说明 2.1、用户态内存地址与内核态用户地址 2.2、根据0xcdcdcdcd异常值初步估计出引发问题的原因 3、详细分析与问题解决 4、变量未初始化在Debug和Release下…

idea 创建 maven项目报错

问题报错 org.apache.maven.model.validation.DefaultModelValidator: method ‘void ()’ not found 第一次使用Maven创建工程,导入依赖的时候出现报错 idea版本:2021.2 maven版本:3.8.5 看了许多博客说把maven版本降低即可 参考文章&a…

技术栈入门------ElasticSearch

使用ElasticSearch的准备工作 一、在Linux上安装ElasticSearch 1、docker下载elasticSearch和kibana的镜像 docker pull elasticsearch:7.4.2 存储和检索数据 docker pull kibana:7.4.2 可视化检索数据 2、创建目录 mkdir -p /mydata/elasticsearch/config mkdir -p /myd…

[含文档+源码等]微信小程序校园生活小助手+后台管理系统前后分离VUE[包运行成功]

博主介绍:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 项目名称 [含文档源码等]微信小程序校园生活小助手后台管理系统前后分离VUE[包运行成功] 演示视频 视频去哪了呢?_哔哩哔哩_bilibili 系统介绍 本系…

简单对比一下VRRP和策略路由之间主备切换的差异

前面我们介绍的VRRP(),两台设备之间处于主备关系,也就是说,当主设备故障之后,流量才会切换到备设备上。这种使用方式一定程度上讲,不太符合经济适用的原则,我们前面介绍过链路聚合&a…

Java面试--SpringMVC请求流程

用户发送请求,请求被 SpringMVC 前端控制器(DispatherServlet)捕获;前端控制器(DispatherServlet)对请求 URL 解析获取请求 URI,根据 URI,调用 HandlerMapping;前端控制器…

求最长递增子序列

题目: 给定数组arr,返回arr的最长递增子序列 举例: arr [2,1,5,3,6,4,8,9,7] 返回最长递增子序列为 [1,3,4,8,9] 方法一:复杂度为O(N^2) 1. 生成长度为N的数组 dp,dp[i] 表示以arr[i] 这…

架构师必读 —— 逻辑模型(8)

利用框架整理信息 框架用于明确“整体结构”,也指“通过MECE分析法将整体构成要素进行大分类”。重要的是框架应是MECE分析框架,因为 一旦有遗漏和重复,就会导致混乱。整体构成要素可大致分为 3~7大类。 建议先确认目的后思考框架&#x…

实时单目追踪和稠密建图的算法框架:TANDEM算法

01 概述 最近在研究TANDEM算法,是一个实时单目追踪和稠密建图的算法框架。TANDEM的算法框架可以概括为如下的几个部分: 1、位姿计算----在关键帧实施基于滑窗的像素级集束优化; 2、追踪前端----实施直接稠密图片配准,基于全局模…

如何找回电脑回收站删除的文件, 10种恢复工具方法!

你想取回你的回收站删除的文件吗?无论是图像、视频还是文档,我们的设备都会存储所有内容。您可能不小心删除了数据,或者由于其他原因而消失了。要恢复您的文件,您可以访问技术人员或下载任何最好的文件恢复软件。 如果您选择第二…

怎样把电脑D盘合并到c盘?相邻的分区怎么合并到C盘

因为C盘是重要的系统盘,系统用户设置文件夹,包括各个用户的文档、收藏夹、上网浏览信息、配置文件,不能随意删除。如果C盘空间不足,就会影响到电脑的整体运行速率,会导致电脑卡顿,要想彻底地解决这种情况&a…

HTML期末作业课程设计期末大作业——电影网页制作

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置,有div的样式格局,这个实例比较全面,有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 精彩专栏推荐&#x1f4…

PHP序列化和反序列化漏洞学习

目录 PHP基础知识: 类的结构: 序列化 反序列化 魔术方法 字符串逃逸 PHP基础知识: 类的结构: 常见访问权限修饰符: public:公共的,在类的内部、子类中或者类的外部都可以使用,不受限制;p…

【GO】 K8s 管理系统项目[API部分--Daemonset]

K8s 管理系统项目[API部分–Daemonset] 1. 接口实现 service/dataselector.go // daemonCell type daemonSetCell appsv1.DaemonSetfunc(d daemonSetCell) GetCreation() time.Time {return d.CreationTimestamp.Time }func(d daemonSetCell) GetName() string {return d.Na…

高性能的Java IDE——IntelliJ IDEA v2022.3全新发布

IntelliJ IDEA,是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具,尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的。 I…

怎样在电脑上录制ppt课件?如何录制课件讲解视频

怎样在电脑上录制ppt课件?在当前的环境下,大部分学生都是在家进行上网课,本文就给大家分享几款非常简单实用的录制教学视频的工具。 一、PPT录屏 在windows系统中有个常用软件就是ppt,ppt也能够录屏,只是我们大家都忽…

postgresql数据库流复制

primary和standby在同一服务器的不同目录下。 primary: /var/postgre/data standby: /var/postgre/data1 1. 加账号 (也可以使用postgres账号) [postgresv-vlxsz-devdb01 data]$ psql psql (14.1) Type "help" for help. postgres# create role replica with r…