массив pytorch 4d numpy, применяющий преобразования внутри пользовательского набора данных

Внутри моего пользовательского набора данных я хочу применить transforms.Compose() к массиву NumPy.

Мои изображения имеют формат массива NumPy с формой (num_samples, width, height, channels).

Как я могу применить следующие преобразования к полному массиву numpy?

img_transform = transforms.Compose([ transforms.Scale((224,224)), transforms.ToTensor(), transforms.Normalize([0.46, 0.48, 0.51], [0.32, 0.32, 0.32]) ])

Мои попытки заканчиваются многочисленными ошибками, поскольку преобразования принимают изображение PIL, а не 4-мерный массив NumPy.

from torchvision import transforms
import numpy as np
import torch

img_transform = transforms.Compose([
        transforms.Scale((224,224)),
        transforms.ToTensor(),
        transforms.Normalize([0.46, 0.48, 0.51], [0.32, 0.32, 0.32])
    ])

a = np.random.randint(0,256, (299,299,3))
print(a.shape)

img_transform(a)

person Zabir Al Nazi    schedule 16.06.2020    source источник


Ответы (1)


Все преобразования torchvision работают с отдельными изображениями, а не с пакетами изображений, поэтому нельзя использовать массив 4D.

Отдельные изображения, представленные в виде массивов NumPy, как в вашем примере кода, можно использовать, преобразовав их в изображение PIL. Вы можете просто добавить transforms.ToPILImage в начало конвейер преобразования, поскольку он преобразует либо тензор, либо массив NumPy в изображение PIL.

img_transform = transforms.Compose([
        transforms.ToPILImage(),
        transforms.Resize((224,224)),
        transforms.ToTensor(),
        transforms.Normalize([0.46, 0.48, 0.51], [0.32, 0.32, 0.32])
    ])

Примечание. transforms.Scale устарел в пользу transforms.Resize.

В вашем примере вы использовали np.random.randint, который по умолчанию использует тип int64, но изображения должны быть uint8. Библиотеки, такие как OpenCV, возвращают массивы uint8 при загрузке изображения.

a = np.random.randint(0,256, (299,299,3), dtype=np.uint8)
person Michael Jungo    schedule 16.06.2020
comment
Спасибо, так должен ли я применять преобразования к каждому изображению отдельно внутри пользовательского набора данных (четырехмерный массив NumPy)? У меня есть несколько миллионов изображений (индивидуальная заявка может замедлиться). Как вы думаете, это правильный путь? - person Zabir Al Nazi; 17.06.2020
comment
Если у вас есть миллион изображений, вы должны загрузить их по запросу в __getitem__ набора данных, а затем применить преобразования к отдельному изображению. При этом изображения можно загружать и преобразовывать в фоновых рабочих процессах при использовании DataLoader вместо того, чтобы делать это в основном процессе. - person Michael Jungo; 17.06.2020
comment
Спасибо, это имеет смысл. Итак, внутри __getitem__ будет передано одно idx для изображения, и я смогу применить там преобразования. Насколько я читал, __getitem__ работает с одной точкой данных в наборе данных, если я не ошибаюсь. - person Zabir Al Nazi; 17.06.2020
comment
Да, это одно изображение. Но под загрузкой изображений по запросу я имел в виду, что вы сохраняете только пути изображений в наборе данных, а не все изображения в памяти, затем загружаете изображение с указанным идентификатором и затем применяете преобразование. Хранение миллиона изображений в памяти может быть проблематичным или, по крайней мере, требует много оперативной памяти. - person Michael Jungo; 17.06.2020
comment
Спасибо за предложение, в моем случае исходный набор данных представляет собой большой толстый массив NumPy, хорошая идея, может быть, я смогу вернуть их к изображениям, чтобы сэкономить немного оперативной памяти. Однако в моем случае моя оперативная память, похоже, не беспокоит (128 гигабайт), кроме того, мое обучение происходит на графическом процессоре, поэтому загрузка полного массива NumPy для меня довольно быстрая. - person Zabir Al Nazi; 17.06.2020