Float32 error when using iter(next())

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?

The issue is raised by ToPILImage as you are passing a numpy array in an unsupported dtype to it:

transforms = transforms.ToPILImage()

# works
x = torch.randint(0, 256, (3, 224, 224)).byte()
img = transforms(x)

# works
x = torch.randn(3, 224, 224)
img = transforms(x)

# fails
x = np.random.randn(224, 224, 3)
img = transforms(x)
# TypeError: Input type float64 is not supported

That’s correct for PyTorch tensors, which also work, but the transformation requires “standard” numpy image formats as seen here.

Thank you!

Transposing my data gave me the error below (which is clearer than what I got before), but your link helped!

Adding mode=‘RGB’ to the ToPILImage call resolved the issue.

(what I get when transposing my data into [C,H,W])

ValueError: Caught ValueError 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-169-4b1060b9c7d1>", 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 283, in to_pil_image
    raise ValueError(f"pic should not have > 4 channels. Got {pic.shape[-1]} channels.")
ValueError: pic should not have > 4 channels. Got 512 channels.