1、学习目标
理解验证集的作用,并使用训练集和验证集完成训练
学会使用Pytorch环境下的模型读取和加载,并了解调参流程
2、如何构造验证集?
在具体回答“如何构造验证集”这个问题之前,作为小白,需要搞清楚几个概念。(训练集、验证集、测试集、过拟合、欠拟合……)
首先,先来明确几个“集”的作用:
训练集(Train Set):用于训练和调整模型参数;
验证集(Validation Set):用来验证模型精度和调整模型超参数
测试集(Test Set):验证模型的泛化能力
光看定义,确实还是不太懂这几个集是如何分工为模型服务的,但是训练集和测试集是比较好理解的,可以通俗地理解成用一部分数据给模型进行初始学习,这就是“训练”过程,模型建好以后,用一部分新数据再给模型输入,看能不能得到期望的结果,这就是“测试”过程。对于“验证集”的作用,这里就需要先引出“过拟合”和“欠拟合”的概念。
“在机器学习模型(特别是深度学习模型)的训练过程中,模型是非常容易过拟合的。深度学习模型在不断的训练过程中训练误差会逐渐降低,但测试误差的走势则不一定。
在模型的训练过程中,模型只能利用训练数据来进行训练,模型并不能接触到测试集上的样本。因此模型如果将训练集学的过好,模型就会记住训练样本的细节,导致模型在测试集的泛化效果较差,这种现象称为过拟合(Overfitting)。与过拟合相对应的是欠拟合(Underfitting),即模型在训练集上的拟合效果较差。”
Datawhale的教程中,用一张图直观地表示了这两个现象:
如图所示,随着模型复杂度和模型训练轮数的增加,CNN模型在训练集上的误差会降低,但在测试集上的误差会逐渐降低,然后逐渐升高,而我们为了追求的是模型在测试集上的精度越高越好。
导致模型过拟合的情况有很多种原因,其中最为常见的情况是模型复杂度(Model Complexity )太高,导致模型学习到了训练数据的方方面面,学习到了一些细枝末节的规律。
解决上述问题最好的解决方法:构建一个与测试集尽可能分布一致的样本集(可称为验证集),在训练过程中不断验证模型在验证集上的精度,并以此控制模型的训练。
因为训练集和验证集是分开的,所以模型在验证集上面的精度在一定程度上可以反映模型的泛化能力。在划分验证集的时候,需要注意验证集的分布应该与测试集尽量保持一致,不然模型在验证集上的精度就失去了指导意义。
既然验证集这么重要,那么如何划分本地验证集呢。在一些比赛中,赛题方会给定验证集;如果赛题方没有给定验证集,那么参赛选手就需要从训练集中拆分一部分得到验证集。验证集的划分有如下几种方式:
留出法(Hold-Out)
划分方法:直接将训练集划分成两部分,新的训练集和验证集。
优点:简单粗暴,最直接
确定:只得到一份验证集,可能导致模型在验证集上过拟合
适用场景:数据量比较大的情况
交叉验证法(Cross Validation, CV)
划分方法:将训练集划分成K份,将其中的K-1份作为训练集,剩余的1份作为验证集,循环K训练。这种划分方式是所有的训练集都是验证集,最终模型验证精度是K份平均得到。
优点:验证集精度比较可靠,训练K次可以得到K个有多样性差异的模型
缺点:需要训练K次,不适合数据量很大的情况
适用场景:数据量不是很大的情况
自助采样法(BootStrap)
划分方法:通过有放回的采样方式得到新的训练集和验证集,每次的训练集和验证集都是有区别的。
适用场景:一般适用于数据量较小的情况
在现有的数据比赛中一般采用的划分方法是留出法和交叉验证法。如果数据量比较大,留出法还是比较合适的。当然任何的验证集的划分得到的验证集都是要保证训练集-验证集-测试集的分布是一致的,所以如果不管划分何种的划分方式都是需要注意的。
这里的分布一般指的是与标签相关的统计分布,比如在分类任务中“分布”指的是标签的类别分布,训练集-验证集-测试集的类别分布情况应该大体一致;如果标签是带有时序信息,则验证集和测试集的时间间隔应该保持一致。
3、模型训练与验证
使用Pytorch来完成CNN的训练和验证过程,需要完成的两步:
- 构造训练集和验证集
- 每轮进行训练和验证,并根据最优验证集精度保存模型
#构建train_loader train_loader = torch.utils.data.DataLoader( train_dataset, batch_size=10, shuffle=True num_workers=10,#windows环境下把这句删掉 ) #构建val_loader val_loader = torch.utils.data.DataLoader( val_dataset, batch_size=10, shuffle=False, num_worker=10,#windows环境下把这句删掉 ) model = SVHN_Model1() criterion = nn.CrossEntropyLoss(size_average=False) optimizer = torch.optim.Adam(model.parameters(), 0.001) best_loss = 1000.0 for epoch in range(10): print('Epoch: ', epoch) train(train_loader, model, criterion, optimizer, epoch)#注意参数数量和函数是否一致 val_loss = validate(val_loader, model, criterion) #记录验证集精度 if val_loss < best_loss: best_loss = val_loss torch.save(model.state_dict(), './model.pt')#存储模型
4、模型调参流程
(这一过程我还没实现,所以只能先抄教程)
训练深度学习模型需要GPU的硬件支持,也需要较多的训练时间,如何有效的训练深度学习模型逐渐成为了一门学问。
与传统的机器学习模型不同,深度学习模型的精度与模型的复杂度、数据量、正则化、数据扩增等因素直接相关。所以当深度学习模型处于不同的阶段(欠拟合、过拟合和完美拟合)的情况下,大家可以知道可以什么角度来继续优化模型。在参加本次比赛的过程中,我建议大家以如下逻辑完成:
初步构建简单的CNN模型,不用特别复杂,跑通训练、验证和预测的流程;
简单CNN模型的损失会比较大,尝试增加模型复杂度,并观察验证集精度;
在增加模型复杂度的同时增加数据扩增方法,直至验证集精度不变。