Hi all,
I have translated the brain MRI scans here:
into a pickle dataset containing 3,064 OpenCV RGB images. My pickle dataset is here:
https://drive.google.com/file/d/143O--CA_hrnGrWOzBy02hQBfbx7OvMBI/view?usp=sharing
I am trying to load this data into a dataloader object to run some pytorch image classification models on this, here is my code:
training_data = pickle.load(open('/content/drive/My Drive/MSc Applied Stats/Thesis/baseline_models/Cheng2015/new_dataset/training_data.pickle', 'rb'))
Xt = []
yt = []
features = None
labels = None
label = []
for features, labels, masks, borders in training_data:
Xt.append(features)
yt.append(labels)
mn = [0.485, 0.456, 0.406]
st = [0.229, 0.224, 0.225]
I define my dataloader object like this
class BrainTumorDataset(Dataset):
def __init__(self, images, labels):
# images
self.X = images
# labels
self.y = labels
# Transformation for converting original image array to an image and then convert it to a tensor
self.transform = transforms.Compose([
transforms.ToPILImage(),
# transforms.ToTensor() does min-max normalisation of pixel values into range 0-1.
transforms.ToTensor(),
#alternatively can standardise so pixel values have similar distribution to imagenet data, for transfer learning models
transforms.Normalize(mean=mn, std=st)
])
# Transformation for converting original image array to an image, rotate it randomly between -90 degrees and 90 degrees, and then convert it to a tensor
self.transform2 = transforms.Compose([
transforms.ToPILImage(),
transforms.RandomRotation(90),
# transforms.ToTensor() does min-max normalisation of pixel values into range 0-1.
transforms.ToTensor(),
#also need to standardise so pixel values have similar distribution to imagenet data, for transfer learning models
transforms.Normalize(mean=mn, std=st)
])
# Transformation for converting original image array to an image, rotate it randomly between -180 degrees and 180 degrees, and then convert it to a tensor
self.transform4 = transforms.Compose([
transforms.ToPILImage(),
transforms.RandomRotation(180),
# transforms.ToTensor() does min-max normalisation of pixel values into range 0-1.
transforms.ToTensor(),
#alternatively need to standardise so pixel values have similar distribution to imagenet data, for transfer learning models
transforms.Normalize(mean=mn, std=st)
])
# Transformation for converting original image array to an image, random vertical flip, and then convert it to a tensor
self.transform7 = transforms.Compose([
transforms.ToPILImage(),
transforms.RandomVerticalFlip(p=0.99),
# transforms.ToTensor() does min-max normalisation of pixel values into range 0-1.
transforms.ToTensor(),
#alternatively can standardise so pixel values have similar distribution to imagenet data, for transfer learning models
transforms.Normalize(mean=mn, std=st)
])
def __len__(self):
# return length of image samples
return len(self.X)
def __getitem__(self, idx):
# perform transformations on one instance of X
# Original image as a tensor
data = self.transform(self.X[idx])
#data = data..astype('float64')
print(data)
# Augmented image at 90 degrees as a tensor
aug90 = self.transform2(self.X[idx])
# Augmented image at 180 degrees as a tensor
aug180 = self.transform4(self.X[idx])
# Augmented image vertical flip as a tensor
augVF = self.transform7(self.X[idx])
# store the transformed images in a list
new_batch = [data, aug90, aug180, augVF]
# one-hot encode the labels
labels = torch.zeros(4, dtype=torch.float32)
labels[int(self.y[idx])] = 1.0
new_labels = [labels, labels, labels, labels]
# 8 augmented images and corresponding labels per sample will be returned
return (torch.stack(new_labels), torch.stack(new_batch))
Creating the dataloader like this works
# 70 % training, 15% validating, 15% testing
X_train, X_test, y_train, y_test = train_test_split(Xt, yt, test_size=0.3, shuffle=True, random_state= 42) # 70% training, 30% testing
X_valid, X_test, y_valid, y_test = train_test_split(X_test, y_test, test_size=0.5, shuffle=True, random_state = 42) # split testing set into 50% validation , 50% testing
train_set = BrainTumorDataset(X_train, y_train)
valid_set = BrainTumorDataset(X_valid, y_valid)
test_set = BrainTumorDataset(X_test, y_test)
train_gen = DataLoader(train_set, batch_size=4, shuffle=True, pin_memory=True, num_workers=4)
valid_gen = DataLoader(valid_set, batch_size=4, shuffle=True, pin_memory=True, num_workers=4)
test_gen = DataLoader(test_set, batch_size=10, shuffle=True, pin_memory=True, num_workers=4)
But when I try to inspect say the train_gen object I get a strange error message
next(iter(train_gen))[1]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-112-6664f9e249ff> in <module>
----> 1 next(iter(train_gen))[1]
3 frames
/usr/local/lib/python3.9/dist-packages/torch/_utils.py in reraise(self)
541 # instantiate since we don't know how to
542 raise RuntimeError(msg) from None
--> 543 raise exception
544
545
TypeError: Caught TypeError in DataLoader worker process 0.
Original Traceback (most recent call last):
File "/usr/local/lib/python3.9/dist-packages/torch/utils/data/_utils/worker.py", line 302, in _worker_loop
data = fetcher.fetch(index)
File "/usr/local/lib/python3.9/dist-packages/torch/utils/data/_utils/fetch.py", line 58, in fetch
data = [self.dataset[idx] for idx in possibly_batched_index]
File "/usr/local/lib/python3.9/dist-packages/torch/utils/data/_utils/fetch.py", line 58, in <listcomp>
data = [self.dataset[idx] for idx in possibly_batched_index]
File "<ipython-input-102-00a3581dfcf5>", line 61, in __getitem__
data = self.transform(self.X[idx])
File "/usr/local/lib/python3.9/dist-packages/torchvision/transforms/transforms.py", line 95, in __call__
img = t(img)
File "/usr/local/lib/python3.9/dist-packages/torchvision/transforms/transforms.py", line 227, in __call__
return F.to_pil_image(pic, self.mode)
File "/usr/local/lib/python3.9/dist-packages/torchvision/transforms/functional.py", line 332, in to_pil_image
raise TypeError(f"Input type {npimg.dtype} is not supported")
TypeError: Input type float32 is not supported
My understanding is that float32 is the standard data type here, so why does iter(next()) not work?