def METHOD_NAME(exe,
                       train_exe,
                       valid_exe,
                       train_ds,
                       valid_ds,
                       test_ds,
                       train_prog,
                       valid_prog,
                       full_batch,
                       model,
                       metric,
                       epoch=20,
                       dev_count=1,
                       train_log_step=5,
                       eval_step=10000,
                       evaluator=None,
                       output_path=None):
    """train and evaluate"""
    global_step = 0
    log_path = os.path.join(output_path, "log")
    _create_if_not_exist(log_path)
    writer = SummaryWriter(log_path)
    best_model = 0
    if full_batch:
        train_iter = _full_batch_wapper(train_ds)
    else:
        train_iter = train_ds.generator
    for e in range(epoch):
        ret_sum_loss = 0
        per_step = 0
        scores = []
        labels = []
        for feed_dict in tqdm.tqdm(
                multi_device(train_iter(), dev_count), desc='Epoch %s' % e):
            if dev_count > 1:
                ret = train_exe.run(feed=feed_dict, fetch_list=metric.vars)
                ret = [[np.mean(v)] for v in ret]
            else:
                ret = train_exe.run(
                    train_prog,
                    feed=feed_dict,
                    fetch_list=[model.loss, model.logits, model.labels]
                    #fetch_list=metric.vars
                )
            scores.append(ret[1])
            labels.append(ret[2])
            ret = [ret[0]]
            ret = metric.parse(ret)
            if global_step % train_log_step == 0:
                for key, value in ret.items():
                    writer.add_scalar(
                        'train_' + key, value, global_step=global_step)
            ret_sum_loss += ret['loss']
            per_step += 1
            global_step += 1
            if global_step % eval_step == 0:
                eval_ret = evaluate(model, exe, valid_ds, valid_prog, 1,
                                    evaluator, "valid", full_batch)
                test_eval_ret = evaluate(model, exe, test_ds, valid_prog, 1,
                                         evaluator, "test", full_batch)
                eval_ret.update(test_eval_ret)
                sys.stderr.write(json.dumps(eval_ret, indent=4) + "\n")
                for key, value in eval_ret.items():
                    writer.add_scalar(key, value, global_step=global_step)
                if eval_ret["valid_acc"] > best_model:
                    F.io.save_persistables(
                        exe,
                        os.path.join(output_path, "checkpoint"), train_prog)
                    eval_ret["epoch"] = e
                    #eval_ret["step"] = global_step
                    with open(os.path.join(output_path, "best.txt"), "w") as f:
                        f.write(json.dumps(eval_ret, indent=2) + '\n')
                    best_model = eval_ret["valid_acc"]
        scores = np.vstack(scores)
        labels = np.vstack(labels)
        ret = evaluator.eval(scores, labels, "train")
        sys.stderr.write(json.dumps(ret, indent=4) + "\n")
        #print(json.dumps(ret, indent=4) + "\n")
        # Epoch End
        sys.stderr.write("epoch:{}, average loss {}\n".format(e, ret_sum_loss /
                                                              per_step))
        eval_ret = evaluate(model, exe, valid_ds, valid_prog, 1, evaluator,
                            "valid", full_batch)
        test_eval_ret = evaluate(model, exe, test_ds, valid_prog, 1, evaluator,
                                 "test", full_batch)
        eval_ret.update(test_eval_ret)
        sys.stderr.write(json.dumps(eval_ret, indent=4) + "\n")
        for key, value in eval_ret.items():
            writer.add_scalar(key, value, global_step=global_step)
        if eval_ret["valid_acc"] > best_model:
            F.io.save_persistables(exe,
                                   os.path.join(output_path, "checkpoint"),
                                   train_prog)
            #eval_ret["step"] = global_step
            eval_ret["epoch"] = e
            with open(os.path.join(output_path, "best.txt"), "w") as f:
                f.write(json.dumps(eval_ret, indent=2) + '\n')
            best_model = eval_ret["valid_acc"]
    writer.close()