diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f3513097..d04ae6bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/extensions-builtin/sdnext-modernui b/extensions-builtin/sdnext-modernui index a9300638a..443f56bff 160000 --- a/extensions-builtin/sdnext-modernui +++ b/extensions-builtin/sdnext-modernui @@ -1 +1 @@ -Subproject commit a9300638a86f77be92d80a7f18dae40ecd5c4a81 +Subproject commit 443f56bffc92dc18d79ad6ab32dca3a5fd93bcc7 diff --git a/javascript/ibmplexmono-nerdfont-medium.ttf b/javascript/ibmplexmono-nerdfont-medium.ttf new file mode 100644 index 000000000..39f178db7 Binary files /dev/null and b/javascript/ibmplexmono-nerdfont-medium.ttf differ diff --git a/modules/devices.py b/modules/devices.py index 83ec573e4..ed8d91a47 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -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: diff --git a/modules/images.py b/modules/images.py index 4e294d7a0..6b3bba16a 100644 --- a/modules/images.py +++ b/modules/images.py @@ -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 diff --git a/modules/intel/ipex/attention.py b/modules/intel/ipex/attention.py index 177f5bc5e..ae1b9a811 100644 --- a/modules/intel/ipex/attention.py +++ b/modules/intel/ipex/attention.py @@ -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 diff --git a/modules/postprocess/yolo.py b/modules/postprocess/yolo.py index e0ada31b8..cb6592244 100644 --- a/modules/postprocess/yolo.py +++ b/modules/postprocess/yolo.py @@ -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() diff --git a/modules/processing_args.py b/modules/processing_args.py index 75b5cd03a..24ea8e6e5 100644 --- a/modules/processing_args.py +++ b/modules/processing_args.py @@ -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|', '<|image_1|>') 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.', '') diff --git a/modules/prompt_parser_diffusers.py b/modules/prompt_parser_diffusers.py index b0c46d71b..a2c0f4b8b 100644 --- a/modules/prompt_parser_diffusers.py +++ b/modules/prompt_parser_diffusers.py @@ -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__: diff --git a/modules/sd_hijack_dynamic_atten.py b/modules/sd_hijack_dynamic_atten.py index 7a394772a..f9f46cb44 100644 --- a/modules/sd_hijack_dynamic_atten.py +++ b/modules/sd_hijack_dynamic_atten.py @@ -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 diff --git a/modules/shared.py b/modules/shared.py index dd7219647..0996277f7 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -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}), diff --git a/modules/ui_common.py b/modules/ui_common.py index 299f8d751..454775e1b 100644 --- a/modules/ui_common.py +++ b/modules/ui_common.py @@ -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: diff --git a/wiki b/wiki index 9b30cf154..8df9dbd32 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 9b30cf154e3f715da69a8317511465fe8b7bf13f +Subproject commit 8df9dbd32e89d51698b73fc00ca6f649be35b39d