天池CV竞赛-Task4 模型训练与验证

在上一task任务中,我们介绍了字符识别模型,并介绍了很多关于CNN模型,一个成熟合格的深度学习训练流程应具备以下三个功能:
1.训练集上进行训练,并在验证集上进行验证;
2.模型可以保存最优的权重,并读取权重;
3.记录下训练集和验证集的精度,便于调参。
为此我们本任务将构建验证集,模型训练和验证,模型保存与模型加载和模型调参。

学习目标

1.理解验证集的作用,并使用训练集和验证集完成训练。
2.学会使用pytorch环境下的模型读取和加载,并了解调参流程。

构造验证集

在机器学习模型(特别是深度学习模型)的训练过程中,模型是非常容易过拟合的。深度学习模型在不断的训练过程中训练误差会逐渐降低,但测试误差走势不一定。

在模型的训练过程中,模型只能够利用训练数据来进行训练,模型并不能接触到测试集上的样本。因此模型如果将训练集学的过好,模型就会记住训练样本的细节,导致模型在测试集的泛化误差较差,这种现象称为过拟合(即在训练集表现非常好,在测试集表现较差)。与过拟合相对应的是欠拟合(即模型在训练集上拟合比较差,同时不能达到训练预期,对数据学习拟合程度不够,并且提取数据规则不好)。
在这里插入图片描述
如图所示L随着模型复杂度和模型训练轮数的增加,CNN模型在训练集上的误差会降低,但在测试集上误差也会降低,然后逐渐身高,而我们为了追求模型在测试集上的精度越高越好。
导致模型过拟合的情况有很多原因,其中最为常见的情况是模型复杂度太高,导致模型学习到了训练集数据上的细微信息,并且学习到细枝末节或者异常值规律。
在这次竞赛中,竞赛数据已经分成训练集和测试集2部分了,我们只需要在训练集上建立模型,并在测试集上进行测试观察loss发生的变化来验证模型的泛化能力。
在一般情况下,我们可以将训练集划分成训练集和验证集:
1.训练集:模型用于训练和调整模型参数;
2.验证集:用于验证模型精度和调整模型超参数;
3.测试集:验证模型的泛化能力。
因为训练集和验证集是分开的,所以模型在验证集上面的精度在一定程度上可以反映模型泛化能力。在划分验证集的时候,需要注意验证集的分布应该与测试集分布保持一致,不然模型在验证集上的精度失去指导意义。
既然验证集这么重要,那么如何划分本地验证集呢?在一些比赛中,赛题方给定验证集:如果赛提分没有给定验证集,那么参赛选手就需要从训练集中拆分一部分得到验证集。验证集的划分有如下几种方式:
在这里插入图片描述
1.留一法
直接将训练集划分为2部分,新的训练集和验证集。这种划分方式的有点是为直接简单:缺点是只得到了一份验证集,有可能导致模型在验证集过拟合。留一法应用场景是数据量比较大的情况。
2.交叉验证
将训练集划分为K份,其中K-1份作为训练集,剩余的一份作为验证集,循环K训练。这种划分方式是所有的训练集都是验证集,最终模型验证精度是K份平均得到。这种方式的有点是验证集精度比较可靠稳定,训练K次得到K个多样性差异模型,CV验证缺点是需要训练K次,不适合数据量恒大情况。
3.自助采样法
通过有放回的采样的方式得到新的训练集和验证集。每次的训练集和验证集都有区别的。这种划分方式一般适用于数据量较小情况。

解决过拟合和欠拟合方法

降低过拟合方法:
(1)从数据入手,获得更多的训练数据。使用更多的训练数据是解决过拟合问题最有效方法,因为更多的样本能够让模型学习到更多有效特征,减小噪声的影响。当然,直接加入实验数据一般是非常困难的,但是可以通过一定的规则来扩充训练数据。比如在图像分类问题上,可以通过图像的平移,旋转,缩放,擦除等方式扩充数据,更进一步可以使用生成对抗网络来合成大量的性训练数据。
(2)降低模型的复杂度。在数据比较少的时候,模型过于复杂是产生过拟合的主要因素,适当的降低模型复杂度可以避免模型拟合过多的采样噪声。例如,在神经网络模型中可以减少模型网络层数,神经元个数,dropout,在决策书中,我们可以降低数的深度,降低叶子节点数,进行剪枝等。
(3)加入正则化(L1范式,L2范式)。给模型的参数加入一定的正则约束,比如将权值的大小加入到损失函数中。
(4)集成学习方法。集成学习是把多个模型集成在一起,来降低单一模型的过拟合风险。如bagging方法(RF),boosting方法(adaboosting,GBDT,XGBOOST等)。
降低欠拟合风险方法:
(1)添加新特征。当特征不足或者现有特征与样本标签的相关性不强时,模型容易出现欠拟合。通过挖掘“上下文特征”“文本特征”“数据长度特征”“组合特征”等新特征,往往能够得到更好的效果。在深度学习潮流中,有跟多模型可以帮助完成特征工程,如因子分解机,梯度提升决策树,Deep-crossing等都可以成为丰富特征的方法。
(2)增加模型的复杂度。简单模型的学习能力比较差,通过增加模型的复杂度可以使模型拥有更强的拟合能力。例如,在线性模型中添加高次项,在神经网络中增加网络的层数,或者神经元个数等。
(3)减少正则化系数。正则化是用来防止过拟合的,但是当模型出现欠拟合现象时,则需要有针对性地减少正则化系数。

