mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 01:04:32 +02:00
jumbo update, see changelog
This commit is contained in:
+14
-2
@@ -1,11 +1,12 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2024-09-17
|
||||
## Update for 2024-09-18
|
||||
|
||||
- **flux**
|
||||
- avoid unet load if unchanged
|
||||
- mark specific unet as unavailable if load failed
|
||||
- fix diffusers local model name parsing
|
||||
- full prompt parser will auto-select `xhinker` for flux models
|
||||
- **xyz grid** full refactor
|
||||
- multi-mode: *selectable-script* and *alwayson-script*
|
||||
- allow usage combined with other scripts
|
||||
@@ -29,9 +30,20 @@
|
||||
- if prompt contains `_tags_` it will be used as placeholder for replacement, otherwise tags will be appended
|
||||
- used tags are also logged and registered in image metadata
|
||||
- correct using of `extra_networks_default_multiplier` if not scale is specified
|
||||
- **hf** force logout/login on token change
|
||||
- **text encoder**:
|
||||
- allow loading different custom text encoders: *clip-vit-l, clip-vit-g, t5*
|
||||
will automatically find appropriate encoder in the loaded model and replace it with loaded text encoder
|
||||
download text encoders into folder set in settings -> system paths -> text encoders
|
||||
default `models/Text-encoder` folder is used if no custom path is set
|
||||
example *clip-vit-l* models: [Detailed & Smooth](https://huggingface.co/zer0int/CLIP-GmP-ViT-L-14), [LongCLIP](https://huggingface.co/zer0int/LongCLIP-GmP-ViT-L-14)
|
||||
- xyz grid support for text encoder
|
||||
- full prompt parser now correctly works with different prompts in batch
|
||||
- **huggingface**:
|
||||
- force logout/login on token change
|
||||
- unified handling of cache folder: set via `HF_HUB` or `HF_HUB_CACHE` or via settings -> system paths
|
||||
- **backend=original** is now marked as in maintenance-only mode
|
||||
- **python 3.12** improved compatibility, automatically handle `setuptools`
|
||||
- massive log cleanup
|
||||
- minor ui optimizations
|
||||
|
||||
## Update for 2024-09-13
|
||||
|
||||
@@ -61,7 +61,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
||||
loaded.tags = loaded.tags[:shared.opts.lora_apply_tags]
|
||||
all_tags.extend(loaded.tags)
|
||||
if len(all_tags) > 0:
|
||||
shared.log.debug(f"LoRA apply: max={shared.opts.lora_apply_tags} tags{all_tags}")
|
||||
shared.log.debug(f"Load network: type=LoRA max={shared.opts.lora_apply_tags} tags={all_tags} apply")
|
||||
all_tags = ', '.join(all_tags)
|
||||
p.extra_generation_params["LoRA tags"] = all_tags
|
||||
if p.all_prompts is not None:
|
||||
@@ -129,7 +129,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
||||
if len(names) > 0 and step == 0:
|
||||
self.infotext(p)
|
||||
self.prompt(p)
|
||||
shared.log.info(f'LoRA apply: {names} patch={t1-t0:.2f} te={te_multipliers} unet={unet_multipliers} dims={dyn_dims} load={t2-t1:.2f}')
|
||||
shared.log.info(f'Load network: type=LoRA apply={names} patch={t1-t0:.2f} te={te_multipliers} unet={unet_multipliers} dims={dyn_dims} load={t2-t1:.2f}')
|
||||
elif self.active:
|
||||
self.active = False
|
||||
|
||||
|
||||
@@ -86,25 +86,24 @@ def load_diffusers(name, network_on_disk, lora_scale=shared.opts.extra_networks_
|
||||
t0 = time.time()
|
||||
name = name.replace(".", "_")
|
||||
#cached = lora_cache.get(name, None)
|
||||
shared.log.debug(f'LoRA load: name="{name}" file="{network_on_disk.filename}" type=diffusers scale={lora_scale} fuse={shared.opts.lora_fuse_diffusers}')
|
||||
shared.log.debug(f'Load network: type=LoRA name="{name}" file="{network_on_disk.filename}" type=diffusers scale={lora_scale} fuse={shared.opts.lora_fuse_diffusers}')
|
||||
# if cached is not None:
|
||||
# return cached
|
||||
if not shared.native:
|
||||
return None
|
||||
if not hasattr(shared.sd_model, 'load_lora_weights'):
|
||||
shared.log.error(f'LoRA load failed: class={shared.sd_model.__class__} does not implement load lora')
|
||||
shared.log.error(f'Load network: type=LoRA class={shared.sd_model.__class__} does not implement load lora')
|
||||
return None
|
||||
try:
|
||||
shared.sd_model.load_lora_weights(network_on_disk.filename, adapter_name=name)
|
||||
except Exception as e:
|
||||
if 'already in use' in str(e):
|
||||
# shared.log.warning(f'LoRA load failed: file={network_on_disk.filename} {e}')
|
||||
pass
|
||||
else:
|
||||
if 'The following keys have not been correctly renamed' in str(e):
|
||||
shared.log.error(f'LoRA load failed: file="{network_on_disk.filename}" diffusers unsupported format')
|
||||
shared.log.error(f'Load network: type=LoRA file="{network_on_disk.filename}" diffusers unsupported format')
|
||||
else:
|
||||
shared.log.error(f'LoRA load failed: file="{network_on_disk.filename}" {e}')
|
||||
shared.log.error(f'Load network: type=LoRA file="{network_on_disk.filename}" {e}')
|
||||
if debug:
|
||||
errors.display(e, "LoRA")
|
||||
return None
|
||||
@@ -123,7 +122,7 @@ def load_network(name, network_on_disk) -> network.Network:
|
||||
t0 = time.time()
|
||||
cached = lora_cache.get(name, None)
|
||||
if debug:
|
||||
shared.log.debug(f'LoRA load: name="{name}" file="{network_on_disk.filename}" type=lora {"cached" if cached else ""}')
|
||||
shared.log.debug(f'Load network: type=LoRA name="{name}" file="{network_on_disk.filename}" type=lora {"cached" if cached else ""}')
|
||||
if cached is not None:
|
||||
return cached
|
||||
net = network.Network(name, network_on_disk)
|
||||
@@ -148,8 +147,6 @@ def load_network(name, network_on_disk) -> network.Network:
|
||||
network_part = '.'.join(parts[-2:]).replace('lora_A', 'lora_down').replace('lora_B', 'lora_up')
|
||||
else:
|
||||
key_network_without_network_parts, network_part = key_network.split(".", 1)
|
||||
# if debug:
|
||||
# shared.log.debug(f'LoRA load: name="{name}" full={key_network} network={network_part} key={key_network_without_network_parts}')
|
||||
key, sd_module = convert(key_network_without_network_parts) # Now returns lists
|
||||
if sd_module[0] is None:
|
||||
if "bundle_emb" not in key_network:
|
||||
@@ -222,7 +219,7 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No
|
||||
if network_on_disk is not None:
|
||||
shorthash = getattr(network_on_disk, 'shorthash', '').lower()
|
||||
if debug:
|
||||
shared.log.debug(f'LoRA load: name="{name}" file="{network_on_disk.filename}" hash="{shorthash}"')
|
||||
shared.log.debug(f'Load network: type=LoRA name="{name}" file="{network_on_disk.filename}" hash="{shorthash}"')
|
||||
try:
|
||||
if recompile_model:
|
||||
shared.compiled_model_state.lora_model.append(f"{name}:{te_multipliers[i] if te_multipliers else shared.opts.extra_networks_default_multiplier}")
|
||||
@@ -234,13 +231,13 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No
|
||||
net.mentioned_name = name
|
||||
network_on_disk.read_hash()
|
||||
except Exception as e:
|
||||
shared.log.error(f'LoRA load failed: file="{network_on_disk.filename}" {e}')
|
||||
shared.log.error(f'Load network: type=LoRA file="{network_on_disk.filename}" {e}')
|
||||
if debug:
|
||||
errors.display(e, 'LoRA')
|
||||
continue
|
||||
if net is None:
|
||||
failed_to_load_networks.append(name)
|
||||
shared.log.error(f'LoRA unknown type: network="{name}"')
|
||||
shared.log.error(f'Load network: type=LoRA network="{name}" unknown type')
|
||||
continue
|
||||
if shared.native:
|
||||
shared.sd_model.embedding_db.load_diffusers_embedding(None, net.bundle_embeddings)
|
||||
@@ -253,17 +250,17 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No
|
||||
name = next(iter(lora_cache))
|
||||
lora_cache.pop(name, None)
|
||||
if len(diffuser_loaded) > 0:
|
||||
shared.log.debug(f'LoRA loaded={diffuser_loaded} scales={diffuser_scales}')
|
||||
shared.log.debug(f'Load network: type=LoRA loaded={diffuser_loaded} scales={diffuser_scales}')
|
||||
shared.sd_model.set_adapters(adapter_names=diffuser_loaded, adapter_weights=diffuser_scales)
|
||||
if shared.opts.lora_fuse_diffusers:
|
||||
shared.sd_model.fuse_lora(adapter_names=diffuser_loaded, lora_scale=1.0, fuse_unet=True, fuse_text_encoder=True) # fuse uses fixed scale since later apply does the scaling
|
||||
shared.sd_model.unload_lora_weights()
|
||||
if len(loaded_networks) > 0 and debug:
|
||||
shared.log.debug(f'LoRA loaded={len(loaded_networks)} cache={list(lora_cache)}')
|
||||
shared.log.debug(f'Load network: type=LoRA loaded={len(loaded_networks)} cache={list(lora_cache)}')
|
||||
devices.torch_gc()
|
||||
|
||||
if recompile_model:
|
||||
shared.log.info("LoRA recompiling model")
|
||||
shared.log.info("Load network: type=LoRA recompiling model")
|
||||
backup_lora_model = shared.compiled_model_state.lora_model
|
||||
if 'Model' in shared.opts.cuda_compile:
|
||||
shared.sd_model = sd_models_compile.compile_diffusers(shared.sd_model)
|
||||
@@ -532,7 +529,7 @@ def list_available_networks():
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor:
|
||||
for fn in candidates:
|
||||
executor.submit(add_network, fn)
|
||||
shared.log.info(f'LoRA networks: available={len(available_networks)} folders={len(forbidden_network_aliases)}')
|
||||
shared.log.info(f'Available LoRAs: items={len(available_networks)} folders={len(forbidden_network_aliases)}')
|
||||
|
||||
|
||||
def infotext_pasted(infotext, params): # pylint: disable=W0613
|
||||
|
||||
@@ -110,7 +110,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
|
||||
|
||||
return item
|
||||
except Exception as e:
|
||||
shared.log.error(f"Networks: type=lora file={name} {e}")
|
||||
shared.log.error(f'Networks: type=lora file="{name}" {e}')
|
||||
if debug:
|
||||
from modules import errors
|
||||
errors.display('e', 'Lora')
|
||||
|
||||
+3
-2
@@ -88,6 +88,7 @@ def setup_logging():
|
||||
from rich.theme import Theme
|
||||
from rich.logging import RichHandler
|
||||
from rich.console import Console
|
||||
from rich import print as rprint
|
||||
from rich.pretty import install as pretty_install
|
||||
from rich.traceback import install as traceback_install
|
||||
|
||||
@@ -102,6 +103,7 @@ def setup_logging():
|
||||
|
||||
level = logging.DEBUG if args.debug else logging.INFO
|
||||
log.setLevel(logging.DEBUG) # log to file is always at level debug for facility `sd`
|
||||
log.print = rprint
|
||||
global console # pylint: disable=global-statement
|
||||
console = Console(log_time=True, log_time_format='%H:%M:%S-%f', theme=Theme({
|
||||
"traceback.border": "black",
|
||||
@@ -789,7 +791,7 @@ def run_extension_installer(folder):
|
||||
env['PYTHONPATH'] = os.path.abspath(".")
|
||||
result = subprocess.run(f'"{sys.executable}" "{path_installer}"', shell=True, env=env, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=folder)
|
||||
txt = result.stdout.decode(encoding="utf8", errors="ignore")
|
||||
debug(f'Extension installer: file={path_installer} {txt}')
|
||||
debug(f'Extension installer: file="{path_installer}" {txt}')
|
||||
if result.returncode != 0:
|
||||
global errors # pylint: disable=global-statement
|
||||
errors += 1
|
||||
@@ -975,7 +977,6 @@ def set_environment():
|
||||
os.environ.setdefault('KINETO_LOG_LEVEL', '3')
|
||||
os.environ.setdefault('DO_NOT_TRACK', '1')
|
||||
os.environ.setdefault('HF_HUB_CACHE', opts.get('hfcache_dir', os.path.join(os.path.expanduser('~'), '.cache', 'huggingface', 'hub')))
|
||||
log.debug(f'Huggingface folders: home="{os.environ.get("HF_HUB")}" cache="{os.environ.get("HF_HUB_CACHE")}"')
|
||||
allocator = f'garbage_collection_threshold:{opts.get("torch_gc_threshold", 80)/100:0.2f},max_split_size_mb:512'
|
||||
if opts.get("torch_malloc", "native") == 'cudaMallocAsync':
|
||||
allocator += ',backend:cudaMallocAsync'
|
||||
|
||||
@@ -16,7 +16,7 @@ class DeepDanbooru:
|
||||
if self.model is not None:
|
||||
return
|
||||
model_path = os.path.join(paths.models_path, "DeepDanbooru")
|
||||
shared.log.debug(f'Loading interrogate model: type=DeepDanbooru folder={model_path}')
|
||||
shared.log.debug(f'Loading interrogate model: type=DeepDanbooru folder="{model_path}"')
|
||||
files = modelloader.load_models(
|
||||
model_path=model_path,
|
||||
model_url='https://github.com/AUTOMATIC1111/TorchDeepDanbooru/releases/download/v1/model-resnet_custom_v3.pt',
|
||||
|
||||
@@ -80,13 +80,13 @@ def face_id(
|
||||
basename, _ext = os.path.splitext(filename)
|
||||
model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.diffusers_dir)
|
||||
if model_path is None:
|
||||
shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}")
|
||||
shared.log.error(f'FaceID download failed: model={model} file="{ip_ckpt}"')
|
||||
return None
|
||||
if faceid_model_weights is None or faceid_model_name != model or not cache:
|
||||
shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}")
|
||||
shared.log.debug(f'FaceID load: model={model} file="{ip_ckpt}"')
|
||||
faceid_model_weights = torch.load(model_path, map_location="cpu")
|
||||
else:
|
||||
shared.log.debug(f"FaceID cached: model={model} file={ip_ckpt}")
|
||||
shared.log.debug(f'FaceID cached: model={model} file="{ip_ckpt}"')
|
||||
|
||||
if "XL Plus" in model and shared.sd_model_type == 'sd':
|
||||
image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K"
|
||||
|
||||
@@ -240,5 +240,5 @@ def apply(pipe, p: processing.StableDiffusionProcessing, adapter_names=[], adapt
|
||||
t1 = time.time()
|
||||
shared.log.info(f'IP adapter: {ip_str} image={adapter_images} mask={adapter_masks is not None} time={t1-t0:.2f}')
|
||||
except Exception as e:
|
||||
shared.log.error(f'IP adapter failed to load: repo={base_repo} folder={ip_subfolder} weights={adapters} names={adapter_names} {e}')
|
||||
shared.log.error(f'IP adapter failed to load: repo="{base_repo}" folder="{ip_subfolder}" weights={adapters} names={adapter_names} {e}')
|
||||
return True
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ def download_model():
|
||||
filename = os.path.basename(parts.path)
|
||||
cached_file = os.path.join(model_dir, filename)
|
||||
if not os.path.exists(cached_file):
|
||||
log.info(f'LaMa download: url={LAMA_MODEL_URL} file={cached_file}')
|
||||
log.info(f'LaMa download: url="{LAMA_MODEL_URL}" file="{cached_file}"')
|
||||
hash_prefix = None
|
||||
download_url_to_file(LAMA_MODEL_URL, cached_file, hash_prefix, progress=True)
|
||||
return cached_file
|
||||
|
||||
@@ -139,7 +139,7 @@ def load_transformer(file_path): # triggered by opts.sd_unet change
|
||||
"torch_dtype": devices.dtype,
|
||||
"cache_dir": shared.opts.hfcache_dir,
|
||||
}
|
||||
shared.log.info(f'Loading UNet: type=FLUX file="{file_path}" offload={shared.opts.diffusers_offload_mode} quant={quant} dtype={devices.dtype}')
|
||||
shared.log.info(f'Load module: type=UNet/Transformer file="{file_path}" offload={shared.opts.diffusers_offload_mode} quant={quant} dtype={devices.dtype}')
|
||||
if quant == 'qint8' or quant == 'qint4':
|
||||
_transformer, _text_encoder_2 = load_flux_quanto(file_path)
|
||||
if _transformer is not None:
|
||||
@@ -191,7 +191,7 @@ def load_flux(checkpoint_info, diffusers_load_config): # triggered by opts.sd_ch
|
||||
if shared.opts.sd_text_encoder != 'None':
|
||||
try:
|
||||
debug(f'Loading FLUX: t5="{shared.opts.sd_text_encoder}"')
|
||||
from modules.model_t5 import load_t5
|
||||
from modules.model_te import load_t5
|
||||
_text_encoder_2 = load_t5(t5=shared.opts.sd_text_encoder, cache_dir=shared.opts.diffusers_dir)
|
||||
if _text_encoder_2 is not None:
|
||||
text_encoder_2 = _text_encoder_2
|
||||
|
||||
@@ -2,13 +2,13 @@ import diffusers
|
||||
|
||||
|
||||
def load_pixart(checkpoint_info, diffusers_load_config={}):
|
||||
from modules import shared, devices, modelloader, model_t5
|
||||
from modules import shared, devices, modelloader, model_te
|
||||
modelloader.hf_login()
|
||||
# shared.opts.data['cuda_dtype'] = 'FP32' # override
|
||||
# shared.opts.data['diffusers_offload_mode}'] = "model" # override
|
||||
# devices.set_cuda_params()
|
||||
fn = checkpoint_info.path.replace('huggingface/', '')
|
||||
t5 = model_t5.load_t5(shared.opts.sd_text_encoder, cache_dir=shared.opts.diffusers_dir)
|
||||
t5 = model_te.load_t5(shared.opts.sd_text_encoder, cache_dir=shared.opts.diffusers_dir)
|
||||
transformer = diffusers.PixArtTransformer2DModel.from_pretrained(
|
||||
fn,
|
||||
subfolder = 'transformer',
|
||||
|
||||
@@ -3,19 +3,21 @@ import json
|
||||
import torch
|
||||
import transformers
|
||||
from safetensors.torch import load_file
|
||||
from modules import shared, devices, files_cache
|
||||
from modules import shared, devices, files_cache, errors
|
||||
from installer import install
|
||||
|
||||
|
||||
t5_dict = {}
|
||||
te_dict = {}
|
||||
debug = os.environ.get('SD_LOAD_DEBUG', None) is not None
|
||||
loaded_te = None
|
||||
|
||||
|
||||
def load_t5(t5=None, cache_dir=None):
|
||||
from modules import modelloader
|
||||
modelloader.hf_login()
|
||||
repo_id = 'stabilityai/stable-diffusion-3-medium-diffusers'
|
||||
fn = t5_dict.get(t5) if t5 in t5_dict else None
|
||||
if fn is not None:
|
||||
fn = te_dict.get(t5) if t5 in te_dict else None
|
||||
if fn is not None and 'fp8' in t5.lower():
|
||||
from accelerate.utils import set_module_tensor_to_device
|
||||
with open(os.path.join('configs', 'flux', 'text_encoder_2', 'config.json'), encoding='utf8') as f:
|
||||
t5_config = transformers.T5Config(**json.load(f))
|
||||
@@ -35,6 +37,11 @@ def load_t5(t5=None, cache_dir=None):
|
||||
except Exception:
|
||||
shared.log.error(f"FLUX: Failed to cast text encoder to {devices.dtype}, set dtype to {t5.dtype}")
|
||||
raise
|
||||
elif fn is not None:
|
||||
with open(os.path.join('configs', 'flux', 'text_encoder_2', 'config.json'), encoding='utf8') as f:
|
||||
t5_config = transformers.T5Config(**json.load(f))
|
||||
state_dict = load_file(fn)
|
||||
t5 = transformers.T5EncoderModel.from_pretrained(None, state_dict=state_dict, config=t5_config)
|
||||
elif 'fp16' in t5.lower():
|
||||
t5 = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder='text_encoder_3', cache_dir=cache_dir, torch_dtype=devices.dtype)
|
||||
elif 'fp4' in t5.lower():
|
||||
@@ -67,11 +74,22 @@ def load_t5(t5=None, cache_dir=None):
|
||||
|
||||
|
||||
def set_t5(pipe, module, t5=None, cache_dir=None):
|
||||
global loaded_te # pylint: disable=global-statement
|
||||
if loaded_te == shared.opts.sd_text_encoder:
|
||||
return
|
||||
if pipe is None or not hasattr(pipe, module):
|
||||
return pipe
|
||||
t5 = load_t5(t5=t5, cache_dir=cache_dir)
|
||||
if module == "text_encoder_2" and t5 is None: # do not unload te2
|
||||
t5 = None
|
||||
try:
|
||||
t5 = load_t5(t5=t5, cache_dir=cache_dir)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Load module: type={module} class="T5" file="{shared.opts.sd_text_encoder}" {e}')
|
||||
if debug:
|
||||
errors.display(e, 'TE:')
|
||||
t5 = None
|
||||
if t5 is None:
|
||||
return None
|
||||
loaded_te = shared.opts.sd_text_encoder
|
||||
setattr(pipe, module, t5)
|
||||
if shared.opts.diffusers_offload_mode == "sequential":
|
||||
from accelerate import cpu_offload
|
||||
@@ -86,9 +104,48 @@ def set_t5(pipe, module, t5=None, cache_dir=None):
|
||||
return pipe
|
||||
|
||||
|
||||
def refresh_t5_list():
|
||||
t5_dict.clear()
|
||||
for file in files_cache.list_files(shared.opts.t5_dir, ext_filter=[".safetensors"]):
|
||||
def set_te(pipe):
|
||||
global loaded_te # pylint: disable=global-statement
|
||||
if loaded_te == shared.opts.sd_text_encoder:
|
||||
return
|
||||
from modules.sd_models import move_model
|
||||
if 'vit-l' in shared.opts.sd_text_encoder.lower() and hasattr(shared.sd_model, 'text_encoder') and shared.sd_model.text_encoder.__class__.__name__ == 'CLIPTextModel':
|
||||
try:
|
||||
config = transformers.PretrainedConfig.from_json_file('configs/sdxl/text_encoder/config.json')
|
||||
state_dict = load_file(os.path.join(shared.opts.te_dir, f'{shared.opts.sd_text_encoder}.safetensors'))
|
||||
te = transformers.CLIPTextModel.from_pretrained(pretrained_model_name_or_path=None, state_dict=state_dict, config=config)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Load module: type="text_encoder" class="ViT-L" file="{shared.opts.sd_text_encoder}" {e}')
|
||||
if debug:
|
||||
errors.display(e, 'TE:')
|
||||
state_dict = None
|
||||
te = None
|
||||
if te is not None:
|
||||
loaded_te = shared.opts.sd_text_encoder
|
||||
pipe.text_encoder = te.to(dtype=devices.dtype)
|
||||
shared.log.info(f'Load module: type="text_encoder" class="ViT-L" file="{shared.opts.sd_text_encoder}"')
|
||||
move_model(pipe.text_encoder, devices.device)
|
||||
if 'vit-g' in shared.opts.sd_text_encoder.lower() and hasattr(shared.sd_model, 'text_encoder_2') and shared.sd_model.text_encoder_2.__class__.__name__ == 'CLIPTextModelWithProjection':
|
||||
try:
|
||||
config = transformers.PretrainedConfig.from_json_file('configs/sdxl/text_encoder_2/config.json')
|
||||
state_dict = load_file(os.path.join(shared.opts.te_dir, f'{shared.opts.sd_text_encoder}.safetensors'))
|
||||
te = transformers.CLIPTextModelWithProjection.from_pretrained(pretrained_model_name_or_path=None, state_dict=state_dict, config=config)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Load module: type module="text_encoder_2" class="ViT-G" file="{shared.opts.sd_text_encoder}" {e}')
|
||||
if debug:
|
||||
errors.display(e, 'TE:')
|
||||
state_dict = None
|
||||
te = None
|
||||
if te is not None:
|
||||
loaded_te = shared.opts.sd_text_encoder
|
||||
pipe.text_encoder_2 = te.to(dtype=devices.dtype)
|
||||
shared.log.info(f'Load module: type="text_encoder_2" class="ViT-G" file="{shared.opts.sd_text_encoder}"')
|
||||
move_model(pipe.text_encoder_2, devices.device)
|
||||
|
||||
|
||||
def refresh_te_list():
|
||||
te_dict.clear()
|
||||
for file in files_cache.list_files(shared.opts.te_dir, ext_filter=[".safetensors"]):
|
||||
name = os.path.splitext(os.path.basename(file))[0]
|
||||
t5_dict[name] = file
|
||||
shared.log.debug(f'Available T5s: path="{shared.opts.t5_dir}" items={len(t5_dict)}')
|
||||
te_dict[name] = file
|
||||
shared.log.info(f'Available TEs: path="{shared.opts.te_dir}" items={len(te_dict)}')
|
||||
@@ -50,11 +50,11 @@ def download_civit_meta(model_path: str, model_id):
|
||||
if r.status_code == 200:
|
||||
try:
|
||||
shared.writefile(r.json(), filename=fn, mode='w', silent=True)
|
||||
msg = f'CivitAI download: id={model_id} url={url} file={fn}'
|
||||
msg = f'CivitAI download: id={model_id} url={url} file="{fn}"'
|
||||
shared.log.info(msg)
|
||||
return msg
|
||||
except Exception as e:
|
||||
msg = f'CivitAI download error: id={model_id} url={url} file={fn} {e}'
|
||||
msg = f'CivitAI download error: id={model_id} url={url} file="{fn}" {e}'
|
||||
errors.display(e, 'CivitAI download error')
|
||||
shared.log.error(msg)
|
||||
return msg
|
||||
@@ -66,7 +66,7 @@ def download_civit_preview(model_path: str, preview_url: str):
|
||||
preview_file = os.path.splitext(model_path)[0] + ext
|
||||
if os.path.exists(preview_file):
|
||||
return ''
|
||||
res = f'CivitAI download: url={preview_url} file={preview_file}'
|
||||
res = f'CivitAI download: url={preview_url} file="{preview_file}"'
|
||||
r = shared.req(preview_url, stream=True)
|
||||
total_size = int(r.headers.get('content-length', 0))
|
||||
block_size = 16384 # 16KB blocks
|
||||
@@ -88,7 +88,7 @@ def download_civit_preview(model_path: str, preview_url: str):
|
||||
except Exception as e:
|
||||
os.remove(preview_file)
|
||||
res += f' error={e}'
|
||||
shared.log.error(f'CivitAI download error: url={preview_url} file={preview_file} written={written} {e}')
|
||||
shared.log.error(f'CivitAI download error: url={preview_url} file="{preview_file}" written={written} {e}')
|
||||
shared.state.end()
|
||||
if img is None:
|
||||
return res
|
||||
@@ -281,7 +281,7 @@ def load_diffusers_models(clear=True):
|
||||
friendly = os.path.join(place, name)
|
||||
snapshots = os.listdir(os.path.join(folder, "snapshots"))
|
||||
if len(snapshots) == 0:
|
||||
shared.log.warning(f"Diffusers folder has no snapshots: location={place} folder={folder} name={name}")
|
||||
shared.log.warning(f'Diffusers folder has no snapshots: location="{place}" folder="{folder}" name="{name}"')
|
||||
continue
|
||||
for snapshot in snapshots:
|
||||
commit = os.path.join(folder, 'snapshots', snapshot)
|
||||
@@ -296,10 +296,10 @@ def load_diffusers_models(clear=True):
|
||||
if os.path.exists(os.path.join(folder, 'hidden')):
|
||||
continue
|
||||
except Exception as e:
|
||||
debug(f"Error analyzing diffusers model: {folder} {e}")
|
||||
debug(f'Error analyzing diffusers model: "{folder}" {e}')
|
||||
except Exception as e:
|
||||
shared.log.error(f"Error listing diffusers: {place} {e}")
|
||||
shared.log.debug(f'Scanning diffusers cache: folder={place} items={len(list(diffuser_repos))} time={time.time()-t0:.2f}')
|
||||
shared.log.debug(f'Scanning diffusers cache: folder="{place}" items={len(list(diffuser_repos))} time={time.time()-t0:.2f}')
|
||||
return diffuser_repos
|
||||
|
||||
|
||||
@@ -444,7 +444,7 @@ def load_file_from_url(url: str, *, model_dir: str, progress: bool = True, file_
|
||||
file_name = os.path.basename(parts.path)
|
||||
cached_file = os.path.abspath(os.path.join(model_dir, file_name))
|
||||
if not os.path.exists(cached_file):
|
||||
shared.log.info(f'Downloading: url="{url}" file={cached_file}')
|
||||
shared.log.info(f'Downloading: url="{url}" file="{cached_file}"')
|
||||
download_url_to_file(url, cached_file)
|
||||
if os.path.exists(cached_file):
|
||||
return cached_file
|
||||
@@ -577,5 +577,5 @@ def load_upscalers():
|
||||
names.append(name[8:])
|
||||
shared.sd_upscalers = sorted(datas, key=lambda x: x.name.lower() if not isinstance(x.scaler, (UpscalerNone, UpscalerLanczos, UpscalerNearest)) else "") # Special case for UpscalerNone keeps it at the beginning of the list.
|
||||
t1 = time.time()
|
||||
shared.log.debug(f"Load upscalers: total={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} time={t1-t0:.2f} {names}")
|
||||
shared.log.info(f"Available Upscalers: items={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} time={t1-t0:.2f} types={names}")
|
||||
return [x.name for x in shared.sd_upscalers]
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ def create_paths(opts):
|
||||
create_path(fix_path('diffusers_dir'))
|
||||
create_path(fix_path('vae_dir'))
|
||||
create_path(fix_path('unet_dir'))
|
||||
create_path(fix_path('t5_dir'))
|
||||
create_path(fix_path('te_dir'))
|
||||
create_path(fix_path('lora_dir'))
|
||||
create_path(fix_path('embeddings_dir'))
|
||||
create_path(fix_path('hypernetwork_dir'))
|
||||
|
||||
@@ -165,38 +165,58 @@ def encode_prompts(pipe, p, prompts: list, negative_prompts: list, steps: int, c
|
||||
return
|
||||
else:
|
||||
t0 = time.time()
|
||||
positive_schedule, scheduled = get_prompt_schedule(prompts[0], steps)
|
||||
negative_schedule, neg_scheduled = get_prompt_schedule(negative_prompts[0], steps)
|
||||
p.scheduled_prompt = scheduled or neg_scheduled
|
||||
p.prompt_embeds = []
|
||||
p.positive_pooleds = []
|
||||
p.negative_embeds = []
|
||||
p.negative_pooleds = []
|
||||
|
||||
if shared.opts.diffusers_offload_mode == "balanced":
|
||||
pipe = sd_models.apply_balanced_offload(pipe)
|
||||
elif hasattr(pipe, "maybe_free_model_hooks"):
|
||||
# if the last job is interrupted, model will stay in the vram and cause oom, send everything back to cpu before continuing
|
||||
pipe.maybe_free_model_hooks()
|
||||
devices.torch_gc()
|
||||
|
||||
for i in range(max(len(positive_schedule), len(negative_schedule))):
|
||||
positive_prompt = positive_schedule[i % len(positive_schedule)]
|
||||
negative_prompt = negative_schedule[i % len(negative_schedule)]
|
||||
if shared.opts.prompt_attention == "xhinker parser":
|
||||
prompt_embed, positive_pooled, negative_embed, negative_pooled = get_xhinker_text_embeddings(pipe, positive_prompt, negative_prompt, clip_skip)
|
||||
else:
|
||||
prompt_embed, positive_pooled, negative_embed, negative_pooled = get_weighted_text_embeddings(pipe, positive_prompt, negative_prompt, clip_skip)
|
||||
if prompt_embed is not None:
|
||||
p.prompt_embeds.append(torch.cat([prompt_embed] * len(prompts), dim=0))
|
||||
if negative_embed is not None:
|
||||
p.negative_embeds.append(torch.cat([negative_embed] * len(negative_prompts), dim=0))
|
||||
if positive_pooled is not None:
|
||||
p.positive_pooleds.append(torch.cat([positive_pooled] * len(prompts), dim=0))
|
||||
if negative_pooled is not None:
|
||||
p.negative_pooleds.append(torch.cat([negative_pooled] * len(negative_prompts), dim=0))
|
||||
prompt_embeds, positive_pooleds, negative_embeds, negative_pooleds = [], [], [], []
|
||||
last_prompt, last_negative = None, None
|
||||
for prompt, negative in zip(prompts, negative_prompts):
|
||||
prompt_embed, positive_pooled, negative_embed, negative_pooled = None, None, None, None
|
||||
if last_prompt == prompt and last_negative == negative or False:
|
||||
prompt_embeds.append(prompt_embed)
|
||||
positive_pooleds.append(positive_pooled)
|
||||
negative_embeds.append(negative_embed)
|
||||
negative_pooleds.append(negative_pooled)
|
||||
continue
|
||||
positive_schedule, scheduled = get_prompt_schedule(prompt, steps)
|
||||
negative_schedule, neg_scheduled = get_prompt_schedule(negative, steps)
|
||||
p.scheduled_prompt = scheduled or neg_scheduled
|
||||
p.prompt_embeds = []
|
||||
p.positive_pooleds = []
|
||||
p.negative_embeds = []
|
||||
p.negative_pooleds = []
|
||||
|
||||
if shared.opts.sd_textencoder_cache:
|
||||
for i in range(max(len(positive_schedule), len(negative_schedule))):
|
||||
positive_prompt = positive_schedule[i % len(positive_schedule)]
|
||||
negative_prompt = negative_schedule[i % len(negative_schedule)]
|
||||
if shared.opts.prompt_attention == "xhinker parser" or 'Flux' in pipe.__class__.__name__:
|
||||
prompt_embed, positive_pooled, negative_embed, negative_pooled = get_xhinker_text_embeddings(pipe, positive_prompt, negative_prompt, clip_skip)
|
||||
else:
|
||||
prompt_embed, positive_pooled, negative_embed, negative_pooled = get_weighted_text_embeddings(pipe, positive_prompt, negative_prompt, clip_skip)
|
||||
prompt_embeds.append(prompt_embed)
|
||||
positive_pooleds.append(positive_pooled)
|
||||
negative_embeds.append(negative_embed)
|
||||
negative_pooleds.append(negative_pooled)
|
||||
last_prompt, last_negative = prompt, negative
|
||||
|
||||
def fix_length(embeds):
|
||||
max_len = max([p.shape[1] for p in embeds])
|
||||
for i, p in enumerate(embeds):
|
||||
if p.shape[1] < max_len:
|
||||
expanded = torch.zeros((p.shape[0], max_len, p.shape[2]), device=p.device, dtype=p.dtype)
|
||||
expanded[:, :p.shape[1], :] = p
|
||||
embeds[i] = expanded
|
||||
return torch.cat(embeds, dim=0)
|
||||
|
||||
p.prompt_embeds.append(fix_length(prompt_embeds))
|
||||
p.negative_embeds.append(fix_length(negative_embeds))
|
||||
p.positive_pooleds.append(fix_length(positive_pooleds))
|
||||
p.negative_pooleds.append(fix_length(negative_pooleds))
|
||||
|
||||
if shared.opts.sd_textencoder_cache and p.batch_size == 1:
|
||||
cache.update({
|
||||
'prompt_embeds': p.prompt_embeds,
|
||||
'negative_embeds': p.negative_embeds,
|
||||
|
||||
+38
-26
@@ -161,15 +161,15 @@ def list_models():
|
||||
if shared.cmd_opts.ckpt is not None:
|
||||
if not os.path.exists(shared.cmd_opts.ckpt) and not shared.native:
|
||||
if shared.cmd_opts.ckpt.lower() != "none":
|
||||
shared.log.warning(f"Requested checkpoint not found: {shared.cmd_opts.ckpt}")
|
||||
shared.log.warning(f"Requested model not found: {shared.cmd_opts.ckpt}")
|
||||
else:
|
||||
checkpoint_info = CheckpointInfo(shared.cmd_opts.ckpt)
|
||||
if checkpoint_info.name is not None:
|
||||
checkpoint_info.register()
|
||||
shared.opts.data['sd_model_checkpoint'] = checkpoint_info.title
|
||||
elif shared.cmd_opts.ckpt != shared.default_sd_model_file and shared.cmd_opts.ckpt is not None:
|
||||
shared.log.warning(f"Checkpoint not found: {shared.cmd_opts.ckpt}")
|
||||
shared.log.info(f'Available models: path="{shared.opts.ckpt_dir}" items={len(checkpoints_list)} time={time.time()-t0:.2f}')
|
||||
shared.log.warning(f"Model not found: {shared.cmd_opts.ckpt}")
|
||||
shared.log.info(f'Available Models: path="{shared.opts.ckpt_dir}" items={len(checkpoints_list)} time={time.time()-t0:.2f}')
|
||||
checkpoints_list = dict(sorted(checkpoints_list.items(), key=lambda cp: cp[1].filename))
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ def read_metadata_from_safetensors(filename):
|
||||
metadata_len = int.from_bytes(metadata_len, "little")
|
||||
json_start = file.read(2)
|
||||
if metadata_len <= 2 or json_start not in (b'{"', b"{'"):
|
||||
shared.log.error(f"Model metadata invalid: fn={filename}")
|
||||
shared.log.error(f'Model metadata invalid: file="{filename}"')
|
||||
json_data = json_start + file.read(metadata_len-2)
|
||||
json_obj = json.loads(json_data)
|
||||
for k, v in json_obj.get("__metadata__", {}).items():
|
||||
@@ -370,7 +370,7 @@ def read_metadata_from_safetensors(filename):
|
||||
pass
|
||||
res[k] = v
|
||||
except Exception as e:
|
||||
shared.log.error(f"Model metadata: fn={filename} {e}")
|
||||
shared.log.error(f'Model metadata: file="{filename}" {e}')
|
||||
sd_metadata[filename] = res
|
||||
global sd_metadata_pending # pylint: disable=global-statement
|
||||
sd_metadata_pending += 1
|
||||
@@ -682,28 +682,28 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True):
|
||||
if hasattr(sd_model, "vae"):
|
||||
if vae is not None:
|
||||
sd_model.vae = vae
|
||||
shared.log.debug(f'Setting {op} VAE: name="{sd_vae.loaded_vae_file}"')
|
||||
shared.log.debug(f'Setting {op}: component=VAE name="{sd_vae.loaded_vae_file}"')
|
||||
if shared.opts.diffusers_vae_upcast != 'default':
|
||||
sd_model.vae.config.force_upcast = True if shared.opts.diffusers_vae_upcast == 'true' else False
|
||||
shared.log.debug(f'Setting {op} VAE: upcast={sd_model.vae.config.force_upcast}')
|
||||
shared.log.debug(f'Setting {op}: component=VAE upcast={sd_model.vae.config.force_upcast}')
|
||||
if shared.opts.no_half_vae:
|
||||
devices.dtype_vae = torch.float32
|
||||
sd_model.vae.to(devices.dtype_vae)
|
||||
shared.log.debug(f'Setting {op} VAE: no-half=True')
|
||||
shared.log.debug(f'Setting {op}: component=VAE no-half=True')
|
||||
if hasattr(sd_model, "enable_vae_slicing"):
|
||||
if shared.opts.diffusers_vae_slicing:
|
||||
shared.log.debug(f'Setting {op}: slicing=True')
|
||||
shared.log.debug(f'Setting {op}: component=VAE slicing=True')
|
||||
sd_model.enable_vae_slicing()
|
||||
else:
|
||||
sd_model.disable_vae_slicing()
|
||||
if hasattr(sd_model, "enable_vae_tiling"):
|
||||
if shared.opts.diffusers_vae_tiling:
|
||||
shared.log.debug(f'Setting {op}: tiling=True')
|
||||
shared.log.debug(f'Setting {op}: component=VAE tiling=True')
|
||||
sd_model.enable_vae_tiling()
|
||||
else:
|
||||
sd_model.disable_vae_tiling()
|
||||
if hasattr(sd_model, "vqvae"):
|
||||
shared.log.debug(f'Setting {op} VQVAE: upcast=True')
|
||||
shared.log.debug(f'Setting {op}: component=VQVAE upcast=True')
|
||||
sd_model.vqvae.to(torch.float32) # vqvae is producing nans in fp16
|
||||
|
||||
set_diffusers_attention(sd_model)
|
||||
@@ -1262,8 +1262,8 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
|
||||
return
|
||||
if shared.opts.diffusers_vae_upcast != 'default' and model_type in ['Stable Diffusion', 'Stable Diffusion XL']:
|
||||
diffusers_load_config['force_upcast'] = True if shared.opts.diffusers_vae_upcast == 'true' else False
|
||||
if debug_load:
|
||||
shared.log.debug(f'Model args: {diffusers_load_config}')
|
||||
# if debug_load:
|
||||
# shared.log.debug(f'Model args: {diffusers_load_config}')
|
||||
if sd_model is not None:
|
||||
diffusers_load_config.pop('vae', None)
|
||||
diffusers_load_config.pop('safety_checker', None)
|
||||
@@ -1311,6 +1311,12 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
|
||||
else:
|
||||
model_data.sd_model = sd_model
|
||||
|
||||
reload_text_encoder(initial=True) # must be before embeddings
|
||||
timer.record("te")
|
||||
|
||||
if debug_load:
|
||||
shared.log.trace(f'Model components: {list(get_signature(sd_model).values())}')
|
||||
|
||||
from modules.textual_inversion import textual_inversion
|
||||
sd_model.embedding_db = textual_inversion.EmbeddingDatabase()
|
||||
sd_model.embedding_db.add_embedding_dir(shared.opts.embeddings_dir)
|
||||
@@ -1337,8 +1343,6 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
|
||||
move_model(sd_model, devices.device)
|
||||
timer.record("move")
|
||||
|
||||
reload_text_encoder(initial=True)
|
||||
|
||||
if shared.opts.ipex_optimize:
|
||||
sd_model = sd_models_compile.ipex_optimize(sd_model)
|
||||
|
||||
@@ -1347,14 +1351,14 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
|
||||
timer.record("compile")
|
||||
|
||||
except Exception as e:
|
||||
shared.log.error("Failed to load diffusers model")
|
||||
errors.display(e, "loading Diffusers model")
|
||||
shared.log.error("Failed to load model")
|
||||
errors.display(e, "Model")
|
||||
|
||||
devices.torch_gc(force=True)
|
||||
if shared.cmd_opts.profile:
|
||||
errors.profile(pr, 'Load')
|
||||
script_callbacks.model_loaded_callback(sd_model)
|
||||
shared.log.info(f"Load {op}: time={timer.summary()} native={get_native(sd_model)} {memory_stats()}")
|
||||
shared.log.info(f"Load {op}: time={timer.summary()} native={get_native(sd_model)} memory={memory_stats()}")
|
||||
|
||||
|
||||
class DiffusersTaskType(Enum):
|
||||
@@ -1377,6 +1381,11 @@ def get_diffusers_task(pipe: diffusers.DiffusionPipeline) -> DiffusersTaskType:
|
||||
return DiffusersTaskType.TEXT_2_IMAGE
|
||||
|
||||
|
||||
def get_signature(cls):
|
||||
signature = inspect.signature(cls.__init__, follow_wrapped=True, eval_str=True)
|
||||
return signature.parameters
|
||||
|
||||
|
||||
def switch_pipe(cls: diffusers.DiffusionPipeline, pipeline: diffusers.DiffusionPipeline = None, args = {}):
|
||||
"""
|
||||
args:
|
||||
@@ -1393,8 +1402,8 @@ def switch_pipe(cls: diffusers.DiffusionPipeline, pipeline: diffusers.DiffusionP
|
||||
if pipeline is None:
|
||||
pipeline = shared.sd_model
|
||||
new_pipe = None
|
||||
signature = inspect.signature(cls.__init__, follow_wrapped=True, eval_str=True)
|
||||
possible = signature.parameters.keys()
|
||||
signature = get_signature(cls)
|
||||
possible = signature.keys()
|
||||
if isinstance(pipeline, cls) and args == {}:
|
||||
return pipeline
|
||||
pipe_dict = {}
|
||||
@@ -1412,10 +1421,10 @@ def switch_pipe(cls: diffusers.DiffusionPipeline, pipeline: diffusers.DiffusionP
|
||||
for item in possible:
|
||||
if item in ['self', 'args', 'kwargs']: # skip
|
||||
continue
|
||||
if signature.parameters[item].default != inspect._empty: # has default value so we dont have to worry about it # pylint: disable=protected-access
|
||||
if signature[item].default != inspect._empty: # has default value so we dont have to worry about it # pylint: disable=protected-access
|
||||
continue
|
||||
if item not in components_used:
|
||||
shared.log.warning(f'Pipeling switch: missing component={item} type={signature.parameters[item].annotation}')
|
||||
shared.log.warning(f'Pipeling switch: missing component={item} type={signature[item].annotation}')
|
||||
pipe_dict[item] = None # try but not likely to work
|
||||
components_missing.append(item)
|
||||
new_pipe = cls(**pipe_dict)
|
||||
@@ -1576,7 +1585,7 @@ def set_diffusers_attention(pipe):
|
||||
|
||||
if 'ControlNet' in pipe.__class__.__name__: # do not replace attention in ControlNet pipelines
|
||||
return
|
||||
shared.log.debug(f"Setting model: attention={shared.opts.cross_attention_optimization}")
|
||||
shared.log.debug(f'Setting model: attention="{shared.opts.cross_attention_optimization}"')
|
||||
if shared.opts.cross_attention_optimization == "Disabled":
|
||||
pass # do nothing
|
||||
elif shared.opts.cross_attention_optimization == "Scaled-Dot-Product": # The default set by Diffusers
|
||||
@@ -1716,16 +1725,19 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None,
|
||||
def reload_text_encoder(initial=False):
|
||||
if initial and (shared.opts.sd_text_encoder is None or shared.opts.sd_text_encoder == 'None'):
|
||||
return # dont unload
|
||||
signature = inspect.signature(shared.sd_model.__class__.__init__, follow_wrapped=True, eval_str=True).parameters
|
||||
signature = get_signature(shared.sd_model)
|
||||
t5 = [k for k, v in signature.items() if 'T5EncoderModel' in str(v)]
|
||||
if len(t5) > 0:
|
||||
from modules.model_t5 import set_t5
|
||||
from modules.model_te import set_t5
|
||||
shared.log.debug(f'Load: t5={shared.opts.sd_text_encoder} module="{t5[0]}"')
|
||||
set_t5(pipe=shared.sd_model, module=t5[0], t5=shared.opts.sd_text_encoder, cache_dir=shared.opts.diffusers_dir)
|
||||
elif hasattr(shared.sd_model, 'text_encoder_3'):
|
||||
from modules.model_t5 import set_t5
|
||||
from modules.model_te import set_t5
|
||||
shared.log.debug(f'Load: t5={shared.opts.sd_text_encoder} module="text_encoder_3"')
|
||||
set_t5(pipe=shared.sd_model, module='text_encoder_3', t5=shared.opts.sd_text_encoder, cache_dir=shared.opts.diffusers_dir)
|
||||
elif hasattr(shared.sd_model, 'text_encoder') and 'vit' in shared.opts.sd_text_encoder.lower():
|
||||
from modules.model_te import set_te
|
||||
set_te(pipe=shared.sd_model)
|
||||
|
||||
|
||||
def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model', force=False):
|
||||
|
||||
+2
-2
@@ -52,7 +52,7 @@ def load_unet(model):
|
||||
if not hasattr(model, 'unet') or model.unet is None:
|
||||
shared.log.error('UNet not found in current model')
|
||||
return
|
||||
shared.log.info(f'Loading UNet: name="{shared.opts.sd_unet}" file="{unet_dict[shared.opts.sd_unet]}" config="{config_file}"')
|
||||
shared.log.info(f'Load module: type=UNet name="{shared.opts.sd_unet}" file="{unet_dict[shared.opts.sd_unet]}" config="{config_file}"')
|
||||
from diffusers import UNet2DConditionModel
|
||||
from safetensors.torch import load_file
|
||||
unet = UNet2DConditionModel.from_config(model.unet.config if config is None else config).to(devices.device, devices.dtype)
|
||||
@@ -73,4 +73,4 @@ def refresh_unet_list():
|
||||
for file in files_cache.list_files(shared.opts.unet_dir, ext_filter=[".safetensors"]):
|
||||
name = os.path.splitext(os.path.basename(file))[0]
|
||||
unet_dict[name] = file
|
||||
shared.log.debug(f'Available UNets: path="{shared.opts.unet_dir}" items={len(unet_dict)}')
|
||||
shared.log.info(f'Available UNets: path="{shared.opts.unet_dir}" items={len(unet_dict)}')
|
||||
|
||||
+1
-1
@@ -210,7 +210,7 @@ def load_vae_diffusers(model_file, vae_file=None, vae_source="unknown-source"):
|
||||
vae_config = sd_models.get_load_config(model_file, model_type, config_type='json')
|
||||
if vae_config is not None:
|
||||
diffusers_load_config['config'] = os.path.join(vae_config, 'vae')
|
||||
shared.log.info(f'Load VAE: model="{vae_file}" source={vae_source} config={diffusers_load_config}')
|
||||
shared.log.info(f'Load module: type=VAE model="{vae_file}" source={vae_source} config={diffusers_load_config}')
|
||||
try:
|
||||
import diffusers
|
||||
if os.path.isfile(vae_file):
|
||||
|
||||
+11
-4
@@ -81,6 +81,14 @@ compatibility_opts = ['clip_skip', 'uni_pc_lower_order_final', 'uni_pc_order']
|
||||
console = Console(log_time=True, log_time_format='%H:%M:%S-%f')
|
||||
dir_timestamps = {}
|
||||
dir_cache = {}
|
||||
if os.environ.get("HF_HUB_CACHE", None) is not None:
|
||||
hfcache_dir = os.environ.get("HF_HUB_CACHE")
|
||||
elif os.environ.get("HF_HUB", None) is not None:
|
||||
hfcache_dir = os.path.join(os.environ.get("HF_HUB"), '.cache')
|
||||
else:
|
||||
hfcache_dir = os.path.join(os.path.expanduser('~'), '.cache', 'huggingface', 'hub')
|
||||
os.environ["HF_HUB_CACHE"] = hfcache_dir
|
||||
log.debug(f'Huggingface cache: folder="{hfcache_dir}"')
|
||||
|
||||
|
||||
class Backend(Enum):
|
||||
@@ -406,8 +414,7 @@ options_templates.update(options_section(('sd', "Execution & Models"), {
|
||||
"sd_model_refiner": OptionInfo('None', "Refiner model", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_vae": OptionInfo("Automatic", "VAE model", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list),
|
||||
"sd_unet": OptionInfo("None", "UNET model", gr.Dropdown, lambda: {"choices": shared_items.sd_unet_items()}, refresh=shared_items.refresh_unet_list),
|
||||
# "sd_text_encoder": OptionInfo('None', "Text encoder model", gr.Dropdown, lambda: {"choices": ['None', 'T5 FP4', 'T5 FP8', 'T5 INT8', 'T5 QINT8', 'T5 FP16']}),
|
||||
"sd_text_encoder": OptionInfo('None', "Text encoder model", gr.Dropdown, lambda: {"choices": shared_items.sd_t5_items()}, refresh=shared_items.refresh_t5_list),
|
||||
"sd_text_encoder": OptionInfo('None', "Text encoder model", gr.Dropdown, lambda: {"choices": shared_items.sd_te_items()}, refresh=shared_items.refresh_te_list),
|
||||
"sd_model_dict": OptionInfo('None', "Use separate base dict", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_checkpoint_autoload": OptionInfo(True, "Model autoload on start"),
|
||||
"sd_textencoder_cache": OptionInfo(True, "Cache text encoder results"),
|
||||
@@ -574,10 +581,10 @@ options_templates.update(options_section(('system-paths', "System Paths"), {
|
||||
"models_dir": OptionInfo('models', "Base path where all models are stored", folder=True),
|
||||
"ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Folder with stable diffusion models", folder=True),
|
||||
"diffusers_dir": OptionInfo(os.path.join(paths.models_path, 'Diffusers'), "Folder with Huggingface models", folder=True),
|
||||
"hfcache_dir": OptionInfo(os.path.join(os.path.expanduser('~'), '.cache', 'huggingface', 'hub'), "Folder for Huggingface cache", folder=True),
|
||||
"hfcache_dir": OptionInfo(hfcache_dir, "Folder for Huggingface cache", folder=True),
|
||||
"vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Folder with VAE files", folder=True),
|
||||
"unet_dir": OptionInfo(os.path.join(paths.models_path, 'UNET'), "Folder with UNET files", folder=True),
|
||||
"t5_dir": OptionInfo(os.path.join(paths.models_path, 'T5'), "Folder with T5 files", folder=True),
|
||||
"te_dir": OptionInfo(os.path.join(paths.models_path, 'Text-encoder'), "Folder with Text encoder files", folder=True),
|
||||
"sd_lora": OptionInfo("", "Add LoRA to prompt", gr.Textbox, {"visible": False}),
|
||||
"lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Folder with LoRA network(s)", folder=True),
|
||||
"lyco_dir": OptionInfo(os.path.join(paths.models_path, 'LyCORIS'), "Folder with LyCORIS network(s)", gr.Text, {"visible": False}),
|
||||
|
||||
@@ -23,15 +23,15 @@ def refresh_unet_list():
|
||||
modules.sd_unet.refresh_unet_list()
|
||||
|
||||
|
||||
def sd_t5_items():
|
||||
import modules.model_t5
|
||||
def sd_te_items():
|
||||
import modules.model_te
|
||||
predefined = ['None', 'T5 FP4', 'T5 FP8', 'T5 INT8', 'T5 QINT8', 'T5 FP16']
|
||||
return predefined + list(modules.model_t5.t5_dict)
|
||||
return predefined + list(modules.model_te.te_dict)
|
||||
|
||||
|
||||
def refresh_t5_list():
|
||||
import modules.model_t5
|
||||
modules.model_t5.refresh_t5_list()
|
||||
def refresh_te_list():
|
||||
import modules.model_te
|
||||
modules.model_te.refresh_te_list()
|
||||
|
||||
|
||||
def list_crossattention(diffusers=False):
|
||||
|
||||
+6
-6
@@ -175,10 +175,10 @@ class StyleDatabase:
|
||||
try:
|
||||
os.makedirs(opts.styles_dir, exist_ok=True)
|
||||
self.save_styles(opts.styles_dir, verbose=True)
|
||||
shared.log.debug(f'Migrated styles: file={legacy_file} folder={opts.styles_dir}')
|
||||
shared.log.debug(f'Migrated styles: file="{legacy_file}" folder="{opts.styles_dir}"')
|
||||
self.reload()
|
||||
except Exception as e:
|
||||
shared.log.error(f'styles failed to migrate: file={legacy_file} error={e}')
|
||||
shared.log.error(f'styles failed to migrate: file="{legacy_file}" error={e}')
|
||||
if not os.path.isdir(opts.styles_dir):
|
||||
opts.styles_dir = os.path.join(paths.models_path, "styles")
|
||||
self.path = opts.styles_dir
|
||||
@@ -216,7 +216,7 @@ class StyleDatabase:
|
||||
)
|
||||
self.styles[style["name"]] = new_style
|
||||
except Exception as e:
|
||||
shared.log.error(f'Failed to load style: file={fn} error={e}')
|
||||
shared.log.error(f'Failed to load style: file="{fn}" error={e}')
|
||||
return new_style
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ class StyleDatabase:
|
||||
|
||||
list_folder(self.path)
|
||||
t1 = time.time()
|
||||
shared.log.debug(f'Load styles: folder="{self.path}" items={len(self.styles.keys())} time={t1-t0:.2f}')
|
||||
shared.log.info(f'Available Styles: folder="{self.path}" items={len(self.styles.keys())} time={t1-t0:.2f}')
|
||||
|
||||
def find_style(self, name):
|
||||
found = [style for style in self.styles.values() if style.name == name]
|
||||
@@ -334,9 +334,9 @@ class StyleDatabase:
|
||||
with open(fn, 'w', encoding='utf-8') as f:
|
||||
json.dump(style, f, indent=2)
|
||||
if verbose:
|
||||
shared.log.debug(f'Saved style: name={name} file={fn}')
|
||||
shared.log.debug(f'Saved style: name={name} file="{fn}"')
|
||||
except Exception as e:
|
||||
shared.log.error(f'Failed to save style: name={name} file={path} error={e}')
|
||||
shared.log.error(f'Failed to save style: name={name} file="{path}" error={e}')
|
||||
count = len(list(self.styles))
|
||||
if count > 0:
|
||||
shared.log.debug(f'Saved styles: folder="{path}" items={count}')
|
||||
|
||||
@@ -287,9 +287,7 @@ class EmbeddingDatabase:
|
||||
try:
|
||||
embedding.vector_sizes = [v.shape[-1] for v in embedding.vec]
|
||||
if shared.opts.diffusers_convert_embed and 768 in hiddensizes and 1280 in hiddensizes and 1280 not in embedding.vector_sizes and 768 in embedding.vector_sizes:
|
||||
embedding.vec.append(
|
||||
convert_embedding(embedding.vec[embedding.vector_sizes.index(768)], text_encoders[hiddensizes.index(768)],
|
||||
text_encoders[hiddensizes.index(1280)]))
|
||||
embedding.vec.append(convert_embedding(embedding.vec[embedding.vector_sizes.index(768)], text_encoders[hiddensizes.index(768)], text_encoders[hiddensizes.index(1280)]))
|
||||
embedding.vector_sizes.append(1280)
|
||||
if (not all(vs in hiddensizes for vs in embedding.vector_sizes) or # Skip SD2.1 in SD1.5/SDXL/SD3 vis versa
|
||||
len(embedding.vector_sizes) > len(hiddensizes) or # Skip SDXL/SD3 in SD1.5
|
||||
@@ -311,7 +309,7 @@ class EmbeddingDatabase:
|
||||
insert_vectors(embedding, tokenizers, text_encoders, hiddensizes)
|
||||
self.register_embedding(embedding, shared.sd_model)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Embedding load: name={embedding.name} fn={embedding.filename} {e}')
|
||||
shared.log.error(f'Embedding load: name="{embedding.name}" file="{embedding.filename}" {e}')
|
||||
return
|
||||
|
||||
def load_from_file(self, path, filename):
|
||||
@@ -418,7 +416,7 @@ class EmbeddingDatabase:
|
||||
if self.previously_displayed_embeddings != displayed_embeddings:
|
||||
self.previously_displayed_embeddings = displayed_embeddings
|
||||
t1 = time.time()
|
||||
shared.log.info(f"Load embeddings: loaded={len(self.word_embeddings)} skipped={len(self.skipped_embeddings)} time={t1-t0:.2f}")
|
||||
shared.log.info(f"Load network: type=embeddings loaded={len(self.word_embeddings)} skipped={len(self.skipped_embeddings)} time={t1-t0:.2f}")
|
||||
|
||||
|
||||
def find_embedding_at_position(self, tokens, offset):
|
||||
|
||||
@@ -203,10 +203,10 @@ def open_folder(result_gallery, gallery_index = 0):
|
||||
except Exception:
|
||||
folder = shared.opts.outdir_samples
|
||||
if not os.path.exists(folder):
|
||||
shared.log.warning(f'Folder open: folder={folder} does not exist')
|
||||
shared.log.warning(f'Folder open: folder="{folder}" does not exist')
|
||||
return
|
||||
elif not os.path.isdir(folder):
|
||||
shared.log.warning(f"Folder open: folder={folder} not a folder")
|
||||
shared.log.warning(f'Folder open: folder="{folder}" not a folder')
|
||||
return
|
||||
|
||||
if not shared.cmd_opts.hide_ui_dir_config:
|
||||
|
||||
@@ -37,7 +37,7 @@ def list_extensions():
|
||||
fn = os.path.join(paths.script_path, "html", "extensions.json")
|
||||
extensions_list = shared.readfile(fn, silent=True) or []
|
||||
if type(extensions_list) != list:
|
||||
shared.log.warning(f'Invalid extensions list: file={fn}')
|
||||
shared.log.warning(f'Invalid extensions list: file="{fn}"')
|
||||
extensions_list = []
|
||||
if len(extensions_list) == 0:
|
||||
shared.log.info('Extension list is empty: refresh required')
|
||||
|
||||
@@ -64,7 +64,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
|
||||
record["info"] = self.find_info(checkpoint.filename)
|
||||
record["description"] = self.find_description(checkpoint.filename, record["info"])
|
||||
except Exception as e:
|
||||
shared.log.debug(f"Networks error: type=model file={name} {e}")
|
||||
shared.log.debug(f'Networks error: type=model file="{name}" {e}')
|
||||
return record
|
||||
|
||||
def list_items(self):
|
||||
|
||||
@@ -27,7 +27,7 @@ class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage):
|
||||
"size": os.path.getsize(path),
|
||||
}
|
||||
except Exception as e:
|
||||
shared.log.debug(f"Networks error: type=hypernetwork file={path} {e}")
|
||||
shared.log.debug(f'Networks error: type=hypernetwork file="{path}" {e}')
|
||||
|
||||
def allowed_directories_for_previews(self):
|
||||
return [shared.opts.hypernetwork_dir]
|
||||
|
||||
@@ -93,7 +93,7 @@ class ExtraNetworksPageStyles(ui_extra_networks.ExtraNetworksPage):
|
||||
"size": os.path.getsize(style.filename),
|
||||
}
|
||||
except Exception as e:
|
||||
shared.log.debug(f"Networks error: type=style file={k} {e}")
|
||||
shared.log.debug(f'Networks error: type=style file="{k}" {e}')
|
||||
return item
|
||||
|
||||
def list_items(self):
|
||||
|
||||
@@ -37,7 +37,7 @@ class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
|
||||
record["info"] = self.find_info(embedding.filename)
|
||||
record["description"] = self.find_description(embedding.filename, record["info"])
|
||||
except Exception as e:
|
||||
shared.log.debug(f"Networks error: type=embedding file={embedding.filename} {e}")
|
||||
shared.log.debug(f'Networks error: type=embedding file="{embedding.filename}" {e}')
|
||||
return record
|
||||
|
||||
def list_items(self):
|
||||
|
||||
@@ -31,7 +31,7 @@ class ExtraNetworksPageVAEs(ui_extra_networks.ExtraNetworksPage):
|
||||
record["description"] = self.find_description(filename, record["info"])
|
||||
yield record
|
||||
except Exception as e:
|
||||
shared.log.debug(f"Networks error: type=vae file={filename} {e}")
|
||||
shared.log.debug(f'Networks error: type=vae file="{filename}" {e}')
|
||||
|
||||
def allowed_directories_for_previews(self):
|
||||
return [v for v in [shared.opts.vae_dir] if v is not None]
|
||||
|
||||
@@ -25,6 +25,8 @@ voluptuous
|
||||
yapf
|
||||
fasteners
|
||||
orjson
|
||||
ruff
|
||||
pylint
|
||||
invisible-watermark
|
||||
pi-heif
|
||||
safetensors==0.4.5
|
||||
|
||||
@@ -51,7 +51,7 @@ class Script(scripts.Script):
|
||||
shared.sd_model.unet.load_state_dict(load_file(hf_hub_download(repo_id=repo, subfolder=models[model], filename="diffusion_pytorch_model.safetensors")), strict=False)
|
||||
sd_models.move_model(shared.sd_model, devices.device) # move pipeline to device
|
||||
sd_models.set_diffuser_options(shared.sd_model, vae=None, op='model')
|
||||
shared.log.debug(f'ResAdapter: pipeline={shared.sd_model.__class__.__name__} model="{model}" weight={weight} fn={models[model]}')
|
||||
shared.log.debug(f'ResAdapter: pipeline={shared.sd_model.__class__.__name__} model="{model}" weight={weight} file="{models[model]}"')
|
||||
processed = processing.process_images(p)
|
||||
shared.sd_model = old_pipe
|
||||
return processed
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from scripts.xyz_grid_shared import apply_field, apply_task_args, apply_setting, apply_prompt, apply_order, apply_sampler, apply_hr_sampler_name, confirm_samplers, apply_checkpoint, apply_refiner, apply_unet, apply_dict, apply_clip_skip, apply_vae, list_lora, apply_lora, apply_te, apply_styles, apply_upscaler, apply_context, apply_face_restore, apply_override, apply_processing, format_value_add_label, format_value, format_value_join_list, do_nothing, format_nothing, str_permutations # pylint: disable=no-name-in-module
|
||||
from modules import shared, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet
|
||||
from modules import shared, shared_items, sd_samplers, ipadapter, sd_models, sd_vae, sd_unet
|
||||
|
||||
|
||||
class AxisOption:
|
||||
@@ -86,7 +86,7 @@ axis_options = [
|
||||
AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: ['None'] + list(sd_vae.vae_dict)),
|
||||
AxisOption("LoRA", str, apply_lora, cost=0.5, choices=list_lora),
|
||||
AxisOption("LoRA strength", float, apply_setting('extra_networks_default_multiplier')),
|
||||
AxisOption("Text encoder", str, apply_te, cost=0.7, choices=lambda: ['None', 'T5 FP4', 'T5 FP8', 'T5 FP16']),
|
||||
AxisOption("Text encoder", str, apply_te, cost=0.7, choices=shared_items.sd_te_items),
|
||||
AxisOption("Styles", str, apply_styles, choices=lambda: [s.name for s in shared.prompt_styles.styles.values()]),
|
||||
AxisOption("Seed", int, apply_field("seed")),
|
||||
AxisOption("Steps", int, apply_field("steps")),
|
||||
|
||||
@@ -24,7 +24,7 @@ import modules.scripts
|
||||
import modules.sd_models
|
||||
import modules.sd_vae
|
||||
import modules.sd_unet
|
||||
import modules.model_t5
|
||||
import modules.model_te
|
||||
import modules.progress
|
||||
import modules.ui
|
||||
import modules.txt2img
|
||||
@@ -91,7 +91,7 @@ def initialize():
|
||||
modules.sd_unet.refresh_unet_list()
|
||||
timer.startup.record("unet")
|
||||
|
||||
modules.model_t5.refresh_t5_list()
|
||||
modules.model_te.refresh_te_list()
|
||||
timer.startup.record("unet")
|
||||
|
||||
extensions.list_extensions()
|
||||
|
||||
Reference in New Issue
Block a user