Merge pull request #3671 from vladmandic/dev

merge dev to master
This commit is contained in:
Vladimir Mandic
2024-12-31 12:29:18 -05:00
committed by GitHub
84 changed files with 100004 additions and 609 deletions
+1
View File
@@ -31,6 +31,7 @@ ignore-paths=/usr/lib/.*$,
modules/rife,
modules/schedulers,
modules/taesd,
modules/teacache,
modules/todo,
modules/unipc,
modules/xadapter,
+1
View File
@@ -26,6 +26,7 @@ exclude = [
"modules/schedulers",
"modules/segmoe",
"modules/taesd",
"modules/teacache",
"modules/todo",
"modules/unipc",
"modules/xadapter",
+57
View File
@@ -1,5 +1,62 @@
# Change Log for SD.Next
## Update for 2024-12-31
NYE refresh release with quite a few optimizatios and bug fixes...
- **LoRA**:
- **Sana** support
- quantized models support
- fuse support with on-demand apply/unapply
- add legacy option in *settings -> networks*
- **HunyuanVideo**:
- optimizations: full offload, quantization and tiling support
- **LTXVideo**:
- optimizations: full offload, quantization and tiling support
- [TeaCache](https://github.com/ali-vilab/TeaCache/blob/main/TeaCache4LTX-Video/README.md) integration
- **VAE**:
- tiling granular options in *settings -> variable auto encoder*
- **UI**:
- live preview optimizations and error handling
- live preview high quality output, thanks @Disty0
- CSS optimizations when log view is disabled
- **Samplers**:
- add flow shift options and separate dynamic thresholding from dynamic shifting
- autodetect matching sigma capabilities
- **API**:
- better default values for generate
- **Refactor**:
- remove all LDM imports if running in native mode
- startup optimizatios
- **Torch**:
- support for `torch==2.6.0`
- **OpenVINO**:
- disable re-compile on resolution change
- fix shape mismatch on resolution change
- **LoRA**:
- LoRA load/apply/unapply methods have been changed in 12/2024 Xmass release and further tuned in this release
- for details on available methods, see <https://github.com/vladmandic/automatic/wiki/Lora#lora-loader>
- **Fixes**:
- flux pipeline switches: txt/img/inpaint
- flux custom unet loader for bnb
- flux do not requantize already quantized model
- interrogate caption with T5
- on-the-fly quantization using TorchAO
- remove concurrent preview requests
- xyz grid recover on error
- hires batch
- sdxl refiner
- increase progress timeout
- kandinsky matmul
- do not show disabled networks
- enable debug logging by default
- image width/height calculation when doing img2img
- corrections with batch processing
- hires with refiner prompt and batch processing
- processing with nested calls
- ui networks initial sort
- esrgan on cpu devices
## Update for 2024-12-24
### Highlights for 2024-12-24
+249
View File
@@ -0,0 +1,249 @@
from typing import Union
import os
import re
import logging
from tqdm.rich import tqdm
import torch
import PIL
import faiss
import numpy as np
import pandas as pd
import transformers
class ImageDB:
# TODO index: quantize and train faiss index
# TODO index: clip batch processing
def __init__(self,
name:str='db',
fmt:str='json',
cache_dir:str=None,
dtype:torch.dtype=torch.float16,
device:torch.device=torch.device('cpu'),
model:str='openai/clip-vit-large-patch14', # 'facebook/dinov2-small'
debug:bool=False,
pbar:bool=True,
):
self.format = fmt
self.name = name
self.cache_dir = cache_dir
self.processor: transformers.AutoImageProcessor = None
self.model: transformers.AutoModel = None
self.tokenizer = transformers.AutoTokenizer = None
self.device: torch.device = device
self.dtype: torch.dtype = dtype
self.dimension = 768 if 'clip' in model else 384
self.debug = debug
self.pbar = pbar
self.repo = model
self.df = pd.DataFrame([], columns=['filename', 'timestamp', 'metadata']) # image/metadata database
self.index = faiss.IndexFlatL2(self.dimension) # embed database
self.log = logging.getLogger(__name__)
self.err = logging.getLogger(__name__).error
self.log = logging.getLogger(__name__).info if self.debug else logging.getLogger(__name__).debug
# self.init()
# self.load()
def __str__(self):
return f'db: name="{self.name}" format={self.format} device={self.device} dtype={self.dtype} dimension={self.dimension} model="{self.repo}" records={len(self.df)} index={self.index.ntotal}'
def init(self): # initialize models
if self.processor is None or self.model is None:
if 'clip' in self.repo:
self.processor = transformers.CLIPImageProcessor.from_pretrained(self.repo, cache_dir=self.cache_dir)
self.tokenizer = transformers.CLIPTokenizer.from_pretrained(self.repo, cache_dir=self.cache_dir)
self.model = transformers.CLIPModel.from_pretrained(self.repo, cache_dir=self.cache_dir).to(device=self.device, dtype=self.dtype)
elif 'dino' in self.repo:
self.processor = transformers.AutoImageProcessor.from_pretrained(self.repo, cache_dir=self.cache_dir)
self.model = transformers.AutoModel.from_pretrained(self.repo, cache_dir=self.cache_dir).to(device=self.device, dtype=self.dtype)
else:
self.err(f'db: model="{self.repo}" unknown')
self.log(f'db: load model="{self.repo}" cache="{self.cache_dir}" device={self.device} dtype={self.dtype}')
def load(self): # load db to disk
if self.format == 'json' and os.path.exists(f'{self.name}.json'):
self.df = pd.read_json(f'{self.name}.json')
elif self.format == 'csv' and os.path.exists(f'{self.name}.csv'):
self.df = pd.read_csv(f'{self.name}.csv')
elif self.format == 'pickle' and os.path.exists(f'{self.name}.pkl'):
self.df = pd.read_pickle(f'{self.name}.parquet')
if os.path.exists(f'{self.name}.index'):
self.index = faiss.read_index(f'{self.name}.index')
if self.index.ntotal != len(self.df):
self.err(f'db: index={self.index.ntotal} data={len(self.df)} mismatch')
self.index = faiss.IndexFlatL2(self.dimension)
self.df = pd.DataFrame([], columns=['filename', 'timestamp', 'metadata'])
self.log(f'db: load data={len(self.df)} name={self.name} format={self.format} name={self.name}')
def save(self): # save db to disk
if self.format == 'json':
self.df.to_json(f'{self.name}.json')
elif self.format == 'csv':
self.df.to_csv(f'{self.name}.csv')
elif self.format == 'pickle':
self.df.to_pickle(f'{self.name}.pkl')
faiss.write_index(self.index, f'{self.name}.index')
self.log(f'db: save data={len(self.df)} name={self.name} format={self.format} name={self.name}')
def normalize(self, embed) -> np.ndarray: # normalize embed before using it
embed = embed.detach().float().cpu().numpy()
faiss.normalize_L2(embed)
return embed
def embedding(self, query: Union[PIL.Image.Image | str]) -> np.ndarray: # calculate embed for prompt or image
if self.processor is None or self.model is None:
self.err('db: model not loaded')
if isinstance(query, str) and os.path.exists(query):
query = PIL.Image.open(query).convert('RGB')
self.model = self.model.to(self.device)
with torch.no_grad():
if 'clip' in self.repo:
if isinstance(query, str):
processed = self.tokenizer(text=query, padding=True, return_tensors="pt").to(device=self.device)
results = self.model.get_text_features(**processed)
else:
processed = self.processor(images=query, return_tensors="pt").to(device=self.device, dtype=self.dtype)
results = self.model.get_image_features(**processed)
elif 'dino' in self.repo:
processed = self.processor(images=query, return_tensors="pt").to(device=self.device, dtype=self.dtype)
results = self.model(**processed)
results = results.last_hidden_state.mean(dim=1)
else:
self.err(f'db: model="{self.repo}" unknown')
return None
return self.normalize(results)
def add(self, embed, filename=None, metadata=None): # add embed to db
rec = pd.DataFrame([{'filename': filename, 'timestamp': pd.Timestamp.now(), 'metadata': metadata}])
if len(self.df) > 0:
self.df = pd.concat([self.df, rec], ignore_index=True)
else:
self.df = rec
self.index.add(embed)
def search(self, filename: str = None, metadata: str = None, embed: np.ndarray = None, k=10, d=1.0): # search by filename/metadata/prompt-embed/image-embed
def dct(record: pd.DataFrame, mode: str, distance: float = None):
if distance is not None:
return {'type': mode, 'filename': record[1]['filename'], 'metadata': record[1]['metadata'], 'distance': round(distance, 2)}
else:
return {'type': mode, 'filename': record[1]['filename'], 'metadata': record[1]['metadata']}
if self.index.ntotal == 0:
return
self.log(f'db: search k={k} d={d}')
if embed is not None:
distances, indexes = self.index.search(embed, k)
records = self.df.iloc[indexes[0]]
for record, distance in zip(records.iterrows(), distances[0]):
if d <= 0 or distance <= d:
yield dct(record, distance=distance, mode='embed')
if filename is not None:
records = self.df[self.df['filename'].str.contains(filename, na=False, case=False)]
for record in records.iterrows():
yield dct(record, mode='filename')
if metadata is not None:
records = self.df[self.df['metadata'].str.contains(filename, na=False, case=False)]
for record in records.iterrows():
yield dct(record, mode='metadata')
def decode(self, s: bytes): # decode byte-encoded exif metadata
remove_prefix = lambda text, prefix: text[len(prefix):] if text.startswith(prefix) else text # pylint: disable=unnecessary-lambda-assignment
for encoding in ['utf-8', 'utf-16', 'ascii', 'latin_1', 'cp1252', 'cp437']: # try different encodings
try:
s = remove_prefix(s, b'UNICODE')
s = remove_prefix(s, b'ASCII')
s = remove_prefix(s, b'\x00')
val = s.decode(encoding, errors="strict")
val = re.sub(r'[\x00-\x09\n\s\s+]', '', val).strip() # remove remaining special characters, new line breaks, and double empty spaces
if len(val) == 0: # remove empty strings
val = None
return val
except Exception:
pass
return None
def metadata(self, image: PIL.Image.Image): # get exif metadata from image
exif = image._getexif() # pylint: disable=protected-access
if exif is None:
return ''
for k, v in exif.items():
if k == 37510: # comment
return self.decode(v)
return ''
def image(self, filename: str, image=None): # add file/image to db
try:
if image is None:
image = PIL.Image.open(filename)
image.load()
embed = self.embedding(image.convert('RGB'))
metadata = self.metadata(image)
image.close()
self.add(embed, filename=filename, metadata=metadata)
except Exception as _e:
# self.err(f'db: {str(_e)}')
pass
def folder(self, folder: str): # add all files from folder to db
files = []
for root, _subdir, _files in os.walk(folder):
for f in _files:
files.append(os.path.join(root, f))
if self.pbar:
for f in tqdm(files):
self.image(filename=f)
else:
for f in files:
self.image(filename=f)
def offload(self): # offload model to cpu
if self.model is not None:
self.model = self.model.to('cpu')
if __name__ == '__main__':
import time
import argparse
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser(description = 'image-search')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--search', action='store_true', help='run search')
group.add_argument('--index', action='store_true', help='run indexing')
parser.add_argument('--db', default='db', help='database name')
parser.add_argument('--model', default='openai/clip-vit-large-patch14', help='huggingface model')
parser.add_argument('--cache', default='/mnt/models/huggingface', help='cache folder')
parser.add_argument('input', nargs='*', default=os.getcwd())
args = parser.parse_args()
db = ImageDB(
name=args.db,
model=args.model, # 'facebook/dinov2-small'
cache_dir=args.cache,
dtype=torch.bfloat16,
device=torch.device('cuda'),
debug=True,
pbar=True,
)
db.init()
db.load()
print(db)
if args.index:
t0 = time.time()
if len(args.input) > 0:
for fn in args.input:
if os.path.isfile(fn):
db.image(filename=fn)
elif os.path.isdir(fn):
db.folder(folder=fn)
t1 = time.time()
print('index', t1-t0)
db.save()
db.offload()
if args.search:
for ref in args.input:
emb = db.embedding(ref)
res = db.search(filename=ref, metadata=ref, embed=emb, k=10, d=0)
for r in res:
print(ref, r)
+35
View File
@@ -0,0 +1,35 @@
{
"_class_name": "StableDiffusionXLImg2ImgPipeline",
"_diffusers_version": "0.19.0.dev0",
"force_zeros_for_empty_prompt": false,
"add_watermarker": null,
"requires_aesthetics_score": true,
"scheduler": [
"diffusers",
"EulerDiscreteScheduler"
],
"text_encoder": [
null,
null
],
"text_encoder_2": [
"transformers",
"CLIPTextModelWithProjection"
],
"tokenizer": [
null,
null
],
"tokenizer_2": [
"transformers",
"CLIPTokenizer"
],
"unet": [
"diffusers",
"UNet2DConditionModel"
],
"vae": [
"diffusers",
"AutoencoderKL"
]
}
@@ -0,0 +1,18 @@
{
"_class_name": "EulerDiscreteScheduler",
"_diffusers_version": "0.19.0.dev0",
"beta_end": 0.012,
"beta_schedule": "scaled_linear",
"beta_start": 0.00085,
"clip_sample": false,
"interpolation_type": "linear",
"num_train_timesteps": 1000,
"prediction_type": "epsilon",
"sample_max_value": 1.0,
"set_alpha_to_one": false,
"skip_prk_steps": true,
"steps_offset": 1,
"timestep_spacing": "leading",
"trained_betas": null,
"use_karras_sigmas": false
}
@@ -0,0 +1,24 @@
{
"architectures": [
"CLIPTextModelWithProjection"
],
"attention_dropout": 0.0,
"bos_token_id": 0,
"dropout": 0.0,
"eos_token_id": 2,
"hidden_act": "gelu",
"hidden_size": 1280,
"initializer_factor": 1.0,
"initializer_range": 0.02,
"intermediate_size": 5120,
"layer_norm_eps": 1e-05,
"max_position_embeddings": 77,
"model_type": "clip_text_model",
"num_attention_heads": 20,
"num_hidden_layers": 32,
"pad_token_id": 1,
"projection_dim": 1280,
"torch_dtype": "float16",
"transformers_version": "4.32.0.dev0",
"vocab_size": 49408
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
{
"bos_token": {
"content": "<|startoftext|>",
"lstrip": false,
"normalized": true,
"rstrip": false,
"single_word": false
},
"eos_token": {
"content": "<|endoftext|>",
"lstrip": false,
"normalized": true,
"rstrip": false,
"single_word": false
},
"pad_token": "!",
"unk_token": {
"content": "<|endoftext|>",
"lstrip": false,
"normalized": true,
"rstrip": false,
"single_word": false
}
}
@@ -0,0 +1,33 @@
{
"add_prefix_space": false,
"bos_token": {
"__type": "AddedToken",
"content": "<|startoftext|>",
"lstrip": false,
"normalized": true,
"rstrip": false,
"single_word": false
},
"clean_up_tokenization_spaces": true,
"do_lower_case": true,
"eos_token": {
"__type": "AddedToken",
"content": "<|endoftext|>",
"lstrip": false,
"normalized": true,
"rstrip": false,
"single_word": false
},
"errors": "replace",
"model_max_length": 77,
"pad_token": "!",
"tokenizer_class": "CLIPTokenizer",
"unk_token": {
"__type": "AddedToken",
"content": "<|endoftext|>",
"lstrip": false,
"normalized": true,
"rstrip": false,
"single_word": false
}
}
File diff suppressed because it is too large Load Diff
+69
View File
@@ -0,0 +1,69 @@
{
"_class_name": "UNet2DConditionModel",
"_diffusers_version": "0.19.0.dev0",
"act_fn": "silu",
"addition_embed_type": "text_time",
"addition_embed_type_num_heads": 64,
"addition_time_embed_dim": 256,
"attention_head_dim": [
6,
12,
24,
24
],
"block_out_channels": [
384,
768,
1536,
1536
],
"center_input_sample": false,
"class_embed_type": null,
"class_embeddings_concat": false,
"conv_in_kernel": 3,
"conv_out_kernel": 3,
"cross_attention_dim": 1280,
"cross_attention_norm": null,
"down_block_types": [
"DownBlock2D",
"CrossAttnDownBlock2D",
"CrossAttnDownBlock2D",
"DownBlock2D"
],
"downsample_padding": 1,
"dual_cross_attention": false,
"encoder_hid_dim": null,
"encoder_hid_dim_type": null,
"flip_sin_to_cos": true,
"freq_shift": 0,
"in_channels": 4,
"layers_per_block": 2,
"mid_block_only_cross_attention": null,
"mid_block_scale_factor": 1,
"mid_block_type": "UNetMidBlock2DCrossAttn",
"norm_eps": 1e-05,
"norm_num_groups": 32,
"num_attention_heads": null,
"num_class_embeds": null,
"only_cross_attention": false,
"out_channels": 4,
"projection_class_embeddings_input_dim": 2560,
"resnet_out_scale_factor": 1.0,
"resnet_skip_time_act": false,
"resnet_time_scale_shift": "default",
"sample_size": 128,
"time_cond_proj_dim": null,
"time_embedding_act_fn": null,
"time_embedding_dim": null,
"time_embedding_type": "positional",
"timestep_post_act": null,
"transformer_layers_per_block": 4,
"up_block_types": [
"UpBlock2D",
"CrossAttnUpBlock2D",
"CrossAttnUpBlock2D",
"UpBlock2D"
],
"upcast_attention": null,
"use_linear_projection": true
}
+32
View File
@@ -0,0 +1,32 @@
{
"_class_name": "AutoencoderKL",
"_diffusers_version": "0.20.0.dev0",
"_name_or_path": "../sdxl-vae/",
"act_fn": "silu",
"block_out_channels": [
128,
256,
512,
512
],
"down_block_types": [
"DownEncoderBlock2D",
"DownEncoderBlock2D",
"DownEncoderBlock2D",
"DownEncoderBlock2D"
],
"force_upcast": true,
"in_channels": 3,
"latent_channels": 4,
"layers_per_block": 2,
"norm_num_groups": 32,
"out_channels": 3,
"sample_size": 1024,
"scaling_factor": 0.13025,
"up_block_types": [
"UpDecoderBlock2D",
"UpDecoderBlock2D",
"UpDecoderBlock2D",
"UpDecoderBlock2D"
]
}
@@ -129,7 +129,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
if len(networks.loaded_networks) > 0 and step == 0:
self.infotext(p)
self.prompt(p)
shared.log.info(f'Load network: type=LoRA apply={[n.name for n in networks.loaded_networks]} te={te_multipliers} unet={unet_multipliers} dims={dyn_dims} load={t1-t0:.2f}')
shared.log.info(f'Load network: type=LoRA apply={[n.name for n in networks.loaded_networks]} method=legacy te={te_multipliers} unet={unet_multipliers} dims={dyn_dims} load={t1-t0:.2f}')
def deactivate(self, p):
t0 = time.time()
+3 -3
View File
@@ -182,11 +182,11 @@ def load_network(name, network_on_disk) -> network.Network:
else:
net.modules[key] = net_module
if len(keys_failed_to_match) > 0:
shared.log.warning(f'LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}')
shared.log.warning(f'Load network: type=LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}')
if debug:
shared.log.debug(f'LoRA name="{name}" unmatched={keys_failed_to_match}')
shared.log.debug(f'Load network: type=LoRA name="{name}" unmatched={keys_failed_to_match}')
else:
shared.log.debug(f'LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)}')
shared.log.debug(f'Load network: type=LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)}')
if len(matched_networks) == 0:
return None
lora_cache[name] = net
@@ -57,7 +57,8 @@ def infotext_pasted(infotext, d): # pylint: disable=unused-argument
d["Prompt"] = re.sub(re_lora, network_replacement, d["Prompt"])
if not shared.native:
if shared.opts.lora_legacy:
shared.log.debug('Register network: type=LoRA method=legacy')
script_callbacks.on_app_started(api_networks)
script_callbacks.on_before_ui(before_ui)
script_callbacks.on_model_loaded(networks.assign_network_names_to_compvis_modules)
@@ -12,6 +12,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
def __init__(self):
super().__init__('Lora')
self.list_time = 0
shared.log.warning('Networks: type=lora method=legacy')
def refresh(self):
networks.list_available_networks()
+7 -1
View File
@@ -2,10 +2,16 @@
"stabilityai--stable-diffusion-3-medium-diffusers": "models/Reference/stabilityai--stable-diffusion-3.jpg",
"stabilityai--stable-diffusion-3.5-medium": "models/Reference/stabilityai--stable-diffusion-3_5.jpg",
"stabilityai--stable-diffusion-3.5-large": "models/Reference/stabilityai--stable-diffusion-3_5.jpg",
"stabilityai--stable-diffusion-3.5-large-turbo": "models/Reference/stabilityai--stable-diffusion-3_5.jpg",
"Disty0--FLUX.1-dev-qint8": "models/Reference/black-forest-labs--FLUX.1-dev.jpg",
"Disty0--FLUX.1-dev-qint4": "models/Reference/black-forest-labs--FLUX.1-dev.jpg",
"sayakpaul--flux.1-dev-nf4": "models/Reference/black-forest-labs--FLUX.1-dev.jpg",
"THUDM--CogVideoX-2b": "models/Reference/THUDM--CogView3-Plus-3B.jpg",
"THUDM--CogVideoX-5b": "models/Reference/THUDM--CogView3-Plus-3B.jpg",
"THUDM--CogVideoX-5b-I2V": "models/Reference/THUDM--CogView3-Plus-3B.jpg"
"THUDM--CogVideoX-5b-I2V": "models/Reference/THUDM--CogView3-Plus-3B.jpg",
"Efficient-Large-Model--Sana_1600M_1024px_BF16_diffusers": "models/Reference/Efficient-Large-Model--Sana_1600M_1024px_diffusers.jpg",
"Efficient-Large-Model--Sana_1600M_2Kpx_BF16_diffusers": "models/Reference/Efficient-Large-Model--Sana_1600M_1024px_diffusers.jpg",
"Efficient-Large-Model--Sana_600M_1024px_diffusers": "models/Reference/Efficient-Large-Model--Sana_1600M_1024px_diffusers.jpg",
"stabilityai--stable-video-diffusion-img2vid-xt-1-1": "models/Reference/stabilityai--stable-video-diffusion-img2vid-xt.jpg",
"shuttleai--shuttle-3-diffusion": "models/Reference/shuttleai--shuttle-3-diffusion.jpg"
}
+30 -30
View File
@@ -54,7 +54,7 @@ git_commit = "unknown"
diffusers_commit = "unknown"
extensions_commit = {
'sd-webui-controlnet': 'ecd33eb',
'adetailer': 'a89c01d'
# 'adetailer': 'a89c01d'
# 'stable-diffusion-webui-images-browser': '27fe4a7',
}
@@ -255,7 +255,7 @@ def uninstall(package, quiet = False):
@lru_cache()
def pip(arg: str, ignore: bool = False, quiet: bool = False, uv = True):
def pip(arg: str, ignore: bool = False, quiet: bool = True, uv = True):
originalArg = arg
arg = arg.replace('>=', '==')
package = arg.replace("install", "").replace("--upgrade", "").replace("--no-deps", "").replace("--force", "").replace(" ", " ").strip()
@@ -1075,6 +1075,7 @@ def set_environment():
os.environ.setdefault('TF_CPP_MIN_LOG_LEVEL', '2')
os.environ.setdefault('TF_ENABLE_ONEDNN_OPTS', '0')
os.environ.setdefault('USE_TORCH', '1')
os.environ.setdefault('TORCH_FORCE_NO_WEIGHTS_ONLY_LOAD', '1')
os.environ.setdefault('UVICORN_TIMEOUT_KEEP_ALIVE', '60')
os.environ.setdefault('KINETO_LOG_LEVEL', '3')
os.environ.setdefault('DO_NOT_TRACK', '1')
@@ -1307,44 +1308,43 @@ def check_timestamp():
def add_args(parser):
group_setup = parser.add_argument_group('Setup')
group_setup.add_argument('--reset', default = os.environ.get("SD_RESET",False), action='store_true', help = "Reset main repository to latest version, default: %(default)s")
group_setup.add_argument('--upgrade', '--update', default = os.environ.get("SD_UPGRADE",False), action='store_true', help = "Upgrade main repository to latest version, default: %(default)s")
group_setup.add_argument('--requirements', default = os.environ.get("SD_REQUIREMENTS",False), action='store_true', help = "Force re-check of requirements, default: %(default)s")
group_setup.add_argument('--reinstall', default = os.environ.get("SD_REINSTALL",False), action='store_true', help = "Force reinstallation of all requirements, default: %(default)s")
group_setup.add_argument('--optional', default = os.environ.get("SD_OPTIONAL",False), action='store_true', help = "Force installation of optional requirements, default: %(default)s")
group_setup.add_argument('--uv', default = os.environ.get("SD_UV",False), action='store_true', help = "Use uv instead of pip to install the packages")
group_setup.add_argument('--reset', default=os.environ.get("SD_RESET",False), action='store_true', help="Reset main repository to latest version, default: %(default)s")
group_setup.add_argument('--upgrade', '--update', default=os.environ.get("SD_UPGRADE",False), action='store_true', help="Upgrade main repository to latest version, default: %(default)s")
group_setup.add_argument('--requirements', default=os.environ.get("SD_REQUIREMENTS",False), action='store_true', help="Force re-check of requirements, default: %(default)s")
group_setup.add_argument('--reinstall', default=os.environ.get("SD_REINSTALL",False), action='store_true', help="Force reinstallation of all requirements, default: %(default)s")
group_setup.add_argument('--optional', default=os.environ.get("SD_OPTIONAL",False), action='store_true', help="Force installation of optional requirements, default: %(default)s")
group_setup.add_argument('--uv', default=os.environ.get("SD_UV",False), action='store_true', help="Use uv instead of pip to install the packages")
group_startup = parser.add_argument_group('Startup')
group_startup.add_argument('--quick', default = os.environ.get("SD_QUICK",False), action='store_true', help = "Bypass version checks, default: %(default)s")
group_startup.add_argument('--skip-requirements', default = os.environ.get("SD_SKIPREQUIREMENTS",False), action='store_true', help = "Skips checking and installing requirements, default: %(default)s")
group_startup.add_argument('--skip-extensions', default = os.environ.get("SD_SKIPEXTENSION",False), action='store_true', help = "Skips running individual extension installers, default: %(default)s")
group_startup.add_argument('--skip-git', default = os.environ.get("SD_SKIPGIT",False), action='store_true', help = "Skips running all GIT operations, default: %(default)s")
group_startup.add_argument('--skip-torch', default = os.environ.get("SD_SKIPTORCH",False), action='store_true', help = "Skips running Torch checks, default: %(default)s")
group_startup.add_argument('--skip-all', default = os.environ.get("SD_SKIPALL",False), action='store_true', help = "Skips running all checks, default: %(default)s")
group_startup.add_argument('--skip-env', default = os.environ.get("SD_SKIPENV",False), action='store_true', help = "Skips setting of env variables during startup, default: %(default)s")
group_startup.add_argument('--quick', default=os.environ.get("SD_QUICK",False), action='store_true', help="Bypass version checks, default: %(default)s")
group_startup.add_argument('--skip-requirements', default=os.environ.get("SD_SKIPREQUIREMENTS",False), action='store_true', help="Skips checking and installing requirements, default: %(default)s")
group_startup.add_argument('--skip-extensions', default=os.environ.get("SD_SKIPEXTENSION",False), action='store_true', help="Skips running individual extension installers, default: %(default)s")
group_startup.add_argument('--skip-git', default=os.environ.get("SD_SKIPGIT",False), action='store_true', help="Skips running all GIT operations, default: %(default)s")
group_startup.add_argument('--skip-torch', default=os.environ.get("SD_SKIPTORCH",False), action='store_true', help="Skips running Torch checks, default: %(default)s")
group_startup.add_argument('--skip-all', default=os.environ.get("SD_SKIPALL",False), action='store_true', help="Skips running all checks, default: %(default)s")
group_startup.add_argument('--skip-env', default=os.environ.get("SD_SKIPENV",False), action='store_true', help="Skips setting of env variables during startup, default: %(default)s")
group_compute = parser.add_argument_group('Compute Engine')
group_compute.add_argument('--use-directml', default = os.environ.get("SD_USEDIRECTML",False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s")
group_compute.add_argument("--use-openvino", default = os.environ.get("SD_USEOPENVINO",False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group_compute.add_argument("--use-ipex", default = os.environ.get("SD_USEIPEX",False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group_compute.add_argument("--use-cuda", default = os.environ.get("SD_USECUDA",False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group_compute.add_argument("--use-rocm", default = os.environ.get("SD_USEROCM",False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group_compute.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s")
group_compute.add_argument("--use-xformers", default = os.environ.get("SD_USEXFORMERS",False), action='store_true', help="Force use xFormers cross-optimization, default: %(default)s")
group_compute.add_argument('--use-directml', default=os.environ.get("SD_USEDIRECTML",False), action='store_true', help="Use DirectML if no compatible GPU is detected, default: %(default)s")
group_compute.add_argument("--use-openvino", default=os.environ.get("SD_USEOPENVINO",False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group_compute.add_argument("--use-ipex", default=os.environ.get("SD_USEIPEX",False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group_compute.add_argument("--use-cuda", default=os.environ.get("SD_USECUDA",False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group_compute.add_argument("--use-rocm", default=os.environ.get("SD_USEROCM",False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group_compute.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help="Force use ZLUDA, AMD GPUs only, default: %(default)s")
group_compute.add_argument("--use-xformers", default=os.environ.get("SD_USEXFORMERS",False), action='store_true', help="Force use xFormers cross-optimization, default: %(default)s")
group_diag = parser.add_argument_group('Diagnostics')
group_diag.add_argument('--safe', default = os.environ.get("SD_SAFE",False), action='store_true', help = "Run in safe mode with no user extensions")
group_diag.add_argument('--experimental', default = os.environ.get("SD_EXPERIMENTAL",False), action='store_true', help = "Allow unsupported versions of libraries, default: %(default)s")
group_diag.add_argument('--test', default = os.environ.get("SD_TEST",False), action='store_true', help = "Run test only and exit")
group_diag.add_argument('--version', default = False, action='store_true', help = "Print version information")
group_diag.add_argument('--ignore', default = os.environ.get("SD_IGNORE",False), action='store_true', help = "Ignore any errors and attempt to continue")
group_diag.add_argument('--safe', default=os.environ.get("SD_SAFE",False), action='store_true', help="Run in safe mode with no user extensions")
group_diag.add_argument('--experimental', default=os.environ.get("SD_EXPERIMENTAL",False), action='store_true', help="Allow unsupported versions of libraries, default: %(default)s")
group_diag.add_argument('--test', default=os.environ.get("SD_TEST",False), action='store_true', help="Run test only and exit")
group_diag.add_argument('--version', default=False, action='store_true', help="Print version information")
group_diag.add_argument('--ignore', default=os.environ.get("SD_IGNORE",False), action='store_true', help="Ignore any errors and attempt to continue")
group_log = parser.add_argument_group('Logging')
group_log.add_argument("--log", type=str, default=os.environ.get("SD_LOG", None), help="Set log file, default: %(default)s")
group_log.add_argument('--debug', default = os.environ.get("SD_DEBUG",False), action='store_true', help = "Run installer with debug logging, default: %(default)s")
# group_log.add_argument('--debug', default=os.environ.get("SD_DEBUG",False), action='store_true', help="Run installer with debug logging, default: %(default)s")
group_log.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s")
group_log.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help = "Mount API docs, default: %(default)s")
group_log.add_argument("--api-log", default=os.environ.get("SD_APILOG", False), action='store_true', help="Enable logging of all API requests, default: %(default)s")
group_log.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help="Mount API docs, default: %(default)s")
def parse_args(parser):
+13 -7
View File
@@ -1,5 +1,6 @@
const activePromptTextarea = {};
let sortVal = -1;
let totalCards = -1;
// helpers
@@ -226,8 +227,8 @@ function sortExtraNetworks(fixed = 'no') {
if (fixed !== 'fixed') sortVal = (sortVal + 1) % sortDesc.length;
for (const pg of pages) {
const cards = Array.from(pg.querySelectorAll('.card') || []);
num = cards.length;
if (num === 0) return 'sort: no cards';
if (cards.length === 0) return 'sort: no cards';
num += cards.length;
cards.sort((a, b) => { // eslint-disable-line no-loop-func
switch (sortVal) {
case 0: return 0;
@@ -243,12 +244,12 @@ function sortExtraNetworks(fixed = 'no') {
for (const card of cards) pg.appendChild(card);
}
const desc = sortDesc[sortVal];
log('sortExtraNetworks', { name: pagename, val: sortVal, order: desc, fixed: fixed === 'fixed', items: num });
log('sortNetworks', { name: pagename, val: sortVal, order: desc, fixed: fixed === 'fixed', items: num });
return desc;
}
function refreshENInput(tabname) {
log('refreshExtraNetworks', tabname, gradioApp().querySelector(`#${tabname}_extra_networks textarea`)?.value);
log('refreshNetworks', tabname, gradioApp().querySelector(`#${tabname}_extra_networks textarea`)?.value);
gradioApp().querySelector(`#${tabname}_extra_networks textarea`)?.dispatchEvent(new Event('input'));
}
@@ -440,7 +441,8 @@ function setupExtraNetworksForTab(tabname) {
for (const el of Array.from(gradioApp().getElementById(`${tabname}_extra_tabs`).querySelectorAll('.extra-networks-page'))) {
const h = Math.trunc(entry.contentRect.height);
if (h <= 0) return;
if (window.opts.extra_networks_card_cover === 'sidebar' && window.opts.theme_type === 'Standard') el.style.height = `max(55vh, ${h - 90}px)`;
const vh = opts.logmonitor_show ? '55vh' : '68vh';
if (window.opts.extra_networks_card_cover === 'sidebar' && window.opts.theme_type === 'Standard') el.style.height = `max(${vh}, ${h - 90}px)`;
// log(`${tabname} height: ${entry.target.id}=${h} ${el.id}=${el.clientHeight}`);
}
}
@@ -466,11 +468,15 @@ function setupExtraNetworksForTab(tabname) {
el.parentElement.style.width = '-webkit-fill-available';
}
}
const cards = Array.from(gradioApp().querySelectorAll('.extra-network-cards > .card'));
if (cards.length > 0 && cards.length !== totalCards) {
totalCards = cards.length;
sortExtraNetworks('fixed');
}
if (lastView !== entries[0].intersectionRatio > 0) {
lastView = entries[0].intersectionRatio > 0;
if (lastView) {
refreshENpage();
// sortExtraNetworks('fixed');
if (window.opts.extra_networks_card_cover === 'cover') {
en.style.position = 'absolute';
en.style.height = 'unset';
@@ -535,5 +541,5 @@ async function setupExtraNetworks() {
registerPrompt('img2img', 'img2img_neg_prompt');
registerPrompt('control', 'control_prompt');
registerPrompt('control', 'control_neg_prompt');
log('initExtraNetworks');
log('initNetworks');
}
+1
View File
@@ -396,6 +396,7 @@ async function initGallery() { // triggered on gradio change to monitor when ui
el.search = gradioApp().querySelector('#tab-gallery-search textarea');
el.search.addEventListener('input', gallerySearch);
el.btnSend = gradioApp().getElementById('tab-gallery-send-image');
document.getElementById('tab-gallery-files').style.height = opts.logmonitor_show ? '75vh' : '85vh';
const intersectionObserver = new IntersectionObserver((entries) => {
if (entries[0].intersectionRatio <= 0) galleryHidden();
+8 -1
View File
@@ -44,10 +44,17 @@ async function logMonitor() {
if (modenUIBtn) modenUIBtn.setAttribute('error-count', logErrors > 0 ? logErrors : '');
};
document.getElementById('txt2img_gallery').style.height = opts.logmonitor_show ? '50vh' : '55vh';
document.getElementById('img2img_gallery').style.height = opts.logmonitor_show ? '50vh' : '55vh';
if (!opts.logmonitor_show) {
Array.from(document.getElementsByClassName('log-monitor')).forEach((el) => el.style.display = 'none');
return;
}
if (logMonitorStatus) setTimeout(logMonitor, opts.logmonitor_refresh_period);
else setTimeout(logMonitor, 10 * 1000); // on failure try to reconnect every 10sec
if (!opts.logmonitor_show) return;
logMonitorStatus = false;
if (!logMonitorEl) {
logMonitorEl = document.getElementById('logMonitorData');
+12 -6
View File
@@ -61,8 +61,8 @@ function randomId() {
function requestProgress(id_task, progressEl, galleryEl, atEnd = null, onProgress = null, once = false) {
localStorage.setItem('task', id_task);
let hasStarted = false;
const dateStart = new Date();
const prevProgress = null;
let dateStart = new Date();
let prevProgress = null;
const parentGallery = galleryEl ? galleryEl.parentNode : null;
let livePreview;
let img;
@@ -113,30 +113,36 @@ function requestProgress(id_task, progressEl, galleryEl, atEnd = null, onProgres
if (!opts.live_previews_enable || opts.live_preview_refresh_period === 0 || opts.show_progress_every_n_steps === 0) return;
const onProgressHandler = (res) => {
// debug('onProgress', res);
if (res?.debug) debug('livePreview:', dateStart, res);
lastState = res;
const elapsedFromStart = (new Date() - dateStart) / 1000;
hasStarted |= res.active;
if (res.completed || (!res.active && (hasStarted || once)) || (elapsedFromStart > 30 && !res.queued && res.progress === prevProgress)) {
debug('onProgressEnd', res);
if (res?.debug) debug('livePreview end:', res);
done();
return;
}
if (res.progress !== prevProgress) {
dateStart = new Date();
prevProgress = res.progress;
}
setProgress(res);
if (res.live_preview && !livePreview) initLivePreview();
if (res.live_preview && galleryEl) {
if (img.src !== res.live_preview) img.src = res.live_preview;
id_live_preview = res.id_live_preview;
}
if (onProgress) onProgress(res);
setTimeout(() => start(id_task, id_live_preview), opts.live_preview_refresh_period || 500);
};
const onProgressErrorHandler = (err) => {
error(`onProgressError: ${err}`);
error(`livePreview: ${err}`);
done();
};
xhrPost('./internal/progress', { id_task, id_live_preview }, onProgressHandler, onProgressErrorHandler, false, 5000);
xhrPost('./internal/progress', { id_task, id_live_preview }, onProgressHandler, onProgressErrorHandler, false, 30000);
};
debug('livePreview start:', dateStart);
start(id_task, 0);
}
+3 -2
View File
@@ -170,7 +170,7 @@ div#extras_scale_to_tab div.form { flex-direction: row; }
.dark .progressDiv { background: #424c5b; }
.progressDiv .progress { width: 0%; height: 20px; background: #0060df; color: white; font-weight: bold; line-height: 20px; padding: 0 8px 0 0; text-align: right; overflow: visible; white-space: nowrap; padding: 0 0.5em; }
.livePreview { position: absolute; z-index: 50; width: -moz-available; width: -webkit-fill-available; height: 100%; background-color: var(--background-color); }
.livePreview img { object-fit: contain; width: 100%; justify-self: center; }
.livePreview img { object-fit: contain; width: 100%; justify-self: center; max-height: calc(100vh - 320px); }
.popup-metadata { color: white; background: #0000; display: inline-block; white-space: pre-wrap; font-size: var(--text-xxs); }
.generating { animation: unset !important; border: unset !important; }
/* fullpage image viewer */
@@ -220,6 +220,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
.extra-networks .second-line { display: flex; width: -moz-available; width: -webkit-fill-available; gap: 0.3em; box-shadow: var(--input-shadow); margin-bottom: 2px; }
.extra-networks .search { flex: 1; height: 4em; }
.extra-networks .description { flex: 3; }
.extra-networks .description textarea { font-size: 0.8rem; }
.extra-networks .tab-nav>button { margin-right: 0; height: 24px; padding: 2px 4px 2px 4px; }
.extra-networks .buttons { position: absolute; right: 0; margin: -4px; background: var(--background-color); }
.extra-networks .buttons>button { margin-left: -0.2em; height: 1.4em; color: var(--primary-300) !important; font-size: 20px !important; }
@@ -323,7 +324,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
div:has(>#tab-gallery-folders) { flex-grow: 0 !important; background-color: var(--input-background-fill); min-width: max-content !important; }
.gallery-separator { background-color: var(--input-background-fill); font-size: larger; padding: 0.5em; display: block !important; }
#html_log_gallery { font-size: 0.95em; }
#gallery_gallery { height: 60vh; }
#gallery_gallery { height: 63vh; }
#gallery_gallery .thumbnails { display: none; }
#gallery_gallery .preview { background: none; }
#gallery_gallery img { object-fit: contain; height: 100% !important; }
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

+17 -15
View File
@@ -17,6 +17,15 @@ def main_args():
group_config.add_argument("--lowvram", default=os.environ.get("SD_LOWVRAM", False), action='store_true', help="Split model components and keep only active part in VRAM, default: %(default)s")
group_config.add_argument("--freeze", default=os.environ.get("SD_FREEZE", False), action='store_true', help="Disable editing settings")
group_compute = parser.add_argument_group('Compute Engine')
group_compute.add_argument("--device-id", type=str, default=os.environ.get("SD_DEVICEID", None), help="Select the default CUDA device to use, default: %(default)s")
group_compute.add_argument('--use-directml', default=os.environ.get("SD_USEDIRECTML", False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s")
group_compute.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s")
group_compute.add_argument("--use-openvino", default=os.environ.get("SD_USEOPENVINO", False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group_compute.add_argument("--use-ipex", default=os.environ.get("SD_USEIPX", False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group_compute.add_argument("--use-cuda", default=os.environ.get("SD_USECUDA", False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group_compute.add_argument("--use-rocm", default=os.environ.get("SD_USEROCM", False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group_paths = parser.add_argument_group('Paths')
group_paths.add_argument("--ckpt", type=str, default=os.environ.get("SD_MODEL", None), help="Path to model checkpoint to load immediately, default: %(default)s")
group_paths.add_argument("--data-dir", type=str, default=os.environ.get("SD_DATADIR", ''), help="Base path where all user data is stored, default: %(default)s")
@@ -26,17 +35,6 @@ def main_args():
group_diag.add_argument("--no-hashing", default=os.environ.get("SD_NOHASHING", False), action='store_true', help="Disable hashing of checkpoints, default: %(default)s")
group_diag.add_argument("--no-metadata", default=os.environ.get("SD_NOMETADATA", False), action='store_true', help="Disable reading of metadata from models, default: %(default)s")
group_diag.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s")
group_diag.add_argument("--disable-queue", default=os.environ.get("SD_DISABLEQUEUE", False), action='store_true', help="Disable queues, default: %(default)s")
group_diag.add_argument('--debug', default=os.environ.get("SD_DEBUG", False), action='store_true', help = "Run installer with debug logging, default: %(default)s")
group_compute = parser.add_argument_group('Compute Engine')
group_compute.add_argument('--use-directml', default=os.environ.get("SD_USEDIRECTML", False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s")
group_compute.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s")
group_compute.add_argument("--use-openvino", default=os.environ.get("SD_USEOPENVINO", False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s")
group_compute.add_argument("--use-ipex", default=os.environ.get("SD_USEIPX", False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s")
group_compute.add_argument("--use-cuda", default=os.environ.get("SD_USECUDA", False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
group_compute.add_argument("--use-rocm", default=os.environ.get("SD_USEROCM", False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
group_diag.add_argument("--device-id", type=str, default=os.environ.get("SD_DEVICEID", None), help="Select the default CUDA device to use, default: %(default)s")
group_http = parser.add_argument_group('HTTP')
group_http.add_argument('--theme', type=str, default=os.environ.get("SD_THEME", None), help='Override UI theme')
@@ -60,8 +58,8 @@ def main_args():
def compatibility_args():
group_compat = parser.add_argument_group('Compatibility options')
# removed args are added here as hidden in fixed format for compatbility reasons
group_compat = parser.add_argument_group('Compatibility options')
group_compat.add_argument("--allow-code", default=os.environ.get("SD_ALLOWCODE", False), action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--use-cpu", nargs='+', default=[], type=str.lower, help=argparse.SUPPRESS)
group_compat.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
@@ -74,13 +72,17 @@ def compatibility_args():
group_compat.add_argument("--disable-safe-unpickle", action='store_true', help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--lowram", action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--disable-extension-access", default=False, action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--api", help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--api", action='store_true', help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--api-auth", type=str, help=argparse.SUPPRESS, default=None)
group_compat.add_argument("--api-log", default=os.environ.get("SD_APILOG", True), action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--disable-queue", default=os.environ.get("SD_DISABLEQUEUE", False), action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument('--debug', default=os.environ.get("SD_DEBUG", True), action='store_true', help=argparse.SUPPRESS)
def settings_args(opts, args):
group_compat = parser.add_argument_group('Compatibility options')
# removed args are added here as hidden in fixed format for compatbility reasons
group_compat = parser.add_argument_group('Compatibility options')
group_compat.add_argument("--allow-code", default=os.environ.get("SD_ALLOWCODE", False), action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--use-cpu", nargs='+', default=[], type=str.lower, help=argparse.SUPPRESS)
group_compat.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
@@ -94,7 +96,7 @@ def settings_args(opts, args):
group_compat.add_argument("--lowram", action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--disable-extension-access", default=False, action='store_true', help=argparse.SUPPRESS)
group_compat.add_argument("--allowed-paths", nargs='+', default=[], type=str, required=False, help="add additional paths to paths allowed for web access")
group_compat.add_argument("--api", help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--api", action='store_true', help=argparse.SUPPRESS, default=True)
group_compat.add_argument("--api-auth", type=str, help=argparse.SUPPRESS, default=None)
# removed args that have been moved to opts are added here as hidden with default values as defined in opts
group_compat.add_argument("--ckpt-dir", type=str, help=argparse.SUPPRESS, default=opts.ckpt_dir)
+2 -1
View File
@@ -486,7 +486,7 @@ def set_cuda_params():
device_name = get_raw_openvino_device()
else:
device_name = torch.device(get_optimal_device_name())
log.info(f'Torch parameters: backend={backend} device={device_name} config={opts.cuda_dtype} dtype={dtype} vae={dtype_vae} unet={dtype_unet} context={inference_context.__name__} nohalf={opts.no_half} nohalfvae={opts.no_half_vae} upcast={opts.upcast_sampling} deterministic={opts.cudnn_deterministic} test-fp16={fp16_ok} test-bf16={bf16_ok} optimization="{opts.cross_attention_optimization}"')
log.info(f'Torch parameters: backend={backend} device={device_name} config={opts.cuda_dtype} dtype={dtype} context={inference_context.__name__} nohalf={opts.no_half} nohalfvae={opts.no_half_vae} upcast={opts.upcast_sampling} deterministic={opts.cudnn_deterministic} fp16={"pass" if fp16_ok else "fail"} bf16={"pass" if bf16_ok else "fail"} optimization="{opts.cross_attention_optimization}"')
def cond_cast_unet(tensor):
@@ -516,6 +516,7 @@ def randn_without_seed(shape):
return torch.randn(shape, device=cpu).to(device)
return torch.randn(shape, device=device)
def autocast(disable=False):
if disable or dtype == torch.float32:
return contextlib.nullcontext()
+1 -1
View File
@@ -154,4 +154,4 @@ def list_extensions():
for dirname, path, is_builtin in extension_paths:
extension = Extension(name=dirname, path=path, enabled=dirname not in disabled_extensions, is_builtin=is_builtin)
extensions.append(extension)
shared.log.debug(f'Disabled extensions: {[e.name for e in extensions if not e.enabled]}')
shared.log.debug(f'Extensions: disabled={[e.name for e in extensions if not e.enabled]}')
+12 -7
View File
@@ -18,7 +18,7 @@ def register_extra_network(extra_network):
def register_default_extra_networks():
from modules.ui_extra_networks_styles import ExtraNetworkStyles
register_extra_network(ExtraNetworkStyles())
if shared.native:
if not shared.opts.lora_legacy:
from modules.lora.networks import extra_network_lora
register_extra_network(extra_network_lora)
if shared.opts.hypernetwork_enabled:
@@ -80,14 +80,14 @@ def activate(p, extra_network_data=None, step=0, include=[], exclude=[]):
if p.disable_extra_networks:
return
extra_network_data = extra_network_data or p.network_data
if extra_network_data is None or len(extra_network_data) == 0:
return
# if extra_network_data is None or len(extra_network_data) == 0:
# return
stepwise = False
for extra_network_args in extra_network_data.values():
stepwise = stepwise or is_stepwise(extra_network_args)
functional = shared.opts.lora_functional
if shared.opts.lora_force_diffusers and stepwise:
shared.log.warning("Composable LoRA not compatible with 'lora_force_diffusers'")
shared.log.warning("Load network: type=LoRA method=composable loader=diffusers not compatible")
stepwise = False
shared.opts.data['lora_functional'] = stepwise or functional
@@ -110,7 +110,12 @@ def activate(p, extra_network_data=None, step=0, include=[], exclude=[]):
if args is not None:
continue
try:
extra_network.activate(p, [])
# extra_network.activate(p, [])
signature = list(inspect.signature(extra_network.activate).parameters)
if 'include' in signature and 'exclude' in signature:
extra_network.activate(p, [], include=include, exclude=exclude)
else:
extra_network.activate(p, [])
except Exception as e:
errors.display(e, f"Activating network: type={extra_network_name}")
@@ -125,8 +130,8 @@ def deactivate(p, extra_network_data=None):
if p.disable_extra_networks:
return
extra_network_data = extra_network_data or p.network_data
if extra_network_data is None or len(extra_network_data) == 0:
return
# if extra_network_data is None or len(extra_network_data) == 0:
# return
for extra_network_name in extra_network_data:
extra_network = extra_network_registry.get(extra_network_name, None)
if extra_network is None:
+1 -1
View File
@@ -6,7 +6,6 @@ import torch
from torch import einsum
from torch.nn.init import normal_, xavier_normal_, xavier_uniform_, kaiming_normal_, kaiming_uniform_, zeros_
from einops import rearrange, repeat
from ldm.util import default
from modules import devices, shared, hashes, errors, files_cache
@@ -327,6 +326,7 @@ def apply_hypernetworks(hypernetworks, context, layer=None):
def attention_CrossAttention_forward(self, x, context=None, mask=None):
from ldm.util import default
h = self.heads
q = self.to_q(x)
context = default(context, x)
+3 -2
View File
@@ -42,10 +42,11 @@ def image_grid(imgs, batch_size=1, rows=None):
imgs = [i for i in imgs if i is not None] if imgs is not None else []
if len(imgs) == 0:
return None
w, h = max(i.width for i in imgs), max(i.height for i in imgs)
w, h = max(i.width for i in imgs if i is not None), max(i.height for i in imgs if i is not None)
grid = Image.new('RGB', size=(params.cols * w, params.rows * h), color=shared.opts.grid_background)
for i, img in enumerate(params.imgs):
grid.paste(img, box=(i % params.cols * w, i // params.cols * h))
if img is not None:
grid.paste(img, box=(i % params.cols * w, i // params.cols * h))
return grid
+1 -1
View File
@@ -129,5 +129,5 @@ def resize_image(resize_mode: int, im: Image.Image, width: int, height: int, ups
shared.log.error(f'Invalid resize mode: {resize_mode}')
t1 = time.time()
fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
shared.log.debug(f'Image resize: input={im} width={width} height={height} mode="{shared.resize_modes[resize_mode]}" upscaler="{upscaler_name}" context="{context}" type={output_type} result={res} time={t1-t0:.2f} fn={fn}') # pylint: disable=protected-access
shared.log.debug(f'Image resize: source={im.width}:{im.height} target={width}:{height} mode="{shared.resize_modes[resize_mode]}" upscaler="{upscaler_name}" type={output_type} time={t1-t0:.2f} fn={fn}') # pylint: disable=protected-access
return np.array(res) if output_type == 'np' else res
+72 -44
View File
@@ -32,16 +32,23 @@ DEFAULT_OPENVINO_PYTHON_CONFIG = MappingProxyType(
class OpenVINOGraphModule(torch.nn.Module):
def __init__(self, gm, partition_id, use_python_fusion_cache, model_hash_str: str = None, file_name=""):
def __init__(self, gm, partition_id, use_python_fusion_cache, model_hash_str: str = None, file_name="", int_inputs=[]):
super().__init__()
self.gm = gm
self.int_inputs = int_inputs
self.partition_id = partition_id
self.executor_parameters = {"use_python_fusion_cache": use_python_fusion_cache,
"model_hash_str": model_hash_str}
self.file_name = file_name
def __call__(self, *args):
result = openvino_execute(self.gm, *args, executor_parameters=self.executor_parameters, partition_id=self.partition_id, file_name=self.file_name)
ov_inputs = []
for arg in args:
if not isinstance(arg, int):
ov_inputs.append(arg)
for idx, int_input in self.int_inputs:
ov_inputs.insert(idx, int_input)
result = openvino_execute(self.gm, *ov_inputs, executor_parameters=self.executor_parameters, partition_id=self.partition_id, file_name=self.file_name)
return result
@@ -111,10 +118,7 @@ def cached_model_name(model_hash_str, device, args, cache_root, reversed = False
else:
inputs_str += "_" + "torch.SymInt1"
elif isinstance(input_data, int):
if reversed:
inputs_str = "_" + "int" + inputs_str
else:
inputs_str += "_" + "int"
pass
else:
if reversed:
inputs_str = "_" + str(input_data.type()) + str(input_data.size())[11:-1].replace(" ", "") + inputs_str
@@ -174,16 +178,13 @@ def openvino_compile(gm: GraphModule, *example_inputs, model_hash_str: str = Non
input_types.append(torch.SymInt)
input_shapes.append(torch.Size([1]))
elif isinstance(input_data, int):
input_types.append(torch.int64)
input_shapes.append(torch.Size([1]))
pass
else:
input_types.append(input_data.type())
input_shapes.append(input_data.size())
decoder = TorchFXPythonDecoder(gm, input_shapes=input_shapes, input_types=input_types)
im = fe.load(decoder)
om = fe.convert(im)
if file_name is not None:
@@ -206,13 +207,13 @@ def openvino_compile(gm: GraphModule, *example_inputs, model_hash_str: str = Non
torch.bool: Type.boolean
}
idx_minus = 0
for idx, input_data in enumerate(example_inputs):
if isinstance(input_data, int):
om.inputs[idx].get_node().set_element_type(dtype_mapping[torch.int64])
om.inputs[idx].get_node().set_partial_shape(PartialShape(list(torch.Size([1]))))
idx_minus += 1
else:
om.inputs[idx].get_node().set_element_type(dtype_mapping[input_data.dtype])
om.inputs[idx].get_node().set_partial_shape(PartialShape(list(input_data.shape)))
om.inputs[idx-idx_minus].get_node().set_element_type(dtype_mapping[input_data.dtype])
om.inputs[idx-idx_minus].get_node().set_partial_shape(PartialShape(list(input_data.shape)))
om.validate_nodes_and_infer_types()
if shared.opts.nncf_quantize and not dont_use_quant:
@@ -305,19 +306,23 @@ def openvino_compile_cached_model(cached_model_path, *example_inputs):
return compiled_model
def openvino_execute(gm: GraphModule, *args, executor_parameters=None, partition_id, file_name=""):
def openvino_execute(gm: GraphModule, *args, executor_parameters=None, partition_id=None, file_name=""):
if hasattr(gm, "partition_id"):
partition_id = gm.partition_id
if hasattr(gm, "gm"):
gm = gm.gm
executor_parameters = executor_parameters or DEFAULT_OPENVINO_PYTHON_CONFIG
use_cache = executor_parameters.get(
use_cache = partition_id is not None and executor_parameters.get(
"use_python_fusion_cache",
DEFAULT_OPENVINO_PYTHON_CONFIG["use_python_fusion_cache"],
)
model_hash_str = executor_parameters.get("model_hash_str", None)
if model_hash_str is not None:
model_hash_str = model_hash_str + str(partition_id)
model_hash_str = model_hash_str + str(partition_id) if partition_id is not None else ""
if use_cache and (partition_id in shared.compiled_model_state.compiled_cache):
if use_cache and (partition_id in shared.compiled_model_state.compiled_cache.keys()):
compiled = shared.compiled_model_state.compiled_cache[partition_id]
req = shared.compiled_model_state.req_cache[partition_id]
else:
@@ -326,14 +331,17 @@ def openvino_execute(gm: GraphModule, *args, executor_parameters=None, partition
compiled = openvino_compile_cached_model(file_name, *args)
else:
compiled = openvino_compile(gm, *args, model_hash_str=model_hash_str, file_name=file_name)
shared.compiled_model_state.compiled_cache[partition_id] = compiled
if use_cache:
shared.compiled_model_state.compiled_cache[partition_id] = compiled
req = compiled.create_infer_request()
shared.compiled_model_state.req_cache[partition_id] = req
if use_cache:
shared.compiled_model_state.req_cache[partition_id] = req
flat_args, _ = tree_flatten(args)
ov_inputs = []
for arg in flat_args:
ov_inputs.append((arg if isinstance(arg, int) else arg.detach().cpu().numpy()))
if not isinstance(arg, int):
ov_inputs.append((arg.detach().cpu().numpy()))
res = req.infer(ov_inputs, share_inputs=True, share_outputs=True)
@@ -352,33 +360,54 @@ def openvino_execute_partitioned(gm: GraphModule, *args, executor_parameters=Non
)
model_hash_str = executor_parameters.get("model_hash_str", None)
signature = str(id(gm))
if file_name:
signature = file_name.rsplit("/", maxsplit=1)[-1].split("_fs", maxsplit=1)[0]
else:
signature = "signature"
if model_hash_str is None:
file_name = None
idx_minus = 0
int_inputs = []
for idx, input_data in enumerate(args):
if isinstance(input_data, torch.Tensor):
signature = signature + "_" + str(idx) + ":" + str(input_data.type())[6:] + ":" + str(input_data.size())[11:-1].replace(" ", "")
if isinstance(input_data, int):
int_inputs.append([idx, input_data])
idx_minus += 1
elif isinstance(input_data, torch.Tensor):
signature = signature + "_" + str(idx-idx_minus) + ":" + str(input_data.type())[6:] + ":" + str(input_data.size())[11:-1].replace(" ", "")
else:
signature = signature + "_" + str(idx) + ":" + type(input_data).__name__ + ":val(" + str(input_data) + ")"
signature = signature + "_" + str(idx-idx_minus) + ":" + type(input_data).__name__ + ":val(" + str(input_data) + ")"
if signature not in shared.compiled_model_state.partitioned_modules:
shared.compiled_model_state.partitioned_modules[signature] = partition_graph(gm, use_python_fusion_cache=use_python_fusion_cache,
model_hash_str=model_hash_str, file_name=file_name)
shared.compiled_model_state.partitioned_modules[signature] = partition_graph(gm, use_python_fusion_cache=use_python_fusion_cache,
model_hash_str=model_hash_str, file_name=file_name, int_inputs=int_inputs)
return shared.compiled_model_state.partitioned_modules[signature](*args)
ov_inputs = []
for arg in args:
if not isinstance(arg, int):
ov_inputs.append(arg)
for idx, int_input in shared.compiled_model_state.partitioned_modules[signature][1]:
ov_inputs.insert(idx, int_input)
return shared.compiled_model_state.partitioned_modules[signature][0](*ov_inputs)
def partition_graph(gm: GraphModule, use_python_fusion_cache: bool, model_hash_str: str = None, file_name=""):
def partition_graph(gm: GraphModule, use_python_fusion_cache: bool, model_hash_str: str = None, file_name="", int_inputs=[]):
for node in gm.graph.nodes:
if node.op == "call_module" and "fused_" in node.name:
openvino_submodule = getattr(gm, node.name)
if isinstance(openvino_submodule, OpenVINOGraphModule):
int_inputs = openvino_submodule.int_inputs
continue
gm.delete_submodule(node.target)
gm.add_submodule(
node.target,
OpenVINOGraphModule(openvino_submodule, shared.compiled_model_state.partition_id, use_python_fusion_cache,
model_hash_str=model_hash_str, file_name=file_name),
OpenVINOGraphModule(
openvino_submodule, shared.compiled_model_state.partition_id, use_python_fusion_cache,
model_hash_str=model_hash_str, file_name=file_name, int_inputs=int_inputs),
)
shared.compiled_model_state.partition_id = shared.compiled_model_state.partition_id + 1
shared.compiled_model_state.partition_id += 1
return gm
return gm, int_inputs
def generate_subgraph_str(tensor):
@@ -432,19 +461,19 @@ def openvino_fx(subgraph, example_inputs):
dont_use_nncf = bool("Text Encoder" not in shared.opts.nncf_compress_weights)
dont_use_quant = bool("Text Encoder" not in shared.opts.nncf_quantize)
# Create a hash to be used for caching
shared.compiled_model_state.model_hash_str = ""
subgraph.apply(generate_subgraph_str)
#shared.compiled_model_state.model_hash_str = shared.compiled_model_state.model_hash_str + sha256(subgraph.code.encode('utf-8')).hexdigest()
shared.compiled_model_state.model_hash_str = sha256(shared.compiled_model_state.model_hash_str.encode('utf-8')).hexdigest()
# Check if the model was fully supported and already cached
example_inputs.reverse()
inputs_reversed = True
maybe_fs_cached_name = cached_model_name(shared.compiled_model_state.model_hash_str + "_fs", get_device(), example_inputs, shared.opts.openvino_cache_path)
if not shared.opts.openvino_disable_model_caching:
os.environ.setdefault('OPENVINO_TORCH_MODEL_CACHING', "1")
# Create a hash to be used for caching
subgraph.apply(generate_subgraph_str)
shared.compiled_model_state.model_hash_str = shared.compiled_model_state.model_hash_str + sha256(subgraph.code.encode('utf-8')).hexdigest()
shared.compiled_model_state.model_hash_str = sha256(shared.compiled_model_state.model_hash_str.encode('utf-8')).hexdigest()
executor_parameters = {"model_hash_str": shared.compiled_model_state.model_hash_str}
# Check if the model was fully supported and already cached
example_inputs.reverse()
inputs_reversed = True
maybe_fs_cached_name = cached_model_name(shared.compiled_model_state.model_hash_str + "_fs", get_device(), example_inputs, shared.opts.openvino_cache_path)
if os.path.isfile(maybe_fs_cached_name + ".xml") and os.path.isfile(maybe_fs_cached_name + ".bin"):
example_inputs_reordered = []
@@ -487,7 +516,6 @@ def openvino_fx(subgraph, example_inputs):
return _call
else:
os.environ.setdefault('OPENVINO_TORCH_MODEL_CACHING', "0")
maybe_fs_cached_name = None
if inputs_reversed:
example_inputs.reverse()
+5 -2
View File
@@ -248,14 +248,16 @@ def update_interrogate_params(caption_max_length, chunk_size, min_flavors, max_f
def get_clip_models():
import open_clip
return ['/'.join(x) for x in open_clip.list_pretrained()]
models = sorted(open_clip.list_pretrained())
shared.log.info(f'Interrogate: pkg=openclip version={open_clip.__version__} models={len(models)}')
return ['/'.join(x) for x in models]
def load_interrogator(clip_model, blip_model):
from installer import install
install('clip_interrogator==0.6.0')
import clip_interrogator
clip_interrogator.CAPTION_MODELS = caption_models
clip_interrogator.clip_interrogator.CAPTION_MODELS = caption_models
global ci # pylint: disable=global-statement
if ci is None:
interrogator_config = clip_interrogator.Config(
@@ -329,6 +331,7 @@ def interrogate_image(image, clip_model, blip_model, mode):
except Exception as e:
prompt = f"Exception {type(e)}"
shared.log.error(f'Interrogate: {e}')
errors.display(e, 'Interrogate')
shared.state.end()
return prompt
+47 -10
View File
@@ -1,11 +1,16 @@
from typing import List
import os
import re
import numpy as np
import modules.lora.networks as networks
from modules.lora import networks
from modules import extra_networks, shared
# from https://github.com/cheald/sd-webui-loractl/blob/master/loractl/lib/utils.py
def get_stepwise(param, step, steps):
debug = os.environ.get('SD_SCRIPT_DEBUG', None) is not None
debug_log = shared.log.trace if debug else lambda *args, **kwargs: None
def get_stepwise(param, step, steps): # from https://github.com/cheald/sd-webui-loractl/blob/master/loractl/lib/utils.py
def sorted_positions(raw_steps):
steps = [[float(s.strip()) for s in re.split("[@~]", x)]
for x in re.split("[,;]", str(raw_steps))]
@@ -46,7 +51,8 @@ def prompt(p):
if len(all_tags) > 0:
all_tags = list(set(all_tags))
all_tags = [t for t in all_tags if t not in p.prompt]
shared.log.debug(f"Load network: type=LoRA tags={all_tags} max={shared.opts.lora_apply_tags} apply")
if len(all_tags) > 0:
shared.log.debug(f"Load network: type=LoRA tags={all_tags} max={shared.opts.lora_apply_tags} apply")
all_tags = ', '.join(all_tags)
p.extra_generation_params["LoRA tags"] = all_tags
if '_tags_' in p.prompt:
@@ -114,26 +120,58 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
self.model = None
self.errors = {}
def signature(self, names: List[str], te_multipliers: List, unet_multipliers: List):
return [f'{name}:{te}:{unet}' for name, te, unet in zip(names, te_multipliers, unet_multipliers)]
def changed(self, requested: List[str], include: List[str], exclude: List[str]):
sd_model = getattr(shared.sd_model, "pipe", shared.sd_model)
if not hasattr(sd_model, 'loaded_loras'):
sd_model.loaded_loras = {}
key = f'{",".join(include)}:{",".join(exclude)}'
loaded = sd_model.loaded_loras.get(key, [])
# shared.log.trace(f'Load network: type=LoRA key="{key}" requested={requested} loaded={loaded}')
if len(requested) != len(loaded):
sd_model.loaded_loras[key] = requested
return True
for r, l in zip(requested, loaded):
if r != l:
sd_model.loaded_loras[key] = requested
return True
return False
def activate(self, p, params_list, step=0, include=[], exclude=[]):
self.errors.clear()
if self.active:
if self.model != shared.opts.sd_model_checkpoint: # reset if model changed
self.active = False
if len(params_list) > 0 and not self.active: # activate patches once
# shared.log.debug(f'Activate network: type=LoRA model="{shared.opts.sd_model_checkpoint}"')
self.active = True
self.model = shared.opts.sd_model_checkpoint
if 'text_encoder' in include:
networks.timer.clear(complete=True)
names, te_multipliers, unet_multipliers, dyn_dims = parse(p, params_list, step)
requested = self.signature(names, te_multipliers, unet_multipliers)
if debug:
import sys
fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
debug_log(f'Load network: type=LoRA include={include} exclude={exclude} requested={requested} fn={fn}')
networks.network_load(names, te_multipliers, unet_multipliers, dyn_dims) # load
networks.network_activate(include, exclude)
has_changed = self.changed(requested, include, exclude)
if has_changed:
networks.network_deactivate(include, exclude)
networks.network_activate(include, exclude)
debug_log(f'Load network: type=LoRA previous={[n.name for n in networks.previously_loaded_networks]} current={[n.name for n in networks.loaded_networks]} changed')
if len(networks.loaded_networks) > 0 and len(networks.applied_layers) > 0 and step == 0:
infotext(p)
prompt(p)
shared.log.info(f'Load network: type=LoRA apply={[n.name for n in networks.loaded_networks]} mode={"fuse" if shared.opts.lora_fuse_diffusers else "backup"} te={te_multipliers} unet={unet_multipliers} time={networks.timer.summary}')
if has_changed and len(include) == 0: # print only once
shared.log.info(f'Load network: type=LoRA apply={[n.name for n in networks.loaded_networks]} mode={"fuse" if shared.opts.lora_fuse_diffusers else "backup"} te={te_multipliers} unet={unet_multipliers} time={networks.timer.summary}')
def deactivate(self, p):
if shared.native:
networks.previously_loaded_networks = networks.loaded_networks.copy()
debug_log(f'Load network: type=LoRA active={[n.name for n in networks.previously_loaded_networks]} deactivate')
if shared.native and len(networks.diffuser_loaded) > 0:
if hasattr(shared.sd_model, "unload_lora_weights") and hasattr(shared.sd_model, "text_encoder"):
if not (shared.compiled_model_state is not None and shared.compiled_model_state.is_compiled is True):
@@ -143,7 +181,6 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork):
shared.sd_model.unload_lora_weights() # fails for non-CLIP models
except Exception:
pass
networks.network_deactivate()
if self.active and networks.debug:
shared.log.debug(f"Network end: type=LoRA time={networks.timer.summary}")
if self.errors:
+91 -68
View File
@@ -19,6 +19,7 @@ extra_network_lora = ExtraNetworkLora()
available_networks = {}
available_network_aliases = {}
loaded_networks: List[network.Network] = []
previously_loaded_networks: List[network.Network] = []
applied_layers: list[str] = []
bnb = None
lora_cache = {}
@@ -131,11 +132,11 @@ def load_safetensors(name, network_on_disk) -> Union[network.Network, None]:
else:
net.modules[key] = net_module
if len(keys_failed_to_match) > 0:
shared.log.warning(f'LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}')
shared.log.warning(f'Load network: type=LoRA name="{name}" type={set(network_types)} unmatched={len(keys_failed_to_match)} matched={len(matched_networks)}')
if debug:
shared.log.debug(f'LoRA name="{name}" unmatched={keys_failed_to_match}')
shared.log.debug(f'Load network: type=LoRA name="{name}" unmatched={keys_failed_to_match}')
else:
shared.log.debug(f'LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)} direct={shared.opts.lora_fuse_diffusers}')
shared.log.debug(f'Load network: type=LoRA name="{name}" type={set(network_types)} keys={len(matched_networks)} direct={shared.opts.lora_fuse_diffusers}')
if len(matched_networks) == 0:
return None
lora_cache[name] = net
@@ -145,6 +146,7 @@ def load_safetensors(name, network_on_disk) -> Union[network.Network, None]:
def maybe_recompile_model(names, te_multipliers):
recompile_model = False
skip_lora_load = False
if shared.compiled_model_state is not None and shared.compiled_model_state.is_compiled:
if len(names) == len(shared.compiled_model_state.lora_model):
for i, name in enumerate(names):
@@ -154,19 +156,23 @@ def maybe_recompile_model(names, te_multipliers):
shared.compiled_model_state.lora_model = []
break
if not recompile_model:
skip_lora_load = True
if len(loaded_networks) > 0 and debug:
shared.log.debug('Model Compile: Skipping LoRa loading')
return recompile_model
return recompile_model, skip_lora_load
else:
recompile_model = True
shared.compiled_model_state.lora_model = []
if recompile_model:
backup_cuda_compile = shared.opts.cuda_compile
backup_scheduler = getattr(shared.sd_model, "scheduler", None)
sd_models.unload_model_weights(op='model')
shared.opts.cuda_compile = []
sd_models.reload_model_weights(op='model')
shared.opts.cuda_compile = backup_cuda_compile
return recompile_model
if backup_scheduler is not None:
shared.sd_model.scheduler = backup_scheduler
return recompile_model, skip_lora_load
def list_available_networks():
@@ -198,7 +204,7 @@ def list_available_networks():
except OSError as e: # should catch FileNotFoundError and PermissionError etc.
shared.log.error(f'LoRA: filename="{filename}" {e}')
candidates = list(files_cache.list_files(shared.cmd_opts.lora_dir, ext_filter=[".pt", ".ckpt", ".safetensors"]))
candidates = sorted(files_cache.list_files(shared.cmd_opts.lora_dir, ext_filter=[".pt", ".ckpt", ".safetensors"]))
with concurrent.futures.ThreadPoolExecutor(max_workers=shared.max_workers) as executor:
for fn in candidates:
executor.submit(add_network, fn)
@@ -229,7 +235,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non
if names[i].startswith('/'):
networks_on_disk[i] = network_download(names[i])
failed_to_load_networks = []
recompile_model = maybe_recompile_model(names, te_multipliers)
recompile_model, skip_lora_load = maybe_recompile_model(names, te_multipliers)
loaded_networks.clear()
diffuser_loaded.clear()
@@ -271,7 +277,7 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non
name = next(iter(lora_cache))
lora_cache.pop(name, None)
if len(diffuser_loaded) > 0:
if not skip_lora_load and len(diffuser_loaded) > 0:
shared.log.debug(f'Load network: type=LoRA loaded={diffuser_loaded} available={shared.sd_model.get_list_adapters()} active={shared.sd_model.get_active_adapters()} scales={diffuser_scales}')
try:
t0 = time.time()
@@ -286,14 +292,13 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non
errors.display(e, 'LoRA')
if len(loaded_networks) > 0 and debug:
shared.log.debug(f'Load network: type=LoRA loaded={len(loaded_networks)} cache={list(lora_cache)}')
shared.log.debug(f'Load network: type=LoRA loaded={[n.name for n in loaded_networks]} cache={list(lora_cache)}')
if recompile_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)
shared.compiled_model_state.lora_model = backup_lora_model
if len(loaded_networks) > 0:
@@ -311,6 +316,14 @@ def network_backup_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.n
t0 = time.time()
weights_backup = getattr(self, "network_weights_backup", None)
bias_backup = getattr(self, "network_bias_backup", None)
if weights_backup is not None or bias_backup is not None:
if (shared.opts.lora_fuse_diffusers and not isinstance(weights_backup, bool)) or (not shared.opts.lora_fuse_diffusers and isinstance(weights_backup, bool)): # invalidate so we can change direct/backup on-the-fly
weights_backup = None
bias_backup = None
self.network_weights_backup = weights_backup
self.network_bias_backup = bias_backup
if weights_backup is None and wanted_names != (): # pylint: disable=C1803
weight = getattr(self, 'weight', None)
self.network_weights_backup = None
@@ -338,7 +351,6 @@ def network_backup_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.n
else:
self.network_weights_backup = weight.clone().to(devices.cpu)
bias_backup = getattr(self, "network_bias_backup", None)
if bias_backup is None:
if getattr(self, 'bias', None) is not None:
if shared.opts.lora_fuse_diffusers:
@@ -355,7 +367,7 @@ def network_backup_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.n
return backup_size
def network_calc_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, diffusers.models.lora.LoRACompatibleLinear, diffusers.models.lora.LoRACompatibleConv], network_layer_name: str):
def network_calc_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, diffusers.models.lora.LoRACompatibleLinear, diffusers.models.lora.LoRACompatibleConv], network_layer_name: str, use_previous: bool = False):
if shared.opts.diffusers_offload_mode == "none":
try:
self.to(devices.device)
@@ -363,7 +375,8 @@ def network_calc_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.
pass
batch_updown = None
batch_ex_bias = None
for net in loaded_networks:
loaded = loaded_networks if not use_previous else previously_loaded_networks
for net in loaded:
module = net.modules.get(network_layer_name, None)
if module is None:
continue
@@ -402,9 +415,41 @@ def network_calc_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.
return batch_updown, batch_ex_bias
def network_add_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, diffusers.models.lora.LoRACompatibleLinear, diffusers.models.lora.LoRACompatibleConv], model_weights: Union[None, torch.Tensor] = None, lora_weights: torch.Tensor = None, deactivate: bool = False):
if lora_weights is None:
return self.weight
if deactivate:
lora_weights *= -1
if model_weights is None: # weights are used if provided-from-backup else use self.weight
model_weights = self.weight
# TODO lora: add other quantization types
if self.__class__.__name__ == 'Linear4bit' and bnb is not None:
try:
dequant_weight = bnb.functional.dequantize_4bit(model_weights.to(devices.device), quant_state=self.quant_state, quant_type=self.quant_type, blocksize=self.blocksize)
new_weight = dequant_weight.to(devices.device) + lora_weights.to(devices.device)
self.weight = bnb.nn.Params4bit(new_weight, quant_state=self.quant_state, quant_type=self.quant_type, blocksize=self.blocksize)
except Exception as e:
shared.log.error(f'Load network: type=LoRA quant=bnb cls={self.__class__.__name__} type={self.quant_type} blocksize={self.blocksize} state={vars(self.quant_state)} weight={self.weight} bias={lora_weights} {e}')
else:
try:
new_weight = model_weights.to(devices.device) + lora_weights.to(devices.device)
except Exception:
new_weight = model_weights + lora_weights # try without device cast
self.weight = torch.nn.Parameter(new_weight, requires_grad=False)
try:
self.weight = self.weight.to(device=devices.device) # required since quantization happens only during .to call, not during params creation
except Exception:
pass # may fail if weights is meta tensor
return self.weight
def network_apply_direct(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, diffusers.models.lora.LoRACompatibleLinear, diffusers.models.lora.LoRACompatibleConv], updown: torch.Tensor, ex_bias: torch.Tensor, deactivate: bool = False):
weights_backup = getattr(self, "network_weights_backup", False)
bias_backup = getattr(self, "network_bias_backup", False)
if not isinstance(weights_backup, bool): # remove previous backup if we switched settings
weights_backup = True
if not isinstance(bias_backup, bool):
bias_backup = True
if not weights_backup and not bias_backup:
return None, None
t0 = time.time()
@@ -413,34 +458,14 @@ def network_apply_direct(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.
if updown is not None and len(self.weight.shape) == 4 and self.weight.shape[1] == 9: # inpainting model. zero pad updown to make channel[1] 4 to 9
updown = torch.nn.functional.pad(updown, (0, 0, 0, 0, 0, 5)) # pylint: disable=not-callable
if updown is not None:
if deactivate:
updown *= -1
if getattr(self, "quant_type", None) in ['nf4', 'fp4'] and bnb is not None:
try: # TODO lora load: direct with bnb
weight = bnb.functional.dequantize_4bit(self.weight, quant_state=self.quant_state, quant_type=self.quant_type, blocksize=self.blocksize)
new_weight = weight.to(devices.device) + updown.to(devices.device)
self.weight = bnb.nn.Params4bit(new_weight, quant_state=self.quant_state, quant_type=self.quant_type, blocksize=self.blocksize)
except Exception:
# shared.log.error(f'Load network: type=LoRA quant=bnb type={self.quant_type} state={self.quant_state} blocksize={self.blocksize} {e}')
extra_network_lora.errors['bnb'] = extra_network_lora.errors.get('bnb', 0) + 1
new_weight = None
else:
try:
new_weight = self.weight.to(devices.device) + updown.to(devices.device)
except Exception:
new_weight = self.weight + updown
self.weight = torch.nn.Parameter(new_weight, requires_grad=False)
del new_weight
if hasattr(self, "qweight") and hasattr(self, "freeze"):
self.freeze()
self.weight = network_add_weights(self, lora_weights=updown, deactivate=deactivate)
if bias_backup:
if ex_bias is not None:
if deactivate:
ex_bias *= -1
new_weight = bias_backup.to(devices.device) + ex_bias.to(devices.device)
self.bias = torch.nn.Parameter(new_weight, requires_grad=False)
del new_weight
self.bias = network_add_weights(self, lora_weights=ex_bias, deactivate=deactivate)
if hasattr(self, "qweight") and hasattr(self, "freeze"):
self.freeze()
timer.apply += time.time() - t0
return self.weight.device, self.weight.dtype
@@ -458,50 +483,44 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn
if updown is not None and len(weights_backup.shape) == 4 and weights_backup.shape[1] == 9: # inpainting model. zero pad updown to make channel[1] 4 to 9
updown = torch.nn.functional.pad(updown, (0, 0, 0, 0, 0, 5)) # pylint: disable=not-callable
if updown is not None:
if deactivate:
updown *= -1
new_weight = weights_backup.to(devices.device) + updown.to(devices.device)
if getattr(self, "quant_type", None) in ['nf4', 'fp4'] and bnb is not None:
self.weight = bnb.nn.Params4bit(new_weight, quant_state=self.quant_state, quant_type=self.quant_type, blocksize=self.blocksize)
else:
self.weight = torch.nn.Parameter(new_weight.to(device=orig_device), requires_grad=False)
del new_weight
self.weight = network_add_weights(self, model_weights=weights_backup, lora_weights=updown, deactivate=deactivate)
else:
self.weight = torch.nn.Parameter(weights_backup.to(device=orig_device), requires_grad=False)
if hasattr(self, "qweight") and hasattr(self, "freeze"):
self.freeze()
if bias_backup is not None:
self.bias = None
if ex_bias is not None:
if deactivate:
ex_bias *= -1
new_weight = bias_backup.to(devices.device) + ex_bias.to(devices.device)
self.bias = torch.nn.Parameter(new_weight.to(device=orig_device), requires_grad=False)
del new_weight
self.weight = network_add_weights(self, model_weights=weights_backup, lora_weights=ex_bias, deactivate=deactivate)
else:
self.bias = torch.nn.Parameter(bias_backup.to(device=orig_device), requires_grad=False)
if hasattr(self, "qweight") and hasattr(self, "freeze"):
self.freeze()
timer.apply += time.time() - t0
return self.weight.device, self.weight.dtype
def network_deactivate():
if not shared.opts.lora_fuse_diffusers:
def network_deactivate(include=[], exclude=[]):
if not shared.opts.lora_fuse_diffusers or shared.opts.lora_force_diffusers:
return
t0 = time.time()
timer.clear()
sd_model = getattr(shared.sd_model, "pipe", shared.sd_model) # wrapped model compatiblility
if shared.opts.diffusers_offload_mode == "sequential":
sd_models.disable_offload(sd_model)
sd_models.move_model(sd_model, device=devices.cpu)
modules = {}
for component_name in ['text_encoder', 'text_encoder_2', 'unet', 'transformer']:
component = getattr(sd_model, component_name, None)
components = include if len(include) > 0 else ['text_encoder', 'text_encoder_2', 'text_encoder_3', 'unet', 'transformer']
components = [x for x in components if x not in exclude]
active_components = []
for name in components:
component = getattr(sd_model, name, None)
if component is not None and hasattr(component, 'named_modules'):
modules[component_name] = list(component.named_modules())
modules[name] = list(component.named_modules())
active_components.append(name)
total = sum(len(x) for x in modules.values())
if len(loaded_networks) > 0:
if len(previously_loaded_networks) > 0 and debug:
pbar = rp.Progress(rp.TextColumn('[cyan]Network: type=LoRA action=deactivate'), rp.BarColumn(), rp.TaskProgressColumn(), rp.TimeRemainingColumn(), rp.TimeElapsedColumn(), rp.TextColumn('[cyan]{task.description}'), console=shared.console)
task = pbar.add_task(description='', total=total)
else:
@@ -519,7 +538,7 @@ def network_deactivate():
if task is not None:
pbar.update(task, advance=1)
continue
batch_updown, batch_ex_bias = network_calc_weights(module, network_layer_name)
batch_updown, batch_ex_bias = network_calc_weights(module, network_layer_name, use_previous=True)
if shared.opts.lora_fuse_diffusers:
weights_device, weights_dtype = network_apply_direct(module, batch_updown, batch_ex_bias, deactivate=True)
else:
@@ -531,11 +550,12 @@ def network_deactivate():
del batch_updown, batch_ex_bias
module.network_current_names = ()
if task is not None:
pbar.update(task, advance=1, description=f'networks={len(loaded_networks)} modules={len(modules)} deactivate={len(applied_layers)}')
weights_devices, weights_dtypes = list(set([x for x in weights_devices if x is not None])), list(set([x for x in weights_dtypes if x is not None])) # noqa: C403 # pylint: disable=R1718
pbar.update(task, advance=1, description=f'networks={len(previously_loaded_networks)} modules={active_components} layers={total} unapply={len(applied_layers)}')
timer.deactivate = time.time() - t0
if debug and len(loaded_networks) > 0:
shared.log.debug(f'Deactivate network: type=LoRA networks={len(loaded_networks)} modules={total} deactivate={len(applied_layers)} device={weights_devices} dtype={weights_dtypes} fuse={shared.opts.lora_fuse_diffusers} time={timer.summary}')
if debug and len(previously_loaded_networks) > 0:
weights_devices, weights_dtypes = list(set([x for x in weights_devices if x is not None])), list(set([x for x in weights_dtypes if x is not None])) # noqa: C403 # pylint: disable=R1718
shared.log.debug(f'Deactivate network: type=LoRA networks={[n.name for n in previously_loaded_networks]} modules={active_components} layers={total} apply={len(applied_layers)} device={weights_devices} dtype={weights_dtypes} fuse={shared.opts.lora_fuse_diffusers} time={timer.summary}')
modules.clear()
if shared.opts.diffusers_offload_mode == "sequential":
sd_models.set_diffuser_offload(sd_model, op="model")
@@ -550,9 +570,11 @@ def network_activate(include=[], exclude=[]):
modules = {}
components = include if len(include) > 0 else ['text_encoder', 'text_encoder_2', 'text_encoder_3', 'unet', 'transformer']
components = [x for x in components if x not in exclude]
active_components = []
for name in components:
component = getattr(sd_model, name, None)
if component is not None and hasattr(component, 'named_modules'):
active_components.append(name)
modules[name] = list(component.named_modules())
total = sum(len(x) for x in modules.values())
if len(loaded_networks) > 0:
@@ -589,13 +611,14 @@ def network_activate(include=[], exclude=[]):
del batch_updown, batch_ex_bias
module.network_current_names = wanted_names
if task is not None:
pbar.update(task, advance=1, description=f'networks={len(loaded_networks)} modules={total} apply={len(applied_layers)} backup={backup_size}')
pbar.update(task, advance=1, description=f'networks={len(loaded_networks)} modules={active_components} layers={total} apply={len(applied_layers)} backup={backup_size}')
if task is not None and len(applied_layers) == 0:
pbar.remove_task(task) # hide progress bar for no action
weights_devices, weights_dtypes = list(set([x for x in weights_devices if x is not None])), list(set([x for x in weights_dtypes if x is not None])) # noqa: C403 # pylint: disable=R1718
timer.activate += time.time() - t0
if debug and len(loaded_networks) > 0:
shared.log.debug(f'Load network: type=LoRA networks={len(loaded_networks)} components={components} modules={total} apply={len(applied_layers)} device={weights_devices} dtype={weights_dtypes} backup={backup_size} fuse={shared.opts.lora_fuse_diffusers} time={timer.summary}')
weights_devices, weights_dtypes = list(set([x for x in weights_devices if x is not None])), list(set([x for x in weights_dtypes if x is not None])) # noqa: C403 # pylint: disable=R1718
shared.log.debug(f'Load network: type=LoRA networks={[n.name for n in loaded_networks]} modules={active_components} layers={total} apply={len(applied_layers)} device={weights_devices} dtype={weights_dtypes} backup={backup_size} fuse={shared.opts.lora_fuse_diffusers} time={timer.summary}')
modules.clear()
if shared.opts.diffusers_offload_mode == "sequential":
sd_models.set_diffuser_offload(sd_model, op="model")
+6 -6
View File
@@ -388,7 +388,7 @@ def run_mask(input_image: Image.Image, input_mask: Image.Image = None, return_ty
if input_image is None:
return input_mask
t0 = time.time()
# t0 = time.time()
input_mask = get_mask(input_image, input_mask) # perform optional auto-masking
if input_mask is None:
return None
@@ -436,14 +436,14 @@ def run_mask(input_image: Image.Image, input_mask: Image.Image = None, return_ty
if opts.invert:
mask = np.invert(mask)
mask_size = np.count_nonzero(mask)
total_size = np.prod(mask.shape)
area_size = np.count_nonzero(mask)
t1 = time.time()
return_type = return_type or opts.preview_type
shared.log.debug(f'Mask: size={input_image.width}x{input_image.height} masked={mask_size}px area={area_size/total_size:.2f} auto={opts.auto_mask} blur={opts.mask_blur:.3f} erode={opts.mask_erode:.3f} dilate={opts.mask_dilate:.3f} type={return_type} time={t1-t0:.2f}')
# mask_size = np.count_nonzero(mask)
# total_size = np.prod(mask.shape)
# area_size = np.count_nonzero(mask)
# t1 = time.time()
# shared.log.debug(f'Mask: size={input_image.width}x{input_image.height} masked={mask_size}px area={area_size/total_size:.2f} auto={opts.auto_mask} blur={opts.mask_blur:.3f} erode={opts.mask_erode:.3f} dilate={opts.mask_dilate:.3f} type={return_type} time={t1-t0:.2f}')
if return_type == 'None':
return input_mask
elif return_type == 'Opaque':
+30 -20
View File
@@ -143,20 +143,25 @@ def quant_flux_bnb(checkpoint_info, transformer, text_encoder_2):
"""
def load_quants(kwargs, repo_id, cache_dir):
if len(shared.opts.bnb_quantization) > 0:
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
quant_args = model_quant.create_ao_config(quant_args)
if not quant_args:
return kwargs
def load_quants(kwargs, repo_id, cache_dir, allow_quant):
if not allow_quant:
return kwargs
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
if quant_args:
model_quant.load_bnb(f'Load model: type=FLUX quant={quant_args}')
if 'Model' in shared.opts.bnb_quantization and 'transformer' not in kwargs:
kwargs['transformer'] = diffusers.FluxTransformer2DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'Text Encoder' in shared.opts.bnb_quantization and 'text_encoder_3' not in kwargs:
kwargs['text_encoder_2'] = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder="text_encoder_2", cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if not quant_args:
quant_args = model_quant.create_ao_config(quant_args)
if quant_args:
model_quant.load_torchao(f'Load model: type=FLUX quant={quant_args}')
if not quant_args:
return kwargs
if 'transformer' not in kwargs and ('Model' in shared.opts.bnb_quantization or 'Model' in shared.opts.torchao_quantization):
kwargs['transformer'] = diffusers.FluxTransformer2DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'text_encoder_2' not in kwargs and ('Text Encoder' in shared.opts.bnb_quantization or 'Text Encoder' in shared.opts.torchao_quantization):
kwargs['text_encoder_2'] = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder="text_encoder_2", cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
return kwargs
@@ -209,7 +214,7 @@ def load_transformer(file_path): # triggered by opts.sd_unet change
_transformer, _text_encoder_2 = load_flux_quanto(file_path)
if _transformer is not None:
transformer = _transformer
elif quant == 'fp8' or quant == 'fp4' or quant == 'nf4':
elif quant == 'fp8' or quant == 'fp4' or quant == 'nf4' or 'Model' in shared.opts.bnb_quantization:
_transformer, _text_encoder_2 = load_flux_bnb(file_path, diffusers_load_config)
if _transformer is not None:
transformer = _transformer
@@ -219,9 +224,15 @@ def load_transformer(file_path): # triggered by opts.sd_unet change
if _transformer is not None:
transformer = _transformer
else:
diffusers_load_config = model_quant.create_bnb_config(diffusers_load_config)
diffusers_load_config = model_quant.create_ao_config(diffusers_load_config)
transformer = diffusers.FluxTransformer2DModel.from_single_file(file_path, **diffusers_load_config)
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
if quant_args:
model_quant.load_bnb(f'Load model: type=Sana quant={quant_args}')
if not quant_args:
quant_args = model_quant.create_ao_config(quant_args)
if quant_args:
model_quant.load_torchao(f'Load model: type=Sana quant={quant_args}')
transformer = diffusers.FluxTransformer2DModel.from_single_file(file_path, **diffusers_load_config, **quant_args)
if transformer is None:
shared.log.error('Failed to load UNet model')
shared.opts.sd_unet = 'None'
@@ -350,11 +361,10 @@ def load_flux(checkpoint_info, diffusers_load_config): # triggered by opts.sd_ch
except Exception:
pass
allow_quant = 'gguf' not in (sd_unet.loaded_unet or '')
allow_quant = 'gguf' not in (sd_unet.loaded_unet or '') and (quant is None or quant == 'none')
fn = checkpoint_info.path
if (fn is None) or (not os.path.exists(fn) or os.path.isdir(fn)):
# transformer, text_encoder_2 = quant_flux_bnb(checkpoint_info, transformer, text_encoder_2)
kwargs = load_quants(kwargs, repo_id, cache_dir=shared.opts.diffusers_dir)
kwargs = load_quants(kwargs, repo_id, cache_dir=shared.opts.diffusers_dir, allow_quant=allow_quant)
kwargs = model_quant.create_bnb_config(kwargs, allow_quant)
kwargs = model_quant.create_ao_config(kwargs, allow_quant)
if fn.endswith('.safetensors') and os.path.isfile(fn):
+1 -1
View File
@@ -102,7 +102,7 @@ def load_quanto(msg='', silent=False):
quanto = optimum_quanto
fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
log.debug(f'Quantization: type=quanto version={quanto.__version__} fn={fn}') # pylint: disable=protected-access
if shared.opts.diffusers_offload_mode != 'none':
if shared.opts.diffusers_offload_mode in {'balanced', 'sequential'}:
shared.log.error(f'Quantization: type=quanto offload={shared.opts.diffusers_offload_mode} not supported')
return quanto
except Exception as e:
+19 -16
View File
@@ -7,20 +7,23 @@ from modules import shared, sd_models, devices, modelloader, model_quant
def load_quants(kwargs, repo_id, cache_dir):
if len(shared.opts.bnb_quantization) > 0:
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
if quant_args:
model_quant.load_bnb(f'Load model: type=Sana quant={quant_args}')
if not quant_args:
quant_args = model_quant.create_ao_config(quant_args)
load_args = kwargs.copy()
if not quant_args:
return kwargs
model_quant.load_bnb(f'Load model: type=SD3 quant={quant_args} args={load_args}')
if 'Model' in shared.opts.bnb_quantization and 'transformer' not in kwargs:
kwargs['transformer'] = diffusers.models.SanaTransformer2DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=cache_dir, **load_args, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'Text Encoder' in shared.opts.bnb_quantization and 'text_encoder_3' not in kwargs:
kwargs['text_encoder_3'] = transformers.AutoModelForCausalLM.from_pretrained(repo_id, subfolder="text_encoder", cache_dir=cache_dir, **load_args, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if quant_args:
model_quant.load_torchao(f'Load model: type=Sana quant={quant_args}')
if not quant_args:
return kwargs
load_args = kwargs.copy()
if 'transformer' not in kwargs and ('Model' in shared.opts.bnb_quantization or 'Model' in shared.opts.torchao_quantization):
kwargs['transformer'] = diffusers.models.SanaTransformer2DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=cache_dir, **load_args, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'text_encoder' not in kwargs and ('Text Encoder' in shared.opts.bnb_quantization or 'Text Encoder' in shared.opts.torchao_quantization):
kwargs['text_encoder'] = transformers.AutoModelForCausalLM.from_pretrained(repo_id, subfolder="text_encoder", cache_dir=cache_dir, **load_args, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
return kwargs
@@ -51,9 +54,9 @@ def load_sana(checkpoint_info, kwargs={}):
kwargs['variant'] = 'fp16'
if (fn is None) or (not os.path.exists(fn) or os.path.isdir(fn)):
kwargs = load_quants(kwargs, repo_id, cache_dir=shared.opts.diffusers_dir)
# kwargs = model_quant.create_bnb_config(kwargs)
# kwargs = model_quant.create_ao_config(kwargs)
# TODO sana: fails when quantized
# kwargs = load_quants(kwargs, repo_id, cache_dir=shared.opts.diffusers_dir)
pass
shared.log.debug(f'Load model: type=Sana repo="{repo_id}" args={list(kwargs)}')
t0 = time.time()
pipe = diffusers.SanaPipeline.from_pretrained(repo_id, cache_dir=shared.opts.diffusers_dir, **kwargs)
+17 -14
View File
@@ -42,29 +42,32 @@ def load_overrides(kwargs, cache_dir):
from modules import sd_vae
vae_file = sd_vae.vae_dict[shared.opts.sd_vae]
if os.path.exists(vae_file):
vae_config = os.path.join('configs', 'flux', 'vae', 'config.json')
vae_config = os.path.join('configs', 'sd3', 'vae', 'config.json')
kwargs['vae'] = diffusers.AutoencoderKL.from_single_file(vae_file, config=vae_config, cache_dir=cache_dir, torch_dtype=devices.dtype)
shared.log.debug(f'Load model: type=SD3 vae="{shared.opts.sd_vae}"')
except Exception as e:
shared.log.error(f"Load model: type=FLUX failed to load VAE: {e}")
shared.log.error(f"Load model: type=SD3 failed to load VAE: {e}")
shared.opts.sd_vae = 'None'
return kwargs
def load_quants(kwargs, repo_id, cache_dir):
if len(shared.opts.bnb_quantization) > 0:
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
quant_args = model_quant.create_ao_config(quant_args)
if not quant_args:
return kwargs
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
if quant_args:
model_quant.load_bnb(f'Load model: type=SD3 quant={quant_args}')
if 'Model' in shared.opts.bnb_quantization and 'transformer' not in kwargs:
kwargs['transformer'] = diffusers.SD3Transformer2DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'Text Encoder' in shared.opts.bnb_quantization and 'text_encoder_3' not in kwargs:
kwargs['text_encoder_3'] = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder="text_encoder_3", variant='fp16', cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if not quant_args:
quant_args = model_quant.create_ao_config(quant_args)
if quant_args:
model_quant.load_torchao(f'Load model: type=SD3 quant={quant_args}')
if not quant_args:
return kwargs
if 'Model' in shared.opts.bnb_quantization and 'transformer' not in kwargs:
kwargs['transformer'] = diffusers.SD3Transformer2DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'text_encoder_3' not in kwargs and ('Text Encoder' in shared.opts.bnb_quantization or 'Text Encoder' in shared.opts.torchao_quantization):
kwargs['text_encoder_3'] = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder="text_encoder_3", variant='fp16', cache_dir=cache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
return kwargs
+1 -1
View File
@@ -142,7 +142,7 @@ class UpscalerESRGAN(Upscaler):
if self.models.get(info.local_data_path, None) is not None:
shared.log.debug(f"Upscaler cached: type={self.name} model={info.local_data_path}")
return self.models[info.local_data_path]
state_dict = torch.load(info.local_data_path, map_location='cpu' if devices.device.type == 'mps' else None)
state_dict = torch.load(info.local_data_path, map_location='cpu' if devices.device.type in {'mps', 'cpu'} else None)
shared.log.info(f"Upscaler loaded: type={self.name} model={info.local_data_path}")
if "params_ema" in state_dict:
+9 -6
View File
@@ -1,15 +1,16 @@
import os
import sys
import traceback
from modules.upscaler import Upscaler, UpscalerData
from modules.ldsr.ldsr_model_arch import LDSR
from modules import shared, script_callbacks
import modules.ldsr.sd_hijack_autoencoder # pylint: disable=unused-import
import modules.ldsr.sd_hijack_ddpm_v1 # pylint: disable=unused-import
class UpscalerLDSR(Upscaler):
class Dummy:
pass
cls = Upscaler if not shared.native else Dummy
class UpscalerLDSR(cls):
def __init__(self, user_path):
self.name = "LDSR"
self.user_path = user_path
@@ -20,6 +21,9 @@ class UpscalerLDSR(Upscaler):
self.scalers = [scaler_data]
def load_model(self, path: str):
from modules.ldsr.ldsr_model_arch import LDSR
import modules.ldsr.sd_hijack_autoencoder # pylint: disable=unused-import
import modules.ldsr.sd_hijack_ddpm_v1 # pylint: disable=unused-import
# Remove incorrect project.yaml file if too big
yaml_path = os.path.join(self.model_path, "project.yaml")
old_model_path = os.path.join(self.model_path, "model.pth")
@@ -50,7 +54,6 @@ class UpscalerLDSR(Upscaler):
try:
return LDSR(model, yaml)
except Exception:
print("Error importing LDSR:", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
+3
View File
@@ -264,6 +264,7 @@ class YoloRestorer(Detailer):
mask_all = []
p.state = ''
prev_state = shared.state.job
for item in items:
if item.mask is None:
continue
@@ -271,6 +272,7 @@ class YoloRestorer(Detailer):
p.image_mask = [item.mask]
# mask_all.append(item.mask)
p.recursion = True
shared.state.job = 'Detailer'
pp = processing.process_images_inner(p)
del p.recursion
p.overlay_images = None # skip applying overlay twice
@@ -289,6 +291,7 @@ class YoloRestorer(Detailer):
p.image_mask = orig_p.get('image_mask', None)
p.state = orig_p.get('state', None)
p.ops = orig_p.get('ops', [])
shared.state.job = prev_state
shared.opts.data['mask_apply_overlay'] = orig_apply_overlay
np_image = np.array(image)
+24 -17
View File
@@ -6,6 +6,7 @@ import time
import inspect
import torch
import numpy as np
from PIL import Image
from modules import shared, errors, sd_models, processing, processing_vae, processing_helpers, sd_hijack_hypertile, prompt_parser_diffusers, timer, extra_networks
from modules.processing_callbacks import diffusers_callback_legacy, diffusers_callback, set_callbacks_p
from modules.processing_helpers import resize_hires, fix_prompts, calculate_base_steps, calculate_hires_steps, calculate_refiner_steps, get_generator, set_latents, apply_circular # pylint: disable=unused-import
@@ -22,7 +23,8 @@ def task_specific_kwargs(p, model):
if len(getattr(p, 'init_images', [])) > 0:
if isinstance(p.init_images[0], str):
p.init_images = [helpers.decode_base64_to_image(i, quiet=True) for i in p.init_images]
p.init_images = [i.convert('RGB') if i.mode != 'RGB' else i for i in p.init_images]
if isinstance(p.init_images[0], Image.Image):
p.init_images = [i.convert('RGB') if i.mode != 'RGB' else i for i in p.init_images if i is not None]
if (sd_models.get_diffusers_task(model) == sd_models.DiffusersTaskType.TEXT_2_IMAGE or len(getattr(p, 'init_images', [])) == 0) and not is_img2img_model:
p.ops.append('txt2img')
if hasattr(p, 'width') and hasattr(p, 'height'):
@@ -99,7 +101,7 @@ def task_specific_kwargs(p, model):
return task_args
def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2: typing.Optional[list]=None, negative_prompts_2: typing.Optional[list]=None, desc:str='', **kwargs):
def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:typing.Optional[list]=None, negative_prompts_2:typing.Optional[list]=None, prompt_attention:typing.Optional[str]=None, desc:typing.Optional[str]='', **kwargs):
t0 = time.time()
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
apply_circular(p.tiling, model)
@@ -118,7 +120,8 @@ def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2
clip_skip = kwargs.pop("clip_skip", 1)
parser = 'fixed'
if shared.opts.prompt_attention != 'fixed' and 'Onnx' not in model.__class__.__name__ and (
prompt_attention = prompt_attention or shared.opts.prompt_attention
if prompt_attention != 'fixed' and 'Onnx' not in model.__class__.__name__ and (
'StableDiffusion' in model.__class__.__name__ or
'StableCascade' in model.__class__.__name__ or
'Flux' in model.__class__.__name__
@@ -221,15 +224,20 @@ def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2
if 'img_guidance_scale' in possible and hasattr(p, 'image_cfg_scale'):
args['img_guidance_scale'] = p.image_cfg_scale
if 'generator' in possible:
args['generator'] = get_generator(p)
generator = get_generator(p)
args['generator'] = generator
else:
generator = None
if 'latents' in possible and getattr(p, "init_latent", None) is not None:
if sd_models.get_diffusers_task(model) == sd_models.DiffusersTaskType.TEXT_2_IMAGE:
args['latents'] = p.init_latent
if 'output_type' in possible:
if not hasattr(model, 'vae'):
args['output_type'] = 'np' # only set latent if model has vae
kwargs['output_type'] = 'np' # only set latent if model has vae
# stable cascade
# model specific
if 'Kandinsky' in model.__class__.__name__:
kwargs['output_type'] = 'np' # only set latent if model has vae
if 'StableCascade' in model.__class__.__name__:
kwargs.pop("guidance_scale") # remove
kwargs.pop("num_inference_steps") # remove
@@ -262,6 +270,9 @@ def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2
elif 'callback' in possible:
args['callback'] = diffusers_callback_legacy
if 'image' in kwargs:
p.init_images = kwargs['image'] if isinstance(kwargs['image'], list) else [kwargs['image']]
# handle remaining args
for arg in kwargs:
if arg in possible: # add kwargs
@@ -314,11 +325,12 @@ def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2
clean.pop('callback_steps', None)
clean.pop('callback_on_step_end', None)
clean.pop('callback_on_step_end_tensor_inputs', None)
if 'prompt' in clean:
if 'prompt' in clean and clean['prompt'] is not None:
clean['prompt'] = len(clean['prompt'])
if 'negative_prompt' in clean:
if 'negative_prompt' in clean and clean['negative_prompt'] is not None:
clean['negative_prompt'] = len(clean['negative_prompt'])
clean.pop('generator', None)
if generator is not None:
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):
@@ -328,16 +340,11 @@ def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2
if not debug_enabled and k.endswith('_embeds'):
del clean[k]
clean['prompt'] = 'embeds'
shared.log.debug(f'Diffuser pipeline: {model.__class__.__name__} task={sd_models.get_diffusers_task(model)} batch={p.iteration + 1}/{p.n_iter}x{p.batch_size} set={clean}')
task = str(sd_models.get_diffusers_task(model)).replace('DiffusersTaskType.', '')
shared.log.info(f'{desc}: pipeline={model.__class__.__name__} task={task} batch={p.iteration + 1}/{p.n_iter}x{p.batch_size} set={clean}')
if p.hdr_clamp or p.hdr_maximize or p.hdr_brightness != 0 or p.hdr_color != 0 or p.hdr_sharpen != 0:
txt = 'HDR:'
txt += f' Brightness={p.hdr_brightness}' if p.hdr_brightness != 0 else ' Brightness off'
txt += f' Color={p.hdr_color}' if p.hdr_color != 0 else ' Color off'
txt += f' Sharpen={p.hdr_sharpen}' if p.hdr_sharpen != 0 else ' Sharpen off'
txt += f' Clamp threshold={p.hdr_threshold} boundary={p.hdr_boundary}' if p.hdr_clamp else ' Clamp off'
txt += f' Maximize boundary={p.hdr_max_boundry} center={p.hdr_max_center}' if p.hdr_maximize else ' Maximize off'
shared.log.debug(txt)
shared.log.debug(f'HDR: clamp={p.hdr_clamp} maximize={p.hdr_maximize} brightness={p.hdr_brightness} color={p.hdr_color} sharpen={p.hdr_sharpen} threshold={p.hdr_threshold} boundary={p.hdr_boundary} max={p.hdr_max_boundry} center={p.hdr_max_center}')
if shared.cmd_opts.profile:
t1 = time.time()
shared.log.debug(f'Profile: pipeline args: {t1-t0:.2f}')
+13
View File
@@ -95,6 +95,10 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict = {}
if kwargs[key] is not None:
kwargs[key] = kwargs[key].chunk(2)[-1]
try:
current_noise_pred = kwargs.get("noise_pred", None)
if current_noise_pred is None:
current_noise_pred = kwargs.get("predicted_image_embedding", None)
if hasattr(pipe, "_unpack_latents") and hasattr(pipe, "vae_scale_factor"): # FLUX
if p.hr_resize_mode > 0 and (p.hr_upscaler != 'None' or p.hr_resize_mode == 5) and p.is_hr_pass:
width = max(getattr(p, 'width', 0), getattr(p, 'hr_upscale_to_x', 0))
@@ -103,8 +107,17 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict = {}
width = getattr(p, 'width', 0)
height = getattr(p, 'height', 0)
shared.state.current_latent = pipe._unpack_latents(kwargs['latents'], height, width, pipe.vae_scale_factor) # pylint: disable=protected-access
if current_noise_pred is not None:
shared.state.current_noise_pred = pipe._unpack_latents(current_noise_pred, height, width, pipe.vae_scale_factor) # pylint: disable=protected-access
else:
shared.state.current_noise_pred = current_noise_pred
else:
shared.state.current_latent = kwargs['latents']
shared.state.current_noise_pred = current_noise_pred
if hasattr(pipe, "scheduler") and hasattr(pipe.scheduler, "sigmas") and hasattr(pipe.scheduler, "step_index"):
shared.state.current_sigma = pipe.scheduler.sigmas[pipe.scheduler.step_index - 1]
shared.state.current_sigma_next = pipe.scheduler.sigmas[pipe.scheduler.step_index]
except Exception as e:
shared.log.error(f'Callback: {e}')
if shared.cmd_opts.profile and shared.profiler is not None:
+13 -8
View File
@@ -29,7 +29,7 @@ class StableDiffusionProcessing:
seed_resize_from_w: int = -1,
batch_size: int = 1,
n_iter: int = 1,
steps: int = 50,
steps: int = 20,
clip_skip: int = 1,
width: int = 1024,
height: int = 1024,
@@ -39,7 +39,7 @@ class StableDiffusionProcessing:
hr_sampler_name: str = None,
eta: float = None,
# guidance
cfg_scale: float = 7.0,
cfg_scale: float = 6.0,
cfg_end: float = 1,
diffusers_guidance_rescale: float = 0.7,
pag_scale: float = 0.0,
@@ -117,11 +117,18 @@ class StableDiffusionProcessing:
override_settings: Dict[str, Any] = {},
override_settings_restore_afterwards: bool = True,
# metadata
extra_generation_params: Dict[Any, Any] = {},
# extra_generation_params: Dict[Any, Any] = {},
# task_args: Dict[str, Any] = {},
# ops: List[str] = [],
**kwargs,
):
for k, v in kwargs.items():
setattr(self, k, v)
# extra args set by processing loop
self.task_args = {}
self.extra_generation_params = {}
# state items
self.state: str = ''
@@ -201,7 +208,6 @@ class StableDiffusionProcessing:
self.do_not_save_samples = do_not_save_samples
self.do_not_save_grid = do_not_save_grid
self.override_settings_restore_afterwards = override_settings_restore_afterwards
self.extra_generation_params = extra_generation_params
self.eta = eta
self.cfg_scale = cfg_scale
self.cfg_end = cfg_end
@@ -266,7 +272,6 @@ class StableDiffusionProcessing:
self.s_max = shared.opts.s_max
self.s_tmin = shared.opts.s_tmin
self.s_tmax = float('inf') # not representable as a standard ui option
self.task_args = {}
# ip adapter
self.ip_adapter_names = []
@@ -299,6 +304,9 @@ class StableDiffusionProcessing:
self.negative_embeds = []
self.negative_pooleds = []
def __str__(self):
return f'{self.__class__.__name__}: {self.__dict__}'
@property
def sd_model(self):
return shared.sd_model
@@ -339,9 +347,6 @@ class StableDiffusionProcessing:
def close(self):
self.sampler = None # pylint: disable=attribute-defined-outside-init
def __str__(self):
return f'{self.__class__.__name__}: {self.__dict__}'
class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
def __init__(self, **kwargs):
+18 -30
View File
@@ -16,7 +16,7 @@ skip_correction = False
def sharpen_tensor(tensor, ratio=0):
if ratio == 0:
debug("Sharpen: Early exit")
# debug("Sharpen: Early exit")
return tensor
kernel = torch.ones((3, 3), dtype=tensor.dtype, device=tensor.device)
kernel[1, 1] = 5.0
@@ -42,18 +42,18 @@ def soft_clamp_tensor(tensor, threshold=0.8, boundary=4):
min_replace = ((tensor + threshold) / (min_vals + threshold)) * (-boundary + threshold) - threshold
under_mask = tensor < -threshold
tensor = torch.where(over_mask, max_replace, torch.where(under_mask, min_replace, tensor))
debug(f'HDR soft clamp: threshold={threshold} boundary={boundary} shape={tensor.shape}')
# debug(f'HDR soft clamp: threshold={threshold} boundary={boundary} shape={tensor.shape}')
return tensor
def center_tensor(tensor, channel_shift=0.0, full_shift=0.0, offset=0.0):
if channel_shift == 0 and full_shift == 0 and offset == 0:
return tensor
debug(f'HDR center: Before Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).float().cpu().numpy()}')
# debug(f'HDR center: Before Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).float().cpu().numpy()}')
tensor -= tensor.mean(dim=(-1, -2), keepdim=True) * channel_shift
tensor -= tensor.mean() * full_shift - offset
debug(f'HDR center: channel-shift={channel_shift} full-shift={full_shift}')
debug(f'HDR center: After Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).float().cpu().numpy()}')
# debug(f'HDR center: channel-shift={channel_shift} full-shift={full_shift}')
# debug(f'HDR center: After Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).float().cpu().numpy()}')
return tensor
@@ -65,7 +65,7 @@ def maximize_tensor(tensor, boundary=1.0):
max_val = tensor.max()
normalization_factor = boundary / max(abs(min_val), abs(max_val))
tensor *= normalization_factor
debug(f'HDR maximize: boundary={boundary} min={min_val} max={max_val} factor={normalization_factor}')
# debug(f'HDR maximize: boundary={boundary} min={min_val} max={max_val} factor={normalization_factor}')
return tensor
@@ -78,7 +78,7 @@ def get_color(colorstr):
def color_adjust(tensor, colorstr, ratio):
color = get_color(colorstr)
debug(f'HDR tint: str={colorstr} color={color} ratio={ratio}')
# debug(f'HDR tint: str={colorstr} color={color} ratio={ratio}')
for i in range(3):
tensor[i] = center_tensor(tensor[i], full_shift=1, offset=color[i]*(ratio/2))
return tensor
@@ -86,35 +86,26 @@ def color_adjust(tensor, colorstr, ratio):
def correction(p, timestep, latent):
if timestep > 950 and p.hdr_clamp:
p.extra_generation_params["HDR clamp"] = f'{p.hdr_threshold}/{p.hdr_boundary}'
latent = soft_clamp_tensor(latent, threshold=p.hdr_threshold, boundary=p.hdr_boundary)
if 600 < timestep < 900 and (p.hdr_color != 0 or p.hdr_tint_ratio != 0):
if p.hdr_brightness != 0:
latent[0:1] = center_tensor(latent[0:1], full_shift=float(p.hdr_mode), offset=2*p.hdr_brightness) # Brightness
p.extra_generation_params["HDR brightness"] = f'{p.hdr_brightness}'
p.hdr_brightness = 0
if p.hdr_color != 0:
latent[1:] = center_tensor(latent[1:], channel_shift=p.hdr_color, full_shift=float(p.hdr_mode)) # Color
p.extra_generation_params["HDR color"] = f'{p.hdr_color}'
p.hdr_color = 0
if p.hdr_tint_ratio != 0:
latent = color_adjust(latent, p.hdr_color_picker, p.hdr_tint_ratio)
p.hdr_tint_ratio = 0
p.extra_generation_params["HDR clamp"] = f'{p.hdr_threshold}/{p.hdr_boundary}'
if 600 < timestep < 900 and p.hdr_color != 0:
latent[1:] = center_tensor(latent[1:], channel_shift=p.hdr_color, full_shift=float(p.hdr_mode)) # Color
p.extra_generation_params["HDR color"] = f'{p.hdr_color}'
if 600 < timestep < 900 and p.hdr_tint_ratio != 0:
latent = color_adjust(latent, p.hdr_color_picker, p.hdr_tint_ratio)
p.extra_generation_params["HDR tint"] = f'{p.hdr_tint_ratio}'
if timestep < 200 and (p.hdr_brightness != 0): # do it late so it doesn't change the composition
if p.hdr_brightness != 0:
latent[0:1] = center_tensor(latent[0:1], full_shift=float(p.hdr_mode), offset=2*p.hdr_brightness) # Brightness
p.extra_generation_params["HDR brightness"] = f'{p.hdr_brightness}'
p.hdr_brightness = 0
latent[0:1] = center_tensor(latent[0:1], full_shift=float(p.hdr_mode), offset=p.hdr_brightness) # Brightness
p.extra_generation_params["HDR brightness"] = f'{p.hdr_brightness}'
if timestep < 350 and p.hdr_sharpen != 0:
p.extra_generation_params["HDR sharpen"] = f'{p.hdr_sharpen}'
per_step_ratio = 2 ** (timestep / 250) * p.hdr_sharpen / 16
if abs(per_step_ratio) > 0.01:
debug(f"HDR Sharpen: timestep={timestep} ratio={p.hdr_sharpen} val={per_step_ratio}")
latent = sharpen_tensor(latent, ratio=per_step_ratio)
p.extra_generation_params["HDR sharpen"] = f'{p.hdr_sharpen}'
if 1 < timestep < 100 and p.hdr_maximize:
p.extra_generation_params["HDR max"] = f'{p.hdr_max_center}/{p.hdr_max_boundry}'
latent = center_tensor(latent, channel_shift=p.hdr_max_center, full_shift=1.0)
latent = maximize_tensor(latent, boundary=p.hdr_max_boundry)
p.extra_generation_params["HDR max"] = f'{p.hdr_max_center}/{p.hdr_max_boundry}'
return latent
@@ -129,9 +120,6 @@ def correction_callback(p, timestep, kwargs, initial: bool = False):
elif skip_correction:
return kwargs
latents = kwargs["latents"]
if debug_enabled:
debug('')
debug(f' Timestep: {timestep}')
# debug(f'HDR correction: latents={latents.shape}')
if len(latents.shape) == 4: # standard batched latent
for i in range(latents.shape[0]):
+9 -14
View File
@@ -57,7 +57,6 @@ def process_base(p: processing.StableDiffusionProcessing):
use_denoise_start = not is_txt2img() and p.refiner_start > 0 and p.refiner_start < 1
shared.sd_model = update_pipeline(shared.sd_model, p)
shared.log.info(f'Base: class={shared.sd_model.__class__.__name__}')
update_sampler(p, shared.sd_model)
timer.process.record('prepare')
base_args = set_pipeline_args(
@@ -90,7 +89,7 @@ def process_base(p: processing.StableDiffusionProcessing):
sd_models.move_model(shared.sd_model.unet, devices.device)
if hasattr(shared.sd_model, 'transformer'):
sd_models.move_model(shared.sd_model.transformer, devices.device)
extra_networks.activate(p, exclude=['text_encoder', 'text_encoder_2'])
extra_networks.activate(p, exclude=['text_encoder', 'text_encoder_2', 'text_encoder_3'])
hidiffusion.apply(p, shared.sd_model_type)
# if 'image' in base_args:
# base_args['image'] = set_latents(p)
@@ -195,23 +194,21 @@ def process_hires(p: processing.StableDiffusionProcessing, output):
if p.hr_force:
shared.state.job_count = 2 * p.n_iter
shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
shared.log.info(f'HiRes: class={shared.sd_model.__class__.__name__} sampler="{p.hr_sampler_name}"')
if 'Upscale' in shared.sd_model.__class__.__name__ or 'Flux' in shared.sd_model.__class__.__name__:
if 'Upscale' in shared.sd_model.__class__.__name__ or 'Flux' in shared.sd_model.__class__.__name__ or 'Kandinsky' in shared.sd_model.__class__.__name__:
output.images = processing_vae.vae_decode(latents=output.images, model=shared.sd_model, full_quality=p.full_quality, output_type='pil', width=p.width, height=p.height)
if p.is_control and hasattr(p, 'task_args') and p.task_args.get('image', None) is not None:
if hasattr(shared.sd_model, "vae") and output.images is not None and len(output.images) > 0:
output.images = processing_vae.vae_decode(latents=output.images, model=shared.sd_model, full_quality=p.full_quality, output_type='pil', width=p.hr_upscale_to_x, height=p.hr_upscale_to_y) # controlnet cannnot deal with latent input
p.task_args['image'] = output.images # replace so hires uses new output
update_sampler(p, shared.sd_model, second_pass=True)
orig_denoise = p.denoising_strength
p.denoising_strength = strength
hires_args = set_pipeline_args(
p=p,
model=shared.sd_model,
prompts=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts,
negative_prompts=[p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts,
prompts_2=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts,
negative_prompts_2=[p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts,
prompts=len(output.images)* [p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts,
negative_prompts=len(output.images) * [p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts,
prompts_2=len(output.images) * [p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts,
negative_prompts_2=len(output.images) * [p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts,
num_inference_steps=calculate_hires_steps(p),
eta=shared.opts.scheduler_eta,
guidance_scale=p.image_cfg_scale if p.image_cfg_scale is not None else p.cfg_scale,
@@ -286,14 +283,12 @@ def process_refine(p: processing.StableDiffusionProcessing, output):
image = output.images[i]
noise_level = round(350 * p.denoising_strength)
output_type='latent'
if 'Upscale' in shared.sd_refiner.__class__.__name__ or 'Flux' in shared.sd_refiner.__class__.__name__:
if 'Upscale' in shared.sd_refiner.__class__.__name__ or 'Flux' in shared.sd_refiner.__class__.__name__ or 'Kandinsky' in shared.sd_refiner.__class__.__name__:
image = processing_vae.vae_decode(latents=image, model=shared.sd_model, full_quality=p.full_quality, output_type='pil', width=p.width, height=p.height)
p.extra_generation_params['Noise level'] = noise_level
output_type = 'np'
if hasattr(p, 'task_args') and p.task_args.get('image', None) is not None and output is not None: # replace input with output so it can be used by hires/refine
p.task_args['image'] = image
shared.log.info(f'Refiner: class={shared.sd_refiner.__class__.__name__}')
update_sampler(p, shared.sd_refiner, second_pass=True)
shared.opts.prompt_attention = 'fixed'
refiner_args = set_pipeline_args(
p=p,
model=shared.sd_refiner,
@@ -310,6 +305,7 @@ def process_refine(p: processing.StableDiffusionProcessing, output):
image=image,
output_type=output_type,
clip_skip=p.clip_skip,
prompt_attention='fixed',
desc='Refiner',
)
shared.state.sampling_steps = refiner_args.get('prior_num_inference_steps', None) or p.steps or refiner_args.get('num_inference_steps', None)
@@ -479,7 +475,6 @@ def process_diffusers(p: processing.StableDiffusionProcessing):
timer.process.record('decode')
shared.sd_model = orig_pipeline
# shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
if p.state == '':
global last_p # pylint: disable=global-statement
+1 -2
View File
@@ -511,10 +511,9 @@ def get_generator(p):
else:
generator_device = devices.cpu if shared.opts.diffusers_generator_device == "CPU" else shared.device
try:
p.seeds = [seed if seed != -1 else get_fixed_seed(seed) for seed in p.seeds if seed]
devices.randn(p.seeds[0])
generator = [torch.Generator(generator_device).manual_seed(s) for s in p.seeds]
seeds = [g.initial_seed() for g in generator]
shared.log.debug(f'Torch generator: device={generator_device} seeds={seeds}')
except Exception as e:
shared.log.error(f'Torch generator: seeds={p.seeds} device={generator_device} {e}')
generator = None
+4 -4
View File
@@ -135,9 +135,9 @@ def full_vae_decode(latents, model):
latents = latents + shift_factor
vae_name = os.path.splitext(os.path.basename(sd_vae.loaded_vae_file))[0] if sd_vae.loaded_vae_file is not None else "default"
vae_stats = f'name="{vae_name}" dtype={model.vae.dtype} device={model.vae.device} upcast={upcast} slicing={getattr(model.vae, "use_slicing", None)} tiling={getattr(model.vae, "use_tiling", None)}'
latents_stats = f'shape={latents.shape} dtype={latents.dtype} device={latents.device}'
stats = f'vae {vae_stats} latents {latents_stats}'
vae_stats = f'vae="{vae_name}" dtype={model.vae.dtype} device={model.vae.device} upcast={upcast} slicing={getattr(model.vae, "use_slicing", None)} tiling={getattr(model.vae, "use_tiling", None)}'
latents_stats = f'latents={latents.shape}:{latents.device}:{latents.dtype}'
stats = f'{vae_stats} {latents_stats}'
log_debug(f'VAE config: {model.vae.config}')
try:
@@ -165,7 +165,7 @@ def full_vae_decode(latents, model):
t1 = time.time()
if debug:
log_debug(f'VAE memory: {shared.mem_mon.read()}')
shared.log.debug(f'VAE decode: {stats} time={round(t1-t0, 3)}')
shared.log.debug(f'Decode: {stats} time={round(t1-t0, 3)}')
return decoded
+11 -6
View File
@@ -1,4 +1,5 @@
import base64
import os
import io
import time
from pydantic import BaseModel, Field # pylint: disable=no-name-in-module
@@ -10,6 +11,8 @@ pending_tasks = {}
finished_tasks = []
recorded_results = []
recorded_results_limit = 2
debug = os.environ.get('SD_PREVIEW_DEBUG', None) is not None
debug_log = shared.log.trace if debug else lambda *args, **kwargs: None
def start_task(id_task):
@@ -48,6 +51,7 @@ class InternalProgressResponse(BaseModel):
queued: bool = Field(title="Whether the task is in queue")
paused: bool = Field(title="Whether the task is paused")
completed: bool = Field(title="Whether the task has already finished")
debug: bool = Field(title="Debug logging level")
progress: float = Field(default=None, title="Progress", description="The progress with a range of 0 to 1")
eta: float = Field(default=None, title="ETA in secs")
live_preview: str = Field(default=None, title="Live preview image", description="Current live preview; a data: uri")
@@ -60,8 +64,6 @@ def progressapi(req: ProgressRequest):
queued = req.id_task in pending_tasks
completed = req.id_task in finished_tasks
paused = shared.state.paused
if not active:
return InternalProgressResponse(job=shared.state.job, active=active, queued=queued, paused=paused, completed=completed, id_live_preview=-1, textinfo="Queued..." if queued else "Waiting...")
shared.state.job_count = max(shared.state.frame_count, shared.state.job_count, shared.state.job_no)
batch_x = max(shared.state.job_no, 0)
batch_y = max(shared.state.job_count, 1)
@@ -75,14 +77,17 @@ def progressapi(req: ProgressRequest):
eta = predicted - elapsed if predicted is not None else None
id_live_preview = req.id_live_preview
live_preview = None
shared.state.set_current_image()
if shared.opts.live_previews_enable and (shared.state.id_live_preview != req.id_live_preview) and (shared.state.current_image is not None):
updated = shared.state.set_current_image()
debug_log(f'Preview: job={shared.state.job} active={active} progress={current}/{total} step={shared.state.current_image_sampling_step}/{shared.state.sampling_step} request={id_live_preview} last={shared.state.id_live_preview} enabled={shared.opts.live_previews_enable} job={shared.state.preview_job} updated={updated} image={shared.state.current_image} elapsed={elapsed:.3f}')
if not active:
return InternalProgressResponse(job=shared.state.job, active=active, queued=queued, paused=paused, completed=completed, id_live_preview=-1, debug=debug, textinfo="Queued..." if queued else "Waiting...")
if shared.opts.live_previews_enable and (shared.state.id_live_preview != id_live_preview) and (shared.state.current_image is not None):
buffered = io.BytesIO()
shared.state.current_image.save(buffered, format='jpeg')
live_preview = f'data:image/jpeg;base64,{base64.b64encode(buffered.getvalue()).decode("ascii")}'
id_live_preview = shared.state.id_live_preview
id_live_preview = shared.state.id_live_preview
res = InternalProgressResponse(job=shared.state.job, active=active, queued=queued, paused=paused, completed=completed, progress=progress, eta=eta, live_preview=live_preview, id_live_preview=id_live_preview, textinfo=shared.state.textinfo)
res = InternalProgressResponse(job=shared.state.job, active=active, queued=queued, paused=paused, completed=completed, progress=progress, eta=eta, live_preview=live_preview, id_live_preview=id_live_preview, debug=debug, textinfo=shared.state.textinfo)
return res
+2
View File
@@ -170,6 +170,8 @@ def get_load_config(model_file, model_type, config_type='yaml'):
return 'configs/sd15'
if model_type == 'Stable Diffusion XL':
return 'configs/sdxl'
if model_type == 'Stable Diffusion XL Refiner':
return 'configs/sdxl-refiner'
if model_type == 'Stable Diffusion 3':
return 'configs/sd3'
if model_type == 'FLUX':
+30 -34
View File
@@ -7,34 +7,30 @@ from torch.nn.functional import silu
import diffusers
from modules import shared
shared.log.debug('Importing LDM')
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
import ldm.modules.attention
import ldm.modules.distributions.distributions
import ldm.modules.diffusionmodules.model
import ldm.modules.diffusionmodules.openaimodel
import ldm.models.diffusion.ddim
import ldm.models.diffusion.plms
import ldm.modules.encoders.modules
if not shared.native:
shared.log.warning('Importing LDM')
stdout = io.StringIO()
with contextlib.redirect_stdout(stdout):
import ldm.modules.attention
import ldm.modules.distributions.distributions
import ldm.modules.diffusionmodules.model
import ldm.modules.diffusionmodules.openaimodel
import ldm.models.diffusion.ddim
import ldm.models.diffusion.plms
import ldm.modules.encoders.modules
attention_CrossAttention_forward = ldm.modules.attention.CrossAttention.forward
diffusionmodules_model_nonlinearity = ldm.modules.diffusionmodules.model.nonlinearity
diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.AttnBlock.forward
ldm.modules.attention.MemoryEfficientCrossAttention = ldm.modules.attention.CrossAttention
ldm.modules.attention.BasicTransformerBlock.ATTENTION_MODES["softmax-xformers"] = ldm.modules.attention.CrossAttention
# silence new console spam from SD2
ldm.modules.attention.print = lambda *args: None
ldm.modules.diffusionmodules.model.print = lambda *args: None
import modules.textual_inversion.textual_inversion
from modules import devices, sd_hijack_optimizations
from modules import devices, sd_hijack_optimizations # pylint: disable=ungrouped-imports
from modules.textual_inversion import textual_inversion
from modules.hypernetworks import hypernetwork
attention_CrossAttention_forward = ldm.modules.attention.CrossAttention.forward
diffusionmodules_model_nonlinearity = ldm.modules.diffusionmodules.model.nonlinearity
diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.AttnBlock.forward
# new memory efficient cross attention blocks do not support hypernets and we already
# have memory efficient cross attention anyway, so this disables SD2.0's memory efficient cross attention
ldm.modules.attention.MemoryEfficientCrossAttention = ldm.modules.attention.CrossAttention
ldm.modules.attention.BasicTransformerBlock.ATTENTION_MODES["softmax-xformers"] = ldm.modules.attention.CrossAttention
# silence new console spam from SD2
ldm.modules.attention.print = lambda *args: None
ldm.modules.diffusionmodules.model.print = lambda *args: None
current_optimizer = SimpleNamespace(**{ "name": "none" })
def apply_optimizations():
@@ -86,9 +82,10 @@ def apply_optimizations():
def undo_optimizations():
ldm.modules.attention.CrossAttention.forward = hypernetwork.attention_CrossAttention_forward
ldm.modules.diffusionmodules.model.nonlinearity = diffusionmodules_model_nonlinearity
ldm.modules.diffusionmodules.model.AttnBlock.forward = diffusionmodules_model_AttnBlock_forward
if not shared.native:
ldm.modules.attention.CrossAttention.forward = hypernetwork.attention_CrossAttention_forward
ldm.modules.diffusionmodules.model.nonlinearity = diffusionmodules_model_nonlinearity
ldm.modules.diffusionmodules.model.AttnBlock.forward = diffusionmodules_model_AttnBlock_forward
def fix_checkpoint():
@@ -153,7 +150,7 @@ class StableDiffusionModelHijack:
clip = None
optimization_method = None
embedding_db = modules.textual_inversion.textual_inversion.EmbeddingDatabase()
embedding_db = textual_inversion.EmbeddingDatabase()
def __init__(self):
self.embedding_db.add_embedding_dir(shared.opts.embeddings_dir)
@@ -330,11 +327,10 @@ def register_buffer(self, name, attr):
setattr(self, name, attr)
ldm.models.diffusion.ddim.DDIMSampler.register_buffer = register_buffer
ldm.models.diffusion.plms.PLMSSampler.register_buffer = register_buffer
# Ensure samping from Guassian for DDPM follows types
ldm.modules.distributions.distributions.DiagonalGaussianDistribution.sample = lambda self: self.mean.to(self.parameters.dtype) + self.std.to(self.parameters.dtype) * torch.randn(self.mean.shape, dtype=self.parameters.dtype).to(device=self.parameters.device)
if not shared.native:
ldm.models.diffusion.ddim.DDIMSampler.register_buffer = register_buffer
ldm.models.diffusion.plms.PLMSSampler.register_buffer = register_buffer
ldm.modules.distributions.distributions.DiagonalGaussianDistribution.sample = lambda self: self.mean.to(self.parameters.dtype) + self.std.to(self.parameters.dtype) * torch.randn(self.mean.shape, dtype=self.parameters.dtype).to(device=self.parameters.device)
# Upcast BF16 to FP32
+8 -6
View File
@@ -108,7 +108,7 @@ def split_attention(layer: nn.Module, tile_size: int=256, min_tile_size: int=128
except Exception as e:
if not error_reported:
error_reported = True
log.error(f'Hypertile error: width={width} height={height} {e}')
log.error(f'Hypertile calculate: width={width} height={height} {e}')
out = forward(x, *args[1:], **kwargs)
return out
if x.ndim == 4: # VAE
@@ -155,7 +155,7 @@ def split_attention(layer: nn.Module, tile_size: int=256, min_tile_size: int=128
except Exception as e:
if not error_reported:
error_reported = True
log.error(f'Hypertile error: width={width} height={height} {e}')
log.error(f'Hypertile apply: cls={layer.__class__} width={width} height={height} {e}')
out = forward(x, *args[1:], **kwargs)
return out
return wrapper
@@ -195,9 +195,10 @@ def context_hypertile_vae(p):
return nullcontext()
else:
tile_size = shared.opts.hypertile_vae_tile if shared.opts.hypertile_vae_tile > 0 else max(128, 64 * min(p.width // 128, p.height // 128))
shared.log.info(f'Applying hypertile: vae={tile_size}')
min_tile_size = shared.opts.hypertile_unet_min_tile if shared.opts.hypertile_unet_min_tile > 0 else 128
shared.log.info(f'Applying hypertile: vae={min_tile_size}/{tile_size}')
p.extra_generation_params['Hypertile VAE'] = tile_size
return split_attention(vae, tile_size=tile_size, min_tile_size=128, swap_size=shared.opts.hypertile_vae_swap_size)
return split_attention(vae, tile_size=tile_size, min_tile_size=min_tile_size, swap_size=shared.opts.hypertile_vae_swap_size)
def context_hypertile_unet(p):
@@ -220,9 +221,10 @@ def context_hypertile_unet(p):
return nullcontext()
else:
tile_size = shared.opts.hypertile_unet_tile if shared.opts.hypertile_unet_tile > 0 else max(128, 64 * min(p.width // 128, p.height // 128))
shared.log.info(f'Applying hypertile: unet={tile_size}')
min_tile_size = shared.opts.hypertile_unet_min_tile if shared.opts.hypertile_unet_min_tile > 0 else 128
shared.log.info(f'Applying hypertile: unet={min_tile_size}/{tile_size}')
p.extra_generation_params['Hypertile UNet'] = tile_size
return split_attention(unet, tile_size=tile_size, min_tile_size=128, swap_size=shared.opts.hypertile_unet_swap_size, depth=shared.opts.hypertile_unet_depth)
return split_attention(unet, tile_size=tile_size, min_tile_size=min_tile_size, swap_size=shared.opts.hypertile_unet_swap_size, depth=shared.opts.hypertile_unet_depth)
def hypertile_set(p, hr=False):
+5 -2
View File
@@ -4,13 +4,16 @@ import math
import psutil
import torch
from torch import einsum
from ldm.util import default
from einops import rearrange
from modules import shared, errors, devices
from modules.hypernetworks import hypernetwork
from .sub_quadratic_attention import efficient_dot_product_attention # pylint: disable=relative-beyond-top-level
if not shared.native:
from ldm.util import default
if shared.opts.cross_attention_optimization == "xFormers":
try:
import xformers.ops # pylint: disable=import-error
@@ -47,7 +50,7 @@ def split_cross_attention_forward_v1(self, x, context=None, mask=None): # pylint
h = self.heads
q_in = self.to_q(x)
context = default(context, x)
context = default(context, x) # pylint: disable=possibly-used-before-assignment
context_k, context_v = hypernetwork.apply_hypernetworks(shared.loaded_hypernetworks, context)
k_in = self.to_k(context_k)
+15 -14
View File
@@ -1,7 +1,7 @@
import torch
from packaging import version
from modules import devices
from modules import devices, shared
from modules.sd_hijack_utils import CondFunc
@@ -59,21 +59,22 @@ ddpm_edit_hijack = None
def hijack_ddpm_edit():
global ddpm_edit_hijack # pylint: disable=global-statement
if not ddpm_edit_hijack:
CondFunc('modules.hijack.ddpm_edit.LatentDiffusion.decode_first_stage', first_stage_sub, first_stage_cond)
CondFunc('modules.hijack.ddpm_edit.LatentDiffusion.encode_first_stage', first_stage_sub, first_stage_cond)
CondFunc('modules.hijack.ddpm_edit.LatentDiffusion.decode_first_stage', first_stage_sub, first_stage_cond) # pylint: disable=possibly-used-before-assignment
CondFunc('modules.hijack.ddpm_edit.LatentDiffusion.encode_first_stage', first_stage_sub, first_stage_cond) # pylint: disable=possibly-used-before-assignment
ddpm_edit_hijack = CondFunc('modules.hijack.ddpm_edit.LatentDiffusion.apply_model', apply_model, unet_needs_upcast)
unet_needs_upcast = lambda *args, **kwargs: devices.unet_needs_upcast # pylint: disable=unnecessary-lambda-assignment
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.apply_model', apply_model, unet_needs_upcast)
CondFunc('ldm.modules.diffusionmodules.openaimodel.timestep_embedding', lambda orig_func, timesteps, *args, **kwargs: orig_func(timesteps, *args, **kwargs).to(torch.float32 if timesteps.dtype == torch.int64 else devices.dtype_unet), unet_needs_upcast)
if version.parse(torch.__version__) <= version.parse("1.13.2") or torch.cuda.is_available():
CondFunc('ldm.modules.diffusionmodules.util.GroupNorm32.forward', lambda orig_func, self, *args, **kwargs: orig_func(self.float(), *args, **kwargs), unet_needs_upcast)
CondFunc('ldm.modules.attention.GEGLU.forward', lambda orig_func, self, x: orig_func(self.float(), x.float()).to(devices.dtype_unet), unet_needs_upcast)
CondFunc('open_clip.transformer.ResidualAttentionBlock.__init__', lambda orig_func, *args, **kwargs: (kwargs.update({'act_layer': GELUHijack}) and False) or orig_func(*args, **kwargs), lambda _, *args, **kwargs: kwargs.get('act_layer') is None or kwargs['act_layer'] == torch.nn.GELU)
if not shared.native:
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.apply_model', apply_model, unet_needs_upcast)
CondFunc('ldm.modules.diffusionmodules.openaimodel.timestep_embedding', lambda orig_func, timesteps, *args, **kwargs: orig_func(timesteps, *args, **kwargs).to(torch.float32 if timesteps.dtype == torch.int64 else devices.dtype_unet), unet_needs_upcast)
if version.parse(torch.__version__) <= version.parse("1.13.2") or torch.cuda.is_available():
CondFunc('ldm.modules.diffusionmodules.util.GroupNorm32.forward', lambda orig_func, self, *args, **kwargs: orig_func(self.float(), *args, **kwargs), unet_needs_upcast)
CondFunc('ldm.modules.attention.GEGLU.forward', lambda orig_func, self, x: orig_func(self.float(), x.float()).to(devices.dtype_unet), unet_needs_upcast)
CondFunc('open_clip.transformer.ResidualAttentionBlock.__init__', lambda orig_func, *args, **kwargs: (kwargs.update({'act_layer': GELUHijack}) and False) or orig_func(*args, **kwargs), lambda _, *args, **kwargs: kwargs.get('act_layer') is None or kwargs['act_layer'] == torch.nn.GELU)
first_stage_cond = lambda _, self, *args, **kwargs: devices.unet_needs_upcast and self.model.diffusion_model.dtype == torch.float16 # pylint: disable=unnecessary-lambda-assignment
first_stage_sub = lambda orig_func, self, x, **kwargs: orig_func(self, x.to(devices.dtype_vae), **kwargs) # pylint: disable=unnecessary-lambda-assignment
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.decode_first_stage', first_stage_sub, first_stage_cond)
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.encode_first_stage', first_stage_sub, first_stage_cond)
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.get_first_stage_encoding', lambda orig_func, *args, **kwargs: orig_func(*args, **kwargs).float(), first_stage_cond)
first_stage_cond = lambda _, self, *args, **kwargs: devices.unet_needs_upcast and self.model.diffusion_model.dtype == torch.float16 # pylint: disable=unnecessary-lambda-assignment
first_stage_sub = lambda orig_func, self, x, **kwargs: orig_func(self, x.to(devices.dtype_vae), **kwargs) # pylint: disable=unnecessary-lambda-assignment
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.decode_first_stage', first_stage_sub, first_stage_cond)
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.encode_first_stage', first_stage_sub, first_stage_cond)
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.get_first_stage_encoding', lambda orig_func, *args, **kwargs: orig_func(*args, **kwargs).float(), first_stage_cond)
+66 -27
View File
@@ -15,7 +15,6 @@ import torch
import safetensors.torch
import accelerate
from omegaconf import OmegaConf
from ldm.util import instantiate_from_config
from modules import paths, shared, shared_state, modelloader, devices, script_callbacks, sd_vae, sd_unet, errors, sd_models_config, sd_models_compile, sd_hijack_accelerate, sd_detect
from modules.timer import Timer, process as process_timer
from modules.memstats import memory_stats
@@ -221,19 +220,12 @@ def copy_diffuser_options(new_pipe, orig_pipe):
new_pipe.is_sdxl = getattr(orig_pipe, 'is_sdxl', False) # a1111 compatibility item
new_pipe.is_sd2 = getattr(orig_pipe, 'is_sd2', False)
new_pipe.is_sd1 = getattr(orig_pipe, 'is_sd1', True)
add_noise_pred_to_diffusers_callback(new_pipe)
if new_pipe.has_accelerate:
set_accelerate(new_pipe)
def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True):
if sd_model is None:
shared.log.warning(f'{op} is not loaded')
return
if hasattr(sd_model, "watermark"):
sd_model.watermark = NoWatermark()
if not (hasattr(sd_model, "has_accelerate") and sd_model.has_accelerate):
sd_model.has_accelerate = False
def set_vae_options(sd_model, vae = None, op: str = 'model'):
if hasattr(sd_model, "vae"):
if vae is not None:
sd_model.vae = vae
@@ -253,7 +245,13 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True):
sd_model.disable_vae_slicing()
if hasattr(sd_model, "enable_vae_tiling"):
if shared.opts.diffusers_vae_tiling:
shared.log.debug(f'Setting {op}: component=VAE tiling=True')
if hasattr(sd_model, 'vae') and hasattr(sd_model.vae, 'config') and hasattr(sd_model.vae.config, 'sample_size') and isinstance(sd_model.vae.config.sample_size, int):
sd_model.vae.tile_sample_min_size = int(shared.opts.diffusers_vae_tile_size)
sd_model.vae.tile_latent_min_size = int(sd_model.vae.config.sample_size / (2 ** (len(sd_model.vae.config.block_out_channels) - 1)))
sd_model.vae.tile_overlap_factor = float(shared.opts.diffusers_vae_tile_overlap)
shared.log.debug(f'Setting {op}: component=VAE tiling=True tile={sd_model.vae.tile_sample_min_size} overlap={sd_model.vae.tile_overlap_factor}')
else:
shared.log.debug(f'Setting {op}: component=VAE tiling=True')
sd_model.enable_vae_tiling()
else:
sd_model.disable_vae_tiling()
@@ -261,6 +259,18 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True):
shared.log.debug(f'Setting {op}: component=VQVAE upcast=True')
sd_model.vqvae.to(torch.float32) # vqvae is producing nans in fp16
def set_diffuser_options(sd_model, vae = None, op: str = 'model', offload=True):
if sd_model is None:
shared.log.warning(f'{op} is not loaded')
return
if hasattr(sd_model, "watermark"):
sd_model.watermark = NoWatermark()
if not (hasattr(sd_model, "has_accelerate") and sd_model.has_accelerate):
sd_model.has_accelerate = False
set_vae_options(sd_model, vae, op)
set_diffusers_attention(sd_model)
if shared.opts.diffusers_fuse_projections and hasattr(sd_model, 'fuse_qkv_projections'):
@@ -499,7 +509,7 @@ def apply_balanced_offload(sd_model, exclude=[]):
module = module.to(devices.cpu, non_blocking=True)
used_gpu -= module_size
if not cached:
shared.log.debug(f'Offload: type=balanced module={module_name} cls={module.__class__.__name__} dtype={module.dtype} quant={getattr(module, "quantization_method", None)} params={offload_hook_instance.param_map[module_name]:.3f} size={offload_hook_instance.offload_map[module_name]:.3f}')
shared.log.debug(f'Model module={module_name} type={module.__class__.__name__} dtype={module.dtype} quant={getattr(module, "quantization_method", None)} params={offload_hook_instance.param_map[module_name]:.3f} size={offload_hook_instance.offload_map[module_name]:.3f}')
debug_move(f'Offload: type=balanced op={"move" if do_offload else "skip"} gpu={prev_gpu:.3f}:{used_gpu:.3f} perc={perc_gpu:.2f} ram={used_ram:.3f} current={module.device} dtype={module.dtype} quant={getattr(module, "quantization_method", None)} module={module.__class__.__name__} size={module_size:.3f}')
except Exception as e:
if 'out of memory' in str(e):
@@ -533,7 +543,7 @@ def apply_balanced_offload(sd_model, exclude=[]):
fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
debug_move(f'Apply offload: time={t:.2f} type=balanced fn={fn}')
if not cached:
shared.log.info(f'Offload: type=balanced op=apply class={sd_model.__class__.__name__} modules={len(offload_hook_instance.offload_map)} size={offload_hook_instance.model_size():.3f}')
shared.log.info(f'Model class={sd_model.__class__.__name__} modules={len(offload_hook_instance.offload_map)} size={offload_hook_instance.model_size():.3f}')
return sd_model
@@ -975,6 +985,8 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
if model_type not in ['Stable Cascade']: # need a special-case
sd_unet.load_unet(sd_model)
add_noise_pred_to_diffusers_callback(sd_model)
timer.record("load")
if op == 'refiner':
@@ -1195,7 +1207,7 @@ def set_diffuser_pipe(pipe, new_pipe_type):
'StableVideoDiffusionPipeline',
]
n = getattr(pipe.__class__, '__name__', '')
has_errors = False
if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE:
clean_diffuser_pipe(pipe)
@@ -1204,7 +1216,7 @@ def set_diffuser_pipe(pipe, new_pipe_type):
# skip specific pipelines
cls = pipe.__class__.__name__
if n in exclude:
if cls in exclude:
return pipe
if 'Onnx' in cls:
return pipe
@@ -1212,9 +1224,9 @@ def set_diffuser_pipe(pipe, new_pipe_type):
new_pipe = None
# in some cases we want to reset the pipeline to parent as they dont have their own variants
if new_pipe_type == DiffusersTaskType.IMAGE_2_IMAGE or new_pipe_type == DiffusersTaskType.INPAINTING:
if n == 'StableDiffusionPAGPipeline':
if cls == 'StableDiffusionPAGPipeline':
pipe = switch_pipe(diffusers.StableDiffusionPipeline, pipe)
if n == 'StableDiffusionXLPAGPipeline':
if cls == 'StableDiffusionXLPAGPipeline':
pipe = switch_pipe(diffusers.StableDiffusionXLPipeline, pipe)
sd_checkpoint_info = getattr(pipe, "sd_checkpoint_info", None)
@@ -1241,8 +1253,8 @@ def set_diffuser_pipe(pipe, new_pipe_type):
return pipe
except Exception as e: # pylint: disable=unused-variable
shared.log.warning(f'Pipeline class change failed: type={new_pipe_type} pipeline={cls} {e}')
return pipe
else:
has_errors = True
if not hasattr(pipe, 'config') or has_errors:
try: # maybe a wrapper pipeline so just change the class
if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE:
pipe.__class__ = diffusers.pipelines.auto_pipeline._get_task_class(diffusers.pipelines.auto_pipeline.AUTO_TEXT2IMAGE_PIPELINES_MAPPING, cls) # pylint: disable=protected-access
@@ -1254,11 +1266,11 @@ def set_diffuser_pipe(pipe, new_pipe_type):
pipe.__class__ = diffusers.pipelines.auto_pipeline._get_task_class(diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING, cls) # pylint: disable=protected-access
new_pipe = pipe
else:
shared.log.error(f'Pipeline class change failed: type={new_pipe_type} pipeline={cls}')
shared.log.error(f'Pipeline class set failed: type={new_pipe_type} pipeline={cls}')
return pipe
except Exception as e: # pylint: disable=unused-variable
shared.log.warning(f'Pipeline class set failed: type={new_pipe_type} pipeline={cls} {e}')
return pipe
has_errors = True
# if pipe.__class__ == new_pipe.__class__:
# return pipe
@@ -1269,16 +1281,23 @@ def set_diffuser_pipe(pipe, new_pipe_type):
new_pipe.has_accelerate = has_accelerate
new_pipe.current_attn_name = current_attn_name
new_pipe.default_scheduler = default_scheduler
new_pipe.image_encoder = image_encoder
new_pipe.feature_extractor = feature_extractor
if image_encoder is not None:
new_pipe.image_encoder = image_encoder
if feature_extractor is not None:
new_pipe.feature_extractor = feature_extractor
if new_pipe.__class__.__name__ == 'FluxPipeline':
new_pipe.register_modules(image_encoder = image_encoder)
new_pipe.register_modules(feature_extractor = feature_extractor)
new_pipe.is_sdxl = getattr(pipe, 'is_sdxl', False) # a1111 compatibility item
new_pipe.is_sd2 = getattr(pipe, 'is_sd2', False)
new_pipe.is_sd1 = getattr(pipe, 'is_sd1', True)
if hasattr(new_pipe, 'watermark'):
new_pipe.watermark = NoWatermark()
add_noise_pred_to_diffusers_callback(new_pipe)
if hasattr(new_pipe, 'pipe'): # also handle nested pipelines
new_pipe.pipe = set_diffuser_pipe(new_pipe.pipe, new_pipe_type)
add_noise_pred_to_diffusers_callback(new_pipe.pipe)
fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
shared.log.debug(f"Pipeline class change: original={cls} target={new_pipe.__class__.__name__} device={pipe.device} fn={fn}") # pylint: disable=protected-access
@@ -1305,6 +1324,8 @@ def set_diffusers_attention(pipe):
module.set_attn_processor(p.HunyuanAttnProcessor2_0())
elif module.__class__.__name__ in ['AuraFlowTransformer2DModel']:
module.set_attn_processor(p.AuraFlowAttnProcessor2_0())
elif 'KandinskyCombinedPipeline' in pipe.__class__.__name__:
pass
elif 'Transformer' in module.__class__.__name__:
pass # unknown transformer so probably dont want to force attention processor
else:
@@ -1333,13 +1354,25 @@ def set_diffusers_attention(pipe):
pipe.current_attn_name = shared.opts.cross_attention_optimization
def add_noise_pred_to_diffusers_callback(pipe):
if not hasattr(pipe, "_callback_tensor_inputs"):
return pipe
if pipe.__class__.__name__.startswith("StableDiffusion"):
pipe._callback_tensor_inputs.append("noise_pred") # pylint: disable=protected-access
elif pipe.__class__.__name__.startswith("StableCascade"):
pipe.prior_pipe._callback_tensor_inputs.append("predicted_image_embedding") # pylint: disable=protected-access
elif hasattr(pipe, "scheduler") and "flow" in pipe.scheduler.__class__.__name__.lower():
pipe._callback_tensor_inputs.append("noise_pred") # pylint: disable=protected-access
elif hasattr(pipe, "default_scheduler") and "flow" in pipe.default_scheduler.__class__.__name__.lower():
pipe._callback_tensor_inputs.append("noise_pred") # pylint: disable=protected-access
return pipe
def get_native(pipe: diffusers.DiffusionPipeline):
if hasattr(pipe, "vae") and hasattr(pipe.vae.config, "sample_size"):
# Stable Diffusion
size = pipe.vae.config.sample_size
size = pipe.vae.config.sample_size # Stable Diffusion
elif hasattr(pipe, "movq") and hasattr(pipe.movq.config, "sample_size"):
# Kandinsky
size = pipe.movq.config.sample_size
size = pipe.movq.config.sample_size # Kandinsky
elif hasattr(pipe, "unet") and hasattr(pipe.unet.config, "sample_size"):
size = pipe.unet.config.sample_size
else:
@@ -1348,6 +1381,7 @@ def get_native(pipe: diffusers.DiffusionPipeline):
def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'):
from ldm.util import instantiate_from_config
from modules import lowvram, sd_hijack
checkpoint_info = checkpoint_info or select_checkpoint(op=op)
if checkpoint_info is None:
@@ -1588,6 +1622,11 @@ def unload_model_weights(op='model'):
model_data.sd_model = None
devices.torch_gc(force=True)
shared.log.debug(f'Unload weights {op}: {memory_stats()}')
if not shared.opts.lora_legacy:
from modules.lora import networks
networks.loaded_networks.clear()
networks.previously_loaded_networks.clear()
networks.lora_cache.clear()
elif op == 'refiner':
if model_data.sd_refiner:
if not shared.native:
+37 -25
View File
@@ -315,9 +315,9 @@ def optimize_openvino(sd_model):
shared.compiled_model_state.partitioned_modules.clear()
shared.compiled_model_state = CompiledModelState()
shared.compiled_model_state.is_compiled = True
shared.compiled_model_state.first_pass = True if not shared.opts.cuda_compile_precompile else False
shared.compiled_model_state.first_pass_vae = True if not shared.opts.cuda_compile_precompile else False
shared.compiled_model_state.first_pass_refiner = True if not shared.opts.cuda_compile_precompile else False
shared.compiled_model_state.first_pass = not shared.opts.cuda_compile_precompile
shared.compiled_model_state.first_pass_vae = not shared.opts.cuda_compile_precompile
shared.compiled_model_state.first_pass_refiner = not shared.opts.cuda_compile_precompile
sd_models.set_accelerate(sd_model)
except Exception as e:
shared.log.warning(f"Model compile: task=OpenVINO: {e}")
@@ -531,31 +531,43 @@ def torchao_quantization(sd_model):
return sd_model
def openvino_recompile_model(p, hires=False, refiner=False): # recompile if a parameter changes
if 'Model' in shared.opts.cuda_compile and shared.opts.cuda_compile_backend != 'none':
if shared.opts.cuda_compile_backend == "openvino_fx":
compile_height = p.height if not hires and hasattr(p, 'height') else p.hr_upscale_to_y
compile_width = p.width if not hires and hasattr(p, 'width') else p.hr_upscale_to_x
if (shared.compiled_model_state is None or
(not shared.compiled_model_state.first_pass
and (shared.compiled_model_state.height != compile_height
or shared.compiled_model_state.width != compile_width
or shared.compiled_model_state.batch_size != p.batch_size))):
if refiner:
shared.log.info("OpenVINO: Recompiling refiner")
sd_models.unload_model_weights(op='refiner')
sd_models.reload_model_weights(op='refiner')
else:
shared.log.info("OpenVINO: Recompiling base model")
sd_models.unload_model_weights(op='model')
sd_models.reload_model_weights(op='model')
shared.compiled_model_state.height = compile_height
shared.compiled_model_state.width = compile_width
shared.compiled_model_state.batch_size = p.batch_size
def openvino_recompile_model(p, hires=False, refiner=False): # recompile if a parameter changes # pylint: disable=unused-argument
if shared.opts.cuda_compile_backend == "openvino_fx" and 'Model' in shared.opts.cuda_compile:
compile_height = p.height if not hires and hasattr(p, 'height') else p.hr_upscale_to_y
compile_width = p.width if not hires and hasattr(p, 'width') else p.hr_upscale_to_x
"""
if shared.compiled_model_state is None:
openvino_first_pass = True
else:
if refiner:
openvino_first_pass = shared.compiled_model_state.first_pass_refiner
else:
openvino_first_pass = shared.compiled_model_state.first_pass
if (shared.compiled_model_state is None or
(
not openvino_first_pass
and (
shared.compiled_model_state.height != compile_height
or shared.compiled_model_state.width != compile_width
or shared.compiled_model_state.batch_size != p.batch_size
)
)):
if refiner:
shared.log.info("OpenVINO: Recompiling refiner")
sd_models.unload_model_weights(op='refiner')
sd_models.reload_model_weights(op='refiner')
else:
shared.log.info("OpenVINO: Recompiling base model")
sd_models.unload_model_weights(op='model')
sd_models.reload_model_weights(op='model')
"""
shared.compiled_model_state.height = compile_height
shared.compiled_model_state.width = compile_width
shared.compiled_model_state.batch_size = p.batch_size
def openvino_post_compile(op="base"): # delete unet after OpenVINO compile
if 'Model' in shared.opts.cuda_compile and shared.opts.cuda_compile_backend == "openvino_fx":
if shared.opts.cuda_compile_backend == "openvino_fx" and 'Model' in shared.opts.cuda_compile:
if shared.compiled_model_state.first_pass and op == "base":
shared.compiled_model_state.first_pass = False
if not shared.opts.openvino_disable_memory_cleanup and hasattr(shared.sd_model, "unet"):
+19 -7
View File
@@ -61,7 +61,11 @@ def create_sampler(name, model):
model.prior_pipe.scheduler = copy.deepcopy(model.default_scheduler)
model.prior_pipe.scheduler.config.clip_sample = False
config = {k: v for k, v in model.scheduler.config.items() if not k.startswith('_')}
shared.log.debug(f'Sampler: sampler=default class={current}: {config}')
shared.log.debug(f'Sampler: "default" class={current}: {config}')
if "flow" in model.scheduler.__class__.__name__.lower():
shared.state.prediction_type = "flow_prediction"
elif hasattr(model.scheduler, "config") and hasattr(model.scheduler.config, "prediction_type"):
shared.state.prediction_type = model.scheduler.config.prediction_type
return model.scheduler
config = find_sampler_config(name)
if config is None or config.constructor is None:
@@ -73,10 +77,10 @@ def create_sampler(name, model):
sampler.config = config
sampler.name = name
sampler.initialize(p=None)
shared.log.debug(f'Sampler: sampler="{name}" config={config.options}')
shared.log.debug(f'Sampler: "{name}" config={config.options}')
return sampler
elif shared.native:
FlowModels = ['Flux', 'StableDiffusion3', 'Lumina', 'AuraFlow', 'Sana']
FlowModels = ['Flux', 'StableDiffusion3', 'Lumina', 'AuraFlow', 'Sana', 'HunyuanVideoPipeline']
if 'KDiffusion' in model.__class__.__name__:
return None
if not any(x in model.__class__.__name__ for x in FlowModels) and 'FlowMatch' in name:
@@ -88,14 +92,22 @@ def create_sampler(name, model):
sampler = config.constructor(model)
if sampler is None:
sampler = config.constructor(model)
if sampler is None or sampler.sampler is None:
model.scheduler = copy.deepcopy(model.default_scheduler)
else:
model.scheduler = sampler.sampler
if not hasattr(model, 'scheduler_config'):
model.scheduler_config = sampler.sampler.config.copy() if hasattr(sampler.sampler, 'config') else {}
model.scheduler = sampler.sampler
model.scheduler_config = sampler.sampler.config.copy() if hasattr(sampler, 'sampler') and hasattr(sampler.sampler, 'config') else {}
if hasattr(model, "prior_pipe") and hasattr(model.prior_pipe, "scheduler"):
model.prior_pipe.scheduler = sampler.sampler
model.prior_pipe.scheduler.config.clip_sample = False
clean_config = {k: v for k, v in sampler.config.items() if v is not None and v is not False}
shared.log.debug(f'Sampler: sampler="{sampler.name}" class="{model.scheduler.__class__.__name__} config={clean_config}')
if "flow" in model.scheduler.__class__.__name__.lower():
shared.state.prediction_type = "flow_prediction"
elif hasattr(model.scheduler, "config") and hasattr(model.scheduler.config, "prediction_type"):
shared.state.prediction_type = model.scheduler.config.prediction_type
clean_config = {k: v for k, v in model.scheduler.config.items() if not k.startswith('_') and v is not None and v is not False}
name = sampler.name if sampler is not None and sampler.sampler is not None else 'Default'
shared.log.debug(f'Sampler: "{name}" class={model.scheduler.__class__.__name__} config={clean_config}')
return sampler.sampler
else:
return None
+8 -3
View File
@@ -52,9 +52,12 @@ def single_sample_to_image(sample, approximation=None):
if len(sample.shape) == 4 and sample.shape[0]: # likely animatediff latent
sample = sample.permute(1, 0, 2, 3)[0]
if approximation == 2: # TAESD
if shared.opts.live_preview_downscale and (sample.shape[-1] > 128 or sample.shape[-2] > 128):
scale = 128 / max(sample.shape[-1], sample.shape[-2])
sample = torch.nn.functional.interpolate(sample.unsqueeze(0), scale_factor=[scale, scale], mode='bilinear', align_corners=False)[0]
if (len(sample.shape) == 3 or len(sample.shape) == 4) and shared.opts.live_preview_downscale and (sample.shape[-1] > 128 or sample.shape[-2] > 128):
try:
scale = 128 / max(sample.shape[-1], sample.shape[-2])
sample = torch.nn.functional.interpolate(sample.unsqueeze(0), scale_factor=[scale, scale], mode='bilinear', align_corners=False)[0]
except Exception:
pass
x_sample = sd_vae_taesd.decode(sample)
x_sample = (1.0 + x_sample) / 2.0 # preview requires smaller range
elif shared.sd_model_type == 'sc' and approximation != 3:
@@ -71,6 +74,8 @@ def single_sample_to_image(sample, approximation=None):
warn_once(f"Unknown latent decode type: {approximation}")
return Image.new(mode="RGB", size=(512, 512))
try:
if x_sample.shape[0] > 4:
return Image.new(mode="RGB", size=(512, 512))
if x_sample.dtype == torch.bfloat16:
x_sample.to(torch.float16)
transform = T.ToPILImage()
+11 -10
View File
@@ -235,16 +235,9 @@ class DiffusionSampler:
if 'beta_end' in self.config and shared.opts.schedulers_beta_end > 0:
self.config['beta_end'] = shared.opts.schedulers_beta_end
if 'shift' in self.config:
if shared.opts.schedulers_shift == 0:
if 'StableDiffusion3' in model.__class__.__name__:
self.config['shift'] = 3
if 'Flux' in model.__class__.__name__:
self.config['shift'] = 1
else:
self.config['shift'] = shared.opts.schedulers_shift
self.config['shift'] = shared.opts.schedulers_shift if shared.opts.schedulers_shift > 0 else 3
if 'use_dynamic_shifting' in self.config:
if 'Flux' in model.__class__.__name__:
self.config['use_dynamic_shifting'] = shared.opts.schedulers_dynamic_shift
self.config['use_dynamic_shifting'] = True if shared.opts.schedulers_shift <= 0 else shared.opts.schedulers_dynamic_shift
if 'use_beta_sigmas' in self.config and 'sigma_schedule' in self.config:
self.config['use_beta_sigmas'] = 'StableDiffusion3' in model.__class__.__name__
if 'rescale_betas_zero_snr' in self.config:
@@ -275,7 +268,15 @@ class DiffusionSampler:
debug(f'Sampler: config={self.config}')
debug(f'Sampler: signature={possible}')
# shared.log.debug(f'Sampler: sampler="{name}" config={self.config}')
self.sampler = constructor(**self.config)
sampler = constructor(**self.config)
accept_sigmas = "sigmas" in set(inspect.signature(sampler.set_timesteps).parameters.keys())
accepts_timesteps = "timesteps" in set(inspect.signature(sampler.set_timesteps).parameters.keys())
debug(f'Sampler: sampler="{name}" sigmas={accept_sigmas} timesteps={accepts_timesteps}')
if ('Flux' in model.__class__.__name__) and (not accept_sigmas):
shared.log.warning(f'Sampler: sampler="{name}" does not accept sigmas')
self.sampler = None
return
self.sampler = sampler
if name == 'DC Solver':
if not hasattr(self.sampler, 'dc_ratios'):
pass
+3 -2
View File
@@ -153,8 +153,9 @@ def decode(latents):
if not previous_warnings:
previous_warnings = True
shared.log.warning(f'TAESD unsupported model type: {model_class}')
return Image.new('RGB', (8, 8), color = (0, 0, 0))
vae = taesd_models[f'{model_class}-decoder']
# return Image.new('RGB', (8, 8), color = (0, 0, 0))
return latents
vae = taesd_models.get(f'{model_class}-decoder', None)
if vae is None:
model_path = os.path.join(paths.models_path, "TAESD", f"tae{model_class}_decoder.pth")
download_model(model_path)
+16 -11
View File
@@ -93,7 +93,6 @@ elif os.environ.get("HF_HUB", None) is not None:
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):
@@ -366,7 +365,7 @@ def list_samplers():
def temp_disable_extensions():
disable_safe = ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-agent-scheduler', 'clip-interrogator-ext', 'stable-diffusion-webui-rembg', 'sd-extension-chainner', 'stable-diffusion-webui-images-browser']
disable_diffusers = ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-animatediff', 'Lora']
disable_diffusers = ['sd-webui-controlnet', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris', 'sd-webui-animatediff']
disable_themes = ['sd-webui-lobe-theme', 'cozy-nest', 'sdnext-modernui']
disable_original = []
disabled = []
@@ -422,6 +421,8 @@ def temp_disable_extensions():
for ext in disable_original:
if ext.lower() not in opts.disabled_extensions:
disabled.append(ext)
if not opts.lora_legacy:
disabled.append('Lora')
cmd_opts.controlnet_loglevel = 'WARNING'
return disabled
@@ -475,7 +476,7 @@ options_templates.update(options_section(('sd', "Models & Loading"), {
"sd_model_checkpoint": OptionInfo(default_checkpoint, "Base model", DropdownEditable, lambda: {"choices": list_checkpoint_titles()}, refresh=refresh_checkpoints),
"sd_model_refiner": OptionInfo('None', "Refiner model", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_titles()}, refresh=refresh_checkpoints),
"sd_unet": OptionInfo("None", "UNET model", gr.Dropdown, lambda: {"choices": shared_items.sd_unet_items()}, refresh=shared_items.refresh_unet_list),
"latent_history": OptionInfo(16, "Latent history size", gr.Slider, {"minimum": 1, "maximum": 100, "step": 1}),
"latent_history": OptionInfo(16, "Latent history size", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
"offload_sep": OptionInfo("<h2>Model Offloading</h2>", "", gr.HTML),
"diffusers_move_base": OptionInfo(False, "Move base model to CPU when using refiner", gr.Checkbox, {"visible": False }),
@@ -504,6 +505,8 @@ options_templates.update(options_section(('vae_encoder', "Variable Auto Encoder"
"no_half_vae": OptionInfo(False if not cmd_opts.use_openvino else True, "Full precision (--no-half-vae)"),
"diffusers_vae_slicing": OptionInfo(True, "VAE slicing", gr.Checkbox, {"visible": native}),
"diffusers_vae_tiling": OptionInfo(cmd_opts.lowvram or cmd_opts.medvram, "VAE tiling", gr.Checkbox, {"visible": native}),
"diffusers_vae_tile_size": OptionInfo(1024, "VAE tile size", gr.Slider, {"minimum": 256, "maximum": 4096, "step": 8 }),
"diffusers_vae_tile_overlap": OptionInfo(0.25, "VAE tile overlap", gr.Slider, {"minimum": 0, "maximum": 0.95, "step": 0.05 }),
"sd_vae_sliced_encode": OptionInfo(False, "VAE sliced encode", gr.Checkbox, {"visible": not native}),
"nan_skip": OptionInfo(False, "Skip Generation if NaN found in latents", gr.Checkbox),
"rollback_vae": OptionInfo(False, "Attempt VAE roll back for NaN values"),
@@ -605,12 +608,12 @@ options_templates.update(options_section(('quantization', "Quantization Settings
options_templates.update(options_section(('advanced', "Pipeline Modifiers"), {
"token_merging_sep": OptionInfo("<h2>Token Merging</h2>", "", gr.HTML),
"token_merging_method": OptionInfo("None", "Token merging method", gr.Radio, {"choices": ['None', 'ToMe', 'ToDo']}),
"token_merging_method": OptionInfo("None", "Token merging enabled", gr.Radio, {"choices": ['None', 'ToMe', 'ToDo']}),
"tome_ratio": OptionInfo(0.0, "ToMe token merging ratio", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.05}),
"todo_ratio": OptionInfo(0.0, "ToDo token merging ratio", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.05}),
"freeu_sep": OptionInfo("<h2>FreeU</h2>", "", gr.HTML),
"freeu_enabled": OptionInfo(False, "FreeU"),
"freeu_enabled": OptionInfo(False, "FreeU enabled"),
"freeu_b1": OptionInfo(1.2, "1st stage backbone", gr.Slider, {"minimum": 1.0, "maximum": 2.0, "step": 0.01}),
"freeu_b2": OptionInfo(1.4, "2nd stage backbone", gr.Slider, {"minimum": 1.0, "maximum": 2.0, "step": 0.01}),
"freeu_s1": OptionInfo(0.9, "1st stage skip", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
@@ -620,9 +623,10 @@ options_templates.update(options_section(('advanced', "Pipeline Modifiers"), {
"pag_apply_layers": OptionInfo("m0", "PAG layer names"),
"hypertile_sep": OptionInfo("<h2>HyperTile</h2>", "", gr.HTML),
"hypertile_hires_only": OptionInfo(False, "HiRes pass only"),
"hypertile_unet_enabled": OptionInfo(False, "UNet Enabled"),
"hypertile_unet_tile": OptionInfo(0, "UNet tile size", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 8}),
"hypertile_hires_only": OptionInfo(False, "HiRes pass only"),
"hypertile_unet_tile": OptionInfo(0, "UNet max tile size", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 8}),
"hypertile_unet_min_tile": OptionInfo(0, "UNet min tile size", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 8}),
"hypertile_unet_swap_size": OptionInfo(1, "UNet swap size", gr.Slider, {"minimum": 1, "maximum": 10, "step": 1}),
"hypertile_unet_depth": OptionInfo(0, "UNet depth", gr.Slider, {"minimum": 0, "maximum": 4, "step": 1}),
"hypertile_vae_enabled": OptionInfo(False, "VAE Enabled", gr.Checkbox),
@@ -817,8 +821,8 @@ options_templates.update(options_section(('sampler-params', "Sampler Settings"),
'schedulers_beta_start': OptionInfo(0, "Beta start", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.00001, "visible": native}),
'schedulers_beta_end': OptionInfo(0, "Beta end", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.00001, "visible": native}),
'schedulers_timesteps_range': OptionInfo(1000, "Timesteps range", gr.Slider, {"minimum": 250, "maximum": 4000, "step": 1, "visible": native}),
'schedulers_shift': OptionInfo(0, "Sampler shift", gr.Slider, {"minimum": 0.1, "maximum": 10, "step": 0.1, "visible": native}),
'schedulers_dynamic_shift': OptionInfo(True, "Sampler dynamic shift", gr.Checkbox, {"visible": native}),
'schedulers_shift': OptionInfo(3, "Sampler shift", gr.Slider, {"minimum": 0.1, "maximum": 10, "step": 0.1, "visible": False}),
'schedulers_dynamic_shift': OptionInfo(True, "Sampler dynamic shift", gr.Checkbox, {"visible": False}),
# managed from ui.py for backend original k-diffusion
"always_batch_cond_uncond": OptionInfo(False, "Disable conditional batching", gr.Checkbox, {"visible": not native}),
@@ -924,8 +928,9 @@ options_templates.update(options_section(('extra_networks', "Networks"), {
"lora_preferred_name": OptionInfo("filename", "LoRA preferred name", gr.Radio, {"choices": ["filename", "alias"], "visible": False}),
"lora_add_hashes_to_infotext": OptionInfo(False, "LoRA add hash info to metadata"),
"lora_fuse_diffusers": OptionInfo(True, "LoRA fuse directly to model"),
"lora_force_diffusers": OptionInfo(False if not cmd_opts.use_openvino else True, "LoRA force loading of all models using Diffusers"),
"lora_maybe_diffusers": OptionInfo(False, "LoRA force loading of specific models using Diffusers"),
"lora_legacy": OptionInfo(not native, "LoRA load using legacy method"),
"lora_force_diffusers": OptionInfo(False if not cmd_opts.use_openvino else True, "LoRA load using Diffusers method"),
"lora_maybe_diffusers": OptionInfo(False, "LoRA load using Diffusers method for selected models"),
"lora_apply_tags": OptionInfo(0, "LoRA auto-apply tags", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}),
"lora_in_memory_limit": OptionInfo(0, "LoRA memory cache", gr.Slider, {"minimum": 0, "maximum": 24, "step": 1}),
"lora_quant": OptionInfo("NF4","LoRA precision when quantized", gr.Radio, {"choices": ["NF4", "FP4"]}),
+1 -1
View File
@@ -68,7 +68,7 @@ def get_pipelines():
'Stable Diffusion Instruct': getattr(diffusers, 'StableDiffusionInstructPix2PixPipeline', None),
'Stable Diffusion Upscale': getattr(diffusers, 'StableDiffusionUpscalePipeline', None),
'Stable Diffusion XL': getattr(diffusers, 'StableDiffusionXLPipeline', None),
'Stable Diffusion XL Refiner': getattr(diffusers, 'StableDiffusionXLPipeline', None),
'Stable Diffusion XL Refiner': getattr(diffusers, 'StableDiffusionXLImg2ImgPipeline', None),
'Stable Diffusion XL Img2Img': getattr(diffusers, 'StableDiffusionXLImg2ImgPipeline', None),
'Stable Diffusion XL Inpaint': getattr(diffusers, 'StableDiffusionXLInpaintPipeline', None),
'Stable Diffusion XL Instruct': getattr(diffusers, 'StableDiffusionXLInstructPix2PixPipeline', None),
+45 -20
View File
@@ -1,7 +1,7 @@
import os
import time
import datetime
from modules.errors import log
from modules.errors import log, display
class State:
@@ -17,11 +17,17 @@ class State:
sampling_step = 0
sampling_steps = 0
current_latent = None
current_noise_pred = None
current_sigma = None
current_sigma_next = None
current_image = None
current_image_sampling_step = 0
id_live_preview = 0
textinfo = None
prediction_type = "epsilon"
api = False
disable_preview = False
preview_job = -1
time_start = None
need_restart = False
server_start = time.time()
@@ -102,8 +108,12 @@ class State:
self.current_image = None
self.current_image_sampling_step = 0
self.current_latent = None
self.current_noise_pred = None
self.current_sigma = None
self.current_sigma_next = None
self.id_live_preview = 0
self.interrupted = False
self.preview_job = -1
self.job = title
self.job_count = -1
self.frame_count = -1
@@ -113,7 +123,8 @@ class State:
self.sampling_step = 0
self.skipped = False
self.textinfo = None
self.api = api if api is not None else self.api
self.prediction_type = "epsilon"
self.api = api or self.api
self.time_start = time.time()
if self.debug_output:
log.debug(f'State begin: {self.job}')
@@ -125,39 +136,53 @@ class State:
# fn = f'{sys._getframe(2).f_code.co_name}:{sys._getframe(1).f_code.co_name}' # pylint: disable=protected-access
# log.debug(f'Access state.end: {fn}') # pylint: disable=protected-access
self.time_start = time.time()
if self.debug_output:
log.debug(f'State end: {self.job} time={time.time() - self.time_start:.2f}')
self.job = ""
self.job_count = 0
self.job_no = 0
self.frame_count = 0
self.preview_job = -1
self.paused = False
self.interrupted = False
self.skipped = False
self.api = api if api is not None else self.api
self.api = api or self.api
modules.devices.torch_gc()
def set_current_image(self):
if self.job == 'VAE': # avoid generating preview while vae is running
return
if self.job == 'VAE' or self.job == 'Upscale': # avoid generating preview while vae is running
return False
from modules.shared import opts, cmd_opts
if cmd_opts.lowvram or self.api or not opts.live_previews_enable or opts.show_progress_every_n_steps <= 0:
return
if abs(self.sampling_step - self.current_image_sampling_step) >= opts.show_progress_every_n_steps:
self.do_set_current_image()
if cmd_opts.lowvram or self.api or (not opts.live_previews_enable) or (opts.show_progress_every_n_steps <= 0):
return False
if (not self.disable_preview) and (abs(self.sampling_step - self.current_image_sampling_step) >= opts.show_progress_every_n_steps):
return self.do_set_current_image()
return False
def do_set_current_image(self):
if self.current_latent is None:
return
from modules.shared import opts
import modules.sd_samplers # pylint: disable=W0621
if (self.current_latent is None) or self.disable_preview or (self.preview_job == self.job_no):
return False
from modules import shared, sd_samplers
self.preview_job = self.job_no
try:
image = modules.sd_samplers.samples_to_image_grid(self.current_latent) if opts.show_progress_grid else modules.sd_samplers.sample_to_image(self.current_latent)
self.assign_current_image(image)
sample = self.current_latent
self.current_image_sampling_step = self.sampling_step
except Exception:
# log.error(f'Error setting current image: step={self.sampling_step} {e}')
pass
try:
if self.current_noise_pred is not None and self.current_sigma is not None and self.current_sigma_next is not None:
original_sample = sample - (self.current_noise_pred * (self.current_sigma_next-self.current_sigma))
if self.prediction_type in {"epsilon", "flow_prediction"}:
sample = original_sample - (self.current_noise_pred * self.current_sigma)
elif self.prediction_type == "v_prediction":
sample = self.current_noise_pred * (-self.current_sigma / (self.current_sigma**2 + 1) ** 0.5) + (original_sample / (self.current_sigma**2 + 1)) # pylint: disable=invalid-unary-operand-type
except Exception:
pass # ignore sigma errors
image = sd_samplers.samples_to_image_grid(sample) if shared.opts.show_progress_grid else sd_samplers.sample_to_image(sample)
self.assign_current_image(image)
self.preview_job = -1
return True
except Exception as e:
self.preview_job = -1
log.error(f'State image: last={self.id_live_preview} step={self.sampling_step} {e}')
display(e, 'State image')
return False
def assign_current_image(self, image):
self.current_image = image
+3 -3
View File
@@ -103,9 +103,9 @@ def apply_wildcards_to_prompt(prompt, all_wildcards, seed=-1, silent=False):
prompt, replaced_file, not_found = apply_file_wildcards(prompt, [], [], recursion=0, seed=seed)
t2 = time.time()
if replaced and not silent:
shared.log.debug(f'Wildcards applied: {replaced} path="{shared.opts.wildcards_dir}" type=style time={t1-t0:.2f}')
shared.log.debug(f'Apply wildcards: {replaced} path="{shared.opts.wildcards_dir}" type=style time={t1-t0:.2f}')
if (len(replaced_file) > 0 or len(not_found) > 0) and not silent:
shared.log.debug(f'Wildcards applied: {replaced_file} missing: {not_found} path="{shared.opts.wildcards_dir}" type=file time={t2-t2:.2f} ')
shared.log.debug(f'Apply wildcards: {replaced_file} missing: {not_found} path="{shared.opts.wildcards_dir}" type=file time={t2-t2:.2f} ')
if old_state is not None:
random.setstate(old_state)
return prompt
@@ -158,7 +158,7 @@ def apply_styles_to_extra(p, style: Style):
fields.append(f'{k}={v}')
else:
skipped.append(f'{k}={v}')
shared.log.debug(f'Applying style: name="{style.name}" extra={fields} skipped={skipped} reference={True if reference_style else False}')
shared.log.debug(f'Apply style: name="{style.name}" extra={fields} skipped={skipped} reference={True if reference_style else False}')
class StyleDatabase:
+167
View File
@@ -0,0 +1,167 @@
"""
source: https://github.com/ali-vilab/TeaCache/blob/main/TeaCache4LTX-Video/teacache_ltx.py
"""
from typing import Any, Dict, Optional, Tuple
import numpy as np
import torch
from diffusers.models.modeling_outputs import Transformer2DModelOutput
from diffusers.utils import is_torch_version, scale_lora_layers, unscale_lora_layers
def teacache_forward(
self,
hidden_states: torch.Tensor,
encoder_hidden_states: torch.Tensor,
timestep: torch.LongTensor,
encoder_attention_mask: torch.Tensor,
num_frames: int,
height: int,
width: int,
rope_interpolation_scale: Optional[Tuple[float, float, float]] = None,
attention_kwargs: Optional[Dict[str, Any]] = None,
return_dict: bool = True,
) -> torch.Tensor:
if attention_kwargs is not None:
attention_kwargs = attention_kwargs.copy()
lora_scale = attention_kwargs.pop("scale", 1.0)
else:
lora_scale = 1.0
scale_lora_layers(self, lora_scale)
image_rotary_emb = self.rope(hidden_states, num_frames, height, width, rope_interpolation_scale)
# convert encoder_attention_mask to a bias the same way we do for attention_mask
if encoder_attention_mask is not None and encoder_attention_mask.ndim == 2:
encoder_attention_mask = (1 - encoder_attention_mask.to(hidden_states.dtype)) * -10000.0
encoder_attention_mask = encoder_attention_mask.unsqueeze(1)
batch_size = hidden_states.size(0)
hidden_states = self.proj_in(hidden_states)
temb, embedded_timestep = self.time_embed(
timestep.flatten(),
batch_size=batch_size,
hidden_dtype=hidden_states.dtype,
)
temb = temb.view(batch_size, -1, temb.size(-1))
embedded_timestep = embedded_timestep.view(batch_size, -1, embedded_timestep.size(-1))
encoder_hidden_states = self.caption_projection(encoder_hidden_states)
encoder_hidden_states = encoder_hidden_states.view(batch_size, -1, hidden_states.size(-1))
if self.enable_teacache:
inp = hidden_states.clone()
temb_ = temb.clone()
inp = self.transformer_blocks[0].norm1(inp)
num_ada_params = self.transformer_blocks[0].scale_shift_table.shape[0]
ada_values = self.transformer_blocks[0].scale_shift_table[None, None] + temb_.reshape(batch_size, temb_.size(1), num_ada_params, -1)
shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = ada_values.unbind(dim=2)
modulated_inp = inp * (1 + scale_msa) + shift_msa
if self.cnt == 0 or self.cnt == self.num_steps-1:
should_calc = True
self.accumulated_rel_l1_distance = 0
else:
coefficients = [2.14700694e+01, -1.28016453e+01, 2.31279151e+00, 7.92487521e-01, 9.69274326e-03]
rescale_func = np.poly1d(coefficients)
self.accumulated_rel_l1_distance += rescale_func(((modulated_inp-self.previous_modulated_input).abs().mean() / self.previous_modulated_input.abs().mean()).cpu().item())
if self.accumulated_rel_l1_distance < self.rel_l1_thresh:
should_calc = False
else:
should_calc = True
self.accumulated_rel_l1_distance = 0
self.previous_modulated_input = modulated_inp
self.cnt += 1
if self.cnt == self.num_steps:
self.cnt = 0
if self.enable_teacache:
if not should_calc:
hidden_states += self.previous_residual
else:
ori_hidden_states = hidden_states.clone()
for block in self.transformer_blocks:
if torch.is_grad_enabled() and self.gradient_checkpointing:
def create_custom_forward(module, return_dict=None):
def custom_forward(*inputs):
if return_dict is not None:
return module(*inputs, return_dict=return_dict)
else:
return module(*inputs)
return custom_forward
ckpt_kwargs: Dict[str, Any] = {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {}
hidden_states = torch.utils.checkpoint.checkpoint(
create_custom_forward(block),
hidden_states,
encoder_hidden_states,
temb,
image_rotary_emb,
encoder_attention_mask,
**ckpt_kwargs,
)
else:
hidden_states = block(
hidden_states=hidden_states,
encoder_hidden_states=encoder_hidden_states,
temb=temb,
image_rotary_emb=image_rotary_emb,
encoder_attention_mask=encoder_attention_mask,
)
scale_shift_values = self.scale_shift_table[None, None] + embedded_timestep[:, :, None]
shift, scale = scale_shift_values[:, :, 0], scale_shift_values[:, :, 1]
hidden_states = self.norm_out(hidden_states)
hidden_states = hidden_states * (1 + scale) + shift
self.previous_residual = hidden_states - ori_hidden_states
else:
for block in self.transformer_blocks:
if torch.is_grad_enabled() and self.gradient_checkpointing:
def create_custom_forward(module, return_dict=None):
def custom_forward(*inputs):
if return_dict is not None:
return module(*inputs, return_dict=return_dict)
else:
return module(*inputs)
return custom_forward
ckpt_kwargs: Dict[str, Any] = {"use_reentrant": False} if is_torch_version(">=", "1.11.0") else {}
hidden_states = torch.utils.checkpoint.checkpoint(
create_custom_forward(block),
hidden_states,
encoder_hidden_states,
temb,
image_rotary_emb,
encoder_attention_mask,
**ckpt_kwargs,
)
else:
hidden_states = block(
hidden_states=hidden_states,
encoder_hidden_states=encoder_hidden_states,
temb=temb,
image_rotary_emb=image_rotary_emb,
encoder_attention_mask=encoder_attention_mask,
)
scale_shift_values = self.scale_shift_table[None, None] + embedded_timestep[:, :, None]
shift, scale = scale_shift_values[:, :, 0], scale_shift_values[:, :, 1]
hidden_states = self.norm_out(hidden_states)
hidden_states = hidden_states * (1 + scale) + shift
output = self.proj_out(hidden_states)
unscale_lora_layers(self, lora_scale)
if not return_dict:
return (output,)
return Transformer2DModelOutput(sample=output)
@@ -418,7 +418,7 @@ class EmbeddingDatabase:
self.word_embeddings.update(sorted_word_embeddings)
displayed_embeddings = (tuple(self.word_embeddings.keys()), tuple(self.skipped_embeddings.keys()))
if self.previously_displayed_embeddings != displayed_embeddings:
if self.previously_displayed_embeddings != displayed_embeddings and shared.opts.diffusers_enable_embed:
self.previously_displayed_embeddings = displayed_embeddings
t1 = time.time()
shared.log.info(f"Load network: type=embeddings loaded={len(self.word_embeddings)} skipped={len(self.skipped_embeddings)} time={t1-t0:.2f}")
+2 -5
View File
@@ -54,11 +54,9 @@ def list_themes():
huggingface = {x['id'] for x in huggingface if x['status'] == 'RUNNING' and 'test' not in x['id'].lower()}
huggingface = [f'huggingface/{x}' for x in huggingface]
themes = sorted(gradio) + sorted(huggingface, key=str.casefold)
modules.shared.log.debug(f'UI themes available: type=={modules.shared.opts.theme_type} gradio={len(gradio)} huggingface={len(huggingface)}')
elif modules.shared.opts.theme_type == 'Standard':
builtin = list_builtin_themes()
themes = sorted(builtin)
modules.shared.log.debug(f'UI themes available: type={modules.shared.opts.theme_type} themes={len(builtin)}')
elif modules.shared.opts.theme_type == 'Modern':
ext = next((e for e in modules.extensions.extensions if e.name == 'sdnext-modernui'), None)
if ext is None:
@@ -76,7 +74,6 @@ def list_themes():
if len(themes) == 0:
themes.append('modern/Default')
themes = sorted(themes)
modules.shared.log.debug(f'UI themes available: type={modules.shared.opts.theme_type} themes={len(themes)}')
else:
modules.shared.log.error(f'UI themes: type={modules.shared.opts.theme_type} unknown')
themes = []
@@ -109,11 +106,11 @@ def reload_gradio_theme():
return None
elif modules.shared.opts.theme_type == 'Standard':
gradio_theme = gr.themes.Base(**default_font_params)
modules.shared.log.info(f'UI theme: type={modules.shared.opts.theme_type} name="{theme_name}"')
modules.shared.log.info(f'UI theme: type={modules.shared.opts.theme_type} name="{theme_name}" available={len(available_themes)}')
return 'sdnext.css'
elif modules.shared.opts.theme_type == 'Modern':
gradio_theme = gr.themes.Base(**default_font_params)
modules.shared.log.info(f'UI theme: type={modules.shared.opts.theme_type} name="{theme_name}"')
modules.shared.log.info(f'UI theme: type={modules.shared.opts.theme_type} name="{theme_name}" available={len(available_themes)}')
return 'base.css'
elif modules.shared.opts.theme_type == 'None':
if theme_name.startswith('gradio/'):
+8 -6
View File
@@ -277,7 +277,7 @@ class ExtraNetworksPage:
self.html += ''.join(htmls)
self.page_time = time.time()
self.html = f"<div id='~tabname_{self_name_id}_subdirs' class='extra-network-subdirs'>{subdirs_html}</div><div id='~tabname_{self_name_id}_cards' class='extra-network-cards'>{self.html}</div>"
shared.log.debug(f"Networks: page='{self.name}' items={len(self.items)} subfolders={len(subdirs)} tab={tabname} folders={self.allowed_directories_for_previews()} list={self.list_time:.2f} thumb={self.preview_time:.2f} desc={self.desc_time:.2f} info={self.info_time:.2f} workers={shared.max_workers} sort={shared.opts.extra_networks_sort}")
shared.log.debug(f"Networks: page='{self.name}' items={len(self.items)} subfolders={len(subdirs)} tab={tabname} folders={self.allowed_directories_for_previews()} list={self.list_time:.2f} thumb={self.preview_time:.2f} desc={self.desc_time:.2f} info={self.info_time:.2f} workers={shared.max_workers}")
if len(self.missing_thumbs) > 0:
threading.Thread(target=self.create_thumb).start()
return self.patch(self.html, tabname)
@@ -464,14 +464,16 @@ def register_pages():
from modules.ui_extra_networks_checkpoints import ExtraNetworksPageCheckpoints
from modules.ui_extra_networks_vae import ExtraNetworksPageVAEs
from modules.ui_extra_networks_styles import ExtraNetworksPageStyles
from modules.ui_extra_networks_history import ExtraNetworksPageHistory
from modules.ui_extra_networks_textual_inversion import ExtraNetworksPageTextualInversion
register_page(ExtraNetworksPageCheckpoints())
register_page(ExtraNetworksPageVAEs())
register_page(ExtraNetworksPageStyles())
register_page(ExtraNetworksPageHistory())
register_page(ExtraNetworksPageTextualInversion())
if shared.native:
if shared.opts.latent_history > 0:
from modules.ui_extra_networks_history import ExtraNetworksPageHistory
register_page(ExtraNetworksPageHistory())
if shared.opts.diffusers_enable_embed:
from modules.ui_extra_networks_textual_inversion import ExtraNetworksPageTextualInversion
register_page(ExtraNetworksPageTextualInversion())
if not shared.opts.lora_legacy:
from modules.ui_extra_networks_lora import ExtraNetworksPageLora
register_page(ExtraNetworksPageLora())
if shared.opts.hypernetwork_enabled:
-4
View File
@@ -57,8 +57,6 @@ def html_css(css: str):
usercss = os.path.join(data_path, "user.css") if os.path.exists(os.path.join(data_path, "user.css")) else None
if modules.shared.opts.theme_type == 'Standard':
if shared.opts.extra_networks_height == 0:
shared.opts.extra_networks_height = 55
themecss = os.path.join(script_path, "javascript", f"{modules.shared.opts.gradio_theme}.css")
if os.path.exists(themecss):
head += stylesheet(themecss)
@@ -66,8 +64,6 @@ def html_css(css: str):
else:
modules.shared.log.error(f'UI theme: css="{themecss}" not found')
elif modules.shared.opts.theme_type == 'Modern':
if shared.opts.extra_networks_height == 0:
shared.opts.extra_networks_height = 87
theme_folder = next((e.path for e in modules.extensions.extensions if e.name == 'sdnext-modernui'), None)
themecss = os.path.join(theme_folder or '', 'themes', f'{modules.shared.opts.gradio_theme}.css')
if os.path.exists(themecss):
+13 -3
View File
@@ -217,7 +217,8 @@ def create_sampler_options(tabname):
shared.opts.save(shared.config_filename, silent=True)
def set_sampler_options(sampler_options):
shared.opts.data['schedulers_use_thresholding'] = 'dynamic' in sampler_options
shared.opts.data['schedulers_dynamic_shift'] = 'dynamic' in sampler_options
shared.opts.data['schedulers_use_thresholding'] = 'thresholding' in sampler_options
shared.opts.data['schedulers_use_loworder'] = 'low order' in sampler_options
shared.opts.data['schedulers_rescale_betas'] = 'rescale' in sampler_options
shared.log.debug(f'Sampler set options: {sampler_options}')
@@ -253,6 +254,11 @@ def create_sampler_options(tabname):
shared.opts.schedulers_beta_schedule = sampler_beta
shared.opts.save(shared.config_filename, silent=True)
def set_sampler_shift(sampler_shift):
shared.log.debug(f'Sampler set options: shift={sampler_shift}')
shared.opts.schedulers_shift = sampler_shift
shared.opts.save(shared.config_filename, silent=True)
# 'linear', 'scaled_linear', 'squaredcos_cap_v2'
def set_sampler_preset(preset):
if preset == 'AYS SD15':
@@ -286,10 +292,13 @@ def create_sampler_options(tabname):
sampler_timesteps = gr.Textbox(label='Timesteps override', elem_id=f"{tabname}_sampler_timesteps", value=shared.opts.schedulers_timesteps)
with gr.Row(elem_classes=['flex-break']):
sampler_order = gr.Slider(minimum=0, maximum=5, step=1, label="Sampler order", value=shared.opts.schedulers_solver_order, elem_id=f"{tabname}_sampler_order")
options = ['low order', 'dynamic', 'rescale']
sampler_shift = gr.Slider(minimum=0, maximum=10, step=0.1, label="Flow shift", value=shared.opts.schedulers_shift, elem_id=f"{tabname}_sampler_shift")
with gr.Row(elem_classes=['flex-break']):
options = ['low order', 'thresholding', 'dynamic', 'rescale']
values = []
values += ['low order'] if shared.opts.data.get('schedulers_use_loworder', True) else []
values += ['dynamic'] if shared.opts.data.get('schedulers_use_thresholding', False) else []
values += ['thresholding'] if shared.opts.data.get('schedulers_use_thresholding', False) else []
values += ['dynamic'] if shared.opts.data.get('schedulers_dynamic_shift', False) else []
values += ['rescale'] if shared.opts.data.get('schedulers_rescale_betas', False) else []
sampler_options = gr.CheckboxGroup(label='Options', elem_id=f"{tabname}_sampler_options", choices=options, value=values, type='value')
@@ -300,6 +309,7 @@ def create_sampler_options(tabname):
sampler_beta.change(fn=set_sampler_beta, inputs=[sampler_beta], outputs=[])
sampler_prediction.change(fn=set_sampler_prediction, inputs=[sampler_prediction], outputs=[])
sampler_order.change(fn=set_sampler_order, inputs=[sampler_order], outputs=[])
sampler_shift.change(fn=set_sampler_shift, inputs=[sampler_shift], outputs=[])
sampler_options.change(fn=set_sampler_options, inputs=[sampler_options], outputs=[])
-1
View File
@@ -217,7 +217,6 @@ def compile_upscaler(model):
try:
if "Upscaler" in shared.opts.cuda_compile and shared.opts.cuda_compile_backend != 'none':
import torch._dynamo # pylint: disable=unused-import,redefined-outer-name
torch._dynamo.reset() # pylint: disable=protected-access
if shared.opts.cuda_compile_backend not in torch._dynamo.list_backends(): # pylint: disable=protected-access
shared.log.warning(f"Upscaler compile not available: backend={shared.opts.cuda_compile_backend} available={torch._dynamo.list_backends()}") # pylint: disable=protected-access
return model
+1 -1
View File
@@ -25,7 +25,7 @@ class Script(scripts.Script):
return 'ConsiStory: Consistent Image Generation'
def show(self, is_img2img):
return not is_img2img if shared.native and shared.cmd_opts.experimental else False
return not is_img2img if shared.native else False
def reset(self):
self.anchor_cache_first_stage = None
+6 -6
View File
@@ -35,16 +35,16 @@ class Script(scripts.Script):
s1_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='Restart step')
with gr.Row():
s2_enable = gr.Checkbox(value=True, label='2nd Stage')
s2_scale = gr.Slider(minimum=1, maximum=8.0, value=2.0, label='Scale')
s2_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='Restart step')
s2_scale = gr.Slider(minimum=1, maximum=8.0, value=2.0, label='2nd Scale')
s2_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='2nd Restart step')
with gr.Row():
s3_enable = gr.Checkbox(value=False, label='3rd Stage')
s3_scale = gr.Slider(minimum=1, maximum=8.0, value=3.0, label='Scale')
s3_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='Restart step')
s3_scale = gr.Slider(minimum=1, maximum=8.0, value=3.0, label='3rd Scale')
s3_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='3rd Restart step')
with gr.Row():
s4_enable = gr.Checkbox(value=False, label='4th Stage')
s4_scale = gr.Slider(minimum=1, maximum=8.0, value=4.0, label='Scale')
s4_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='Restart step')
s4_scale = gr.Slider(minimum=1, maximum=8.0, value=4.0, label='4th Scale')
s4_restart = gr.Slider(minimum=0, maximum=1.0, value=0.75, label='4th Restart step')
return [cosine_scale, override_sampler, cosine_scale_bg, dilate_tau, s1_enable, s1_scale, s1_restart, s2_enable, s2_scale, s2_restart, s3_enable, s3_scale, s3_restart, s4_enable, s4_scale, s4_restart]
def run(self, p: processing.StableDiffusionProcessing, cosine_scale, override_sampler, cosine_scale_bg, dilate_tau, s1_enable, s1_scale, s1_restart, s2_enable, s2_scale, s2_restart, s3_enable, s3_scale, s3_restart, s4_enable, s4_scale, s4_restart): # pylint: disable=arguments-differ
+103 -37
View File
@@ -1,26 +1,55 @@
import time
import torch
import gradio as gr
import transformers
import diffusers
from modules import scripts, processing, shared, images, devices, sd_models, sd_checkpoint, model_quant
from modules import scripts, processing, shared, images, devices, sd_models, sd_checkpoint, model_quant, timer
repo_id = 'tencent/HunyuanVideo'
default_template = """Describe the video by detailing the following aspects:
1. The main content and theme of the video.
2. The color, shape, size, texture, quantity, text, and spatial relationships of the objects.
3. Actions, events, behaviors temporal relationships, physical movement changes of the objects.
4. Background environment, light, style and atmosphere.
5. Camera angles, movements, and transitions used in the video.
6. Thematic and aesthetic concepts associated with the scene, i.e. realistic, futuristic, fairy tale, etc.
"""
prompt_template = { # default
"template": (
"<|start_header_id|>system<|end_header_id|>\n\nDescribe the video by detailing the following aspects: "
"1. The main content and theme of the video."
"2. The color, shape, size, texture, quantity, text, and spatial relationships of the contents, including objects, people, and anything else."
"3. Actions, events, behaviors temporal relationships, physical movement changes of the contents."
"4. Background environment, light, style, atmosphere, and qualities."
"5. Camera angles, movements, and transitions used in the video."
"6. Thematic and aesthetic concepts associated with the scene, i.e. realistic, futuristic, fairy tale, etc<|eot_id|>"
"<|start_header_id|>user<|end_header_id|>\n\n{}<|eot_id|>"
),
"crop_start": 95,
}
"""
def get_template(template: str = None):
# diffusers.pipelines.hunyuan_video.pipeline_hunyuan_video.DEFAULT_PROMPT_TEMPLATE
base_template_pre = "<|start_header_id|>system<|end_header_id|>\n\n"
base_template_post = "<|eot_id|>\n"
base_template_end = "<|start_header_id|>user<|end_header_id|>\n\n{}<|eot_id|>"
if template is None or len(template) == 0:
template = default_template
template_lines = '\n'.join([line for line in template.split('\n') if len(line) > 0])
prompt_template = {
"crop_start": 95,
"template": base_template_pre + template_lines + base_template_post + base_template_end
}
return prompt_template
def hijack_decode(*args, **kwargs):
t0 = time.time()
vae: diffusers.AutoencoderKLHunyuanVideo = shared.sd_model.vae
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model, exclude=['vae'])
res = shared.sd_model.vae.orig_decode(*args, **kwargs)
t1 = time.time()
timer.process.add('vae', t1-t0)
shared.log.debug(f'Video: vae={vae.__class__.__name__} tile={vae.tile_sample_min_width}:{vae.tile_sample_min_height}:{vae.tile_sample_min_num_frames} stride={vae.tile_sample_stride_width}:{vae.tile_sample_stride_height}:{vae.tile_sample_stride_num_frames} time={t1-t0:.2f}')
return res
def hijack_encode_prompt(*args, **kwargs):
t0 = time.time()
res = shared.sd_model.vae.orig_encode_prompt(*args, **kwargs)
t1 = time.time()
timer.process.add('te', t1-t0)
shared.log.debug(f'Video: te={shared.sd_model.text_encoder.__class__.__name__} time={t1-t0:.2f}')
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
return res
class Script(scripts.Script):
@@ -44,6 +73,11 @@ class Script(scripts.Script):
gr.HTML('<a href="https://huggingface.co/tencent/HunyuanVideo">&nbsp Hunyuan Video</a><br>')
with gr.Row():
num_frames = gr.Slider(label='Frames', minimum=9, maximum=257, step=1, value=45)
tile_frames = gr.Slider(label='Tile frames', minimum=1, maximum=64, step=1, value=16)
with gr.Row():
override_scheduler = gr.Checkbox(label='Override scheduler', value=True)
with gr.Row():
template = gr.TextArea(label='Prompt processor', lines=3, value=default_template)
with gr.Row():
video_type = gr.Dropdown(label='Video file', choices=['None', 'GIF', 'PNG', 'MP4'], value='None')
duration = gr.Slider(label='Duration', minimum=0.25, maximum=10, step=0.25, value=2, visible=False)
@@ -52,57 +86,89 @@ class Script(scripts.Script):
mp4_pad = gr.Slider(label='Pad frames', minimum=0, maximum=24, step=1, value=1, visible=False)
mp4_interpolate = gr.Slider(label='Interpolate frames', minimum=0, maximum=24, step=1, value=0, visible=False)
video_type.change(fn=video_type_change, inputs=[video_type], outputs=[duration, gif_loop, mp4_pad, mp4_interpolate])
return [num_frames, video_type, duration, gif_loop, mp4_pad, mp4_interpolate]
return [num_frames, tile_frames, override_scheduler, template, video_type, duration, gif_loop, mp4_pad, mp4_interpolate]
def run(self, p: processing.StableDiffusionProcessing, num_frames, video_type, duration, gif_loop, mp4_pad, mp4_interpolate): # pylint: disable=arguments-differ, unused-argument
def run(self, p: processing.StableDiffusionProcessing, num_frames, tile_frames, override_scheduler, template, video_type, duration, gif_loop, mp4_pad, mp4_interpolate): # pylint: disable=arguments-differ, unused-argument
# set params
num_frames = int(num_frames)
p.width = 32 * int(p.width // 32)
p.height = 32 * int(p.height // 32)
p.task_args['output_type'] = 'pil'
p.task_args['generator'] = torch.manual_seed(p.seed)
p.task_args['num_frames'] = num_frames
# p.task_args['prompt_template'] = prompt_template
p.sampler_name = 'Default'
p.width = 16 * int(p.width // 16)
p.height = 16 * int(p.height // 16)
p.do_not_save_grid = True
p.ops.append('video')
# load model
cls = diffusers.HunyuanVideoPipeline
if shared.sd_model.__class__ != cls:
if shared.sd_model.__class__ != diffusers.HunyuanVideoPipeline:
sd_models.unload_model_weights()
kwargs = {}
kwargs = model_quant.create_bnb_config(kwargs)
kwargs = model_quant.create_ao_config(kwargs)
t0 = time.time()
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
if quant_args:
model_quant.load_bnb(f'Load model: type=HunyuanVideo quant={quant_args}')
if not quant_args:
quant_args = model_quant.create_ao_config(quant_args)
if quant_args:
model_quant.load_torchao(f'Load model: type=HunyuanVideo quant={quant_args}')
transformer = diffusers.HunyuanVideoTransformer3DModel.from_pretrained(
repo_id,
subfolder="transformer",
torch_dtype=devices.dtype,
revision="refs/pr/18",
cache_dir = shared.opts.hfcache_dir,
**kwargs
**quant_args
)
shared.sd_model = cls.from_pretrained(
shared.log.debug(f'Video: module={transformer.__class__.__name__}')
text_encoder = transformers.LlamaModel.from_pretrained(
repo_id,
transformer=transformer,
subfolder="text_encoder",
revision="refs/pr/18",
cache_dir = shared.opts.hfcache_dir,
torch_dtype=devices.dtype,
**kwargs
**quant_args
)
shared.sd_model.scheduler._shift = 7.0 # pylint: disable=protected-access
shared.log.debug(f'Video: module={text_encoder.__class__.__name__}')
shared.sd_model = diffusers.HunyuanVideoPipeline.from_pretrained(
repo_id,
transformer=transformer,
text_encoder=text_encoder,
revision="refs/pr/18",
cache_dir = shared.opts.hfcache_dir,
torch_dtype=devices.dtype,
**quant_args
)
t1 = time.time()
shared.log.debug(f'Video: load cls={shared.sd_model.__class__.__name__} repo="{repo_id}" dtype={devices.dtype} time={t1-t0:.2f}')
sd_models.set_diffuser_options(shared.sd_model)
shared.sd_model.sd_checkpoint_info = sd_checkpoint.CheckpointInfo(repo_id)
shared.sd_model.sd_model_hash = None
shared.sd_model.vae.orig_decode = shared.sd_model.vae.decode
shared.sd_model.vae.orig_encode_prompt = shared.sd_model.encode_prompt
shared.sd_model.vae.decode = hijack_decode
shared.sd_model.encode_prompt = hijack_encode_prompt
shared.sd_model.vae.enable_slicing()
shared.sd_model.vae.enable_tiling()
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
shared.sd_model.vae.enable_slicing()
shared.sd_model.vae.enable_tiling()
devices.torch_gc(force=True)
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} args={p.task_args}')
if override_scheduler:
p.sampler_name = 'Default'
shared.sd_model.scheduler._shift = 7.0 # pylint: disable=protected-access
# encode prompt
processing.fix_seed(p)
p.task_args['num_frames'] = num_frames
p.task_args['output_type'] = 'pil'
p.task_args['generator'] = torch.manual_seed(p.seed)
# p.task_args['prompt'] = None
# p.task_args['prompt_embeds'], p.task_args['pooled_prompt_embeds'], p.task_args['prompt_attention_mask'] = shared.sd_model.encode_prompt(prompt=p.prompt, prompt_template=get_template(template), device=devices.device)
# run processing
t0 = time.time()
shared.sd_model.vae.tile_sample_min_num_frames = tile_frames
shared.state.disable_preview = True
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} width={p.width} height={p.height} frames={num_frames}')
processed = processing.process_images(p)
shared.state.disable_preview = False
t1 = time.time()
if processed is not None and len(processed.images) > 0:
shared.log.info(f'Video: frames={len(processed.images)} time={t1-t0:.2f}')
+1 -1
View File
@@ -1,6 +1,5 @@
import inspect
import gradio as gr
import diffusers
from modules import scripts, processing, shared, sd_models
@@ -38,6 +37,7 @@ class Script(scripts.Script):
if shared.sd_model_type not in self.supported_models:
shared.log.warning(f'K-Diffusion: class={shared.sd_model.__class__.__name__} model={shared.sd_model_type} required={self.supported_models}')
return None
import diffusers
cls = None
if shared.sd_model_type == "sd":
cls = diffusers.pipelines.StableDiffusionKDiffusionPipeline
+53 -18
View File
@@ -4,7 +4,8 @@ import torch
import gradio as gr
import diffusers
import transformers
from modules import scripts, processing, shared, images, devices, sd_models, sd_checkpoint, model_quant
from modules import scripts, processing, shared, images, devices, sd_models, sd_checkpoint, model_quant, timer
from modules.teacache.teacache_ltx import teacache_forward
repos = {
@@ -15,26 +16,45 @@ repos = {
def load_quants(kwargs, repo_id):
if len(shared.opts.bnb_quantization) > 0:
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
quant_args = {}
quant_args = model_quant.create_bnb_config(quant_args)
if quant_args:
model_quant.load_bnb(f'Load model: type=LTXVideo quant={quant_args}')
if not quant_args:
quant_args = model_quant.create_ao_config(quant_args)
if not quant_args:
return kwargs
model_quant.load_bnb(f'Load model: type=LTX quant={quant_args}')
if 'Model' in shared.opts.bnb_quantization and 'transformer' not in kwargs:
kwargs['transformer'] = diffusers.LTXVideoTransformer3DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=shared.opts.hfcache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'Text Encoder' in shared.opts.bnb_quantization and 'text_encoder_3' not in kwargs:
kwargs['text_encoder'] = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder="text_encoder", cache_dir=shared.opts.hfcache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if quant_args:
model_quant.load_torchao(f'Load model: type=LTXVideo quant={quant_args}')
if not quant_args:
return kwargs
model_quant.load_bnb(f'Load model: type=LTX quant={quant_args}')
if 'transformer' not in kwargs and ('Model' in shared.opts.bnb_quantization or 'Model' in shared.opts.torchao_quantization):
kwargs['transformer'] = diffusers.LTXVideoTransformer3DModel.from_pretrained(repo_id, subfolder="transformer", cache_dir=shared.opts.hfcache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=transformer type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
if 'text_encoder' not in kwargs and ('Text Encoder' in shared.opts.bnb_quantization or 'Text Encoder' in shared.opts.torchao_quantization):
kwargs['text_encoder'] = transformers.T5EncoderModel.from_pretrained(repo_id, subfolder="text_encoder", cache_dir=shared.opts.hfcache_dir, torch_dtype=devices.dtype, **quant_args)
shared.log.debug(f'Quantization: module=t5 type=bnb dtype={shared.opts.bnb_quantization_type} storage={shared.opts.bnb_quantization_storage}')
return kwargs
def hijack_decode(*args, **kwargs):
shared.log.debug('Video: decode')
t0 = time.time()
# vae: diffusers.AutoencoderKLHunyuanVideo = shared.sd_model.vae
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model, exclude=['vae'])
res = shared.sd_model.vae.orig_decode(*args, **kwargs)
t1 = time.time()
timer.process.add('vae', t1-t0)
shared.log.debug(f'Video: vae={shared.sd_model.vae.__class__.__name__} time={t1-t0:.2f}')
return res
def hijack_encode_prompt(*args, **kwargs):
t0 = time.time()
res = shared.sd_model.vae.orig_encode_prompt(*args, **kwargs)
t1 = time.time()
timer.process.add('te', t1-t0)
shared.log.debug(f'Video: te={shared.sd_model.text_encoder.__class__.__name__} time={t1-t0:.2f}')
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
return shared.sd_model.vae.orig_decode(*args, **kwargs)
return res
class Script(scripts.Script):
@@ -64,6 +84,9 @@ class Script(scripts.Script):
with gr.Row():
num_frames = gr.Slider(label='Frames', minimum=9, maximum=257, step=1, value=41)
sampler = gr.Checkbox(label='Override sampler', value=True)
with gr.Row():
teacache_enable = gr.Checkbox(label='Enable TeaCache', value=False)
teacache_threshold = gr.Slider(label='Threshold', minimum=0.01, maximum=0.1, step=0.01, value=0.03)
with gr.Row():
model_custom = gr.Textbox(value='', label='Path to model file', visible=False)
with gr.Row():
@@ -75,9 +98,9 @@ class Script(scripts.Script):
mp4_interpolate = gr.Slider(label='Interpolate frames', minimum=0, maximum=24, step=1, value=0, visible=False)
video_type.change(fn=video_type_change, inputs=[video_type], outputs=[duration, gif_loop, mp4_pad, mp4_interpolate])
model.change(fn=model_change, inputs=[model], outputs=[model_custom])
return [model, model_custom, decode, sampler, num_frames, video_type, duration, gif_loop, mp4_pad, mp4_interpolate]
return [model, model_custom, decode, sampler, num_frames, video_type, duration, gif_loop, mp4_pad, mp4_interpolate, teacache_enable, teacache_threshold]
def run(self, p: processing.StableDiffusionProcessing, model, model_custom, decode, sampler, num_frames, video_type, duration, gif_loop, mp4_pad, mp4_interpolate): # pylint: disable=arguments-differ, unused-argument
def run(self, p: processing.StableDiffusionProcessing, model, model_custom, decode, sampler, num_frames, video_type, duration, gif_loop, mp4_pad, mp4_interpolate, teacache_enable, teacache_threshold): # pylint: disable=arguments-differ, unused-argument
# set params
image = getattr(p, 'init_images', None)
image = None if image is None or len(image) == 0 else image[0]
@@ -111,6 +134,7 @@ class Script(scripts.Script):
kwargs = {}
kwargs = model_quant.create_bnb_config(kwargs)
kwargs = model_quant.create_ao_config(kwargs)
diffusers.LTXVideoTransformer3DModel.forward = teacache_forward
if os.path.isfile(repo_id):
shared.sd_model = cls.from_single_file(
repo_id,
@@ -128,14 +152,25 @@ class Script(scripts.Script):
)
sd_models.set_diffuser_options(shared.sd_model)
shared.sd_model.vae.orig_decode = shared.sd_model.vae.decode
shared.sd_model.vae.orig_encode_prompt = shared.sd_model.encode_prompt
shared.sd_model.vae.decode = hijack_decode
shared.sd_model.encode_prompt = hijack_encode_prompt
shared.sd_model.sd_checkpoint_info = sd_checkpoint.CheckpointInfo(repo_id)
shared.sd_model.sd_model_hash = None
shared.sd_model = sd_models.apply_balanced_offload(shared.sd_model)
shared.sd_model.vae.enable_slicing()
shared.sd_model.vae.enable_tiling()
devices.torch_gc(force=True)
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} args={p.task_args}')
shared.sd_model.transformer.cnt = 0
shared.sd_model.transformer.accumulated_rel_l1_distance = 0
shared.sd_model.transformer.previous_modulated_input = None
shared.sd_model.transformer.previous_residual = None
shared.sd_model.transformer.enable_teacache = teacache_enable
shared.sd_model.transformer.rel_l1_thresh = teacache_threshold
shared.sd_model.transformer.num_steps = p.steps
shared.log.debug(f'Video: cls={shared.sd_model.__class__.__name__} args={p.task_args} steps={p.steps} teacache={teacache_enable} threshold={teacache_threshold}')
# run processing
t0 = time.time()
+7 -4
View File
@@ -22,7 +22,7 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
def index(ix, iy, iz):
return ix + iy * len(xs) + iz * len(xs) * len(ys)
shared.state.job = 'grid'
shared.state.job = 'Grid'
p0 = time.time()
processed: processing.Processed = cell(x, y, z, ix, iy, iz)
p1 = time.time()
@@ -97,10 +97,10 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
process_cell(x, y, z, ix, iy, iz)
if not processed_result:
shared.log.error("XYZ grid: Failed to initialize processing")
shared.log.error("XYZ grid: failed to initialize processing")
return processing.Processed(p, [])
elif not any(processed_result.images):
shared.log.error("XYZ grid: Failed to return processed image")
shared.log.error("XYZ grid: failed to return processed image")
return processing.Processed(p, [])
t1 = time.time()
@@ -109,7 +109,10 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
idx0 = (i * len(xs) * len(ys)) + i # starting index of images in subgrid
idx1 = (len(xs) * len(ys)) + idx0 # ending index of images in subgrid
to_process = processed_result.images[idx0:idx1]
w, h = max(i.width for i in to_process), max(i.height for i in to_process)
w, h = max(i.width for i in to_process if i is not None), max(i.height for i in to_process if i is not None)
if w is None or h is None or w == 0 or h == 0:
shared.log.error("XYZ grid: failed get valid image")
continue
if (not no_grid or include_sub_grids) and images.check_grid_size(to_process):
grid = images.image_grid(to_process, rows=len(ys))
if draw_legend:
+1
View File
@@ -379,6 +379,7 @@ class Script(scripts.Script):
)
if not processed.images:
active = False
return processed # something broke, no further handling needed.
# processed.images = (1)*grid + (z > 1 ? z : 0)*subgrids + (x*y*z)*images
have_grid = 1 if include_grid else 0
+10 -6
View File
@@ -13,7 +13,7 @@ import modules.loader
import torch # pylint: disable=wrong-import-order
from modules import timer, errors, paths # pylint: disable=unused-import
from installer import log, git_commit, custom_excepthook
import ldm.modules.encoders.modules # pylint: disable=unused-import, wrong-import-order
# import ldm.modules.encoders.modules # pylint: disable=unused-import, wrong-import-order
from modules import shared, extensions, gr_tempdir, modelloader # pylint: disable=ungrouped-imports
from modules import extra_networks, ui_extra_networks # pylint: disable=ungrouped-imports
from modules.paths import create_paths
@@ -84,6 +84,8 @@ def initialize():
modules.hashes.init_cache()
check_rollback_vae()
log.debug(f'Huggingface cache: path="{shared.opts.hfcache_dir}"')
modules.sd_samplers.list_samplers()
timer.startup.record("samplers")
@@ -100,7 +102,7 @@ def initialize():
modules.sd_models.setup_model()
timer.startup.record("models")
if shared.native:
if not shared.opts.lora_legacy:
import modules.lora.networks as lora_networks
lora_networks.list_available_networks()
timer.startup.record("lora")
@@ -226,7 +228,7 @@ def start_common():
if shared.cmd_opts.data_dir is not None and len(shared.cmd_opts.data_dir) > 0:
log.info(f'Using data path: {shared.cmd_opts.data_dir}')
if shared.cmd_opts.models_dir is not None and len(shared.cmd_opts.models_dir) > 0 and shared.cmd_opts.models_dir != 'models':
log.info(f'Using models path: {shared.cmd_opts.models_dir}')
log.info(f'Models path: {shared.cmd_opts.models_dir}')
create_paths(shared.opts)
async_policy()
initialize()
@@ -301,7 +303,7 @@ def start_ui():
shared.log.info(f'API ReDocs: {local_url[:-1]}/redocs') # pylint: disable=unsubscriptable-object
if share_url is not None:
shared.log.info(f'Share URL: {share_url}')
shared.log.debug(f'Gradio functions: registered={len(shared.demo.fns)}')
# shared.log.debug(f'Gradio functions: registered={len(shared.demo.fns)}')
shared.demo.server.wants_restart = False
setup_middleware(app, cmd_opts)
@@ -321,8 +323,10 @@ def start_ui():
modules.script_callbacks.app_started_callback(shared.demo, app)
timer.startup.record("app-started")
time_setup = [f'{k}:{round(v,3)}' for (k,v) in modules.scripts.time_setup.items() if v > 0.005]
shared.log.debug(f'Scripts setup: {time_setup}')
time_sorted = sorted(modules.scripts.time_setup.items(), key=lambda x: x[1], reverse=True)
time_script = [f'{k}:{round(v,3)}' for (k,v) in time_sorted if v > 0.01]
time_total = sum(modules.scripts.time_setup.values())
shared.log.debug(f'Scripts setup: time={time_total:.3f} {time_script}')
time_component = [f'{k}:{round(v,3)}' for (k,v) in modules.scripts.time_component.items() if v > 0.005]
if len(time_component) > 0:
shared.log.debug(f'Scripts components: {time_component}')
+1 -1
Submodule wiki updated: 22951c9818...fc38907c83