def METHOD_NAME(self, get_loss, model_file=None, pretrain_file=None, data_parallel=True):
    """ Train Loop """
    self.model.METHOD_NAME() # train mode
    self.load(model_file, pretrain_file)
    model = self.model.to(self.device)
    if data_parallel: # use Data Parallelism with Multi-GPU
        model = nn.DataParallel(model)
    global_step = 0 # global iteration steps regardless of epochs
    for e in range(self.cfg.n_epochs):
        loss_sum = 0. # the sum of iteration losses to get average loss in every epoch
        iter_bar = tqdm(self.data_iter, desc='Iter (loss=X.XXX)')
        for i, batch in enumerate(iter_bar):
            batch = [t.to(self.device) for t in batch]
            self.optimizer.zero_grad()
            loss = get_loss(model, batch, global_step).mean() # mean() for Data Parallelism
            loss.backward()
            self.optimizer.step()
            global_step += 1
            loss_sum += loss.item()
            iter_bar.set_description('Iter (loss=%5.3f)'%loss.item())
            if global_step % self.cfg.save_steps == 0: # save
                self.save(global_step)
            if self.cfg.total_steps and self.cfg.total_steps < global_step:
                print(f"Epoch {e+1}/{self.cfg.n_epochs} : Average Loss {loss_sum/(i+1)}")
                print('The Total Steps have been reached.')
                self.save(final=True) # save and finish when global_steps reach total_steps
                return
        print(f"Epoch {e+1}/{self.cfg.n_epochs} : Average Loss {loss_sum/(i+1)}")
    self.save(final=True)