上一篇文章,一个CV算法工程师的小反思 引起了很多人的赞同和共鸣,倍感荣幸。今天是正式工作后的第一年,打算做一件事,以后要持续记录自己的工作感想和生活状态。人这一辈子那么有限,作为一个普通人,也许我穷极一生也不会有什么大的成就可以让外人为我写下一个传记。但是我可以用自己的手记录下我这一生,吃过的苦,犯过的错,爱过的人,在和一些网友聊过之后,我发现我是芸芸众生中的一粒沙,那些自以为的经历其实在陌生的一个环境里也有人同样地经历着。希望我的文字可以激励那些人,希望我的错误可以警惕那些人。
算法工程师必备的技能
我的具体研究方向是计算机视觉算法工程师,众所周知,当我们在说起算法工程师的时候,大家一般都会把工程师说成调参侠,而那种天天看论文发论文的又被捧上天。其实不然,我想以我从业一年的角度来说,一个计算机视觉算法工程师需要具备的技能。
算法工程师的工作内容首先是每日三问:业务KPI达标了吗?badcase解决了吗?CornerCase优化了吗?你所有的工作的目的就是去解决这三个问题。所以日常的工作内容是看看什么Case没有解决,制定优化目标,迭代,再看,再优化,不断循环往复。看上去是不是觉得算法工程师这个工作简单,枯燥,无聊?
其实不然,因为我相信每一份工作都是有它枯燥简单的地方,大名鼎鼎的李飞飞,吴恩达这些数据科学家难道就没有做过调参的工作了?凡是不可以偏概全,我眼中的算法工程师要具备的技能点是这样的。
能意识到数据的价值和用法:顶尖的数据科学家肯定是会比一般人更理解数据的价值,以及做一个算法类的项目,需要用到什么样的数据,使用什么样的特征,有哪些需要考量的细节,在这个项目中的优化目标所关联的数据需求是什么。
能做好高效合理的算法选型:这一个我就是要打脸那些说算法工程师是调参侠的人了,你以为的调参侠是把一个学习率从0到1e-3挨个尝试,改改配置就行。实际上当接到一个新项目的时候,作为一个算法工程师是需要快速调研算法论文,并且制定算法优化方案的。并且很多时候这个子方向你是之前没有接触过,比如突然让你去从一个分类项目中去做一个跟踪项目,你需要在一周之内去调研业界的跟踪算法文章并理清楚跟踪算法的分类成绩,优缺点分析,核心思想分析,这一点没有论文积累是比较难的。优秀的算法工程师就是要具备这种快速选型并且抓重点,最后还能给出一个合理的算法选型。一般考虑的角度是(可部署性,精度指标,速度怎么样,有没有不支持的算子,是否开源等等)。话说在这一点上,没有人会傻到对一个新项目去复现没开源的SOTA论文。
全流程的把控能力:这方面算软实力,偏项目管理。正如我之前说的一个需求从定义,调研,方案制定,数据采集,标注,模型训练,Inference,SDK的集成。这一套流程都是要有时间节点的,不仅仅是项目负责人给的节点,算法工程师自身也要给自己定义节点并且高效把控。比如采集的安排要考虑采集方案的合理性,高效性。标注的时候要定义好标注边界,在你手里过的数据要要详细的记录,不然到时候数据找不到真是个很麻烦的事情。模型训练的时候从输入图片校对,target校对,inference代码,看着loss慢慢降下去了就可以安心喝个咖啡休息休息,这套流程其实就是一般的软件开发一样,不需要担心完不成的问题,但是要考虑风险,把控进度,注重细节,考验的是一个算法工程细不细的问题。
代码功底:算法工程师基本都是Python为主,python作为一种简单的语言使用起来当然非常方便。(不要用C++的高端来批判使用python的我们了,用C++写模型的训练那是憨憨或者是大神(yolo作者)干的事。python代码除了基础的操作,数字,字符串,类,装饰器等等,其他就是各种工具要用的数量,numpy, pandas, torch, opencv, multiprocess等,具体看你的研究方向了。在系统架构上,我觉得学习开源代码,比如PaddlePaddle和MMLab的代码都是非常好的学习资源。只不过我们所谓的架构是把一个算法项目的前处理,后处理,model_build, backbone,neck,head等等这些组件化的一种架构,但是我认为一些设计模式的思想还是和软件开发一样的,大量的工厂模式,观察者模式的思想在这些算法架构中都有体现。对于C++这方面,我之前也有执念要不要学CUDA,现在觉得不需要,我所任务的算法工程师的C++功底是要能高效完成逻辑上的处理,以及能够快速定位和调试遇到的bug,Cmake也要能看得懂,要有把算法模型部署上线的能力,对C++的基础类型,STL,指针,引用,多态,继承,命名空间,模板都熟悉。至于一些指令级优化,算子融合啥的,那都是专业的人去做了。
算法优化能力:这是个核心技能,一定要秉持着数据>算法>创新的思路去做一个项目,当优先级高的遇到了瓶颈了再去做下一个环节的事情。数据侧就是要不断去做badcase分析,按场景按类别去分好自己的训练数据,同样要对测试集,测试方案,测试指标要不断改进和优化。算法上则要考虑的是backbone的设计选择,neck的设计选择,head中target的设计选择,数据增强方案(这个比较重要,除了几何增强,还有像素级增强),更好的Pretrain模型,后处理的逻辑优化,大模型KD优化,类别不均衡的优化,难样本挖掘优化等。重点说下后处理,这个环节其实非常重要,很多时候基于逻辑的规则可以提高你模型一大半的性能,代码一般都简单,但是需要你去从数据反馈中挖掘这个规则怎么制定。创新性则是你的研究能力。
研究能力:很多论文其实价值不大,不是在于没有创新,而是在于这个创新都是为了“新”去做的,并且在那么一两个公开数据集上达到了比较好的效果就可以发论文来证明这个工作的价值。有时候实验了发现不好,就改一通网络,我已经看了很多篇加了deform_conv魔改网络的方案了。非常solid的文章当然值得尊重,比如之前看多目标跟踪的时候看完centertrack的时候,感觉这篇文章真的简单,温柔,有力量!不过我其实也不是吃不到葡萄说葡萄酸哈,能发顶会当然是大大的好哈。毕竟程序员往高了走,顶会顶刊,行业影响力是妥妥的硬通货!但是不过是工程还会做研究,调研论文,复现论文都是必备的技能,这块其实我觉得也是属于研究能力的范畴。
数学能力:很多人都说算法工程师对数学要求高,其实我不太清楚这个要求高具体指啥水平,但是起码公式推导是肯定要掌握的,不然很多论文也看不懂的,比如最近在看目标跟踪的文章,我感觉对数学水平还是有一定要求的,不然连傅里叶变换,卡尔曼滤波都整不明白,那真的没法玩,至于比这更高的数学要求,那就让那些数学家,研究员搞去吧。我反正是搞不了,爹妈就给我这脑袋,不是金刚钻我也不揽瓷器活。
聚焦一个方向:由点开始出发,算法一般就是推荐,搜索,NLP,CV,控制规划这些子方向。我本身是做CV的,所以对CV稍微比较了解一点,在CV里其实方向也非常多,传统图像处理,识别,检测,分割,单目标跟踪,多目标跟踪,人脸相关任务(属性,情绪,识别等等),GAN,显著性检测,异常检测,超分辨率,OCR,图像复原(去雾,去雨,去阴影,补全图像…),深度估计,ReID,SLAM,以及通用技术模型量化,剪枝,模型蒸馏,meta learning,迁移学习……。看到这应该明白为啥CV这么卷了吧,而且有些方向的门槛和技术栈比较高,比如SLAM,一般社招SLAM的话基本都是要有相关经验的,不然一个只做过分类任务的人去做SLAM估计会很吃力。我的想法就是要从一个小方向出发,在几个小方向内挖深,然后对其他大方向也触类旁通,这样才能有更好的进步。毕竟方向是不一样,能力需求还是差不多的。
算法工程师的技术成长
这一年下来,我感觉自己在技术上收获还是蛮多的,在这个大项目组里,检测,分割,分类,识别,关键点都有所接触,同事也非常nice,不同方向的同事平时也乐于分享自己技术栈里的工作和前沿文章。但是有点比较无奈的就是自己在算法创新这一点上还是有所欠缺。希望下一年的时间里,自己可以不断加强这方面的能力提升。
算法能力:当然是重中之重,leetcode不仅仅是招聘的筛选标准,也是锻炼一个人算法思维的重要手段。虽然不得不说hard的题一般都是有一些ACM的技巧性在里面,但是我认为一个成熟的算法工程师,一定是要有秒解easy题,对middle的题也要基本能cover得住。不然用技巧性,题目和业务不搭边这样的说法只能是掩盖自己思维能力不足的借口。这一点自己做得还不够好,还是要不断提高。
PPT和文字能力:对,没错,我要把这个放到技术篇。因为写PPT真的是个技术活!!!看了组内老大哥写的那PPT,技术逻辑条理分明,布局结构美观大气,讲PPT那个滔滔不绝的样子真是好莱坞大片一镜到底,绝了!!!作为一个有语言障碍的人,十分佩服,羡慕这样的人。不过我总结了大佬的PPT和演讲。做一个好的PPT,尤其是技术类的PPT,第一点就是要对自己的技术栈非常清晰,技术能力是绝对要过关。图和文字上,就是要以图代字,不能空洞,也不用浮夸,更不用像学校课件一样放一些动态特效。技术人员的PPT只要三个点:逻辑清晰,内容充实,一目了然。在美观性上,我下载了论坛和组内会议的优质PPT分析了下,所谓美观其实只要有个简约的背景,文字和图标最好一起用,多放一些柱状图,折线图等说明你的工作,时间线的汇报来个带箭头的图表述下。PPT这个东西,要积累模板,要理清逻辑,要整理材料,要抓住重点,要自信表达。希望自己和观众老爷们的PPT能力都可以不断进步,一时菜鸡不要紧,永远不行动才是最可怕的。
前沿技术的跟进:做算法这一点确实是和其他行业差异比较大的,算法的技术更迭特别快。要经常阅读前沿论文,也许不会直接拿来用,但是技术的优化细节是否有助于现有的项目这个其实还是需要考量一下的。不要用(不都是用老方法做项目)这样的说法来diss我,你要是这么想你就用10年的算法一直用,近3年的文章都不看,当有新的有价值的东西出来的时候等你知道了别人早就用上了,而且长时间不看论文。也会慢慢丧失对文献阅读和理解的能力,就和一个人长时间不写代码了就不会写代码一样。
现有的技术方案总结:仅仅根据自己比较了解的识别,检测,分割方面的一些总结。比较通用的算法侧优化是backbone(resnet resnext resnest efficientNet等大模型,mobilenet hrnet shufflenet等系列小模型),Neck(fpn, bi-fpn,panet等各种FPN层),比较实用的网络优化(deform_conv,se-net,cbam等attention结构),head优化(主要是target设计的方方面面,比如检测anchor-base和anchor-free之间的差异就是在于target和输出之间加了一个anchor作为桥梁),训练策略优化(主要集中在正负样本均衡,损失函数设计,比如过采样,欠采样,损失函数比如FocalLoss,triplet_loss,训练流程上比如OHEM等),训练参数优化(CosineLearningRate等LR方面的优化,AutoAugment、Mixup、CutOut等数据增强方面的优化),预训练模型(基于无监督大数据Moco等, 大分辨率pretrain, 最差也地ImageNet-pretrain了,这块NLP方面做的比较好,CV这块我比较看好无监督或者半监督的方法),新方案(ViT,DETR等transformer在CV里的各种应用)。知识蒸馏,大模型蒸馏小模型是每一个公司都会要的技术栈,可看hinto的开山之作,当时后面还有各种多teacher,加权等方案。最后就是训练数据的干净,对不同场景都能cover到,对于训练参数中的具体数值就跑模型看效果。以上是我这一年经验所总结的算法优化方向,重点在于总结方向,具体细节方法太多了就不一一赘述。就这一年的工作经验看来,很多时候不同的算法方案之间很多时候效果上实际差距其实不大,这一点在我跑ATSS的实验的时候也更加确定。但是有些东西比如attention_block,transformer,KD等确实是硬通货。做一个算法工程师最重要的素质是在海量的算法方案中理解,吃透那些真正的干货,然后不断在实践中去验证,并总结吸收到自己的脑子里。
后记:以后的时间啊,要做一个说书人,记录自己的所思所想,讲好一个故事,一个属于我的故事。在这个谁都不认识谁的网络世界里,输出我对这个世界的看法,激励和我曾经一样堕落的人,照亮和我一样前进的人,温暖和我一样坎坷的人。清除了所有的可能包含个人信息的痕迹,我想以后,在这个世界里,为自己,写一个故事,一个用一生来记录的故事。
参考资料
https://www.bilibili.com/read/cv22309254/
https://zhuanlan.zhihu.com/p/395255446/