def TrainModel(model, session, mnist, cfg):
    data_tr = mnist.train
    data_val = mnist.validation
    loss_history = []
    logs = []
    acc_val_best_so_far = 0
    current_step = session.run(model.global_step)
    lg = ConfigUtils.LogGenerator()
    for iteration in range(current_step, cfg.max_batch+1):
        batch = data_tr.next_batch(cfg.batch_size)
        learn_rate = cfg.lr * cfg.lr_mapper.GetFactor(iteration)
        feed_dict = {model.pl_images:_SubtractByMean(batch[0]), model.pl_labels:batch[1], model.pl_dropout_rate:0.5, model.pl_phase:1, model.pl_lr:learn_rate}
        loss, _ = session.run([model.loss, model.op_train], feed_dict=feed_dict)
        loss_history.append(loss)
        
        if cfg.is_save and iteration % cfg.save_every==0:
            model.saver.save(session, cfg.save_dir, iteration)
        if iteration % cfg.print_every != 0:
            continue
        feed_dict[model.pl_dropout_rate] = 0
        feed_dict[model.pl_phase] = 0
        acc_tr, loss_softmax_tr, loss_re_tr = session.run([model.accuracy, model.loss_softmax, model.loss_reg], feed_dict=feed_dict)
        acc_val, loss_softmax_val, loss_re_val = EvaluateModel(model, session, data_val, cfg)
        
        acc_val_best_so_far = acc_val if acc_val > acc_val_best_so_far else acc_val_best_so_far
        log = lg.GetContent()
        log.iteration = iteration
        log.acc_tr = acc_tr
        log.loss_softmax_tr = loss_softmax_tr
        log.loss_re_tr = loss_re_tr
        log.loss_tr = loss_softmax_tr + loss_re_tr
        log.acc_val = acc_val
        log.loss_softmax_val = loss_softmax_val
        log.loss_re_val = loss_re_val
        log.loss_val = loss_softmax_val + loss_re_val
        logs.append(log)
        if cfg.verbose:
            print('iteration: {0}\t acc_tr: {1:4.3f}\t acc_te: {2:4.3f}\t loss_tr: {3:4.4f}\t loss_val: {4:4.4f}\t lr: {5:4.2f}'.format(iteration, acc_tr, acc_val, log.loss_tr, log.loss_val, np.log(learn_rate)))
            
    acc_val, loss_softmax_val, loss_re_val = EvaluateModel(model, session, data_val, cfg) 
    rg = ConfigUtils.ReportGenerator()
    report = rg.GetContent()
    report.acc = acc_val
    report.best_acc = acc_val_best_so_far
    report.loss_softmax =loss_softmax_val
    report.loss_re = loss_re_val
    report.loss = loss_softmax_val + loss_re_val
    report.traing_loss_hist = loss_history
    report.distribution = model.cfg.distribution
    report.reg = model.cfg.reg
    report.lr = cfg.lr
    return report, logs