*Please Help: Data Loader for Image and Mask*

username: Younggee
cooked: <p>Hi everyone,<br>
I am currently developing a meta learning for semantic segmentation using MAML approach and my dataset comprises of an image and its mask with tif format. My file path is ,/dataset&gt; Train, Test and Validate and each has a sub-folder of  image_folder and mask_folder. Am writing a custom dataset to random crop the image with size of 256x256 and number of crops for each image should be 5. I was able to do the random crop class but was trying to check what i did was correct but getting this error: TypeError: Unexpected type &lt;class ‘str’&gt;</p>
<p>My code:<br>
import os<br>
import numpy as np<br>
import torch<br>
import torchvision.transforms as TF</p>
<p>from torch.utils import data<br>
from skimage import io<br>
from skimage import transform<br>
from skimage import util</p>
<h1>Constants.</h1>
<p>num_classes = 4</p>
<h1>Class that reads a sequence of image paths from a directory and creates a data.Dataset with them.</h1>
<p>class ListDataset(data.Dataset):</p>
<pre><code>def __init__(self, dataset, mode, normalization='minmax', hidden_classes=None):

    # Initializing variables.
    self.root = './' + dataset + '/'
    self.mode = mode
    self.normalization = normalization
    self.hidden_classes = hidden_classes
    
    
    if self.hidden_classes is not None:
        self.n_classes = num_classes - len(hidden_classes)
    else:
        self.n_classes = num_classes

    # Creating list of paths.
    self.imgs = self.make_dataset()

    # Check for consistency in list.
    if len(self.imgs) == 0:

        raise (RuntimeError('Found 0 images, please check the data set'))

def make_dataset(self):

    # Making sure the mode is correct.
    assert self.mode in ['Train', 'Test', 'Validate']

    # Setting string for the mode.
    img_dir = os.path.join(self.root, self.mode, 'image_folder')
    msk_dir = os.path.join(self.root, self.mode, 'mask_folder')
    
    if self.mode == 'Validate':
        img_dir = os.path.join(self.root, 'Train', 'image_folder')
        msk_dir = os.path.join(self.root, 'Train', 'mask_folder')
        
        
        
    data_list = sorted([f for f in os.listdir(msk_dir) if os.path.isfile(os.path.join(msk_dir, f))])
        
    #print(data_list)
    # Creating list containing image and ground truth paths.
    items = []
    for it in data_list:
        item = (os.path.join(img_dir, it.replace('Mask.tif', '.tif')), os.path.join(msk_dir, it))
        items.append(item)
        
        #print(item)
       # print(img_dir, it, it.replace('_noBoundary.tif', '.tif'), os.path.join(msk_dir, it))
    # Returning list.
    return items


def transform(self, image, mask):
    

    # Random crop
    i, j, h, w = TF.RandomCrop.get_params(
        image, output_size=(256, 256))
    image = TF.crop(image, i, j, h, w)
    mask = TF.crop(mask, i, j, h, w)

    # Random horizontal flipping
    if random.random() &gt; 0.5:
        image = TF.hflip(image)
        mask = TF.hflip(mask)

    # Random vertical flipping
    if random.random() &gt; 0.5:
        image = TF.vflip(image)
        mask = TF.vflip(mask)

    # Transform to tensor
    image = TF.to_tensor(image)
    mask = TF.to_tensor(mask)
    
    return image, mask

def __getitem__(self, index):
    # Reading items from list.
    img_path, msk_path = self.imgs[index]
    
    # Reading images.
    image = io.imread(img_path)
    mask = io.imread(msk_path)
    
    x, y = self.transform(image, mask)
    return x, y

def __len__(self):

    return len(self.imgs)
</code></pre>
<p>Please any Help?</p>

username: ptrblck
cooked: <p>Which line of code raises this error?<br>
Could you post the complete stack trace?</p>

