keras/src/callbacks/learning_rate_scheduler.py/LearningRateScheduler/on_epoch_begin
class LearningRateScheduler:    def on_epoch_begin(self, epoch, logs=None):
        if not hasattr(self.model.optimizer, "learning_rate"):
            raise ValueError('Optimizer must have a "learning_rate" attribute.')

        try:  # new API
            learning_rate = float(
                backend.convert_to_numpy(self.model.optimizer.learning_rate)
            )
            learning_rate = self.schedule(epoch, learning_rate)
        except TypeError:  # Support for old API for backward compatibility
            learning_rate = self.schedule(epoch)

        if not isinstance(learning_rate, (float, np.float32, np.float64)):
            raise ValueError(
                "The output of the `schedule` function should be a float. "
                f"Got: {learning_rate}"
            )

        self.model.optimizer.learning_rate = learning_rate
        if self.verbose > 0:
            io_utils.print_msg(
                f"\nEpoch {epoch + 1}: LearningRateScheduler setting learning "
                f"rate to {learning_rate}."
            )