class_docstr: Run training based on the number of iterations. This is common when
  the training dataset size is large. Underhood logic is similar to
  epoch-based training by considering every #iters_per_inner_epoch as an
  inner epoch.
  
  In iter-based runner, after every #iters_per_inner_epoch steps, we
  
      1) do a validation epoch;
      2) schedule the learning rate;
      3) save the checkpoint.
  
  We refer every #iters_per_inner_epoch steps as an inner epoch.
class_docstr_tok: ["Run","training","based","on","the","number","of","iterations",".","This","is","common","when","the","training","dataset","size","is","large",".","Underhood","logic","is","similar","to","epoch-based","training","by","considering","every","#","iters_per_inner_epoch","as","an","inner","epoch",".","In","iter-based","runner",",","after","every","#","iters_per_inner_epoch","steps",",","we","1",")","do","a","validation","epoch",";","2",")","schedule","the","learning","rate",";","3",")","save","the","checkpoint",".","We","refer","every","#","iters_per_inner_epoch","steps","as","an","inner","epoch","."]
code: def train(self):
      start_time = time.time()
      best_agg_metric = 0
      best_iters = 0
  
      self.log_config()
  
      # resume from checkpoint if specified
      if not self.evaluate_only and self.resume_ckpt_path is not None:
          self._load_checkpoint(self.resume_ckpt_path)
  
      for start_iters in range(
          self.start_iters, self.max_iters, self.iters_per_inner_epoch
      ):
          end_iters = start_iters + self.iters_per_inner_epoch
  
          # training phase
          if not self.evaluate_only:
              logging.info(
                  "Start training, max_iters={}, in total {} inner epochs.".format(
                      self.max_iters,
                      int(self.max_iters / self.iters_per_inner_epoch),
                  )
              )
              if start_iters == self.start_iters:
                  self.task.before_training(
                      model=self.unwrap_dist_model(self.model),
                      dataset=self.datasets,
                  )
              train_stats = self.train_iters(
                  self.cur_epoch, start_iters
              )
              self.log_stats(split_name="train", stats=train_stats)
  
          # evaluation phase
          if len(self.valid_splits) > 0 and (
              self.evaluate_only
              or (end_iters // self.iters_per_inner_epoch)
              % self.val_freq
              == 0
          ):
              for split_name in self.valid_splits:
                  logging.info("Evaluating on {}.".format(split_name))
  
                  val_log = self.eval_epoch(
                      split_name=split_name,
                      cur_epoch=self._progress(end_iters),
                  )
                  if val_log is not None:
                      if is_main_process():
                          assert (
                              "agg_metrics" in val_log
                          ), "No agg_metrics found in validation log."
  
                          agg_metrics = val_log["agg_metrics"]
                          if (
                              agg_metrics > best_agg_metric
                              and split_name == "val"
                          ):
                              best_iters, best_agg_metric = (
                                  end_iters,
                                  agg_metrics,
                              )
  
                              self._save_checkpoint(
                                  end_iters, is_best=True
                              )
  
                          val_log.update({"best_iters": best_iters})
                          self.log_stats(val_log, split_name)
  
          else:
              # if no validation split is provided, we just save the checkpoint at the end of each inner epoch.
              if not self.evaluate_only:
                  self._save_checkpoint(end_iters, is_best=False)
  
          if self.evaluate_only:
              break
  
          # save checkpoint according to save freq
          # if self.save_freq>0 and (end_iters//self.iters_per_inner_epoch)%self.save_freq == 0:
          self._save_checkpoint(end_iters, is_best=False)
  
          dist.barrier()
  
      # save last checkpoint
      if self.save_last and not self.evaluate_only:
          self._save_checkpoint(end_iters, is_best=False)
  
      # testing phase
      self.evaluate(cur_epoch=self.cur_epoch)
  
      total_time = time.time() - start_time
      total_time_str = str(datetime.timedelta(seconds=int(total_time)))
      logging.info("Training time {}".format(total_time_str))
  
imports: import datetime
  import logging
  import os
  import time
  import torch
  import torch.distributed
  import webdataset
  from lavis.common.dist_utils import download_cached_file, is_main_process, main_process
  from lavis.common.registry import registry
  from lavis.common.utils import is_url
  from lavis.datasets.data_utils import concat_datasets, reorg_datasets_by_split
  from lavis.runners.runner_base import RunnerBase
  from torch.utils.data.dataset import ChainDataset
label_desc: Use image node_id 5 for calling the RunnerIter obj's underlying member method code with example usage: obj.train() without return types