Pytorch DataLoader迭代顺序是否稳定?

Pytorch DataLoader迭代顺序是否稳定?,pytorch,iterable,deterministic,dataloader,Pytorch,Iterable,Deterministic,Dataloader,Pytorch数据加载器的迭代顺序是否保证相同(在温和条件下) 例如: dataloader = DataLoader(my_dataset, batch_size=4, shuffle=True, num_workers=4) print("run 1") for batch in dataloader: print(batch["index"]) print("run 2") for batch in dataloader: prin

Pytorch数据加载器的迭代顺序是否保证相同(在温和条件下)

例如:

dataloader = DataLoader(my_dataset, batch_size=4,
                        shuffle=True, num_workers=4)
print("run 1")
for batch in dataloader:
  print(batch["index"])

print("run 2")
for batch in dataloader:
  print(batch["index"])

到目前为止,我已经尝试过测试它,但它似乎没有被修复,两次运行的顺序相同。有没有办法让订单也一样?谢谢

编辑:我也试过这样做

unlabeled_sampler = data.sampler.SubsetRandomSampler(unlabeled_indices)
unlabeled_dataloader = data.DataLoader(train_dataset, 
                sampler=unlabeled_sampler, batch_size=args.batch_size, drop_last=False)

然后在数据加载器中迭代两次,但结果是相同的非确定性

简短的回答是否定的,当
shuffle=True
数据加载程序的迭代顺序在迭代之间不稳定时。每次在加载程序上迭代时,内部
RandomSampler
都会创建一个新的随机顺序

获得稳定的无序
DataLoader
的一种方法是使用一组无序索引创建一个
子集
数据集

shuffled_dataset = torch.utils.data.Subset(my_dataset, torch.randperm(len(my_dataset)).tolist())
dataloader = DataLoader(shuffled_dataset, batch_size=4, num_workers=4, shuffled=False)

简短的回答是否定的,当
shuffle=True
数据加载程序的迭代顺序在迭代之间不稳定时。每次在加载程序上迭代时,内部
RandomSampler
都会创建一个新的随机顺序

获得稳定的无序
DataLoader
的一种方法是使用一组无序索引创建一个
子集
数据集

shuffled_dataset = torch.utils.data.Subset(my_dataset, torch.randperm(len(my_dataset)).tolist())
dataloader = DataLoader(shuffled_dataset, batch_size=4, num_workers=4, shuffled=False)

事实上,我在回答jodag的评论时也这么认为:

torch.manual_seed("0")

for i,elt in enumerate(unlabeled_dataloader):
    order.append(elt[2].item())
    print(elt)

    if i > 10:
        break

torch.manual_seed("0")

print("new dataloader")
for i,elt in enumerate( unlabeled_dataloader):
    print(elt)
    if i > 10:
        break
exit(1)                       
以及输出:

