def METHOD_NAME(args, initial_global_step, model, optimizer, scheduler, vocoder, loader_train, loader_test):
    # saver
    saver = Saver(args, initial_global_step=initial_global_step)
    # model size
    params_count = utils.get_network_paras_amount({'model': model})
    saver.log_info('--- model size ---')
    saver.log_info(params_count)
    # run
    num_batches = len(loader_train)
    model.METHOD_NAME()
    saver.log_info('======= start training =======')
    scaler = GradScaler()
    if args.METHOD_NAME.amp_dtype == 'fp32':
        dtype = torch.float32
    elif args.METHOD_NAME.amp_dtype == 'fp16':
        dtype = torch.float16
    elif args.METHOD_NAME.amp_dtype == 'bf16':
        dtype = torch.bfloat16
    else:
        raise ValueError(' [x] Unknown amp_dtype: ' + args.METHOD_NAME.amp_dtype)
    for epoch in range(args.METHOD_NAME.epochs):
        for batch_idx, data in enumerate(loader_train):
            saver.global_step_increment()
            optimizer.zero_grad()
            # unpack data
            for k in data.keys():
                if not k.startswith('name'):
                    data[k] = data[k].to(args.device)
            # forward
            if dtype == torch.float32:
                loss = model(data['units'].float(), data['f0'], data['volume'], data['spk_id'], 
                                aug_shift = data['aug_shift'], gt_spec=data['mel'].float(), infer=False)
            else:
                with autocast(device_type=args.device, dtype=dtype):
                    loss = model(data['units'], data['f0'], data['volume'], data['spk_id'], 
                                    aug_shift = data['aug_shift'], gt_spec=data['mel'], infer=False)
            # handle nan loss
            if torch.isnan(loss):
                raise ValueError(' [x] nan loss ')
            else:
                # backpropagate
                if dtype == torch.float32:
                    loss.backward()
                    optimizer.step()
                else:
                    scaler.scale(loss).backward()
                    scaler.step(optimizer)
                    scaler.update()
                scheduler.step()
            # log loss
            if saver.global_step % args.METHOD_NAME.interval_log == 0:
                current_lr =  optimizer.param_groups[0]['lr']
                saver.log_info(
                    'epoch: {} | {:3d}/{:3d} | {} | batch/s: {:.2f} | lr: {:.6} | loss: {:.3f} | time: {} | step: {}'.format(
                        epoch,
                        batch_idx,
                        num_batches,
                        args.env.expdir,
                        args.METHOD_NAME.interval_log/saver.get_interval_time(),
                        current_lr,
                        loss.item(),
                        saver.get_total_time(),
                        saver.global_step
                    )
                )
                saver.log_value({
                    'train/loss': loss.item()
                })
                saver.log_value({
                    'train/lr': current_lr
                })
            # validation
            if saver.global_step % args.METHOD_NAME.interval_val == 0:
                optimizer_save = optimizer if args.METHOD_NAME.save_opt else None
                # save latest
                saver.save_model(model, optimizer_save, postfix=f'{saver.global_step}')
                last_val_step = saver.global_step - args.METHOD_NAME.interval_val
                if last_val_step % args.METHOD_NAME.interval_force_save != 0:
                    saver.delete_model(postfix=f'{last_val_step}')
                # run testing set
                test_loss = test(args, model, vocoder, loader_test, saver)
                # log loss
                saver.log_info(
                    ' --- <validation> --- \nloss: {:.3f}. '.format(
                        test_loss,
                    )
                )
                saver.log_value({
                    'validation/loss': test_loss
                })
                model.METHOD_NAME()