算法工程师老潘总结的一些教训
前一段时间始终在优化部署模型。这几天终于来了需要,又要开始重操训练一些新模型了。趁着这次机会总结了下之前的一些训练模型的笔记,可能比拟杂,抛砖引玉!当然这是不齐全统计的教训,除了训练局部,还有很多部署的坑没有写。
- 算法工程师 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 为模型执行的毫秒,不过有些工作如果输出图像特地大,那么这样算是不行的,咱们须要思考理论图像传输的工夫,是否本机、是否跨网段等等。
撩我吧
- 如果你与我气味相投于此,老潘很违心与你交换!
- 如果你喜爱老潘的内容,欢送关注和反对~
- 如果有问题想要分割我,可加公众号间接私信,点这里!