How to add noise to MNIST dataset when using pytorch

copyrightly: <p>I want to add noise to MNIST. I am using the following code to read the dataset:</p>
<pre><code class="lang-auto">train_loader = torch.utils.data.DataLoader(
    datasets.MNIST('../data', train=True, download=True,
                   transform=transforms.Compose([
                       transforms.ToTensor(),
                       transforms.Normalize((0.1307,), (0.3081,))
                   ])),
    batch_size=64, shuffle=True)
</code></pre>
<p>I’m not sure how to add (gaussian) noise to each image in MNIST.</p>

ptrblck: <p>You could create a custom transformation:</p>
<pre><code class="lang-python">class AddGaussianNoise(object):
    def __init__(self, mean=0., std=1.):
        self.std = std
        self.mean = mean
        
    def __call__(self, tensor):
        return tensor + torch.randn(tensor.size()) * self.std + self.mean
    
    def __repr__(self):
        return self.__class__.__name__ + '(mean={0}, std={1})'.format(self.mean, self.std)
</code></pre>
<p>and just add it to <code>transforms.Compose</code>:</p>
<pre><code class="lang-python">transform=transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.1307,), (0.3081,)),
    AddGaussianNoise(0., 1.)
])
</code></pre>

copyrightly: <p>Hi Ptrblck, may I ask another question. What if I want to add noise to just a fraction of the training samples, not all of them? Thank you!</p>

ptrblck: <p>If you would like to add it randomly, you could specify a probability inside the transformation and pass this probability while instantiating it.</p>
<p>On the other hand, if you would like to apply it just for specified data indices, you might need to apply the noise inside the training loop and use the data index (return the index additionally in your <code>Dataset</code>).</p>

copyrightly: <p>I tried to add it randomly and used the following code:<br>
<code>transforms.RandomApply(AddGaussianNoise(args.mean, args.std), p=0.5)</code><br>
But I received an error:</p>
<p>assert isinstance(transforms, (list, tuple))<br>
AssertionError</p>
<p>Is there anything wrong with my code? Thank you!</p>

ptrblck: <p>Could you try to pass <code>AddGaussianNoise</code> as a <code>list</code> or <code>tuple</code>?</p>

copyrightly: <p>Thank you! I changed it to <code>[AddGaussianNoise(args.mean, args.std)]</code>. Now it works!</p>

saba: <p>Hi Dear Ptrblck,</p>
<p>I have a question, I want to add noise to my original training dataset to have more robust model. It is good to add noise after data normalization or before data normalization my normalization is zero mean and unite variance?</p>

ptrblck: <p>I would probably add it after the normalization, as you can easily define the standard deviation and mean of your (white) noise.</p>

saba: <p>after normalization cause each value of the noise have different effect on the training, but before normalization the effect of the noise on training is same.is not it?</p>

ptrblck: <p>The effect would be the same, but I think it might be easier to define the noise relative to your samples, if each data sample has already a zero mean and a unit variance.<br>
Anyway, I don’t think it should make a difference if you define the noise using the mean of the unnormalized inputs and their stddev.</p>

saba: <p>my inputs are patches, for each patch if I define a Gaussian noise with the same mean and std can be good? the patch are 11<em>11</em>7</p>

ptrblck: <p>The approach sounds reasonable, but I can’t say if it’ll work good or bad.<br>
Feel free to share the results of your experiments. <img src="https://discuss.pytorch.org/images/emoji/apple/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>

saba: <p>Hi Ptrblck,</p>
<p>I want to create a 3 dimensional Gaussian with defined size and standard deviation. My code in Matlab is :</p>
<pre><code class="lang-auto"> % Gaussian3D Creates 3-D Gaussian Kernel of specified
 % width sigma_array=[sigma_x, sigma_y, sigma_z] with
 % profile length of size_array=[size_x, size_y, size_z]
 a1=t1;
 b1=t2;
 c1=t3;
 if(all([sigma_array ])&gt;0 &amp; length(size_array) == length(sigma_array))
  % Make 1D Gaussian kernel
  % Filter each dimension with the 1D Gaussian kernels\
  sigma_x=sigma_array(1);
  size_x=size_array(1);
  sigma_y=sigma_array(2);
  size_y=size_array(2);
  sigma_z=sigma_array(3);
  size_z=size_array(3);

   Kx = fspecial('gaussian', [1 round(size_x)], sigma_x);
   Ky = fspecial('gaussian', [1 round(size_y)], sigma_y);
  Kz = fspecial('gaussian', [1 round(size_z)], sigma_z);
  % since gaussian Kernel is separable
  G=convn(Hz,convn(Hx,Hy));
 end
