Early Stopping中基于测试集(而非验证集)上的表现选取模型的讨论
创始人
2024-05-24 00:30:15
0

论文中一般都是用在验证集上效果最好的模型去预测测试集,多次预测的结果取平均计算准确率或者mAP值而不是单纯的取一次验证集最好的结果作为论文的结果。如果你在写论文的过程中,把测试集当做验证集去验证的话,这其实是作假的,建议不要这样,一旦有人举报或者复现出来你的结果和你论文中的结果相差很大的话,是会受到很大处分的。

我之前曾遇到过这种情况,我在图像分类的过程中曾经用过CutMix增强方式,CutMix其实就是将两张图片放在一起,如下图所示,这种结果会造成验证集上准确率很大的波动,可能一会儿变成99%,一会儿变成88%,那我总不能拿99%作为我论文中的结果啊,所以还是要以最终的测试集的准确率为主,因为这个才是我们需要关注的。

如果只是单纯的取提高准确率的话可以看看文中下面的一些方式,这些方式的提升一定会比单纯取最好的模型的效果要好的。

首先我们需要理解一下概念,什么是训练集?什么是验证集?什么是测试集?大家很容易将“验证集”与“测试集”,“交叉验证”混淆。

首先我们来了解一下基本的概念哈,然后在分析如何解决分类问题,提高模型的准确率和泛化能力。

训练集、验证集、测试集:

训练集(train set) —— 用于模型拟合的数据样本。
验证集(development set)—— 是模型训练过程中单独留出的样本集,它可以用于调整模型的超参数(包括EarlyStopping的epoch)和用于对模型的能力进行初步评估。
测试集 —— 用来评估模最终模型的泛化能力,也就是计算论文里最后各个评价指标的值。但不能作为调参、选择特征等算法相关的选择的依据。

一个形象的比喻:
训练集:学生的课本;学生 根据课本里的内容来掌握知识。
验证集:作业,通过作业可以知道 不同学生学习情况、进步的速度快慢。
测试集:考试,考的题是平常都没有见过,考察学生举一反三的能力。

为什么验证数据集测试数据集两者都需要?

因为验证数据集(Validation Set)用来调整模型参数从而选择最优模型,模型本身已经同时知道了输入和输出,所以从验证数据集上得出的误差(Error)会有偏差(Bias)。
但是我们只用测试数据集(Test Set) 去评估模型的表现,并不会去调整优化模型
传统上,一般三者切分的比例是:6:2:2,验证集并不是必须的,即验证集可有可无(可以选择不用验证集调整超参数)
所以,很多人口中的测试集应该是验证集的意思,测试集不能作为调参、选择特征等算法相关的选择的依据。

K-折交叉验证(K-fold Cross Validation,记为K-CV)

就按照作者说的10折交叉来说,算法步骤是(图如1):

  1. 将数据集分成十份,轮流将其中9份作为训练数据,1份作为测试数据,进行试验。每次试验都会得出相应的正确率。
  2. 10次的结果的正确率的平均值作为对算法精度的估计,一般还需要进行多次10折交叉验证(例如10次10折交叉验证),再求其均值,作为对算法准确性的估计。
    在这里插入图片描述在数据缺乏的情况下使用,如果设原始数据有N个样本,那么LOO-CV就是N-CV,即每个样本单独作为验证集,其余的N-1个样本作为训练集,故LOO-CV会得到N个模型,用这N个模型最终的验证集的分类准确率的平均数,作为此下LOO-CV分类器的性能指标。
    优点:(1)每一回合中几乎所有的样本皆用于训练模型,因此最接近原始样本的分布,这样评估所得的结果比较可靠。(2)实验过程中没有随机因素会影响实验数据,确保实验过程是可以被复制的。
    缺点:计算成本高,需要建立的模型数量与原始数据样本数量相同。当数据集较大时几乎不能使用。

关于EarlyStopping保存最优的模型

Pytroch保存最优的训练模型

		min_loss = 100000#随便设置一个比较大的数for epoch in range(epochs):train()val_loss = val()if val_loss < min_loss:min_loss = val_lossprint("save model")torch.save(net.state_dict(),'model.pth')

图像分类

