//  [python]
def train(self, data):

        best_mean_frob = 101
        latest_checkpoint = tf.train.latest_checkpoint(self.res_dir_tr)
        b_resume = latest_checkpoint is not None
        if b_resume:
            # Restore network
            print("Restoring from {}...".format(self.res_dir_tr))
            self.saver_cur.restore(self.sess,latest_checkpoint)

            # restore number of steps so far
            init_epoch = self.sess.run(self.global_step % len(data['train']['x1']))
            # restore best validation result
            if os.path.exists(self.mean_frob_file):
                with open(self.mean_frob_file, "r") as ifp:
                    dump_res = ifp.read()
                dump_res = parse("{best_mean_frob:e}\n", dump_res)
                best_mean_frob = dump_res["best_mean_frob"]
        else:

            if self.config.data_aug:
                suffix_tr = self.config.aug_dir
                self.res_dir_restore = os.path.join(self.config.res_dir, suffix_tr)
                self.res_dir_restore = os.path.join(self.res_dir_restore, "model-cur_best")

                # Restore network
                print("Data Augmentation from {}...".format(self.res_dir_restore))
                self.saver_cur.restore(self.sess, self.res_dir_restore)

            print("Starting from scratch...")
            init_epoch = 0


        # ----------------------------------------
        # The training loop
        print("Initializing...")
        self.sess.run(tf.global_variables_initializer())

        self.saver_cur.save(self.sess, self.save_file_cur, global_step=self.global_step, write_meta_graph=True)

        batch_size = self.config.train_batch_size
        max_epoch = self.config.train_epoch
        max_iter = self.config.train_step
        step = 0

        for epoch in trange(init_epoch, max_epoch, ncols=self.config.tqdm_width):

            x1_tr, x2_tr, Rs_tr, ts_tr, fs_tr = prepareBatch(data['train'], batch_size, max_iter)

            if self.config.data_aug:

                if self.config.aug_cl:
                    x1_tr, Rs_tr, ts_tr = dataTransform(x1_tr, Rs_tr, ts_tr, epoch, aug_cl = True)
                else:
                    x1_tr, Rs_tr, ts_tr = dataTransform(x1_tr, Rs_tr, ts_tr, step)

            for idx in trange(0, max_iter-1, ncols=self.config.tqdm_width):
                # ----------------------------------------
                # Batch construction

                numkps = np.array([x1_tr[idx][_i].shape[0] for _i in range(len(x1_tr[idx]))])
                cur_num_kp = numkps.min()

                # Actual construction of the batch
                x1_b = np.array([x1_tr[idx][_i][:cur_num_kp, :] for _i in range(len(x1_tr[idx]))]
                ).reshape((len(x1_tr[idx]), 1, cur_num_kp, 3))

                x2_b = np.array([x2_tr[idx][_i][:cur_num_kp, :] for _i in range(len(x1_tr[idx]))]
                ).reshape((len(x1_tr[idx]), 1, cur_num_kp, 3))

                Rs_b = np.array([Rs_tr[idx][_i] for _i in range(len(x1_tr[idx]))]).reshape(len(x1_tr[idx]), 9)
                ts_b = np.array([ts_tr[idx][_i] for _i in range(len(x1_tr[idx]))]).reshape(len(x1_tr[idx]), 3)
                fs_b = np.array([fs_tr[idx][_i][:cur_num_kp] for _i in range(len(x1_tr[idx]))]).reshape(len(x1_tr[idx]), cur_num_kp)

                # ----------------------------------------
                # Train

                # Feed Dict
                feed_dict = {
                    self.x_in_1: x1_b,
                    self.x_in_2: x2_b,
                    self.R_in: Rs_b,
                    self.t_in: ts_b,
                    self.f_in: fs_b,
                    self.is_training: True,
                }

                b_write_summary = ((step + 1) % self.config.report_intv) == 0
                b_validate = (idx - (max_iter-2)) == 0

                if b_validate:
                    fetch = {"summary":self.summary_op, "global_step":self.global_step}
                elif b_write_summary:
                    fetch = {"optim": self.optim, "rec_loss": self.rec_loss, "summary": self.summary_op,
                             "global_step": self.global_step}
                else:
                    fetch = {"optim": self.optim, "rec_loss": self.rec_loss}

                try:
                    res = self.sess.run(fetch, feed_dict=feed_dict)

                except tf.errors.InvalidArgumentError:
                    print("Backward pass had numerical errors.")
                    continue

                    # Write summary and save current model
                if b_write_summary:
                    self.summary_tr.add_summary(
                        res["summary"], global_step=res["global_step"])
                    self.saver_cur.save(self.sess, self.save_file_cur, global_step=self.global_step,
                        write_meta_graph=False)

                if b_validate:
                    valid = {'x1': x1_tr[idx+1], 'x2': x2_tr[idx+1], 'R': Rs_tr[idx+1], 't': ts_tr[idx+1], 'flag': fs_tr[idx+1]}
                    cur_global_step = res["global_step"]
                    mean_frob = test_process('valid', self.sess, valid, cur_global_step, self.summary_va,
                                             self.config,
                                             self.x_in_1, self.x_in_2, self.R_in, self.t_in, self.f_in,
                                             self.is_training,
                                             self.R_hat, self.t_hat, self.logits, self.rec_loss, self.weights,
                                             self.config.reg_flag, self.config.reg_function)

                    if mean_frob < best_mean_frob and step > self.config.loss_reconstruction_init_iter:
                        print(
                            "Saving best model with mean_frob = {}".format(
                                mean_frob))
                        best_mean_frob = mean_frob
                        # Save best validation result
                        with open(self.mean_frob_file, "w") as ofp:
                            ofp.write("{:e}\n".format(best_mean_frob))
                        # Save best model
                        self.saver_best.save(self.sess, self.save_file_best, write_meta_graph=False)

                step += 1