You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 16:06:08