当我们拿到数据集的第一步就是对数据进行分析

  • 各个种类的样本是否平衡,如果数据不平衡的话对模型准确性的影响是非常大的。举个栗子:如果有100个样本,其中99个是正样本,1个是负样本。那么就算我们把所有的样本都预测成正样本,准确率也有99%,显然这是不对的,因为这个模型只能识别正样本了,泛化能力非常差。这个时候,可以考虑改动损失函数,增加难样本(负样本)的权重,减少简单样本(正样本)的权重。
  • 数据集中是否含有大量噪声。
  • 数据量是否充足等等.

接下来我们讲解一下图像分类中的一些trick:
1.数据清洗
借助弱监督方式引入外部数据集中的高质量数据——解决了自行扩展数据集带来的测试偏移。步骤如下:

  • 使用训练数据建立模型
  • 预测爬取的数据的标签,对外部数据进行伪标签标注。
  • 结合样本分布和混淆矩阵的结果,设置了多级阈值,选择可信度高的数据,组合成新的数据集
  • 重复1,2,3。

2.数据增强
①几何变换——只进行水平翻转和平移0.05

transforms.RandomAffine(degrees=0, translate=(0.05, 0.05)),
transforms.RandomHorizontalFlip()

②CutMix

3.数据不均衡
在数据层面和算法层面同时测试选取—— 上采样和class_wight相结合
①上采样——通过混淆矩阵和验证集的随机化设置,提取模型预测错误的数据,然后按照一定的权重进行数据复制扩充,为了减少上采样可能带来的过拟合问题,我们对扩充的数据进行了区域裁剪,使数据更倾向于需要关注的部分。
②class_weight——将不同的类别映射为不同的权值,该参数用来在训练过程中调整损失函数(只能用于训练)。该参数在处理非平衡的训练数据(某些类的训练样本数很少)时,可以使得损失函数对样本数不足的数据更加关注。

4.数据标签平滑
目的:减小过拟合问题
平滑过后的样本交叉熵损失就不仅考虑到了训练样本中正确的标签位置的损失,也稍微考虑到其他错误标签位置的损失,导致最后的损失增大,导致模型的学习能力提高,即要下降到原来的损失,就得学习的更好,也就是迫使模型往增大正确分类概率并且同时减小错误分类概率的方向前进。

#!/usr/bin/python
# -*- encoding: utf-8 -*-import torch
import torch.nn as nnclass LabelSmoothSoftmaxCE(nn.Module):def __init__(self,lb_pos=0.9,lb_neg=0.005,reduction='mean',lb_ignore=255,):super(LabelSmoothSoftmaxCE, self).__init__()self.lb_pos = lb_posself.lb_neg = lb_negself.reduction = reductionself.lb_ignore = lb_ignoreself.log_softmax = nn.LogSoftmax(1)def forward(self, logits, label):logs = self.log_softmax(logits)ignore = label.data.cpu() == self.lb_ignoren_valid = (ignore == 0).sum()label = label.clone()label[ignore] = 0lb_one_hot = logits.data.clone().zero_().scatter_(1, label.unsqueeze(1), 1)label = self.lb_pos * lb_one_hot + self.lb_neg * (1-lb_one_hot)ignore = ignore.nonzero()_, M = ignore.size()a, *b = ignore.chunk(M, dim=1)label[[a, torch.arange(label.size(1)), *b]] = 0if self.reduction == 'mean':loss = -torch.sum(torch.sum(logs*label, dim=1)) / n_validelif self.reduction == 'none':loss = -torch.sum(logs*label, dim=1)return lossif __name__ == '__main__':torch.manual_seed(15)criteria = LabelSmoothSoftmaxCE(lb_pos=0.9, lb_neg=5e-3)net1 = nn.Sequential(nn.Conv2d(3, 3, kernel_size=3, stride=2, padding=1),)net1.cuda()net1.train()net2 = nn.Sequential(nn.Conv2d(3, 3, kernel_size=3, stride=2, padding=1),)net2.cuda()net2.train()with torch.no_grad():inten = torch.randn(2, 3, 5, 5).cuda()lbs = torch.randint(0, 3, [2, 5, 5]).cuda()lbs[1, 3, 4] = 255lbs[1, 2, 3] = 255print(lbs)import torch.nn.functional as Flogits1 = net1(inten)logits1 = F.interpolate(logits1, inten.size()[2:], mode='bilinear')logits2 = net2(inten)logits2 = F.interpolate(logits2, inten.size()[2:], mode='bilinear')#  loss1 = criteria1(logits1, lbs)loss = criteria(logits1, lbs)#  print(loss.detach().cpu())loss.backward()

