步步为营!高手教你如何有效使用深度学习解决实际问题

 

 

来自法国 Capgemini Invent 公司的高级数据科学家 Ahmed BESBES 三个月前参加了一个其公司内部的比赛:使用机器学习方法帮助海洋科学家更好的识别鲸鱼,根据鲸尾页突的外观作为主要特征。

比赛要求对于每一幅测试图像模型要给出最相似的前20幅图像,这不是一个简单的分类任务而是相似检索任务。

 

 

最终,Ahmed获得了第三名,他把在此过程中搭建模型的全过程详细分享了出来,并附上了其在各个步骤使用的开源工具,相信对那些想要使用深度学习解决实际问题的朋友肯定有帮助。

01  问题定义和选择正确的损失函数

 

第一种方法:分类

简单的做法是使用分类分数作为相似性排序的依据,但很不幸的是,这样做难以得到好的相似性排序结果。

这提醒我们,如果要体现个体之间的相似性,必须在训练阶段对样本进行显式学习和排序。

第二种方法:度量学习
学习有效的嵌入特征用于样本相似度比较和排序属于度量学习的范畴。
好在这是一个成熟的技术领域,对于想要入门的朋友可以看看:
https://gombru.github.io/2019/04/03/ranking_loss/
https://omoindrot.github.io/triplet-loss
作者使用了两种损失函数:
  • Triplet loss
  • ArcFace loss

 

Ⅰ、Triplet loss来自谷歌2015年论文 FaceNet。

 

 

使用Triplet loss 时作者又加入了如下训练tricks:

  1. 硬采样,即triplet (a, p, n) 满足不等式 d(a, n) < d(a, p)
  2. PK采样,保证每一个batch来自P个不同的类,每一类K幅图像
  3. 在线生成triplets

 

了解执行细节可以查看作者代码:

https://github.com/ahmedbesbes/whales-classification/tree/master

学习更多这些技术推荐阅读论文:

https://arxiv.org/pdf/1703.07737.pdf
Ⅱ、ArcFace loss 来自CVPR 2019。
论文中该算法在人脸识别问题中打败了 triplet loss, intra-loss, 和 inter-loss等。

 

ArcFace loss  相比 triplet loss有更好的特性:

  1. 对于类别很多的问题也表现的很好;
  2. 消除了训练triplet loss中的难样本挖掘的问题;
  3. 提供了漂亮的几何解释;
  4. 能够稳定训练;
  5. 收敛更快;
  6. 更重要的,实验发现仅需要一个ArcFace loss训练的单模型打败了5个triplet loss训练的模型的融合。

02  小心研究数据
功夫再高也怕菜刀!模型再好,数据质量不高也白搭!
作者花费了大量心思在数据上:
  • 去除噪声和已经损坏的图像,比如分辨率很低的,或者鲸鱼的尾巴根本看不见的图像。
  • 去除那些只含有一幅图像的类别,这被证明非常有效。因为度量学习需要类别内部的上下文信息,所以只含有一幅图像的类别是信息不足的。
  • 检测并提取鲸尾页突的图像,以去除大海、水花等的干扰,这一步扮演了注意力机制的角色。作者标注了大约300幅鲸尾页突的图像,训练了一个YOLOv3检测器,使用的标注工具来自:https://www.makesense.ai/ ,YOLOv3的训练代码来自:https://github.com/ultralytics/yolov3

 

学习要点:我们应该在合适且干净的数据上赢得更多的精度提升,而不是努力做花里胡哨的模型。

03  不要忽视迁移学习
作者最开始使用ImageNet数据集上的预训练模型(renset34, densenet121等)作为骨干网,后来发现了一个类似比赛 Kaggle Humpback Whale Identification ,尽管两个比赛中鲸鱼属于不同种,但将ImageNet预训练模型在Humpback数据集上微调后获得了巨大的精度提升!使作者的方案一下跳到了前几名,而且收敛更快(减少了30%的epochs)。

 

学习要点:

  • 迁移学习往往是有效的,且很少会带来伤害,如果可以请把ImageNet预训练模型在与你的问题相似的数据集上进行微调是很有必要的;
  • 迁移学习是增加训练样本的间接方式。
