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。