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