[tensor([[-0.3583, -0.6944]]), tensor([3]), tensor([1610])]
[tensor([[-0.6623, -0.3790]]), tensor([3]), tensor([1958])]
[tensor([[-0.5046, -0.6399]]), tensor([3]), tensor([1814])]
[tensor([[-0.5349,  0.2365]]), tensor([2]), tensor([1086])]
[tensor([[-0.1310,  0.1158]]), tensor([0]), tensor([321])]
[tensor([[-0.2085,  0.0727]]), tensor([0]), tensor([422])]
[tensor([[ 0.1263, -0.1597]]), tensor([0]), tensor([142])]
[tensor([[-0.1387,  0.3769]]), tensor([1]), tensor([894])]
[tensor([[-0.0500,  0.8009]]), tensor([3]), tensor([1924])]
[tensor([[-0.6907,  0.6448]]), tensor([4]), tensor([2016])]
[tensor([[-0.2817,  0.5136]]), tensor([2]), tensor([1267])]
[tensor([[-0.4257,  0.8338]]), tensor([4]), tensor([2411])]
new dataloader
[tensor([[-0.3583, -0.6944]]), tensor([3]), tensor([1610])]
[tensor([[-0.6623, -0.3790]]), tensor([3]), tensor([1958])]
[tensor([[-0.5046, -0.6399]]), tensor([3]), tensor([1814])]
[tensor([[-0.5349,  0.2365]]), tensor([2]), tensor([1086])]
[tensor([[-0.1310,  0.1158]]), tensor([0]), tensor([321])]
[tensor([[-0.2085,  0.0727]]), tensor([0]), tensor([422])]
[tensor([[ 0.1263, -0.1597]]), tensor([0]), tensor([142])]
[tensor([[-0.1387,  0.3769]]), tensor([1]), tensor([894])]
[tensor([[-0.0500,  0.8009]]), tensor([3]), tensor([1924])]
[tensor([[-0.6907,  0.6448]]), tensor([4]), tensor([2016])]
[tensor([[-0.2817,  0.5136]]), tensor([2]), tensor([1267])]
[tensor([[-0.4257,  0.8338]]), tensor([4]), tensor([2411])]

这是我们想要的。然而,我认为乔达格的主要答案还是更好;这只是一个暂时有效的快速破解;)

在评论回答中,我实际上赞同乔达格的观点:

torch.manual_seed("0")

for i,elt in enumerate(unlabeled_dataloader):
    order.append(elt[2].item())
    print(elt)

    if i > 10:
        break

torch.manual_seed("0")

print("new dataloader")
for i,elt in enumerate( unlabeled_dataloader):
    print(elt)
    if i > 10:
        break
exit(1)                       
以及输出:

[tensor([[-0.3583, -0.6944]]), tensor([3]), tensor([1610])]
[tensor([[-0.6623, -0.3790]]), tensor([3]), tensor([1958])]
[tensor([[-0.5046, -0.6399]]), tensor([3]), tensor([1814])]
[tensor([[-0.5349,  0.2365]]), tensor([2]), tensor([1086])]
[tensor([[-0.1310,  0.1158]]), tensor([0]), tensor([321])]
[tensor([[-0.2085,  0.0727]]), tensor([0]), tensor([422])]
[tensor([[ 0.1263, -0.1597]]), tensor([0]), tensor([142])]
[tensor([[-0.1387,  0.3769]]), tensor([1]), tensor([894])]
[tensor([[-0.0500,  0.8009]]), tensor([3]), tensor([1924])]
[tensor([[-0.6907,  0.6448]]), tensor([4]), tensor([2016])]
[tensor([[-0.2817,  0.5136]]), tensor([2]), tensor([1267])]
[tensor([[-0.4257,  0.8338]]), tensor([4]), tensor([2411])]
new dataloader
[tensor([[-0.3583, -0.6944]]), tensor([3]), tensor([1610])]
[tensor([[-0.6623, -0.3790]]), tensor([3]), tensor([1958])]
[tensor([[-0.5046, -0.6399]]), tensor([3]), tensor([1814])]
[tensor([[-0.5349,  0.2365]]), tensor([2]), tensor([1086])]
[tensor([[-0.1310,  0.1158]]), tensor([0]), tensor([321])]
[tensor([[-0.2085,  0.0727]]), tensor([0]), tensor([422])]
[tensor([[ 0.1263, -0.1597]]), tensor([0]), tensor([142])]
[tensor([[-0.1387,  0.3769]]), tensor([1]), tensor([894])]
[tensor([[-0.0500,  0.8009]]), tensor([3]), tensor([1924])]
[tensor([[-0.6907,  0.6448]]), tensor([4]), tensor([2016])]
[tensor([[-0.2817,  0.5136]]), tensor([2]), tensor([1267])]
[tensor([[-0.4257,  0.8338]]), tensor([4]), tensor([2411])]


