mirror of
https://github.com/vladmandic/automatic
synced 2026-09-18 16:54:33 +02:00
Merge branch 'dev' into patch-2
This commit is contained in:
+8
-6
@@ -1,16 +1,16 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2025-07-25
|
||||
## Update for 2025-07-26
|
||||
|
||||
### Highlights for 2025-07-25
|
||||
### Highlights for 2025-07-26
|
||||
|
||||
Feature highlights include:
|
||||
- **ModernUI** layout redesign which should make it more user friendly and easier to navigate and several new UI themes!
|
||||
- **ModernUI** layout redesign which should make it more user friendly and easier to navigate plus several new UI themes!
|
||||
- New models [WanAI Wan 2.1](https://wan.video/) for text-to-image workflows, [FreePix F-Lite](https://huggingface.co/Freepik/F-Lite), [Bria 3.2](https://huggingface.co/briaai/BRIA-3.2)
|
||||
- Redesigned [LTXVideo](https://vladmandic.github.io/sdnext-docs/Video) interface with support for general video models plus optimized [FramePack](https://vladmandic.github.io/sdnext-docs/FramePack) and [LTXVideo](https://vladmandic.github.io/sdnext-docs/LTX) support
|
||||
- Fully integrated nudity detection and optional censorship with [NudeNet](https://vladmandic.github.io/sdnext-docs/NudeNet)
|
||||
- New background replacement and relightning methods using **Latent Bridge Matching** and new **PixelArt** processing filter
|
||||
- New **LLM/VLM** models available for captioning and prompt enhance
|
||||
- Additional **LLM/VLM** models available for captioning and prompt enhance
|
||||
- Number of workflow and general quality-of-life improvements, especially around **Styles**, **Detailer**, **Preview**, **Batch**, **Control**
|
||||
- Compute improvements
|
||||
- [Wiki](https://github.com/vladmandic/automatic/wiki) & [Docs](https://vladmandic.github.io/sdnext-docs/) updates, especially new end-to-end [Parameters](https://vladmandic.github.io/sdnext-docs/Parameters/) page
|
||||
@@ -29,7 +29,7 @@ For details, see [ChangeLog](https://github.com/vladmandic/automatic/blob/master
|
||||
|
||||
[ReadMe](https://github.com/vladmandic/automatic/blob/master/README.md) | [ChangeLog](https://github.com/vladmandic/automatic/blob/master/CHANGELOG.md) | [Docs](https://vladmandic.github.io/sdnext-docs/) | [WiKi](https://github.com/vladmandic/automatic/wiki) | [Discord](https://discord.com/invite/sd-next-federal-batch-inspectors-1101998836328697867)
|
||||
|
||||
### Details for 2025-07-25
|
||||
### Details for 2025-07-26
|
||||
|
||||
- **License**
|
||||
- SD.Next [license](https://github.com/vladmandic/sdnext/blob/dev/LICENSE.txt) switched from **aGPL-v3.0** to **Apache-v2.0**
|
||||
@@ -81,7 +81,7 @@ For details, see [ChangeLog](https://github.com/vladmandic/automatic/blob/master
|
||||
- support for post load quantization
|
||||
- **UI**
|
||||
- major update to modernui layout
|
||||
- add new Windows-like *Blcoks* UI theme
|
||||
- add new Windows-like *Blocks* UI theme
|
||||
- redesign of the *Flat* UI theme
|
||||
- **WIKI**
|
||||
- new [Parameters](https://vladmandic.github.io/sdnext-docs/Parameters/) page that lists and explains all generation parameters
|
||||
@@ -144,6 +144,8 @@ For details, see [ChangeLog](https://github.com/vladmandic/automatic/blob/master
|
||||
- fix modules merge save model
|
||||
- fix torchvision bicubic upsample with ipex
|
||||
- fix instantir pipeline
|
||||
- fix prompt encoding if prompts within batch have different segment counts
|
||||
- fix detailer min/max size
|
||||
- cleanup control infotext
|
||||
- allow upscaling with models that have implicit VAE processing
|
||||
- framepack improve offloading
|
||||
|
||||
Submodule extensions-builtin/sdnext-modernui updated: a9300638a8...443f56bffc
Binary file not shown.
+14
-4
@@ -455,7 +455,7 @@ def set_sdpa_params():
|
||||
from flash_attn import flash_attn_func
|
||||
sdpa_pre_flash_atten = torch.nn.functional.scaled_dot_product_attention
|
||||
@wraps(sdpa_pre_flash_atten)
|
||||
def sdpa_flash_atten(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None):
|
||||
def sdpa_flash_atten(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None, enable_gqa=False, **kwargs):
|
||||
if query.shape[-1] <= 128 and attn_mask is None and query.dtype != torch.float32:
|
||||
is_unsqueezed = False
|
||||
if query.dim() == 3:
|
||||
@@ -465,6 +465,9 @@ def set_sdpa_params():
|
||||
key = key.unsqueeze(0)
|
||||
if value.dim() == 3:
|
||||
value = value.unsqueeze(0)
|
||||
if enable_gqa:
|
||||
key = key.repeat_interleave(query.size(-3)//key.size(-3), -3)
|
||||
value = value.repeat_interleave(query.size(-3)//value.size(-3), -3)
|
||||
query = query.transpose(1, 2)
|
||||
key = key.transpose(1, 2)
|
||||
value = value.transpose(1, 2)
|
||||
@@ -473,7 +476,9 @@ def set_sdpa_params():
|
||||
attn_output = attn_output.squeeze(0)
|
||||
return attn_output
|
||||
else:
|
||||
return sdpa_pre_flash_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale)
|
||||
if enable_gqa:
|
||||
kwargs["enable_gqa"] = enable_gqa
|
||||
return sdpa_pre_flash_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs)
|
||||
torch.nn.functional.scaled_dot_product_attention = sdpa_flash_atten
|
||||
log.debug('Torch attention: type="ck flash attention"')
|
||||
except Exception as err:
|
||||
@@ -485,11 +490,16 @@ def set_sdpa_params():
|
||||
from sageattention import sageattn
|
||||
sdpa_pre_sage_atten = torch.nn.functional.scaled_dot_product_attention
|
||||
@wraps(sdpa_pre_sage_atten)
|
||||
def sdpa_sage_atten(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None):
|
||||
def sdpa_sage_atten(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None, enable_gqa=False, **kwargs):
|
||||
if (query.shape[-1] in {128, 96, 64}) and (attn_mask is None) and (query.dtype != torch.float32):
|
||||
if enable_gqa:
|
||||
key = key.repeat_interleave(query.size(-3)//key.size(-3), -3)
|
||||
value = value.repeat_interleave(query.size(-3)//value.size(-3), -3)
|
||||
return sageattn(q=query, k=key, v=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale)
|
||||
else:
|
||||
return sdpa_pre_sage_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale)
|
||||
if enable_gqa:
|
||||
kwargs["enable_gqa"] = enable_gqa
|
||||
return sdpa_pre_sage_atten(query=query, key=key, value=value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs)
|
||||
torch.nn.functional.scaled_dot_product_attention = sdpa_sage_atten
|
||||
log.debug('Torch attention: type="sage attention"')
|
||||
except Exception as err:
|
||||
|
||||
+4
-4
@@ -242,7 +242,7 @@ def parse_comfy_metadata(data: dict):
|
||||
version = dct.get('extra', {}).get('frontendVersion', 'unknown')
|
||||
if version is not None:
|
||||
res = f" | Version: {version} | Nodes: {nodes}"
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
return res
|
||||
|
||||
@@ -257,7 +257,7 @@ def parse_comfy_metadata(data: dict):
|
||||
model = inp.get('model', None)
|
||||
if isinstance(model, str) and len(model) > 0:
|
||||
res += f" | Model: {model} | Class: {val.get('class_type', '')}"
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
return res
|
||||
|
||||
@@ -280,7 +280,7 @@ def parse_invoke_metadata(data: dict):
|
||||
version = dct['app_version']
|
||||
if isinstance(version, str) and len(version) > 0:
|
||||
res += f" | Version: {version}"
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
return res
|
||||
|
||||
@@ -299,7 +299,7 @@ def parse_novelai_metadata(data: dict):
|
||||
dct = json.loads(data["Comment"])
|
||||
sampler = sd_samplers.samplers_map.get(dct["sampler"], "Euler a")
|
||||
geninfo = f'{data["Description"]} Negative prompt: {dct["uc"]} Steps: {dct["steps"]}, Sampler: {sampler}, CFG scale: {dct["scale"]}, Seed: {dct["seed"]}, Clip skip: 2, ENSD: 31337'
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
pass
|
||||
return geninfo
|
||||
|
||||
|
||||
@@ -57,9 +57,11 @@ def find_sdpa_slice_sizes(query_shape, key_shape, query_element_size, slice_rate
|
||||
|
||||
original_scaled_dot_product_attention = torch.nn.functional.scaled_dot_product_attention
|
||||
@wraps(torch.nn.functional.scaled_dot_product_attention)
|
||||
def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, **kwargs):
|
||||
def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None, enable_gqa=False, **kwargs):
|
||||
if query.device.type != "xpu":
|
||||
return original_scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, **kwargs)
|
||||
if enable_gqa:
|
||||
kwargs["enable_gqa"] = enable_gqa
|
||||
return original_scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs)
|
||||
is_unsqueezed = False
|
||||
if query.dim() == 3:
|
||||
query = query.unsqueeze(0)
|
||||
@@ -68,6 +70,9 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key = key.unsqueeze(0)
|
||||
if value.dim() == 3:
|
||||
value = value.unsqueeze(0)
|
||||
if enable_gqa:
|
||||
key = key.repeat_interleave(query.size(-3)//key.size(-3), -3)
|
||||
value = value.repeat_interleave(query.size(-3)//value.size(-3), -3)
|
||||
do_batch_split, do_head_split, do_query_split, split_batch_size, split_head_size, split_query_size = find_sdpa_slice_sizes(query.shape, key.shape, query.element_size(), slice_rate=attention_slice_rate, trigger_rate=sdpa_slice_trigger_rate)
|
||||
|
||||
# Slice SDPA
|
||||
@@ -93,7 +98,7 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
value[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
attn_mask=attn_mask[start_idx:end_idx, start_idx_h:end_idx_h, start_idx_q:end_idx_q, :] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal, **kwargs
|
||||
dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs
|
||||
)
|
||||
else:
|
||||
hidden_states[start_idx:end_idx, start_idx_h:end_idx_h, :, :] = original_scaled_dot_product_attention(
|
||||
@@ -101,7 +106,7 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
value[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
attn_mask=attn_mask[start_idx:end_idx, start_idx_h:end_idx_h, :, :] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal, **kwargs
|
||||
dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs
|
||||
)
|
||||
else:
|
||||
hidden_states[start_idx:end_idx, :, :, :] = original_scaled_dot_product_attention(
|
||||
@@ -109,11 +114,11 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key[start_idx:end_idx, :, :, :],
|
||||
value[start_idx:end_idx, :, :, :],
|
||||
attn_mask=attn_mask[start_idx:end_idx, :, :, :] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal, **kwargs
|
||||
dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs
|
||||
)
|
||||
torch.xpu.synchronize(query.device)
|
||||
else:
|
||||
hidden_states = original_scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, **kwargs)
|
||||
hidden_states = original_scaled_dot_product_attention(query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs)
|
||||
if is_unsqueezed:
|
||||
hidden_states = hidden_states.squeeze(0)
|
||||
return hidden_states
|
||||
|
||||
@@ -144,8 +144,8 @@ class YoloRestorer(Detailer):
|
||||
mask_image = None
|
||||
w, h = box[2] - box[0], box[3] - box[1]
|
||||
x_size, y_size = w/image.width, h/image.height
|
||||
min_size = shared.opts.detailer_min_size if shared.opts.detailer_min_size > 0 and shared.opts.detailer_min_size < 1 else 0
|
||||
max_size = shared.opts.detailer_max_size if shared.opts.detailer_max_size > 0 and shared.opts.detailer_max_size < 1 else 1
|
||||
min_size = shared.opts.detailer_min_size if shared.opts.detailer_min_size >= 0 and shared.opts.detailer_min_size <= 1 else 0
|
||||
max_size = shared.opts.detailer_max_size if shared.opts.detailer_max_size >= 0 and shared.opts.detailer_max_size <= 1 else 1
|
||||
if x_size >= min_size and y_size >=min_size and x_size <= max_size and y_size <= max_size:
|
||||
if mask:
|
||||
mask_image = image.copy()
|
||||
|
||||
+24
-17
@@ -157,7 +157,7 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:t
|
||||
'StableCascade' in model.__class__.__name__ or
|
||||
'Flux' in model.__class__.__name__ or
|
||||
'Chroma' in model.__class__.__name__ or
|
||||
'HiDreamImagePipeline' in model.__class__.__name__ # hidream-e1 has different embeds
|
||||
'HiDreamImagePipeline' in model.__class__.__name__
|
||||
):
|
||||
try:
|
||||
prompt_parser_diffusers.embedder = prompt_parser_diffusers.PromptEmbedder(prompts, negative_prompts, steps, clip_skip, p)
|
||||
@@ -173,23 +173,28 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:t
|
||||
if 'prompt' in possible:
|
||||
if 'OmniGen' in model.__class__.__name__:
|
||||
prompts = [p.replace('|image|', '<img><|image_1|></img>') for p in prompts]
|
||||
if 'HiDreamImage' in model.__class__.__name__ and prompt_parser_diffusers.embedder is not None:
|
||||
if ('HiDreamImage' in model.__class__.__name__) and (prompt_parser_diffusers.embedder is not None):
|
||||
args['pooled_prompt_embeds'] = prompt_parser_diffusers.embedder('positive_pooleds')
|
||||
prompt_embeds = prompt_parser_diffusers.embedder('prompt_embeds')
|
||||
args['prompt_embeds_t5'] = prompt_embeds[0]
|
||||
args['prompt_embeds_llama3'] = prompt_embeds[1]
|
||||
elif hasattr(model, 'text_encoder') and hasattr(model, 'tokenizer') and 'prompt_embeds' in possible and prompt_parser_diffusers.embedder is not None:
|
||||
args['prompt_embeds'] = prompt_parser_diffusers.embedder('prompt_embeds')
|
||||
if 'StableCascade' in model.__class__.__name__:
|
||||
args['prompt_embeds_pooled'] = prompt_parser_diffusers.embedder('positive_pooleds').unsqueeze(0)
|
||||
elif 'XL' in model.__class__.__name__:
|
||||
args['pooled_prompt_embeds'] = prompt_parser_diffusers.embedder('positive_pooleds')
|
||||
elif 'StableDiffusion3' in model.__class__.__name__:
|
||||
args['pooled_prompt_embeds'] = prompt_parser_diffusers.embedder('positive_pooleds')
|
||||
elif 'Flux' in model.__class__.__name__:
|
||||
args['pooled_prompt_embeds'] = prompt_parser_diffusers.embedder('positive_pooleds')
|
||||
elif 'Chroma' in model.__class__.__name__:
|
||||
args['prompt_attention_mask'] = prompt_parser_diffusers.embedder('prompt_attention_masks')
|
||||
elif hasattr(model, 'text_encoder') and hasattr(model, 'tokenizer') and ('prompt_embeds' in possible) and (prompt_parser_diffusers.embedder is not None):
|
||||
embeds = prompt_parser_diffusers.embedder('prompt_embeds')
|
||||
if embeds is None:
|
||||
shared.log.warning('Prompt parser encode: empty prompt embeds')
|
||||
args['prompt'] = prompts
|
||||
else:
|
||||
args['prompt_embeds'] = embeds
|
||||
if 'StableCascade' in model.__class__.__name__:
|
||||
args['prompt_embeds_pooled'] = prompt_parser_diffusers.embedder('positive_pooleds').unsqueeze(0)
|
||||
elif 'XL' in model.__class__.__name__:
|
||||
args['pooled_prompt_embeds'] = prompt_parser_diffusers.embedder('positive_pooleds')
|
||||
elif 'StableDiffusion3' in model.__class__.__name__:
|
||||
args['pooled_prompt_embeds'] = prompt_parser_diffusers.embedder('positive_pooleds')
|
||||
elif 'Flux' in model.__class__.__name__:
|
||||
args['pooled_prompt_embeds'] = prompt_parser_diffusers.embedder('positive_pooleds')
|
||||
elif 'Chroma' in model.__class__.__name__:
|
||||
args['prompt_attention_mask'] = prompt_parser_diffusers.embedder('prompt_attention_masks')
|
||||
else:
|
||||
args['prompt'] = prompts
|
||||
if 'negative_prompt' in possible:
|
||||
@@ -406,11 +411,13 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:t
|
||||
clean['generator'] = f'{generator[0].device}:{[g.initial_seed() for g in generator]}'
|
||||
clean['parser'] = parser
|
||||
for k, v in clean.copy().items():
|
||||
if isinstance(v, torch.Tensor) or isinstance(v, np.ndarray):
|
||||
if v is None:
|
||||
clean[k] = None
|
||||
elif isinstance(v, torch.Tensor) or isinstance(v, np.ndarray):
|
||||
clean[k] = v.shape
|
||||
if isinstance(v, list) and len(v) > 0 and (isinstance(v[0], torch.Tensor) or isinstance(v[0], np.ndarray)):
|
||||
elif isinstance(v, list) and len(v) > 0 and (isinstance(v[0], torch.Tensor) or isinstance(v[0], np.ndarray)):
|
||||
clean[k] = [x.shape for x in v]
|
||||
if not debug_enabled and k.endswith('_embeds'):
|
||||
elif not debug_enabled and k.endswith('_embeds'):
|
||||
del clean[k]
|
||||
clean['prompt'] = 'embeds'
|
||||
task = str(sd_models.get_diffusers_task(model)).replace('DiffusersTaskType.', '')
|
||||
|
||||
@@ -73,17 +73,17 @@ class PromptEmbedder:
|
||||
earlyout = self.checkcache(p)
|
||||
if earlyout:
|
||||
return
|
||||
pipe = prepare_model(p.sd_model)
|
||||
if pipe is None:
|
||||
self.pipe = prepare_model(p.sd_model)
|
||||
if self.pipe is None:
|
||||
shared.log.error("Prompt encode: cannot find text encoder in model")
|
||||
return
|
||||
# per prompt in batch
|
||||
for batchidx, (prompt, negative_prompt) in enumerate(zip(self.prompts, self.negative_prompts)):
|
||||
self.prepare_schedule(prompt, negative_prompt)
|
||||
if self.scheduled_prompt:
|
||||
self.scheduled_encode(pipe, batchidx)
|
||||
self.scheduled_encode(self.pipe, batchidx)
|
||||
else:
|
||||
self.encode(pipe, prompt, negative_prompt, batchidx)
|
||||
self.encode(self.pipe, prompt, negative_prompt, batchidx)
|
||||
self.checkcache(p)
|
||||
debug(f"Prompt encode: time={(time.time() - t0):.3f}")
|
||||
|
||||
@@ -223,6 +223,8 @@ class PromptEmbedder:
|
||||
batch = getattr(self, key)
|
||||
res = []
|
||||
try:
|
||||
if len(batch) == 0 or len(batch[0]) == 0:
|
||||
return None # flux has no negative prompts
|
||||
if isinstance(batch[0][0], list) and len(batch[0][0]) == 2 and isinstance(batch[0][0][1], torch.Tensor) and batch[0][0][1].shape[0] == 32:
|
||||
# hidream uses a list of t5 + llama prompt embeds: [t5_embeds, llama_embeds]
|
||||
# t5_embeds shape: [batch_size, seq_len, dim]
|
||||
@@ -248,9 +250,11 @@ class PromptEmbedder:
|
||||
res.append(batch[i][step])
|
||||
except IndexError:
|
||||
res.append(batch[i][0]) # if not scheduled, return default
|
||||
if any(res[0].shape[1] != r.shape[1] for r in res):
|
||||
res = pad_to_same_length(self.pipe, res)
|
||||
return torch.cat(res)
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
shared.log.error(f"Prompt encode: {e}")
|
||||
return None
|
||||
|
||||
|
||||
@@ -472,7 +476,7 @@ def prepare_embedding_providers(pipe, clip_skip) -> list[EmbeddingsProvider]:
|
||||
|
||||
|
||||
def pad_to_same_length(pipe, embeds, empty_embedding_providers=None):
|
||||
if not hasattr(pipe, 'encode_prompt') and 'StableCascade' not in pipe.__class__.__name__:
|
||||
if not hasattr(pipe, 'encode_prompt') and ('StableCascade' not in pipe.__class__.__name__):
|
||||
return embeds
|
||||
device = devices.device
|
||||
if shared.opts.diffusers_zeros_prompt_pad or 'StableDiffusion3' in pipe.__class__.__name__:
|
||||
|
||||
@@ -54,7 +54,7 @@ def find_sdpa_slice_sizes(query_shape, key_shape, query_element_size, slice_rate
|
||||
if devices.sdpa_pre_dyanmic_atten is None:
|
||||
devices.sdpa_pre_dyanmic_atten = torch.nn.functional.scaled_dot_product_attention
|
||||
@wraps(devices.sdpa_pre_dyanmic_atten)
|
||||
def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, **kwargs):
|
||||
def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False, scale=None, enable_gqa=False, **kwargs):
|
||||
is_unsqueezed = False
|
||||
if query.dim() == 3:
|
||||
query = query.unsqueeze(0)
|
||||
@@ -63,6 +63,9 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key = key.unsqueeze(0)
|
||||
if value.dim() == 3:
|
||||
value = value.unsqueeze(0)
|
||||
if enable_gqa:
|
||||
key = key.repeat_interleave(query.size(-3)//key.size(-3), -3)
|
||||
value = value.repeat_interleave(query.size(-3)//value.size(-3), -3)
|
||||
do_batch_split, do_head_split, do_query_split, split_batch_size, split_head_size, split_query_size = find_sdpa_slice_sizes(query.shape, key.shape, query.element_size(), slice_rate=shared.opts.dynamic_attention_slice_rate, trigger_rate=shared.opts.dynamic_attention_trigger_rate)
|
||||
|
||||
# Slice SDPA
|
||||
@@ -88,7 +91,7 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
value[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
attn_mask=attn_mask[start_idx:end_idx, start_idx_h:end_idx_h, start_idx_q:end_idx_q, :] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal, **kwargs
|
||||
dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs
|
||||
)
|
||||
else:
|
||||
hidden_states[start_idx:end_idx, start_idx_h:end_idx_h, :, :] = devices.sdpa_pre_dyanmic_atten(
|
||||
@@ -96,7 +99,7 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
value[start_idx:end_idx, start_idx_h:end_idx_h, :, :],
|
||||
attn_mask=attn_mask[start_idx:end_idx, start_idx_h:end_idx_h, :, :] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal, **kwargs
|
||||
dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs
|
||||
)
|
||||
else:
|
||||
hidden_states[start_idx:end_idx, :, :, :] = devices.sdpa_pre_dyanmic_atten(
|
||||
@@ -104,12 +107,12 @@ def dynamic_scaled_dot_product_attention(query, key, value, attn_mask=None, drop
|
||||
key[start_idx:end_idx, :, :, :],
|
||||
value[start_idx:end_idx, :, :, :],
|
||||
attn_mask=attn_mask[start_idx:end_idx, :, :, :] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal, **kwargs
|
||||
dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs
|
||||
)
|
||||
if devices.backend != "directml":
|
||||
getattr(torch, query.device.type).synchronize()
|
||||
else:
|
||||
hidden_states = devices.sdpa_pre_dyanmic_atten(query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, **kwargs)
|
||||
hidden_states = devices.sdpa_pre_dyanmic_atten(query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal, scale=scale, **kwargs)
|
||||
if is_unsqueezed:
|
||||
hidden_states = hidden_states.squeeze(0)
|
||||
return hidden_states
|
||||
|
||||
+2
-2
@@ -618,8 +618,8 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), {
|
||||
"detailer_iou": OptionInfo(0.5, "Max overlap", gr.Slider, {"minimum": 0, "maximum": 1.0, "step": 0.05, "visible": False}),
|
||||
"detailer_sigma_adjust": OptionInfo(1.0, "Detailer sigma adjust", gr.Slider, {"minimum": 0, "maximum": 1.0, "step": 0.05, "visible": False}),
|
||||
"detailer_sigma_adjust_max": OptionInfo(1.0, "Detailer sigma end", gr.Slider, {"minimum": 0, "maximum": 1.0, "step": 0.05, "visible": False}),
|
||||
"detailer_min_size": OptionInfo(0.0, "Min object size", gr.Slider, {"minimum": 0.1, "maximum": 1, "step": 0.05, "visible": False}),
|
||||
"detailer_max_size": OptionInfo(1.0, "Max object size", gr.Slider, {"minimum": 0.1, "maximum": 1, "step": 0.05, "visible": False}),
|
||||
"detailer_min_size": OptionInfo(0.0, "Min object size", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.05, "visible": False}),
|
||||
"detailer_max_size": OptionInfo(1.0, "Max object size", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.05, "visible": False}),
|
||||
"detailer_padding": OptionInfo(20, "Item padding", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}),
|
||||
"detailer_blur": OptionInfo(10, "Item edge blur", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1, "visible": False}),
|
||||
"detailer_models": OptionInfo(['face-yolo8n'], "Detailer models", gr.Dropdown, lambda: {"multiselect":True, "choices": list(yolo.list), "visible": False}),
|
||||
|
||||
@@ -174,10 +174,11 @@ def save_files(js_data, files, html_info, index):
|
||||
items = infotext.parse(geninfo)
|
||||
p = PObject(items)
|
||||
try:
|
||||
seed = p.all_seeds[i]
|
||||
prompt = p.all_prompts[i]
|
||||
seed = p.all_seeds[i] if i < len(p.all_seeds) else p.seed
|
||||
prompt = p.all_prompts[i] if i < len(p.all_prompts) else p.prompt
|
||||
fullfn, txt_fullfn, _exif = images.save_image(image, shared.opts.outdir_save, "", seed=seed, prompt=prompt, info=info, extension=shared.opts.samples_format, grid=is_grid, p=p)
|
||||
except Exception as e:
|
||||
fullfn, txt_fullfn = None, None
|
||||
shared.log.error(f'Save: image={image} i={i} seeds={p.all_seeds} prompts={p.all_prompts}')
|
||||
errors.display(e, 'save')
|
||||
if fullfn is None:
|
||||
|
||||
+1
-1
Submodule wiki updated: 9b30cf154e...8df9dbd32e
Reference in New Issue
Block a user