算法工程师老潘总结的一些教训

前一段时间始终在优化部署模型。这几天终于来了需要,又要开始重操训练一些新模型了。趁着这次机会总结了下之前的一些训练模型的笔记,可能比拟杂,抛砖引玉!当然这是不齐全统计的教训,除了训练局部,还有很多部署的坑没有写。

  • 算法工程师50%的工夫是和数据打交道,有时候拷贝数据(别离从多个文件夹拷贝到某一文件夹);有时候筛选数据(过滤掉一些品质不好的数据);有时候把数据换个名字、加个前缀(为了后续训练的时候辨别数据的个性,比方多尺度、多种图像增强策略)等等,这些工作可能一个月要反复n屡次,因而最好总结起来;能够用Python或者shell脚本来解决,或者用jupyter notebook存本人罕用的文件解决代码。
  • 如果你不分明拿到数据的起源和牢靠度,能够先用 find ./ -size -1k -exec rm {} \ 等命令简略过滤一下,方才这个命令是扫描1k(或者其余值)以下的损坏图像并删除掉,当然也能够设置其余的参数。很多时候给你的图不肯定都是失常的图,最好提前筛一遍,要不然后续解决很麻烦
  • 并不所有的数据都曾经有标注信息,如果收集了一批数据要拿去标注,正好公司也有标注人力,能够尝试将这批数据打上预标框让他们再去调整或者补充标框,这样效率更高些。至于预标框怎么打,能够先让模型训练一小批数据,训练个召回率高的小模型,而后预测打框就能够,也能够用一些老模型打框;不过有一个景象比拟神奇,标注人员在标注的时候,对于有预标框的数据,标注的品质反而变差了,尽管速度上来了,这是因为大部分标注人员不想调整,这时候须要你好好监督一下,要不然后续模型精度上不去大概率就是数据的问题。
  • 有时候模型的指标不仅仅看准招,当模型给他人提供服务的时候,要看PM那边怎么对待这个模型输入后果在理论场景中的应用成果;对于检测模型最终的输入分数,最终给到应用方的框个别是依据你获得分数阈值来设,设的低一点,那么框就多一点(召回率高),设的高一点,那么框就少一点(准确度高);不同形式不同场景设置不同的阈值有不同的成果,说白了模型成果好坏很大一部分依赖于场景;这个状况在理论我的项目中其实挺常见的,说白了loss也好, accuracy也好,都是很全面且软弱的评估指标。与模型构造以及评测的数据分布都有很大关系,具体如何抉择模型应该与利用场景强相干。
  • 当模型遇到badcase的时候,简略粗犷地减少模型的容量成果可能并不好;因为这个badcase大概率和场景强相干,这种状况下最好就是收集badcase,可能会有应用你模型的人给你提供badcase,但这种效率比拟低,看提供者的情绪or紧急水平;你能够间接捞一大批模型应用场景的query而后应用以后模型做检测,收集相应类别置信度比拟低的case,而后筛选进去;
  • 测试集很重要,测试集个别不是从训练集中切分进去的,从训练集中切分进去的是验证集;验证集个别用于判断这个模型有没有过拟合、有没有训练走火入魔啦,如果想用验证集来判断模型好坏的话,往往并不能代表模型理论的程度;最好是有测试集,而且测试集是和模型采集批次不同训练模型的时候比拟靠近实际水平的评估规范;如果没有测试集也能够看训练集的loss大略确定一下,一般来说只有不是demo级别的场景,模型不会轻易过拟合,咱们的训练集往往有很重的图像增强策略,每一个epoch可能图像散布都不一样,这时候其实也能够选取模型model_last
  • 再强调下,loss和准确率不是齐全反比的关系,loss稳定很失常,loss低了不肯定代表模型的mAP高;相同如果loss变高,模型的精度也不肯定差,有可能是loss设的不够好导致局部回升占主导,覆盖了另一部分失常的降落也很失常;
    相干探讨:https://github.com/thegregyan... 和
    https://www.zhihu.com/questio...
  • 计算检测模型的mAP,理论中在计算的时候是不思考指标框分数阈值的,也就是说咱们会将所有分数大于0的检测框送去计算mAP;但这里要留神,计算mAP是有max_num也就是最大检测出指标个数,依据工作需要可能是100、可能是500也可能是5000等等,当有这个限度的时候,此时框就须要依据分数来排序,取前100、前500或者前5000的框去计算;最初,如果咱们须要可视化后果在图上画框的话,这时候是能够卡阈值的,比方大于0.2分数阈值的要,要不然最终画进去的图会有很多碎框;最初的最初,别忘了NMS!
  • 测试转换后的模型是否正确,肯定要保障输出图像的统一;这里的统一指的是输出图像的数值必须截然不同,dif为0才行;一般来说咱们输出的模型的图像范畴是0-1,通道数个别是黑白也就是RGB,不过须要留神这个黑白是否是假彩色(有时候为了传输节俭资源会传灰度图再理论推理的时候变成黑白图,对于某种场景来说,假彩色和真彩色的精度相差不大),输出尺寸也要保持一致,是否须要padding(padding成0或者127或者255,这几种padding形式队对后果影响很大)、须要补成32的倍数、或者须要最大边最小边限度,肯定要保持一致;对于类别,这样测试模型才可能保障准确性。
  • 对于模型来说,如果之后思考上线。上线的形式很多种:能够pytorch+flask间接docker上线,也能够尝试libtorch上线,也能够TensorRT上线,当然也能够通过自研框架上线…等等等等。如果这个模型谋求精度,而且是线下某一时间段跑,并不是实时,能够尝试flask+docker的服务;如果这个模型的实时性很高,在设计模型的时候就要思考之后的上线,那就须要思考模型优化以及对应的服务器推理框架了能够尝试TensorRT+triton server;