这是我们想要的。然而,我认为乔达格的主要答案还是更好;这只是一个暂时有效的快速破解;)

如果
shuffle=False
,它是稳定的,在您的情况下,您通过设置
shuffle=True
明确请求以随机顺序返回数据,这是正确的。但它是“相同”的数据加载器,不是吗?相同的数据集不是相同的加载器。加载器“只是”数据集的接口,其中定义了采样器。采样器按照定义的方式和顺序对数据集进行采样。如果您更改了shuffle,那么您正在更改dataloader使用的采样器,它可以使数据从稳定变为不稳定。您还可以在定义数据加载器时显式指定采样器。感谢您的澄清!所以实际上我有:
unlabeled\u sampler=data.sampler.substrandomsampler(unlabeled\u index)
然后
unlabeled\u dataloader=data.dataloader(train\u dataset,sampler=unlabeled\u sampler,batch\u size=args.batch\u size,drop\u last=False)
,迭代顺序仍然不稳定。有什么想法吗?我想我现在更了解你的问题了。我发布了一个我相信能回答您问题的答案。如果
shuffle=False
,它是稳定的,在您的情况下,您通过设置
shuffle=True
明确要求以随机顺序返回数据,这一点很好。但它是“相同”的数据加载器,不是吗?相同的数据集不是相同的加载器。加载器“只是”数据集的接口,其中定义了采样器。采样器按照定义的方式和顺序对数据集进行采样。如果您更改了shuffle,那么您正在更改dataloader使用的采样器,它可以使数据从稳定变为不稳定。您还可以在定义数据加载器时显式指定采样器。感谢您的澄清!所以实际上我有:
unlabeled\u sampler=data.sampler.substrandomsampler(unlabeled\u index)
然后
unlabeled\u dataloader=data.dataloader(train\u dataset,sampler=unlabeled\u sampler,batch\u size=args.batch\u size,drop\u last=False)
,迭代顺序仍然不稳定。有什么想法吗?我想我现在更了解你的问题了。我发布了一个我相信能回答你问题的答案。谢谢你,让我再测试一个我的想法,然后我会尝试你的答案并接受。对我来说奇怪的是,如果我适当地设置种子,那么内部的
随机采样器每次都应该给出相同的随机索引,不是吗?@information\u interchange我相信
随机采样器中的随机性发生在创建数据加载器迭代器时(例如,当您对标签执行
时,数据加载器中的数据:
). 您需要在每次迭代数据加载器之前立即使用相同的种子值为torch的随机数生成器(例如,
torch.manual_seed(1234)
)种子,以确保可复制性。这并不理想,因为系统中的任何其他随机行为最终也会被重复,这可能并不理想。嘿,事实上,我刚刚尝试了这种方法,但不幸的是它不起作用:
ValueError:sampler应该是torch.utils.data.sampler的一个实例,但是get sampler=[739,841,1892,…]
哦,这真的很有趣,你说得对。这非常令人惊讶,因为这是pytorch开发人员之一的推荐。不管怎样,我回到了我的第一个解决方案,它同样有效,我已经测试过了。谢谢,让我再测试一个想法,然后我会尝试你的答案并接受。对我来说奇怪的是,如果我适当地设置种子,那么内部的
随机采样器每次都应该给出相同的随机索引,不是吗?@information\u interchange我相信
随机采样器中的随机性发生在创建数据加载器迭代器时(例如,当您对标签执行
时,数据加载器中的数据:
). 您需要在每次迭代数据加载器之前立即使用相同的种子值为torch的随机数生成器(例如,
torch.manual_seed(1234)
)种子,以确保可复制性。这并不理想,因为系统中的任何其他随机行为最终也会被重复,这可能是不理想的。嘿,实际上,我刚刚尝试了这种方法,但遗憾的是它不起作用:
ValueError:sampler应该是torch.utils.data.sampler的一个实例,但是got sampler=[7398411892,…]
哦,实际上是这样