模型训练与验证

1.构造训练集和验证集。
2.每轮进行训练和验证,并根据最优验证集精度保存模型。
定义好训练,验证和预测模块。

def train(train_loader, model, criterion, optimizer):
    # 切换模型为训练模式
    model.train()
    train_loss = []
    
    for i, (input, target) in enumerate(train_loader):
        if use_cuda:
            input = input.cuda()
            target = target.cuda()
            
        c0, c1, c2, c3, c4 = model(input)
        target=target.long()
        loss = criterion(c0, target[:, 0]) + \
                criterion(c1, target[:, 1]) + \
                criterion(c2, target[:, 2]) + \
                criterion(c3, target[:, 3]) + \
                criterion(c4, target[:, 4])

        # loss /= 6
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        if i % 100 == 0:
            print(loss.item())
        train_loss.append(loss.item())
    return np.mean(train_loss)
def validate(val_loader, model, criterion):
    # 切换模型为预测模型
    model.eval()
    val_loss = []
    
    # 不记录模型梯度信息
    with torch.no_grad():
        for i, (input, target) in enumerate(val_loader):
            if use_cuda:
                input = input.cuda()
                target = target.cuda()
                
        c0, c1, c2, c3, c4 = model(input)
        target=target.long()
        loss = criterion(c0, target[:, 0]) + \
                criterion(c1, target[:, 1]) + \
                criterion(c2, target[:, 2]) + \
                criterion(c3, target[:, 3]) + \
                criterion(c4, target[:, 4])
        # loss /= 6
        val_loss.append(loss.item())
    return np.mean(val_loss)
def predict(test_loader, model, tta=10):
    model.eval()
    test_pred_tta = None
    
    # TTA 次数
    for _ in range(tta):
        test_pred = []
        
        with torch.no_grad():
            for i, (input, target) in enumerate(test_loader):
                if use_cuda:
                    input = input.cuda()

                c0, c1, c2, c3, c4 = model(input)
                output = np.concatenate([
                    c0.data.numpy(),
                    c1.data.numpy(),
                    c2.data.numpy(),
                    c3.data.numpy(),
                    c4.data.numpy()], axis=1)
                test_pred.append(output)
                
        test_pred = np.vstack(test_pred)
        if test_pred_tta is None:
            test_pred_tta = test_pred
        else:
            test_pred_tta += test_pred
    return test_pred_tta

迭代训练和验证模型

model = SVHN_Model1()
criterion = nn.NLLLoss2d()
optimizer = torch.optim.Adam(model.parameters(), 0.0005)
best_loss = 1000.0

use_cuda = False
if use_cuda:
    model = model.cuda()
    
for epoch in range(35):
    train_loss = train(train_loader, model, criterion, optimizer)
    val_loss = validate(val_loader, model, criterion)

    val_label = [''.join(map(str, x)) for x in val_loader.dataset.img_label]
    val_predict_label = predict(val_loader, model, 1)
    val_predict_label = np.vstack([
        val_predict_label[:, :11].argmax(1),
        val_predict_label[:, 11:22].argmax(1),
        val_predict_label[:, 22:33].argmax(1),
        val_predict_label[:, 33:44].argmax(1),
        val_predict_label[:, 44:55].argmax(1),
    ]).T
    val_label_pred = []
    for x in val_predict_label:
        val_label_pred.append(''.join(map(str, x[x!=10])))
        
    val_char_acc = np.mean(np.array(val_label_pred) == np.array(val_label))

    print('Epoch: {0}, Train loss: {1} \t Val loss: {2}'.format(epoch, train_loss, val_loss))
    print(val_char_acc)
    
    # 记录下验证集精度
    if val_loss < best_loss:
        best_loss = val_loss
        torch.save(model.state_dict(), './model_tzzq.pt')
模型保存与加载

在pytorch中模型的保存和价值非常简单,比较常见的做法是保存和加载模型参数:

torch.save(model_object,state_dict(),'model.pt')
model.load_state_dict(torch.load('model.pt'))
模型调参流程

深度学习原来少但是实践性非常强,基本上很多的模型的验证只能通过训练完成。同时深度学习有众多的网络结果和超参数,因此需要反复尝试。训练深度学习模型需要GPU硬件支持。也需要较多的训练时间,如何有效的训练深度学习模型逐渐成为一门学问。
深度学习有众多的训练技巧,比较推荐阅读链接有:

  1. http://lamda.nju.edu.cn/weixs/project/CNNTricks/CNNTricks.html
  2. . . http://karpathy.github.io/2019/04/25/recipe/
    与传统的机器学习模型不同,深度学习模型的精度和模型的复杂度,数据量,正则化,数据扩增等因素直接相关,所以当深度学习模型处于不同的阶段(欠拟合,过拟合和完美拟合)的情况下,可以从什么角度进行模型继续优化。
    在本次比赛中,模型调参可以从简单构建CNN开始进行模型参数认识:
    1.初步构建简单CNN模型,2层CNN,跑通训练,验证,和预测过程。
    2.简单CNN模型的损失会比较大,尝试着增加CNN层数,增加模型复杂度,并观察验证集精度变化。
    3.在增加模型复杂度同时增加数据扩增方法,资质验证集精度不变。
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值