视觉算法工业部署及优化学习路线分享
最近这个问题在知乎比较火,这里将本公众号两个作者的回答以文章的方式分享出来,希望对感兴趣的读者有帮助。
白神回答
这几天被华为的atlas板子折磨的够呛,加班之余,写点心得吧。
2017年:比你大一届,本人也是20届的渣渣硕士,刚刚上研的时候,和大多数“内卷儿”一样,我也很幸运被老板安排了“计算机视觉&图像处理&模式识别”的研究方向。屁颠屁颠的开始看cvpr,iccv的paper。回想起过去,那时的我年幼无知,在地平线的一台四卡服务器上非root权限一步一步的装好了caffe,开始跑起来了openpose的训练,原本以为我的炼丹生涯就这样正式开始了,没想到怎么都复现不到paper上的精度,当时对multi-scale的测试看半天还不懂怎么回事。经常被leader push进度,真心觉得自己菜得扣脚,很多时候都想放弃炼丹。一步一步,在工业界,从单帧图像上的目标检测,语义分割,实例分割,到人体姿态估计。再迁移到视频上的目标检测,语义分割,关键点检测。以及最后毕业论文的多目标跟踪。算是把整个工业界能用的cv模型都摸了一遍,领域内的经典paper也能做到信手拈来?起码,各种开源的检测框架(商汤的mmdet, Facebook 最早的mask rcnn,detectron1 (caffe2), detectron2 (pytorch), gluonCV)都用过并完成了自定义的项目,其中的源码也都是“随心”看过一遍,但是自己太蠢了,写不到这个水平的python和cuda代码,以及每次用完,对很多细节的设计只能感慨作者的牛逼。
2018年:一个偶然的机会,我开始看mxnet的源码(当时还是使用的symbol接口),看着看着,觉得这玩意和caffe代码好像,很多地方都是从caffe那里复用的,设计也比caffe灵活不少,毕竟粒度更细,安装也更加友好。我一步一步的学习mxnet官网上放出来的所有有关framework设计的知识,包括从“怎样设计一个高效的data loader”,“怎么样设计一个engine把框架中的所有组件schedule起来”,“以及怎么样更好的优化memory和减少数据IO”,“包括怎么样设计一套面向任何等级用户都友好的API”。原本以为自己掌握了设计DL framework的大体奥义,发现还是想太多了,在面对让自己从头实现一个框架的时候,我也只会用python定义class 包来包去,性能什么的就别说了,我的菜还是没办法改变,最终还是想自己的愚蠢低下了头。。。
2019年:又一个偶然的机会,我开始在大洋彼岸某个村的CSL做summer research,项目的需求是为他们实验室的一款深度学习编译器(target为fpga)去写一套opencl的backend。什么是编译器?什么是backend?什么是fpga?什么是opencl?一连串的问题对傻逼的我来说,一切都是未知。扒开这套编译器的codebase,我发现大部分代码都是从tvm那里借鉴来的, 于是,我又走上了tvm的学习之路,从tvm的design到完整的编译flow,包括底层的c++到与上层的python交互,以及autoTVM(那会Ansor还没出来)全部走了一遍。对于一个根本没玩过硬件开发板的我,这一切在当时来看是非常困难的,还好实验室有给力的Ph.D.们,在他们的配合下,我也成功把基于xilinx和intel fpga的opencl backend全部添加了上去。那会的我,觉得自己算是掌握了 编译器的大体奥义。可最终我还是想自己的傻逼低下了头,涉及到传统编译器中的llvm的设计,codegen的很多细节,我还是一无所知。。。回国后,又加入了某条的mlsys组继续做编译器,我随后又在glow的基础上,为硬件组的自研芯片MVP开发profile-guided的quantization工具链以及针对网络的每个layer开发了方便debug的可视化工具。
2020年:又又一个偶然的机会,被安排到了一家创业公司做intern,刚刚入职第一天就要求在2080ti上去优化一个超分4k视频。对于一行cuda代码都没写过的我来说,那是不敢想象的,项目负责人每两天催一次进度,连给我配tensorRT,学习如何写高性能cuda代码的机会都不给。我每天都活在自责与痛苦中,为什么我这么菜?这么垃圾啊?待我整完了从pytorch模型到onnx模型转换,再到trt的编译,以及为各种不支持的operator写完tensorRT的plugin,再到关于image的前后处理全部手写cuda kernel去和opencv硬碰硬。遗憾的是,整个inference还是没有跑起来,当我用尽了我当时力所能及的cuda的debug工具(cuda-gdb,cuda-memcheck,...)最终发现还是败在了模型的多张帧输入没办法做到CPU和GPU上的memory 对齐。就这次偶然的机会,我竟然学会了tensorRT的部署。仗着这个经验,我又把组里其他模型:OCR,简化版超清视频到TX2,NX,AGX,智能相机等设备上,用尽了各种能优化的框架ncnn,mnn (其中包括针对工业级的二阶段的OCR模型,det用tensorRT,reg用mnn的vulkan后端联合开多线程优化在TX2上达到real-time)也熟悉了很多不同的backend和指令集架构。原本以为,我已经掌握了深度学习CV模型落地的要领,直到这几天接到了要在华为的atlas 500板子上部署算法团队自己整的一套faster rcnn的二阶段检测模型以及tracking,几乎所有套件都要从头开始手写c++(借助FFmpeg对RTSP拉流,解码,udp报文传送,前处理,rpn生成proposals,proposal变anchor,anchor到bbox,kalman filter, hungary, track ID筛选 ...),我才发现自己的无知,模型部署真的是个大坑。
以上内容吹逼归吹逼,且当个故事听听就好。
其实我想表达的是 视觉算法的工业部署和落地是没有你想得那么容易的,dirty work(手写c++, cuda各种前后处理) 全靠你对于上层模型算法的理解,以及不同hardware backend设计的深刻认知。如果要利用编译技术,你又得对深度学习编译器中如何在design space中搜optim的值和手写template来达到半自动优化有很好的掌握,你才能真正把一个paper里吹的“天花乱坠”的model部署到一个理论算力能跟得上的设备上( 当然,real-time和power是很重要的指标)
从工业界的角度想要快速出活,真正要自学的话:
深度学习框架方面,读一读caffe的源码和设计理念,看看其中的cpu/gpu上的op是怎么写的。 深度学习编译器方面,读一读tvm的源码和设计理念,看看编译器是怎么把一个dl model经过relay IR 再到 tvm IR,再到不同backend的codegen。以及编译器对计算图的常见优化(算子融合,data layout等) 深度学习模型部署方面,针对nvidia的gpu,看看cuda,tensorRT的document,自己尝试着把一个检测或者分割的模型部署到实验室的机器上。针对移动端的cpu,gpu,看看mnn,学习下mnn的code design。很多非常好的profiling,可视化工具。针对fpga设备,可以看看hls,opencl,verilog。毕竟直接拿现成的tool把model中的op翻译成hls,opencl代码还不是非常高效,很多东西还是直接写HDL所带来的speed up才更直接。这就和很多时候在arm架构的cpu上去优化算法,直接手写汇编所带来的提升更加直接。
从提升自己内功的角度来看,认真啃好:“编译器,计算机体系结构,并行计算,编程语言设计,计算机系统,计算机网络,C++程序设计” 来说是更好不过了。
当然,一切的一切都得来源于你对上层DL算法都有了深入了解,知道每个layer是怎么跑的,输入的feature和输出的feature都是怎么存的,软件和算法层面都经历过怎样的加速,还有哪些加速是需要结合hardware来进行co-design的,你才能更好地把模型中的不同layer合理高效地部署到不同的hardware上。
给个结论:如果要真正想习得视觉算法的部署和落地,最快捷的方法,首先你需要有一个极为严格经常push你并且还活跃在代码一线的leader,然后还得有一个特定的业务场景和急迫的ddl。
现在以intern的身份带着一帮和我一样啥都不会的老弟老妹们一起探索着模型编译加速部署的大坑,欢迎加入我的打工人队伍(思谋科技),私信我简历即可。
BBuf回答
谢邀,我是19年开始逐渐接触CV中的一些算法部署,在NCNN,TensorRT,OpenVINO,NNIE和华为Atlas系列的各个框架上都有一些部署经历。另外目前作为一个新的小型Pytorch推理框架MsnhNet的核心开发者之一,感觉自己是比较适合回答这个问题的。我个人将从两个方面回答这个问题,第一个是怎么学的问题,第二个是怎么学得更好的问题。
算法落地部署怎么学?
我这里就以Hisi 3519A嵌入式开发版(AI硬件和工具链叫NNIE)为例,描述一下我的学习经历。
首先,拿到一块开发版我们做CV相关算法部署的人员最关注的应该就是它的CPU以及AI硬件的浮点峰值,这可以让我们后面在部署我们某个算法,某个网络的时候做到心中有数,具体怎么算或者怎么查看可以参考:浮点峰值那些事 。实际上,各个厂家的开发板都会提供对应的工具链和一些Benchmark数据。例如最近接触到的地平线旭日开发板就提供了包括Mobilenetv1/2/3,Yolov3/4/5,FCN/SegNet等常见视觉场景用到的网络的Benchmark数据,通过这些数据我们可以清楚的看到对于某个分辨率的图像跑特定网络的fps以及内存消耗等等。上面介绍的这些是我在拿到一个开发板进行部署之前关注的。
然后,在了解了硬件的一些关键信息之后,我们就可以花几天熟悉一下开发版对应工具链(也就是开发板的前向推理框架)和官方示例。一般来说特定的开发板使用厂商提供的推理框架性能应该是最高的,因为他分它们的AI芯片如NNIE一些通用框架(比如NCNN,MNN,Tegine等)是没有相关的底层加速实现的,例如nvida的显卡部署我们首选TensorRT,Intel的CPU首选OpenVINO,arm的cpu选NCNN或者MNN。一般来说特定开发版官方示例都提供了一些经典的视觉任务比如分类,检测使用它们的工具链进行部署的例子,我们要熟悉这些例子,特别关注一下如何Debug,内存释放等等。
再然后,我们就可以针对我们的某个任务在我们想要的硬件平台进行部署了。例如我要部署一个DeepSort框架到Hisi 3519A开发板上,首先我要保证我能在CPU上正常运行我们的DeepSort代码。然后将我们的DeepSort代码拆分成检测,Reid,卡尔曼滤波,帧匹配各个过程利用开发版的推理框架分别编码。我建议在部署一个工程的时候最好进行子任务的拆分,因为这样更容易让我们编码完成之后进行Debug的时候更容易找到是哪部分出了问题,不至于调试时长时间卡顿,降低工作效率。
最后,在我们部署完一个工程或者视觉任务以后我们最好再评估一下我们的网络耗时和Benchmark提供的数据是否能对应上,如果我们的某个网络性能明显低于Benchmark数据需要查看是否AI硬件被使用了,是否网络细节设计不合理等等。只有我们部署的项目的精度和速度在上线之后经过了大量数据验证,我们才能算完成了一个部署任务。
所以,我将自己部署一个工程的思路分享出来,这里面都是我认为应该学习的比较关键的点。希望能帮助到你。
算法落地部署怎么学得更好?
上面说了怎么学,这个只是基于一些已有的开源推理框架或者开发板对应的工具链进行开发。如果你想学得更好,我就不班门弄斧了。如果感兴趣可以搜索一下知乎的 AI移动端优化 这个专栏,从里面圈圈虫,章小龙,白牛,梁德澎等做优化部署的大佬们的文章可以看出,想要学得更好得尝试自己去做一些算法优化的活。
因为,算法部署用到的各个框架的核心技术就是针对特定硬件平台的底层优化,例如NCNN针对Arm平台使用Neon汇编优化,针对X86使用SSE/AVX2优化,针对GPU使用Vulkan优化等等。当然我知道一个人的能力是有限的,如果你仅仅是感兴趣而已,那么你可以选择只学习某个平台比如Arm CPU的优化技术。
我也是处于一边学,一边做的状态。个人认为NCNN是这个世界上最好的优化框架,如果你基础已经够了(例如你了解了Neon汇编,知道卷积的计算过程)可以参考NCNN源码进行学习,如果你不太了解可以参考上面那个专栏或者在GiantPandaCV的AI移动端优化专栏学习一些基础知识,先入门然后我们一起学得更好。
相关链接
GiantPandaCV网站:http://www.giantpandacv.com/ NCNN:https://github.com/Tencent/ncnn MNN:https://github.com/alibaba/MNN Tengine:https://github.com/OAID/Tengine https://github.com/msnh2012/Msnhnet
欢迎关注GiantPandaCV, 在这里你将看到独家的深度学习分享,坚持原创,每天分享我们学习到的新鲜知识。( • ̀ω•́ )✧
有对文章相关的问题,或者想要加入交流群,欢迎添加BBuf微信:
为了方便读者获取资料以及我们公众号的作者发布一些Github工程的更新,我们成立了一个QQ群,二维码如下,感兴趣可以加入。