55import torch
66
77import PIL
8- from diffusers import AutoencoderKL , DDIMScheduler , DiffusionPipeline , PNDMScheduler , UNet2DConditionModel
8+ from diffusers import (
9+ AutoencoderKL ,
10+ DDIMScheduler ,
11+ DiffusionPipeline ,
12+ LMSDiscreteScheduler ,
13+ PNDMScheduler ,
14+ UNet2DConditionModel ,
15+ )
916from diffusers .pipelines .stable_diffusion import StableDiffusionSafetyChecker
1017from tqdm .auto import tqdm
1118from transformers import CLIPFeatureExtractor , CLIPTextModel , CLIPTokenizer
@@ -87,12 +94,17 @@ def __call__(
8794 # get the original timestep using init_timestep
8895 init_timestep = int (num_inference_steps * strength ) + offset
8996 init_timestep = min (init_timestep , num_inference_steps )
90- timesteps = self .scheduler .timesteps [- init_timestep ]
91- timesteps = torch .tensor ([timesteps ] * batch_size , dtype = torch .long , device = self .device )
97+ if isinstance (self .scheduler , LMSDiscreteScheduler ):
98+ timesteps = torch .tensor (
99+ [num_inference_steps - init_timestep ] * batch_size , dtype = torch .long , device = self .device
100+ )
101+ else :
102+ timesteps = self .scheduler .timesteps [- init_timestep ]
103+ timesteps = torch .tensor ([timesteps ] * batch_size , dtype = torch .long , device = self .device )
92104
93105 # add noise to latents using the timesteps
94106 noise = torch .randn (init_latents .shape , generator = generator , device = self .device )
95- init_latents = self .scheduler .add_noise (init_latents , noise , timesteps )
107+ init_latents = self .scheduler .add_noise (init_latents , noise , timesteps ). to ( self . device )
96108
97109 # get prompt text embeddings
98110 text_input = self .tokenizer (
@@ -133,8 +145,15 @@ def __call__(
133145 latents = init_latents
134146 t_start = max (num_inference_steps - init_timestep + offset , 0 )
135147 for i , t in tqdm (enumerate (self .scheduler .timesteps [t_start :])):
148+ t_index = t_start + i
136149 # expand the latents if we are doing classifier free guidance
137150 latent_model_input = torch .cat ([latents ] * 2 ) if do_classifier_free_guidance else latents
151+ if isinstance (self .scheduler , LMSDiscreteScheduler ):
152+ sigma = self .scheduler .sigmas [t_index ]
153+ # the model input needs to be scaled to match the continuous ODE formulation in K-LMS
154+ latent_model_input = latent_model_input / ((sigma ** 2 + 1 ) ** 0.5 )
155+ latent_model_input = latent_model_input .to (self .unet .dtype )
156+ t = t .to (self .unet .dtype )
138157
139158 # predict the noise residual
140159 noise_pred = self .unet (latent_model_input , t , encoder_hidden_states = text_embeddings )["sample" ]
@@ -145,11 +164,14 @@ def __call__(
145164 noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond )
146165
147166 # compute the previous noisy sample x_t -> x_t-1
148- latents = self .scheduler .step (noise_pred , t , latents , ** extra_step_kwargs )["prev_sample" ]
167+ if isinstance (self .scheduler , LMSDiscreteScheduler ):
168+ latents = self .scheduler .step (noise_pred , t_index , latents , ** extra_step_kwargs )["prev_sample" ]
169+ else :
170+ latents = self .scheduler .step (noise_pred , t , latents , ** extra_step_kwargs )["prev_sample" ]
149171
150172 # scale and decode the image latents with vae
151173 latents = 1 / 0.18215 * latents
152- image = self .vae .decode (latents )
174+ image = self .vae .decode (latents . to ( self . vae . dtype ) )
153175
154176 image = (image / 2 + 0.5 ).clamp (0 , 1 )
155177 image = image .cpu ().permute (0 , 2 , 3 , 1 ).numpy ()
0 commit comments