我在 PyTorch 中有一个模型,在使用标准训练过程时,它可以很好地收敛于参考示例,其中优化器同时对所有样本进行训练:
loss = loss_fnc(samples)
model.optim.zero_grad()
loss.backward()
model.optim.step()
现在模型应该训练更多的内存密集型任务(更多的样本,更大的输入大小),所以我认为这将有助于批量训练。为此,我使用了这个非常标准的方法和 for 循环:
loss_sum = 0
for k_batch in range(0, len(samples), batch_size):
samples_batch = samples[k_batch:k_batch + batch_size]
loss = loss_fnc(samples_batch)
loss_sum += loss*len(samples_batch)
model.optim.zero_grad()
loss.backward()
model.optim.step()
loss_comp = loss_sum/len(samples)
现在,当我跳过此方法中的训练部分并仅计算损失时,得到的
loss_comp
与一次计算所有样本时的结果相同(如上面的方法)。当然,通过批量训练,loss_comp
会有所不同,因为模型在整个批次中都会发生变化。
现在我面临的问题是,在使用批量训练时,模型不再收敛于我的参考示例。在这两种情况下,样本在训练之前就已随机排序。
由于我只对减少计算所需的内存需求感兴趣,因此在尝试其他操作之前,有没有办法在使用批量而不是“一次性”时真正进行相同的训练?我尝试更改函数,以便只批量计算损失,并在最后完成优化步骤,但我似乎没有让它发挥作用。
据我了解,使用 DataLoader 不会改变与此行为有关的任何内容。
我想我找到了一个非常简单的解决方案。我再次尝试了这种方法,在批量计算过程中对
loss
进行了总结,但最后只训练了一次。之前,我一定在 loss
数据类型方面做错了什么,所以我现在用第一批 loss
初始化它,以确保正确的类型:
for k_batch in range(0, len(samples), batch_size):
samples_batch = samples[k_batch:k_batch + batch_size]
loss = loss_fnc(samples_batch)
if k_batch == 0:
loss_sum = loss*len(samples_batch)
else:
loss_sum += loss*len(samples_batch)
loss = loss_sum/len(samples)
model.optim.zero_grad()
loss.backward()
model.optim.step()
当我现在将
loss
与参考 loss
(来自“一次性”训练)进行比较时,值是相等的。作为梯度函数,参考 loss
具有 MseLossBackward0
,而这些批次新计算的损失具有 DivBackward0
。尽管如此,无论是否使用批次,以下训练似乎都是相同的。