IndexError: too many indices for tensor of dimension 3. Unable to apply a custom transform in transforms.Compose

username: Sarah_Khaleel
cooked: <p>This is my custom transform function that I want to apply over the whole dataset.</p>
<pre><code class="lang-auto">class normalization(object):
    def __call__(self, sample):
          image, label = sample['image'], sample['labels']
          fmin= torch.min (image)
          fm = image- fmin
          image = 255*fm/torch.max(fm)  
          return {'Normalized image': image, 'Labels':label
                  }
</code></pre>
<p>I am adding the custom transform in transforms.Compose using code below.</p>
<pre><code class="lang-auto">batch_size= 100
size= 299, 299
data_transforms = transforms.Compose([transforms.Resize(size),
                                       transforms.ToTensor(),                                       
                                       transforms.Normalize([0.485, 0.456, 0.406],
                                                            [0.229, 0.224, 0.225]),
                                       transforms.Grayscale(num_output_channels=1),
                                       normalization()
])
</code></pre>
<p>Data loading is done using:</p>
<pre data-code-wrap="data_dir"><code class="lang-data_dir">
data_set = torchvision.datasets.ImageFolder(root= data_dir, transform=data_transforms)

train_set_size = int(len(data_set) * 0.6)
test_set_size = len(data_set) - train_set_size

train_set, test_set = torch.utils.data.random_split(
    data_set, [train_set_size, test_set_size], 
    generator=torch.Generator().manual_seed(72))

data_loader = DataLoader(data_set, batch_size=batch_size,shuffle=False)

train_data_loader = DataLoader(train_set, batch_size=batch_size,shuffle=True)

test_data_loader = DataLoader(test_set, batch_size=batch_size,shuffle=False)

</code></pre>
<p>The below code block is causing the error:</p>
<pre data-code-wrap="for"><code class="lang-for">    
    image, _ = data_set[i]
    print('types:', type(image))
    print(i, image.size())
    ax = plt.subplot(1, 4, i+1 )
    plt.tight_layout()
    ax.set_title('Sample #{}'.format(i))

    if i == 3:
        plt.show()
        break
</code></pre>
<p>Error:<br>
<img src="https://discuss.pytorch.org/uploads/default/original/3X/4/7/478d875dfe93e828190e2b707b75b3617c4c34fd.png" alt="pytorch 1" data-base62-sha1="acZ7Ies1KUgcMWnEo200NrBmiG9" width="682" height="335"></p>
<p>I don’t understand what’s causing an issue in my custom transform function. Also, the ‘image’ should be tensor type but currently it’s type is ‘dict’.</p>
<p>Any help is appreciated!</p>

username: ptrblck
cooked: <p>The used transformations expect a single tensor while your custom <code>normalization</code> transformation expects a <code>dict</code> and thus tries to index the tensor with the <code>"image"</code> and <code>"labels"</code> keys, which breaks:</p>
<pre><code class="lang-python">x = torch.randn(3, 224, 224)
x["image"]
# IndexError: too many indices for tensor of dimension 3
</code></pre>

username: Sarah_Khaleel
cooked: <p>Ok. So, should I apply the custom transform separately or change the custom transform function somehow? I need to apply custom <code>normalization</code> transformation to the images of my dataset.</p>

username: ptrblck
cooked: <p>Yes, change the custom <code>normalization</code> method to work on a single input tensor only and it should work.<br>
I.e. in particular something like this should work:</p>
<pre><code class="lang-python">class normalization(object):
    def __call__(self, x):
          fmin = torch.min(x)
          fm = image - fmin
          image = 255 * fm / torch.max(fm)
          return image
</code></pre>