持续老潘的含泪教训,紧接着AI算法工程师的一些含泪教训(一),除了训练模型阶段的留神点,这次更多的是一些部署方面的教训,心愿可能对大家有帮忙。仍然是抛砖引玉,持不同意见的小伙伴欢送留言!

  • 再次强调一下训练集、验证集和测试集在训练模型中理论的角色:训练集相当于老师安排的作业,验证集相当于模仿试卷,测试集相当于考试试卷,做完家庭作业间接上考卷预计大概率考不好,然而做完作业之后,再做一做模仿卷就晓得大体考哪些、重点在哪里,而后调整一下参数啥的,最初真正考试的时候就能考好;训练集中拆分出一部分能够做验证集、然而测试集千万不要再取自训练集,因为咱们要保障测试集的”未知“性;验证集尽管不会直接参与训练,但咱们仍然会依据验证集的体现状况去调整模型的一些超参数,其实这里也算是”学习了“验证集的常识;千万不要把测试集搞成和验证集一样,”以各种模式“参加训练,要不然就是信息泄露。咱们应用测试集作为泛化误差的近似,所以不到最初是不能将测试集的信息泄露进来的。
  • 数据好坏间接影响模型好坏;在数据量初步阶段的状况下,模型精度一开始能够通过改模型构造来晋升,加点注意力、加点DCN、加强点backbone、或者用点其余奇妙的构造能够减少最终的精度。然而在前期想要晋升模型泛化能力就须要减少训练数据了,为什么呢?因为此时你的badcase大部分训练集中是没有的,模型没有见过badcase必定学不会的,此时须要针对性地补充badcase;那如果badcase不好补充呢?此时图像生成就很重要了,如何生成badcase场景的训练集图,生成数据的品质好坏间接影响到模型的最终成果;另外图像增强也十分十分重要,咱们要做的就是尽可能让数据在图像增强后的散布靠近测试集的散布,说白了就是通过图像生成和图像增强两大技术模仿理论中的场景。
  • 当有两个数据集A和B,A有类别a和b,但只有a的GT框;B也有类别a和b,但只有b的GT框,显然这个数据集不能间接拿来用(没有GT框的a和b在训练时会被当成背景),而你的模型要训练成一个能够同时检测a和b框,怎么办?四种形式:1、训练别离检测a和检测b的模型,而后别离在对方数据集上进行预测帮忙打标签,管制好分数阈值,制作好新的数据集后训练模型;2、应用蒸馏的形式,同样训练别离检测a和检测b的模型,而后利用这两个模型的soft-label去训练新模型;3、批改一下loss,一般来说,咱们的loss函数也会对负样本(也就是背景)进行反向流传,也是有损失回传的,这里咱们批改为,如果以后图片没有类别a的GT框,咱们对于a的损失间接置为0,让这个类别通道不进行反向流传,这样就能够对没有a框的图片进行训练,模型不会将a当成背景,因为模型“看都不看a一眼,也不晓得a是什么东东”,大家能够想一下最终训练后的模型是什么样的呢?4、在模型的最初局部将head头离开,一个负责检测a一个负责检测b,此时模型的backbone就变成了特征提取器。
  • 工作中,有很多场景,你须要通过旧模型去给须要训练的新模型筛选数据,比方通过曾经训练好的检测模型A去筛选有类别a的图给新模型去训练,这时就须要搭建一个小服务去实现这个过程;当然你也能够关上你之前的旧模型python库代码,而后回顾一番去找之前的demo.py和对应的一些参数;显然这样是比拟麻烦的,最好是将之前模型总结起来随时搭个小服务供外部应用,因为他人也可能须要应用你的模型去挑数据,小服务怎么搭建呢?间接应用flask+Pytorch就行,不过这个qps申请大的时候会假死,不过毕竟只是筛选数据么,能够适当升高一些qps,离线申请一早晨搞定。
  • 目前比拟好使的指标检测框架,无非还是那些经典的、用的人多的、资源多的、部署不便的。毕竟咱们训练模型最终的目标还是上线嘛;单阶段有SSD、yolov2-v5系列、FCOS、CenterNet系列,Cornernet等等单阶段系列,双阶段的faster-rcnn曾经被实现了好屡次了,还有mask-rcnn,也被很多人实现过了;以及最新的DETR应用transformer构造的检测框架,上述这些都能够应用TensorRT部署;其实用什么无非也就是看速度和精度怎么样,是否反对动静尺寸;不过跑分最好的不肯定在你的数据上好,千万千万要依据数据集特点选模型,对于本人的数据集可能成果又不一样,这个须要本人拉下来跑一下;
    相干模型TensorRT部署资源:
    https://github.com/grimoire/m...
    https://github.com/wang-xinyu...
  • 再扯一句,其实很多模型最终想要部署,首要难点在于这个模型是否曾经有人搞过;如果有人曾经搞过并且开源,那间接复制粘贴批改一下就能够,有坑他人曾经帮你踩了;如果没有开源代码可借鉴,那么就须要自个儿来了!首先看这个模型的backbone是否有非凡的op(比方dcn、比方senet,当然这两个曾经反对了),构造是否非凡(不仅仅是一般的卷积组合,有各种reshape、roll、window-shift等非凡操作)、后处理是否简单?我转换过最简单的模型,backbone有自定义op,须要本人实现、另外,这个模型有相当多的后处理,后处理还有一部分会参加训练,也就是有学习到的参数,然而这个后处理有些操作是无奈转换为trt或者其余框架的(局部操作不反对),因而只能把这个模型拆成两局部,一部分用TensorRT实现另一部分应用libtorc实现;其实大部分的模型都能够部署,只不过难度不一样,只有肯多想,法子总是有的。
  • 转换后的模型,不论是从Pytorch->onnx还是onnx->TensorRT还是tensorflow->TFLITE,转换前和转换后的模型,尽管参数一样构造一样,但同样的输出,输入不可能是齐全一样的。当然如果你输出精度卡到小数点后4位那应该是一样的,然而小数点后5、6、7位那是不可能齐全截然不同的,转换自身不可能是无损的;举个例子,一个检测模型A应用Pytorch训练,而后还有一个转换为TensorRT的模型A`,这俩是同一个模型,而且转换后的TensorRT也是FP32精度,你能够输出一个随机数,发现这两个模型的输入比照,绝对误差和相对误差在1e-4的基准下为0,然而你拿这两个模型去检测的时候,放弃所有的统一(输出、后处理等),最终产生的检测框,分数高的完全一致,分数低的(比方小于0.1或者0.2)会有一些不一样的中央,而且处于边缘的hardcase也会不统一;当然这种状况一般来说影响不大,但也须要留一个心眼。
  • 模型的实践flops和理论模型执行的速度关系不大,要看具体执行的平台,不要一味的认为flops低的模型速度就快。很多开源的检测库都是间接在Pytorch上运行进行比拟,尽管都是GPU,但这个其实是没有任何优化的,因为Pytorch是动态图;个别的模型部署都会波及到大大小小的优化,比方算子交融和计算图优化,最简略的例子就是CONV+BN的优化,很多基于Pytorch的模型速度比拟是疏忽这一点的,咱们比拟两个模型的速度,最好还是在理论要部署的框架和平台去比拟;不过如果这个模型参数比拟多的话,那模型大概率快不了,理由很简略,大部分的参数个别都是卷积核参数、全连贯参数,这些参数多了天然代表这些op操作多,天然会慢。
  • 同一个TensorRT模型(或者Pytorch、或者其余利用GPU跑的模型)在同一个型号卡上跑,可能会因为cuda、cudnn、驱动等版本不同、或者显卡的硬件功耗墙设置(P0、P1、P2)不同、或者所处零碎版本/内核版本不同而导致速度方面有差别,这种差别有大有小,我见过最大的,有70%的速度差别,所以不晓得为什么模型速度不统一的状况下,无妨思考思考这些起因。
  • 转换好要部署的模型后,个别须要测试这个模型的速度以及吞吐量;速度能够间接for循环推理跑取平均值,不过理论的吞吐量的话要模仿数据传输、模型执行以及排队的工夫;一般来说模型的吞吐量能够简略地通过1000/xx计算,xx为模型执行的毫秒,不过有些工作如果输出图像特地大,那么这样算是不行的,咱们须要思考理论图像传输的工夫,是否本机、是否跨网段等等。

撩我吧

  • 如果你与我气味相投于此,老潘很违心与你交换!
  • 如果你喜爱老潘的内容,欢送关注和反对~
  • 如果有问题想要分割我,可加公众号间接私信,点这里!