最近优化的是一个人脸伪造检测的项目,一些人脸检测的技术其实也都用得到,想总结一下有过的一些思路。很多东西我并不方便说的特别细,包括一些图,大概说一下就行,其实大家都不缺查资料学习的能力,查一下就知道了。我也是第一次做,没人问,这些可能都很常用,而且有很多想法也要验证,没想清楚,麻烦轻点喷。
项目介绍整个项目我认为是一个典型的CV类应用的一个推理优化,一开始是一个基于pytorch的串行的程序,跑在intel的cpu和Nvidia GPU上,整个流程大致上可以分为下列几个部分
- 数据读取。数据包括图片或者视频。
- 数据处理。这里我指的比较宽泛,数据输入一个GPU端模型之前所作的数据前处理或者后处理我都总包在这一块里面,举个例子,CV里面会有PriorBox、NMS、decode这些算法用来做图片处理的算法。我感觉这部分操作都是访存类型的操作,有很多都是向量拼接啥的。
- 模型。这里主要指的是项目所用到的神经网络模型比如人脸检测常用的efficientNet、mobileNet
主要是优化了这么一些东西。
- 数据读取层面的话我做profiling的时候,单张图片占比其实并不大,因此并没有做多线程读取。只是后期做流水的时候考虑了一下这个问题。
- 数据处理这一块其实问题挺多的,整个项目除开GPU端模型,很多工作都是在CPU端做的,比如说视频抽帧、解码、图片人脸框选取、过滤等等,这些时间占比很高,那其实可以考虑把这些python实现的算法通过cython调c的方式(调用C的方式很多,ctypes、c-ext等,但是我觉得这个是最好的,从开发成本和加速效果来说),然后在C代码里面通过openMP和向量化来做。或者也可以在这里直接封装cuda kernel,但是我没试过,我觉得也没必要,这部分算法都是一些访存密集型的操作我感觉
- 数据处理这一块还包括之前说到过的用到了openCV和一些专门用来做视频解码的加速库例如decord,这一块我觉得可以看看这篇文章吧:视频训练加速方法。这一块我没有深入的去做过。
- 还是在数据处理这一块,我发现写算法的那帮人一但用了pytorch就恨不得全部都用tensor,其实我觉得很多可以用Numpy来做的还是用这个来做。一方面,针对numpy有一个叫Numba的加速手段,挺方便的。另一方面,Tensor这个类型我是没有找到一个好的办法通过Cython把其指针传递给C函数。但是我这里有两个方法可以一试,一个是考虑Tensor.data_ptr,但是这个是int类型,可以在C函数那里强制转成指针试一下。另一方面,可以用Tensor.numpy(),这里我自己测试是和Tensor共享内存的,开销并不大,而意思就是说,cython接口那里的的参数可以写成Tensor.numpy()就行。
- 模型这一块的话其实在N卡上我觉得大家都是TensorRT吧感觉,主要是两个,一个是op不支持的问题,可以通过tensorRT plugin的方式,另一个,可以用一些量化的方法,TensorRT也支持int8 的QAT,需要懂一些量化的基本原理,实在不行半精度也是可以的。另外如果TensorRT转模型也觉得麻烦,也有一些工具例如说TRTTorch的开源工具,直接两句话就搞定了。我有一个正在试的想法,可以试试Taso转完,再丢回到TensorRT,没准效果不错,不清楚。
- 整个流程并行上其实用过这么一些方法、多进程数据拆分、MPS、affinity CPU绑核、batch推理,以及把功能做拆分,通过生产者-消费者的方式做流水。
- 然后是我这里并不是一次CPU处理->GPU模型计算的模式,CPU端和GPU端Tensor转移很频繁,这一部分原因也是因为给我的代码里面搞算法的经常动不动就.cuda(),然后又.cpu,一些Tensor操作其实pytorch既支持CPU端也支持GPU端的Tensor,而且不是计算类型的我自己觉得是没必要特意丢到GPU上做的,为此我测试过一些代码,分别用的GPU端的Tensor和CPU端Tensor,CPU端反而快点,而且没准还能减少.cuda()的次数。说回正题,这里一方面可以用pin_memory,进一步的话可以试试speedTorch。
现在大概就这么一些。我想深入做的其实包括模型优化那一块,感觉TensorRT就是一个黑盒子,没啥子意思,另一方面,一些openCV和视频解码的库也不好直接改,感觉其实时间占比也不少,值得了解一下原理自己实现。最后其实做优化最重要的就是性能测试,但是这种项目我感觉NV的两个profiling工具并没有那么好使,可以参考一下这个 profiling总结



