分批培训会导致过度拟合

时间:2020-04-09 13:43:09

标签: python machine-learning neural-network pytorch training-data

我正在训练一个序列到序列(seq2seq)模型,并且我需要为input_sequence_length训练不同的值。

对于值1015,我得到了可接受的结果,但是当我尝试使用20进行训练时,出现了内存错误,因此我切换了训练进行分批训练,但是模型过度拟合和验证损失激增,即使累积了梯度,我也得到了相同的行为,因此我在寻找提示并寻求更准确的方法更新。


这是我的训练功能(仅用于批处理部分):

    if batch_size is not None:
        k=len(list(np.arange(0,(X_train_tensor_1.size()[0]//batch_size-1), batch_size )))
        for epoch in range(num_epochs):
            optimizer.zero_grad()
            epoch_loss=0
            for i in list(np.arange(0,(X_train_tensor_1.size()[0]//batch_size-1), batch_size )): # by using equidistant batch till the last one it becomes much faster than using the X.size()[0] directly
                sequence = X_train_tensor[i:i+batch_size,:,:].reshape(-1, sequence_length, input_size).to(device)
                labels = y_train_tensor[i:i+batch_size,:,:].reshape(-1, sequence_length, output_size).to(device)
                # Forward pass
                outputs = model(sequence)
                loss = criterion(outputs, labels)
                epoch_loss+=loss.item()
                # Backward and optimize
                loss.backward() 

            optimizer.step()    
            epoch_loss=epoch_loss/k
            model.eval
            validation_loss,_= evaluate(model,X_test_hard_tensor_1,y_test_hard_tensor_1)
            model.train()
            training_loss_log.append(epoch_loss)
            print ('Epoch [{}/{}], Train MSELoss: {}, Validation : {} {}'.format(epoch+1, num_epochs,epoch_loss,validation_loss))

编辑: 这是我正在训练的参数:

batch_size = 1024 
num_epochs = 25000
learning_rate = 10e-04

optimizer=torch.optim.Adam(model.parameters(), lr=learning_rate)
criterion = nn.MSELoss(reduction='mean')

1 个答案:

答案 0 :(得分:2)

批处理大小会影响正则化。一次只训练一个例子是很吵的,这使得过拟合变得更加困难。批量培训可以使所有内容变得平滑,从而更容易过度拟合。转换回正则化:

  • 较小的批次添加正则化。
  • 较大的批次会减少正则化。

我也对您的学习速度感到好奇。对class SiteCensus extends Model { public function groups() { return $this->belongsToMany("App\Group"); } } 的每次调用都会累积渐变。如果您将学习速度设置为一次只希望有一个示例,而没有降低它来说明批量累积,那么将发生两种情况之一。

  1. 对于现在已累积的梯度,学习率将太高,训练将有所不同,并且训练和验证错误都会爆炸。

  2. 学习速度不会太高,并且不会出现任何差异。该模型将更快,更有效地进行训练。如果模型太大而无法拟合数据,则训练误差将变为0,但由于过度拟合,验证误差将爆炸。


更新

有关梯度累积的更多信息。

每次调用loss.backward()都会累积渐变,直到您用loss.backward()重置渐变为止。当您调用optimizer.zero_grad()时,它会根据其积累的内容进行操作。

编写代码的方式是,每次通过内部循环调用optimizer.step(),然后在重置之前在外部循环调用loss.backward()。因此,在批次中的所有示例上,而不是一次仅添加一个示例,就已经累计了梯度,求和了。

在大多数假设下,这将使批次累积的梯度大于单个示例的梯度。如果梯度全部对齐,则对于B批,它将大B倍。如果渐变为i.i.d.,那么它将更像是optimizer.step()倍。

如果您不考虑这一点,那么您已经有效地提高了学习率。较大批次的平滑效果将减轻其中的一些,然后可以容忍较高的学习率。较大的批次会减少正则化,较大的学习率又会增加正则化。但这并不是补偿的完美选择,因此您仍然需要进行相应的调整。

通常,每当更改批次大小时,您还需要重新调整学习率以补偿。


Leslie N. Smith 写了一些极好的论文,介绍了一种有条不紊的超参数调整方法。 A disciplined approach to neural network hyper-parameters: Part 1 -- learning rate, batch size, momentum, and weight decay是一个不错的起点。他建议您先阅读一下做得很好的图表。