username: Younggee
cooked: <p>Since i was trying to define the transform function and it was not working for me i decided to go with this: num_classes = 4</p>
<h1><a name="class-that-reads-a-sequence-of-image-paths-from-a-directory-and-creates-a-datadataset-with-them-1" class="anchor" href="#class-that-reads-a-sequence-of-image-paths-from-a-directory-and-creates-a-datadataset-with-them-1"></a>Class that reads a sequence of image paths from a directory and creates a data.Dataset with them.</h1>
<p>class ListDataset(data.Dataset):</p>
<pre><code>def __init__(self, dataset, mode, transforms=None, normalization='minmax', hidden_classes=None):

    # Initializing variables.
    self.root = './' + dataset + '/'
    self.mode = mode
    self.normalization = normalization
    self.hidden_classes = hidden_classes
    
    
    if self.hidden_classes is not None:
        self.n_classes = num_classes - len(hidden_classes)
    else:
        self.n_classes = num_classes

    # Creating list of paths.
    self.imgs = self.make_dataset()

    # Check for consistency in list.
    if len(self.imgs) == 0:

        raise (RuntimeError('Found 0 images, please check the data set'))

def make_dataset(self):

    # Making sure the mode is correct.
    assert self.mode in ['Train', 'Test', 'Validate']

    # Setting string for the mode.
    img_dir = os.path.join(self.root, self.mode, 'image_folder')
    msk_dir = os.path.join(self.root, self.mode, 'mask_folder')
    
    if self.mode == 'Validate':
        img_dir = os.path.join(self.root, 'Train', 'image_folder')
        msk_dir = os.path.join(self.root, 'Train', 'mask_folder')
        
        
        
    data_list = sorted([f for f in os.listdir(msk_dir) if os.path.isfile(os.path.join(msk_dir, f))])
        
    #print(data_list)
    # Creating list containing image and ground truth paths.
    items = []
    for it in data_list:
        item = (os.path.join(img_dir, it.replace('Mask.tif', '.tif')), os.path.join(msk_dir, it))
        items.append(item)
        
        #print(item)
       # print(img_dir, it, it.replace('_noBoundary.tif', '.tif'), os.path.join(msk_dir, it))
    # Returning list.
    return items


def __getitem__(self, index):
    # Reading items from list.
    img_path, msk_path = self.imgs[index]
    
    # Reading images.
    image = io.imread(img_path)
    mask = io.imread(msk_path)
    
    # Turning to tensors.
    image = torch.from_numpy(image)
    mask = torch.from_numpy(mask)
    
    return image, mask

def __len__(self):

    return len(self.imgs)
</code></pre>
<p>And my transform for dataloader goes like this:<br>
if <strong>name</strong> == ‘<strong>main</strong>’:<br>
train_transform = transforms.Compose([<br>
transforms.ToPILImage(),<br>
transforms.FiveCrop(256),<br>
transforms.RandomHorizontalFlip(),<br>
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),<br>
transforms.ToTensor()</p>
<pre><code>])
test_transform = transforms.Compose([
    transforms.ToPILImage(),
    transforms.ToTensor()
])

train_dataset = ListDataset('./dataset', 'Train', transforms=train_transform)
train_loader = DataLoader(dataset=train_dataset, batch_size=2, shuffle=True, sampler=None,
           batch_sampler=None, num_workers=0, collate_fn=None,
           pin_memory=False, drop_last=False, timeout=0,
           worker_init_fn=None)


dataiter = iter(train_loader)
data = dataiter.next()
features, labels = data
print(features, labels)
</code></pre>
<p>but i get this error below:<br>
RuntimeError: stack expects each tensor to be equal size, but got [11361, 7665, 3] at entry 0 and [13488, 14017, 3] at entry 1<div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/8/b/8b207715c977af7c027ddd494710fa0cda54e764.jpeg" data-download-href="https://discuss.pytorch.org/uploads/default/8b207715c977af7c027ddd494710fa0cda54e764" title="Capture"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/8/b/8b207715c977af7c027ddd494710fa0cda54e764_2_690x248.jpeg" alt="Capture" data-base62-sha1="jQLVkAFCzBYtp1QB5LQbJvTGSiM" width="690" height="248" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/8/b/8b207715c977af7c027ddd494710fa0cda54e764_2_690x248.jpeg, https://discuss.pytorch.org/uploads/default/original/3X/8/b/8b207715c977af7c027ddd494710fa0cda54e764.jpeg 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/8/b/8b207715c977af7c027ddd494710fa0cda54e764.jpeg 2x" data-dominant-color="F1F4F3"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">Capture</span><span class="informations">739×266 31.9 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>

username: Younggee
cooked: <p>Basically my images are of different dimensions but after the FiveCrops, i dont know if it is that it was not appleid to the train_loader</p>

