图像预处理库CV-CUDA开源,打破预处理瓶颈,推理吞吐量提升20倍以上。学习模型依靠其强大的视觉内容理解能力,可以对其进行各种处理和优化。但是以往在视觉模型的开发和应用中,我们更多的是关注模型本身的优化,以提高其速度和效果。相反,对于图像的预处理和后处理阶段,很少认真考虑如何优化它们。因此,当模型的计算效率越来越高的时候,相对于图像的前处理和后处理,没想到它们成为了整个图像任务的瓶颈。为了解决这样的瓶颈,NVIDIA携手字节跳动机器学习团队开源了众多图像预处理算子库CV-CUDA,可以在GPU上高效运行,算子速度可以达到OpenCV的100倍左右(在CPU上运行)。如果我们使用CV-CUDA作为后端来替代OpenCV和TorchVision,整个推理的吞吐量可以达到原来的二十多倍。此外,不仅速度有所提升,而且CV-CUDA在计算精度上已经与OpenCV看齐,训练和推理可以无缝对接,大大减轻了工程师的工作量。以图像背景模糊算法为例,用CV-CUDA代替OpenCV作为图像前/后处理的后端,可以将整个推理过程的吞吐量提高20倍以上。如果你想尝试更快更好的视觉预处理库,可以试试这个开源工具。开源地址:https://github.com/CVCUDA/CV-CUDA图像前/后处理成为CV瓶颈。很多从事工程和产品的算法工程师都知道,虽然我们经常只讨论“前沿研究”等模型结构和训练任务,但要真正做出一款靠谱的产品,这中间会遇到很多工程问题,但模型训练是最简单的部分。图像预处理就是这样一个工程问题。我们在实验或者训练中可能会简单的调用一些API,对图像进行几何变换、过滤、颜色变换等,我们可能并不特别在意。但是当我们重新思考整个推理过程时,我们会发现图像预处理已经成为性能瓶颈,尤其是对于预处理过程复杂的视觉任务。这样的性能瓶颈主要体现在CPU上。一般来说,对于常规的图像处理过程,我们会先在CPU上进行预处理,然后在GPU上运行模型,最后返回给CPU,可能还需要做一些后处理。以图像背景虚化算法为例,传统图像处理过程中的前/后处理主要在CPU中完成,占整体工作量的90%,成为该任务的瓶颈。因此,对于视频应用或3D图像建模等复杂场景,由于图像帧数或图像信息量足够大,预处理过程足够复杂,时延要求足够低,优化预/后处理算子。当然,更好的方法是用更快的解决方案替换OpenCV。为什么OpenCV仍然不够好?在CV中,使用最广泛的图像处理库当然是维护已久的OpenCV。它的图像处理操作范围非常广泛,基本可以满足各种视觉任务的前/后处理需求。但是随着图像任务负载的增加,它的速度已经有点跟不上了,因为OpenCV的大部分图像操作都是CPU实现的,缺少GPU实现,或者GPU实现存在一些问题。在NVIDIA和字节跳动算法同学的研发经验中,发现OpenCV中为数不多的有GPU实现的算子存在三大问题:部分算子的CPU和GPU结果精度无法对齐;部分算子的GPU性能比CPU还弱;同时存在各种CPU算子和各种GPU算子。当处理流程需要同时使用两种时,会增加内存和显存的额外空间申请和数据迁移/数据拷贝;比如第一题,结果精度无法对齐。NVIDIA和字节跳动算法的同学会发现,我们在训练的时候,是OpenCV的某个算子使用了CPU,但是在推理阶段,考虑到性能问题,我们改用了OpenCV对应的GPU算子。可能CPU和GPU结果的准确率无法对齐,导致整个推理过程的准确率出现异常。当出现这样的问题时,要么切回CPU实现,要么重新对齐精度需要很大的努力,是一个比较难处理的问题。由于OpenCV还不够好,可能有读者会问,火炬视觉呢?事实上,它会面临与OpenCV相同的问题。此外,部署模型的工程师更可能使用C++来实现推理过程以提高效率。因此,他们将无法使用Torchvision,需要转向OpenCV等C++视觉库。这不会带来另一个挑战:对齐Torchvision和OpenCV的准确性。总的来说,目前视觉任务在CPU上的前/后处理已经成为瓶颈,而OpenCV等传统工具无法很好地应对。因此,将运算迁移到GPU和CV-CUDA,一个完全基于CUDA实现的高效图像处理算子库,成为一种新的解决方案。完全在GPU上进行前处理和后处理,将大大降低图像处理部分的CPU瓶颈。GPU图像处理加速库:CV-CUDA是一个基于CUDA的前/后处理算子库。算法工程师可能会期待三点:足够快、足够通用、足够易用。NVIDIA和字节跳动的机器学习团队联合开发的CV-CUDA可以满足这三点。它利用GPU并行计算能力提高算子速度,对齐OpenCV运算结果,连接C++/Python接口时易于使用。CV-CUDA的速度CV-CUDA的速度首先体现在高效的算子实现上。毕竟是NVIDIA写的,CUDA并行计算的代码肯定是做了很多优化的。二是支持批量操作,可以充分利用GPU设备的计算能力。与在CPU上串行执行图像相比,批处理操作肯定要快得多。最后,得益于CV-CUDA适配的Volta、Turing、Ampere等GPU架构,在各个GPU的CUDA内核层面对性能进行了高度优化,以获得最佳效果。也就是说,GPU卡用的越好,其加速能力就越夸张。如上图背景模糊吞吐量提速图所示,如果使用CV-CUDA替代OpenCV和TorchVision的前处理和后处理,整个推理过程的吞吐量将提升20倍以上。其中,预处理对图像进行Resize、Padding、Image2Tensor等操作,后处理对预测结果进行Tensor2Mask、Crop、Resize、Denoise等操作。在同一个计算节点(2xIntelXeonPlatinum8168CPUs,1xNVIDIAA100GPU)上,处理帧率为30fps的1080p视频,使用不同CV库支持的最大并行流数。测试使用4个进程,每个进程的batchSize为64。对于单个算子的性能,NVIDIA和字节跳动的合作伙伴也进行了性能测试,很多算子在GPU上的吞吐量可以达到CPU的100倍.图片大小为480*360,CPU为Intel(R)Core(TM)i9-7900X,BatchSize为1,进程数为1。虽然很多pre/postprocessing算子不是简单的矩阵乘法和其他操作,为了达到上述高效的性能,CV-CUDA其实在算子层面做了很多优化。例如,大量采用内核融合策略,减少内核启动和全局内存的访问时间;优化内存访问,提高数据读写效率;所有算子异步处理,减少同步等待等耗时。CV-CUDA通用灵活的计算结果的稳定性对于实际项目来说非常重要。比如常见的Resize操作,OpenCV、OpenCV-gpu和Torchvision都有不同的实现方式。从训练到部署,对齐结果会做更多的工作。在设计CV-CUDA之初,考虑到在目前的图像处理库中,很多工程师都习惯使用CPU版本的OpenCV。因此,在设计算子时,无论是函数参数还是图像处理结果,都应尽可能与OpenCV的CPU版本对齐。操作员。因此,从OpenCV迁移到CV-CUDA只需稍作改动即可获得一致的计算结果,无需重新训练模型。另外,CV-CUDA是从算子层面设计的,因此无论模型的前处理/后处理过程是怎样的,都可以自由组合,具有很高的灵活性。字节跳动机器学习团队表示,企业中训练的模型很多,需要的预处理逻辑也多种多样。有很多自定义的预处理逻辑需求。CV-CUDA的灵活性可以保证每个OP都支持流对象和显存对象(Buffer和Tensor类,内部存储显存指针)的输入,从而可以更灵活地配置相应的GPU资源。每个op在设计开发时,不仅考虑了通用性,还按需提供定制接口,可以覆盖图像预处理的各种需求。CV-CUDA易于使用。很多工程师可能会觉得CV-CUDA涉及到底层的CUDA算子,应该比较难用吧?但实际上,即使不依赖更高层的API,CV-CUDA底层本身也会提供其他结构体,提供Allocator类,所以在C++中调整起来并不麻烦。此外,CV-CUDA在上层提供了PyTorch、OpenCV和Pillow的数据转换接口,工程师可以用熟悉的方式快速替换和调用算子。另外,由于CV-CUDA既有C++接口,也有Python接口,因此既可以用于训练场景,也可以用于服务部署场景。Python接口用于训练时快速验证模型能力,C++接口用于部署时更高效的预测。CV-CUDA免去了繁琐的预处理结果对齐过程,提高了整个过程的效率。CV-CUDA的C++接口forResize,如何使用CV-CUDA如果我们在训练过程中使用CV-CUDA的Python接口,其实会非常好用。只需几个简单的步骤即可在CPU上调整原始数据的大小。所有预处理操作都迁移到GPU。以图像分类为例,基本上我们需要在预处理阶段将图像解码为张量,并裁剪以适应模型输入尺寸。裁剪后,我们需要将像素值转换为浮点数据类型并归一化,然后传给深度学习模型进行前向传播。下面我们将从一些简单的代码块来体验CV-CUDA如何预处理图像以及如何与Pytorch进行交互。对于常规图像识别的预处理过程,使用CV-CUDA将预处理过程和模型计算运行在GPU上。如下,使用torchvisionAPI加载图像到GPU后,可以通过as_tensor直接将TorchTensor类型转换为CV-CUDA对象nvcvInputTensor,这样就可以直接调用CV-CUDA预处理操作的API来在GPU中完成对图像的各种处理。转换。下面几行代码将使用CV-CUDA在GPU中完成图像识别的预处理:裁剪图像和归一化像素。其中,resize()将图像张量转换为模型的输入张量大小;convertto()将像素值转换为单精度浮点值;normalize()对像素值进行归一化处理,使取值范围更适合模型训练。CV-CUDA的各种预处理操作的使用不会和OpenCV或者Torchvision中的有太大区别,只是简单的调整一下方法,计算已经在背后的GPU上完成了。现在借助CV-CUDA的各种API,已经完成了图像分类任务的预处理,可以在GPU上高效完成并行计算,轻松融入PyTorch中等主流深度学习框架的建模过程。对于其余部分,您只需将CV-CUDA对象nvcvPreprocessedTensor转换为TorchTensor类型,然后将其提供给模型。这一步也非常简单,转换只需要一行代码:通过这个简单的例子,不难发现CV-CUDA确实非常容易嵌入到正常的模型训练逻辑中。如果读者想了解更多的使用细节,还是可以参考上面提到的CV-CUDA的开源地址。CV-CUDA对实际业务的改进CV-CUDA其实已经通过了实际业务的考验。对于视觉任务,尤其是图像预处理复杂的任务,利用GPU巨大的计算能力进行预处理,可以有效提高模型训练和推理的效率。CV-CUDA目前应用于抖音组内的多个线上线下场景,如多模态搜索、图像分类等。字节跳动机器学习团队表示,内部使用CV-CUDA可以显着提升训练和推理的性能。比如在训练方面,字节跳动是视频相关的多模态任务。它的预处理部分不仅对多帧视频进行解码,还有大量的数据增强,使得这部分的逻辑非常复杂。复杂的预处理逻辑导致CPU多核性能仍然跟不上训练。因此采用CV-CUDA将CPU上的预处理逻辑全部迁移到GPU上,整体训练速度提升了90%。请注意,这是整体训练速度的提高,而不仅仅是预处理部分的加速。在字节跳动的OCR和视频多模态任务上,通过使用CV-CUDA,整体训练速度可以提升1~2倍(注:是模型整体训练速度的提升)。在推理过程中也是如此,字节跳动机器学习团队表示,在多模态搜索任务中使用CV-CUDA后,相比使用CPU进行预处理,整体在线吞吐量提升了一倍多。值得注意的是这里的CPUbaseline结果经过多核高度优化,本次任务涉及的预处理逻辑比较简单,但使用CV-CUDA后加速效果还是非常明显的。速度足够高效,可以打破视觉任务中的预处理瓶颈,使用起来也简单灵活。CV-CUDA已经证明在实际应用场景中可以极大的提升模型推理和训练效果,所以如果读者视觉任务也受限于预处理效率,不妨试试最新开源的CV-CUDA。
