5

我已经多次使用 pytorch 数据加载器的 shuffle 选项。但我想知道这种洗牌何时发生以及它是否在迭代期间动态执行。以下面的代码为例:

namesDataset = NamesDataset()
namesTrainLoader = DataLoader(namesDataset, batch_size=16, shuffle=True)
for batch_data in namesTrainLoader:
    print(batch_data)

当我们定义“namesTrainLoader”时,这是否意味着洗牌已经完成,接下来的迭代将基于固定的数据顺序?定义 namesTrainLoader 后,for 循环会不会有随机性?

我试图用一些特殊值替换一半的“batch_data”:

for batch_data in namesTrainLoader:
    batch_data[:8] = special_val
    pre = model(batch_data)

假设会有无限个 epoch,“模型”最终会看到“namesTrainLoader”中的所有数据吗?还是“namesTrainLoader”的一半数据实际上丢失给了“model”?

4

2 回答 2

6

创建迭代器时发生改组。在 for 循环的情况下,这发生在 for 循环开始之前。

您可以使用以下方法手动创建迭代器:

# Iterator gets created, the data has been shuffled at this point.
data_iterator = iter(namesTrainLoader)

默认情况下,torch.utils.data.RandomSampler如果您设置,数据加载器将使用shuffle=True(不提供您自己的采样器)。它的实现非常简单,您可以通过查看RandomSampler.__iter__方法来查看创建迭代器时数据在哪里打乱:

def __iter__(self):
    n = len(self.data_source)
    if self.replacement:
        return iter(torch.randint(high=n, size=(self.num_samples,), dtype=torch.int64).tolist())
    return iter(torch.randperm(n).tolist())

return 语句是进行洗牌的重要部分。它只是创建索引的随机排列。

这意味着每次完全使用迭代器时都会看到整个数据集,只是每次都以不同的顺序。因此没有数据丢失(不包括带有 的情况drop_last=True),并且您的模型将在每个时期看到所有数据。

于 2020-05-10T21:57:19.567 回答
2

torch.utils.data.DataLoader 你可以在这里查看 PyTorch 的实现。

如果您指定shuffle=True torch.utils.data.RandomSampler将使用(SequentialSampler否则)。

DataLoader创建实例时,什么都不会被洗牌,它只是实例化对象的必要私有成员和其他类似的设置。

当您__iter__在迭代期间发出特殊方法时,在您的情况下,会返回一个名为的特殊对象_SingleProcessDataLoader(self),它是数据的生成器(可能是批处理、混洗等,假设您不使用多处理)。

有一个兔子洞可以找到所有私有和辅助相关的方法,但它基本上所做的是它使用底层sampler来获取用于从中获取样本的索引torch.utils.data.Dataset

采样器一直运行直到用尽并且该过程重复(通常是一个时期)。

定义 namesTrainLoader 后,for 循环会不会有随机性?

在每个周期/纪元开始时RandomSampler对索引进行洗牌,所以是的,它将在每个纪元(何时__iter__调用并_SingleProcessDataLoader(self)返回新的)之前随机化,这可以无限期地完成。

[...]“模型”最终会看到“namesTrainLoader”中的所有数据吗?

是的,它很可能最终会看到所有数据点

于 2020-05-10T21:46:38.050 回答