class_docstr: Multi step soft actor critic.
  
  :param algorithm_config: Algorithm options.
  :param learner_model: Structured torch actor critic to train.
  :param distributed_actors: Distributed actors for collection of training rollouts.
  :param model_selection: Optional model selection class, receives model evaluation results.
  :param evaluator: The evaluator to use.
class_docstr_tok: ["Multi","step","soft","actor","critic",".",":","param","algorithm_config",":","Algorithm","options",".",":","param","learner_model",":","Structured","torch","actor","critic","to","train",".",":","param","distributed_actors",":","Distributed","actors","for","collection","of","training","rollouts",".",":","param","model_selection",":","Optional","model","selection","class",",","receives","model","evaluation","results",".",":","param","evaluator",":","The","evaluator","to","use","."]
docstr: Train function that wraps normal train function in order to close all processes properly
  
  :param n_epochs: number of epochs to train.
docstr_tok: ["Train","function","that","wraps","normal","train","function","in","order","to","close","all","processes","properly",":","param","n_epochs",":","number","of","epochs","to","train","."]
code: def train(self, n_epochs: Optional[int] = None) -> None:
      """Train function that wraps normal train function in order to close all processes properly
  
      :param n_epochs: number of epochs to train.
      """
  
      n_epochs = (
          self.algorithm_config.n_epochs
          if n_epochs is None
          else n_epochs
      )
  
      # init minimum best model selection for early stopping
      if self.model_selection is None:
          self.model_selection = BestModelSelection(
              dump_file=None, model=None
          )
  
      try:
          self.distributed_workers.broadcast_updated_policy(
              self.learner_model.policy.state_dict()
          )
          self.distributed_workers.start()
          self._train_async(n_epochs=n_epochs)
          self.distributed_workers.stop()
      except Exception as e:
          print("caught exception")
          self.distributed_workers.stop()
          raise e
  
imports: import sys
  import time
  from typing import Union, Optional, BinaryIO, Dict, Tuple, List
  import numpy
  import torch
  import torch.nn
  from gym import spaces
  from maze.core.agent.torch_actor_critic import TorchActorCritic
  from maze.core.annotations import override
  from maze.core.env.base_env_events import BaseEnvEvents
  from maze.core.env.structured_env import ActorID
  from maze.core.log_stats.log_stats import increment_log_step, LogStatsLevel
  from maze.core.trajectory_recording.records.structured_spaces_record import StructuredSpacesRecord
  from maze.train.trainers.common.evaluators.rollout_evaluator import RolloutEvaluator
  from maze.train.trainers.common.model_selection.best_model_selection import BestModelSelection
  from maze.train.trainers.common.trainer import Trainer
  from maze.train.utils.train_utils import compute_gradient_norm
  from maze.utils.bcolors import BColors
  from maze.train.parallelization.distributed_actors.base_distributed_workers_with_buffer import BaseDistributedWorkersWithBuffer
  from maze.train.trainers.sac.sac_algorithm_config import SACAlgorithmConfig
  from maze.train.trainers.sac.sac_events import SACEvents
  from torch.distributions.utils import logits_to_probs
label_desc: Use image node_id 3 for calling the SAC obj's underlying member method code with example usage: obj.train(n_epochs) without return types