class_docstr: Implementation of Knowledge distillation from the paper "Distilling Task-Specific
  Knowledge from BERT into Simple Neural Networks" https://arxiv.org/pdf/1903.12136.pdf
  
  :param student_model (torch.nn.Module): Student model
  :param distill_train_loader (torch.utils.data.DataLoader): Student Training Dataloader for distillation
  :param distill_val_loader (torch.utils.data.DataLoader): Student Testing/validation Dataloader
  :param train_df (pandas.DataFrame): Dataframe for training the teacher model
  :param val_df (pandas.DataFrame): Dataframe for validating the teacher model
  :param loss_fn (torch.nn.module): Loss function
  :param temp (float): Temperature parameter for distillation
  :param distil_weight (float): Weight paramter for distillation loss
  :param device (str): Device used for training; 'cpu' for cpu and 'cuda' for gpu
  :param log (bool): True if logging required
  :param logdir (str): Directory for storing logs
class_docstr_tok: ["Implementation","of","Knowledge","distillation","from","the","paper","``","Distilling","Task-Specific","Knowledge","from","BERT","into","Simple","Neural","Networks","''","https",":","\/\/arxiv.org\/pdf\/1903.12136.pdf",":","param","student_model","(","torch.nn.Module",")",":","Student","model",":","param","distill_train_loader","(","torch.utils.data.DataLoader",")",":","Student","Training","Dataloader","for","distillation",":","param","distill_val_loader","(","torch.utils.data.DataLoader",")",":","Student","Testing\/validation","Dataloader",":","param","train_df","(","pandas.DataFrame",")",":","Dataframe","for","training","the","teacher","model",":","param","val_df","(","pandas.DataFrame",")",":","Dataframe","for","validating","the","teacher","model",":","param","loss_fn","(","torch.nn.module",")",":","Loss","function",":","param","temp","(","float",")",":","Temperature","parameter","for","distillation",":","param","distil_weight","(","float",")",":","Weight","paramter","for","distillation","loss",":","param","device","(","str",")",":","Device","used","for","training",";","'cpu","'","for","cpu","and","'cuda","'","for","gpu",":","param","log","(","bool",")",":","True","if","logging","required",":","param","logdir","(","str",")",":","Directory","for","storing","logs"]
docstr: Function that will be training the teacher
  
  :param epochs (int): Number of epochs you want to train the teacher
  :param plot_losses (bool): True if you want to plot the losses
  :param save_model (bool): True if you want to save the teacher model
  :param save_model_pth (str): Path where you want to store the teacher model
  :param train_batch_size (int): Batch size paramter for generating dataloaders
  :param batch_print_freq (int): Frequency at which batch number needs to be printed per epoch
docstr_tok: ["Function","that","will","be","training","the","teacher",":","param","epochs","(","int",")",":","Number","of","epochs","you","want","to","train","the","teacher",":","param","plot_losses","(","bool",")",":","True","if","you","want","to","plot","the","losses",":","param","save_model","(","bool",")",":","True","if","you","want","to","save","the","teacher","model",":","param","save_model_pth","(","str",")",":","Path","where","you","want","to","store","the","teacher","model",":","param","train_batch_size","(","int",")",":","Batch","size","paramter","for","generating","dataloaders",":","param","batch_print_freq","(","int",")",":","Frequency","at","which","batch","number","needs","to","be","printed","per","epoch"]
code: def train_teacher(
      self,
      epochs=1,
      plot_losses=True,
      save_model=True,
      save_model_pth="./models/teacher.pt",
      train_batch_size=16,
      batch_print_freq=40,
      val_batch_size=16,
  ):
      """
      Function that will be training the teacher
  
      :param epochs (int): Number of epochs you want to train the teacher
      :param plot_losses (bool): True if you want to plot the losses
      :param save_model (bool): True if you want to save the teacher model
      :param save_model_pth (str): Path where you want to store the teacher model
      :param train_batch_size (int): Batch size paramter for generating dataloaders
      :param batch_print_freq (int): Frequency at which batch number needs to be printed per epoch
      """
      self.teacher_train_loader = self._get_teacher_dataloaders(
          train_batch_size, mode="train"
      )
  
      self.teacher_model.to(self.device)
      self.teacher_model.train()
  
      # training_stats = []
      loss_arr = []
  
      length_of_dataset = len(self.teacher_train_loader.dataset)
      best_acc = 0.0
      self.best_teacher_model_weights = deepcopy(
          self.teacher_model.state_dict()
      )
  
      print("Training Teacher... ")
  
      for ep in range(0, epochs):
          print("")
          print(
              "======== Epoch {:} / {:} ========".format(ep + 1, epochs)
          )
  
          epoch_loss = 0.0
          correct = 0
  
          for step, batch in enumerate(self.teacher_train_loader):
              if step % (batch_print_freq) == 0 and not step == 0:
                  print(
                      "  Batch {:>5,}  of  {:>5,}.".format(
                          step, len(self.teacher_train_loader)
                      )
                  )
  
              b_input_ids = batch[0].to(self.device)
              b_input_mask = batch[1].to(self.device)
              b_labels = batch[2].to(self.device)
  
              self.optimizer_teacher.zero_grad()
  
              loss, logits = self.teacher_model(
                  b_input_ids,
                  token_type_ids=None,
                  attention_mask=b_input_mask,
                  labels=b_labels,
              )
  
              epoch_loss += loss.item()
  
              logits = logits.detach().cpu().numpy()
              label_ids = b_labels.to("cpu").numpy()
              preds = np.argmax(logits, axis=1).flatten()
              labels = label_ids.flatten()
              correct += np.sum(preds == labels)
  
              loss.backward()
  
              # For preventing exploding gradients
              torch.nn.utils.clip_grad_norm_(
                  self.teacher_model.parameters(), 1.0
              )
  
              self.optimizer_teacher.step()
  
          epoch_acc = correct / length_of_dataset
          print(f"Loss: {epoch_loss} | Accuracy: {epoch_acc}")
  
          _, epoch_val_acc = self.evaluate_teacher(val_batch_size)
  
          if epoch_val_acc > best_acc:
              best_acc = epoch_val_acc
              self.best_teacher_model_weights = deepcopy(
                  self.teacher_model.state_dict()
              )
  
          if self.log:
              self.writer.add_scalar(
                  "Training loss/Teacher", epoch_loss, epochs
              )
              self.writer.add_scalar(
                  "Training accuracy/Teacher", epoch_acc, epochs
              )
              self.writer.add_scalar(
                  "Validation accuracy/Teacher", epoch_val_acc, epochs
              )
  
          loss_arr.append(epoch_loss)
  
      self.teacher_model.load_state_dict(
          self.best_teacher_model_weights
      )
  
      if save_model:
          torch.save(self.teacher_model.state_dict(), save_model_pth)
  
      if plot_losses:
          plt.plot(loss_arr)
  
file_path: KD_Lib/KD_Lib/KD/text/BERT2LSTM/bert2lstm.py
imports: import random
  from copy import deepcopy
  import matplotlib.pyplot
  import numpy
  import torch
  import torch.nn
  import torch.nn.functional
  from transformers import AdamW, BertForSequenceClassification, BertTokenizer
  from KD_Lib.KD.common import BaseClass
  from KD_Lib.KD.text.utils import get_bert_dataloader
label_desc: Use image node_id 5 for calling the BERT2LSTM obj's underlying member method code with example usage: obj.train_teacher(epochs, plot_losses, save_model, save_model_pth, train_batch_size, batch_print_freq, val_batch_size) without return types