为何使用DataLoader训练模型与手动分批次的训练结果不同?
两种鸢尾花模型训练方式结果差异的原因分析
你观察到的训练结果和速度差异,核心原因是DataLoader版本的训练代码存在循环嵌套错误,导致参数更新次数暴增,同时数据集shuffle策略也有差异,具体如下:
1. 循环嵌套导致迭代次数远超预期
手动分批次的训练逻辑是正确的:每个epoch遍历一次训练集的所有batch(120个训练样本,batch_size=5,共24个batch),每个batch完成一次参数更新,1个epoch总计24次参数更新。
而DataLoader版本的train函数里出现了多余的循环嵌套:
# 错误的双层循环 for start in bar: # 这层循环遍历24个batch起始索引 for X_train_batch, y_train_batch in train_dataloader: # 这层循环又遍历整个训练集的24个batch # 参数更新操作
这导致每个epoch实际执行了24*24=576次参数更新,相当于手动版本24个epoch的训练量。更多的迭代次数让模型收敛得更充分(MSE更低),但也因为做了大量重复计算,运行速度远慢于手动版本。
2. 数据集shuffle策略的差异
- 手动版本:仅在
train_test_split时做了一次shuffle,后续每个epoch都是按固定顺序切分batch,样本顺序无变化。 - DataLoader版本:设置了
shuffle=True,每个epoch都会重新打乱数据集的样本顺序,让模型每次接触的样本组合更随机,这也会辅助模型更好地收敛,但这不是结果差异的核心原因。
修正后的DataLoader训练函数
去掉多余的外层循环,直接遍历DataLoader即可让训练逻辑和手动版本对齐:
def train(model, loss_fn, optimizer): model.train() # 直接用DataLoader作为tqdm的迭代对象 with tqdm.tqdm(train_dataloader, unit="batch", mininterval=0, disable=False) as bar: bar.set_description(f"Epoch {epoch}") for X_train_batch, y_train_batch in bar: y_pred = model(X_train_batch) loss = loss_fn(y_pred, y_train_batch) optimizer.zero_grad() loss.backward() optimizer.step() bar.set_postfix(mse=float(loss))
修正后,每个epoch的参数更新次数和手动版本一致,训练速度和收敛效果会与手动版本接近。
内容的提问来源于stack exchange,提问作者user23115083
相关产品推荐
相关产品推荐

