Why do images look weird after (Imagenet) normalization?

username: mayool
cooked: <p>Hey,<br>
I am using a pretrained network and wanted to normalize my images according to the ImageNet.<br>
For some reason however the images look really weird after the normalization.</p>
<p>Can someone explain to me why this is happening?</p>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/e/6/e639d21fc1ba3e89e7039a3b4fa1d387a4f98932.jpeg" data-download-href="https://discuss.pytorch.org/uploads/default/e639d21fc1ba3e89e7039a3b4fa1d387a4f98932" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/e/6/e639d21fc1ba3e89e7039a3b4fa1d387a4f98932_2_353x375.jpeg" alt="image" data-base62-sha1="wQFHjLjmKLL2HHrPAFaKeoq4GLE" width="353" height="375" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/e/6/e639d21fc1ba3e89e7039a3b4fa1d387a4f98932_2_353x375.jpeg, https://discuss.pytorch.org/uploads/default/optimized/3X/e/6/e639d21fc1ba3e89e7039a3b4fa1d387a4f98932_2_529x562.jpeg 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/e/6/e639d21fc1ba3e89e7039a3b4fa1d387a4f98932_2_706x750.jpeg 2x" data-dominant-color="576159"><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">image</span><span class="informations">786×834 415 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><br>
(with normalization)</p>
<p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/2/5/25c884f2f0b6b574acf0a769353c6ddda7326f39.jpeg" data-download-href="https://discuss.pytorch.org/uploads/default/25c884f2f0b6b574acf0a769353c6ddda7326f39" title="image"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/2/5/25c884f2f0b6b574acf0a769353c6ddda7326f39_2_355x375.jpeg" alt="image" data-base62-sha1="5ofhb9grZ4qk9bKIchpzVyT0Zyp" width="355" height="375" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/2/5/25c884f2f0b6b574acf0a769353c6ddda7326f39_2_355x375.jpeg, https://discuss.pytorch.org/uploads/default/optimized/3X/2/5/25c884f2f0b6b574acf0a769353c6ddda7326f39_2_532x562.jpeg 1.5x, https://discuss.pytorch.org/uploads/default/optimized/3X/2/5/25c884f2f0b6b574acf0a769353c6ddda7326f39_2_710x750.jpeg 2x" data-dominant-color="706855"><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">image</span><span class="informations">787×830 166 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><br>
(without normalization)</p>
<p>Here is the code of the transform (I build my own):</p>
<pre><code class="lang-auto">import torchvision.transforms.functional as TF

class my_transform:
    def __init__(self):
        #my_parameters

    def __call__(self, img, label=False):
        #(some other transforms like Horizontal flip)
        img = TF.to_tensor(img)
        if not label:
            img = TF.normalize(img, mean=[0.485, 0.456, 0.406],
                               std=[0.229, 0.224, 0.225])
        return img

</code></pre>
<p>any help is much appreciated!</p>

username: JuanFMontesinos
cooked: <p>btw normalizing that way doesn’t even ensure a proper format to visualize them…<br>
You need to make them to be between 0-1 or 0-255</p>

username: mayool
cooked: <p>right before the normalization at:</p>
<pre><code class="lang-auto">img = TF.to_tensor(img)
</code></pre>
<p>the values are in range [0-1] but after they are &gt;1.</p>
<p>So you mean the normalization works and is just for the network input and not meant to be visualized directly?</p>
<p>If I want to visualize it I need to re-normalize it back to 0-1?</p>
<p>If so, how do I do that? <img src="https://discuss.pytorch.org/images/emoji/apple/smiley.png?v=9" title=":smiley:" class="emoji" alt=":smiley:"></p>

username: JuanFMontesinos
cooked: <p>You can just map values to 0-1 in a linear way. <a href="https://stackoverflow.com/questions/4154969/how-to-map-numbers-in-range-099-to-range-1-01-0" rel="nofollow noopener">https://stackoverflow.com/questions/4154969/how-to-map-numbers-in-range-099-to-range-1-01-0</a></p>

username: mayool
cooked: <p>Thanks man!<br>
Worked perfectly.</p>
<p>In case anyone else comes across this issue:</p>
<pre><code class="lang-auto">    def renormalize(self, tensor):
        minFrom= tensor.min()
        maxFrom= tensor.max()
        minTo = 0
        maxTo=1
        return minTo + (maxTo - minTo) * ((tensor - minFrom) / (maxFrom - minFrom))
</code></pre>
<p>this code worked for me</p>

username: Nikronic
cooked: <p>Hi,<br>
As you are using custom mean and std, I think the proper approach of unnormalization would be to unnormalize using those mean and stds. Please see this thread: <a href="https://discuss.pytorch.org/t/simple-way-to-inverse-transform-normalization/4821/4" class="inline-onebox">Simple way to inverse transform ? Normalization</a></p>
<p>Bests</p>

username: mayool
cooked: <p>Thank you! Tried it out and the output looks like a normal picture…</p>
<p>I will definitely keep a solution from the post you send, thanks for that! <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>
<p>One think that still confuses me now is which tensor should be fed into the network?</p>
<pre><code class="lang-auto"># bring the values back to a range of [0-1]
invTrans = T.Normalize(
                mean=[-0.485 / 0.229, -0.456 / 0.224, -0.406 / 0.225],
                std=[1 / 0.229, 1 / 0.224, 1 / 0.225]
            )

img = TF.normalize(img, mean=[0.485, 0.456, 0.406],
                               std=[0.229, 0.224, 0.225])
            
img2 = invTrans(img)
</code></pre>
<p>img <strong>without</strong> range [0-1] or img2 <strong>with</strong> range [0-1]?</p>

username: JuanFMontesinos
cooked: <p>Hi,<br>
For me the point is he want to visualize the images after normalizing. It’s not possible due to the format they use but you can keep the normalization and remap it.</p>
<p>Unnormalize is indeed returning the original image.</p>

username: Nikronic
cooked: <p>Yes, the reason that I suggested that approach is that it will give the statistics similar original images in the dataset, meanwhile it might not be necessary for visualization purposes.</p>

username: Nikronic
cooked: <aside class="quote no-group" data-username="mayool" data-post="7" data-topic="92071">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/m/41988e/48.png" class="avatar"> mayool:</div>
<blockquote>
<p>which tensor should be fed into the network?</p>
</blockquote>
</aside>
<p>If you want to just scale your input in range of <code>[0, 1]</code>, <code>transforms.ToTensor</code> will do the job. If you need to compute z-score you can use <code>transforms.Normalize</code>.<br>
As you have mentioned you are using pretrained network, you may want to normalize them. Unnormalization is used for viewing the transformed images or when your model predicts an image which usually is normalized output.</p>
<aside class="quote no-group" data-username="mayool" data-post="7" data-topic="92071">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/m/41988e/48.png" class="avatar"> mayool:</div>
<blockquote>
<p>img <strong>without</strong> range [0-1] or img2 <strong>with</strong> range [0-1]?</p>
</blockquote>
</aside>
<p>Just note that when you are using <code>transforms.Normalize</code>, you are using z-score, so the output will not be in range <code>[0, 1]</code>. It depends on the mean and std but if you set mean and std = 0.5 for all channels it will be in <code>[-1, 1]</code>, otherwise, out of this range.</p>
<p>You can find the proper input from the implementation of pretrained model, but usually, you will find normalization based on ImageNet values.</p>

username: cuteboyqq
cooked: <p>It works for me, thanks a lot</p>