【问题标题】:Training on minibatches of varying size对不同大小的 minibatch 进行训练
【发布时间】:2018-11-12 19:10:03
【问题描述】:

我正在尝试在 PyTorch 中针对已分桶到特定维度的图像训练深度学习模型。我想使用小批量训练我的模型,但小批量大小并不能很好地划分每个桶中的示例数。

我在a previous post 中看到的一个解决方案是用额外的空白填充图像(在训练开始时即时或一次全部填充),但我不想这样做。相反,我想在训练期间允许批量大小灵活。

具体来说,如果N 是存储桶中的图像数量并且B 是批量大小,那么对于该存储桶,如果BN 相除,我想获得N // B 批次987654328@ 批次,否则。最后一批可以少于B 个示例。

例如,假设我有索引 [0, 1, ..., 19],包括在内,我想使用 3 的批量大小。

索引 [0, 9] 对应存储桶 0 中的图像(形状 (C, W1, H1))
索引 [10, 19] 对应存储桶 1 中的图像(形状 (C, W2, H2))

(所有图像的通道深度相同)。那么一个可接受的索引分区将是

batches = [
    [0, 1, 2], 
    [3, 4, 5], 
    [6, 7, 8], 
    [9], 
    [10, 11, 12], 
    [13, 14, 15], 
    [16, 17, 18], 
    [19]
]

我更愿意分别处理索引为 9 和 19 的图像,因为它们具有不同的尺寸。

查看 PyTorch 的文档,我找到了生成小批量索引列表的 BatchSampler 类。我创建了一个自定义的Sampler 类来模拟上述索引的分区。如果有帮助,这是我的实现:

class CustomSampler(Sampler):

    def __init__(self, dataset, batch_size):
        self.batch_size = batch_size
        self.buckets = self._get_buckets(dataset)
        self.num_examples = len(dataset)

    def __iter__(self):
        batch = []
        # Process buckets in random order
        dims = random.sample(list(self.buckets), len(self.buckets))
        for dim in dims:
            # Process images in buckets in random order
            bucket = self.buckets[dim]
            bucket = random.sample(bucket, len(bucket))
            for idx in bucket:
                batch.append(idx)
                if len(batch) == self.batch_size:
                    yield batch
                    batch = []
            # Yield half-full batch before moving to next bucket
            if len(batch) > 0:
                yield batch
                batch = []

    def __len__(self):
        return self.num_examples

    def _get_buckets(self, dataset):
        buckets = defaultdict(list)
        for i in range(len(dataset)):
            img, _ = dataset[i]
            dims = img.shape
            buckets[dims].append(i)
        return buckets

但是,当我使用我的自定义 Sampler 类时,我会生成以下错误:

Traceback (most recent call last):
    File "sampler.py", line 143, in <module>
        for i, batch in enumerate(dataloader):
    File "/home/roflcakzorz/anaconda3/lib/python3.6/site-packages/torch/utils/data/dataloader.py", line 263, in __next__
        indices = next(self.sample_iter)  # may raise StopIteration
    File "/home/roflcakzorz/anaconda3/lib/python3.6/site-packages/torch/utils/data/sampler.py", line 139, in __iter__
        batch.append(int(idx))
TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'

DataLoader 类似乎期望传递索引,而不是索引列表。

我不应该为此任务使用自定义Sampler 类吗?我还考虑过自定义collate_fn 以传递给DataLoader,但使用这种方法我不相信我可以控制允许哪些索引在同一个小批量中。任何指导将不胜感激。

【问题讨论】:

    标签: python deep-learning pytorch mini-batch


    【解决方案1】:

    每个样本是否有 2 个网络(必须修复 cnn 内核大小)。如果是,只需将上面的custom_sampler 传递给 DataLoader 类的 batch_sampler 参数。这将解决问题。

    【讨论】:

    • 我不确定我是否理解这个问题。我确实使用 CNN 来处理图像,但是图像的大小是可变的,并且 CNN 的输出不需要是固定大小。不幸的是,当我使用 CustomSampler 作为 DataLoader 类的参数时出现错误。
    • 我认为你的意思是你的批量大小变化(-1、1、28、28)你的意思是说图像大小相同。如果不是这样,你能告诉我你的代码吗?此外,您可以查看 here 了解我的 RandomSampler 实现,我认为您可以根据自己的情况进行更改。
    • 是的,所以我想这里有两件事可以改变,批量大小和批量中图像的空间尺寸。但是,对于任何给定批次,该批次中的图像都具有相同的空间维度。
    • 原来我的错误是在调用DataLoader 时调用了我的CustomSampler。令人尴尬的是,直到前几天我才意识到DataLoader 对采样器和批处理采样器有单独的关键字参数。感谢您向我指出这一点。我实现的CustomSampler 类现在按预期工作。
    【解决方案2】:

    您好,因为每个批次都应该包含相同尺寸的图像,所以您的 CustomSampler 工作正常,它需要作为参数传递给 mx.gluon.data.DataLoader,使用关键字 batch_sampler。但是,如文档中所述,请记住这一点:

    “如果指定了batch_sampler,请不要指定shufflesamplerlast_batch

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-20
      • 2021-05-22
      • 2014-10-26
      • 1970-01-01
      • 2018-02-21
      • 2020-05-27
      • 2023-03-12
      • 1970-01-01
      相关资源
      最近更新 更多