PyTorch结果复现异常:单次运行Block1后多次运行Block2结果不一致
问题分析与解决方案
我帮你排查下这个复现性的问题——看起来你已经做了不少种子设置的工作,但单独运行Block2时结果还是不稳定,主要有这几个核心原因:
问题根源
你只在Block1里初始化了一次随机种子,但当你单独运行Block2时,之前的随机状态(包括PyTorch、NumPy、Python原生random模块的状态)已经被之前的运行打乱了。另外,GPU环境下的cuDNN库默认会使用一些非确定性算法,这也会悄悄导致结果波动。
具体修复步骤
你需要在每次运行Block2时都重新重置所有随机源,并启用cuDNN的确定性模式,具体修改如下:
1. 在Block2开头添加种子重置与确定性设置
把这段代码加到Block2的最开头,确保每次运行都从相同的随机状态起步:
# 重置所有随机种子 torch.manual_seed(123) random.seed(123) np.random.seed(123) if cuda: torch.cuda.manual_seed(123) torch.cuda.manual_seed_all(123) # 单GPU场景也加上,多GPU时必须设置 # 启用cuDNN确定性模式,避免非确定性算法干扰 torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False
2. 明确设置模型为训练模式
虽然PyTorch模型默认是train()模式,但如果之前有过测试操作(比如调用过eval()),可能会导致Dropout失效。在初始化模型后明确加上这句更稳妥:
net = Net() if cuda: net.cuda() net.train() # 确保Dropout处于训练时的随机失活状态
修改后的完整Block2代码
# 重置随机种子与确定性设置 torch.manual_seed(123) random.seed(123) np.random.seed(123) if cuda: torch.cuda.manual_seed(123) torch.cuda.manual_seed_all(123) torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False net=Net() if cuda: net.cuda() net.train() # 明确设置训练模式 # create a stochastic gradient descent optimizer optimizer = optim.Adam(net.parameters()) # create a loss function (mse) loss = nn.MSELoss(size_average=False) # run the main training loop epochs =20 hold_loss=[] for epoch in range(epochs): cum_loss=0. cum_records_epoch =0 for batch_idx, (data, target) in enumerate(data_loader_trn): tr_x, tr_y = data.float(), target.float() if cuda: tr_x, tr_y = tr_x.cuda(), tr_y.cuda() # Reset gradient optimizer.zero_grad() # Forward pass fx = net(tr_x) output = loss(fx, tr_y) #loss for this batch cum_loss += output.item() #accumulate the loss # Backward output.backward() # Update parameters based on backprop optimizer.step() cum_records_epoch +=len(tr_x) if batch_idx % 1 == 0: print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( epoch, cum_records_epoch, len(data_loader_trn.dataset), 100. * (batch_idx+1) / len(data_loader_trn), output.item())) print('Epoch average loss: {:.6f}'.format(cum_loss/cum_records_epoch)) hold_loss.append(cum_loss/cum_records_epoch) #training loss plt.plot(np.array(hold_loss)) plt.show()
为什么这样能解决问题?
- 重置种子:每次运行Block2时,把所有随机源的状态都拉回初始值,确保Dropout的随机失活、Adam优化器的初始化等都用相同的随机序列。
- cuDNN确定性模式:禁用cuDNN的自动算法选择(benchmark模式),强制使用确定性算法,避免GPU上的非确定性计算导致结果差异。
内容的提问来源于stack exchange,提问作者B_Miner
相关产品推荐
相关产品推荐