04  输入图像分辨率影响很大
在该问题中因为拍摄的设备很专业,很多图像很大,可以达到3000×1200像素或者更大。

作者首先使用224 x 224分辨率的图像,后来改成大一些分辨率的图像,得到了明显的精度提升,最后发现 480×480是对这个问题最好的输入大小。

学习要点:

  • 如果你在处理高分辨率图像,尝试较大的分辨率是不错的选择,大分辨率能够让模型学到特别小的细节特征,有助于样本个体间的区分;
  • 并不是越大越好,过大会使得训练收敛更慢,且如果原来数据中图像较小,resize到过大分辨率会带来精度下降,因为原有信号被破坏了。
05  网络结构的选择
业界有很多流行的深度学习架构如 VGG 或 ResNet,还有很多新出的复杂架构 ResNet-Inception-V4 、 NASNet等。到底如何选择呢?

作者经过三个月实验,作者总结出如下结论:
学习要点:
  • 大而深的SOTA骨干网并不总是最优选择,如果你的数据量不大,这些模型会快速过拟合,而且如果你计算资源有限,你也不能训练它们。
  • 一种比较好的做法是,最开始选择简单的网络,在验证集上监控性能变化,逐步增加模型复杂度。
  • 如果你计划把你的方案部署到网页端,则必须要考虑模型大小、内存消耗、推断时间等。
06  设计一个鲁棒的流程
作者模型训练的5个步骤如下:

特别值得一提的是,作者使用了种类繁多的增广方法:高斯噪声和模糊、运动模糊、模拟随机下雨、颜色偏移、随机颜色(亮度、饱和度、色度)改变、锐化、随机透视变换、伸缩变换、随机旋转、仿射变换、随机遮挡。
具体细节可以在代码中查看:

https://github.com/ahmedbesbes/whales-classification

07   通用训练技巧
  • 固定种子保证模型可重复性

在PyTorch中可以使用如下代码:

import randomimport numpy as npimport torchrandom.seed(seed)torch.manual_seed(0)np.random.seed(0)torch.backends.cudnn.deterministic = Truetorch.backends.cudnn.benchmark = False
  • Adam是安全的优化器,但不要忘记把weight decay 设置为非0值。作者使用了1e-3。
  • 大量的数据增广确实改进了模型精度,强烈推荐使用:albumentations
    (https://github.com/albumentations-team/albumentations)
  • 选择合适的学习率调度方案,避免模型陷入局部极小值。作者使用了warmup 调度机制后面加cosine退火的方法。
  • Loss 和其他度量结果的监控,作者使用了 Tensorbaord。
  • 使用伪标签往往可以带来精度提升。这在kaggle竞赛中经常被使用,它使用训练好的模型预测测试数据的类别,将置信度很高(比如大于0.9概率)预测结果的样本加入训练样本,重新训练模型。
  • 最好有强大的硬件支持,训练速度快,可以快速验证改进策略。
  • 保存训练好的模型,跟踪并记录模型的表现。
08  最终方案:从嵌入到元嵌入
作者训练了两个模型,如下:

 

作者将此二模型联合起来,使用元嵌入的方法,这是一种在NLP中经常使用的方法。

学习要点:
  • 元嵌入特征连接的方式在模型差异比较大的时候能够提供有意义的结果,比如:骨干网不同(resnet34 vs densenet121), 图像输入大小不同 (480 vs 620), 正则化模式不同 (dropout vs no dropout)的模型;
  • 每一个不同的基模型看到不同的事物,把它们联合能够产生新的增强混合模型(这个解释太朴素了——CV君)。
  
传送门
原文链接:

A Hacker’s Guide to Efficiently Train Deep Learning Models

https://towardsdatascience.com/a-hackers-guide-to-efficiently-train-deep-learning-models-b2cccbd1bc0a

开源地址:

https://github.com/ahmedbesbes/whales-classification

更多阅读:

文中作者使用了ArcFace Loss,今年一种新的更好的Loss出现了:

       
旷视提出Circle Loss,革新深度特征学习范式 |CVPR 2020 Oral

转载请注明:《步步为营!高手教你如何有效使用深度学习解决实际问题