class_docstr: Utility to train a policy on a particular task.
  
  Different from traditional DL trainer, the iteration of this trainer is "collect",
  rather than "epoch", or "mini-batch".
  In each collect, :class:`Collector` collects a number of policy-env interactions, and accumulates
  them into a replay buffer. This buffer is used as the "data" to train the policy.
  At the end of each collect, the policy is *updated* several times.
  
  The API has some resemblence with `PyTorch Lightning <https://pytorch-lightning.readthedocs.io/>`__,
  but it's essentially different because this trainer is built for RL applications, and thus
  most configurations are under RL context.
  We are still looking for ways to incorporate existing trainer libraries, because it looks like
  big efforts to build a trainer as powerful as those libraries, and also, that's not our primary goal.
  
  It's essentially different
  `tianshou's built-in trainers <https://tianshou.readthedocs.io/en/master/api/tianshou.trainer.html>`__,
  as it's far much more complicated than that.
  
  Parameters
  ----------
  max_iters
      Maximum iterations before stopping.
  val_every_n_iters
      Perform validation every n iterations (i.e., training collects).
  logger
      Logger to record the backtest results. Logger must be present because
      without logger, all information will be lost.
  finite_env_type
      Type of finite env implementation.
  concurrency
      Parallel workers.
  fast_dev_run
      Create a subset for debugging.
      How this is implemented depends on the implementation of training vessel.
      For :class:`~qlib.rl.vessel.TrainingVessel`, if greater than zero,
      a random subset sized ``fast_dev_run`` will be used
      instead of ``train_initial_states`` and ``val_initial_states``.
code: def _metrics_callback(
      self, on_episode: bool, on_collect: bool, log_buffer: LogBuffer
  ) -> None:
      if on_episode:
          # Update the global counter.
          self.current_episode = log_buffer.global_episode
          metrics = log_buffer.episode_metrics()
      elif on_collect:
          # Update the latest metrics.
          metrics = log_buffer.collect_metrics()
      if self.current_stage == "val":
          metrics = {
              "val/" + name: value for name, value in metrics.items()
          }
      self.metrics.update(metrics)
  
imports: from __future__ import annotations
  import collections
  import copy
  from contextlib import AbstractContextManager, contextmanager
  from datetime import datetime
  from pathlib import Path
  from typing import Any, Dict, Iterable, List, OrderedDict, Sequence, TypeVar, cast
  import torch
  from qlib.log import get_module_logger
  from qlib.rl.simulator import InitialStateType
  from qlib.rl.utils import EnvWrapper, FiniteEnvType, LogBuffer, LogCollector, LogLevel, LogWriter, vectorize_env
  from qlib.rl.utils.finite_env import FiniteVectorEnv
  from qlib.typehint import Literal
  from .callbacks import Callback
  from .vessel import TrainingVesselBase
label_desc: Use image node_id 12 for calling the Trainer obj's underlying member method code with example usage: obj._metrics_callback(on_episode, on_collect, log_buffer) without return types