def fit_generator(self, generator: "DataGenerator", nb_epochs: int = 20, verbose: bool = False, **kwargs) -> None:
        """
        Fit the classifier using the generator that yields batches as specified.

        :param generator: Batch generator providing `(x, y)` for each epoch. If the generator can be used for native
                          training in TensorFlow, it will.
        :param nb_epochs: Number of epochs to use for training.
        :param verbose: Display training progress bar.
        :param kwargs: Dictionary of framework-specific arguments. This parameter currently supports
                       "scheduler" which is an optional function that will be called at the end of every
                       epoch to adjust the learning rate.
        """
        import tensorflow as tf
        from art.data_generators import TensorFlowV2DataGenerator

        if self._train_step is None:  # pragma: no cover
            if self._loss_object is None:  # pragma: no cover
                raise TypeError(
                    "A loss function `loss_object` or training function `train_step` is required for fitting the "
                    "model, but it has not been defined."
                )
            if self._optimizer is None:  # pragma: no cover
                raise ValueError(
                    "An optimizer `optimizer` or training function `train_step` is required for fitting the "
                    "model, but it has not been defined."
                )

            @tf.function
            def train_step(model, images, labels):
                with tf.GradientTape() as tape:
                    predictions = model(images, training=True)
                    loss = self.loss_object(labels, predictions)
                gradients = tape.gradient(loss, model.trainable_variables)
                self.optimizer.apply_gradients(zip(gradients, model.trainable_variables))

        else:
            train_step = self._train_step

        scheduler = kwargs.get("scheduler")

        # Train directly in TensorFlow
        from art.preprocessing.standardisation_mean_std.tensorflow import StandardisationMeanStdTensorFlow

        if isinstance(generator, TensorFlowV2DataGenerator) and (
            self.preprocessing is None
            or (
                isinstance(self.preprocessing, StandardisationMeanStdTensorFlow)
                and (
                    self.preprocessing.mean,
                    self.preprocessing.std,
                )
                == (0, 1)
            )
        ):
            for epoch in tqdm(range(nb_epochs), disable=not verbose, desc="Epochs"):
                for i_batch, o_batch in generator.iterator:
                    if self._reduce_labels:
                        o_batch = tf.math.argmax(o_batch, axis=1)
                    train_step(self._model, i_batch, o_batch)

                if scheduler is not None:
                    scheduler(epoch)
        else:
            # Fit a generic data generator through the API
            super().fit_generator(generator, nb_epochs=nb_epochs)

        Fit the classifier using the generator that yields batches as specified.

        :param generator: Batch generator providing `(x, y)` for each epoch. If the generator can be used for native
                          training in TensorFlow, it will.
        :param nb_epochs: Number of epochs to use for training.
        :param verbose: Display training progress bar.
        :param kwargs: Dictionary of framework-specific arguments. This parameter currently supports
                       "scheduler" which is an optional function that will be called at the end of every
                       epoch to adjust the learning rate.
        
art/estimators/classification/tensorflow.py