Incorrect shape of data from DataLoader

David_Hresko: <p>DataLoader is returning wrong shape when using BTCV dataset.</p>
<p><strong>This is my dataset, which contains pairs of CT image and segmentation label in NIFTI format. Result shape of TRAIN_PAIR_PATHS is List of dicts</strong></p>
<pre><code class="lang-auto">file_list = os.listdir(f"{DATASET_PATH}/img/")
val_files = set(random.sample(file_list, NUMBER_OF_VAL_FILES))

TRAIN_PAIR_PATHS = [
    {"img": f"{DATASET_PATH}img/{f}", "seg": f"{DATASET_PATH}label/{f.replace('img', 'label')}"}
    for f in set(file_list) - val_files
]
</code></pre>
<p><strong>This is my dataLoader:</strong></p>
<pre><code class="lang-auto">trainLoader = DataLoader(
    batch_size=2,
    dataset=CacheDataset(data=TRAIN_PAIR_PATHS, transform=TRAINING_PRE_TRANSFORM, cache_rate=1.), shuffle=True
)
</code></pre>
<p>I expect that data can be accessed like this via keys:</p>
<pre><code class="lang-auto"> print(batchData['img'].shape)
 print(batchData['seg'].shape)
</code></pre>
<p>but dataloader is returning me this shape when using standard loop like this:</p>
<pre><code class="lang-auto">for batchData in trainLoader:
   another code
</code></pre>
<p>Output of dataloader:</p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/1/6/1631a5b23d9a690ae7b5079a445e0c6f617f6599.png" alt="obrázok" data-base62-sha1="3akS8aSqBmWJT7Z8PjvY2OVYEoV" width="275" height="138"></p>
<p>Expected output</p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/c/7/c7dc3bd354325a2d2b8f368d87acf0d53161d98a.png" alt="obrázok" data-base62-sha1="sw2RDz0lxjwA5Gu3bcBxplcf5Bo" width="338" height="199"></p>

TzviNoy: <p>Can you please share your CacheDataset class and an example of the wrong shape that you get vs the expected shape?</p>

David_Hresko: <p>Hi CacheDataset is provided by MONAI framework (<a href="https://docs.monai.io/en/stable/data.html#cachedataset" class="inline-onebox" rel="noopener nofollow ugc">Data — MONAI 1.1.0 Documentation</a>) and I also attached output of debugger …as you can see wrong shape is list of dicts. I also added expected shape. THanks</p>

ptrblck: <p>The <code>DataLoader</code> should be able to consume <code>dict</code>s as seen here:</p>
<pre><code class="lang-python">class MyDataset(Dataset):
    def __init__(self):
        self.data = torch.arange(10)
        self.target = torch.arange(10, 20)
        
    def __len__(self):
        return len(self.data)
    
    def __getitem__(self, index):
        x = self.data[index]
        y = self.target[index]
        return {"img": x, "target": y}

dataset = MyDataset()
print(dataset[0])
# {'img': tensor(0), 'target': tensor(10)}

loader = DataLoader(dataset, batch_size=5)
for batch in loader:
    print(batch)
    print(batch["img"].shape)
    
# {'img': tensor([0, 1, 2, 3, 4]), 'target': tensor([10, 11, 12, 13, 14])}
# torch.Size([5])
# {'img': tensor([5, 6, 7, 8, 9]), 'target': tensor([15, 16, 17, 18, 19])}
# torch.Size([5])
</code></pre>
<p>but it’s unclear how you are setting up your dataset and how the samples are created.</p>

TzviNoy: <p>Since the input / output format seems unusual wouldn’t it be a suitable case for using custom-made collate_fn?</p>

ptrblck: <p>Maybe a custom <code>collate_fn</code> could help as I don’t know why the original code doesn’t work.<br>
My code snippet shows that <code>dict</code>s are acceptable and won’t create the mentioned output.</p>

TzviNoy: <p>Isn’t it because the batch contains elements that are not tensors (dicts and list) that pytorch unable to batch? in your last code snippet you are returning a dict but its values are tensors so it is clear how to batch across samples. As I understand the question we will have:</p>
<pre><code class="lang-auto">   def __getitem__(self, index):
      x = img, img_meta_dict, img_transforms # tensor, dict, list
      y = seg, seg_meta_dict, seg_transforms # tensor, dict, list
      return {"img": x, "target": y}
</code></pre>
<p><a class="mention" href="/u/david_hresko">@David_Hresko</a> I think you can change the get_item for something as follow:</p>
<pre><code class="lang-auto">   def __getitem__(self, index):
      img_transforms = Compose(img_transforms)
      x = img_transforms(img)
      seg_transforms = Compose(seg_transforms)
      y = seg_transforms(img)
      
      return {"img": x, "target": y, "img_meta": img_meta_dict, "seg_meta": seg_meta_dict}
</code></pre>
<p>and:</p>
<pre><code class="lang-auto">for (imgs, targets, imgs_meta, targets_meta) in train_loader:
   your_code
</code></pre>
<p>then the imgs and targets will have the expected shapes</p>