首页 > 人工智能 > 人工智能 > 上线视频推理服务 使AI应用更高效
在爱奇艺视频图像增强项目中上线视频推理服务,通过优化将处理速率提升了10倍,GPU利用率稳定在90%以上。本文通过分享视频推理服务解决方案,帮助为解决利用率低的问题相关从业者提供一些思路。
背 景
已有方案
对于视频变换服务,出现在大多数工程师脑中的第一个方案,通常是先将视频拆成图像,然后调用原有的图像推理服务,最后将推理结果汇总处理,返回汇总结果。这个汇总结果可能是一系列图片,也可能是编码后的视频。
在视频图像增强项目中,编码团队改造了ffmpeg,完成解码→推理转换→编码整个过程。其中推理转换过程,采用了一个自定义的filter,用于前后处理和模型推理。速度比写硬盘方案快了不少,资源消耗也少了很多。
实际运行过程中,发现GPU利用率较低。主要原因是,CPU编码速度比GPU推理速度要慢。于是采用GPU硬件编码器,速度大大提升,GPU利用率有所提升,但是距离GPU计算极限还有较大差距。
这里需要指出一个普遍存在对GPU利用率(GPU utilization)的误解。手册中,GPU utilization含义是:
“Percent of time over the past sample period during which one or more kernels was executing on the GPU.”
也就是说,计算时间占总时间的比例。简单来讲,也就是GPU在干活时间中的比例。至于GPU干得累不累,需要用另一个指标(Occupancy)来衡量。可惜的是这个指标不是那么容易拿到。
那么要怎么让GPU工作更加饱满呢?有一个直接办法,就是加大计算任务规模。原来一次处理一张图片,现在一次处理16张图片。通常把一次处理样本的数量叫做batch size。对于多数图像模型来说,batch size大于16之后,处理速度不会有显著增加。调大batch size之后,吞吐量可能增加2-4倍,单张图片的处理延迟略有增加。
解码 → NV12转RGB → 前处理 → 模型推理 → 后处理 → RGB转NV12 → 编码
如果编解码在CPU上完成,推理在GPU完成,还会多出在内存和显存之间搬移数据的环节。1080p一帧图片RGB原数据大小为5.93MB。按两倍视频速率计算,一秒钟需要在内存和显存之间传输的数据量为:2x24x5.93x2=569.28MB。按照3GB/s的传输速度(Pageable Data Transform),大约需要190ms。也就是说大约20%时间,会花费在数据传输上。
优化方案介绍
一个典型的请求流程如下:
请求方发送任务请求到服务入口;
服务入口程序将任务信息,如视频来源地址/目标地址、回调地址等信息记录到数据库中;
工作程序(worker)读取任务数据库,执行推理逻辑,最后将处理结果上传到云端存储,并发送处理结果到回调地址。
其中,工作程序的推理环节是我们优化的重点和难点。
所有操作都在GPU完成,并且支持批量推理;
前后处理及推理过程都通过python脚本完成;
完整方案包括视频下载,处理,上传流水线并行服务。
本方案的第二特点是最独特的亮点,解决DeepStream内部黑盒操作方式,最大化使用自由度。我们采用用户自定义python脚本,来加载模型和执行推理,大大增加了业务适配和验证工作的速度。本方案提供的python环境预装了Tensorflow,PyTorch,cupy,opencv等常见的算法库,覆盖了大多数基本功能。同时也支持自定义CUDA kernel调用,解决长尾和性能需求。
一些模型还有复杂的前后处理要求。开始部署时,对资源的需求量比较少,通过脚本快速开发,将一些基础操作组合起来,实现业务快速落地,尽早评估模型效果,加快迭代速度。如果反馈结果比较好,业务扩大服务规模,资源需求变得庞大。这时我们可以针对计算瓶颈,使用CUDA API编写计算kernel,提高计算效率,节省大量成本。
我们最终的期望是,算法工程师可以自行使用SDK来调试推理功能,确认结果,以减少平台工程师介入。同时,SDK还提供了操作计时功能,可用于分析性能瓶颈。
常见使用场景是,一个服务通常会使用多个模型进行推理,然后使用boosting算法取得更加可靠的结果。本方案可以轻松支持多模型推理,只要显存容量满足需求,甚至可以同时对Tensorflow和PyTorch的模型进行推理。
在不同计算框架间,进行数据交换,是这个方案面临的重要问题。深度学习开发社区提出了DLPack协议,来解决这个问题。因为DLPack没有做数据搬移,性能损失可以忽略。这个协议一推出就得到PyTorch,mxnet,cupy等框架的支持。但是在项目开发时,Tensorflow还没有不支持DLPack功能。Google工程师建议,将显存数据搬移到内存中,生成一个numpy对象后,再发送到Tensorflow Session。这样一来,把数据保持在显存的设计就被打破了。我们通过编写了特殊的Tensorflow OP,解决了这个问题。这个OP将显存中的数据复制到指定变量中,推理时使用指定变量作为输入。但在使用这个特殊OP时,调用者需要保证传递的数据不能超过目标变量的空间。
值得庆幸的是,社区开发了tfdlpack-gpu来完成这个目标。这个特殊OP也完成了它的历史使命。
仅仅“算得快”还不能满足业务实际需求。我们将整个计算过程封装成一个统一服务:从开发调试,模型部署,到运行监控,形成了完整功能闭环。为了更好的提供开箱即用体验,我们提供了任务管理、监控、日志等API。算法工程师只需要提交模型和推理脚本,就可以在云端部署服务。调度系统可以根据待运行任务的多寡进行动态的扩缩容,也可以按照预先设定完成定时扩缩容。
在推广该方案中,我们遇到的一个最常见的问题是:推理时预处理结果和训练的样本不一致。视频解码完之后,拿到的结果通常是NV12编码,通过自定义的CUDA kernel转换成RGB编码。但是,因为不同运算单元的计算方式和取整误差的影响,CUDA kernel得到RGB编码与ffmepg拿到的结果存在1%-2%的误差。虽然人眼看过去没有太大区别,但是对模型结果却有不同程度的影响。此外,不同的图像缩放算法也给结果带来不小的影响。
解决预处理结果不一致问题,最直接的办法是使用视频推理服务对训练素材进行处理,用同一个预处理结果进行训练。这样方式,保证了训练和推理时的输入一致性。
短视频推理服务
在解决长视频变换问题之后,我们尝试将这个服务扩展到短视频推理业务上。短视频推理服务多用于审核、打标签等业务中,使用场景多为同步在线服务。这就对整个请求延迟要一定的要求。业务愿意用更多的资源来换取更低的请求延迟,所以这类服务在线上的GPU利用率比长视频服务更低。
要达到低延迟的目标,常见的办法是降低处理数据量。其中一个典型的方法是,只对短视频的关键帧做处理。一两分钟的视频,关键帧的数量为10到20个。这方式可以通过一次推理就能取得结果。
但是为长视频构建的流水线,在短视频上表现得并不好。因为在开始解码前,我们需要对硬件解码器做初始化,通常会花费大约110ms。推理的耗时大概也在100ms左右,实际端到端延迟是纯推理耗时的大约两倍。经过仔细阅读手册,我们发现一个解决办法:对硬件编码器进行重新配置,而不是重新初始化。拿到第一帧数据的时间从110ms缩短到15ms。最终得到的结果是,推理时间占比大于85%。
总 结
经过爱奇艺技术产品团队的细致调优后,视频图像增强项目最终吞吐速率比ffmpeg方案提升了10倍,相同的任务使用的资源量只有原来的10%。这样因为资源使用量减少了,所以视频图像增强项目中,运营同学就可以把节约的资源更多的用于扩大视频增强的覆盖范围。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69945252/viewspace-2704705/,如需转载,请注明出处,否则将追究法律责任。