Use a subset of Composed Transforms with same random seed

Nikronic: <p>Hi,<br>
I have a <code>custom_transform</code> variable defined as follows:</p>
<pre><code class="lang-python">custom_transforms = Compose([
    RandomResizedCrop(size=224, scale=(0.8, 1.2)),
    RandomRotation(degrees=(-30, 30)),
    RandomHorizontalFlip(p=0.5),
    ToTensor(),
    Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
    RandomNoise(p=0.5, mean=0, std=0.1)])
</code></pre>
<p>I use this to apply transformations on input images through <code>__getitem__</code> method. I have 3 images in each sample returned by <code>__getitem__</code>.<br>
The first image is the target image which I generate it dynamically from input and my input is the ground truth. Finally, the third image is also generated using some modification on the target image.</p>
<p>Now the question is, I do not want to use <code>RandomNoise</code> and <code>Normalize</code> on the second and third images, but will same random transforms like <code>Crop</code>, <code>Flip</code>, etc happen on ground truth?</p>
<p>I have read some issues on Github and it seems random seed resets somehow.<br>
Here is what I have done:</p>
<pre><code class="lang-python">transform_gt = Compose(custom_transform.transforms[:-1])
</code></pre>
<p>Thanks for any advices</p>

JuanFMontesinos: <p>Githhub transformations applies transformations frame-wise. Thus, different transformations will be applied to both gt and images. It’s not a matter of seed rather than the way torchvision is done. <a href="https://github.com/JuanFMontesinos/flerken/blob/master/flerken/dataloaders/transforms/transforms.py" rel="nofollow noopener">https://github.com/JuanFMontesinos/flerken/blob/master/flerken/dataloaders/transforms/transforms.py</a><br>
This file reimplements transforms such that you can apply same transformation to a list a frames.<br>
About subsets try to apply common part in one transform and specific parts in other transforms</p>

Nikronic: <p>I tried this code using your <code>transforms.py</code>:</p>
<pre><code class="lang-python">custom_transforms = Compose([
    RandomRotation(degrees=(-30, 30)),
    RandomHorizontalFlip(p=0.5),
])

i1 = Image.open('dataset/sub_test/data/Places365_val_00000002.jpg')
i2 = Image.open('dataset/sub_test/data/Places365_val_00000003.jpg')

it12 = custom_transforms([i1, i2])
</code></pre>
<p>But I got these errors:</p>
<pre><code class="lang-python"> File "C:\Users\NIkan\Desktop\Deep Halftoning\Github\Deep-Halftoning\lib\transforms.py", line 69, in __call__
    return self.apply_sequence(inpt)
  File "C:\Users\NIkan\Desktop\Deep Halftoning\Github\Deep-Halftoning\lib\transforms.py", line 79, in apply_sequence
    output = list(map(self.apply_img, seq))
  File "C:\Users\NIkan\Desktop\Deep Halftoning\Github\Deep-Halftoning\lib\transforms.py", line 75, in apply_img
    img = t(img)
  File "C:\Users\NIkan\Desktop\Deep Halftoning\Github\Deep-Halftoning\lib\transforms.py", line 990, in __call__
    self.get_params()
TypeError: get_params() missing 1 required positional argument: 'degrees'
</code></pre>
<p>It seems it calls <code>self.get_params()</code> without passing provided <code>degrees</code>.</p>
<aside class="onebox githubblob">
  <header class="source">
      <a href="https://github.com/JuanFMontesinos/flerken/blob/dae0d5f33e1b3d7cf3dc7c159ffec326179f9f8f/flerken/dataloaders/transforms/transforms.py#L971-L990" target="_blank" rel="nofollow noopener">github.com</a>
  </header>
  <article class="onebox-body">
    <h4><a href="https://github.com/JuanFMontesinos/flerken/blob/dae0d5f33e1b3d7cf3dc7c159ffec326179f9f8f/flerken/dataloaders/transforms/transforms.py#L971-L990" target="_blank" rel="nofollow noopener">JuanFMontesinos/flerken/blob/dae0d5f33e1b3d7cf3dc7c159ffec326179f9f8f/flerken/dataloaders/transforms/transforms.py#L971-L990</a></h4>
<pre class="onebox"><code class="lang-py"><ol class="start lines" start="971" style="counter-reset: li-counter 970 ;">
<li>def get_params(self, degrees):</li>
<li>    """Get parameters for ``rotate`` for a random rotation.</li>
<li>
</li>
<li>    Returns:</li>
<li>        sequence: params to be passed to ``rotate`` for random rotation.</li>
<li>    """</li>
<li>    self.angle = random.uniform(degrees[0], degrees[1])</li>
<li>
</li>
<li>def reset_params(self):</li>
<li>    self.angle = None</li>
<li>
</li>
<li>def __call__(self, img):</li>
<li>    """</li>
<li>        img (PIL Image): Image to be rotated.</li>
<li>
</li>
<li>    Returns:</li>
<li>        PIL Image: Rotated image.</li>
<li>    """</li>
<li>    if self.angle is None:</li>
<li>        self.get_params()</li>
</ol></code></pre>


  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>


Nikronic: <p>The problem solved using feeding same <code>seed</code> value before applying each <code>Compose</code> of transforms.</p>
<aside class="onebox githubissue">
  <header class="source">
      <a href="https://github.com/pytorch/vision/issues/9#issuecomment-304224800" target="_blank" rel="nofollow noopener">github.com/pytorch/vision</a>
  </header>
  <article class="onebox-body">
    <a href="https://github.com/fmassa" rel="nofollow noopener">
<img src="https://avatars1.githubusercontent.com/u/9110200?v=2&amp;s=96" class="thumbnail onebox-avatar" width="60" height="60">
</a>

<h4><a href="https://github.com/pytorch/vision/issues/9#issuecomment-304224800" target="_blank" rel="nofollow noopener">Issue: Random transforms for both input and target?</a></h4>

<div class="date" style="margin-top:10px;">
	<div class="user" style="margin-top:10px;">
	opened by <a href="https://github.com/fmassa" target="_blank" rel="nofollow noopener">fmassa</a>
	on <a href="https://github.com/pytorch/vision/issues/9#issuecomment-304224800" target="_blank" rel="nofollow noopener">2016-11-28</a>
	</div>
	<div class="user">
	closed by <a href="https://github.com/fmassa" target="_blank" rel="nofollow noopener">fmassa</a>
	on <a href="https://github.com/pytorch/vision/issues/9#issuecomment-304224800" target="_blank" rel="nofollow noopener">2017-09-03</a>
	</div>
</div>

<pre class="content" style="white-space: pre-wrap;">In some scenarios (like semantic segmentation), we might want to apply the same random transform to both the input and the...</pre>

<div class="labels">
</div>

  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>

<pre><code class="lang-auto">def __getitem__(self,index):      
        img = Image.open(self.data[index]).convert('RGB')
        target = Image.open(self.data_labels[index])
        
        seed = np.random.randint(2147483647) # make a seed with numpy generator 
        random.seed(seed) # apply this seed to img tranfsorms
        if self.transform is not None:
            img = self.transform(img)
            
        random.seed(seed) # apply this seed to target tranfsorms
        if self.target_transform is not None:
            target = self.target_transform(target)

        target = torch.ByteTensor(np.array(target))
    
        return img, target
</code></pre>
<p>By the way, it works completely fine on a subset of transforms.</p>

JuanFMontesinos: <p>I just rewrote everything so there may be minor issues</p>

Nikronic: <p>Ow, sorry.<br>
Thanks for your help.</p>