code: def train_model(self, metric="acc"):
      best_metric = 0
      global_step = 0
      for epoch in range(self.max_epoch):
          self.train()
          logging.info("=== Epoch %d train ===" % epoch)
          avg_loss = AverageMeter()
          avg_acc = AverageMeter()
          t = tqdm(self.train_loader)
          for iter, data in enumerate(t):
              if torch.cuda.is_available():
                  for i in range(len(data)):
                      try:
                          data[i] = data[i].cuda()
                      except:
                          pass
              label = data[0]
              args = data[1:]
              logits = self.parallel_model(*args)
  
              label_vec = torch.zeros_like(logits).cuda()
              label_vec[torch.arange(label_vec.size(0)), label] = 1
              label_vec = label_vec[:, 1:]
              logits = logits[:, 1:]
  
              loss = self.criterion(
                  logits.reshape(-1), label_vec.reshape(-1)
              )
              pred = (torch.sigmoid(logits) >= 0.5).long()
              acc = float((pred == label_vec).long().sum()) / (
                  label_vec.size(0) * label_vec.size(1)
              )
  
              # Log
              avg_loss.update(loss.item(), 1)
              avg_acc.update(acc, 1)
              t.set_postfix(loss=avg_loss.avg, acc=avg_acc.avg)
              # Optimize
              loss.backward()
              self.optimizer.step()
              if self.scheduler is not None:
                  self.scheduler.step()
              self.optimizer.zero_grad()
              global_step += 1
          # Val
          logging.info("=== Epoch %d val ===" % epoch)
          result = self.eval_model(self.val_loader)
          logging.info(
              "Metric {} current / best: {} / {}".format(
                  metric, result[metric], best_metric
              )
          )
          if result[metric] > best_metric:
              logging.info("Best ckpt and saved.")
              folder_path = "/".join(self.ckpt.split("/")[:-1])
              if not os.path.exists(folder_path):
                  os.mkdir(folder_path)
              torch.save(
                  {"state_dict": self.model.state_dict()}, self.ckpt
              )
              best_metric = result[metric]
      logging.info("Best %s on val set: %f" % (metric, best_metric))
  
file_path: OpenNRE/opennre/framework/multi_label_sentence_re.py
imports: import os, logging, json
  from tqdm import tqdm
  import torch
  from torch import nn, optim
  from .data_loader import MultiLabelSentenceRELoader
  from .utils import AverageMeter
  import numpy
label_desc: Use image node_id 2 for calling the MultiLabelSentenceRE obj's underlying member method code with example usage: obj.train_model(metric) without return types