哔哩哔哩大规模AI模型推理实践
本期作者
戴彦
哔哩哔哩资深算法工程师
杨典
哔哩哔哩资深开发工程师
一、背景
AI算法复杂度逐年上升,需要高效的方式支持AI模型的推理和部署。
随着应用规模的扩大,算力资源消耗也在快速增长,对线上资源产生极大的压力。
B站AI涉及计算机视觉(CV)、自然语言处理(NLP)、语音等多个场景,服务于内容安全审核、内容理解和创作的上百个应用场景。
二、挑战和目标
挑战
线上资源随着流量线性增长,在降本增效的背景下,希望控制线上资源的增长。
随着大语言模型在工业界的推广和落地,NLP场景部署了BERT,GPT,T5-Large模型,模型复杂度明显提升。
帧级别的视频处理。例如,在OCR(Optical character recognition) 场景下,24小时内累计处理超过10亿张720p图片。这给模型推理和模型服务带来了极大的压力。
流量的增长和算法复杂度的提升给线上服务的Response Time和QPS带来了巨大的挑战。
大量长尾场景需要有统一的方式接入。
目标
提高推理的吞吐,降低资源增长速度。
改进Response Time,提升服务的质量。
扩展新业务,落地更多场景。
三、InferX推理框架 介绍
针对上述的问题,我们自研了推理框架,内部研发代号InferX。架构图如下所示。
通用推理框架可以拆分为Interpreter, Graph Optimizer和Backend等组件。除了上述组件之外,InferX支持若干模型计算前链路优化,例如稀疏化和量化。
近期InferX迭代主要包括了如下几个方面。
支持ONNX链路,通过ONNX链路支持Tensorflow和paddle模型。提高模型的部署效率。
改进InferX运行时,优化资源获取方式,减少了CPU占用
模型前链路优化的能力:支持int8和sparsity
扩展了图像算子的能力。
四、InferX推理框架计算前链路
InferX计算前链路指模型在上线前进行的若干离线处理,当前主要包括量化和稀疏化。
模型量化:
相比于FP16, INT8 TensorCore的性能翻倍。
InferX实现了量化SDK,能够较为方便地进行模型量化。
PTQ量化已经在OCR和版权场景落地。
上图展示了InferX量化的流程。需要注意的是,InferX实现了TensorRT Lowering Graph Optimizer。如果跳过上述的Graph Optimizer,量化的模型将会没有任何加速。
下图显示了量化在版权模型推理场景的收益。量化模型精度近乎无损,同时实现了2x的加速比。
模型结构化稀疏:
NVidia从Ampere架构开始支持2:4稀疏方案,2:4 Sparsity能够利用Sparsity TensorCore的性能。
训练后pruning,与算法协同完成sparsity模型的链路
支持稀疏化构建
相比于dense的TensorCore,稀疏化TensorCore加速比为2x。但是由于稀疏化tensor-core只能作用于卷积,linear算子,因此,模型总体的加速比低于2x。例如,下图中,长尾kernel无法使用sparsity-tensorcore进行优化。
FP16 sparsity tensor-core在部分模型上有精度的问题,工程上可以通过混合精度计算解决。
五、使用InferX优化重点场景
—— 以OCR为例
项目背景:
OCR是审核能力的重要组成部分。
OCR需要进行逐帧的处理,需要消耗大量的计算资源。
需要注意的是,本章节讨论了如何优化一个重点场景,涉及到的技术不限于InferX。
模型适配:
由于OCR中存在第三方的算子,无法直接导出,针对这一缺陷,InferX支持了ONNX作为模型的交换格式,实现了ONNX Parser将ONNX模型转换为图中间表示。同时由于OCR中有第三方的算子可变形卷积(deformable convolution),需要在后端中添加算子的实现。后续deformable convolution这一技术在多个检测场景中都得到了复用。
基于CUDA的可变形卷积的实现
通过优化cuda算子提高性能
实现了NHWC 版本 deformable convolution,改进了im2col 操作的访存效率。
实现内存对齐,将矩阵乘法的m/n/k补齐到8的倍数,确保使用tensor-core进行计算(需要注意的是,这是CUDA11之前的约束,CUDA11之后,TensorCore的使用已经没有了上述限制)。
下图中展示NCHW和NHWC Layout在进行im2col时的差别,相比于原始的NCHW内存布局,NHWC是更加内存和Cache友好的内存布局,能够进行合并的内存访问(Memory Coalescing)。
基于结构化稀疏的模型加速
InferX支持稀疏化模型的构建并且支持显式定义层精度,解决精度问题。
识别模型加速大约为25%。
基于CUDA的JPEG Decoder优化
libjpeg的decode是CPU密集型任务, 过高的CPU占用会影响服务的稳定性并且由于libjpeg已经非常成熟,很难优化。
实现了inferx_cv 解码库,封装了nvjpeg,支持硬件解码,CUDA解码和CPU解码。
使用CUDA进行jpeg解码, cuda以非常低的GPU利用率解码jpeg,耗时仅为CPU的1/4。
视频/直播OCR资源复用和同步化改造
旧的架构中,视频/直播OCR是不同的模型服务。
旧的架构为异步执行的GRPC,但是视频/直播OCR的协议不同。
通过模型服务的同步改造,统一了协议,视频和直播共享模型服务,Response Time和服务的稳定性都得到了提升。
模型服务增加优先级的支持,直播请求有更高的优先级。
通过利用视频和直播服务的流量趋势的差异,大幅提高了线上机器的GPU利用率。
基于上述优化的OCR服务,能够以80%的GPU利用率稳定运行,并且保证服务具有较低的response Time。与未优化前相比,总资源数节省了63%。
六、Triton模型服务介绍
相比于推理框架,模型服务的关注点是不同的,更加侧重于提高吞吐和并行,提升整体资源利用率。
挑战:
对于不同业务使用的不用类型的模型,提供统一的工程链路帮助模型快速上线。
部门自研的推理加速框架InferX能缩短推理时间,但同样需要提高吞吐以增加GPU资源利用率。
很多业务使用了多个模型,模型间会有逻辑及依赖关系,需要对模型串联/并联提供编排能力。
针对上述问题,我们调研了常用的开源框架(Triton, TF-Serving等),最终选择了基于Nvidia Triton Inference Server的模型推理服务,它提供了以下功能:
支持多种深度学习框架,包括Pytorch,Tensorflow,ONNX,Python,DALI,TensorRT等框架生成的模型均可部署。并支持自定义的模型框架。
支持模型编排BLS。对于多模型串联/并联场景可以使用Python编写模型编排代码来完成(1)前处理,(2)分发tensor到各个模型推理并回收结果,(3)后处理的整个流程。
支持动态batch。即向模型服务发送请求不需要提前组batch,Triton可以根据需要自动完成组batch操作,并且可以配置batch的参数,如prefered batch size,queue size,default timeout等。
提供HTTP/gRPC client,可以方便推理服务上游分发侧接入。
支持Metrics,自动采集服务实时QPS,错误数,耗时,GPU利用率等参数。
七、Triton模型服务
+InferX推理框架
我们将InferX推理框架集成进Triton模型服务,则构成了AI模型推理的终极状态:低延时+高吞吐。
推理过程:
模型并发http/gRPC请求到达Triton后进入模型队列,根据请求到达时间动态组成batch,其实现效率远高于手动组batch,能使请求更加均衡。
batch请求通过模型编排脚本bls的方式,异步分发到各个子模型上,使用InferX推理框架的子模型通过推理加速,在最短的时间内完成推理请求。
对于多模型并联的场景,同样的输入tensor,多个模型实现完美的并行操作,并在内部异步回收结果,对外整体仍是同步接口。
对于多模型串联的场景,通过流水线复用覆盖了多个请求的网络传输及队列等待时间,使得GPU能够尽量少的处于idle状态。
同步返回推理结果,并且统一上报监控指标。
性能收益:
AI目前已经大量部署了Triton模型服务,相比于手写的python服务框架,平均单实例的吞吐都有3-8倍的提高,节省了50%的GPU卡数,压力测试下实现GPU利用率>90%。
结合InferX推理框架4-7倍的推理加速,基本上把显卡的性能压榨到极致,在不增加GPU采购的情况下支持业务流量增长。
八、总结
通过自研InferX推理框架+Triton模型服务部署,显著提升了计算资源使用效率,降低资源成本,保证服务响应时间和稳定,同时降低了ai服务开发部署成本,更快捷地支持各类型业务落地。
以上是今天的分享内容,如果你有什么想法或疑问,欢迎大家在留言区与我们互动,如果喜欢本期内容的话,欢迎点个“在看”吧!
往期精彩指路