text: from collections.abc import Sequence
  
  import mmcv
  import numpy as np
  import torch
  from mmcv.parallel import DataContainer as DC
  
  from ..registry import PIPELINES
  
  
  def to_tensor(data):
      """Convert objects of various python types to :obj:`torch.Tensor`.
  
      Supported types are: :class:`numpy.ndarray`, :class:`torch.Tensor`,
      :class:`Sequence`, :class:`int` and :class:`float`.
      """
      if isinstance(data, torch.Tensor):
          return data
      elif isinstance(data, np.ndarray):
          return torch.from_numpy(data)
      elif isinstance(data, Sequence) and not mmcv.is_str(data):
          return torch.tensor(data)
      elif isinstance(data, int):
          return torch.LongTensor([data])
      elif isinstance(data, float):
          return torch.FloatTensor([data])
      else:
          raise TypeError('type {} cannot be converted to tensor.'.format(
              type(data)))
  
  
  @PIPELINES.register_module
  class ToTensor(object):
  
      def __init__(self, keys):
          self.keys = keys
  
      def __call__(self, results):
          for key in self.keys:
              results[key] = to_tensor(results[key])
          return results
  
      def __repr__(self):
          return self.__class__.__name__ + '(keys={})'.format(self.keys)
  
  
  @PIPELINES.register_module
  class ImageToTensor(object):
  
      def __init__(self, keys):
          self.keys = keys
  
      def __call__(self, results):
          for key in self.keys:
              if results[key].ndim == 3:
                results[key] = to_tensor(results[key].transpose(2, 0, 1))
              else:
                results[key] = to_tensor(results[key])
          return results
  
      def __repr__(self):
          return self.__class__.__name__ + '(keys={})'.format(self.keys)
  
  
  @PIPELINES.register_module
  class Transpose(object):
  
      def __init__(self, keys, order):
          self.keys = keys
          self.order = order
  
      def __call__(self, results):
          for key in self.keys:
              results[key] = results[key].transpose(self.order)
          return results
  
      def __repr__(self):
          return self.__class__.__name__ + '(keys={}, order={})'.format(
              self.keys, self.order)
  
  
  @PIPELINES.register_module
  class ToDataContainer(object):
  
      def __init__(self,
                   fields=(dict(key='img', stack=True), dict(key='gt_bboxes'),
                           dict(key='gt_labels'))):
          self.fields = fields
  
      def __call__(self, results):
          for field in self.fields:
              field = field.copy()
              key = field.pop('key')
              results[key] = DC(results[key], **field)
          return results
  
      def __repr__(self):
          return self.__class__.__name__ + '(fields={})'.format(self.fields)
  
  
  @PIPELINES.register_module
  class DefaultFormatBundle(object):
      """Default formatting bundle.
  
      It simplifies the pipeline of formatting common fields, including "img",
      "proposals", "gt_bboxes", "gt_labels", "gt_masks" and "gt_semantic_seg".
      These fields are formatted as follows.
  
      - img: (1)transpose, (2)to tensor, (3)to DataContainer (stack=True)
      - proposals: (1)to tensor, (2)to DataContainer
      - gt_bboxes: (1)to tensor, (2)to DataContainer
      - gt_bboxes_ignore: (1)to tensor, (2)to DataContainer
      - gt_labels: (1)to tensor, (2)to DataContainer
      - gt_masks: (1)to tensor, (2)to DataContainer (cpu_only=True)
      - gt_semantic_seg: (1)unsqueeze dim-0 (2)to tensor,
                         (3)to DataContainer (stack=True)
      """
  
      def __call__(self, results):
          if 'img' in results:
              img = np.ascontiguousarray(results['img'].transpose(2, 0, 1))
              results['img'] = DC(to_tensor(img), stack=True)
          for key in ['proposals', 'gt_bboxes', 'gt_bboxes_ignore', 'gt_labels', 'gt_relations']:
              if key not in results:
                  continue
              results[key] = DC(to_tensor(results[key]))
          if 'gt_masks' in results:
              results['gt_masks'] = DC(results['gt_masks'], cpu_only=True)
          if 'gt_semantic_seg' in results:
              results['gt_semantic_seg'] = DC(
                  to_tensor(results['gt_semantic_seg'][None, ...]), stack=True)
          return results
  
      def __repr__(self):
          return self.__class__.__name__
  
  
  @PIPELINES.register_module
  class Collect(object):
      """
      Collect data from the loader relevant to the specific task.
  
      This is usually the last stage of the data loader pipeline. Typically keys
      is set to some subset of "img", "proposals", "gt_bboxes",
      "gt_bboxes_ignore", "gt_labels", and/or "gt_masks".
  
      The "img_meta" item is always populated.  The contents of the "img_meta"
      dictionary depends on "meta_keys". By default this includes:
  
          - "img_shape": shape of the image input to the network as a tuple
              (h, w, c).  Note that images may be zero padded on the bottom/right
              if the batch tensor is larger than this shape.
  
          - "scale_factor": a float indicating the preprocessing scale
  
          - "flip": a boolean indicating if image flip transform was used
  
          - "filename": path to the image file
  
          - "ori_shape": original shape of the image as a tuple (h, w, c)
  
          - "pad_shape": image shape after padding
  
          - "img_norm_cfg": a dict of normalization information:
              - mean - per channel mean subtraction
              - std - per channel std divisor
              - to_rgb - bool indicating if bgr was converted to rgb
      """
  
      def __init__(self,
                   keys,
                   meta_keys=('filename', 'ori_shape', 'img_shape', 'pad_shape',
                              'scale_factor', 'flip', 'img_norm_cfg',
                              'rotate_angle', 'classes'),
                   ):
          self.keys = keys
          self.meta_keys = meta_keys
          pass
  
      def __call__(self, results):
          data = {}
          img_meta = {}
          for key in self.meta_keys:
            if key in results:
              img_meta[key] = results[key]
          data['img_meta'] = DC(img_meta, cpu_only=True)
          for key in self.keys:
              if key not in results:
                continue
              data[key] = results[key]
          self.filter_classes(data)
          return data
  
      def filter_classes(self, data):
          if 'gt_labels' not in data:
            return
          if isinstance(data['gt_labels'], np.ndarray):
            mask = data['gt_labels'] >= 0
            data['gt_bboxes'] = data['gt_bboxes'][mask]
            data['gt_labels'] = data['gt_labels'][mask]
          else:
            mask = data['gt_labels'].data >= 0
            data['gt_bboxes'] = DC(data['gt_bboxes'].data[mask])
            n0 = mask.shape[0]
            n1 = data['gt_relations'].data.shape[0]
            if n0==n1:
              data['gt_relations'] = DC(data['gt_relations'].data[mask])
            else:
              print(f'\n\n gt_relations num = {n1}, but gt_labels num = {n0} \n\n')
            data['gt_labels'] = DC(data['gt_labels'].data[mask])
  
  
  def unused_filter_classes(gt_bboxes, gt_labels):
      valid_labels = [self.beike._category_ids_map[c] for c in self.classes]
      masks = [results['gt_labels'].data == l for l in valid_labels ]
      mask = masks[0]
      for m in masks[1:]:
        mask += m
      import pdb; pdb.set_trace()  # XXX BREAKPOINT
      results['gt_bboxes'].data = results['gt_bboxes'].data[mask]
      results['gt_labels'].data = results['gt_labels'].data[mask]
      import pdb; pdb.set_trace()  # XXX BREAKPOINT
      pass
  
  
      def __repr__(self):
          return self.__class__.__name__ + '(keys={}, meta_keys={})'.format(
              self.keys, self.meta_keys)
  