博主不是专业搞竞赛出生,仅依赖博主为数有限的工程经验,从工程实践的方面讨论如何把深度学习模型训练好。如果写的不好,欢迎各位大佬在评论区留言互动。训练好深度学习模型与训练深度学习模型差别还是很大的,训练好需要保证模型的性能与泛化能力,这里有许多的工作需要完成,如分析数据分布,分析模型结构,分析特征提取方式与梯度传递时的不足。而训练深度学习模型只需要代码中的前行传播与反向传播流程是正确的即可。
训练深度学习模型,本质就是用好三个函数,一:构建假设函数(也就是我们的深度学习模型),用于实现对具体任务输入特定数据,输出特定结果的功能;二:构造代价函数(也就是模型的loss),用于评估假设函数预测值与真实数值之间的差异,差异越小则loss值越小;三:实现迭代函数,用于求解代价函数拟合数据loss最小的权重w。这只是一个较泛的概率,在实际操作中,我们并没有做那么多,而是依赖于现有的深度学习框架进行调用。这里需要注意的是,针对不同的任务,loss函数可能是不一样的。
针对深度学习模型由很多评价指标,针对分类模型有acc、recall、precession、f-socre,auc面积等,针对语义分割模型有iou、dice系数等,总之针对不同的任务类型,有不同的评价指标。在这里训练好深度学习模型,博主只谈两个关键指标:拟合效果与泛化能力。
拟合效果也就是指loss值的大小,拟合效果越好,loss越小。因为训练模型的步骤是梯度下降,也就是使loss值最小;所以可以使用loss值的大小衡量拟合效果。而其它的评价指标,如acc、iou等也不过是loss在另一方面的体系,它们与loss存在一种正相关。但loss值最小,并不代表在指标上效果最好。
泛化能力又称鲁棒性,指模型在训练集上的性能与测试集性能上的差异,这个差异越小,则泛化能力越强,差异越大泛化能力越差。
拟合效果的提升本质就是如何使loss值变得更小。这里有多种思路,分别从数据、模型与loss逐步探讨。
从数据入手,要考虑数据量与质。数据的量指数量,既样本数量要多;数据的质指本质,既样本的代表性要足够。针对到具体场景,比如说猫狗分类,数据的量要多,指猫和狗的照片数要多,针对不同个体的猫和狗要拍摄很多的照片;数据的质要好,针对不同的场景下,各种角度、动作都要有相应的代表数据。数据的量最容易影响模型的拟合效果,而数据的质最容易影响模型的泛化能力。
针对于数据的质量,我们最后是能自己过一下数据,保证数据的分布是正常,也就是说要保证在各种特征计算统计维度下,数据的分布是正常的。这主要是对数据的质进行考量。如猫狗分类,拍摄的照片某些场景的图片多,某些场景的图片上,某些动作的重复图像多某些场景的重复图像少。我们最好是能保证这些数据的频次正常一些。
此外,还有一些数据扩充方法需要考量,因为数据扩充可以在一定程度上影响数据的质和量。关于数据扩充方法可以参考一下Albumentations库的使用,在设置数据扩充方法时要考虑现实数据的分布特征。比如在做猫狗分类时,对于镜像操作,我们只做图像的左右翻转,从不做上下翻转和弹性变化。 博主看了不少论文,大部分论文在做数据增强时仅仅是做了镜像与旋转,可见过多的数据增强或许作用有限。
从模型入手,这里考虑的可能就没有那么多,通常来说模型越复杂,拟合能力越强,训练出来的效果越好,但同时需要的训练数据越多。也就是说模型的复杂度与训练数据的量存在一定关系,但是在实际工程操作中大部分人使用的都是预训练模型。因此,很少考虑到模型复杂度与训练数据量的关系。但是,这也是值得思考的。
博主在做过语义分割中,对比了linknet、hrnet、pspnet、unet3+、segfomer等多个模型。在实验中,发现设计越为精妙的模型,拟合效果越好,segformer>hrnet>unet3+>linknet。在这次实验中,博主一直使用的都是基于预训练二次微调,这5个模型参数量太小不一,但是在相同的体系下,却表现出参数越小模型效果越好的状态。也就是博主的模型中segformerb0>segformerb1>segformerb2。总结来说,模型并非越复杂越好,同时要测试更多体系下的模型才能展现效果。 如做图像分类时,resnet系列、densenet系列、efficientnet系统、hrnet系列都可以测试一下。
但是,并非所有的工作都能用到预训练模型,有的时候完全需要我们自己构建模型。这里就需要考虑到模型结构的设计,如何能更好的提取特征,如何才能更好的传递梯度,如何能为模型深层提供优质的特征表达。关于特征提取,与网络部件结构相关,如时序特征提取需考虑了lstm、gru与普通rnn网络的性能差异;同时也就是block的结构设计相关,如inception提出了多种支路、acnet提出了对kernel骨架的加强。关于梯度传递,与网络的forword流程相关,如resnet结构、densenet结构。关于优质特征表达,在语义分割论文最为显著,如pspnet提出的金字塔特征,deeplab提出的孔洞卷积、hrnet所提出的高分辨率特征。只有所设计的模型结构,契合数据特征前向传播与模型梯度反向传播的过程,才能是模型训练的效果变得更好。
此外,在模型任务上可以设计一些预训练增强模型的特征提取能力,如进行AE、GAN的训练,使模型能了解到每一个数据的本质。还可以设计一些辅助任务或辅助头(例如论文unet3+),进行深度监督,来优化特征的提取与梯度的传递。
其实在loss这一方面是很难操作的,因为交叉熵是各种做离散预测(图像分类、语义分割、目标检测)必用的基本loss,基本上不存在改进空间。调整loss权重,本质就是改善loss的分布,降低数据质量对其影响(尤其是数据类别不平衡->[weight ce loss],难易样本不平衡的情况->[focal loss, ghm loss])。除了对交叉熵loss进行改善外,还可以使用混合loss(对多个loss进行加权),从多个角度对数据进行优化。如语义分割中的dice loss(直接在指标上优化目标),目标检测中的DIOU loss,GIOU loss(用于目标框的回归)等。
模型泛化能力差的一个本质原因是,训练集分布与测试集分布差异较大。其中这两个数据集的差异可以被量化噪声差异和域差异。噪声差异是指一些无关训练目标上的差别,比如猫狗分类,训练集的猫大都在居家环境下,测试集的猫大都在草地上,也就是背景的差异;而域差异则是指两个数据间主题的差异,比如猫狗分类,训练集中大都为真实图像,测试集中大都为卡通图像,真实数据与卡通数据就存在域差异。通常训练集与测试集的差异不会这么离谱,但是当数据集的量比较少时,就有可能这么离谱。因此,提升泛化能力的首先一点就是扩大你的数据集,使随机划分的训练集与测试集在噪声差异与域差异很小。
此外,不同结构的模型泛化能力差异是不一样的,要刨根问底的话就是有的模型学习的特征通用性不强,有的模型学习的特征通用性强,就如博主在使用过程中用inception结构做迁移学习效果总是不如resnet。在进行工程时,我们要多进行对比实验哪些模型的拟合能力与泛化能力强,如segformer论文中就进行了zero-shot鲁棒性测试,表明segformer比DeepLabV3+强。
虽然数据分布与模型结构都影响着最终的泛化能力,但这其实是较难操作的部分。因此人们提出了dropout与Norm两种方式来增强模型的泛化能力。
dropout有很多的变种操作,具体可以参考一下8种dropout的变种操作,其核心原理是随机丢弃掉模型forword过程中的一些数据,增强了训练过程中的随机性,使模型在抽取特征时不对某些像素更为依赖,加强了特征间的适应性,同时也相当于在模型forword过程中添加了一些随机性,使得模型难以进入较窄的局部极小值,从而增强了模型的泛化能力。这种dropout的思想应用到输入数据上就衍生出了cutup、cutmix等数据增强方式,同样也可以增强模型的泛化能力。
Norm也有很多的变种操作,有LocalResponseNorm、BatchNorm、GroupNorm、LayerNorm、SpectralNorm等。Norm操作本质就是为了保证数据在forword过程中分布的一致性,博主暂时也很难解释Nrom为什么可以增强泛化能力,姑且理解为Norm操作使得forword过程中的训练数据与测试数据在分布上变得更为相似了,也就是说减少了训练集与测试集在forword过程中的分布差异。很多论文的网络在用来batchnorm操作后就不在使用dropout操作了,且表示用上Norm操作后,模型的收敛速度和拟合效果都进一步提升。这里有待进一步完善,通过该文博主发现自己对BatchNorm的理解又全忘了,后期补上。