5.双损失函数
categorical_crossentropy 和 Label Smoothing Regularization :在对原始标签进行平滑的过程中,可能存在某些数据对标签变化特别敏感,导致损失函数的异常增大,使模型变得不稳定,为了增加模型的稳定性所以使用双损失函数——categorical_crossentropy 和 Label Smoothing Regularization,即保证了模型的泛化能力,又保证了数据不会对标签过于敏感,增加了模型的稳定性。

criterion = L.JointLoss(first=nn.crossentropyloss(), second=LabelSmoothSoftmaxCE(),first_weight=0.5, second_weight=0.5)

6.优化器
RAdam LookAhead:兼具Adam和SGD两者的优化器RAdam,收敛速度快,鲁棒性好LookAhead对SGD进行改进,在各种深度学习任务上实现了更快的收敛 。
将RAdam和LookAhead结合在了一起,形成名为Ranger的新优化器。在ImageNet上进行了测试,在128px,20epoch的测试中,Ranger的训练精度达到了93%,比目前FastAI排行榜榜首提高了1%。
在这里插入图片描述

7.选择的模型

ResNeXt101系列,EfficientNet系列。
resnext101_32x16d_wsl
resnext101_32x8d_wsl
efficientnet-b4
efficientnet-b5

8.注意力机制

在模型中加入SE&CBAM注意力机制——提升网络模型的特征提取能力。
在这里插入图片描述

  • channel attention的过程。比SE多了一个 global max pooling(池化本身是提取高层次特征,不同的池化意味着提取的高层次特征更加丰富)。其第2个池化之后的处理过程和SE一样,都是先降维再升维,不同的是将2个池化后相加再sigmod和原 feature map。
    在这里插入图片描述
class ChannelAttention(nn.Module):def __init__(self, in_planes, ratio=16):super(ChannelAttention, self).__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)self.max_pool = nn.AdaptiveMaxPool2d(1)self.fc1   = nn.Conv2d(in_planes, in_planes // 16, 1, bias=False)self.relu1 = nn.ReLU()self.fc2   = nn.Conv2d(in_planes // 16, in_planes, 1, bias=False)self.sigmoid = nn.Sigmoid()def forward(self, x):avg_out = self.fc2(self.relu1(self.fc1(self.avg_pool(x))))max_out = self.fc2(self.relu1(self.fc1(self.max_pool(x))))out = avg_out + max_outreturn self.sigmoid(out)

② spatial attention 的过程。将做完 channel attention 的feature map 作为输入,之后作2个大小为列通道的维度池化,每一次池化得到的 feature map 大小就为 h * w * 1 ,再将两次池化的 feature map 作基于通道的连接变成了大小为 h * w * 2 的 feature map ,再对这个feature map 进行核大小为 7*7 ,卷积核个数为1的卷积操作(通道压缩)再sigmod,最后就是熟悉的矩阵全乘。
在这里插入图片描述

class SpatialAttention(nn.Module):def __init__(self, kernel_size=7):super(SpatialAttention, self).__init__()assert kernel_size in (3, 7), 'kernel size must be 3 or 7'padding = 3 if kernel_size == 7 else 1self.conv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)self.sigmoid = nn.Sigmoid()def forward(self, x):avg_out = torch.mean(x, dim=1, keepdim=True)max_out, _ = torch.max(x, dim=1, keepdim=True)x = torch.cat([avg_out, max_out], dim=1)x = self.conv1(x)return self.sigmoid(x)

9.SVM替换softmax层
抽取出模型的最后一层,将其接入SVM,用训练数据动态训练SVM分类器,再使用训练好的SVM分类器进行预测。
深度学习模型有支持向量机无法比拟的非线性函数逼近能力,能够很好地提取并表达数据的特征,深度学习模型的本质是特征学习器。然而,深度模型往往在独立处理分类、回归等问题上难以取得理想的效果。对于 SVM 来说,可以利用核函数的思想将非线性样本映射到高维空间,使其线性可分,再通过使数据集之间的分类间隔最大化来寻找最优分割超平面,在分类问题上表现出许多特有优势。但实质上,SVM 只含有一个隐层,数据表征能力并不理想。因此将深度学习方法与 SVM 相结合,构造用于分类的深层模型。利用深度学习的无监督方式分层提取样本高级特征,然后将这些高级特征输入 SVM 模型进行分类,从而达到最优分类精度。
在这里插入图片描述
10.模型融合
多模型融合的策略,Stacking,VotingClassifier—— 提升分类准确率Stacking方法: Stacking 先从初始数据集训练出初级学习器,然后”生成”一个新数据集用于训练次级学习器。在这个新数据集中,初级学习器的输出被当作样例输入特征,而初始样本的标记仍被当作样例标记。stacking使用交叉验证的方式,初始训练集 D 被随机划分为 k 个大小相似的集合 D1 , D2 , … , Dk,每次用k-1 个部分训练 T 个模型,对另个一个部分产生 T 个预测值作为特征,遍历每一折后,也就得到了新的特征集合,标记还是源数据的标记,用新的特征集合训练一个集合模型。

