Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b6af0a3809 | |||
| 8c3e64f4f6 | |||
| 3ee1238630 | |||
| 17a66931da | |||
| 915d1da1cd | |||
| 884435796a | |||
| 3690e4e82c | |||
| 6427ffde4d | |||
| c63d46ceb8 | |||
| fae8bdfa48 | |||
| 10dbee0d59 | |||
| 20ae71faa8 | |||
| 6095ade147 | |||
| dd377637ca | |||
| 50906bf78b | |||
| b186045fee | |||
| 3f50b7d71c |
+15
-1
@@ -1,4 +1,18 @@
|
|||||||
## Upcoming 1.3.0
|
## 1.3.1
|
||||||
|
|
||||||
|
### Features:
|
||||||
|
* revert default cross attention optimization to Doggettx
|
||||||
|
|
||||||
|
### Bug Fixes:
|
||||||
|
* fix bug: LoRA don't apply on dropdown list sd_lora
|
||||||
|
* fix png info always added even if setting is not enabled
|
||||||
|
* fix some fields not applying in xyz plot
|
||||||
|
* fix "hires. fix" prompt sharing same labels with txt2img_prompt
|
||||||
|
* fix lora hashes not being added properly to infotex if there is only one lora
|
||||||
|
* fix --use-cpu failing to work properly at startup
|
||||||
|
* make --disable-opt-split-attention command line option work again
|
||||||
|
|
||||||
|
## 1.3.0
|
||||||
|
|
||||||
### Features:
|
### Features:
|
||||||
* add UI to edit defaults
|
* add UI to edit defaults
|
||||||
|
|||||||
+1
-1
@@ -62,7 +62,7 @@ parser.add_argument("--opt-split-attention-invokeai", action='store_true', help=
|
|||||||
parser.add_argument("--opt-split-attention-v1", action='store_true', help="prefer older version of split attention optimization for automatic choice of optimization")
|
parser.add_argument("--opt-split-attention-v1", action='store_true', help="prefer older version of split attention optimization for automatic choice of optimization")
|
||||||
parser.add_argument("--opt-sdp-attention", action='store_true', help="prefer scaled dot product cross-attention layer optimization for automatic choice of optimization; requires PyTorch 2.*")
|
parser.add_argument("--opt-sdp-attention", action='store_true', help="prefer scaled dot product cross-attention layer optimization for automatic choice of optimization; requires PyTorch 2.*")
|
||||||
parser.add_argument("--opt-sdp-no-mem-attention", action='store_true', help="prefer scaled dot product cross-attention layer optimization without memory efficient attention for automatic choice of optimization, makes image generation deterministic; requires PyTorch 2.*")
|
parser.add_argument("--opt-sdp-no-mem-attention", action='store_true', help="prefer scaled dot product cross-attention layer optimization without memory efficient attention for automatic choice of optimization, makes image generation deterministic; requires PyTorch 2.*")
|
||||||
parser.add_argument("--disable-opt-split-attention", action='store_true', help="does not do anything")
|
parser.add_argument("--disable-opt-split-attention", action='store_true', help="prefer no cross-attention layer optimization for automatic choice of optimization")
|
||||||
parser.add_argument("--disable-nan-check", action='store_true', help="do not check if produced images/latent spaces have nans; useful for running without a checkpoint in CI")
|
parser.add_argument("--disable-nan-check", action='store_true', help="do not check if produced images/latent spaces have nans; useful for running without a checkpoint in CI")
|
||||||
parser.add_argument("--use-cpu", nargs='+', help="use CPU as torch device for specified modules", default=[], type=str.lower)
|
parser.add_argument("--use-cpu", nargs='+', help="use CPU as torch device for specified modules", default=[], type=str.lower)
|
||||||
parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests")
|
parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests")
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ExtraNetworkParams:
|
|||||||
self.named = {}
|
self.named = {}
|
||||||
|
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
parts = item.split('=', 2)
|
parts = item.split('=', 2) if isinstance(item, str) else [item]
|
||||||
if len(parts) == 2:
|
if len(parts) == 2:
|
||||||
self.named[parts[0]] = parts[1]
|
self.named[parts[0]] = parts[1]
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ def reset():
|
|||||||
|
|
||||||
|
|
||||||
def quote(text):
|
def quote(text):
|
||||||
if ',' not in str(text) and '\n' not in str(text):
|
if ',' not in str(text) and '\n' not in str(text) and ':' not in str(text):
|
||||||
return text
|
return text
|
||||||
|
|
||||||
return json.dumps(text, ensure_ascii=False)
|
return json.dumps(text, ensure_ascii=False)
|
||||||
|
|||||||
@@ -493,9 +493,12 @@ def save_image_with_geninfo(image, geninfo, filename, extension=None, existing_p
|
|||||||
existing_pnginfo['parameters'] = geninfo
|
existing_pnginfo['parameters'] = geninfo
|
||||||
|
|
||||||
if extension.lower() == '.png':
|
if extension.lower() == '.png':
|
||||||
|
if opts.enable_pnginfo:
|
||||||
pnginfo_data = PngImagePlugin.PngInfo()
|
pnginfo_data = PngImagePlugin.PngInfo()
|
||||||
for k, v in (existing_pnginfo or {}).items():
|
for k, v in (existing_pnginfo or {}).items():
|
||||||
pnginfo_data.add_text(k, str(v))
|
pnginfo_data.add_text(k, str(v))
|
||||||
|
else:
|
||||||
|
pnginfo_data = None
|
||||||
|
|
||||||
image.save(filename, format=image_format, quality=opts.jpeg_quality, pnginfo=pnginfo_data)
|
image.save(filename, format=image_format, quality=opts.jpeg_quality, pnginfo=pnginfo_data)
|
||||||
|
|
||||||
|
|||||||
@@ -321,14 +321,13 @@ class StableDiffusionProcessing:
|
|||||||
have been used before. The second element is where the previously
|
have been used before. The second element is where the previously
|
||||||
computed result is stored.
|
computed result is stored.
|
||||||
"""
|
"""
|
||||||
|
if cache[0] is not None and (required_prompts, steps, opts.CLIP_stop_at_last_layers, shared.sd_model.sd_checkpoint_info) == cache[0]:
|
||||||
if cache[0] is not None and (required_prompts, steps) == cache[0]:
|
|
||||||
return cache[1]
|
return cache[1]
|
||||||
|
|
||||||
with devices.autocast():
|
with devices.autocast():
|
||||||
cache[1] = function(shared.sd_model, required_prompts, steps)
|
cache[1] = function(shared.sd_model, required_prompts, steps)
|
||||||
|
|
||||||
cache[0] = (required_prompts, steps)
|
cache[0] = (required_prompts, steps, opts.CLIP_stop_at_last_layers, shared.sd_model.sd_checkpoint_info)
|
||||||
return cache[1]
|
return cache[1]
|
||||||
|
|
||||||
def setup_conds(self):
|
def setup_conds(self):
|
||||||
|
|||||||
+17
-6
@@ -48,6 +48,11 @@ def apply_optimizations():
|
|||||||
|
|
||||||
undo_optimizations()
|
undo_optimizations()
|
||||||
|
|
||||||
|
if len(optimizers) == 0:
|
||||||
|
# a script can access the model very early, and optimizations would not be filled by then
|
||||||
|
current_optimizer = None
|
||||||
|
return ''
|
||||||
|
|
||||||
ldm.modules.diffusionmodules.model.nonlinearity = silu
|
ldm.modules.diffusionmodules.model.nonlinearity = silu
|
||||||
ldm.modules.diffusionmodules.openaimodel.th = sd_hijack_unet.th
|
ldm.modules.diffusionmodules.openaimodel.th = sd_hijack_unet.th
|
||||||
|
|
||||||
@@ -63,12 +68,15 @@ def apply_optimizations():
|
|||||||
|
|
||||||
if selection == "None":
|
if selection == "None":
|
||||||
matching_optimizer = None
|
matching_optimizer = None
|
||||||
|
elif selection == "Automatic" and shared.cmd_opts.disable_opt_split_attention:
|
||||||
|
matching_optimizer = None
|
||||||
elif matching_optimizer is None:
|
elif matching_optimizer is None:
|
||||||
matching_optimizer = optimizers[0]
|
matching_optimizer = optimizers[0]
|
||||||
|
|
||||||
if matching_optimizer is not None:
|
if matching_optimizer is not None:
|
||||||
print(f"Applying optimization: {matching_optimizer.name}")
|
print(f"Applying optimization: {matching_optimizer.name}... ", end='')
|
||||||
matching_optimizer.apply()
|
matching_optimizer.apply()
|
||||||
|
print("done.")
|
||||||
current_optimizer = matching_optimizer
|
current_optimizer = matching_optimizer
|
||||||
return current_optimizer.name
|
return current_optimizer.name
|
||||||
else:
|
else:
|
||||||
@@ -149,6 +157,13 @@ class StableDiffusionModelHijack:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.embedding_db.add_embedding_dir(cmd_opts.embeddings_dir)
|
self.embedding_db.add_embedding_dir(cmd_opts.embeddings_dir)
|
||||||
|
|
||||||
|
def apply_optimizations(self):
|
||||||
|
try:
|
||||||
|
self.optimization_method = apply_optimizations()
|
||||||
|
except Exception as e:
|
||||||
|
errors.display(e, "applying cross attention optimization")
|
||||||
|
undo_optimizations()
|
||||||
|
|
||||||
def hijack(self, m):
|
def hijack(self, m):
|
||||||
if type(m.cond_stage_model) == xlmr.BertSeriesModelWithTransformation:
|
if type(m.cond_stage_model) == xlmr.BertSeriesModelWithTransformation:
|
||||||
model_embeddings = m.cond_stage_model.roberta.embeddings
|
model_embeddings = m.cond_stage_model.roberta.embeddings
|
||||||
@@ -168,11 +183,7 @@ class StableDiffusionModelHijack:
|
|||||||
if m.cond_stage_key == "edit":
|
if m.cond_stage_key == "edit":
|
||||||
sd_hijack_unet.hijack_ddpm_edit()
|
sd_hijack_unet.hijack_ddpm_edit()
|
||||||
|
|
||||||
try:
|
self.apply_optimizations()
|
||||||
self.optimization_method = apply_optimizations()
|
|
||||||
except Exception as e:
|
|
||||||
errors.display(e, "applying cross attention optimization")
|
|
||||||
undo_optimizations()
|
|
||||||
|
|
||||||
self.clip = m.cond_stage_model
|
self.clip = m.cond_stage_model
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class SdOptimizationSdpNoMem(SdOptimization):
|
|||||||
name = "sdp-no-mem"
|
name = "sdp-no-mem"
|
||||||
label = "scaled dot product without memory efficient attention"
|
label = "scaled dot product without memory efficient attention"
|
||||||
cmd_opt = "opt_sdp_no_mem_attention"
|
cmd_opt = "opt_sdp_no_mem_attention"
|
||||||
priority = 90
|
priority = 80
|
||||||
|
|
||||||
def is_available(self):
|
def is_available(self):
|
||||||
return hasattr(torch.nn.functional, "scaled_dot_product_attention") and callable(torch.nn.functional.scaled_dot_product_attention)
|
return hasattr(torch.nn.functional, "scaled_dot_product_attention") and callable(torch.nn.functional.scaled_dot_product_attention)
|
||||||
@@ -73,7 +73,7 @@ class SdOptimizationSdp(SdOptimizationSdpNoMem):
|
|||||||
name = "sdp"
|
name = "sdp"
|
||||||
label = "scaled dot product"
|
label = "scaled dot product"
|
||||||
cmd_opt = "opt_sdp_attention"
|
cmd_opt = "opt_sdp_attention"
|
||||||
priority = 80
|
priority = 70
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
ldm.modules.attention.CrossAttention.forward = scaled_dot_product_attention_forward
|
ldm.modules.attention.CrossAttention.forward = scaled_dot_product_attention_forward
|
||||||
@@ -116,7 +116,7 @@ class SdOptimizationInvokeAI(SdOptimization):
|
|||||||
class SdOptimizationDoggettx(SdOptimization):
|
class SdOptimizationDoggettx(SdOptimization):
|
||||||
name = "Doggettx"
|
name = "Doggettx"
|
||||||
cmd_opt = "opt_split_attention"
|
cmd_opt = "opt_split_attention"
|
||||||
priority = 20
|
priority = 90
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
ldm.modules.attention.CrossAttention.forward = split_cross_attention_forward
|
ldm.modules.attention.CrossAttention.forward = split_cross_attention_forward
|
||||||
|
|||||||
@@ -313,8 +313,6 @@ def load_model_weights(model, checkpoint_info: CheckpointInfo, state_dict, timer
|
|||||||
|
|
||||||
timer.record("apply half()")
|
timer.record("apply half()")
|
||||||
|
|
||||||
devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16
|
|
||||||
devices.dtype_vae = torch.float32 if shared.cmd_opts.no_half or shared.cmd_opts.no_half_vae else torch.float16
|
|
||||||
devices.dtype_unet = model.model.diffusion_model.dtype
|
devices.dtype_unet = model.model.diffusion_model.dtype
|
||||||
devices.unet_needs_upcast = shared.cmd_opts.upcast_sampling and devices.dtype == torch.float16 and devices.dtype_unet == torch.float16
|
devices.unet_needs_upcast = shared.cmd_opts.upcast_sampling and devices.dtype == torch.float16 and devices.dtype_unet == torch.float16
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import threading
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
import gradio as gr
|
import gradio as gr
|
||||||
|
import torch
|
||||||
import tqdm
|
import tqdm
|
||||||
|
|
||||||
import modules.interrogate
|
import modules.interrogate
|
||||||
@@ -76,6 +77,9 @@ cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or cmd_op
|
|||||||
devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_esrgan, devices.device_codeformer = \
|
devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_esrgan, devices.device_codeformer = \
|
||||||
(devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'esrgan', 'codeformer'])
|
(devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'esrgan', 'codeformer'])
|
||||||
|
|
||||||
|
devices.dtype = torch.float32 if cmd_opts.no_half else torch.float16
|
||||||
|
devices.dtype_vae = torch.float32 if cmd_opts.no_half or cmd_opts.no_half_vae else torch.float16
|
||||||
|
|
||||||
device = devices.device
|
device = devices.device
|
||||||
weight_load_location = None if cmd_opts.lowram else "cpu"
|
weight_load_location = None if cmd_opts.lowram else "cpu"
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -505,10 +505,10 @@ def create_ui():
|
|||||||
with FormRow(elem_id="txt2img_hires_fix_row4", variant="compact", visible=opts.hires_fix_show_prompts) as hr_prompts_container:
|
with FormRow(elem_id="txt2img_hires_fix_row4", variant="compact", visible=opts.hires_fix_show_prompts) as hr_prompts_container:
|
||||||
with gr.Column(scale=80):
|
with gr.Column(scale=80):
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
hr_prompt = gr.Textbox(label="Prompt", elem_id="hires_prompt", show_label=False, lines=3, placeholder="Prompt for hires fix pass.\nLeave empty to use the same prompt as in first pass.", elem_classes=["prompt"])
|
hr_prompt = gr.Textbox(label="Hires prompt", elem_id="hires_prompt", show_label=False, lines=3, placeholder="Prompt for hires fix pass.\nLeave empty to use the same prompt as in first pass.", elem_classes=["prompt"])
|
||||||
with gr.Column(scale=80):
|
with gr.Column(scale=80):
|
||||||
with gr.Row():
|
with gr.Row():
|
||||||
hr_negative_prompt = gr.Textbox(label="Negative prompt", elem_id="hires_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt for hires fix pass.\nLeave empty to use the same negative prompt as in first pass.", elem_classes=["prompt"])
|
hr_negative_prompt = gr.Textbox(label="Hires negative prompt", elem_id="hires_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt for hires fix pass.\nLeave empty to use the same negative prompt as in first pass.", elem_classes=["prompt"])
|
||||||
|
|
||||||
elif category == "batch":
|
elif category == "batch":
|
||||||
if not opts.dimensions_and_batch_together:
|
if not opts.dimensions_and_batch_together:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import tempfile
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import gradio as gr
|
import gradio.components
|
||||||
|
|
||||||
from PIL import PngImagePlugin
|
from PIL import PngImagePlugin
|
||||||
|
|
||||||
@@ -31,13 +31,16 @@ def check_tmp_file(gradio, filename):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def save_pil_to_file(pil_image, dir=None):
|
def save_pil_to_file(self, pil_image, dir=None):
|
||||||
already_saved_as = getattr(pil_image, 'already_saved_as', None)
|
already_saved_as = getattr(pil_image, 'already_saved_as', None)
|
||||||
if already_saved_as and os.path.isfile(already_saved_as):
|
if already_saved_as and os.path.isfile(already_saved_as):
|
||||||
register_tmp_file(shared.demo, already_saved_as)
|
register_tmp_file(shared.demo, already_saved_as)
|
||||||
|
filename = already_saved_as
|
||||||
|
|
||||||
file_obj = Savedfile(f'{already_saved_as}?{os.path.getmtime(already_saved_as)}')
|
if not shared.opts.save_images_add_number:
|
||||||
return file_obj
|
filename += f'?{os.path.getmtime(already_saved_as)}'
|
||||||
|
|
||||||
|
return filename
|
||||||
|
|
||||||
if shared.opts.temp_dir != "":
|
if shared.opts.temp_dir != "":
|
||||||
dir = shared.opts.temp_dir
|
dir = shared.opts.temp_dir
|
||||||
@@ -51,11 +54,11 @@ def save_pil_to_file(pil_image, dir=None):
|
|||||||
|
|
||||||
file_obj = tempfile.NamedTemporaryFile(delete=False, suffix=".png", dir=dir)
|
file_obj = tempfile.NamedTemporaryFile(delete=False, suffix=".png", dir=dir)
|
||||||
pil_image.save(file_obj, pnginfo=(metadata if use_metadata else None))
|
pil_image.save(file_obj, pnginfo=(metadata if use_metadata else None))
|
||||||
return file_obj
|
return file_obj.name
|
||||||
|
|
||||||
|
|
||||||
# override save to file function so that it also writes PNG info
|
# override save to file function so that it also writes PNG info
|
||||||
gr.processing_utils.save_pil_to_file = save_pil_to_file
|
gradio.components.IOComponent.pil_to_temp_file = save_pil_to_file
|
||||||
|
|
||||||
|
|
||||||
def on_tmpdir_changed():
|
def on_tmpdir_changed():
|
||||||
|
|||||||
@@ -756,13 +756,22 @@ footer {
|
|||||||
.extra-network-cards .card .metadata-button, .extra-network-thumbs .card .metadata-button{
|
.extra-network-cards .card .metadata-button, .extra-network-thumbs .card .metadata-button{
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
|
||||||
color: white;
|
color: white;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.extra-network-cards .card .metadata-button {
|
||||||
text-shadow: 2px 2px 3px black;
|
text-shadow: 2px 2px 3px black;
|
||||||
padding: 0.25em;
|
padding: 0.25em;
|
||||||
font-size: 22pt;
|
font-size: 22pt;
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
}
|
}
|
||||||
|
.extra-network-thumbs .card .metadata-button {
|
||||||
|
text-shadow: 1px 1px 2px black;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 16pt;
|
||||||
|
width: 1em;
|
||||||
|
top: -0.25em;
|
||||||
|
}
|
||||||
.extra-network-cards .card:hover .metadata-button, .extra-network-thumbs .card:hover .metadata-button{
|
.extra-network-cards .card:hover .metadata-button, .extra-network-thumbs .card:hover .metadata-button{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@@ -787,6 +796,13 @@ footer {
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extra-network-thumbs .card .preview{
|
||||||
|
position: absolute;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height:100%;
|
||||||
|
}
|
||||||
|
|
||||||
.extra-network-thumbs .card:hover .additional a {
|
.extra-network-thumbs .card:hover .additional a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,9 +291,20 @@ def initialize_rest(*, reload_script_modules=False):
|
|||||||
modules.sd_hijack.list_optimizers()
|
modules.sd_hijack.list_optimizers()
|
||||||
startup_timer.record("scripts list_optimizers")
|
startup_timer.record("scripts list_optimizers")
|
||||||
|
|
||||||
# load model in parallel to other startup stuff
|
def load_model():
|
||||||
# (when reloading, this does nothing)
|
"""
|
||||||
Thread(target=lambda: shared.sd_model).start()
|
Accesses shared.sd_model property to load model.
|
||||||
|
After it's available, if it has been loaded before this access by some extension,
|
||||||
|
its optimization may be None because the list of optimizaers has neet been filled
|
||||||
|
by that time, so we apply optimization again.
|
||||||
|
"""
|
||||||
|
|
||||||
|
shared.sd_model # noqa: B018
|
||||||
|
|
||||||
|
if modules.sd_hijack.current_optimizer is None:
|
||||||
|
modules.sd_hijack.apply_optimizations()
|
||||||
|
|
||||||
|
Thread(target=load_model).start()
|
||||||
|
|
||||||
shared.reload_hypernetworks()
|
shared.reload_hypernetworks()
|
||||||
startup_timer.record("reload hypernetworks")
|
startup_timer.record("reload hypernetworks")
|
||||||
|
|||||||
Reference in New Issue
Block a user