username: Sarah_Khaleel
cooked: <p>Thanks! Now the image is in tensor form. But the custom <code>normalization</code> transform should be resulting in a tensor with min and max range between 0 and 1. Currently, the resulting tensor is between 0 and 255.</p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/1/5/1532a52c37b8d9482dd9ecab7b4fd6964198d17e.png" alt="pytorch 2" data-base62-sha1="31wx5FsHhG0MNX19uo34f5NBy7Y" width="347" height="179"><br>
<img src="https://discuss.pytorch.org/uploads/default/original/3X/1/c/1c2a4528d0d5fe7b36415999bad5cc89af52e1b1.png" alt="pytorch 0" data-base62-sha1="419VOL99WeFnnD4IomeG9apQsdH" width="682" height="187"></p>
<p>Unlike the results that I got when I applied the below <code>normalization</code> function for a single image.</p>
<pre><code class="lang-auto">def normalization(img, train_set):
    for n in enumerate(train_set):

        fmin= torch.min (img)
        fm= img- fmin
        img_sca= 255*fm/torch.max(fm)  
        return img_sca
</code></pre>
<pre><code class="lang-auto">img=img=torchvision.io.read_image('/content/drive/MyDrive/Dataset/Chest x-ray (COVID-19 &amp; Pneumonia)/train/COVID19/COVID19(0).jpg')

imgs_sca= normalization (img, train_set)
imgs_sca = imgs_sca[0, :,:]
print(imgs_sca.shape)
plt.imshow(imgs_sca.squeeze(), cmap="gray") 
plt.title("Normalized image")
</code></pre>
<p>Output was a tensor between 0 and 1. As shown below.</p>
<p><img src="https://discuss.pytorch.org/uploads/default/original/3X/f/5/f5e36a90dd0b25d61b9d7e8463083ca182741add.png" alt="pytorch 3" data-base62-sha1="z5edtBbDOAaULhuDVqBgqTJcEd7" width="432" height="308"><br>
<img src="https://discuss.pytorch.org/uploads/default/original/3X/7/b/7b29ba3971bd0200d4cf071d55f6f9453faae927.png" alt="pytorch 4" data-base62-sha1="hzy81LlbtBl1U9jp42YIimSY5jV" width="606" height="183"></p>
<p>I want this same result. What could be causing the difference in the output of these transform functions?</p>

username: Sarah_Khaleel
cooked: <p>Hi <a class="mention" href="/u/ptrblck">@ptrblck</a>,</p>
<p>I used the custom normalization function that you suggested. It gave the following error:</p>
<pre><code class="lang-auto">UnboundLocalError                         Traceback (most recent call last)
&lt;ipython-input-12-72e5a241f536&gt; in &lt;module&gt;
      1 for i in range(len(data_set)):
      2 
----&gt; 3     image, label = data_set[i]
      4     print('types:', type(image), type(label))
      5     print(i, image.size())

2 frames
&lt;ipython-input-9-954be77ef823&gt; in __call__(self, x)
     11     def __call__(self, x):
     12           fmin = torch.min(x)
---&gt; 13           fm = image - fmin
     14           image = 255 * fm / torch.max(fm)
     15           return image

UnboundLocalError: local variable 'image' referenced before assignment
</code></pre>
<p>So, I changed the function as:</p>
<pre><code class="lang-auto">class normalization(object):    
    def __call__(self, x):          
          fmin = torch.min(x)          
          fm = x - fmin     #fm=f−min⁡(f)
          image = 255 * fm / torch.max(fm)      #fs=K[fm/max⁡(fm ) , for 8 bit image, K=255 
          return image 
</code></pre>
<p>The normalization function is not working when used with transforms.Compose. Is there any other way I can apply the custom transform function to the whole dataset?</p>

username: ptrblck
cooked: <p>It works for me:</p>
<pre><code class="lang-python">class normalization(object):    
    def __call__(self, x):          
          fmin = torch.min(x)          
          fm = x - fmin
          image = 255 * fm / torch.max(fm)
          return image 

transform = transforms.Compose([
    transforms.ToTensor(),
    normalization(),])

img = transforms.ToPILImage()(torch.randn(3, 224, 224))
out = transform(img)
print(out.min(), out.max())
# tensor(0.) tensor(255.)
</code></pre>
<p>What kind of error are you seeing?</p>

username: Sarah_Khaleel
cooked: <p>Ok, I got it. My custom transform is working differently depending on the different images given to it. It is working when used with transform.Compose. Thanks for your help so far.</p>