end```

Would you please tell me what is the equivalent of Convn and the fspecial in pytorch?</code></pre>

ptrblck: <p>You could use <a href="https://pytorch.org/docs/stable/distributions.html#torch.distributions.multivariate_normal.MultivariateNormal">torch.distributions.multivariate_normal.MultiVariateNormal</a> or alternatively sample from <code>torch.randn</code> and scale with the stddev as well as shift with the mean.</p>

saba: <p>Hi Ptrblck,</p>
<p>I wrote this code for Gaussian in pytorch . But I can not see my Gaussian. ```</p>
<p>“”"<br>
import torch<br>
import torch.nn as nn<br>
import numpy as np</p>
<p>sigma_array=np.array([.5, .5, .5])<br>
size_array=11<br>
G= Gaussian3d(sigma_array,size_array)<br>
def Gaussian3d(sigma_array,size_array):<br>
size_array1=torch.tensor([1,2,3,4,5,6,7,8,9,10,11])<br>
G = np.asarray(size_array)<br>
x,y,z= torch.meshgrid(size_array1,size_array1,size_array1)</p>
<pre><code>x = x -size_array/2-0.5
y = y -size_array/2-0.5
z = z -size_array/2-0.5

G = torch.exp(-((x)**2/(2*(sigma_array[0]**2)) +(y)**2/(2*(sigma_array[1]**2)) +(z)**2/(2*(sigma_array[2]**2)) ))

return G```
</code></pre>
<p>Do you see any problem?</p>

saba: <p>is it right now?"""<br>
import torch<br>
import torch.nn as nn<br>
import numpy as np</p>
<p>sigma_array=np.array([1.5,1.5, 1.5])<br>
size_array=11<br>
G= Gaussian3d(sigma_array,size_array)<br>
def Gaussian3d(sigma_array,size_array):<br>
size_array1=torch.tensor([-5,-4 ,-3 ,-2 ,-1 ,0 ,1 ,2 ,3 ,4 ,5])<br>
G = np.asarray(size_array)<br>
x,y,z= torch.meshgrid(size_array1,size_array1,size_array1)</p>
<h1>x = x -size_array/2-0.5</h1>
<h1>y = y -size_array/2-0.5</h1>
<h1>z = z -size_array/2-0.5</h1>

saba: <p>Many thanks for your reply. Sorry I need t find the local maxima in the 3 dimension. In Matlab I use “imreginalmax” , My input is 120<em>220</em>80 ,the out put is a binary with the same size of the  input.  which means wherever it is 1 there is a local maximum in the input.</p>
<p>What is the equivalent in pytorch I need to have the same output means the binary in 3D wherever is 1 there is a local maxima in the input.</p>
<p>I really appreciate your help</p>

Ripley: <p>Hi, I saw your solution and it helps alot! Thank you so much! However, i am quite new to python from zero knowledge, would you be able to explain what the function under call does? and in general what noise adjust?</p>
<p>Oh and also, by adjusting the mean and std will it affect the normalization of the image when we pass it into our dataloader? Thank you!</p>

ptrblck: <p><code>AddGaussianNoise</code> adds gaussian noise using the specified <code>mean</code> and <code>std</code> to the input tensor in the preprocessing of the data.<br>
<code>torch.randn</code> creates a tensor filled with random numbers from the standard normal distribution (zero mean, unit variance) as described in the <a href="https://pytorch.org/docs/stable/generated/torch.randn.html#torch.randn">docs</a>. In <code>AddGaussianNoise.__call__</code> this noise tensor will be multiplied with <code>self.std</code> and <code>self.mean</code> will be added to scale and shift the distribution.</p>