diff --git a/modules/processing.py b/modules/processing.py index 6e4485dfd..cbf41d853 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -121,7 +121,7 @@ class StableDiffusionProcessing: """ The first set of paramaters: sd_models -> do_not_reload_embeddings represent the minimum required to create a StableDiffusionProcessing """ - def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, latent_sampler: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, full_quality: bool = True, restore_faces: bool = False, tiling: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 3.5, hdr_center: bool = False, hdr_channel_shift: float = 0.8, hdr_full_shift: float = 0.8, hdr_maximize: bool = False, hdr_max_boundry: float = 4.0, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument + def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, latent_sampler: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, full_quality: bool = True, restore_faces: bool = False, tiling: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, hdr_clamp: bool = False, hdr_boundary: float = 4.0, hdr_threshold: float = 3.5, hdr_center: bool = False, hdr_channel_shift: float = 0.8, hdr_full_shift: float = 0.8, hdr_maximize: bool = False, hdr_max_center: float = 0.6, hdr_max_boundry: float = 1.0, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument self.outpath_samples: str = outpath_samples self.outpath_grids: str = outpath_grids @@ -211,6 +211,7 @@ class StableDiffusionProcessing: self.hdr_channel_shift = hdr_channel_shift self.hdr_full_shift = hdr_full_shift self.hdr_maximize = hdr_maximize + self.hdr_max_center = hdr_max_center self.hdr_max_boundry = hdr_max_boundry diff --git a/modules/processing_correction.py b/modules/processing_correction.py index 5ddecc885..c95526609 100644 --- a/modules/processing_correction.py +++ b/modules/processing_correction.py @@ -11,11 +11,12 @@ from modules import shared debug = shared.log.info if os.environ.get('SD_HDR_DEBUG', None) is not None else lambda *args, **kwargs: None -def soft_clamp_tensor(input_tensor, threshold=3.5, boundary=4): +def soft_clamp_tensor(input_tensor, threshold=0.8, boundary=4): # shrinking towards the mean; will also remove outliers - if max(abs(input_tensor.max()), abs(input_tensor.min())) < 4: + if max(abs(input_tensor.max()), abs(input_tensor.min())) < boundary or threshold == 0: return input_tensor channel_dim = 1 + threshold *= boundary max_vals = input_tensor.max(channel_dim, keepdim=True)[0] max_replace = ((input_tensor - threshold) / (max_vals - threshold)) * (boundary - threshold) + threshold over_mask = input_tensor > threshold @@ -23,21 +24,26 @@ def soft_clamp_tensor(input_tensor, threshold=3.5, boundary=4): min_replace = ((input_tensor + threshold) / (min_vals + threshold)) * (-boundary + threshold) - threshold under_mask = input_tensor < -threshold debug(f'HDE soft clamp: threshold={threshold} boundary={boundary}') - res = torch.where(over_mask, max_replace, torch.where(under_mask, min_replace, input_tensor)) - return res + input_tensor = torch.where(over_mask, max_replace, torch.where(under_mask, min_replace, input_tensor)) + return input_tensor def center_tensor(input_tensor, channel_shift=1.0, full_shift=1.0, channels=[0, 1, 2, 3]): + if channel_shift == 0 and full_shift == 0: + return input_tensor means = [] for channel in channels: means.append(input_tensor[0, channel].mean()) input_tensor[0, channel] -= means[-1] * channel_shift debug(f'HDR center: channel-shift{channel_shift} full-shift={full_shift} means={torch.stack(means)}') - res = input_tensor - input_tensor.mean() * full_shift - return res + input_tensor = input_tensor - input_tensor.mean() * full_shift + return input_tensor -def maximize_tensor(input_tensor, boundary=4.0, channels=[0, 1, 2]): +def maximize_tensor(input_tensor, boundary=1.0, channels=[0, 1, 2]): + if boundary == 1.0: + return input_tensor + boundary *= 4 min_val = input_tensor.min() max_val = input_tensor.max() normalization_factor = boundary / max(abs(min_val), abs(max_val)) @@ -52,6 +58,6 @@ def correction_callback(p, timestep, kwags): if timestep > 700 and p.hdr_center: kwags["latents"] = center_tensor(kwags["latents"], channel_shift=p.hdr_channel_shift, full_shift=p.hdr_full_shift) if timestep > 1 and timestep < 100 and p.hdr_maximize: - kwags["latents"] = center_tensor(kwags["latents"], channel_shift=0.6, full_shift=1.0) + kwags["latents"] = center_tensor(kwags["latents"], channel_shift=p.hdr_max_center, full_shift=1.0) kwags["latents"] = maximize_tensor(kwags["latents"], boundary=p.hdr_max_boundry) return kwags diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 55cbdb690..1a21c34f5 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -346,6 +346,12 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro clean['generator'] = generator_device clean['parser'] = parser shared.log.debug(f'Diffuser pipeline: {model.__class__.__name__} task={sd_models.get_diffusers_task(model)} set={clean}') + if p.hdr_clamp or p.hdr_center or p.hdr_maximize: + txt = 'HDR:' + txt += f' Clamp threshold={p.hdr_threshold} boundary={p.hdr_boundary}' if p.hdr_clamp else 'Clamp off' + txt += f' Center channel-shift={p.hdr_channel_shift} full-shift={p.hdr_full_shift}' if p.hdr_center else 'Center off' + txt += f' Maximize boundary={p.hdr_max_boundry} center={p.hdr_max_center}' if p.hdr_maximize else 'Maximize off' + shared.log.debug(txt) # components = [{ k: getattr(v, 'device', None) } for k, v in model.components.items()] # shared.log.debug(f'Diffuser pipeline components: {components}') return args diff --git a/modules/txt2img.py b/modules/txt2img.py index 3e51190cc..55751bb2d 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -4,7 +4,7 @@ from modules.generation_parameters_copypaste import create_override_settings_dic from modules.ui import plaintext_to_html -def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, full_quality: bool, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_force: bool, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, refiner_steps: int, refiner_start: int, refiner_prompt: str, refiner_negative: str, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_boundry, override_settings_texts, *args): # pylint: disable=unused-argument +def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, full_quality: bool, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_force: bool, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, refiner_steps: int, refiner_start: int, refiner_prompt: str, refiner_negative: str, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry, override_settings_texts, *args): # pylint: disable=unused-argument shared.log.debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|clip_skip={clip_skip}|seed={seed}|subseed={subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}||height={height}|width={width}|enable_hr={enable_hr}|denoising_strength={denoising_strength}|hr_scale={hr_scale}|hr_upscaler={hr_upscaler}|hr_force={hr_force}|hr_second_pass_steps={hr_second_pass_steps}|hr_resize_x={hr_resize_x}|hr_resize_y={hr_resize_y}|image_cfg_scale={image_cfg_scale}|diffusers_guidance_rescale={diffusers_guidance_rescale}|refiner_steps={refiner_steps}|refiner_start={refiner_start}|refiner_prompt={refiner_prompt}|refiner_negative={refiner_negative}|override_settings_texts={override_settings_texts}') @@ -59,7 +59,7 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step refiner_negative=refiner_negative, hdr_clamp=hdr_clamp, hdr_boundary=hdr_boundary, hdr_threshold=hdr_threshold, hdr_center=hdr_center, hdr_channel_shift=hdr_channel_shift, hdr_full_shift=hdr_full_shift, - hdr_maximize=hdr_maximize, hdr_max_boundry=hdr_max_boundry, + hdr_maximize=hdr_maximize, hdr_max_center=hdr_max_center, hdr_max_boundry=hdr_max_boundry, override_settings=override_settings, ) p.scripts = modules.scripts.scripts_txt2img diff --git a/modules/ui.py b/modules/ui.py index 611d1c0ae..3caa6016a 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -417,27 +417,31 @@ def create_ui(startup_timer = None): seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = create_seed_inputs('txt2img') with gr.Accordion(open=False, label="Advanced", elem_id="txt2img_advanced", elem_classes=["small-accordion"]): - with FormRow(): - cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG scale', value=6.0, elem_id="txt2img_cfg_scale") - clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=14, step=1, elem_id='txt2img_clip_skip', interactive=True) - with FormRow(): - image_cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='Secondary CFG scale', value=6.0, elem_id="txt2img_image_cfg_scale") - diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") - with FormRow(): - full_quality = gr.Checkbox(label='Full quality', value=True, elem_id="txt2img_full_quality") - restore_faces = gr.Checkbox(label='Face restore', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="txt2img_restore_faces") - tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling") - with FormRow(): - hdr_clamp = gr.Checkbox(label='HDR clamp', value=False, elem_id="txt2img_hdr_clamp") - hdr_boundary = gr.Slider(minimum=0.0, maximum=10.0, step=0.1, value=4.0, label='Range', elem_id="txt2img_hdr_boundary") - hdr_threshold = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, value=0.95, label='Threshold', elem_id="txt2img_hdr_threshold") - with FormRow(): - hdr_center = gr.Checkbox(label='HDR center', value=False, elem_id="txt2img_hdr_center") - hdr_channel_shift = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1.0, label='Channel shift', elem_id="txt2img_hdr_channel_shift") - hdr_full_shift = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1, label='Full shift', elem_id="txt2img_hdr_full_shift") - with FormRow(): - hdr_maximize = gr.Checkbox(label='HDR maximize', value=False, elem_id="txt2img_hdr_maximize") - hdr_max_boundry = gr.Slider(minimum=0.0, maximum=10.0, step=0.1, value=4.0, label='range', elem_id="txt2img_hdr_max_boundry") + with gr.Group(): + with FormRow(): + cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG scale', value=6.0, elem_id="txt2img_cfg_scale") + clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=14, step=1, elem_id='txt2img_clip_skip', interactive=True) + with FormRow(): + image_cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='Secondary CFG scale', value=6.0, elem_id="txt2img_image_cfg_scale") + diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id="txt2img_image_cfg_rescale") + with gr.Group(): + with FormRow(): + full_quality = gr.Checkbox(label='Full quality', value=True, elem_id="txt2img_full_quality") + restore_faces = gr.Checkbox(label='Face restore', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="txt2img_restore_faces") + tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling") + with gr.Group(): + with FormRow(): + hdr_clamp = gr.Checkbox(label='HDR clamp', value=False, elem_id="txt2img_hdr_clamp") + hdr_boundary = gr.Slider(minimum=0.0, maximum=10.0, step=0.1, value=4.0, label='Range', elem_id="txt2img_hdr_boundary") + hdr_threshold = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, value=0.95, label='Threshold', elem_id="txt2img_hdr_threshold") + with FormRow(): + hdr_center = gr.Checkbox(label='HDR center', value=False, elem_id="txt2img_hdr_center") + hdr_channel_shift = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1.0, label='Channel shift', elem_id="txt2img_hdr_channel_shift") + hdr_full_shift = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1, label='Full shift', elem_id="txt2img_hdr_full_shift") + with FormRow(): + hdr_maximize = gr.Checkbox(label='HDR maximize', value=False, elem_id="txt2img_hdr_maximize") + hdr_max_center = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=0.6, label='Center', elem_id="txt2img_hdr_max_center") + hdr_max_boundry = gr.Slider(minimum=0.5, maximum=2.0, step=0.1, value=1.0, label='Range', elem_id="txt2img_hdr_max_boundry") with gr.Accordion(open=False, label="Second pass", elem_id="txt2img_second_pass", elem_classes=["small-accordion"]): with FormGroup(): @@ -504,7 +508,7 @@ def create_ui(startup_timer = None): enable_hr, denoising_strength, hr_scale, hr_upscaler, hr_force, hr_second_pass_steps, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative, - hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_boundry, + hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry, override_settings, ] + custom_inputs, outputs=[ diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 1ca2d838c..15d11e555 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -261,6 +261,7 @@ axis_options = [ AxisOption("[HDR] Clamp threshold", float, apply_field("hdr_threshold")), AxisOption("[HDR] Center channel shift", float, apply_field("hdr_channel_shift")), AxisOption("[HDR] Center full shift", float, apply_field("hdr_full_shift")), + AxisOption("[HDR] Maximize center shift", float, apply_field("hdr_max_center")), AxisOption("[HDR] Maximize boundary", float, apply_field("hdr_max_boundry")), AxisOption("[ToMe] Token merging ratio (txt2img)", float, apply_override('token_merging_ratio')), AxisOption("[ToMe] Token merging ratio (hires)", float, apply_override('token_merging_ratio_hr')), diff --git a/wiki b/wiki index 6f0a39eda..0a871354e 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 6f0a39edad41d6d13b2822c7f93fab22d706c693 +Subproject commit 0a871354eeac24412a44c00f8da3b7fa767ee857