mirror of
https://github.com/vladmandic/automatic
synced 2026-09-18 16:54:33 +02:00
@@ -31,6 +31,7 @@ ignore-paths=/usr/lib/.*$,
|
||||
modules/rife,
|
||||
modules/schedulers,
|
||||
modules/taesd,
|
||||
modules/teacache,
|
||||
modules/todo,
|
||||
modules/unipc,
|
||||
modules/xadapter,
|
||||
|
||||
@@ -26,6 +26,7 @@ exclude = [
|
||||
"modules/schedulers",
|
||||
"modules/segmoe",
|
||||
"modules/taesd",
|
||||
"modules/teacache",
|
||||
"modules/todo",
|
||||
"modules/unipc",
|
||||
"modules/xadapter",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Submodule extensions-builtin/sdnext-modernui updated: f6f629dfbe...62d8a54a7e
+7
-1
@@ -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
@@ -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):
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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()
|
||||
|
||||
@@ -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]}')
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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):
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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}')
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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]):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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"]}),
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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/'):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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=[])
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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">  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
@@ -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
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user