How to modify and use a data loader?

username: jarvico
cooked: <p>Hi,</p>
<p>I need to use a modified version of data loader in my study.</p>
<p>Assume that I have a basic train loader like this:</p>
<pre><code class="lang-auto">train_data = datasets.MNIST(root='../../Data', train=True, download=False, transform=transforms.ToTensor())

train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=False)
</code></pre>
<p>First I use it in the beginning.</p>
<p>But then for a different task, I need to add a noise to all samples in train dataset. And then I should be able use the noisy data, using a new data loader.</p>
<p>I can update all samples with noise using below code, but I don’t know how to save that modified train dataset as a data loader and use it later in different code sections.</p>
<pre><code class="lang-auto">def noise(x, eps, clip_min, clip_max):
    eta = torch.FloatTensor(*x.shape).normal_(mean=0,std=eps).to(x.device)
    adv_x = x + eta
    if clip_min is not None and clip_max is not None:
        adv_x = torch.clamp(adv_x, min=clip_min, max=clip_max)
    return adv_x


my_noisy_train_loader = train_loader

for i, (image,label) in enumerate(my_noisy_train_loader):
    image = noise(image,0.3,0,1)
   #How to update noisy train loader?


</code></pre>
<p>Could you please suggest how can I modify the data loader and use afterwards?</p>
<p>Or;<br>
Maybe I need to create a custom modified dataset(noisy MNIST dataset lets say), and load this new modified dataset using a new data loader, but I also do not know how to modify and save datasets.MNIST so that I can use it later on.</p>

username: albanD
cooked: <p>Hi,</p>
<p>I think that the simplest solution is to create a custom <code>transform</code> that adds this noise. You can them pass that transform when you create your Dataset and keep using the Dataloader as before.</p>

username: jarvico
cooked: <p>Thanks for your prompt reply.</p>
<p>The point is I will not only need noise dataset, but later I will also use perturbed dataset. For example all the data in dataset will need to be perturbed with different adversarial attack types like FGSM, BIM, CW etc.</p>
<p>Thats why I thought that I can create a custom dataset for all different cases like noisy_MNIST_dataset , BIM_MNIST dataset etc.</p>
<p>I can not meet this need this using transform…</p>

username: Wesley_Neill
cooked: <p>To just add to what <a class="mention" href="/u/alband">@albanD</a> mentioned, here is an excellent resource for custom datasets and transforms:</p>
<p><a href="https://pytorch.org/tutorials/beginner/data_loading_tutorial.html" rel="noopener nofollow ugc">Writing Custom Datasets, DataLoaders and Transforms — PyTorch Tutorials 1.6.0 documentation</a></p>

username: albanD
cooked: <p>If you want these to be “permanent” datasets, then you might be able to modify the dataset and save it again on disk. You can later load it again as a TensorDataset (for mnist it shouldn’t be too large).</p>

username: jarvico
cooked: <p>Actually i do not know how to modify and save as a new dataset. Is it possible to share some piece of code to guide me on this?</p>

username: Wesley_Neill
cooked: <p>Is there any reason that these perturbations can’t be in the form of a custom transform? As far as I know, what you are describing is the exact use case of transforms.</p>

username: albanD
cooked: <p>The mnist dataset is actually a file with two Tensors, one for images and one for labels. You can see how it’s loaded here: <a href="https://github.com/pytorch/vision/blob/74de51d6d478e289135d9274e6af550a9bfba137/torchvision/datasets/mnist.py#L89">https://github.com/pytorch/vision/blob/74de51d6d478e289135d9274e6af550a9bfba137/torchvision/datasets/mnist.py#L89</a></p>
<p>So you can just modify these two Tensors and save them again.</p>

username: Deeply
cooked: <p>In order to have flexibility to play with the noise, I wouldn’t save a noise-added dataset.<br>
As for your case where you want to add more perturbations, that transform approach also works here. You can have several conditional transforms if needed, <em>ie</em> to add or not add noise, followed by other perturbations as needed. Here’s one example from one of my projects:</p>
<pre><code class="lang-auto">train_transform = transforms.Compose([
            ImageThinning(p = cf.thinning_threshold) if cf.thinning_threshold &lt; 1 else NoneTransform(),            
            OverlayImage(cf) if cf.overlay_image else NoneTransform(), # Add random image background here, to mimic painting            
            PadImage((cf.MAX_IMAGE_WIDTH, cf.MAX_IMAGE_HEIGHT)) if cf.pad_images else NoneTransform(),            
            transforms.Resize(cf.input_size) if cf.resize_images else NoneTransform(),            
            transforms.ToTensor(),            
            transforms.Lambda(lambda x: x.repeat(3, 1, 1))  if not(RGB_img)  else NoneTransform(), # in case the image has a single channel 
            transforms.Normalize( mu, std ) if cf.normalize_images else NoneTransform(),                                   
            ])    
</code></pre>
<p><code>ImageThinning</code>, <code>OverlayImage</code>, and, <code>PadImage</code> are custom transforms.</p>
<p>You still need to code your customized transforms (if you can’t find one from PyTorch that works for you)… Here’s an example for the (custom) <code>ImageThinning</code> transform shown above.</p>
<pre><code class="lang-auto">class ImageThinning(object):
    """  Image input as PIL and output as PIL
        To be used as part of  torchvision.transforms
       Args: p, a threshold value to control image thinning        
    """
    def __init__(self, p = 0.2):
        self.p = p                  
        
    def __call__(self, image):
        image = image_thinning(image, self.p)         
        return image

</code></pre>
<p>The other approach (as Wesley mentioned) is to define a <a href="https://pytorch.org/tutorials/beginner/data_loading_tutorial.html" rel="noopener nofollow ugc">custom dataset</a> class and have <code>train_data = datasets.MNIST...</code> as the object of that class, and then, play with the noise or any other perturbations at the <code>__getitem__ </code> level.</p>
<p>Either ways, you’d have to get your hands dirty with coding. Good luck!</p>