平时比较喜欢做笔记复盘,做笔记看起来费时费力,其实是有比较多的好处:
- 及时进行巩固,避免过段时间遗忘,能快速找到之前的资料
- 在进行记录的时候其实也在将知识点转成自己的理解输出,强化理解,并且整个思路框架也会更清晰
- 每次进行复盘后,做的不好的地方下次改进,做的好的经验,继续保持,会更加地高效,这也是学习能力很重要的一部分
这里记录一下之前做的图像分类模型的一些经验总结,用目前多任务layer4的BN分流+swsl_resnext+cutmix+labelsmooth+均方采样+swsl101的js蒸馏,基本上可以在百万级别上,相比se_resnext提升3个点左右,如果数据少,提升会更明显
算法模型主要分为三个方面
- 建模
- 标签和数据
- 网络结构、tricks、蒸馏学习、半监督学习等
- 模型的训练和推理优化
1. 建模
需求确认、研发目标、研发要求主要包含这三点,下面是介绍一些流程。
建模是用算法模型解决实际业务问题,需要清晰知道什么样的业务场景用什么模型解决问题、很多系统都是由多个模型构成、模型能做到什么程度;需要结合具体的项目进行问题拆解,比如一个视频理解算法系统,会包含视频分类、实体分类、物品识别等,每个模型的定位是什么。每个模型可以做到多少范围的准确率,需要结合具体问题分析。如果是ToB业务,一定在建模的时候需要考虑竞品和客户的需求。
2 标签
标签决定数据,数据决定模型的天花板。
2.1 标签一定要紧密联系业务场景进行制定。比如在做图像分类模型的时候一定要结合业务问题和模型能力制定标签,以足球这个场景为例,比如图像分类出来的标签是做偏检索的,那么可以出足球场、球门、足球、运动员这种实体类的标签,如果是偏推荐,那么出踢足球、足球比赛、点球这种抽象或者更具有语义的标签好些。
2.2 标签建立一二三级分类,方便进行制定、管理和扩展。标签尽量覆盖面比较广,可以根据需求再进行细化这样,同时兼容不在标签体系中的标签(比如增加其他标签),方便后面拓展,提高标签鲁棒性;尽量不要做把标签从很多类砍到比较少的做法,如果留下比较少的标签这种做法可能出现验证集准确率高些,但在实际业务中针对一些标签体系外的图像的效果就不理想。
2.3 标签之间尽量有比较清晰的边界,减少交叉冗余的情况。如果交叉情况多,可以考虑把模型拆分成实体类、人物类、场景类这种多模型或者多标签,标签交叉冗余容易导致标签之前的误召;
2.4 获取细分类别标签。如果想把某个领域获取细分的结果,比如游戏这样的可以采用主干加分支的做法,这种主干+分支的准确率往往更高,因为如果主干有70多类游戏分支,那么分类器中游戏的权重比较重很容易把其他跟游戏相近的类别召回成游戏
2.5 标签来源。比如需要制定一个体育分支标签,那么可以搜集冬奥会和奥运会的体育项目,这样出来的标签起码能够覆盖比赛项目,避免标签上线发现某些部分标签覆盖不够。
2.6 未知类别的图像。1)将模型的适用范围限制在「应用程序将面对的物体与模型的训练数据匹配」的情况。要做到这一点,一个简单的方法就是对产品进行设计。你可以创建一个用户界面,指引人们在运行分类器之前确保摄像头画面中已经出现了要分类的目标,这和那些要求你对支票或其他文档进行拍照的应用程序经常做的是一样的。2)你可以编写一个独立的图像分类器,它试图去识别那些那些主图像分类器不能识别的情况。这和添加一个单一的「未知」类是不同的,因为它的作用更像一种级联操作,或者用做一个详细的模型前的过滤器。在识别农作物患病情况的例子中,视觉上的操作环境足够独特,所以只需要训练一个训练一个模型来区分叶子和随机选择的其他图片。这些照片之间有足够的相似性,而门模型至少应该能够识别出图片是否是在不支持的场景中拍摄的。该门模型将在运行完整的图像分类器之前运行,如果它没有检测到一些看起来像是植物的东西,它就会提前跳出程序并且返回表明没有发现任何植物的错误信息。(面对未知分类的图像,如何改进分类器、如何克服这个问题呢?-电子发烧友网 (elecfans.com))
3. 数据
3.1 数据同源。比如imageNet或者google搜图的图像跟视频中的图像会不一样,在imagenet图像训练出的图像在视频分析上往往效果会不好,在数据源有限的情况,是数据同源很容易提升效果;
3.2 数据规模越大越好。数据规模大到一定程度需要考虑投入和产出比,实际应用中,像图像分类每类1000-2000即可,太多了需要大量的标注成本,提升可能也有限,而且容易导入不平衡问题。如果想用大规模数据可以利用一些半监督学习的方法。
3.3 数据不平衡。可以采用均方/均衡采样,权重Loss,DWS,可以参考《Bag of Tricks for Long-Tailed Visual Recognition with Deep Convolutional Neural》,汇总一些经典不平衡方法,这些方法需要尝试在业务数据集上的效果。有时候可以提升均衡的验证集准确率不能提升业务测试集的准确率,因为业务测试集本身就是不平衡的。
3.4 半监督学习。可以用一些大模型训练出来在一些未标注的数据上进行机器标注,然后在人工标注,提升标注效率,该方法缺点是需要底库有已有类别数据;如果是没有这个类别的数据,可以采用标签搜视频,视频爬取-抽帧-聚类去重,人工二次标注的方法,好的点在于数据同源并且有大量数据源,不好的点是可能留下的图像并不是那么多。
4. 算法提升
4.1 验证集制定。验证集制定在整个算法预研很重要,尽量是线上业务数据并且进行多次标注确保验证集没问题,验证集尽量覆盖面广一些,否则容易出现算法在一个噪声多的验证集上出现各种奇怪情况,还有出现在非业务的验证集上提升了结果到了业务数据没有提升
4.2. 可以采用五分之一或者十分之一类别的数据进行快算法调研。快速迭代出一个比较好的超参数,最好是在一天内出结果,先不用任何tricks,看下训练集和验证集的准确率差距,一般在10个点左右,如果训练集比验证集多20个点,那么可能过拟合了,多用一些正则化,如果两者差不多,可能是欠拟合,那么多用一些过拟合,比如大模型、增加epoch、降低lsm参数
可以采用经验的参数gridsearch的方法进行微调,也可以用autogluon。
参数包括bs,lr,学习器,epoch,weight_decay,学习策略,网络的超参数,cutmix,随机深度,labelsmooth,dropout,蒸馏学习等等一些常用的超参数;
网络升级可以参考imagenet上的准确率,一般resnet50系列,在imagenet上准确率越高,预训练模型越好;
经验来说cutmix比mixup、cutout,randaug效果好,如果正则化多可以考虑降低一下weight_decay,用imagenet模型finetune一般lr=0.01,bs=256,epoch=30,SGD收敛慢但一般效果好些;
蒸馏学习使用JSloss比KLLoss效果好
4.3. 数据增强、网络升级、蒸馏学习一般都有提升,加上模型集成提升会更高。蒸馏学习需要减少10倍的学习速率以及增加训练周期,像bs、正则化、学习速率、学习器、wiamgeneteight_decay有些时候有提升,但有时候提升不明显,需要尝试;半监督学习在小数据集上效果好,标注数据数据量大的时候,需要未标注数据量更大比如上亿级别效果更明显
4.4 图像分类结果聚合生成视频维度结果。最简单出结果的是策略,但是策略比较依赖经验而且鲁棒性不一定强,可以采用图像分类标签+机器学习或者时序模型,需要多一些的标注数据
5.训练和推理优化
5.1 Apex混合精度训练。在基本确保准确率的情况下,能减少一半显存,提升将近一倍训练速度,提升训练速度大杀器,T4和v100,a100都支持;增加dataloader的num_worker;可以提前把图像进行resize好,在图像分辨率较大的时候提升较多;DALI也可以尝试下,在小模型上提升效果比较好,大模型提升比较少;增大batchsize会提升速度,但是需要调节lr,并且需要看下是否对准确率有影响
5.2 推理优化。常用的就是C++TensorRT加速或者Python的torch2trt,进阶的话可以使用int8量化,速度会更快,不过有些层比如SE模块就TRT优化不好,影响速度;网络上也可以优化,使用一些moblilenet+蒸馏学习的方法