Обучение по мини-пакетам различного размера

Я пытаюсь обучить модели глубокого обучения в PyTorch на изображениях, которые были привязаны к определенным измерениям. Я хотел бы обучить свою модель с использованием мини-пакетов, но размер мини-партии не делит аккуратно на количество примеров в каждой корзине.

Одним из решений, которое я видел в предыдущем посте, было добавление к изображениям дополнительных пробелов (либо на лету, либо сразу в начале обучения), но я не хочу этого делать. Вместо этого я бы хотел, чтобы размер партии был гибким во время обучения.

В частности, если N количество изображений в ведре и B это размер партии, то для этого ведра я хотел бы получить N // B партии, если B водоразделы N, а также N // B + 1 партии в противном случае. Последняя партия может иметь меньше, чем 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 Класс I генерирует следующую ошибку:

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, но при таком подходе я не верю, что смогу контролировать, какие индексы могут находиться в одном мини-пакете. Любое руководство будет с благодарностью.

1 ответ

Решение

У вас есть 2 сети для каждого из примеров (размер ядра CNN должен быть исправлен). Если да, просто передайте выше custom_sampler к аргументам batch_sampler класса DataLoader. Это решило бы проблему.

Привет, так как каждая партия должна содержать изображения одного размера, ваш CustomSampler работает нормально, его нужно передать в качестве аргумента mx.gluon.data.DataLoader, с ключевым словом, batch_sampler. Однако, как указано в документации, помните следующее:

"Не указывать shuffle, sampler, а также last_batch если batch_sampler указано "

Другие вопросы по тегам