11.TTA:测试时数据增强(保证数据增强的几何变换和tta一致)
可将准确率提高若干个百分点,它就是测试时增强(test time augmentation, TTA)。这里会为原始图像造出多个不同版本,包括不同区域裁剪和更改缩放程度等,并将它们输入到模型中;然后对多个版本进行计算得到平均输出,作为图像的最终输出分数。

tta_model = tta.TTAWrapper(model,tta.fliplr_image2label)

作者:初识CV
链接:https://www.zhihu.com/question/408153243/answer/1490901503
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关内容

热门资讯

初三语文辅导作文600字 初三语文辅导作文600字  在日常生活或是工作学习中,大家最不陌生的就是作文了吧,写作文可以锻炼我们...
写景优美作文摘抄好句好段 写景优美作文摘抄好句好段大全  大家都写过作文,肯定对各类作文都很熟悉吧,尤其是充满意境的写景作文,...
成长类的作文 成长类的作文(精选5篇)  在日常学习、工作抑或是生活中,大家对作文都再熟悉不过了吧,借助作文可以提...
柳作文 柳作文  在平日的学习、工作和生活里,大家都有写作文的经历,对作文很是熟悉吧,借助作文人们可以实现文...
洗菜作文400字 洗菜作文400字四篇  在日常学习、工作或生活中,大家都有写作文的经历,对作文很是熟悉吧,写作文是培...
那一次我真什么的作文400字 那一次我真什么的作文400字(精选72篇)  在日常学习、工作和生活中,大家都不可避免地会接触到作文...
心存美好作文800字 心存美好作文800字(精选25篇)  在平平淡淡的学习、工作、生活中,许多人都写过作文吧,借助作文人...
我的新老师作文800字 我的新老师作文800字第1篇我的新老师作文800字  在2015年的秋季,我便正式成为了马关县民族中...
作文 人生若只如初见 作文 人生若只如初见  人生若只如初见,所有往事都化为江南的一场烟雨,在相视一笑中,随风荡漾起回忆的...
我的心爱之物作文500字 关于我的心爱之物作文500字(精选25篇)  在平凡的学习、工作、生活中,大家都经常接触到作文吧,写...
小路之变作文 小路之变作文 谁没有自己的故乡?谁又不爱自己的故乡呢?每个人的家庭虽然不一样,但对家乡的爱却是相同的...
英文。。我的朋友 英文。。我的朋友英文。。我的'朋友1  I have a good friend. Let me t...
我的家作文 我的家作文我们家有时快乐,有时也有小矛盾。我们家的每一个成员都有着不同的性格。他们的性格还真像他们属...
拔萝卜作文 拔萝卜作文拔萝卜作文1 拔呀拔拔萝卜 !················ 今天,我...
未来的战斗机器人作文 未来的战斗机器人作文  在日常学习、工作或生活中,大家或多或少都会接触过作文吧,作文要求篇章结构完整...
我尊敬的人作文800字 我尊敬的人作文800字  在我们的心中,都有一个最敬佩的人。以下是我尊敬的人作文800字,给大家作为...
一件感动的事作文 一件感动的事作文(精选43篇)  在平平淡淡的学习、工作、生活中,大家都接触过作文吧,作文根据体裁的...
曼珠沙华300字作文 -小学... 梦中的花仙子:你好!我喜欢养花,一些奇特的花,曼珠沙华300字作文。一次无意间想当了曼珠沙华便想养几...
除夕的作文200字 精选除夕的作文200字五篇  在现实生活或工作学习中,大家都有写作文的经历,对作文很是熟悉吧,作文是...
汉字的作文 关于汉字的作文(15篇)  在日常的学习、工作、生活中,大家对作文都不陌生吧,作文是由文字组成,经过...