diff --git a/html/reference.json b/html/reference.json index 8c6d752d2..49f85b189 100644 --- a/html/reference.json +++ b/html/reference.json @@ -24,7 +24,12 @@ "desc": "Segmind's Tiny-SD offers a compact, efficient, and distilled version of Realistic Vision 4.0 and is up to 80% faster than SD1.5", "preview": "segmind--tiny-sd.jpg" }, - "LCM Dreamshaper 7": { + "LCM SD-XL": { + "path": "latent-consistency/lcm-sdxl", + "desc": "Latent Consistencey Models enable swift inference with minimal steps on any pre-trained LDMs, including Stable Diffusion. By distilling classifier-free guidance into the model's input, LCM can generate high-quality images in very short inference time. LCM can generate quality images in as few as 3-4 steps, making it blazingly fast.", + "preview": "latent-consistency--lcm-sdxl.jpg" + }, + "LCM SD-1.5 Dreamshaper 7": { "path": "SimianLuo/LCM_Dreamshaper_v7", "desc": "Latent Consistencey Models enable swift inference with minimal steps on any pre-trained LDMs, including Stable Diffusion. By distilling classifier-free guidance into the model's input, LCM can generate high-quality images in very short inference time. LCM can generate quality images in as few as 3-4 steps, making it blazingly fast.", "preview": "simianluo--lcm_dreamshaper_v7.jpg" diff --git a/models/Reference/latent-consistency--lcm-sdxl.jpg b/models/Reference/latent-consistency--lcm-sdxl.jpg new file mode 100644 index 000000000..34e6b2394 Binary files /dev/null and b/models/Reference/latent-consistency--lcm-sdxl.jpg differ diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index a2d650ca7..bde6efdbc 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -387,22 +387,25 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro steps = (p.steps // (1.0 - p.refiner_start)) if shared.sd_model_type == 'sdxl' else p.steps if os.environ.get('SD_STEPS_DEBUG', None) is not None: shared.log.debug(f'Steps: type=base input={p.steps} output={steps} refiner={use_refiner_start}') - return int(steps) + return max(2, int(steps)) def calculate_hires_steps(): - steps = (p.hr_second_pass_steps * p.denoising_strength) if p.hr_second_pass_steps > 0 else (p.steps * p.denoising_strength) + # denoising strength is applied to steps by diffusers so this is no-op + # steps = (p.hr_second_pass_steps * p.denoising_strength) if p.hr_second_pass_steps > 0 else (p.steps * p.denoising_strength) + steps = p.hr_second_pass_steps if p.hr_second_pass_steps > 0 else p.steps if os.environ.get('SD_STEPS_DEBUG', None) is not None: shared.log.debug(f'Steps: type=hires input={p.hr_second_pass_steps} output={steps} denoise={p.denoising_strength}') - return int(steps) + return max(2, int(steps)) def calculate_refiner_steps(): + # diffusers apply additional math to refiner steps, but we leave numbers as-is without correction if p.refiner_start > 0 and p.refiner_start < 1: - steps = (p.refiner_steps // p.refiner_start) if p.refiner_steps > 0 else (p.steps // p.refiner_start) + steps = ((1 - p.refiner_start) * p.refiner_steps) if p.refiner_steps > 0 else ((1 - p.refiner_start) * p.steps) else: steps = (p.denoising_strength * p.refiner_steps) if p.refiner_steps > 0 else (p.denoising_strength * p.steps) if os.environ.get('SD_STEPS_DEBUG', None) is not None: shared.log.debug(f'Steps: type=refiner input={p.refiner_steps} output={steps} start={p.refiner_start} denoise={p.denoising_strength}') - return int(steps) + return max(2, int(steps)) # pipeline type is set earlier in processing, but check for sanity if sd_models.get_diffusers_task(shared.sd_model) != sd_models.DiffusersTaskType.TEXT_2_IMAGE and len(getattr(p, 'init_images' ,[])) == 0: # reset pipeline @@ -460,8 +463,6 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE) recompile_model(hires=True) update_sampler(shared.sd_model, second_pass=True) - if p.hr_second_pass_steps == 0: - p.hr_second_pass_steps = p.steps hires_args = set_pipeline_args( model=shared.sd_model, prompts=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else prompts, diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index b613fca99..4891950df 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -17,6 +17,7 @@ try: UniPCMultistepScheduler, LMSDiscreteScheduler, KDPM2AncestralDiscreteScheduler, + LCMScheduler, ) except Exception as e: import diffusers @@ -40,6 +41,7 @@ config = { 'LMSD': { 'use_karras_sigmas': False, 'timestep_spacing': 'linspace', 'steps_offset': 0 }, 'PNDM': { 'skip_prk_steps': False, 'set_alpha_to_one': False, 'steps_offset': 0 }, 'UniPC': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'predict_x0': 'bh2', 'lower_order_final': True }, + 'LCM': { 'num_train_timesteps': 1000, 'beta_start': 0.00085, 'beta_end': 0.012, 'beta_schedule': "scaled_linear", 'set_alpha_to_one': True, 'rescale_betas_zero_snr': False }, } samplers_data_diffusers = [ @@ -58,6 +60,7 @@ samplers_data_diffusers = [ sd_samplers_common.SamplerData('Euler', lambda model: DiffusionSampler('Euler', EulerDiscreteScheduler, model), [], {}), sd_samplers_common.SamplerData('Euler a', lambda model: DiffusionSampler('Euler a', EulerAncestralDiscreteScheduler, model), [], {}), sd_samplers_common.SamplerData('Heun', lambda model: DiffusionSampler('Heun', HeunDiscreteScheduler, model), [], {}), + sd_samplers_common.SamplerData('LCM', lambda model: DiffusionSampler('Heun', LCMScheduler, model), [], {}), ] class DiffusionSampler: diff --git a/requirements.txt b/requirements.txt index f34360881..b62ebcb89 100644 --- a/requirements.txt +++ b/requirements.txt @@ -50,7 +50,7 @@ requests==2.31.0 tqdm==4.66.1 accelerate==0.20.3 opencv-python-headless==4.7.0.72 -diffusers==0.22.3 +diffusers==0.23.0 einops==0.4.1 gradio==3.43.2 huggingface_hub==0.18.0