username: ptrblck
cooked: <p>You are not using any transformations in <code>Dataset.__getitem__</code> at the moment, so <code>image</code> and <code>mask</code> will be the loaded images transformed to tensors.<br>
It seems they have a different shape, which would yield this error.</p>
<p>To apply the transformations, you would have to assign <code>transforms</code> in <code>__init__</code> via:</p>
<pre><code class="lang-python">self.transforms = transforms
</code></pre>
<p>and apply it in <code>__getitem__</code>:</p>
<pre><code class="lang-python">if self.transforms:
    image = self.transforms(image)
</code></pre>
<p>Note that the <code>torchvision</code>transforms<code>work on</code>PIL.Images<code>by default, so you might need to switch to</code>PIL` to load the images.</p>

username: Younggee
cooked: <p>Thanks for your reply and i edited like u suggested but got this error : TypeError: pic should be Tensor or ndarray. Got &lt;class ‘PIL.TiffImagePlugin.TiffImageFile’&gt;.</p>
<p>import os<br>
import numpy as np<br>
import torch<br>
import torchvision.transforms as transforms<br>
from PIL import Image<br>
Image.MAX_IMAGE_PIXELS = None</p>
<p>from torch.utils import data<br>
from skimage import io<br>
from skimage import transform<br>
from skimage import util</p>
<h1>Constants.</h1>
<p>num_classes = 4</p>
<h1>Class that reads a sequence of image paths from a directory and creates a data.Dataset with them.</h1>
<p>class ListDataset(data.Dataset):</p>
<pre><code>def __init__(self, dataset, mode, normalization='minmax', hidden_classes=None):

    # Initializing variables.
    self.root = './' + dataset + '/'
    self.mode = mode
    self.normalization = normalization
    self.hidden_classes = hidden_classes
    self.transforms = transforms
    
    
    if mode == 'Train':
        self.transforms = transforms.Compose([
                                            transforms.ToPILImage(),
                                            transforms.FiveCrop(256),
                                            transforms.RandomHorizontalFlip(),
                                            transforms.ToTensor(),
                                            transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
                                            
    
                                            ])
    else:
        self.transforms = transforms.Compose([
                                            transforms.ToPILImage(),
                                            transforms.ToTensor(),
                                            transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
                                            ])
        
    if self.hidden_classes is not None:
        self.n_classes = num_classes - len(hidden_classes)
    else:
        self.n_classes = num_classes

    # Creating list of paths.
    self.imgs = self.make_dataset()

    # Check for consistency in list.
    if len(self.imgs) == 0:

        raise (RuntimeError('Found 0 images, please check the data set'))

def make_dataset(self):

    # Making sure the mode is correct.
    assert self.mode in ['Train', 'Test', 'Validate']

    # Setting string for the mode.
    img_dir = os.path.join(self.root, self.mode, 'image_folder')
    msk_dir = os.path.join(self.root, self.mode, 'mask_folder')
    
    if self.mode == 'Validate':
        img_dir = os.path.join(self.root, 'Train', 'image_folder')
        msk_dir = os.path.join(self.root, 'Train', 'mask_folder')
        
        
        
    data_list = sorted([f for f in os.listdir(msk_dir) if os.path.isfile(os.path.join(msk_dir, f))])
        
    #print(data_list)
    # Creating list containing image and ground truth paths.
    items = []
    for it in data_list:
        item = (os.path.join(img_dir, it.replace('Mask.tif', '.tif')), os.path.join(msk_dir, it))
        items.append(item)
        
        #print(item)
       # print(img_dir, it, it.replace('_noBoundary.tif', '.tif'), os.path.join(msk_dir, it))
    # Returning list.
    return items


def __getitem__(self, index):
    # Reading items from list.
    img_path, msk_path = self.imgs[index]
    
    # Reading images.

    image = Image.open(img_path)
    mask = Image.open(msk_path)
    
    if self.transforms:
        image = self.transforms(image)
        mask  = self.transforms(mask)
    
    # Turning to tensors.
    image = torch.tensor(image)
    mask = torch.tensor(mask)
    
    
    print(image, mask)
    return image, mask

def __len__(self):

    return len(self.imgs)</code></pre>

username: ptrblck
cooked: <p>The <code>transforms.ToPILImage()</code> transformations wouldn’t be needed, if you are already passing a <code>PIL.Image</code> to the transformations.<br>
Try to remove it and rerun the script.</p>

username: Younggee
cooked: <p>This  was what i got i think its not so easy dealing with tif images<br>
TypeError: pic should be PIL Image or ndarray. Got &lt;class ‘tuple’&gt;</p>

username: ptrblck
cooked: <p>I don’t think this error is related to the TIF image, but assume that you are trying to pass the image and mask to the transformation together as a <code>tuple</code>.</p>

username: Younggee
cooked: <p>Ok so what do u think will be best solution because at this point i dnt think i have a clue on what to do next</p>

username: ptrblck
cooked: <p>Try to pass only the image to the transformation and check if it works.<br>
If you would need to transform the image and the mask together (using the same “random” transformations), I would recommend to use the functional API as described <a href="https://discuss.pytorch.org/t/torchvision-transfors-how-to-perform-identical-transform-on-both-image-and-target/10606/7">here</a>.</p>

username: Younggee
cooked: <p>Thanks alot the Custom data worked but i i had to pre-process the image manually using a loop to crop the required images in the range of 50 then i applied the transform and my custom dataset is as follows:</p>
<p>num_classes = 2</p>
<h1>Class that reads a sequence of image paths from a directory and creates a data.Dataset with them.</h1>
<p>class ListDataset(data.Dataset):</p>
<pre><code>def __init__(self, dataset, mode, normalization='minmax', hidden_classes=None):

    # Initializing variables.
    
    self.root = '/content/drive/My Drive/dataset'
    
    #self.root = './' + dataset + '/'
    self.mode = mode
    self.normalization = normalization
    self.hidden_classes = hidden_classes
    self.transforms = transforms
    
    if self.mode == 'Train':
        self.transforms = transforms.Compose([
                                            #transforms.ToPILImage(mode=None),
                                            #transforms.FiveCrop(256),
                                            #lambda x: Image.open(x).convert('RGB'),
                                            transforms.ToTensor(),
                                            #transforms.Lambda(lambda crops: torch.stack([(transforms.ToTensor()(crop)) 
                                             #                                            for  crop in crops])),
                                            transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
                                            
    
                                            ])
    else:
        self.transforms = transforms.Compose([
                                           # transforms.ToPILImage(mode=None),
                                            #lambda x: Image.open(x).convert('RGB'),
                                            transforms.ToTensor(),
                                           transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225))
                                           ])
    
    
    
        
    
    # Creating list of paths.
    self.imgs = self.make_dataset()

    # Check for consistency in list.
    if len(self.imgs) == 0:

        raise (RuntimeError('Found 0 images, please check the data set'))

def make_dataset(self):

    # Making sure the mode is correct.
    assert self.mode in ['Train', 'Test', 'Validate']

    # Setting string for the mode.
    img_dir = os.path.join(self.root, self.mode, 'image_folder')
    msk_dir = os.path.join(self.root, self.mode, 'mask_folder')
    
    if self.mode == 'Validate':
        img_dir = os.path.join(self.root, 'Train', 'image_folder')
        msk_dir = os.path.join(self.root, 'Train', 'mask_folder')
        
        
        
    data_list = sorted([f for f in os.listdir(msk_dir) if os.path.isfile(os.path.join(msk_dir, f))])
        
    #print(data_list)
    # Creating list containing image and ground truth paths.
    items = []
    for it in data_list:
        item = (os.path.join(img_dir, it.replace('Mask.tif', '.tif')), os.path.join(msk_dir, it))
        items.append(item)
        
        #print(item)
       # print(img_dir, it, it.replace('_noBoundary.tif', '.tif'), os.path.join(msk_dir, it))
    # Returning list.
    return items


def __getitem__(self, index):
    # Reading items from list.
    img_path, msk_path = self.imgs[index]
    
    # Reading images.
    
    image = io.imread(img_path)
    mask =  io.imread(msk_path)
    
    image_array = np.asarray(image)
    mask_array  = np.asarray(mask)
     
    
    
    
    
    #image = self.transforms(image)
    #mask  = self.transforms(mask)
    image_array = self.transforms(image_array)
    mask_array  = self.transforms(mask_array)
    
    # Turning to tensors.
    #image_array = torch.from_numpy(image_array)
    #mask_array = torch.from_numpy(mask_array)
     
    return image_array, mask_array

def __len__(self):
    return len(self.imgs)</code></pre>