为什么 PyTorch 的 DataLoader 不是确定性的?

数据挖掘 Python 火炬
2021-09-25 20:28:55

我已经设置了这样的种子(希望涵盖所有基础):

random.seed(666)
np.random.seed(666)
torch.manual_seed(666)
torch.cuda.manual_seed_all(666)
torch.backends.cudnn.deterministic = True

下面的代码仍然会为两者输出不同的批次namesTrainLoader1namesTrainLoader2 它们应该是相同的。为什么创建model会影响确定性值?

namesDataset = NamesDataset()
namesTrainLoader1 = DataLoader(namesDataset, batch_size=5, shuffle=True)
for each in namesTrainLoader1:
    print(each)

model = TorchRNN(inputSize, hiddenSize, outputSize)

namesTrainLoader2 = DataLoader(namesDataset, batch_size=5, shuffle=True)
for each in namesTrainLoader2:
    print(each)

输出namesTrainLoader1

('saiki', 'close', 'sloan', 'horos', 'roman')
...

输出namesTrainLoader2

('david', 'abeln', 'hatit', 'holan', 'protz')
...

我也尝试在 中使用worker_init_fn(例如使用 lambda x: 0)DataLoader,但这并没有什么区别。

为什么这不是确定性的?我怎样才能使它具有确定性?即重置内部种子DataLoader

2个回答

如果您想以一种确定性的方式对数据进行洗牌,那么如何预先对数据集进行洗牌,例如在一个简单的文件名列表中,然后简单地在单处理循环中确定性地读取该列表,shuffle = FalseDataLoader??

可能导致非确定性行为的另一件事是使用多个进程 - 然后有一些操作由操作系统传递和管理,它不注意您设置的任何随机种子。性能取决于可用资源,即受主机上运行的其他活动的影响。

除此之外,CPU 和 GPU 之间的任何交互都可能导致不确定的行为,因为数据传输是不确定的(相关的 Nvidia 线程)。数据包每次都可以以不同的方式拆分,但流水线中有明显的 CUDA 级解决方案。

我在使用 DataLoader 时遇到了同样的问题。

在我看来,这可能源于模型的初始化。由于模型参数需要随机数来初始化,因此可以更改随机数生成器,因为模型从中获取了一些数字。因此,在模型初始化之后对数据集进行洗牌可能会导致不同的顺序。