class_docstr: VISSL wraps around transforms so that they work with the multimodal input.
  VISSL supports batches that come from several datasets and sources. Hence
  the input batch (images, labels) always is a list.
  
  To apply the user defined transforms, VISSL takes "indices" as input which
  defines on what dataset/source data in the sample should the transform be
  applied to. For example:
      Assuming input sample is {
          "data": [dataset1_imgX, dataset2_imgY],
          "label": [dataset1_lblX, dataset2_lblY]
      }
      and the transform is:
          TRANSFORMS:
              - name: RandomGrayscale
                p: 0.2
                indices: 0
      then the transform is applied only on dataset1_imgX. If however, the
      indices are either not specified or set to 0, 1 then the transform
      is applied on both dataset1_imgX and dataset2_imgY
  
  Since this structure of data is introduced by vissl, the SSLTransformsWrapper
  takes care of dealing with the multi-modality input by wrapping the
  original transforms (pytorch transforms or custom transforms defined by user)
  and calling each transform on each index.
  
  VISSL also supports _TRANSFORMS_WITH_LABELS transforms that modify the label
  or are used to generate the labels used in self-supervised learning tasks like
  Jigsaw. When the transforms in _TRANSFORMS_WITH_LABELS are called, the new
  label is also returned besides the transformed image.
  
  VISSL also supports the _TRANSFORMS_WITH_COPIES which are transforms
  that basically generate several copies of image. Common example
  of self-supervised training methods that do this is SimCLR, SwAV, MoCo etc
  When a transform from _TRANSFORMS_WITH_COPIES is used, the SSLTransformsWrapper
  will flatten the transform output.
  For example for the input [img1], if we apply ImgReplicatePil to replicate
  the image 2 times:
      SSLTransformsWrapper(
          ImgReplicatePil(num_times=2), [img1]
      )
      will output [img1_1, img1_2] instead of nested list [[img1_1, img1_2]].
  The benefit of this is that the next set of transforms specified by user can now
  operate on img1_1 and img1_2 as the input becomes multi-modal nature.
  
  VISSL also supports _TRANSFORMS_WITH_GROUPING which essentially means
  that a single transform should be applied on the full multi-modal input
  together instead of separately. This is common transform used in BYOL/
  For example:
      SSLTransformsWrapper(
          ImgPilMultiCropRandomApply(
              RandomApply, prob=[0.0, 0.2]
          ), [img1_1, img1_2]
      )
      this will apply RandomApply on img1_1 with prob=0.0 and on img1_2 with
      prob=0.2
code: def _transform(self, sample):
      # Run on all indices if empty set is passed.
      indices = (
          self.indices
          if self.indices
          else set(range(len(sample["data"])))
      )
      if self._is_grouping_transform():
          # if the transform needs to be applied to all the indices
          # together. For example: one might want to vary the intensity
          # of a transform across several crops of an image as in BYOL.
          output = self.transform(sample["data"])
          sample["data"] = output
      else:
          for idx in indices:
              output = self.transform(sample["data"][idx])
              # Generalized transformation: we can add additional
              # keys inside the sample (for instance a label, a mask, etc)
              if isinstance(output, dict):
                  sample["data"][idx] = output["data"]
                  for k, v in output.items():
                      if k != "data":
                          sample.setdefault(k, []).append(v)
              # Deprecated generalized transformation (only working
              # for "labels"). Return a map instead
              elif self._is_transform_with_labels():
                  sample["data"][idx] = output[0]
                  sample["label"][-1] = output[1]
              # Transformation on the data only
              else:
                  sample["data"][idx] = output
  
      if self._is_transform_with_copies():
          # if the transform makes copies of the data, we just flatten the list
          # so the next set of transforms will operate on more indices. We also
          # need to replicate the label and metadata.
  
          data, label, data_valid, data_idx = [], [], [], []
          for i, img_replicas in enumerate(sample["data"]):
              num_times = len(img_replicas)
              data += img_replicas
              label += [sample["label"][i]] * num_times
              data_valid += [sample["data_valid"][i]] * num_times
              data_idx += [sample["data_idx"][i]] * num_times
  
          sample["data"] = data
          sample["label"] = label
          sample["data_idx"] = data_idx
          sample["data_valid"] = data_valid
  
      return sample
  
file_path: vissl/vissl/data/ssl_transforms/ssl_transforms_wrapper.py
imports: from typing import Any, Dict
  from classy_vision.dataset.transforms import build_transform, register_transform
  from classy_vision.dataset.transforms.classy_transform import ClassyTransform
  from vissl.utils.misc import is_augly_available
label_desc: Use image node_id 9 for calling the SSLTransformsWrapper obj's underlying member method code with example usage: obj._transform(sample) and returns: sample