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