diff --git a/CHANGELOG.md b/CHANGELOG.md index 6da6e6b5c..7723741ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ And it also includes fixes for all reported issues so far - api: sanitize response object - api: cleanup error logging - sampler: guard against invalid sampler index + - sampler: add img2img_extra_noise option - config: reset default cfg scale to 6.0 - processing: correct display metadata - processing: fix batch file names diff --git a/extensions-builtin/sd-webui-controlnet b/extensions-builtin/sd-webui-controlnet index 02c155e42..70d95d394 160000 --- a/extensions-builtin/sd-webui-controlnet +++ b/extensions-builtin/sd-webui-controlnet @@ -1 +1 @@ -Subproject commit 02c155e4209cf6c9bf2e5a8c0e79e4c4fd877d92 +Subproject commit 70d95d3943f0c9be27ab99b55f212fd7eaf5a0c6 diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index 9b57c69c8..dd5fca68b 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -27,6 +27,18 @@ class ImageSaveParams: """dictionary with parameters for image's PNG info data; infotext will have the key 'parameters'""" +class ExtraNoiseParams: + def __init__(self, noise, x, xi): + self.noise = noise + """Random noise generated by the seed""" + + self.x = x + """Latent representation of the image""" + + self.xi = xi + """Noisy latent representation of the image""" + + class CFGDenoiserParams: def __init__(self, x, image_cond, sigma, sampling_step, total_sampling_steps, text_cond, text_uncond): self.x = x @@ -246,6 +258,14 @@ def image_save_btn_callback(filename: str): report_exception(e, c, 'image_save_btn_callback') +def extra_noise_callback(params: ExtraNoiseParams): + for c in callback_map['callbacks_extra_noise']: + try: + c.callback(params) + except Exception as e: + report_exception(e, c, 'callbacks_extra_noise') + + def cfg_denoiser_callback(params: CFGDenoiserParams): for c in callback_map['callbacks_cfg_denoiser']: try: @@ -437,6 +457,14 @@ def on_image_save_btn(callback): add_callback(callback_map['callbacks_image_save_btn'], callback) +def on_extra_noise(callback): + """register a function to be called before adding extra noise in img2img or hires fix; + The callback is called with one argument: + - params: ExtraNoiseParams - contains noise determined by seed and latent representation of image + """ + add_callback(callback_map['callbacks_extra_noise'], callback) + + def on_cfg_denoiser(callback): """register a function to be called in the kdiffussion cfg_denoiser method after building the inner model inputs. The callback is called with one argument: diff --git a/modules/sd_samplers_kdiffusion.py b/modules/sd_samplers_kdiffusion.py index 399c05317..c26f0753e 100644 --- a/modules/sd_samplers_kdiffusion.py +++ b/modules/sd_samplers_kdiffusion.py @@ -10,6 +10,7 @@ import modules.shared as shared from modules.script_callbacks import CFGDenoiserParams, cfg_denoiser_callback from modules.script_callbacks import CFGDenoisedParams, cfg_denoised_callback from modules.script_callbacks import AfterCFGCallbackParams, cfg_after_cfg_callback +from modules.script_callbacks import ExtraNoiseParams, extra_noise_callback # deal with k-diffusion imports @@ -329,6 +330,13 @@ class KDiffusionSampler: sigmas = self.get_sigmas(p, steps) sigma_sched = sigmas[steps - t_enc - 1:] xi = x + noise * sigma_sched[0] + if shared.opts.img2img_extra_noise > 0: + p.extra_generation_params["Extra noise"] = shared.opts.img2img_extra_noise + extra_noise_params = ExtraNoiseParams(noise, x, xi) + extra_noise_callback(extra_noise_params) + noise = extra_noise_params.noise + xi += noise * shared.opts.img2img_extra_noise + extra_params_kwargs = self.initialize(p) parameters = inspect.signature(self.func).parameters if 'sigma_min' in parameters: diff --git a/modules/shared.py b/modules/shared.py index 38da113e0..212566d8e 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -600,6 +600,7 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), { "img2img_background_color": OptionInfo("#ffffff", "Image transparent color fill", ui_components.FormColorPicker, {}), "inpainting_mask_weight": OptionInfo(1.0, "Inpainting conditioning mask strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), "initial_noise_multiplier": OptionInfo(1.0, "Noise multiplier for image processing", gr.Slider, {"minimum": 0.1, "maximum": 1.5, "step": 0.01}), + "img2img_extra_noise": OptionInfo(0.0, "Extra noise multiplier for img2img", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), "CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 8, "step": 1, "visible": False}), "postprocessing_sep_face_restoration": OptionInfo("