class_docstr: This is the Detection Model training class, which allows you to train object detection models
  on image datasets that are in YOLO format, using the YOLOv3.
docstr: 'trainModel()' function starts the actual model training. Once the training starts, the training instance
  creates 3 sub-folders in your dataset folder which are:
  - json,  where the JSON configuration file for using your trained model is stored
  - models, where your trained models are stored once they are generated after each improved experiments
  - cache , where temporary traing configuraton files are stored
  :return:
docstr_tok: ["'trainModel","(",")","'","function","starts","the","actual","model","training",".","Once","the","training","starts",",","the","training","instance","creates","3","sub-folders","in","your","dataset","folder","which","are",":","-","json",",","where","the","JSON","configuration","file","for","using","your","trained","model","is","stored","-","models",",","where","your","trained","models","are","stored","once","they","are","generated","after","each","improved","experiments","-","cache",",","where","temporary","traing","configuraton","files","are","stored",":","return",":"]
code: def trainModel(self) -> None:
      """
      'trainModel()' function starts the actual model training. Once the training starts, the training instance
      creates 3 sub-folders in your dataset folder which are:
      - json,  where the JSON configuration file for using your trained model is stored
      - models, where your trained models are stored once they are generated after each improved experiments
      - cache , where temporary traing configuraton files are stored
      :return:
      """
  
      self.__load_data()
      os.makedirs(self.__output_models_dir, exist_ok=True)
      os.makedirs(self.__output_json_dir, exist_ok=True)
  
      mp, mr, map50, map50_95, best_fitness = 0, 0, 0, 0, 0.0
      nbs = 64  # norminal batch size
      nb = len(self.__train_loader)  # number of batches
      nw = max(3 * nb, 1000)  # number of warmup iterations.
      last_opt_step = -1
      prev_save_name, recent_save_name = "", ""
  
      accumulate = max(
          round(nbs / self.__mini_batch_size), 1
      )  # accumulate loss before optimizing.
  
      self.__set_training_param(self.__epochs, accumulate)
  
      with open(
          os.path.join(
              self.__output_json_dir,
              f"{self.__dataset_name}_{self.__model_type}_detection_config.json",
          ),
          "w",
      ) as configWriter:
          json.dump(
              {"labels": self.__classes, "anchors": self.__anchors},
              configWriter,
          )
  
      since = time.time()
  
      self.__lr_scheduler.last_epoch = -1
  
      for epoch in range(1, self.__epochs + 1):
          self.__optimizer.zero_grad()
          mloss = torch.zeros(3, device=self.__device)
          print(f"Epoch {epoch}/{self.__epochs}", "-" * 10, sep="\n")
  
          for phase in ["train", "validation"]:
              if phase == "train":
                  self.__model.train()
                  print("Train: ")
                  for batch_i, (data, anns) in tqdm(
                      enumerate(self.__train_loader)
                  ):
                      batches_done = batch_i + nb * epoch
  
                      data = data.to(self.__device)
                      anns = anns.to(self.__device)
  
                      # warmup
                      if batches_done <= nw:
                          xi = [0, nw]  # x interp
                          accumulate = max(
                              1,
                              np.interp(
                                  batches_done,
                                  xi,
                                  [1, nbs / self.__mini_batch_size],
                              ).round(),
                          )
                          for j, x in enumerate(
                              self.__optimizer.param_groups
                          ):
                              # bias lr falls from 0.1 to lr0, all other lrs rise from 0.0 to lr0
                              x["lr"] = np.interp(
                                  batches_done,
                                  xi,
                                  [
                                      0.1 if j == 2 else 0.0,
                                      0.01 * self.__lr_lambda(epoch),
                                  ],
                              )
                              if "momentum" in x:
                                  x["momentum"] = np.interp(
                                      batches_done, xi, [0.8, 0.9]
                                  )
  
                      with amp.autocast(enabled=self.__cuda):
                          _ = self.__model(data)
                          loss_layers = self.__model.get_loss_layers()
                          loss, loss_components = compute_loss(
                              loss_layers, anns.detach(), self.__device
                          )
  
                      self.__scaler.scale(loss).backward()
                      mloss = (mloss * batch_i + loss_components) / (
                          batch_i + 1
                      )
  
                      # Optimize
                      if batches_done - last_opt_step >= accumulate:
                          self.__scaler.step(
                              self.__optimizer
                          )  # optimizer.step
                          self.__scaler.update()
                          self.__optimizer.zero_grad()
                          last_opt_step = batches_done
  
                  print(
                      f"    box loss-> {float(mloss[0]):.5f}, object loss-> {float(mloss[1]):.5f}, class loss-> {float(mloss[2]):.5f}"
                  )
  
                  self.__lr_scheduler.step()
  
              else:
                  self.__model.eval()
                  print("Validation:")
  
                  mp, mr, map50, map50_95 = validate.run(
                      self.__model,
                      self.__val_loader,
                      self.__num_classes,
                      device=self.__device,
                  )
  
                  print(
                      f"    recall: {mr:0.6f} precision: {mp:0.6f} mAP@0.5: {map50:0.6f}, mAP@0.5-0.95: {map50_95:0.6f}"
                      "\n"
                  )
  
                  if map50 > best_fitness:
                      best_fitness = map50
                      recent_save_name = (
                          self.__model_type
                          + f"_{self.__dataset_name}_mAP-{best_fitness:0.5f}_epoch-{epoch}.pt"
                      )
                      if prev_save_name:
                          os.remove(
                              os.path.join(
                                  self.__output_models_dir,
                                  prev_save_name,
                              )
                          )
                      torch.save(
                          self.__model.state_dict(),
                          os.path.join(
                              self.__output_models_dir, recent_save_name
                          ),
                      )
                      prev_save_name = recent_save_name
  
          if epoch == self.__epochs:
              torch.save(
                  self.__model.state_dict(),
                  os.path.join(
                      self.__output_models_dir,
                      self.__model_type
                      + f"_{self.__dataset_name}_last.pt",
                  ),
              )
  
      elapsed_time = time.time() - since
      print(
          f"Training completed in {elapsed_time//60:.0f}m {elapsed_time % 60:.0f}s"
      )
      torch.cuda.empty_cache()
  
imports: import os
  import time
  import math
  import json
  import warnings
  from typing import List, Union, Tuple, Dict
  from collections import defaultdict
  import numpy
  from PIL import Image
  import cv2
  import torch
  from torch.cuda import amp
  from torch.utils.data import DataLoader
  from torch.optim import SGD, lr_scheduler
  from tqdm import tqdm
  from .yolo.dataset import LoadImagesAndLabels
  from .yolo.custom_anchors import generate_anchors
  from .yolo.compute_loss import compute_loss
  from .yolo import validate
  from ...yolov3.tiny_yolov3 import YoloV3Tiny
  from ...yolov3.yolov3 import YoloV3
  from ...yolov3.utils import draw_bbox_and_label, get_predictions, prepare_image
  from ...backend_check.model_extension import extension_check
label_desc: Use image node_id 9 for calling the DetectionModelTrainer obj's underlying member method code with example usage: obj.trainModel() without return types