//  [python]
def make_train_function(self):
        """Creates a function that executes one step of training.

            This method can be overridden to support custom training logic.
            This method is called by `Model.fit` and `Model.train_on_batch`.

            Typically, this method directly controls `tf.function` and
            `tf.distribute.Strategy` settings, and delegates the actual training
            logic to `Model.train_step`.

            This function is cached the first time `Model.fit` or
            `Model.train_on_batch` is called. The cache is cleared whenever
            `Model.compile` is called.

            Returns:
              Function. The function created by this method should accept a
              `tf.data.Iterator`, and return a `dict` containing values that will
              be passed to `tf.keras.Callbacks.on_train_batch_end`, such as
              `{'loss': 0.2, 'accuracy': 0.7}`.
            """
        if self.train_function is not None:
            return self.train_function

        def step_function(model, iterator):
            """Runs a single training step."""

            def run_step(data):
                outputs = model.train_step(data)
                # Ensure counter is updated only if `train_step` succeeds.
                with ops.control_dependencies(_minimum_control_deps(outputs)):
                    model._train_counter.assign_add(1)  # pylint: disable=protected-access
                return outputs

            err_cnt = 0
            while err_cnt < 10:
                try:
                    data = next(iterator)
                    break
                except (StopIteration, tf.errors.OutOfRangeError) as e:
                    raise e
                except tf.errors.OpError as e:
                    tf.logging.exception(e)
                    err_cnt += 1
                    if err_cnt >= 10:
                        raise e

            outputs = model.distribute_strategy.run(run_step, args=(data,))
            outputs = training.reduce_per_replica(outputs, self.distribute_strategy,
                                                  reduction='first')
            training.write_scalar_summaries(outputs,
                                            step=model._train_counter)  # pylint: disable=protected-access
            return outputs

        def train_function(iterator):
            outputs = step_function(self, iterator)
            return outputs

        def accum(model, iterator):
            """Runs a single training step."""

            def run_step(data):
                model.train_step(data, accum_only=True)

            err_cnt = 0
            while err_cnt < 10:
                try:
                    data = next(iterator)
                    break
                except (StopIteration, tf.errors.OutOfRangeError) as e:
                    raise e
                except tf.errors.OpError as e:
                    tf.logging.exception(e)
                    err_cnt += 1
                    if err_cnt >= 10:
                        raise e

            model.distribute_strategy.run(run_step, args=(data,))

        def accum_function(iterator):
            accum(self, iterator)

        if not self.run_eagerly:
            train_function = tf.function(
                train_function, experimental_relax_shapes=True)
            if self._update_cycle > 1:
                accum_function = tf.function(accum_function, experimental_relax_shapes=True)

        self.train_function = train_function
        if self._update_cycle > 1:
            self.accumulate_function = accum_function
        return self.train_function