Усовершенствование данных в PyTorch

Я немного смущен об увеличении данных, выполненных в PyTorch. Теперь, насколько я знаю, когда мы выполняем аудит данных, мы сохраняем наш исходный набор данных, а затем добавляем другие его версии (Flipping, Cropping... и т.д.). Но это не похоже на то, что происходит в PyTorch. Насколько я понял из ссылок, когда мы используем data.transforms в PyTorch, тогда он применяет их один за другим. Так, например:

data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}

Здесь, для обучения, мы сначала произвольно обрезаем изображение и (224,224) его размер до формы (224,224). Затем мы берем эти (224,224) изображения и горизонтально переворачиваем их. Поэтому наш набор данных теперь содержит ТОЛЬКО горизонтально перевернутые изображения, поэтому наши исходные изображения теряются в этом случае.

Я прав? Правильно ли это понимание? Если нет, то где мы скажем PyTorch в этом коде выше (взятом из официальной документации), чтобы сохранить исходные изображения и изменить их размер до ожидаемой формы (224,224)?

Спасибо

Ответ 1

Операции transforms применяются к вашим исходным изображениям при каждом выпуске партии. Таким образом, ваш набор данных остается неизменным, только копии партий копируются и преобразуются на каждую итерацию.

Путаница может возникнуть из-за того, что часто, как и в вашем примере, transforms используются как для подготовки данных (изменение размера/обрезка до ожидаемых размеров, нормализация значений и т.д.), Так и для увеличения данных (рандомизация изменения размера/обрезки, случайное переключение изображения и т.д.).


Что data_transforms['train'] ваш data_transforms['train']:

  • Случайно измените размер предоставленного изображения и произвольно обрезайте его, чтобы получить патч (224, 224)
  • Примените или не произвольный горизонтальный флип на этот патч с вероятностью 50/50
  • Преобразуйте его в Tensor
  • Нормализовать полученный Tensor, учитывая значения среднего и отклонения, которые вы предоставили

Что data_transforms['val'] ваш data_transforms['val']:

  • Измените размер изображения на (256, 256)
  • Центрируйте обрезанное изображение, чтобы получить патч (224, 224)
  • Преобразуйте его в Tensor
  • Нормализовать полученный Tensor, учитывая значения среднего и отклонения, которые вы предоставили

(т.е. случайное изменение размера/обрезка для данных обучения заменяется фиксированной операцией для проверки, чтобы иметь надежные результаты проверки)


Если вы не хотите, чтобы ваши обучающие изображения были горизонтально перевернуты с вероятностью 50/50, просто удалите transforms.RandomHorizontalFlip().

Аналогично, если вы хотите, чтобы ваши изображения всегда были обрезаны по центру, замените transforms.RandomResizedCrop на transforms.Resize и transforms.CenterCrop, как это сделано для data_transforms['val'].

Ответ 2

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

Запустив следующий простой фрагмент кода, мы могли заметить, что последнее верно, т.е. Если у вас есть набор данных из 8 изображений, и вы создали объект набора данных PyTorch для этого набора данных, когда вы выполняете итерацию по набору данных, преобразования вызываются в каждой точке данных, и преобразованная точка данных возвращается. Так, например, если у вас случайное переворачивание, некоторые точки данных возвращаются как оригинальные, некоторые возвращаются как перевернутые (например, 4 перевёрнутых и 4 оригинальных). Другими словами, за одну итерацию элементов набора данных вы получите 8 точек данных (некоторые перевернуты, а некоторые нет). [Что противоречит общепринятому пониманию расширения набора данных (например, в этом случае наличие 16 точек данных в расширенном наборе данных)]

class experimental_dataset(Dataset):

    def __init__(self, data, transform):
        self.data = data
        self.transform = transform

    def __len__(self):
        return len(self.data.shape[0])

    def __getitem__(self, idx):
        item = self.data[idx]
        item = self.transform(item)
        return item

    transform = transforms.Compose([
        transforms.ToPILImage(),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor()
    ])

x = torch.rand(8, 1, 2, 2)
print(x)

dataset = experimental_dataset(x,transform)

for item in dataset:
    print(item)

Результаты: (Небольшие различия в числах с плавающей точкой вызваны преобразованием в изображение и обратно)

Исходный набор фиктивных данных:

tensor([[[[0.1872, 0.5518],
          [0.5733, 0.6593]]],


    [[[0.6570, 0.6487],
      [0.4415, 0.5883]]],


    [[[0.5682, 0.3294],
      [0.9346, 0.1243]]],


    [[[0.1829, 0.5607],
      [0.3661, 0.6277]]],


    [[[0.1201, 0.1574],
      [0.4224, 0.6146]]],


    [[[0.9301, 0.3369],
      [0.9210, 0.9616]]],


    [[[0.8567, 0.2297],
      [0.1789, 0.8954]]],


    [[[0.0068, 0.8932],
      [0.9971, 0.3548]]]])

преобразованный набор данных:

tensor([[[0.1843, 0.5490],
     [0.5725, 0.6588]]])
tensor([[[0.6549, 0.6471],
     [0.4392, 0.5882]]])
tensor([[[0.5647, 0.3255],
         [0.9333, 0.1216]]])
tensor([[[0.5569, 0.1804],
         [0.6275, 0.3647]]])
tensor([[[0.1569, 0.1176],
         [0.6118, 0.4196]]])
tensor([[[0.9294, 0.3333],
         [0.9176, 0.9608]]])
tensor([[[0.8549, 0.2275],
         [0.1765, 0.8941]]])
tensor([[[0.8902, 0.0039],
         [0.3529, 0.9961]]])