PyTorch实验结果无法复现,已设随机种子用单GPU仍波动求助
修复步骤
1. 修复训练函数逻辑bug
你当前的train函数计算训练集指标的逻辑完全错误:只把最后一个batch的输出和标签拼接统计,之前所有batch的数据都没计入,每次最后一个batch样本不同自然会导致指标大幅波动。
直接修改train函数的循环逻辑,把拼接操作移到每个batch内执行:
def train(model, device, train_loader, optimizer, epoch): print('Training on {} samples...'.format(len(train_loader.dataset))) model.train() total_train = torch.Tensor() total_label = torch.Tensor() train_losses = [] for batch_idx, data in enumerate(train_loader): data = data.to(device) optimizer.zero_grad() output = model(data) loss = loss_fn(output, data.y.view(-1,1).float()).to(device) loss.backward() optimizer.step() train_losses.append(loss.item()) # 新增这两行,每个batch都拼接数据,原来的这两行在循环外,删掉循环外的对应代码 total_train = torch.cat((total_train, output.cpu()), 0) total_label = torch.cat((total_label, data.y.view(-1, 1).cpu()), 0) if batch_idx % LOG_INTERVAL == 0: print('Train epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch, batch_idx * len(data.x), len(train_loader.dataset), 100. * batch_idx / len(train_loader), loss.item())) # 删掉原来在这里的两行拼接代码,已经移到循环内了 G_train = total_label.detach().numpy().flatten() P_train = total_train.detach().numpy().flatten() # 后面的代码不变
2. 修正随机种子设置的顺序和缺失项
- 首先把
os.environ['PYTHONHASHSEED'] = str(8)移到你代码所有import语句的最前面,这个环境变量必须在Python解释器初始化前设置才生效,你现在在导入完所有库之后设置完全无效。 - 修改你的
set_random_seed函数,补全缺失的确定性配置:
def set_random_seed(seed): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) # 替换原来的单卡种子设置,适配所有场景 torch.cuda.manual_seed_all(seed) torch.backends.cudnn.benchmark = False torch.backends.cudnn.deterministic = True # 新增这行,强制PyTorch使用确定性操作实现,避免底层算子的随机性 torch.use_deterministic_algorithms(True, warn_only=True)
3. 给DataLoader固定随机配置
你开启了训练集的shuffle=True,但没有固定shuffle用的随机生成器,也没有配置数据加载子进程的种子,新增如下配置:
# 在定义DataLoader前新增这两个配置 def seed_worker(worker_id): worker_seed = torch.initial_seed() % 2**32 np.random.seed(worker_seed) random.seed(worker_seed) g = torch.Generator() g.manual_seed(8) # 和你用的随机种子保持一致 # 修改train_loader的定义,传入新增的两个参数 train_loader = DataLoader(train_data, batch_size=TRAIN_BATCH_SIZE, shuffle=True, worker_init_fn=seed_worker, generator=g)
4. 排查其他随机操作
- 确认你的
TestbedDataset类的__getitem__方法有没有随机预处理、随机增广之类的操作,如果有也要固定对应随机种子。 - 如果后续要用到你注释掉的
random_split切分数据集,也要给它传上面定义的generator=g参数,避免每次切分结果不一样。 - 检查你用到的GAT、GCN等模型实现,有没有自定义的随机操作,如果用到dropout的话不需要额外处理,种子固定后dropout的掩码每次运行是一致的。
做完上面的修改后可以先跑2个epoch,对比两次运行第一个batch的loss值,如果第一个batch的loss完全一致,说明随机性已经被固定,后续结果就可以复现。
内容的提问来源于stack exchange,提问作者minyao qiu
相关产品推荐
相关产品推荐

