def METHOD_NAME(self, batch):
    """One Step
    Args:
        batch (List[Object]): utts, xs, xlens, ys, ylens
    """
    losses_dict = {}
    self.msg = "Rank: {}, ".format(dist.get_rank())
    # forward
    batch_size = batch[1].shape[0]
    loss, attention_loss, ctc_loss = self.model(*batch[1:])
    # loss div by `batch_size * accum_grad`
    loss /= self.accum_grad
    # loss backward
    if (self.forward_count + 1) != self.accum_grad:
        # Disable gradient synchronizations across DDP processes.
        # Within this context, gradients will be accumulated on module
        # variables, which will later be synchronized.
        context = self.model.no_sync
    else:
        # Used for single gpu training and DDP gradient synchronization
        # processes.
        context = nullcontext
    with context():
        loss.backward()
        layer_tools.print_grads(self.model, print_func=None)
    # loss info
    losses_dict['loss'] = float(loss) * self.accum_grad
    if attention_loss:
        losses_dict['att_loss'] = float(attention_loss)
    if ctc_loss:
        losses_dict['ctc_loss'] = float(ctc_loss)
    # report loss
    for k, v in losses_dict.items():
        report("train/" + k, v)
    # loss msg
    self.msg += "batch size: {}, ".format(batch_size)
    self.msg += "accum: {}, ".format(self.accum_grad)
    self.msg += ', '.join('{}: {:>.6f}'.format(k, v)
                          for k, v in losses_dict.items())
    # Truncate the graph
    loss.detach()
    # update parameters
    self.forward_count += 1
    if self.forward_count != self.accum_grad:
        return
    self.forward_count = 0
    self.optimizer.step()
    self.optimizer.clear_grad()
    self.scheduler.step()