【问题标题】:Why did the loss of CNN model change little throughout the whole epoch?为什么 CNN 模型的 loss 在整个 epoch 中变化不大?
【发布时间】:2020-02-23 09:26:13
【问题描述】:

我正在运行一个关于视觉语音识别任务的深度学习项目,我发现了一个奇怪的现象。 在前几个时期,损失可以以正常速度减少。我的意思是,在一个时代,损失会随着迭代次数的增加而减少。而在后期的 epoch 中,损失在整个 epoch 中几乎没有变化,但在下一个 epoch 开始时会减少。

有时我会在一个 epoch 结束后中断正在运行的代码,然后从训练好的权重重新开始。损失也会在下一个 epoch 开始时减少。

这是训练代码:

    for epoch in range(283,args.epochs):

        model.train()
        running_loss, running_corrects, running_all, cer = 0., 0., 0., 0.

        for batch_idx, sample_batched in enumerate(dset_loaders['train']):
            optimizer.zero_grad()
            inputs,targets,lengths,y_lengths,idx = sample_batched
            inputs = inputs.float()     
            inputs, targets = inputs.to(device) , targets.to(device) 
            outputs = model(inputs)  
            loss = criterion(F.log_softmax(outputs,dim=-1),targets,lengths,y_lengths)
            loss.backward()
            optimizer.step()

            decoded = decoder.decode_greedy(outputs,lengths)
            cursor, gt = 0, []
            for b in range(inputs.size(0)):
                y_str = ''.join([vocabularies[ch] for ch in targets[cursor: cursor + y_lengths[b]]])
                gt.append(y_str)
                cursor += y_lengths[b]
            CER = decoder.cer_batch(decoded,gt)
            cer += CER
            cer_mean = cer/(batch_idx+1)

            running_loss += loss.data * inputs.size(0)
            running_all += len(inputs)
            if batch_idx == 0:
                since = time.time()      
            else (batch_idx+1) % args.interval == 0 or (batch_idx == len(dset_loaders['train'])-1):            
                print('Process: [{:5.0f}/{:5.0f} ({:.0f}%)]\tLoss: {:.4f}\tcer:{:.4f}\tCost time:{:5.0f}s\tEstimated time:{:5.0f}s\t'.format(
                    running_all,
                    len(dset_loaders['train'].dataset),
                    100. * batch_idx / (len(dset_loaders['train'])-1),
                    running_loss / running_all,
                    cer_mean,
                    time.time()-since,
                    (time.time()-since)*(len(dset_loaders['train'])-1) / batch_idx - (time.time()-since)))
        print('{} Epoch:\t{:2}\tLoss: {:.4f}\tcer:{:.4f}\t'.format(
            'pretrain',
            epoch,
            running_loss / len(dset_loaders['train'].dataset),
            cer_mean)+'\n')
        torch.save(model.state_dict(), save_path+'/'+args.mode+'_'+str(epoch+1)+'.pt')

我对这种现象感到非常困惑。我认为如果整个时期的损失没有改变,那么下一个时期的损失也不应该改变。为什么在整个 epoch 不变之后,Loss 在下一个 epoch 开始时仍然变化? 有人可以帮我解决这个问题吗?谢谢!

【问题讨论】:

    标签: python-3.x deep-learning pytorch


    【解决方案1】:

    我认为这可能与您打印损失的方式有关。

    您有一个 running_loss 表示在此时期计算的每个数据点的总损失,而 running_all 将在此时期计算的数据点总数降级。您打印running_loss / running_all,这是该时期每个数据点的平均损失。

    随着收集的数据点越来越多,即使损失在稳步下降,新的损失也会与之前计算的损失的更大数量进行平均,这使得下降看起来更慢。在这里解释:https://gist.github.com/valkjsaaa/b0b26075174a87b3fd302b4b52ab035a

    我建议将running_loss / running_all 替换为loss.data / len(inputs),这是当前批次的损失,看看是否有帮助。

    更改后的代码应如下所示:

       for epoch in range(283,args.epochs):
    
            model.train()
            running_loss, running_corrects, running_all, cer = 0., 0., 0., 0.
    
            for batch_idx, sample_batched in enumerate(dset_loaders['train']):
                optimizer.zero_grad()
                inputs,targets,lengths,y_lengths,idx = sample_batched
                inputs = inputs.float()     
                inputs, targets = inputs.to(device) , targets.to(device) 
                outputs = model(inputs)  
                loss = criterion(F.log_softmax(outputs,dim=-1),targets,lengths,y_lengths)
                loss.backward()
                optimizer.step()
    
                decoded = decoder.decode_greedy(outputs,lengths)
                cursor, gt = 0, []
                for b in range(inputs.size(0)):
                    y_str = ''.join([vocabularies[ch] for ch in targets[cursor: cursor + y_lengths[b]]])
                    gt.append(y_str)
                    cursor += y_lengths[b]
                CER = decoder.cer_batch(decoded,gt)
                cer += CER
                cer_mean = cer/(batch_idx+1)
    
                running_loss += loss.data * inputs.size(0)
                running_all += len(inputs)
                if batch_idx == 0:
                    since = time.time()      
                else (batch_idx+1) % args.interval == 0 or (batch_idx == len(dset_loaders['train'])-1):            
                    print('Process: [{:5.0f}/{:5.0f} ({:.0f}%)]\tLoss: {:.4f}\tcer:{:.4f}\tCost time:{:5.0f}s\tEstimated time:{:5.0f}s\t'.format(
                        running_all,
                        len(dset_loaders['train'].dataset),
                        100. * batch_idx / (len(dset_loaders['train'])-1),
                        loss.data,
                        cer_mean,
                        time.time()-since,
                        (time.time()-since)*(len(dset_loaders['train'])-1) / batch_idx - (time.time()-since)))
            print('{} Epoch:\t{:2}\tLoss: {:.4f}\tcer:{:.4f}\t'.format(
                'pretrain',
                epoch,
                running_loss / len(dset_loaders['train'].dataset),
                cer_mean)+'\n')
            torch.save(model.state_dict(), save_path+'/'+args.mode+'_'+str(epoch+1)+'.pt')
    

    【讨论】:

    • 谢谢!我认为当前批次的损失应该是loss.data 而不是loss.data / len(inputs)。我尝试打印batch-loss,batch-loss不稳定,时大时小。为什么损失在下一个时期减少了很多?例如,损失在整个第 20 个 epoch 稳定在 0.8,而在第 21 个 epoch 变为 0.7,在整个第 21 个 epoch 稳定在 0.7。
    • 是的。你说的对。您计算平均损失的方式导致了奇怪的行为,如下所述:gist.github.com/valkjsaaa/b0b26075174a87b3fd302b4b52ab035a
    • 我还建议你将损失输出到 TensorboardX。 TensorboardX 提供了一种消除损失的正确方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 2021-10-25
    • 2021-10-25
    • 2019-02-12
    • 1970-01-01
    相关资源
    最近更新 更多