
# We ignore warnings about stepping the scheduler since we step it ourselves during gradient accumulation

import warnings

from .state import AcceleratorState, GradientState


warnings.filterwarnings('''ignore''', category=UserWarning, module='''torch.optim.lr_scheduler''')




class 					_SCREAMING_SNAKE_CASE  :
      def __init__(			self		,	lowerCamelCase		,	lowerCamelCase		,	lowerCamelCase = True		,	lowerCamelCase = False ):
          snake_case__						=				scheduler
          snake_case__						=				optimizers if isinstance(lowerCamelCase		,	(list, tuple) ) else [optimizers]
          snake_case__						=				split_batches
          snake_case__						=				step_with_optimizer
          snake_case__						=				GradientState()
      def A_			(			self		,	*lowerCamelCase		,	**lowerCamelCase ):
          if not self.step_with_optimizer:
              # No link between scheduler and optimizer -> just step
              self.scheduler.step(*lowerCamelCase		,	**lowerCamelCase )
              return

          # Otherwise, first make sure the optimizer was stepped.
          if not self.gradient_state.sync_gradients:
              if self.gradient_state.adjust_scheduler:
                  self.scheduler._step_count += 1
              return

          for opt in self.optimizers:
              if opt.step_was_skipped:
                  return
          if self.split_batches:
              # Split batches -> the training dataloader batch size is not changed so one step per training step
              self.scheduler.step(*lowerCamelCase		,	**lowerCamelCase )
          else:
              # Otherwise the training dataloader batch size was multiplied by `num_processes`, so we need to do
              # num_processes steps per training step
              snake_case__						=				AcceleratorState().num_processes
              for _ in range(lowerCamelCase ):
                  # Special case when using OneCycle and `drop_last` was not used
                  if hasattr(self.scheduler		,	"total_steps" ):
                      if self.scheduler._step_count <= self.scheduler.total_steps:
                          self.scheduler.step(*lowerCamelCase		,	**lowerCamelCase )
                  else:
                      self.scheduler.step(*lowerCamelCase		,	**lowerCamelCase )
      def A_			(			self ):
          return self.scheduler.get_last_lr()
      def A_			(			self ):
          return self.scheduler.state_dict()
      def A_			(			self		,	lowerCamelCase ):
          self.scheduler.load_state_dict(lowerCamelCase )
      def A_			(			self ):
          return self.scheduler.get_lr()



      def A_			(			self		,	*lowerCamelCase		,	**lowerCamelCase ):
          return self.scheduler.print_lr(*lowerCamelCase		,	**lowerCamelCase )





import torch

from diffusers import KDPMaDiscreteScheduler
from diffusers.utils import torch_device

from .test_schedulers import SchedulerCommonTest




