mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 09:14:35 +02:00
add torch full deterministic mode
This commit is contained in:
@@ -38,6 +38,9 @@
|
||||
*note*: alternative to regular hidiffusion method, but with different approach to scaling
|
||||
- additional built-in 4 great custom trained **ControlNet SDXL** models from Xinsir: OpenPose, Canny, Scribble, AnimePainter
|
||||
thanks @lbeltrame
|
||||
- add torch **full deterministic mode**
|
||||
enable in settings -> compute -> use deterministic mode
|
||||
typical differences are not large and its disabled by default as it does have some performance impact
|
||||
- lower overhead on generate calls
|
||||
- cumulative fixes since the last release
|
||||
- add python version check for torch-directml
|
||||
|
||||
+5
-5
@@ -991,19 +991,19 @@ def check_ui(ver):
|
||||
return
|
||||
if ver['branch'] == ver['ui']:
|
||||
return
|
||||
log.warning(f'Branch mismatch: sdnext={ver["branch"]} ui={ver["ui"]}')
|
||||
log.debug(f'Branch mismatch: sdnext={ver["branch"]} ui={ver["ui"]}')
|
||||
cwd = os.getcwd()
|
||||
try:
|
||||
os.chdir('extensions-builtin/sdnext-modernui')
|
||||
git('checkout ' + ver['branch'])
|
||||
git('checkout ' + ver['branch'], ignore=True)
|
||||
os.chdir(cwd)
|
||||
ver = get_version(force=True)
|
||||
if ver['branch'] == ver['ui']:
|
||||
log.info(f'Branch synchronized: {ver["branch"]}')
|
||||
log.debug(f'Branch synchronized: {ver["branch"]}')
|
||||
else:
|
||||
log.error(f'Branch synchronize: sdnext={ver["branch"]} ui={ver["ui"]}')
|
||||
log.debug(f'Branch synch failed: sdnext={ver["branch"]} ui={ver["ui"]}')
|
||||
except Exception as e:
|
||||
log.error(f'Branch switch: {e}')
|
||||
log.debug(f'Branch switch: {e}')
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
|
||||
+8
-2
@@ -232,9 +232,13 @@ def set_cuda_params():
|
||||
if torch.backends.cudnn.is_available():
|
||||
try:
|
||||
torch.backends.cudnn.deterministic = shared.opts.cudnn_deterministic
|
||||
torch.use_deterministic_algorithms(shared.opts.cudnn_deterministic)
|
||||
log.debug(f'Torch mode: deterministic={shared.opts.cudnn_deterministic}')
|
||||
if shared.opts.cudnn_deterministic:
|
||||
os.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8'
|
||||
torch.backends.cudnn.benchmark = True
|
||||
if shared.opts.cudnn_benchmark:
|
||||
log.debug('Torch enable cuDNN benchmark')
|
||||
log.debug('Torch cuDNN: enable benchmark')
|
||||
torch.backends.cudnn.benchmark_limit = 0
|
||||
torch.backends.cudnn.allow_tf32 = True
|
||||
except Exception:
|
||||
@@ -363,10 +367,12 @@ def cond_cast_float(tensor):
|
||||
return tensor.float() if unet_needs_upcast else tensor
|
||||
|
||||
|
||||
def randn(seed, shape):
|
||||
def randn(seed, shape=None):
|
||||
torch.manual_seed(seed)
|
||||
if backend == 'ipex':
|
||||
torch.xpu.manual_seed_all(seed)
|
||||
if shape is None:
|
||||
return None
|
||||
if device.type == 'mps':
|
||||
return torch.randn(shape, device=cpu).to(device)
|
||||
elif shared.opts.diffusers_generator_device == "CPU":
|
||||
|
||||
@@ -5,13 +5,13 @@ from modules import shared
|
||||
from modules.hidiffusion import hidiffusion
|
||||
|
||||
|
||||
def apply_hidiffusion(p, model_type):
|
||||
def apply(p, model_type):
|
||||
if not shared.native:
|
||||
return
|
||||
if model_type not in ['sd', 'sdxl'] and p.hidiffusion:
|
||||
shared.log.warning(f'HiDiffusion: class={shared.sd_model.__class__.__name__} not supported')
|
||||
return
|
||||
remove_hidiffusion(p)
|
||||
unapply()
|
||||
if getattr(p, 'hidiffusion', False) is True:
|
||||
t0 = time.time()
|
||||
hidiffusion.is_aggressive_raunet = shared.opts.hidiffusion_steps > 0
|
||||
@@ -38,6 +38,6 @@ def apply_hidiffusion(p, model_type):
|
||||
shared.log.debug(f'HiDiffusion apply: raunet={shared.opts.hidiffusion_raunet} attn={shared.opts.hidiffusion_attn} aggressive={shared.opts.hidiffusion_steps > 0}:{shared.opts.hidiffusion_steps} t1={shared.opts.hidiffusion_t1} t2={shared.opts.hidiffusion_t2} time={t1-t0:.2f} type={shared.sd_model_type} width={p.width} height={p.height}')
|
||||
|
||||
|
||||
def remove_hidiffusion(p):
|
||||
def unapply():
|
||||
if hasattr(shared.sd_model, "unet"):
|
||||
hidiffusion.remove_hidiffusion(shared.sd_model)
|
||||
|
||||
@@ -3,7 +3,6 @@ import torch
|
||||
import torch.nn.functional as F
|
||||
from diffusers.utils.torch_utils import is_torch_version
|
||||
from diffusers.pipelines import auto_pipeline
|
||||
from modules.shared import log
|
||||
|
||||
|
||||
def sd15_hidiffusion_key():
|
||||
@@ -229,7 +228,7 @@ def make_diffusers_transformer_block(block_class: Type[torch.nn.Module]) -> Type
|
||||
norm_hidden_states = self.norm2(hidden_states)
|
||||
norm_hidden_states = norm_hidden_states * (1 + scale_mlp) + shift_mlp
|
||||
if self._chunk_size is not None:
|
||||
ff_output = _chunked_feed_forward(self.ff, norm_hidden_states, self._chunk_dim, self._chunk_size)
|
||||
ff_output = _chunked_feed_forward(self.ff, norm_hidden_states, self._chunk_dim, self._chunk_size) # TODO hidiffusion undefined
|
||||
else:
|
||||
ff_output = self.ff(norm_hidden_states)
|
||||
if self.use_ada_layer_norm_zero:
|
||||
@@ -268,7 +267,7 @@ def make_diffusers_cross_attn_down_block(block_class: Type[torch.nn.Module]) ->
|
||||
encoder_attention_mask: Optional[torch.FloatTensor] = None,
|
||||
additional_residuals: Optional[torch.FloatTensor] = None,
|
||||
) -> Tuple[torch.FloatTensor, Tuple[torch.FloatTensor, ...]]:
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
|
||||
# self.max_timestep = len(self.info['scheduler'].timesteps)
|
||||
ori_H, ori_W = self.info['size']
|
||||
if self.model == 'sd15':
|
||||
@@ -303,7 +302,7 @@ def make_diffusers_cross_attn_down_block(block_class: Type[torch.nn.Module]) ->
|
||||
self.T1 = int(self.max_timestep * self.T1_ratio)
|
||||
|
||||
output_states = ()
|
||||
cross_attention_kwargs.get("scale", 1.0) if cross_attention_kwargs is not None else 1.0
|
||||
_scale = cross_attention_kwargs.get("scale", 1.0) if cross_attention_kwargs is not None else 1.0 # TODO hidiffusion unused
|
||||
|
||||
blocks = list(zip(self.resnets, self.attentions))
|
||||
|
||||
@@ -407,7 +406,7 @@ def make_diffusers_cross_attn_up_block(block_class: Type[torch.nn.Module]) -> Ty
|
||||
return F.interpolate(first, scale_factor=rescale, mode='bicubic')
|
||||
return first
|
||||
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
|
||||
ori_H, ori_W = self.info['size']
|
||||
if self.model == 'sd15':
|
||||
if ori_H < 256 or ori_W < 256:
|
||||
@@ -489,8 +488,8 @@ def make_diffusers_downsampler_block(block_class: Type[torch.nn.Module]) -> Type
|
||||
aggressive_raunet = False
|
||||
max_timestep = 50
|
||||
|
||||
def forward(self, hidden_states: torch.Tensor, scale = 1.0) -> torch.Tensor:
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps
|
||||
def forward(self, hidden_states: torch.Tensor, scale = 1.0) -> torch.Tensor: # pylint: disable=unused-argument
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
|
||||
# self.max_timestep = len(self.info['scheduler'].timesteps)
|
||||
ori_H, ori_W = self.info['size']
|
||||
if self.model == 'sd15':
|
||||
@@ -522,20 +521,20 @@ def make_diffusers_downsampler_block(block_class: Type[torch.nn.Module]) -> Type
|
||||
else:
|
||||
self.T1 = int(self.max_timestep * self.T1_ratio)
|
||||
if self.timestep < self.T1:
|
||||
self.ori_stride = self.stride
|
||||
self.ori_padding = self.padding
|
||||
self.ori_dilation = self.dilation
|
||||
self.stride = (4,4)
|
||||
self.padding = (2,2)
|
||||
self.dilation = (2,2)
|
||||
self.ori_stride = self.stride # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.ori_padding = self.padding # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.ori_dilation = self.dilation # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.stride = (4,4) # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.padding = (2,2) # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.dilation = (2,2) # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
|
||||
hidden_states = F.conv2d(
|
||||
hidden_states, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups
|
||||
)
|
||||
if self.timestep < self.T1:
|
||||
self.stride = self.ori_stride
|
||||
self.padding = self.ori_padding
|
||||
self.dilation = self.ori_dilation
|
||||
self.stride = self.ori_stride # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.padding = self.ori_padding # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.dilation = self.ori_dilation # pylint: disable=access-member-before-definition, attribute-defined-outside-init
|
||||
self.timestep += 1
|
||||
if self.timestep == self.max_timestep:
|
||||
self.timestep = 0
|
||||
@@ -557,8 +556,8 @@ def make_diffusers_upsampler_block(block_class: Type[torch.nn.Module]) -> Type[t
|
||||
aggressive_raunet = False
|
||||
max_timestep = 50
|
||||
|
||||
def forward(self, hidden_states: torch.Tensor, scale = 1.0) -> torch.Tensor:
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps
|
||||
def forward(self, hidden_states: torch.Tensor, scale = 1.0) -> torch.Tensor: # pylint: disable=unused-argument
|
||||
self.max_timestep = self.info['pipeline']._num_timesteps # pylint: disable=protected-access
|
||||
# self.max_timestep = len(self.info['scheduler'].timesteps)
|
||||
ori_H, ori_W = self.info['size']
|
||||
if self.model == 'sd15':
|
||||
@@ -645,24 +644,21 @@ def apply_hidiffusion(
|
||||
modified_key = sd15_hidiffusion_key()
|
||||
for key, module in diffusion_model.named_modules():
|
||||
if apply_raunet and key in modified_key['down_module_key']:
|
||||
make_block_fn = make_diffusers_downsampler_block
|
||||
module.__class__ = make_block_fn(module.__class__)
|
||||
module.__class__ = make_diffusers_downsampler_block(module.__class__)
|
||||
module.switching_threshold_ratio = 'T1_ratio'
|
||||
if apply_raunet and key in modified_key['down_module_key_extra']:
|
||||
make_block_fn = make_diffusers_cross_attn_down_block
|
||||
module.__class__ = make_block_fn(module.__class__)
|
||||
module.__class__ = make_diffusers_cross_attn_down_block(module.__class__)
|
||||
module.switching_threshold_ratio = 'T2_ratio'
|
||||
if apply_raunet and key in modified_key['up_module_key']:
|
||||
make_block_fn = make_diffusers_upsampler_block
|
||||
module.__class__ = make_block_fn(module.__class__)
|
||||
module.__class__ = make_diffusers_upsampler_block(module.__class__)
|
||||
module.switching_threshold_ratio = 'T1_ratio'
|
||||
if apply_raunet and key in modified_key['up_module_key_extra']:
|
||||
make_block_fn = make_diffusers_cross_attn_up_block
|
||||
module.__class__ = make_block_fn(module.__class__)
|
||||
module.__class__ = make_diffusers_cross_attn_up_block(module.__class__)
|
||||
module.switching_threshold_ratio = 'T2_ratio'
|
||||
if apply_window_attn and key in modified_key['windown_attn_module_key']:
|
||||
make_block_fn = make_diffusers_transformer_block
|
||||
module.__class__ = make_block_fn(module.__class__)
|
||||
module.__class__ = make_diffusers_transformer_block(module.__class__)
|
||||
if hasattr(module, "_patched_forward"):
|
||||
module.forward = module._patched_forward # pylint: disable=protected-access
|
||||
module.model = 'sd15'
|
||||
module.info = diffusion_model.info
|
||||
|
||||
@@ -685,7 +681,7 @@ def apply_hidiffusion(
|
||||
if apply_window_attn and key in modified_key['windown_attn_module_key']:
|
||||
module.__class__ = make_diffusers_transformer_block(module.__class__)
|
||||
if hasattr(module, "_patched_forward"):
|
||||
module.forward = module._patched_forward
|
||||
module.forward = module._patched_forward # pylint: disable=protected-access
|
||||
module.model = 'sdxl'
|
||||
module.info = diffusion_model.info
|
||||
else:
|
||||
@@ -702,7 +698,7 @@ def remove_hidiffusion(model: torch.nn.Module):
|
||||
module.info["hooks"].clear()
|
||||
del module.info
|
||||
if hasattr(module, "_forward"):
|
||||
module.forward = module._forward
|
||||
module.forward = module._forward # pylint: disable=protected-access
|
||||
if hasattr(module, "_parent"):
|
||||
module.__class__ = module._parent
|
||||
module.__class__ = module._parent # pylint: disable=protected-access
|
||||
return model
|
||||
|
||||
@@ -10,15 +10,15 @@ orig_pipeline = None
|
||||
|
||||
def apply(p: processing.StableDiffusionProcessing): # pylint: disable=arguments-differ
|
||||
global orig_pipeline # pylint: disable=global-statement
|
||||
c = shared.sd_model.__class__ if shared.sd_loaded else None
|
||||
if not shared.native:
|
||||
return None
|
||||
if p.pag_scale == 0:
|
||||
c = shared.sd_model.__class__ if shared.sd_loaded else None
|
||||
if c == StableDiffusionPAGPipeline or c == StableDiffusionXLPAGPipeline:
|
||||
unapply()
|
||||
return None
|
||||
if c == StableDiffusionPAGPipeline or c == StableDiffusionXLPAGPipeline:
|
||||
pass
|
||||
elif detect.is_sd15(c):
|
||||
if p.pag_scale == 0:
|
||||
return
|
||||
if detect.is_sd15(c):
|
||||
orig_pipeline = shared.sd_model
|
||||
shared.sd_model = sd_models.switch_pipe(StableDiffusionPAGPipeline, shared.sd_model)
|
||||
elif detect.is_sdxl(c):
|
||||
|
||||
@@ -113,7 +113,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing):
|
||||
t0 = time.time()
|
||||
sd_models_compile.check_deepcache(enable=True)
|
||||
sd_models.move_model(shared.sd_model, devices.device)
|
||||
hidiffusion.apply_hidiffusion(p, shared.sd_model_type)
|
||||
hidiffusion.apply(p, shared.sd_model_type)
|
||||
# if 'image' in base_args:
|
||||
# base_args['image'] = set_latents(p)
|
||||
if hasattr(shared.sd_model, 'tgate') and getattr(p, 'gate_step', -1) > 0:
|
||||
@@ -123,7 +123,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing):
|
||||
output = shared.sd_model(**base_args)
|
||||
if isinstance(output, dict):
|
||||
output = SimpleNamespace(**output)
|
||||
hidiffusion.remove_hidiffusion(p)
|
||||
hidiffusion.unapply()
|
||||
sd_models_compile.openvino_post_compile(op="base") # only executes on compiled vino models
|
||||
sd_models_compile.check_deepcache(enable=False)
|
||||
if shared.cmd_opts.profile:
|
||||
|
||||
@@ -482,7 +482,10 @@ def get_generator(p):
|
||||
else:
|
||||
generator_device = devices.cpu if shared.opts.diffusers_generator_device == "CPU" else shared.device
|
||||
try:
|
||||
devices.randn(p.seeds[0])
|
||||
generator = [torch.Generator(generator_device).manual_seed(s) for s in p.seeds]
|
||||
seeds = [g.initial_seed() for g in generator]
|
||||
shared.log.debug(f'Torch generator: device={generator_device} seeds={seeds}')
|
||||
except Exception as e:
|
||||
shared.log.error(f'Torch generator: seeds={p.seeds} device={generator_device} {e}')
|
||||
generator = None
|
||||
|
||||
+5
-3
@@ -406,6 +406,9 @@ options_templates.update(options_section(('cuda', "Compute Settings"), {
|
||||
"math_sep": OptionInfo("<h2>Execution precision</h2>", "", gr.HTML),
|
||||
"precision": OptionInfo("Autocast", "Precision type", gr.Radio, {"choices": ["Autocast", "Full"]}),
|
||||
"cuda_dtype": OptionInfo("FP32" if sys.platform == "darwin" or cmd_opts.use_openvino else "BF16" if devices.backend == "ipex" else "FP16", "Device precision type", gr.Radio, {"choices": ["FP32", "FP16", "BF16"]}),
|
||||
"cudnn_deterministic": OptionInfo(False, "Use deterministic mode"),
|
||||
|
||||
"model_sep": OptionInfo("<h2>Model options</h2>", "", gr.HTML),
|
||||
"no_half": OptionInfo(False if not cmd_opts.use_openvino else True, "Full precision for model (--no-half)", None, None, None),
|
||||
"no_half_vae": OptionInfo(False if not cmd_opts.use_openvino else True, "Full precision for VAE (--no-half-vae)"),
|
||||
"upcast_sampling": OptionInfo(False if sys.platform != "darwin" else True, "Upcast sampling"),
|
||||
@@ -415,7 +418,7 @@ options_templates.update(options_section(('cuda', "Compute Settings"), {
|
||||
"nan_skip": OptionInfo(False, "Skip Generation if NaN found in latents", gr.Checkbox, {"visible": True}),
|
||||
"rollback_vae": OptionInfo(False, "Attempt VAE roll back for NaN values"),
|
||||
|
||||
"cross_attention_sep": OptionInfo("<h2>Attention</h2>", "", gr.HTML),
|
||||
"cross_attention_sep": OptionInfo("<h2>Cross Attention</h2>", "", gr.HTML),
|
||||
"cross_attention_optimization": OptionInfo(cross_attention_optimization_default, "Attention optimization method", gr.Radio, lambda: {"choices": shared_items.list_crossattention(native) }),
|
||||
"sdp_options": OptionInfo(sdp_options_default, "SDP options", gr.CheckboxGroup, {"choices": ['Flash attention', 'Memory attention', 'Math attention'] }),
|
||||
"xformers_options": OptionInfo(['Flash attention'], "xFormers options", gr.CheckboxGroup, {"choices": ['Flash attention'] }),
|
||||
@@ -425,10 +428,9 @@ options_templates.update(options_section(('cuda', "Compute Settings"), {
|
||||
"sub_quad_kv_chunk_size": OptionInfo(512, "Attention kv chunk size", gr.Slider, {"minimum": 0, "maximum": 8192, "step": 8, "visible": not native}),
|
||||
"sub_quad_chunk_threshold": OptionInfo(80, "Attention chunking threshold", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": not native}),
|
||||
|
||||
"other_sep": OptionInfo("<h2>Execution precision</h2>", "", gr.HTML),
|
||||
"other_sep": OptionInfo("<h2>Execution options</h2>", "", gr.HTML),
|
||||
"opt_channelslast": OptionInfo(False, "Use channels last "),
|
||||
"cudnn_benchmark": OptionInfo(False, "Full-depth cuDNN benchmark feature"),
|
||||
"cudnn_deterministic": OptionInfo(False, "Use deterministic options for cuDNN"),
|
||||
"diffusers_fuse_projections": OptionInfo(False, "Fused projections"),
|
||||
"torch_gc_threshold": OptionInfo(80, "Torch memory threshold for GC", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
|
||||
"torch_malloc": OptionInfo("native", "Torch memory allocator", gr.Radio, {"choices": ['native', 'cudaMallocAsync'] }),
|
||||
|
||||
Reference in New Issue
Block a user