code: def fit(
      self,
      epochs=None,
      lr=None,
      validate=True,
      return_results=False,
      schedule_type="warmup_cosine",
      optimizer_type="lamb",
  ):
      results_val = []
      tensorboard_dir = self.output_dir / "tensorboard"
      tensorboard_dir.mkdir(exist_ok=True)
  
      if epochs is None:
          epochs = self.epochs
  
      if lr is None:
          lr = self.learning_rate
      # Train the model
      tb_writer = SummaryWriter(tensorboard_dir)
  
      train_dataloader = self.data.train_dl
      if self.max_steps > 0:
          t_total = self.max_steps
          self.epochs = (
              self.max_steps
              // len(train_dataloader)
              // self.grad_accumulation_steps
              + 1
          )
      else:
          t_total = (
              len(train_dataloader)
              // self.grad_accumulation_steps
              * epochs
          )
  
      # Prepare optimiser
      if (
          self.optimizer_type != optimizer_type
          or self.learning_rate != lr
          or self.epochs != epochs
      ):
          self.optimizer = self.get_optimizer(
              lr, optimizer_type=optimizer_type
          )
          self.lr_scheduler = self.get_scheduler(
              self.optimizer,
              t_total=t_total,
              schedule_type=schedule_type,
          )
          self.callback_handler.optimizer = self.optimizer
          self.callback_handler.lr_scheduler = self.lr_scheduler
  
      # get the base model if its already wrapped around DataParallel
      if hasattr(self.model, "module"):
          self.model = self.model.module
  
      # Parallelize the model architecture
      if self.multi_gpu is True:
          self.model = torch.nn.DataParallel(self.model)
          self.callback_handler.model = self.model
  
      # Start Training
      self.logger.info("***** Running training *****")
      self.logger.info(
          "  Num examples = %d", len(train_dataloader.dataset)
      )
      self.logger.info("  Num Epochs = %d", epochs)
      self.logger.info(
          "  Total train batch size (w. parallel, distributed & accumulation) = %d",
          self.data.train_batch_size * self.grad_accumulation_steps,
      )
      self.logger.info(
          "  Gradient Accumulation steps = %d",
          self.grad_accumulation_steps,
      )
      self.logger.info("  Total optimization steps = %d", t_total)
  
      # Update the references
      self.callback_handler.model = self.model
      self.callback_handler.optimizer = self.optimizer
      self.callback_handler.lr_scheduler = self.lr_scheduler
      self.callback_handler.train_dataloader = train_dataloader
      self.state.max_steps = self.max_steps
      self.state.num_train_epochs = epochs
  
      global_step = 0
      epoch_step = 0
      self.state.epoch = 0
      tr_loss, logging_loss, epoch_loss = 0.0, 0.0, 0.0
      self.model.zero_grad()
  
      self.control = self.callback_handler.on_train_begin(
          self.training_arguments, self.state, self.control
      )
      pbar = master_bar(range(epochs))
  
      for epoch in pbar:
          epoch_step = 0
          epoch_loss = 0.0
  
          # epoch begin callback
          self.control = self.callback_handler.on_epoch_begin(
              self.training_arguments, self.state, self.control
          )
  
          for step, batch in enumerate(
              progress_bar(train_dataloader, parent=pbar)
          ):
              if step % self.grad_accumulation_steps == 0:
                  self.control = self.callback_handler.on_step_begin(
                      self.training_arguments, self.state, self.control
                  )
  
              # Run training step and get loss
              loss = self.training_step(batch)
  
              tr_loss += loss.item()
              epoch_loss += loss.item()
              if (step + 1) % self.grad_accumulation_steps == 0:
                  # gradient clipping
                  torch.nn.utils.clip_grad_norm_(
                      self.model.parameters(), self.max_grad_norm
                  )
                  if self.is_fp16:
                      # AMP: gradients need unscaling
                      self.scaler.unscale_(self.optimizer)
  
                  if self.is_fp16:
                      self.scaler.step(self.optimizer)
                      self.scaler.update()
                  else:
                      self.optimizer.step()
                  self.lr_scheduler.step()
  
                  self.model.zero_grad()
                  global_step += 1
                  epoch_step += 1
                  self.state.global_step = global_step
                  self.state.epoch = epoch + (step + 1) / len(
                      train_dataloader
                  )
  
                  self.state.learning_rate = self.lr_scheduler.get_lr()[
                      0
                  ]
                  self.control = self.callback_handler.on_step_end(
                      self.training_arguments, self.state, self.control
                  )
  
                  if (
                      self.logging_steps > 0
                      and global_step % self.logging_steps == 0
                  ):
                      self.state.loss = (
                          tr_loss - logging_loss
                      ) / self.logging_steps
                      if validate:
                          # evaluate model
                          results = self.validate()
                          for key, value in results.items():
                              tb_writer.add_scalar(
                                  "eval_{}".format(key),
                                  value,
                                  global_step,
                              )
                              self.logger.info(
                                  "eval_{} after step {}: {}: ".format(
                                      key, global_step, value
                                  )
                              )
  
                      # Log metrics
                      self.logger.info(
                          "lr after step {}: {}".format(
                              global_step, self.lr_scheduler.get_lr()[0]
                          )
                      )
                      self.logger.info(
                          "train_loss after step {}: {}".format(
                              global_step,
                              (tr_loss - logging_loss)
                              / self.logging_steps,
                          )
                      )
                      tb_writer.add_scalar(
                          "lr",
                          self.lr_scheduler.get_lr()[0],
                          global_step,
                      )
                      tb_writer.add_scalar(
                          "loss",
                          (tr_loss - logging_loss) / self.logging_steps,
                          global_step,
                      )
  
                      logging_loss = tr_loss
  
          # Evaluate the model against validation set after every epoch
          self.state.learning_rate = self.lr_scheduler.get_lr()[0]
          self.state.loss = epoch_loss / epoch_step
          if validate:
              results = self.validate()
              for key, value in results.items():
                  self.logger.info(
                      "eval_{} after epoch {}: {}: ".format(
                          key, (epoch + 1), value
                      )
                  )
              results_val.append(results)
  
          self.state.epoch = epoch + 1
          self.control = self.callback_handler.on_epoch_end(
              self.training_arguments, self.state, self.control
          )
          # Log metrics
          self.logger.info(
              "lr after epoch {}: {}".format(
                  (epoch + 1), self.lr_scheduler.get_lr()[0]
              )
          )
          self.logger.info(
              "train_loss after epoch {}: {}".format(
                  (epoch + 1), epoch_loss / epoch_step
              )
          )
          self.logger.info("\n")
  
      tb_writer.close()
      self.control = self.callback_handler.on_train_end(
          self.training_arguments, self.state, self.control
      )
  
      if return_results:
          return global_step, tr_loss / global_step, results_val
      else:
          return global_step, tr_loss / global_step
  
