class_docstr: Trainer for behavioral cloning learning.
  
  Runs training on top of provided trajectory data and rolls out the policy using the provided evaluator.
  
  In structured (multi-step) envs, all policies are trained simultaneously based on the substep actions
  and observation present in the trajectory data.
class_docstr_tok: ["Trainer","for","behavioral","cloning","learning",".","Runs","training","on","top","of","provided","trajectory","data","and","rolls","out","the","policy","using","the","provided","evaluator",".","In","structured","(","multi-step",")","envs",",","all","policies","are","trained","simultaneously","based","on","the","substep","actions","and","observation","present","in","the","trajectory","data","."]
docstr: Run training.
  :param evaluator: Evaluator to use for evaluation rollouts
  :param n_epochs: How many epochs to train for
  :param eval_every_k_iterations: Number of iterations after which to run evaluation (in addition to evaluations
  at the end of each epoch, which are run automatically). If set to None, evaluations will run on epoch end only.
docstr_tok: ["Run","training",".",":","param","evaluator",":","Evaluator","to","use","for","evaluation","rollouts",":","param","n_epochs",":","How","many","epochs","to","train","for",":","param","eval_every_k_iterations",":","Number","of","iterations","after","which","to","run","evaluation","(","in","addition","to","evaluations","at","the","end","of","each","epoch",",","which","are","run","automatically",")",".","If","set","to","None",",","evaluations","will","run","on","epoch","end","only","."]
code: def train(
      self,
      evaluator: Evaluator,
      n_epochs: Optional[int] = None,
      eval_every_k_iterations: Optional[int] = None,
  ) -> None:
      """
      Run training.
      :param evaluator: Evaluator to use for evaluation rollouts
      :param n_epochs: How many epochs to train for
      :param eval_every_k_iterations: Number of iterations after which to run evaluation (in addition to evaluations
      at the end of each epoch, which are run automatically). If set to None, evaluations will run on epoch end only.
      """
  
      if n_epochs is None:
          n_epochs = self.algorithm_config.n_epochs
      if eval_every_k_iterations is None:
          eval_every_k_iterations = (
              self.algorithm_config.eval_every_k_iterations
          )
  
      for epoch in range(n_epochs):
          print(f"\n********** Epoch {epoch + 1} started **********")
          evaluator.evaluate(self.policy)
          increment_log_step()
  
          for iteration, data in enumerate(self.data_loader, 0):
              observations, actions, actor_ids = data
              self._run_iteration(
                  observations=observations,
                  actions=actions,
                  actor_ids=actor_ids,
              )
  
              # Evaluate after each k iterations if set
              if (
                  eval_every_k_iterations is not None
                  and iteration % eval_every_k_iterations
                  == (eval_every_k_iterations - 1)
              ):
                  print(
                      f"\n********** Epoch {epoch + 1}: Iteration {iteration + 1} **********"
                  )
                  evaluator.evaluate(self.policy)
                  increment_log_step()
  
      print(f"\n********** Final evaluation **********")
      evaluator.evaluate(self.policy)
      increment_log_step()
  
imports: from dataclasses import dataclass
  from typing import Dict, Union, Optional, List
  import torch
  from torch.optim import Optimizer
  from torch.utils.data import DataLoader
  from typing.io import BinaryIO
  from maze.core.agent.torch_policy import TorchPolicy
  from maze.core.annotations import override
  from maze.core.env.action_conversion import ActionType, TorchActionType
  from maze.core.env.observation_conversion import ObservationType, TorchObservationType
  from maze.core.env.structured_env import ActorID
  from maze.core.log_stats.log_stats import LogStatsAggregator, LogStatsLevel, get_stats_logger, increment_log_step
  from maze.perception.perception_utils import convert_to_torch
  from maze.train.trainers.common.evaluators.evaluator import Evaluator
  from maze.train.trainers.common.trainer import Trainer
  from maze.train.trainers.imitation.bc_algorithm_config import BCAlgorithmConfig
  from maze.train.trainers.imitation.bc_loss import BCLoss
  from maze.train.trainers.imitation.imitation_events import ImitationEvents
  from maze.train.utils.train_utils import compute_gradient_norm, debatch_actor_ids
label_desc: Use image node_id 2 for calling the BCTrainer obj's underlying member method code with example usage: obj.train(evaluator, n_epochs, eval_every_k_iterations) without return types