Усовершенствование данных в 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]]])