Seed Variance Enhancer

https://github.com/ChangeTheConstants/SeedVarianceEnhancer
This commit is contained in:
Haoming 2025-12-08 22:48:03 +08:00
parent 077c2d4d32
commit eecfcc461e
4 changed files with 78 additions and 36 deletions

View File

@ -0,0 +1,77 @@
# https://github.com/ChangeTheConstants/SeedVarianceEnhancer
import gradio as gr
import torch
from modules import scripts
from modules.infotext_utils import PasteField
from modules.processing import StableDiffusionProcessingTxt2Img
from modules.script_callbacks import CFGDenoiserParams, on_cfg_denoiser
from modules.ui_components import InputAccordion
class SeedVarianceEnhancer(scripts.Script):
enable: bool
steps: int
percentage: float
strength: float
seed: int
def title(self):
return "SeedVarianceEnhancer Integrated"
def show(self, is_img2img):
return None if is_img2img else scripts.AlwaysVisible
def ui(self, is_img2img):
with InputAccordion(value=False, label=self.title()) as enable:
with gr.Row():
steps = gr.Slider(value=3, minimum=0, maximum=8, step=1, label="Steps", info="the number of steps to inject random noise")
percentage = gr.Slider(value=0.6, minimum=0.0, maximum=1.0, step=0.05, label="Percentage", info="the percentage of conditioning to inject random noise")
strength = gr.Slider(value=32, minimum=0, maximum=64, step=1, label="Strength", info="the strength of the random noise")
self.infotext_fields = [
PasteField(steps, "SVE Steps"),
PasteField(percentage, "SVE Percentage"),
PasteField(strength, "SVE Strength"),
]
return [enable, steps, percentage, strength]
def before_process_batch(self, p: StableDiffusionProcessingTxt2Img, enable: bool, steps: int, percentage: float, strength: int, **kwargs):
SeedVarianceEnhancer.enable = enable and isinstance(p, StableDiffusionProcessingTxt2Img)
if not SeedVarianceEnhancer.enable:
return
SeedVarianceEnhancer.steps = steps
SeedVarianceEnhancer.percentage = percentage
SeedVarianceEnhancer.strength = strength
SeedVarianceEnhancer.seed = kwargs["seeds"][0]
p.extra_generation_params.update(
{
"SVE Steps": steps,
"SVE Percentage": percentage,
"SVE Strength": strength,
}
)
@classmethod
@torch.inference_mode()
def on_cfg(cls, params: CFGDenoiserParams):
if not cls.enable:
return
if cls.steps < params.sampling_step:
return
cond: torch.Tensor = params.text_cond
torch.manual_seed(cls.seed)
noise = torch.rand_like(cond) * 2.0 * cls.strength - cls.strength
noise_mask = torch.bernoulli(torch.ones_like(cond) * cls.percentage).bool()
modified_noise = noise * noise_mask
params.text_cond = cond + modified_noise
on_cfg_denoiser(SeedVarianceEnhancer.on_cfg)

View File

@ -379,16 +379,6 @@ def forge_model_reload():
script_callbacks.model_loaded_callback(sd_model)
timer.record("scripts callbacks")
if opts.early_empty_prompt > 0:
_cond = sd_model.get_learned_conditioning(SdConditioning([opts.empty_prompt_template]))
if isinstance(_cond, dict):
_cond = DictWithShape(_cond)
elif isinstance(_cond, list):
_cond = torch.stack(_cond)
sd_model.empty_cond = _cond.to(devices.cpu)
timer.record("calculate empty prompt")
print(f"Model loaded in {timer.summary()}.")
model_data.forge_hash = current_hash

View File

@ -1,8 +1,7 @@
import torch
import modules.shared as shared
from backend.sampling.sampling_function import sampling_function
from modules import processing, prompt_parser, sd_samplers_common
from modules import prompt_parser, sd_samplers_common
from modules.script_callbacks import AfterCFGCallbackParams, CFGDenoiserParams, cfg_after_cfg_callback, cfg_denoiser_callback
from modules.shared import opts, state
@ -127,11 +126,6 @@ class CFGDenoiser(torch.nn.Module):
noisy_initial_latent = predictor.noise_scaling(sigma[:, None, None, None], torch.randn_like(self.init_latent).to(self.init_latent), self.init_latent, max_denoise=False)
x = x * self.nmask + noisy_initial_latent * self.mask
if 0 < self.step <= opts.early_empty_prompt:
if isinstance(self.p, processing.StableDiffusionProcessingTxt2Img):
cond = shared.sd_model.empty_cond.to(original_x_device)
self.p.extra_generation_params["Empty Early CFG"] = opts.early_empty_prompt
denoiser_params = CFGDenoiserParams(x, image_cond, sigma, state.sampling_step, state.sampling_steps, cond, uncond, self)
cfg_denoiser_callback(denoiser_params)

View File

@ -242,25 +242,6 @@ options_templates.update(
gr.Textbox,
{"lines": 3, "max_lines": 6, "placeholder": "<Prompt Start>"},
),
"divdistill": OptionDiv(),
"early_empty_prompt": OptionInfo(
0,
"Steps to use Empty Prompt at the beginning",
gr.Slider,
{"minimum": 0, "maximum": 8, "step": 1},
infotext="Empty Early CFG",
)
.info("improve variance for distilled models")
.info("does not affect img2img")
.needs_restart(),
"empty_prompt_template": OptionInfo(
"",
"Prompt to Encode as the Empty Prompt",
gr.Textbox,
{"lines": 1, "max_lines": 3, "placeholder": "high quality"},
)
.info("default is empty")
.needs_restart(),
},
)
)