imports: import os
  import copy
  import logging
  from packaging import version
  from .data_cls import BertDataBunch
  from tqdm.autonotebook import tqdm
  import matplotlib.pyplot
  from .learner_util import Learner
  from torch import nn
  from typing import List, Optional
  from .modeling import BertForMultiLabelSequenceClassification, XLNetForMultiLabelSequenceClassification, RobertaForMultiLabelSequenceClassification, DistilBertForMultiLabelSequenceClassification, CamembertForMultiLabelSequenceClassification, AlbertForMultiLabelSequenceClassification, ElectraForMultiLabelSequenceClassification, FlaubertForMultiLabelSequenceClassification
  from fastprogress.fastprogress import master_bar, progress_bar
  import torch
  import pandas
  import numpy
  from sklearn.metrics import roc_curve, auc
  from pathlib import Path
  from torch.optim.lr_scheduler import _LRScheduler, Optimizer
  from tensorboardX import SummaryWriter
  from transformers import WEIGHTS_NAME, BertConfig, BertForSequenceClassification, BertTokenizer, XLMConfig, XLMForSequenceClassification, XLMTokenizer, XLNetConfig, XLNetForSequenceClassification, XLNetTokenizer, RobertaConfig, RobertaForSequenceClassification, RobertaTokenizer, CamembertConfig, CamembertForSequenceClassification, CamembertTokenizer, AlbertConfig, AlbertForSequenceClassification, AlbertTokenizer, DistilBertConfig, DistilBertForSequenceClassification, DistilBertTokenizer, ElectraConfig, ElectraForSequenceClassification, ElectraTokenizer, FlaubertConfig, FlaubertForSequenceClassification, FlaubertTokenizer
  from transformers import AutoModelForSequenceClassification, AutoConfig, TrainingArguments
  from transformers.trainer_callback import TrainerCallback, TrainerControl, TrainerState, CallbackHandler, DefaultFlowCallback
label_desc: Use image node_id 3 for calling the BertLearner obj's underlying member method code with example usage: obj.fit(epochs, lr, validate, return_results, schedule_type, optimizer_type) and returns: global_step,  unknown,  results_val, global_step,  unknown