Обучение по мини-пакетам различного размера - PullRequest
0 голосов
/ 03 июня 2018

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

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 Ответ

0 голосов
/ 06 июня 2018

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

...