content: import copy as cp
  
  import torch
  from mmcv.parallel import MMDataParallel, MMDistributedDataParallel
  from mmcv.runner import (DistSamplerSeedHook, EpochBasedRunner, OptimizerHook,
                           build_optimizer)
  from mmcv.runner.hooks import Fp16OptimizerHook
  
  from ..core import (DistEpochEvalHook, EpochEvalHook,
                      OmniSourceDistSamplerSeedHook, OmniSourceRunner, AnnealingRunner)
  from ..datasets import build_dataloader, build_dataset
  from ..utils import get_root_logger
  
  
  def train_model(model,
                  dataset,
                  cfg,
                  distributed=False,
                  validate=False,
                  timestamp=None,
                  meta=None):
      """Train model entry function.
  
      Args:
          model (nn.Module): The model to be trained.
          dataset (:obj:`Dataset`): Train dataset.
          cfg (dict): The config dict for training.
          distributed (bool): Whether to use distributed training.
              Default: False.
          validate (bool): Whether to do evaluation. Default: False.
          timestamp (str | None): Local time for runner. Default: None.
          meta (dict | None): Meta dict to record some important information.
              Default: None
      """
      logger = get_root_logger(log_level=cfg.log_level)
  
      # prepare data loaders
      dataset = dataset if isinstance(dataset, (list, tuple)) else [dataset]
  
      dataloader_setting = dict(
          videos_per_gpu=cfg.data.get('videos_per_gpu', 1),
          workers_per_gpu=cfg.data.get('workers_per_gpu', 1),
          num_gpus=len(cfg.gpu_ids),
          dist=distributed,
          seed=cfg.seed,
          pin_memory=cfg.data.get('pin_memory', True))  # by default, pin_memory=True
      dataloader_setting = dict(dataloader_setting,
                                **cfg.data.get('train_dataloader', {}))
  
      if cfg.omnisource:
          # The option can override videos_per_gpu
          train_ratio = cfg.data.get('train_ratio', [1] * len(dataset))
          omni_videos_per_gpu = cfg.data.get('omni_videos_per_gpu', None)
          if omni_videos_per_gpu is None:
              dataloader_settings = [dataloader_setting] * len(dataset)
          else:
              dataloader_settings = []
              for videos_per_gpu in omni_videos_per_gpu:
                  this_setting = cp.deepcopy(dataloader_setting)
                  this_setting['videos_per_gpu'] = videos_per_gpu
                  dataloader_settings.append(this_setting)
          data_loaders = [
              build_dataloader(ds, **setting)
              for ds, setting in zip(dataset, dataloader_settings)
          ]
  
      else:
          data_loaders = [
              build_dataloader(ds, **dataloader_setting) for ds in dataset
          ]
  
      # put model on gpus
      if distributed:
          find_unused_parameters = cfg.get('find_unused_parameters', False)
          # Sets the `find_unused_parameters` parameter in
          # torch.nn.parallel.DistributedDataParallel
          model = MMDistributedDataParallel(
              model.cuda(),
              device_ids=[torch.cuda.current_device()],
              broadcast_buffers=False,
              find_unused_parameters=find_unused_parameters)
      else:
          model = MMDataParallel(
              model.cuda(cfg.gpu_ids[0]), device_ids=cfg.gpu_ids)
  
      # build runner
      optimizer = build_optimizer(model, cfg.optimizer)
  
      # Runner = OmniSourceRunner if cfg.omnisource else EpochBasedRunner
      if cfg.omnisource:
          Runner = OmniSourceRunner
      elif cfg.get('annealing_runner', False):
          Runner = AnnealingRunner  # add annealing runner support
      else:
          Runner = EpochBasedRunner
      runner = Runner(
          model,
          optimizer=optimizer,
          work_dir=cfg.work_dir,
          logger=logger,
          meta=meta)
      # an ugly workaround to make .log and .log.json filenames the same
      runner.timestamp = timestamp
  
      # fp16 setting
      fp16_cfg = cfg.get('fp16', None)
      if fp16_cfg is not None:
          optimizer_config = Fp16OptimizerHook(
              **cfg.optimizer_config, **fp16_cfg, distributed=distributed)
      elif distributed and 'type' not in cfg.optimizer_config:
          optimizer_config = OptimizerHook(**cfg.optimizer_config)
      else:
          optimizer_config = cfg.optimizer_config
  
      # register hooks
      runner.register_training_hooks(cfg.lr_config, optimizer_config,
                                     cfg.checkpoint_config, cfg.log_config,
                                     cfg.get('momentum_config', None))
      if distributed:
          if cfg.omnisource:
              runner.register_hook(OmniSourceDistSamplerSeedHook())
          else:
              runner.register_hook(DistSamplerSeedHook())
  
      if validate:
          eval_cfg = cfg.get('evaluation', {})
          val_dataset = build_dataset(cfg.data.val, dict(test_mode=True))
          dataloader_setting = dict(
              videos_per_gpu=cfg.data.get('videos_per_gpu', 1),
              workers_per_gpu=cfg.data.get('workers_per_gpu', 1),
              # cfg.gpus will be ignored if distributed
              num_gpus=len(cfg.gpu_ids),
              dist=distributed,
              pin_memory=cfg.data.get('pin_memory', True),  # by default, pin_memory=True
              shuffle=False)
          dataloader_setting = dict(dataloader_setting,
                                    **cfg.data.get('val_dataloader', {}))
          val_dataloader = build_dataloader(val_dataset, **dataloader_setting)
          eval_hook = DistEpochEvalHook if distributed else EpochEvalHook
          runner.register_hook(eval_hook(val_dataloader, **eval_cfg))
  
      if cfg.resume_from:
          runner.resume(cfg.resume_from)
      elif cfg.load_from:
          runner.load_checkpoint(cfg.load_from)
      runner_kwargs = dict()
      if cfg.omnisource:
          runner_kwargs = dict(train_ratio=train_ratio)
      if cfg.get('annealing_runner', False):
          runner_kwargs.update(annealing=True)
      runner.run(data_loaders, cfg.workflow, cfg.total_epochs, **runner_kwargs)
  