title: Pytorch : Applying lambda transformations in case of segmentation tasks in custom transformation function
body: <p>I am trying to perform multiclass image segmentation. There are some transformations which should be applied to both image and masks like rotations and flips etc. I followed <a href="https://discuss.pytorch.org/t/torchvision-transfors-how-to-perform-identical-transform-on-both-image-and-target/10606/7?u=rishav_sapahia" rel="nofollow noreferrer">this</a>
  post and applied it but the issue is I have certain lambda transformations also which I need to apply but I can't apply using the above method.How to apply them.
  Below are the transformations I need-</p>
  
  <pre><code>data_transforms = transforms.Compose([transforms.RandomCrop((512,512)),
                               transforms.Lambda(gaussian_blur),
                               transforms.Lambda(elastic_transform),
                               transforms.RandomRotation([+90,+180]),
                               transforms.RandomRotation([+180,+270]),
                               transforms.RandomHorizontalFlip(),
                               transforms.ToTensor(),
                               transforms.Normalize(mean=train_mean, std=train_std)
                             ])
  </code></pre>
  
  <p>My Dataloader for identical transformations for the image and mask is below, I wasn't able to apply my lambda transformations in it, it was throwing an error 
  <code>AttributeError: module 'torchvision.transforms.functional' has no attribute 'Lambda'
  </code></p>
  
  <pre><code>class DataLoaderSegmentation(data.Dataset):
  def __init__(self,folder_path,transform = None):
      super(DataLoaderSegmentation, self).__init__()
      self.img_files = glob.glob(os.path.join(folder_path,'images','*.tif'))
      self.mask_files = glob.glob(os.path.join(folder_path,'mask','*.bmp'))
      # self.transform = transform
  
  
  def mask_to_class(self,mask):
      target = torch.from_numpy(mask)
      h,w = target.shape[0],target.shape[1]
      masks = torch.empty(h, w, dtype=torch.long)
      colors = torch.unique(target.view(-1,target.size(2)),dim=0).numpy()
      target = target.permute(2, 0, 1).contiguous()
      mapping = {tuple(c): t for c, t in zip(colors.tolist(), range(len(colors)))}
      for k in mapping:
          idx = (target==torch.tensor(k, dtype=torch.uint8).unsqueeze(1).unsqueeze(2))
          validx = (idx.sum(0) == 3) 
          masks[validx] = torch.tensor(mapping[k], dtype=torch.long)
      return masks
  
  def transform(self,image,mask):
      i, j, h, w = transforms.RandomCrop.get_params(
      image, output_size=(512, 512))
      image = TF.crop(image, i, j, h, w)
      mask = TF.crop(mask, i, j, h, w)
  
      #image = TF.Lambda(gaussian_blur),
  
      #image = TF.Lambda(elastic_transform)
      # Random horizontal flipping
      if random.random() &gt; 0.5:
          image = TF.hflip(image)
          mask = TF.hflip(mask)
  
      image = TF.rotate(image,90)
      mask = TF.rotate(mask,90)
      image = TF.rotate(image,180)
      mask = TF.rotate(mask,180)
      image = TF.rotate(image,270)
      mask = TF.rotate(mask,270)
  
      # Transform to tensor
      image = TF.to_tensor(image)
      return image, mask
  
  def __getitem__(self, index):
      img_path = self.img_files[index]
      mask_path = self.mask_files[index]
      data = Image.open(img_path)
      label = Image.open(mask_path)
      data,label = self.transform(data,label)
      label = np.array(label)  
      mask = self.mask_to_class(label)
      return data,mask
  
  
  def __len__(self):
      return len(self.img_files)
  </code></pre>
  
  <p>How to do it, or is there any other way to do it?</p>
  
  <p>Edit---
  Following is my solution for it-</p>
  
  <pre><code>class DataLoaderSegmentation(data.Dataset):
  def __init__(self,folder_path,transform = None):
      super(DataLoaderSegmentation, self).__init__()
      self.img_files = glob.glob(os.path.join(folder_path,'images','*.tif'))
      self.mask_files = glob.glob(os.path.join(folder_path,'mask','*.bmp'))
      self.transforms = transform
      #for img_path in img_files:
       #   self.mask_files.append(os.path.join(folder_path,'masks',os.path.basename(img_path))
  
  def mask_to_class(self,mask):
      target = torch.from_numpy(mask)
      h,w = target.shape[0],target.shape[1]
      masks = torch.empty(h, w, dtype=torch.long)
      colors = torch.unique(target.view(-1,target.size(2)),dim=0).numpy()
      target = target.permute(2, 0, 1).contiguous()
      mapping = {tuple(c): t for c, t in zip(colors.tolist(), range(len(colors)))}
      for k in mapping:
          idx = (target==torch.tensor(k, dtype=torch.uint8).unsqueeze(1).unsqueeze(2))
          validx = (idx.sum(0) == 3) 
          masks[validx] = torch.tensor(mapping[k], dtype=torch.long)
      return masks
  
  def transform(self,image,mask):
      i, j, h, w = transforms.RandomCrop.get_params(
      image, output_size=(512, 512))
      image = TF.crop(image, i, j, h, w)
      mask = TF.crop(mask, i, j, h, w)
  
      #image = TF.Lambda(gaussian_blur),
     # mask = 
      #image = TF.Lambda(elastic_transform)
      # Random horizontal flipping
      image = F.Lambda(gaussian_blur)
      if random.random() &gt; 0.5:
          image = TF.hflip(image)
          mask = TF.hflip(mask)
  
      image = TF.rotate(image,90)
      mask = TF.rotate(mask,90)
      image = TF.rotate(image,180)
      mask = TF.rotate(mask,180)
      image = TF.rotate(image,270)
      mask = TF.rotate(mask,270)
  
      # Transform to tensor
      #image = TF.to_tensor(image)
      #mask = TF.to_tensor(mask)
      return image, mask
  
  def __getitem__(self, index):
      img_path = self.img_files[index]
      mask_path = self.mask_files[index]
      data = Image.open(img_path)
      label = Image.open(mask_path)
     # label = np.array(label)
      data,label = self.transform(data,label)
      label = np.array(label)
      data = np.array(data)
      #label = np.transpose(label,(2,0,1))
      mask = self.mask_to_class(label)
      if transforms is not None:
          data = self.transforms(data)
      return data,mask
     # return data, torch.from_numpy(label).long()
  
  def __len__(self):
      return len(self.img_files)
  </code></pre>
  
  <p>and the transformation are below-</p>
  
  <pre><code>data_transforms = transforms.Compose([
                               transforms.Lambda(gaussian_blur),
                               transforms.Lambda(elastic_transform),
                               transforms.ToTensor(),
                               transforms.Normalize(mean=train_mean, std=train_std)
                             ])
  </code></pre>