class_docstr: Trainer for the AlphaTensor model. The trainer does not require an
  explicit loss since the loss is computed by the model itself. The trainer
  is responsible for both the training step and the acting one, storing
  acting performance in a buffer.
class_docstr_tok: ["Trainer","for","the","AlphaTensor","model",".","The","trainer","does","not","require","an","explicit","loss","since","the","loss","is","computed","by","the","model","itself",".","The","trainer","is","responsible","for","both","the","training","step","and","the","acting","one",",","storing","acting","performance","in","a","buffer","."]
docstr: Trains the model for a given number of epochs.
  
  Args:
      n_epochs (int): Number of training epochs.
      n_games (int): Number of games to generate / actors to be run in
      parallel at each step.
      mc_n_sim (int): Number of simulations used in the Monte Carlo tree
      search at each step.
      N_bar (int): N_bar parameter used to compute tau when improving
      the policy.
      initial_lr (float): Initial learning rate.
      lr_decay_factor (float): Learning rate's decay factor.
      lr_decay_steps (int): Number of learning rate's decay steps.
      starting_epoch (int, optional): Epoch from which to start / resume
      training.
docstr_tok: ["Trains","the","model","for","a","given","number","of","epochs",".","Args",":","n_epochs","(","int",")",":","Number","of","training","epochs",".","n_games","(","int",")",":","Number","of","games","to","generate","\/","actors","to","be","run","in","parallel","at","each","step",".","mc_n_sim","(","int",")",":","Number","of","simulations","used","in","the","Monte","Carlo","tree","search","at","each","step",".","N_bar","(","int",")",":","N_bar","parameter","used","to","compute","tau","when","improving","the","policy",".","initial_lr","(","float",")",":","Initial","learning","rate",".","lr_decay_factor","(","float",")",":","Learning","rate","'s","decay","factor",".","lr_decay_steps","(","int",")",":","Number","of","learning","rate","'s","decay","steps",".","starting_epoch","(","int",",","optional",")",":","Epoch","from","which","to","start","\/","resume","training","."]
code: def train(
      self,
      n_epochs: int,
      n_games: int,
      mc_n_sim: int,
      N_bar: int,
      initial_lr: float,
      lr_decay_factor: float,
      lr_decay_steps: int,
      starting_epoch: int = 0,
  ):
      """Trains the model for a given number of epochs.
  
      Args:
          n_epochs (int): Number of training epochs.
          n_games (int): Number of games to generate / actors to be run in
          parallel at each step.
          mc_n_sim (int): Number of simulations used in the Monte Carlo tree
          search at each step.
          N_bar (int): N_bar parameter used to compute tau when improving
          the policy.
          initial_lr (float): Initial learning rate.
          lr_decay_factor (float): Learning rate's decay factor.
          lr_decay_steps (int): Number of learning rate's decay steps.
          starting_epoch (int, optional): Epoch from which to start / resume
          training.
      """
      self.model = self.model.to(self.device)
      if starting_epoch + 1 > n_epochs // 50:
          self.dataset.change_training_split(0.7, 0.05)
      if (
          starting_epoch + 1 > n_epochs // 10
      ):  # when restarting from a checkpoint
          mc_n_sim = mc_n_sim * 4
      for epoch in range(starting_epoch, n_epochs):
          if epoch + 1 == n_epochs // 50:
              self.dataset.change_training_split(0.7, 0.05)
          if epoch + 1 == n_epochs // 10:
              mc_n_sim = mc_n_sim * 4
          # apply learning rate decay each epoch if epoch < lr_decay_steps
          if 0 < epoch < lr_decay_steps - 1:
              lr = initial_lr * lr_decay_factor ** (
                  epoch / lr_decay_steps
              )
              for param_group in self.optimizer.param_groups:
                  param_group["lr"] = lr
  
          print(f"Epoch {epoch} / {n_epochs}")
          self.train_step()
          if epoch % 10 == 0:
              self.act_step(
                  self.dataset.input_tensor, n_games, mc_n_sim, N_bar
              )
          # save checkpoint
          if (epoch + 1) % 100 == 0:
              checkpoint_name = f"checkpoint_{epoch + 1}.pt"
              checkpoint = {
                  "model_state_dict": self.model.state_dict(),
                  "optimizer_state_dict": self.optimizer.state_dict(),
              }
              torch.save(
                  checkpoint,
                  self.checkpoint_dir / checkpoint_name,
              )
              self.dataset.save_game_data(self.checkpoint_data_dir)
          # exit strategy
          if self.dataset.games_are_good():
              break
      print("Training finished")
  
file_path: nebuly/optimization/open_alpha_tensor/open_alpha_tensor/core/training.py
imports: from pathlib import Path
  from typing import Tuple, List
  import torch.optim
  import tqdm
  from torch.utils.data import DataLoader
  from open_alpha_tensor.config import BASE_CHECKPOINT_DATA_DIR, BASE_CHECKPOINT_DIR
  from open_alpha_tensor.core.actors.stage import actor_prediction
  from open_alpha_tensor.core.data.basis_change import ChangeOfBasis
  from open_alpha_tensor.core.data.dataset import TensorGameDataset
  from open_alpha_tensor.core.data.generation import f_prob_distribution
  from open_alpha_tensor.core.data.utils import map_action_to_triplet
  from open_alpha_tensor.core.modules.alpha_tensor import AlphaTensorModel
label_desc: Use image node_id 4 for calling the Trainer obj's underlying member method code with example usage: obj.train(n_epochs, n_games, mc_n_sim, N_bar, initial_lr, lr_decay_factor, lr_decay_steps, starting_epoch) without return types