code: def concat_detection_datasets(
      datasets: Sequence[SupportedDetectionDataset],
      *,
      transform: Optional[XTransform] = None,
      target_transform: Optional[YTransform] = None,
      transform_groups: Optional[
          Mapping[str, Tuple[XTransform, YTransform]]
      ] = None,
      initial_transform_group: Optional[str] = None,
      task_labels: Optional[
          Union[int, Sequence[int], Sequence[Sequence[int]]]
      ] = None,
      targets: Optional[
          Union[Sequence[TTargetType], Sequence[Sequence[TTargetType]]]
      ] = None,
      collate_fn: Optional[Callable[[List], Any]] = None,
  ) -> Union[DetectionDataset, SupervisedDetectionDataset]:
      """Creates a ``AvalancheConcatDataset`` instance.
  
      For simple subset operations you should use the method
      `dataset.concat(other)` or
      `concat_datasets` from `avalanche.benchmarks.utils.utils`.
      Use this constructor only if you need to redefine transformation or
      class/task labels.
  
      A Dataset that behaves like a PyTorch
      :class:`torch.utils.data.ConcatDataset`. However, this Dataset also supports
      transformations, slicing, advanced indexing and the targets field and all
      the other goodies listed in :class:`AvalancheDataset`.
  
      This dataset guarantees that the operations involving the transformations
      and transformations groups are consistent across the concatenated dataset
      (if they are subclasses of :class:`AvalancheDataset`).
  
      :param datasets: A collection of datasets.
      :param transform: A function/transform that takes the X value of a
          pattern from the original dataset and returns a transformed version.
      :param target_transform: A function/transform that takes in the target
          and transforms it.
      :param transform_groups: A dictionary containing the transform groups.
          Transform groups are used to quickly switch between training and
          eval (test) transformations. This becomes useful when in need to
          test on the training dataset as test transformations usually don't
          contain random augmentations. ``AvalancheDataset`` natively supports
          the 'train' and 'eval' groups by calling the ``train()`` and
          ``eval()`` methods. When using custom groups one can use the
          ``with_transforms(group_name)`` method instead. Defaults to None,
          which means that the current transforms will be used to
          handle both 'train' and 'eval' groups (just like in standard
          ``torchvision`` datasets).
      :param initial_transform_group: The name of the initial transform group
          to be used. Defaults to None, which means that if all
          AvalancheDatasets in the input datasets list agree on a common
          group (the "current group" is the same for all datasets), then that
          group will be used as the initial one. If the list of input datasets
          does not contain an AvalancheDataset or if the AvalancheDatasets
          do not agree on a common group, then 'train' will be used.
      :param targets: The label of each pattern. Can either be a sequence of
          labels or, alternatively, a sequence containing sequences of labels
          (one for each dataset to be concatenated). Defaults to None, which
          means that the targets will be retrieved from the datasets (if
          possible).
      :param task_labels: The task labels for each pattern. Must be a sequence
          of ints, one for each pattern in the dataset. Alternatively, task
          labels can be expressed as a sequence containing sequences of ints
          (one for each dataset to be concatenated) or even a single int,
          in which case that value will be used as the task label for all
          instances. Defaults to None, which means that the dataset will try
          to obtain the task labels from the original datasets. If no task
          labels could be found for a dataset, a default task label 0 will
          be applied to all patterns of that dataset.
      :param collate_fn: The function to use when slicing to merge single
          patterns. This function is the function used in the data loading
          process, too. If None, the constructor will check if a `collate_fn`
          field exists in the first dataset. If no such field exists, the
          default collate function for detection  will be used.
          Beware that the chosen collate function will be applied to all
          the concatenated datasets even if a different collate is defined
          in different datasets.
      """
      dds = []
      per_dataset_task_labels = _split_user_def_task_label(
          datasets, task_labels
      )
  
      per_dataset_targets = _split_user_def_targets(
          datasets, targets, lambda x: isinstance(x, dict)
      )
  
      for dd, dataset_task_labels, dataset_targets in zip(
          datasets, per_dataset_task_labels, per_dataset_targets
      ):
          dd = make_detection_dataset(
              dd,
              transform=transform,
              target_transform=target_transform,
              transform_groups=transform_groups,
              initial_transform_group=initial_transform_group,
              task_labels=dataset_task_labels,
              targets=dataset_targets,
              collate_fn=collate_fn,
          )
          dds.append(dd)
  
      if (
          transform is None
          and target_transform is None
          and transform_groups is None
          and initial_transform_group is None
          and task_labels is None
          and targets is None
          and collate_fn is None
          and len(datasets) > 0
      ):
          d0 = datasets[0]
          if isinstance(d0, DetectionDataset):
              for d1 in datasets[1:]:
                  d0 = d0.concat(d1)
              return d0
  
      das: List[DataAttribute] = []
      if len(dds) > 0:
          #######################################
          # TRANSFORMATION GROUPS
          #######################################
          transform_groups_obj = _init_transform_groups(
              transform_groups,
              transform,
              target_transform,
              initial_transform_group,
              dds[0],
          )
  
          # Find common "current_group" or use "train"
          if initial_transform_group is None:
              uniform_group = None
              for d_set in datasets:
                  if isinstance(d_set, AvalancheDataset):
                      if uniform_group is None:
                          uniform_group = (
                              d_set._transform_groups.current_group
                          )
                      else:
                          if (
                              uniform_group
                              != d_set._transform_groups.current_group
                          ):
                              uniform_group = None
                              break
  
              if uniform_group is None:
                  initial_transform_group = "train"
              else:
                  initial_transform_group = uniform_group
  
          #######################################
          # DATA ATTRIBUTES
          #######################################
  
          totlen = sum([len(d) for d in datasets])
          if (
              task_labels is not None
          ):  # User defined targets always take precedence
              all_labels: IDataset[int]
              if isinstance(task_labels, int):
                  all_labels = ConstantSequence(task_labels, totlen)
              else:
                  all_labels_lst = []
                  for dd, dataset_task_labels in zip(
                      dds, per_dataset_task_labels
                  ):
                      assert dataset_task_labels is not None
  
                      # We already checked that len(t_labels) == len(dataset)
                      # (done in _split_user_def_task_label)
                      if isinstance(dataset_task_labels, int):
                          all_labels_lst.extend(
                              [dataset_task_labels] * len(dd)
                          )
                      else:
                          all_labels_lst.extend(dataset_task_labels)
                  all_labels = all_labels_lst
              das.append(
                  DataAttribute(
                      all_labels,
                      "targets_task_labels",
                      use_in_getitem=True,
                  )
              )
  
          if (
              targets is not None
          ):  # User defined targets always take precedence
              all_targets_lst: List[TTargetType] = []
              for dd, dataset_targets in zip(dds, per_dataset_targets):
                  assert dataset_targets is not None
  
                  # We already checked that len(targets) == len(dataset)
                  # (done in _split_user_def_targets)
                  all_targets_lst.extend(dataset_targets)
              das.append(DataAttribute(all_targets_lst, "targets"))
      else:
          transform_groups_obj = None
          initial_transform_group = "train"
  
      data = DetectionDataset(
          dds,
          transform_groups=transform_groups_obj,
          data_attributes=das if len(das) > 0 else None,
      )
      return data.with_transforms(initial_transform_group)
  
imports: from functools import partial
  from typing import List, Any, Sequence, Union, Optional, TypeVar, Callable, Dict, Tuple, Mapping, overload
  import torch
  from torch import Tensor
  from torch.utils.data.dataset import Subset, ConcatDataset
  from avalanche.benchmarks.utils.utils import TaskSet, _init_task_labels, _init_transform_groups, _split_user_def_targets, _split_user_def_task_label, _traverse_supported_dataset
  from .collate_functions import detection_collate_fn
  from .data import AvalancheDataset
  from .data_attribute import DataAttribute
  from .dataset_definitions import IDataset, IDatasetWithTargets
  from .dataset_utils import SubSequence
  from .flat_data import ConstantSequence
  from .transform_groups import TransformGroupDef, DefaultTransformGroups, TransformGroups, XTransform, YTransform
label_desc: Use image node_id 14 for calling a global function with example usage: concat_detection_datasets(datasets) and returns: data, d0