class 					_SCREAMING_SNAKE_CASE  (      __UpperCamelCase ):
      _A						:		Any    	=     (KDPMaDiscreteScheduler,)
      _A						:		Dict    	=     10
      def A_			(			self		,	**lowerCamelCase ):
          snake_case__						=				{
              "num_train_timesteps": 11_00,
              "beta_start": 0.0_0_0_1,
              "beta_end": 0.0_2,
              "beta_schedule": "linear",
          }

          config.update(**lowerCamelCase )
          return config
      def A_			(			self ):
          for timesteps in [10, 50, 1_00, 10_00]:
              self.check_over_configs(num_train_timesteps=lowerCamelCase )
      def A_			(			self ):
          for beta_start, beta_end in zip([0.0_0_0_0_1, 0.0_0_0_1, 0.0_0_1]		,	[0.0_0_0_2, 0.0_0_2, 0.0_2] ):
              self.check_over_configs(beta_start=lowerCamelCase		,	beta_end=lowerCamelCase )
      def A_			(			self ):
          for schedule in ["linear", "scaled_linear"]:
              self.check_over_configs(beta_schedule=lowerCamelCase )
      def A_			(			self ):
          for prediction_type in ["epsilon", "v_prediction"]:
              self.check_over_configs(prediction_type=lowerCamelCase )
      def A_			(			self ):
          snake_case__						=				self.scheduler_classes[0]
          snake_case__						=				self.get_scheduler_config(prediction_type="v_prediction" )
          snake_case__						=				scheduler_class(**lowerCamelCase )

          scheduler.set_timesteps(self.num_inference_steps )

          snake_case__						=				self.dummy_model()
          snake_case__						=				self.dummy_sample_deter * scheduler.init_noise_sigma
          snake_case__						=				sample.to(lowerCamelCase )

          for i, t in enumerate(scheduler.timesteps ):
              snake_case__						=				scheduler.scale_model_input(lowerCamelCase		,	lowerCamelCase )

              snake_case__						=				model(lowerCamelCase		,	lowerCamelCase )

              snake_case__						=				scheduler.step(lowerCamelCase		,	lowerCamelCase		,	lowerCamelCase )
              snake_case__						=				output.prev_sample

          snake_case__						=				torch.sum(torch.abs(lowerCamelCase ) )
          snake_case__						=				torch.mean(torch.abs(lowerCamelCase ) )

          if torch_device in ["cpu", "mps"]:
              assert abs(result_sum.item() - 4.69_34e-07 ) < 1e-2
              assert abs(result_mean.item() - 6.11_12e-10 ) < 1e-3
          else:
              # CUDA
              assert abs(result_sum.item() - 4.6_93_42_86_50_17_09_72e-07 ) < 1e-2
              assert abs(result_mean.item() - 0.0_0_0_2 ) < 1e-3
      def A_			(			self ):
          if torch_device == "mps":
              return
          snake_case__						=				self.scheduler_classes[0]
          snake_case__						=				self.get_scheduler_config()
          snake_case__						=				scheduler_class(**lowerCamelCase )

          scheduler.set_timesteps(self.num_inference_steps )

          snake_case__						=				self.dummy_model()
          snake_case__						=				self.dummy_sample_deter * scheduler.init_noise_sigma
          snake_case__						=				sample.to(lowerCamelCase )

          for i, t in enumerate(scheduler.timesteps ):
              snake_case__						=				scheduler.scale_model_input(lowerCamelCase		,	lowerCamelCase )

              snake_case__						=				model(lowerCamelCase		,	lowerCamelCase )

              snake_case__						=				scheduler.step(lowerCamelCase		,	lowerCamelCase		,	lowerCamelCase )
              snake_case__						=				output.prev_sample

          snake_case__						=				torch.sum(torch.abs(lowerCamelCase ) )
          snake_case__						=				torch.mean(torch.abs(lowerCamelCase ) )

          if torch_device in ["cpu", "mps"]:
              assert abs(result_sum.item() - 2_0.4_1_2_5 ) < 1e-2
              assert abs(result_mean.item() - 0.0_2_6_6 ) < 1e-3
          else:
              # CUDA
              assert abs(result_sum.item() - 2_0.4_1_2_5 ) < 1e-2
              assert abs(result_mean.item() - 0.0_2_6_6 ) < 1e-3



      def A_			(			self ):
          if torch_device == "mps":
              return
          snake_case__						=				self.scheduler_classes[0]
          snake_case__						=				self.get_scheduler_config()
          snake_case__						=				scheduler_class(**lowerCamelCase )

          scheduler.set_timesteps(self.num_inference_steps		,	device=lowerCamelCase )

          snake_case__						=				self.dummy_model()
          snake_case__						=				self.dummy_sample_deter.to(lowerCamelCase ) * scheduler.init_noise_sigma

          for t in scheduler.timesteps:
              snake_case__						=				scheduler.scale_model_input(lowerCamelCase		,	lowerCamelCase )

              snake_case__						=				model(lowerCamelCase		,	lowerCamelCase )

              snake_case__						=				scheduler.step(lowerCamelCase		,	lowerCamelCase		,	lowerCamelCase )
              snake_case__						=				output.prev_sample

          snake_case__						=				torch.sum(torch.abs(lowerCamelCase ) )
          snake_case__						=				torch.mean(torch.abs(lowerCamelCase ) )

          if str(lowerCamelCase ).startswith("cpu" ):
              # The following sum varies between 148 and 156 on mps. Why?
              assert abs(result_sum.item() - 2_0.4_1_2_5 ) < 1e-2
              assert abs(result_mean.item() - 0.0_2_6_6 ) < 1e-3
          else:
              # CUDA
              assert abs(result_sum.item() - 2_0.4_1_2_5 ) < 1e-2
              assert abs(result_mean.item() - 0.0_2_6_6 ) < 1e-3



