mirror of
https://github.com/vladmandic/automatic
synced 2026-09-06 21:10:45 +02:00
+14
-14
@@ -17,29 +17,29 @@
|
||||
url = https://github.com/kohya-ss/sd-scripts
|
||||
ignore = dirty
|
||||
[submodule "extensions-builtin/clip-interrogator-ext"]
|
||||
path = extensions-builtin/clip-interrogator-ext
|
||||
url = https://github.com/pharmapsychotic/clip-interrogator-ext.git
|
||||
path = extensions-builtin/clip-interrogator-ext
|
||||
url = https://github.com/Dahvikiin/clip-interrogator-ext.git
|
||||
ignore = dirty
|
||||
[submodule "extensions-builtin/sd-webui-controlnet"]
|
||||
path = extensions-builtin/sd-webui-controlnet
|
||||
url = https://github.com/Mikubill/sd-webui-controlnet
|
||||
path = extensions-builtin/sd-webui-controlnet
|
||||
url = https://github.com/Mikubill/sd-webui-controlnet
|
||||
ignore = dirty
|
||||
[submodule "modules/lycoris"]
|
||||
path = modules/lycoris
|
||||
url = https://github.com/KohakuBlueleaf/LyCORIS
|
||||
path = modules/lycoris
|
||||
url = https://github.com/KohakuBlueleaf/LyCORIS
|
||||
ignore = dirty
|
||||
[submodule "extensions-builtin/stable-diffusion-webui-rembg"]
|
||||
path = extensions-builtin/stable-diffusion-webui-rembg
|
||||
url = https://github.com/AUTOMATIC1111/stable-diffusion-webui-rembg
|
||||
path = extensions-builtin/stable-diffusion-webui-rembg
|
||||
url = https://github.com/AUTOMATIC1111/stable-diffusion-webui-rembg
|
||||
ignore = dirty
|
||||
[submodule "extensions-builtin/a1111-sd-webui-lycoris"]
|
||||
path = extensions-builtin/a1111-sd-webui-lycoris
|
||||
url = https://github.com/KohakuBlueleaf/a1111-sd-webui-lycoris
|
||||
path = extensions-builtin/a1111-sd-webui-lycoris
|
||||
url = https://github.com/KohakuBlueleaf/a1111-sd-webui-lycoris
|
||||
ignore = dirty
|
||||
[submodule "extensions-builtin/multidiffusion-upscaler-for-automatic1111"]
|
||||
path = extensions-builtin/multidiffusion-upscaler-for-automatic1111
|
||||
url = https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111
|
||||
path = extensions-builtin/multidiffusion-upscaler-for-automatic1111
|
||||
url = https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111
|
||||
ignore = dirty
|
||||
[submodule "extensions-builtin/sd-webui-agent-scheduler"]
|
||||
path = extensions-builtin/sd-webui-agent-scheduler
|
||||
url = https://github.com/ArtVentureX/sd-webui-agent-scheduler
|
||||
path = extensions-builtin/sd-webui-agent-scheduler
|
||||
url = https://github.com/ArtVentureX/sd-webui-agent-scheduler
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 07/08/2023
|
||||
|
||||
- add pan & zoom controls (touch and mouse) to image viewer (lightbox)
|
||||
- cache extra networks between tabs
|
||||
this should result in neat 2x speedup on building extra networks
|
||||
- add settings -> extra networks -> do not automatically build extra network pages
|
||||
speeds up app start if you have a lot of extra networks and you want to build them manually when needed
|
||||
- extra network ui tweaks
|
||||
- merge experimental diffusers support
|
||||
covered in details in a separate post
|
||||
|
||||
## Update for 07/01/2023
|
||||
|
||||
Small quality-of-life updates and bugfixes:
|
||||
|
||||
@@ -67,6 +67,19 @@ Below is partial list of all available parameters, run `webui --help` for the fu
|
||||
|
||||
## Notes
|
||||
|
||||
### **Extensions**
|
||||
|
||||
SD.Next comes with several extensions pre-installed:
|
||||
|
||||
- [Dyanmic Thresholding](https://github.com/mcmonkeyprojects/sd-dynamic-thresholding)
|
||||
- [ControlNet](https://github.com/Mikubill/sd-webui-controlnet)
|
||||
- [Agent Scheduler](https://github.com/ArtVentureX/sd-webui-agent-scheduler)
|
||||
- [Multi-Diffusion Tiled Diffusion and VAE](https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111)
|
||||
- [LyCORIS](https://github.com/KohakuBlueleaf/a1111-sd-webui-lycoris)
|
||||
- [Image Browser](https://github.com/AlUlkesh/stable-diffusion-webui-images-browser)
|
||||
- [CLiP Interrogator](https://github.com/pharmapsychotic/clip-interrogator-ext)
|
||||
- [Rembg Background Removal](https://github.com/AUTOMATIC1111/stable-diffusion-webui-rembg)
|
||||
|
||||
### **Collab**
|
||||
|
||||
- To avoid having this repo rely just on me, I'd love to have additional maintainers with full admin rights. If you're interested, ping me!
|
||||
|
||||
@@ -26,7 +26,8 @@ Stuff to be investigated...
|
||||
|
||||
Pick & merge PRs from main repo...
|
||||
|
||||
- list: <https://github.com/AUTOMATIC1111/stable-diffusion-webui/compare/89f9faa...baf6946>
|
||||
- up-to-date with: df004be
|
||||
- current todo list: <https://github.com/AUTOMATIC1111/stable-diffusion-webui/compare/df004be...394ffa7>
|
||||
|
||||
## Integration
|
||||
|
||||
@@ -41,13 +42,13 @@ Tech that can be integrated as part of the core workflow...
|
||||
- [DataComp CLiP](https://github.com/mlfoundations/open_clip/blob/main/docs/datacomp_models.md)
|
||||
- [ClipSeg](https://github.com/timojl/clipseg)
|
||||
- [DragGAN](https://github.com/XingangPan/DragGAN)
|
||||
- [LamaCleaner]([Title](https://github.com/Sanster/lama-cleaner))
|
||||
- `TensorRT`
|
||||
|
||||
## Random
|
||||
|
||||
- Bunch of stuff: <https://pharmapsychotic.com/tools.html>
|
||||
- <https://towardsdatascience.com/mastering-memoization-in-python-dcdd8b435189>
|
||||
- shared.info
|
||||
- docker
|
||||
- port `p.all_hr_prompts`
|
||||
- test `lyco_patch_lora`
|
||||
@@ -56,6 +57,10 @@ Tech that can be integrated as part of the core workflow...
|
||||
- image watermark
|
||||
- image `imagehash` phash and hdash
|
||||
- custom exif tags
|
||||
- replace lightbox with iv-viewer
|
||||
- git-rebasin
|
||||
- additional upscalers
|
||||
- new image browser
|
||||
- update `transformers`
|
||||
- `git submodule set-url extensions-builtin/clip-interrogator-ext https://github.com/Dahvikiin/clip-interrogator-ext.git`
|
||||
- upate `gradio`
|
||||
- extra network refresh breaks if new extra network type found
|
||||
|
||||
+3
-4
@@ -11,9 +11,8 @@ if __name__ == "__main__":
|
||||
model_filter = hf.ModelFilter(
|
||||
model_name=keyword,
|
||||
task='text-to-image',
|
||||
tags='stable-diffusion',
|
||||
library=['diffusers', 'stable-diffusion'],
|
||||
library=['diffusers'],
|
||||
)
|
||||
res = hf_api.list_models(filter=model_filter, full=True, limit=50, sort="downloads", direction=-1)
|
||||
models = [{ 'name': m.modelId, 'downloads': m.downloads, 'mtime': m.lastModified, 'url': f'https://huggingface.co/{m.modelId}' } for m in res]
|
||||
print('Online', models)
|
||||
models = [{ 'name': m.modelId, 'downloads': m.downloads, 'mtime': m.lastModified, 'url': f'https://huggingface.co/{m.modelId}', 'pipeline': m.pipeline_tag, 'tags': m.tags } for m in res]
|
||||
print(models)
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ def get_log():
|
||||
def get_info():
|
||||
import time
|
||||
t0 = time.time()
|
||||
res = getsync('/sdapi/v1/system-info/status')
|
||||
res = getsync('/sdapi/v1/system-info/status?full=true&refresh=true')
|
||||
t1 = time.time()
|
||||
print({ 'duration': 1000 * round(t1-t0, 3), **res })
|
||||
return res
|
||||
|
||||
+8
-3
@@ -265,6 +265,7 @@ def prepare_options():
|
||||
options.lora.in_json = None
|
||||
if args.type == 'dreambooth':
|
||||
log.info('train using dreambooth style training')
|
||||
options.lora.vae_batch_size = args.batch
|
||||
options.lora.in_json = None
|
||||
if args.type == 'lora':
|
||||
log.info('train using lora style training')
|
||||
@@ -378,14 +379,18 @@ def check_versions():
|
||||
log.info('experimental mode enabled')
|
||||
return
|
||||
log.info('checking accelerate')
|
||||
error = False
|
||||
import accelerate
|
||||
if accelerate.__version__ != '0.19.0':
|
||||
log.error(f'invalid accelerate version: required=0.19.0 found={accelerate.__version__}')
|
||||
exit(1)
|
||||
log.error(f'invalid accelerate version: accelerate=0.19.0 found={accelerate.__version__}')
|
||||
error = True
|
||||
log.info('checking diffusers')
|
||||
import diffusers
|
||||
if diffusers.__version__ != '0.10.2':
|
||||
log.error(f'invalid diffusers version: required=0.10.2 found={diffusers.__version__}')
|
||||
log.error(f'invalid diffusers version: diffusers=0.10.2 found={diffusers.__version__}')
|
||||
error = True
|
||||
if error:
|
||||
log.info('> pip install accelerate==0.19.0 diffusers==0.10.2')
|
||||
exit(1)
|
||||
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ class LDSR:
|
||||
global cached_ldsr_model
|
||||
|
||||
if shared.opts.ldsr_cached and cached_ldsr_model is not None:
|
||||
print("Loading model from cache")
|
||||
shared.log.info("LDSR Loading model from cache")
|
||||
model: torch.nn.Module = cached_ldsr_model
|
||||
else:
|
||||
print(f"Loading model from {self.modelPath}")
|
||||
shared.log.info(f"LDSR Loading model from {self.modelPath}")
|
||||
_, extension = os.path.splitext(self.modelPath)
|
||||
if extension.lower() == ".safetensors":
|
||||
pl_sd = safetensors.torch.load_file(self.modelPath, device="cpu")
|
||||
@@ -126,11 +126,10 @@ class LDSR:
|
||||
height_downsampled_pre = int(np.ceil(hd))
|
||||
|
||||
if down_sample_rate != 1:
|
||||
print(
|
||||
f'Downsampling from [{width_og}, {height_og}] to [{width_downsampled_pre}, {height_downsampled_pre}]')
|
||||
shared.log.info(f'LDSR Downsampling from [{width_og}, {height_og}] to [{width_downsampled_pre}, {height_downsampled_pre}]')
|
||||
im_og = im_og.resize((width_downsampled_pre, height_downsampled_pre), Image.LANCZOS)
|
||||
else:
|
||||
print(f"Down sample rate is 1 from {target_scale} / 4 (Not downsampling)")
|
||||
shared.log.info(f"LDSR Downsample rate is 1 from {target_scale} / 4 (Not downsampling)")
|
||||
|
||||
# pad width and height to multiples of 64, pads with the edge values of image to avoid artifacts
|
||||
pad_w, pad_h = np.max(((2, 2), np.ceil(np.array(im_og.size) / 64).astype(int)), axis=0) * 64 - im_og.size
|
||||
@@ -183,7 +182,7 @@ def convsample_ddim(model, cond, steps, shape, eta=1.0, callback=None, normals_s
|
||||
ddim = DDIMSampler(model)
|
||||
bs = shape[0]
|
||||
shape = shape[1:]
|
||||
print(f"Sampling with eta = {eta}; steps: {steps}")
|
||||
shared.log.info(f"LDSR Sampling with eta = {eta}; steps: {steps}")
|
||||
samples, intermediates = ddim.sample(steps, batch_size=bs, shape=shape, conditioning=cond, callback=callback,
|
||||
normals_sequence=normals_sequence, quantize_x0=quantize_x0, eta=eta,
|
||||
mask=mask, x0=x0, temperature=temperature, verbose=False,
|
||||
@@ -206,7 +205,7 @@ def make_convolutional_sample(batch, model, custom_steps=None, eta=1.0, quantize
|
||||
|
||||
if custom_shape is not None:
|
||||
z = torch.randn(custom_shape)
|
||||
print(f"Generating {custom_shape[0]} samples of shape {custom_shape[1:]}")
|
||||
shared.log.info(f"LDSR Generating {custom_shape[0]} samples of shape {custom_shape[1:]}")
|
||||
|
||||
z0 = None
|
||||
|
||||
|
||||
@@ -162,7 +162,6 @@ class DDPMV1(pl.LightningModule):
|
||||
lvlb_weights = 0.5 * np.sqrt(torch.Tensor(alphas_cumprod)) / (2. * 1 - torch.Tensor(alphas_cumprod))
|
||||
else:
|
||||
raise NotImplementedError("mu not supported")
|
||||
# TODO how to choose this term
|
||||
lvlb_weights[0] = lvlb_weights[1]
|
||||
self.register_buffer('lvlb_weights', lvlb_weights, persistent=False)
|
||||
assert not torch.isnan(self.lvlb_weights).all()
|
||||
@@ -872,7 +871,7 @@ class LatentDiffusionV1(DDPMV1):
|
||||
assert c is not None
|
||||
if self.cond_stage_trainable:
|
||||
c = self.get_learned_conditioning(c)
|
||||
if self.shorten_cond_schedule: # TODO: drop this option
|
||||
if self.shorten_cond_schedule:
|
||||
tc = self.cond_ids[t].to(self.device)
|
||||
c = self.q_sample(x_start=c, t=tc, noise=torch.randn_like(c.float()))
|
||||
return self.p_losses(x, c, t, *args, **kwargs)
|
||||
@@ -958,7 +957,7 @@ class LatentDiffusionV1(DDPMV1):
|
||||
cond_list = [{'c_crossattn': [e]} for e in adapted_cond]
|
||||
|
||||
else:
|
||||
cond_list = [cond for i in range(z.shape[-1])] # Todo make this more efficient
|
||||
cond_list = [cond for i in range(z.shape[-1])]
|
||||
|
||||
# apply model by loop over crops
|
||||
output_list = [self.model(z_list[i], t, **cond_list[i]) for i in range(z.shape[-1])]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from modules import extra_networks, shared
|
||||
import lora
|
||||
from modules import extra_networks, shared
|
||||
|
||||
|
||||
class ExtraNetworkLora(extra_networks.ExtraNetwork):
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import os
|
||||
import re
|
||||
import torch
|
||||
from typing import Union
|
||||
|
||||
import torch
|
||||
from modules import shared, devices, sd_models, errors, scripts, sd_hijack, hashes
|
||||
|
||||
metadata_tags_order = {"ss_sd_model_name": 1, "ss_resolution": 2, "ss_clip_skip": 3, "ss_num_train_images": 10, "ss_tag_frequency": 20}
|
||||
@@ -127,7 +126,6 @@ class LoraModule:
|
||||
self.multiplier = 1.0
|
||||
self.modules = {}
|
||||
self.mtime = None
|
||||
|
||||
self.mentioned_name = None
|
||||
"""the text that was used to add lora to prompt - can be either name or an alias"""
|
||||
|
||||
@@ -154,6 +152,13 @@ def assign_lora_names_to_compvis_modules(sd_model):
|
||||
|
||||
sd_model.lora_layer_mapping = lora_layer_mapping
|
||||
|
||||
def load_diffuser_lora(name, lora_on_disk, multiplier):
|
||||
lora = LoraModule(name, lora_on_disk)
|
||||
lora.mtime = os.path.getmtime(lora_on_disk.filename)
|
||||
from modules.lora_diffusers import load_diffusers_lora
|
||||
load_diffusers_lora(name, lora_on_disk, multiplier)
|
||||
return lora
|
||||
|
||||
|
||||
def load_lora(name, lora_on_disk):
|
||||
lora = LoraModule(name, lora_on_disk)
|
||||
@@ -205,7 +210,6 @@ def load_lora(name, lora_on_disk):
|
||||
else:
|
||||
print(f'Lora layer {key_diffusers} matched a layer with unsupported type: {type(sd_module).__name__}')
|
||||
continue
|
||||
raise AssertionError(f"Lora layer {key_diffusers} matched a layer with unsupported type: {type(sd_module).__name__}")
|
||||
|
||||
with torch.no_grad():
|
||||
module.weight.copy_(weight)
|
||||
@@ -243,14 +247,17 @@ def load_loras(names, multipliers=None):
|
||||
failed_to_load_loras = []
|
||||
|
||||
for i, name in enumerate(names):
|
||||
lora = already_loaded.get(name, None)
|
||||
lora = already_loaded.get(name, None) if shared.backend == shared.Backend.ORIGINAL else None
|
||||
|
||||
lora_on_disk = loras_on_disk[i]
|
||||
|
||||
if lora_on_disk is not None:
|
||||
if lora is None or os.path.getmtime(lora_on_disk.filename) > lora.mtime:
|
||||
try:
|
||||
lora = load_lora(name, lora_on_disk)
|
||||
if shared.backend == shared.Backend.DIFFUSERS:
|
||||
lora = load_diffuser_lora(name, lora_on_disk, multipliers[i] if multipliers else 1.0)
|
||||
else:
|
||||
lora = load_lora(name, lora_on_disk)
|
||||
except Exception as e:
|
||||
errors.display(e, f"loading Lora {lora_on_disk.filename}")
|
||||
continue
|
||||
|
||||
Submodule extensions-builtin/clip-interrogator-ext updated: c0bf90052a...6e31272e14
Submodule extensions-builtin/sd-extension-system-info updated: b30e324552...9433a15b89
Submodule extensions-builtin/sd-webui-agent-scheduler updated: 8198489fd4...75ba093d46
Submodule extensions-builtin/sd-webui-controlnet updated: 2785cbe61a...dd766de862
+4
-4
@@ -146,7 +146,7 @@
|
||||
{"id":"","label":"System Paths","localized":"","hint":""},
|
||||
{"id":"","label":"Image Options","localized":"","hint":""},
|
||||
{"id":"","label":"Image Processing","localized":"","hint":""},
|
||||
{"id":"","label":"Output Paths","localized":"","hint":""},
|
||||
{"id":"","label":"Image Paths","localized":"","hint":""},
|
||||
{"id":"","label":"User Interface","localized":"","hint":""},
|
||||
{"id":"","label":"Live Previews","localized":"","hint":""},
|
||||
{"id":"","label":"Sampler Settings","localized":"","hint":""},
|
||||
@@ -524,9 +524,9 @@
|
||||
],
|
||||
"scripts": [
|
||||
{"id":"","label":"Script","localized":"","hint":""},
|
||||
{"id":"","label":"Swap X/Y axes","localized":"","hint":""},
|
||||
{"id":"","label":"Swap Y/Z axes","localized":"","hint":""},
|
||||
{"id":"","label":"Swap X/Z axes","localized":"","hint":""},
|
||||
{"id":"","label":"Swap X/Y","localized":"","hint":""},
|
||||
{"id":"","label":"Swap Y/Z","localized":"","hint":""},
|
||||
{"id":"","label":"Swap X/Z","localized":"","hint":""},
|
||||
{"id":"","label":"Resize to","localized":"","hint":""},
|
||||
{"id":"","label":"Resize by","localized":"","hint":""},
|
||||
{"id":"","label":"Use via API","localized":"","hint":""},
|
||||
|
||||
+42
-30
@@ -105,6 +105,7 @@ def setup_logging():
|
||||
logging.getLogger("httpx").setLevel(logging.ERROR)
|
||||
logging.getLogger("ControlNet").handlers = log.handlers
|
||||
logging.getLogger("lycoris").handlers = log.handlers
|
||||
# logging.getLogger("DeepSpeed").handlers = log.handlers
|
||||
|
||||
|
||||
def print_profile(profile: cProfile.Profile, msg: str):
|
||||
@@ -199,6 +200,8 @@ def git(arg: str, folder: str = None, ignore: bool = False):
|
||||
txt += ('\n' if len(txt) > 0 else '') + result.stderr.decode(encoding="utf8", errors="ignore")
|
||||
txt = txt.strip()
|
||||
if result.returncode != 0 and not ignore:
|
||||
if "couldn't find remote ref" in txt: # not a git repo
|
||||
return txt
|
||||
global errors # pylint: disable=global-statement
|
||||
errors += 1
|
||||
log.error(f'Error running git: {folder} / {arg}')
|
||||
@@ -207,25 +210,34 @@ def git(arg: str, folder: str = None, ignore: bool = False):
|
||||
log.debug(f'Git output: {txt}')
|
||||
return txt
|
||||
|
||||
|
||||
# update switch to main branch as head can get detached and update repository
|
||||
def update(folder):
|
||||
# switch to main branch as head can get detached
|
||||
def branch(folder):
|
||||
if args.experimental:
|
||||
return None
|
||||
if not os.path.exists(os.path.join(folder, '.git')):
|
||||
return
|
||||
branch = git('branch', folder)
|
||||
if 'main' in branch:
|
||||
branch = 'main'
|
||||
elif 'master' in branch:
|
||||
branch = 'master'
|
||||
return None
|
||||
b = git('branch', folder)
|
||||
if 'main' in b:
|
||||
b = 'main'
|
||||
elif 'master' in b:
|
||||
b = 'master'
|
||||
else:
|
||||
branch = branch.split('\n')[0].replace('*', '').strip()
|
||||
# log.debug(f'Setting branch: {folder} / {branch}')
|
||||
git(f'checkout {branch}', folder)
|
||||
b = b.split('\n')[0].replace('*', '').strip()
|
||||
log.debug(f'Submodule: {folder} / {b}')
|
||||
git(f'checkout {b}', folder, ignore=True)
|
||||
return b
|
||||
|
||||
|
||||
# update git repository
|
||||
def update(folder, current_branch = False):
|
||||
if current_branch:
|
||||
git('pull --autostash --rebase --force', folder)
|
||||
return
|
||||
b = branch(folder)
|
||||
if branch is None:
|
||||
git('pull --autostash --rebase --force', folder)
|
||||
else:
|
||||
git(f'pull origin {branch} --autostash --rebase --force', folder)
|
||||
# branch = git('branch', folder)
|
||||
git(f'pull origin {b} --autostash --rebase --force', folder)
|
||||
|
||||
|
||||
# clone git repository
|
||||
@@ -283,6 +295,7 @@ def check_torch():
|
||||
log.debug(f'Torch overrides: cuda={args.use_cuda} rocm={args.use_rocm} ipex={args.use_ipex} diml={args.use_directml}')
|
||||
log.debug(f'Torch allowed: cuda={allow_cuda} rocm={allow_rocm} ipex={allow_ipex} diml={allow_directml}')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', '')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
if torch_command != '':
|
||||
pass
|
||||
elif allow_cuda and (shutil.which('nvidia-smi') is not None or os.path.exists(os.path.join(os.environ.get('SystemRoot') or r'C:\Windows', 'System32', 'nvidia-smi.exe'))):
|
||||
@@ -301,7 +314,6 @@ def check_torch():
|
||||
if shutil.which('sycl-ls') is None:
|
||||
log.error('Intel OneAPI Toolkit is not activated! Start the WebUI with --use-ipex or activate OneAPI manually')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch==1.13.0a0 torchvision==0.14.1a0 intel_extension_for_pytorch==1.13.120+xpu -f https://developer.intel.com/ipex-whl-stable-xpu')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
else:
|
||||
machine = platform.machine()
|
||||
if sys.platform == 'darwin':
|
||||
@@ -309,13 +321,11 @@ def check_torch():
|
||||
elif allow_directml and args.use_directml and ('arm' not in machine and 'aarch' not in machine):
|
||||
log.info('Using DirectML Backend')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch-directml')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
if 'torch' in torch_command and not args.version:
|
||||
install(torch_command, 'torch torchvision')
|
||||
else:
|
||||
log.info('Using CPU-only Torch')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
if 'torch' in torch_command and not args.version:
|
||||
install(torch_command, 'torch torchvision')
|
||||
if args.skip_torch:
|
||||
@@ -405,6 +415,8 @@ def install_packages():
|
||||
# install(openclip_package, 'open-clip-torch')
|
||||
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git")
|
||||
install(clip_package, 'clip')
|
||||
invisiblewatermark_package = os.environ.get('INVISIBLEWATERMARK_PACKAGE', "git+https://github.com/patrickvonplaten/invisible-watermark.git@remove_onnxruntime_depedency")
|
||||
install(invisiblewatermark_package, 'invisible-watermark')
|
||||
install('onnxruntime==1.15.1', 'onnxruntime', ignore=True)
|
||||
if args.profile:
|
||||
print_profile(pr, 'Packages')
|
||||
@@ -417,7 +429,7 @@ def install_repositories():
|
||||
pr.enable()
|
||||
def d(name):
|
||||
return os.path.join(os.path.dirname(__file__), 'repositories', name)
|
||||
log.info('Installing repositories')
|
||||
log.info('Verifying repositories')
|
||||
os.makedirs(os.path.join(os.path.dirname(__file__), 'repositories'), exist_ok=True)
|
||||
stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git")
|
||||
# stable_diffusion_commit = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "cf1d67a6fd5ea1aa600c4df58e5b47da45f6bdbf")
|
||||
@@ -529,9 +541,9 @@ def install_submodules():
|
||||
if args.profile:
|
||||
pr = cProfile.Profile()
|
||||
pr.enable()
|
||||
log.info('Installing submodules')
|
||||
log.info('Verifying submodules')
|
||||
txt = git('submodule')
|
||||
log.debug(f'Submodules list: {txt}')
|
||||
# log.debug(f'Submodules list: {txt}')
|
||||
if 'no submodule mapping found' in txt:
|
||||
log.warning('Attempting repository recover')
|
||||
git('add .')
|
||||
@@ -543,15 +555,16 @@ def install_submodules():
|
||||
txt = git('submodule')
|
||||
log.info('Continuing setup')
|
||||
git('submodule --quiet update --init --recursive')
|
||||
if args.upgrade:
|
||||
log.info('Updating submodules')
|
||||
submodules = txt.splitlines()
|
||||
for submodule in submodules:
|
||||
try:
|
||||
name = submodule.split()[1].strip()
|
||||
submodules = txt.splitlines()
|
||||
for submodule in submodules:
|
||||
try:
|
||||
name = submodule.split()[1].strip()
|
||||
if args.upgrade:
|
||||
update(name)
|
||||
except Exception:
|
||||
log.error(f'Error updating submodule: {submodule}')
|
||||
else:
|
||||
branch(name)
|
||||
except Exception:
|
||||
log.error(f'Error updating submodule: {submodule}')
|
||||
if args.profile:
|
||||
print_profile(pr, 'Submodule')
|
||||
|
||||
@@ -656,7 +669,7 @@ def check_version(offline=False, reset=True): # pylint: disable=unused-argument
|
||||
try:
|
||||
git('add .')
|
||||
git('stash')
|
||||
update('.')
|
||||
update('.', current_branch=True)
|
||||
# git('git stash pop')
|
||||
ver = git('log -1 --pretty=format:"%h %ad"')
|
||||
log.info(f'Upgraded to version: {ver}')
|
||||
@@ -678,7 +691,6 @@ def update_wiki():
|
||||
log.info('Updating Wiki')
|
||||
try:
|
||||
update(os.path.join(os.path.dirname(__file__), "wiki"))
|
||||
update(os.path.join(os.path.dirname(__file__), "wiki", "origin-wiki"))
|
||||
except Exception:
|
||||
log.error('Error updating wiki')
|
||||
|
||||
|
||||
+61
-63
@@ -1,43 +1,58 @@
|
||||
/* generic html tags */
|
||||
:root { --font: "Source Sans Pro", 'ui-sans-serif', 'system-ui', "Roboto", sans-serif; }
|
||||
html { font-size: 16px; }
|
||||
:root {
|
||||
--font: "Source Sans Pro", 'ui-sans-serif', 'system-ui', "Roboto", sans-serif;
|
||||
--font-size: 16px;
|
||||
--left-column: 490px;
|
||||
--highlight-color: #ce6400;
|
||||
--inactive-color: #4e1400;
|
||||
--background-color: #000000;
|
||||
--primary-50: #fff7ed;
|
||||
--primary-100: #ffedd5;
|
||||
--primary-200: #fed7aa;
|
||||
--primary-300: #fdba74;
|
||||
--primary-400: #fb923c;
|
||||
--primary-500: #f97316;
|
||||
--primary-600: #ea580c;
|
||||
--primary-700: #c2410c;
|
||||
--primary-800: #9a3412;
|
||||
--primary-900: #7c2d12;
|
||||
--primary-950: #6c2e12;
|
||||
}
|
||||
.light, .dark {
|
||||
--radius-lg: 2px;
|
||||
--radius-sm: 1px;
|
||||
--spacing-md: 5px;
|
||||
}
|
||||
|
||||
html { font-size: var(--font-size); }
|
||||
body, button, input, select, textarea { font-family: var(--font);}
|
||||
button { font-size: 1.2rem; }
|
||||
img { background-color: black; }
|
||||
input[type=range] { height: 18px; appearance: none; margin-top: 0; min-width: 160px; background-color: black; width: 100%; background: transparent; }
|
||||
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 18px; cursor: pointer; box-shadow: 2px 2px 3px #111111; background: #50555C; border-radius: 2px; border: 0px solid #222222; }
|
||||
input[type=range]::-moz-range-track { width: 100%; height: 18px; cursor: pointer; box-shadow: 2px 2px 3px #111111; background: #50555C; border-radius: 2px; border: 0px solid #222222; }
|
||||
input[type=range]::-webkit-slider-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: 18px; width: 40px; border-radius: 2px; background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; }
|
||||
input[type=range]::-moz-range-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: 18px; width: 40px; border-radius: 2px; background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; }
|
||||
img { background-color: var(--background-color); }
|
||||
input[type=range] { height: 18px; appearance: none; margin-top: 0; min-width: 160px; background-color: var(--background-color); width: 100%; background: transparent; }
|
||||
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 18px; cursor: pointer; box-shadow: 2px 2px 3px #111111; background: #50555C; border-radius: var(--radius-lg); border: 0px solid #222222; }
|
||||
input[type=range]::-moz-range-track { width: 100%; height: 18px; cursor: pointer; box-shadow: 2px 2px 3px #111111; background: #50555C; border-radius: var(--radius-lg); border: 0px solid #222222; }
|
||||
input[type=range]::-webkit-slider-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: 18px; width: 40px; border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; }
|
||||
input[type=range]::-moz-range-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: 18px; width: 40px; border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; }
|
||||
::-webkit-scrollbar { width: 12px; }
|
||||
::-webkit-scrollbar-track { background: #333333; }
|
||||
::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: 2px; border-width: 0; box-shadow: 2px 2px 3px #111111; }
|
||||
::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px #111111; }
|
||||
div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em; margin-bottom: 6px; }
|
||||
|
||||
/* main gradio components by selector */
|
||||
div.gradio-container.dark > div.w-full.flex.flex-col.min-h-screen > div { background-color: black; }
|
||||
|
||||
/* gradio shadowroot */
|
||||
.gradio-container { font-family: var(--font); --left-column: 490px; --highlight-color: #CE6400; --inactive-color: #4E1400; }
|
||||
div.compact { gap: 0.8em; }
|
||||
|
||||
/* gradio style classes */
|
||||
fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; }
|
||||
.border-2 { border-width: 0; }
|
||||
.border-b-2 { border-bottom-width: 2px; border-color: var(--highlight-color) !important; padding-bottom: 2px; margin-bottom: 8px; }
|
||||
.dark .bg-white { color: lightyellow; border-radius: 0; background-color: var(--inactive-color); }
|
||||
.dark .bg-gray-200, .dark .\!bg-gray-200 { background-color: transparent; }
|
||||
.dark .dark\:bg-gray-900 { background-color: black; }
|
||||
.dark .gr-box { border-radius: 0 !important; background-color: #111111 !important; box-shadow: 2px 2px 3px #111111; border-width: 0; padding: 4px; margin: 12px 0px 12px 0px }
|
||||
.dark .gr-button { border-radius: 0; font-weight: normal; box-shadow: 2px 2px 3px #111111; font-size: 0.8rem; min-width: 32px; min-height: 32px; padding: 3px; margin: 3px; }
|
||||
.dark .gr-check-radio { background-color: var(--inactive-color); border-width: 0; border-radius: 2px; box-shadow: 2px 2px 3px #111111; }
|
||||
.dark .gr-check-radio:checked { background-color: var(--highlight-color); }
|
||||
.dark .gr-compact { border-radius: 0; background-color: black; }
|
||||
.dark .gr-form { border-radius: 0; border-width: 0; }
|
||||
.dark .gr-input { background-color: #333333 !important; padding: 4px; margin: 4px; }
|
||||
.dark .gr-input-label { color: lightyellow; border-width: 0; background: transparent; padding: 2px !important; }
|
||||
.dark .gr-panel { border-radius: 0; background-color: black; }
|
||||
.dark { background-color: black; }
|
||||
.dark fieldset span.text-gray-500, .dark .gr-block.gr-box span.text-gray-500, .dark label.block span { padding: 0; margin-top: -4px; }
|
||||
.dark fieldset span.text-gray-500, .dark .gr-block.gr-box span.text-gray-500, .dark label.block span { border-radius: 0;}
|
||||
.bg-white { color: lightyellow; background-color: var(--inactive-color); }
|
||||
.gr-box { border-radius: var(--radius-sm) !important; background-color: #111111 !important; box-shadow: 2px 2px 3px #111111; border-width: 0; padding: 4px; margin: 12px 0px 12px 0px }
|
||||
.gr-button { font-weight: normal; box-shadow: 2px 2px 3px #111111; font-size: 0.8rem; min-width: 32px; min-height: 32px; padding: 3px; margin: 3px; }
|
||||
.gr-check-radio { background-color: var(--inactive-color); border-width: 0; border-radius: var(--radius-lg); box-shadow: 2px 2px 3px #111111; }
|
||||
.gr-check-radio:checked { background-color: var(--highlight-color); }
|
||||
.gr-compact { background-color: var(--background-color); }
|
||||
.gr-form { border-width: 0; }
|
||||
.gr-input { background-color: #333333 !important; padding: 4px; margin: 4px; }
|
||||
.gr-input-label { color: lightyellow; border-width: 0; background: transparent; padding: 2px !important; }
|
||||
.gr-panel { background-color: var(--background-color); }
|
||||
.eta-bar { display: none !important }
|
||||
svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
.gap-2 { padding-top: 8px; }
|
||||
@@ -48,11 +63,9 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
.p-2 { padding: 0; }
|
||||
.px-4 { padding-lefT: 1rem; padding-right: 1rem; }
|
||||
.py-6 { padding-bottom: 0; }
|
||||
.rounded-lg { border-radius: 0; }
|
||||
.tabs { background-color: black; }
|
||||
.gradio-button.tool { border-radius: 0; }
|
||||
.block.token-counter span { background-color: #222 !important; box-shadow: 2px 2px 2px #111; border: none !important; border-radius: 0; font-size: 0.8rem; }
|
||||
.tab-nav { zoom: 120%; margin-bottom: 10px; border-bottom: 2px solid #CE6400 !important; padding-bottom: 2px; }
|
||||
.tabs { background-color: var(--background-color); }
|
||||
.block.token-counter span { background-color: #222 !important; box-shadow: 2px 2px 2px #111; border: none !important; font-size: 0.8rem; }
|
||||
.tab-nav { zoom: 120%; margin-bottom: 10px; border-bottom: 2px solid var(--highlight-color) !important; padding-bottom: 2px; }
|
||||
.label-wrap { margin: 16px 0px 8px 0px; }
|
||||
.gradio-slider input[type="number"] { width: 4.5em; font-size: 0.8rem; }
|
||||
#tab_extensions table td, #tab_extensions table th { border: none; padding: 0.5em; }
|
||||
@@ -60,26 +73,25 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
#tab_extensions table thead { background-color: var(--neutral-700); }
|
||||
|
||||
/* automatic style classes */
|
||||
.progressDiv { border-radius: 0 !important; position: fixed; top: 44px; right: 26px; max-width: 262px; height: 48px; z-index: 99; box-shadow: var(--button-shadow); }
|
||||
.progressDiv .progress { border-radius: 0 !important; background: var(--highlight-color); line-height: 3rem; height: 48px; }
|
||||
.progressDiv { border-radius: var(--radius-sm) !important; position: fixed; top: 44px; right: 26px; max-width: 262px; height: 48px; z-index: 99; box-shadow: var(--button-shadow); }
|
||||
.progressDiv .progress { border-radius: var(--radius-lg) !important; background: var(--highlight-color); line-height: 3rem; height: 48px; }
|
||||
.gallery-item { box-shadow: none !important; }
|
||||
.performance { color: #888; }
|
||||
.extra-networks { border-left: 2px solid #CE6400 !important; padding-left: 4px; }
|
||||
.extra-networks { border-left: 2px solid var(--highlight-color) !important; padding-left: 4px; }
|
||||
.image-buttons { gap: 10px !important}
|
||||
|
||||
/* gradio elements overrides */
|
||||
#div.gradio-container.dark { overflow-x: hidden; }
|
||||
#div.gradio-container { overflow-x: hidden; }
|
||||
#img2img_label_copy_to_img2img { font-weight: normal; }
|
||||
#txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt { background-color: black; box-shadow: 4px 4px 4px 0px #333333 !important; }
|
||||
#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.2rem; }
|
||||
#txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt { background-color: var(--background-color); box-shadow: 4px 4px 4px 0px #333333 !important; }
|
||||
#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.1rem; }
|
||||
#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: #111111; padding-top: 16px; }
|
||||
#interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; }
|
||||
#lightboxModal { background-color: rgba(20, 20, 20, 0.8) }
|
||||
#quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; }
|
||||
#quicksettings > div, #quicksettings > fieldset { min-width: 24em; max-width: 26em; line-height: 2em; }
|
||||
#refresh_sd_model_checkpoint { height: 48px; margin-left: -14px; background: #333333; box-shadow: none; }
|
||||
#open_folder_extras, #footer, #style_pos_col, #style_neg_col, #roll_col, #extras_upscaler_2, #extras_upscaler_2_visibility, #txt2img_seed_resize_from_w, #txt2img_seed_resize_from_h { display: none; }
|
||||
#save-animation { border-radius: 0 !important; margin-bottom: 16px; background-color: #111111; }
|
||||
#save-animation { border-radius: var(--radius-sm) !important; margin-bottom: 16px; background-color: #111111; }
|
||||
#script_list { padding: 4px; margin-top: 20px; margin-bottom: 20px; }
|
||||
#settings > div.flex-wrap { width: 15em; }
|
||||
#tab_extensions table { background-color: #222222; }
|
||||
@@ -90,7 +102,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
|
||||
#extras_upscale { margin-top: 10px }
|
||||
#txt2img_progress_row > div { min-width: var(--left-column); max-width: var(--left-column); }
|
||||
#txt2img_results, #img2img_results, #extras_results { background-color: black; padding: 0; }
|
||||
#txt2img_results, #img2img_results, #extras_results { background-color: var(--background-color); padding: 0; }
|
||||
#txt2img_seed_row { padding: 0; margin-top: 8px; }
|
||||
#txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: #111111; padding-top: 16px; }
|
||||
#txt2img_subseed_row { padding: 0; margin-top: 16px; }
|
||||
@@ -104,14 +116,14 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
#steps-animation, #controlnet { border-width: 0; }
|
||||
|
||||
/* based on gradio built-in dark theme */
|
||||
.dark {
|
||||
--body-background-fill: black;
|
||||
:root, .light, .dark {
|
||||
--body-background-fill: var(--background-color);
|
||||
--body-text-color: var(--neutral-100);
|
||||
--color-accent-soft: var(--neutral-700);
|
||||
--background-fill-primary: #222222;
|
||||
--background-fill-secondary: none;
|
||||
--border-color-accent: black;
|
||||
--border-color-primary: black;
|
||||
--border-color-accent: var(--background-color);
|
||||
--border-color-primary: var(--background-color);
|
||||
--link-text-color-active: var(--secondary-500);
|
||||
--link-text-color: var(--secondary-500);
|
||||
--link-text-color-hover: var(--secondary-400);
|
||||
@@ -191,17 +203,6 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
--button-secondary-border-color-hover: var(--button-secondary-border-color);
|
||||
--button-secondary-text-color: white;
|
||||
--button-secondary-text-color-hover: var(--button-secondary-text-color);
|
||||
--primary-50: #fff7ed;
|
||||
--primary-100: #ffedd5;
|
||||
--primary-200: #fed7aa;
|
||||
--primary-300: #fdba74;
|
||||
--primary-400: #fb923c;
|
||||
--primary-500: #f97316;
|
||||
--primary-600: #ea580c;
|
||||
--primary-700: #c2410c;
|
||||
--primary-800: #9a3412;
|
||||
--primary-900: #7c2d12;
|
||||
--primary-950: #6c2e12;
|
||||
--secondary-50: #eff6ff;
|
||||
--secondary-100: #dbeafe;
|
||||
--secondary-200: #bfdbfe;
|
||||
@@ -227,15 +228,12 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
--spacing-xxs: 1px;
|
||||
--spacing-xs: 2px;
|
||||
--spacing-sm: 4px;
|
||||
--spacing-md: 6px;
|
||||
--spacing-lg: 8px;
|
||||
--spacing-xl: 10px;
|
||||
--spacing-xxl: 18px;
|
||||
--radius-xxs: 0;
|
||||
--radius-xs: 0;
|
||||
--radius-sm: 0;
|
||||
--radius-md: 0;
|
||||
--radius-lg: 0;
|
||||
--radius-xl: 0;
|
||||
--radius-xxl: 0;
|
||||
--text-xxs: 9px;
|
||||
@@ -282,7 +280,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
--section-header-text-weight: 400;
|
||||
--checkbox-border-radius: var(--radius-sm);
|
||||
--checkbox-label-gap: 2px;
|
||||
--checkbox-label-padding: var(--spacing-md) calc(2 * var(--spacing-md));
|
||||
--checkbox-label-padding: var(--spacing-md);
|
||||
--checkbox-label-shadow: var(--shadow-drop);
|
||||
--checkbox-label-text-size: var(--text-md);
|
||||
--checkbox-label-text-weight: 400;
|
||||
|
||||
+29
-30
@@ -9,6 +9,7 @@ function setupExtraNetworksForTab(tabname) {
|
||||
const refresh = gradioApp().getElementById(`${tabname}_extra_refresh`);
|
||||
const description = gradioApp().getElementById(`${tabname}_description`);
|
||||
const close = gradioApp().getElementById(`${tabname}_extra_close`);
|
||||
const en = gradioApp().getElementById(`${tabname}_extra_networks`);
|
||||
search.classList.add('search');
|
||||
description.classList.add('description');
|
||||
tabs.appendChild(refresh);
|
||||
@@ -19,48 +20,46 @@ function setupExtraNetworksForTab(tabname) {
|
||||
searchTerm = search.value.toLowerCase();
|
||||
gradioApp().querySelectorAll(`#${tabname}_extra_tabs div.card`).forEach((elem) => {
|
||||
text = `${elem.querySelector('.name').textContent.toLowerCase()} ${elem.querySelector('.search_term').textContent.toLowerCase()}`;
|
||||
text = text.replace('models--', 'Diffusers')
|
||||
elem.style.display = text.indexOf(searchTerm) == -1 ? 'none' : '';
|
||||
});
|
||||
});
|
||||
|
||||
intersectionObserver = new IntersectionObserver((entries) => {
|
||||
// if (entries[0].intersectionRatio <= 0) onHidden();
|
||||
const en = gradioApp().getElementById(`${tabname}_extra_networks`);
|
||||
if (!en) return
|
||||
for (el of Array.from(gradioApp().querySelectorAll('.extra-networks-page'))) el.style.height = window.opts.extra_networks_height + 'vh';
|
||||
if (entries[0].intersectionRatio > 0) {
|
||||
for (el of Array.from(gradioApp().querySelectorAll('.extra-network-cards'))) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
if (window.opts.extra_networks_card_cover === 'cover') {
|
||||
en.style.transition = '';
|
||||
en.style.zIndex = 9999;
|
||||
en.style.position = 'absolute';
|
||||
en.style.right = 'unset';
|
||||
en.style.width = 'unset';
|
||||
en.style.height = 'unset';
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset'
|
||||
} else if (window.opts.extra_networks_card_cover === 'sidebar') {
|
||||
en.style.transition = 'width 0.2s ease';
|
||||
if (rect.top > 0) {
|
||||
if (!en) return
|
||||
if (window.opts.extra_networks_card_cover == 'cover') {
|
||||
en.style.zIndex = 9999;
|
||||
en.style.position = 'absolute';
|
||||
en.style.right = 'unset';
|
||||
en.style.width = 'unset';
|
||||
el.style.height = document.body.offsetHeight - el.getBoundingClientRect().top + 'px';
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset'
|
||||
} if (window.opts.extra_networks_card_cover == 'sidebar') {
|
||||
en.style.zIndex = 0;
|
||||
en.style.position = 'absolute';
|
||||
en.style.right = '0';
|
||||
en.style.width = window.opts.extra_networks_sidebar_width + 'vw';
|
||||
el.style.height = gradioApp().getElementById(`${tabname}_settings`).offsetHeight - 90 + 'px';
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 100 - 2 - window.opts.extra_networks_sidebar_width + 'vw';
|
||||
} else {
|
||||
en.style.zIndex = 0;
|
||||
en.style.position = 'relative';
|
||||
en.style.right = 'unset';
|
||||
en.style.width = 'unset';
|
||||
el.style.height = window.innerHeight - el.getBoundingClientRect().top + 'px';
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset'
|
||||
}
|
||||
}
|
||||
en.style.zIndex = 0;
|
||||
en.style.position = 'absolute';
|
||||
en.style.right = '0';
|
||||
en.style.width = window.opts.extra_networks_sidebar_width + 'vw';
|
||||
en.style.height = '-webkit-fill-available'
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 100 - 2 - window.opts.extra_networks_sidebar_width + 'vw';
|
||||
} else {
|
||||
en.style.transition = '';
|
||||
en.style.zIndex = 0;
|
||||
en.style.position = 'relative';
|
||||
en.style.right = 'unset';
|
||||
en.style.width = 'unset';
|
||||
en.style.height = 'unset';
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset'
|
||||
}
|
||||
} else {
|
||||
en.style.width = 0;
|
||||
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset'
|
||||
}
|
||||
});
|
||||
intersectionObserver.observe(search); // monitor visibility of
|
||||
intersectionObserver.observe(en); // monitor visibility of
|
||||
}
|
||||
|
||||
function setupExtraNetworks() {
|
||||
|
||||
@@ -149,9 +149,7 @@ onAfterUiUpdate(() => {
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// const modalFragment = document.createDocumentFragment();
|
||||
const modal = document.createElement('div');
|
||||
modal.onclick = closeModal;
|
||||
modal.id = 'lightboxModal';
|
||||
modal.tabIndex = 0;
|
||||
modal.addEventListener('keydown', modalKeyHandler, true);
|
||||
@@ -182,22 +180,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
modalSave.title = 'Save Image(s)';
|
||||
modalControls.appendChild(modalSave);
|
||||
|
||||
/*
|
||||
const modalClose = document.createElement('span');
|
||||
modalClose.className = 'modalClose cursor';
|
||||
modalClose.innerHTML = '×';
|
||||
modalClose.onclick = closeModal;
|
||||
modalClose.title = 'Close image viewer';
|
||||
modalControls.appendChild(modalClose);
|
||||
*/
|
||||
|
||||
const modalImage = document.createElement('img');
|
||||
modalImage.id = 'modalImage';
|
||||
modalImage.onclick = closeModal;
|
||||
modalImage.tabIndex = 0;
|
||||
modalImage.addEventListener('keydown', modalKeyHandler, true);
|
||||
modal.appendChild(modalImage);
|
||||
modalImage.onload = () => panzoom(modalImage, { zoomSpeed: 0.025, minZoom: 0.25, maxZoom: 4.0 });
|
||||
|
||||
let drag = false;
|
||||
modal.addEventListener('mousedown', () => drag = false);
|
||||
modal.addEventListener('mousemove', () => drag = true);
|
||||
modal.addEventListener('scroll', () => drag = true);
|
||||
modal.addEventListener('mouseup', () => { if (!drag) closeModal(); });
|
||||
|
||||
const modalPrev = document.createElement('a');
|
||||
modalPrev.className = 'modalPrev';
|
||||
modalPrev.innerHTML = '❮';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+7
-11
@@ -28,7 +28,7 @@ div.gradio-html.min{ min-height: 0; }
|
||||
footer { display: none; }
|
||||
|
||||
/* general styled components */
|
||||
.gradio-button.tool{ max-width: 2.3em; min-width: 2.3em !important; height: 2.3em; align-self: end; line-height: 1em; border-radius: 0.5em; }
|
||||
.gradio-button.tool{ max-width: 2.3em; min-width: 2.3em !important; height: 2.3em; align-self: end; line-height: 1em }
|
||||
.gradio-button.secondary-down{ background: var(--button-secondary-background-fill); color: var(--button-secondary-text-color); }
|
||||
.gradio-button.secondary-down, .gradio-button.secondary-down:hover{ box-shadow: 1px 1px 1px rgba(0,0,0,0.25) inset, 0px 0px 3px rgba(0,0,0,0.15) inset; }
|
||||
.gradio-button.secondary-down:hover{ background: var(--button-secondary-background-fill-hover); color: var(--button-secondary-text-color-hover); }
|
||||
@@ -69,7 +69,6 @@ button.custom-button{
|
||||
background: var(--input-background-fill) !important;
|
||||
box-shadow: 0 0 0.0 0.3em rgba(192,192,192,0.15), inset 0 0 0.6em rgba(192,192,192,0.075);
|
||||
border: 2px solid rgba(192,192,192,0.4) !important;
|
||||
border-radius: 0.4em;
|
||||
}
|
||||
|
||||
.block.token-counter.error span{
|
||||
@@ -100,7 +99,8 @@ button.custom-button{
|
||||
}
|
||||
|
||||
#txt2img_gallery img, #img2img_gallery img, #extras_gallery img { object-fit: scale-down; width: -webkit-fill-available !important; }
|
||||
#txt2img_footer, #img2img_footer, #extras_footer{ height: fit-content; display: none; }
|
||||
#txt2img_footer, #img2img_footer, #extras_footer { height: fit-content; }
|
||||
#txt2img_footer, #img2img_footer { height: fit-content; display: none; }
|
||||
#txt2img_generate_box, #img2img_generate_box { gap: 0.5em; flex-wrap: wrap-reverse; }
|
||||
#txt2img_actions_column, #img2img_actions_column { gap: 0.5em; }
|
||||
#txt2img_generate_box > button, #img2img_generate_box > button { height: 2.2em; line-height: 0; }
|
||||
@@ -315,7 +315,6 @@ div#extras_scale_to_tab div.form{
|
||||
position: relative;
|
||||
height: 20px;
|
||||
background: #b4c0cc;
|
||||
border-radius: 3px !important;
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
||||
@@ -332,7 +331,6 @@ div#extras_scale_to_tab div.form{
|
||||
line-height: 20px;
|
||||
padding: 0 8px 0 0;
|
||||
text-align: right;
|
||||
border-radius: 3px;
|
||||
overflow: visible;
|
||||
white-space: nowrap;
|
||||
padding: 0 0.5em;
|
||||
@@ -434,6 +432,7 @@ div#extras_scale_to_tab div.form{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
table.settings-value-table{
|
||||
@@ -463,14 +462,12 @@ table.settings-value-table td{
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
transition: 0.6s ease;
|
||||
border-radius: 0 3px 3px 0;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.modalNext {
|
||||
right: 0;
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
|
||||
.modalPrev:hover, .modalNext:hover {
|
||||
@@ -496,7 +493,6 @@ table.settings-value-table td{
|
||||
display:block;
|
||||
padding:0px 0;
|
||||
border:2px solid #a55000;
|
||||
border-radius:8px;
|
||||
box-shadow:1px 1px 2px #CE6400;
|
||||
width: 200px;
|
||||
}
|
||||
@@ -538,11 +534,11 @@ table.settings-value-table td{
|
||||
.extra-networks .description { margin-top: 8px; }
|
||||
.extra-networks .tab-nav > button { margin-right: 0; height: auto; padding: 2px 4px 2px 4px; }
|
||||
.extra-networks-tab { padding: 0 !important; }
|
||||
.extra-network-subdirs { background: var(--input-background-fill); }
|
||||
.extra-network-subdirs { background: var(--input-background-fill); overflow-x: hidden; overflow-y: auto; min-width: 80px; max-width: 120px; }
|
||||
.extra-networks-page { display: flex }
|
||||
.extra-networks .custom-button { min-width: 60px; width: 100%; background: none; justify-content: left; padding: 2px 8px 2px 8px; box-shadow: none; }
|
||||
.extra-networks .custom-button { min-width: 80px; max-width: 120px; width: 100%; background: none; justify-content: left; text-align: left; padding: 2px 8px 2px 8px; box-shadow: none; line-break: auto; }
|
||||
.extra-networks .custom-button:hover { background: var(--button-primary-background-fill) }
|
||||
.extra-network-cards { display: flex; flex-wrap: wrap; height: 50vh; overflow-y: scroll; overflow-x: hidden; scroll-snap-type: y mandatory; width: -webkit-fill-available; }
|
||||
.extra-network-cards { display: flex; flex-wrap: wrap; overflow-y: scroll; overflow-x: hidden; width: -webkit-fill-available; }
|
||||
.extra-network-cards .card { height: fit-content; margin: 0.5em; position: relative; scroll-snap-align: start; scroll-margin-top: 0; }
|
||||
.extra-network-cards .card .overlay { position: absolute; bottom: 0; padding: 0.2em; z-index: 10; width: 100%; background: none; }
|
||||
.extra-network-cards .card:hover .overlay { background: rgba(0, 0, 0, 0.40); }
|
||||
|
||||
@@ -174,6 +174,7 @@ if __name__ == "__main__":
|
||||
installer.install_repositories()
|
||||
installer.install_submodules()
|
||||
installer.install_extensions()
|
||||
installer.install_packages() # redo packages since extensions may change them
|
||||
installer.update_wiki()
|
||||
if installer.errors == 0:
|
||||
installer.log.debug(f'Setup complete without errors: {round(time.time())}')
|
||||
|
||||
+6
-8
@@ -237,7 +237,7 @@ class Api:
|
||||
script_runner = scripts.scripts_txt2img
|
||||
if not script_runner.scripts:
|
||||
script_runner.initialize_scripts(False)
|
||||
ui.create_ui()
|
||||
ui.create_ui(None)
|
||||
if not self.default_script_arg_txt2img:
|
||||
self.default_script_arg_txt2img = self.init_default_script_args(script_runner)
|
||||
selectable_scripts, selectable_script_idx = self.get_selectable_script(txt2imgreq.script_name, script_runner)
|
||||
@@ -282,7 +282,7 @@ class Api:
|
||||
script_runner = scripts.scripts_img2img
|
||||
if not script_runner.scripts:
|
||||
script_runner.initialize_scripts(True)
|
||||
ui.create_ui()
|
||||
ui.create_ui(None)
|
||||
if not self.default_script_arg_img2img:
|
||||
self.default_script_arg_img2img = self.init_default_script_args(script_runner)
|
||||
selectable_scripts, selectable_script_idx = self.get_selectable_script(img2imgreq.script_name, script_runner)
|
||||
@@ -406,17 +406,15 @@ class Api:
|
||||
|
||||
def interruptapi(self):
|
||||
shared.state.interrupt()
|
||||
|
||||
return {}
|
||||
|
||||
def unloadapi(self):
|
||||
unload_model_weights()
|
||||
|
||||
unload_model_weights(op='model')
|
||||
unload_model_weights(op='refiner')
|
||||
return {}
|
||||
|
||||
def reloadapi(self):
|
||||
reload_model_weights()
|
||||
|
||||
return {}
|
||||
|
||||
def skip(self):
|
||||
@@ -650,8 +648,8 @@ class Api:
|
||||
"port": shared.cmd_opts.port,
|
||||
"keyfile": shared.cmd_opts.tls_keyfile,
|
||||
"certfile": shared.cmd_opts.tls_certfile,
|
||||
"loop": "auto",
|
||||
"http": "auto",
|
||||
"loop": "auto", # auto, asyncio, uvloop
|
||||
"http": "auto", # auto, h11, httptools
|
||||
}
|
||||
from modules.server import UvicornServer
|
||||
server = UvicornServer(self.app, **config)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import inspect
|
||||
from typing import Any, Optional, Dict, List
|
||||
from pydantic import BaseModel, Field, create_model # pylint: disable=no-name-in-module
|
||||
from typing_extensions import Literal
|
||||
from inflection import underscore
|
||||
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
|
||||
import modules.shared as shared
|
||||
@@ -133,7 +132,7 @@ class ImageToImageResponse(BaseModel):
|
||||
info: str
|
||||
|
||||
class ExtrasBaseRequest(BaseModel):
|
||||
resize_mode: Literal[0, 1] = Field(default=0, title="Resize Mode", description="Sets the resize mode: 0 to upscale by upscaling_resize amount, 1 to upscale up to upscaling_resize_h x upscaling_resize_w.")
|
||||
resize_mode: float = Field(default=0, title="Resize Mode", description="Sets the resize mode: 0 to upscale by upscaling_resize amount, 1 to upscale up to upscaling_resize_h x upscaling_resize_w.")
|
||||
show_extras_results: bool = Field(default=True, title="Show results", description="Should the backend return the generated image?")
|
||||
gfpgan_visibility: float = Field(default=0, title="GFPGAN Visibility", ge=0, le=1, allow_inf_nan=False, description="Sets the visibility of GFPGAN, values should be between 0 and 1.")
|
||||
codeformer_visibility: float = Field(default=0, title="CodeFormer Visibility", ge=0, le=1, allow_inf_nan=False, description="Sets the visibility of CodeFormer, values should be between 0 and 1.")
|
||||
|
||||
+3
-1
@@ -45,7 +45,7 @@ group.add_argument('--use-directml', default = False, action='store_true', help
|
||||
group.add_argument("--use-cuda", default=False, action='store_true', help="Force use nVidia CUDA backend, default: %(default)s")
|
||||
group.add_argument("--use-rocm", default=False, action='store_true', help="Force use AMD ROCm backend, default: %(default)s")
|
||||
group.add_argument('--subpath', type=str, help='Customize the URL subpath for usage with reverse proxy')
|
||||
group.add_argument('--backend', type=str, choices=[None, 'original', 'diffusers'], default=None, required=False, help='force backend type')
|
||||
group.add_argument('--backend', type=str, choices=['original', 'diffusers'], required=False, help='force model pipeline type')
|
||||
|
||||
|
||||
# removed args are added here as hidden in fixed format for compatbility reasons
|
||||
@@ -90,6 +90,8 @@ def compatibility_args(opts, args):
|
||||
group.add_argument("--sub-quad-chunk-threshold", help=argparse.SUPPRESS, default=opts.sub_quad_chunk_threshold)
|
||||
group.add_argument("--lora-dir", help=argparse.SUPPRESS, default=opts.lora_dir)
|
||||
group.add_argument("--lyco-dir", help=argparse.SUPPRESS, default=opts.lyco_dir)
|
||||
group.add_argument("--embeddings-dir", help=argparse.SUPPRESS, default=opts.embeddings_dir)
|
||||
group.add_argument("--hypernetwork-dir", help=argparse.SUPPRESS, default=opts.hypernetwork_dir)
|
||||
group.add_argument("--lyco-patch-lora", help=argparse.SUPPRESS, default=opts.lyco_patch_lora)
|
||||
group.add_argument("--lyco-debug", help=argparse.SUPPRESS, action='store_true', default=False)
|
||||
group.add_argument("--enable-console-prompts", help=argparse.SUPPRESS, action='store_true', default=False)
|
||||
|
||||
@@ -8,6 +8,8 @@ if sys.platform == "darwin":
|
||||
from modules import mac_specific # pylint: disable=ungrouped-imports
|
||||
|
||||
cuda_ok = torch.cuda.is_available()
|
||||
previous_oom = 0
|
||||
|
||||
|
||||
def has_mps() -> bool:
|
||||
if sys.platform != "darwin":
|
||||
@@ -15,6 +17,7 @@ def has_mps() -> bool:
|
||||
else:
|
||||
return mac_specific.has_mps
|
||||
|
||||
|
||||
def extract_device_id(args, name): # pylint: disable=redefined-outer-name
|
||||
for x in range(len(args)):
|
||||
if name in args[x]:
|
||||
@@ -61,6 +64,18 @@ def get_device_for(task):
|
||||
|
||||
|
||||
def torch_gc(force=False):
|
||||
mem = memstats.memory_stats()
|
||||
gpu = mem.get('gpu', {})
|
||||
oom = gpu.get('oom', 0)
|
||||
used = round(100 * gpu.get('used', 0) / gpu.get('total', 1))
|
||||
global previous_oom # pylint: disable=global-statement
|
||||
if oom > previous_oom:
|
||||
previous_oom = oom
|
||||
shared.log.warning(f'GPU out-of-memory error: {mem}')
|
||||
if used > 90:
|
||||
shared.log.warning(f'GPU high memory utilization: {used}% {mem}')
|
||||
force = True
|
||||
|
||||
if shared.opts.disable_gc and not force:
|
||||
return
|
||||
collected = gc.collect()
|
||||
@@ -122,6 +137,7 @@ def set_cuda_params():
|
||||
try:
|
||||
torch.backends.cudnn.benchmark = True
|
||||
if shared.opts.cudnn_benchmark:
|
||||
shared.log.debug('Torch enable cuDNN benchmark')
|
||||
torch.backends.cudnn.benchmark_limit = 0
|
||||
torch.backends.cudnn.allow_tf32 = shared.opts.cuda_allow_tf32
|
||||
except Exception:
|
||||
|
||||
@@ -3,6 +3,7 @@ import torch
|
||||
import torch_directml # pylint: disable=import-error
|
||||
import modules.dml.hijack
|
||||
import modules.dml.amp as amp
|
||||
from modules.dml.opts import override_opts
|
||||
|
||||
from .optimizer.unknown import UnknownOptimizer
|
||||
|
||||
@@ -31,6 +32,8 @@ class DirectML():
|
||||
return optimizer.memory_stats(device.index)
|
||||
|
||||
|
||||
# Alternative of torch.cuda for DirectML.
|
||||
DirectML.amp = amp
|
||||
# Alternative of torch.cuda for DirectML.
|
||||
torch.dml = DirectML
|
||||
|
||||
override_opts()
|
||||
|
||||
@@ -3,3 +3,4 @@ import modules.dml.hijack.stablediffusion
|
||||
import modules.dml.hijack.torch
|
||||
import modules.dml.hijack.realesrgan_model
|
||||
import modules.dml.hijack.plms
|
||||
import modules.dml.hijack.diffusers
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
from torch import FloatTensor
|
||||
import diffusers
|
||||
|
||||
def _get_prev_sample(self, sample: FloatTensor, timestep, prev_timestep, model_output):
|
||||
# See formula (9) of PNDM paper https://arxiv.org/pdf/2202.09778.pdf
|
||||
# this function computes x_(t−δ) using the formula of (9)
|
||||
# Note that x_t needs to be added to both sides of the equation
|
||||
|
||||
# Notation (<variable name> -> <name in paper>
|
||||
# alpha_prod_t -> α_t
|
||||
# alpha_prod_t_prev -> α_(t−δ)
|
||||
# beta_prod_t -> (1 - α_t)
|
||||
# beta_prod_t_prev -> (1 - α_(t−δ))
|
||||
# sample -> x_t
|
||||
# model_output -> e_θ(x_t, t)
|
||||
# prev_sample -> x_(t−δ)
|
||||
sample.__str__() # DML Solution: PNDM Sampling does not work without 'stringify'. (because it depends on PLMS)
|
||||
alpha_prod_t = self.alphas_cumprod[timestep]
|
||||
alpha_prod_t_prev = self.alphas_cumprod[prev_timestep] if prev_timestep >= 0 else self.final_alpha_cumprod
|
||||
beta_prod_t = 1 - alpha_prod_t
|
||||
beta_prod_t_prev = 1 - alpha_prod_t_prev
|
||||
|
||||
if self.config.prediction_type == "v_prediction":
|
||||
model_output = (alpha_prod_t**0.5) * model_output + (beta_prod_t**0.5) * sample
|
||||
elif self.config.prediction_type != "epsilon":
|
||||
raise ValueError(
|
||||
f"prediction_type given as {self.config.prediction_type} must be one of `epsilon` or `v_prediction`"
|
||||
)
|
||||
|
||||
# corresponds to (α_(t−δ) - α_t) divided by
|
||||
# denominator of x_t in formula (9) and plus 1
|
||||
# Note: (α_(t−δ) - α_t) / (sqrt(α_t) * (sqrt(α_(t−δ)) + sqr(α_t))) =
|
||||
# sqrt(α_(t−δ)) / sqrt(α_t))
|
||||
sample_coeff = (alpha_prod_t_prev / alpha_prod_t) ** (0.5)
|
||||
|
||||
# corresponds to denominator of e_θ(x_t, t) in formula (9)
|
||||
model_output_denom_coeff = alpha_prod_t * beta_prod_t_prev ** (0.5) + (
|
||||
alpha_prod_t * beta_prod_t * alpha_prod_t_prev
|
||||
) ** (0.5)
|
||||
|
||||
# full formula (9)
|
||||
prev_sample = (
|
||||
sample_coeff * sample - (alpha_prod_t_prev - alpha_prod_t) * model_output / model_output_denom_coeff
|
||||
)
|
||||
|
||||
return prev_sample
|
||||
|
||||
diffusers.PNDMScheduler._get_prev_sample = _get_prev_sample
|
||||
@@ -48,7 +48,7 @@ def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=F
|
||||
|
||||
def get_x_prev_and_pred_x0(e_t, index):
|
||||
# select parameters corresponding to the currently considered timestep
|
||||
print(alphas[index]) # DML Solution: PLMS Sampling does not work without this print.
|
||||
alphas[index].__str__() # DML Solution: PLMS Sampling does not work without this 'stringify'.
|
||||
a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
|
||||
a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
|
||||
sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
|
||||
|
||||
@@ -51,7 +51,7 @@ def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=F
|
||||
sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
|
||||
sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
|
||||
# select parameters corresponding to the currently considered timestep
|
||||
print(alphas[index]) # DML Solution: DDIM Sampling does not work without this print.
|
||||
alphas[index].__str__() # DML Solution: DDIM Sampling does not work without this 'stringify'.
|
||||
a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
|
||||
a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
|
||||
sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from modules import shared
|
||||
|
||||
def override_opts():
|
||||
if shared.backend == shared.Backend.DIFFUSERS:
|
||||
shared.opts.diffusers_generator_device = "cpu" # DirectML does not support torch.Generator API.
|
||||
+1
-1
@@ -133,7 +133,7 @@ def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0):
|
||||
except Exception:
|
||||
return ImageFont.truetype('html/roboto.ttf', fontsize)
|
||||
|
||||
def draw_texts(drawing, draw_x, draw_y, lines, initial_fnt, initial_fontsize):
|
||||
def draw_texts(drawing: ImageDraw, draw_x, draw_y, lines, initial_fnt, initial_fontsize):
|
||||
for line in lines:
|
||||
fnt = initial_fnt
|
||||
fontsize = initial_fontsize
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import diffusers
|
||||
from modules import shared
|
||||
|
||||
lora_state = { # TODO Lora state for Diffusers
|
||||
'multiplier': 1.0,
|
||||
'active': False,
|
||||
'loaded': 0,
|
||||
}
|
||||
|
||||
def unload_diffusers_lora():
|
||||
try:
|
||||
pipe = shared.sd_model
|
||||
lora_state['active'] = False
|
||||
lora_state['loaded'] = 0
|
||||
pipe._remove_text_encoder_monkey_patch() # pylint: disable=W0212
|
||||
proc_cls_name = next(iter(pipe.unet.attn_processors.values())).__class__.__name__
|
||||
non_lora_proc_cls = getattr(diffusers.models.attention_processor, proc_cls_name[len("LORA"):])
|
||||
pipe.unet.set_attn_processor(non_lora_proc_cls())
|
||||
# shared.log.debug('Diffusers LoRA unloaded')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def load_diffusers_lora(name, lora, strength = 1.0):
|
||||
try:
|
||||
pipe = shared.sd_model
|
||||
pipe.load_lora_weights(lora.filename, cache_dir=shared.opts.diffusers_dir, local_files_only=True)
|
||||
lora_state['active'] = True
|
||||
lora_state['loaded'] += 1
|
||||
lora_state['multiplier'] = strength
|
||||
# pipe.unet.load_attn_procs("pcuenq/pokemon-lora")
|
||||
shared.log.info(f"Diffusers LoRA loaded: {name} {lora_state['multiplier']}")
|
||||
except Exception as e:
|
||||
shared.log.error(f"Diffusers LoRA loading failed: {name} {e}")
|
||||
+51
-20
@@ -1,6 +1,8 @@
|
||||
import os
|
||||
import shutil
|
||||
import importlib
|
||||
import json
|
||||
from typing import Dict
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from modules import shared
|
||||
@@ -9,30 +11,60 @@ from modules.paths import script_path, models_path
|
||||
|
||||
diffuser_repos = []
|
||||
|
||||
def load_diffusers(model_path: str, hub_url: str = None, command_path: str = None):
|
||||
import huggingface_hub as hf
|
||||
|
||||
def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config: Dict[str, str] = None, token = None):
|
||||
from diffusers import DiffusionPipeline
|
||||
import huggingface_hub as hf
|
||||
|
||||
if download_config is None:
|
||||
download_config = {
|
||||
"force_download": False,
|
||||
"resume_download": True,
|
||||
"cache_dir": shared.opts.diffusers_dir,
|
||||
# "use_auth_token": True,
|
||||
}
|
||||
if cache_dir is not None:
|
||||
download_config["cache_dir"] = cache_dir
|
||||
shared.log.debug(f"Diffusers downloading: {hub_id} to {cache_dir}")
|
||||
if token is not None and len(token) > 2:
|
||||
shared.log.debug(f"Diffusers authentication: {token}")
|
||||
hf.login(token)
|
||||
pipeline_dir = DiffusionPipeline.download(hub_id, **download_config)
|
||||
try:
|
||||
model_info_dict = hf.model_info(hub_id).cardData # TODO HF-Hub cardData invalid property
|
||||
except Exception:
|
||||
model_info_dict = None
|
||||
# some checkpoints need to be downloaded as "hidden" as they just serve as pre- or post-pipelines of other pipelines
|
||||
if model_info_dict is not None and "prior" in model_info_dict:
|
||||
download_dir = DiffusionPipeline.download(model_info_dict["prior"], **download_config)
|
||||
model_info_dict["prior"] = download_dir
|
||||
# mark prior as hidden
|
||||
with open(os.path.join(download_dir, "hidden"), "w", encoding="utf-8") as f:
|
||||
f.write("True")
|
||||
with open(os.path.join(pipeline_dir, "model_info.json"), "w", encoding="utf-8") as json_file:
|
||||
json.dump(model_info_dict, json_file)
|
||||
return pipeline_dir
|
||||
|
||||
|
||||
def load_diffusers_models(model_path: str, command_path: str = None):
|
||||
import huggingface_hub as hf
|
||||
places = []
|
||||
|
||||
# download repo
|
||||
if hub_url is not None:
|
||||
DiffusionPipeline.download(hub_url, cache_dir=model_path)
|
||||
|
||||
places.append(model_path)
|
||||
if command_path is not None and command_path != model_path and os.path.isdir(command_path):
|
||||
places.append(command_path)
|
||||
diffuser_repos.clear()
|
||||
output = []
|
||||
try:
|
||||
for place in places:
|
||||
for place in places:
|
||||
try:
|
||||
res = hf.scan_cache_dir(cache_dir=place)
|
||||
for r in list(res.repos):
|
||||
diffuser_repos.append({ 'name': r.repo_id, 'filename': r.repo_id, 'path': str(r.repo_path), 'size': r.size_on_disk, 'mtime': r.last_modified, 'hash': list(r.revisions)[-1].commit_hash })
|
||||
output.append(str(r.repo_id))
|
||||
except Exception as e:
|
||||
shared.log.error(f"Error listing diffusers: {place} {e}")
|
||||
shared.log.debug(f'Scanning diffusers cache: {len(output)} {model_path} {command_path}')
|
||||
cache_path = os.path.join(r.repo_path, "snapshots", list(r.revisions)[-1].commit_hash)
|
||||
diffuser_repos.append({ 'name': r.repo_id, 'filename': r.repo_id, 'path': cache_path, 'size': r.size_on_disk, 'mtime': r.last_modified, 'hash': list(r.revisions)[-1].commit_hash, 'model_info': str(os.path.join(cache_path, "model_info.json")) })
|
||||
if not os.path.isfile(os.path.join(cache_path, "hidden")):
|
||||
output.append(str(r.repo_id))
|
||||
except Exception as e:
|
||||
shared.log.error(f"Error listing diffusers: {place} {e}")
|
||||
shared.log.debug(f'Scanning diffusers cache: {model_path} {command_path} {len(output)}')
|
||||
return output
|
||||
|
||||
|
||||
@@ -47,10 +79,9 @@ def find_diffuser(name: str):
|
||||
filt = hf.ModelFilter(
|
||||
model_name=name,
|
||||
task='text-to-image',
|
||||
tags='stable-diffusion',
|
||||
library=['diffusers', 'stable-diffusion'],
|
||||
library=['diffusers'],
|
||||
)
|
||||
models = list(api.list_models(filter=filt, full=True, limit=50, sort="downloads", direction=-1))
|
||||
models = list(api.list_models(filter=filt, full=True, limit=5, sort="downloads", direction=-1))
|
||||
shared.log.debug(f'Searching diffusers models: {name} {len(models) > 0}')
|
||||
if len(models) > 0:
|
||||
return models[0].modelId
|
||||
@@ -77,7 +108,7 @@ def load_models(model_path: str, model_url: str = None, command_path: str = None
|
||||
for place in places:
|
||||
for full_path in shared.walk_files(place, allowed_extensions=ext_filter):
|
||||
if os.path.islink(full_path) and not os.path.exists(full_path):
|
||||
print(f"Skipping broken symlink: {full_path}")
|
||||
shared.log.error(f"Skipping broken symlink: {full_path}")
|
||||
continue
|
||||
if ext_blacklist is not None and any(full_path.endswith(x) for x in ext_blacklist):
|
||||
continue
|
||||
@@ -144,13 +175,13 @@ def move_files(src_path: str, dest_path: str, ext_filter: str = None):
|
||||
if ext_filter is not None:
|
||||
if ext_filter not in file:
|
||||
continue
|
||||
print(f"Moving {file} from {src_path} to {dest_path}.")
|
||||
shared.log.warning(f"Moving {file} from {src_path} to {dest_path}.")
|
||||
try:
|
||||
shutil.move(fullpath, dest_path)
|
||||
except Exception:
|
||||
pass
|
||||
if len(os.listdir(src_path)) == 0:
|
||||
print(f"Removing empty folder: {src_path}")
|
||||
shared.log.info(f"Removing empty folder: {src_path}")
|
||||
shutil.rmtree(src_path, True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -174,7 +174,6 @@ class DDPM(pl.LightningModule):
|
||||
lvlb_weights = 0.5 * np.sqrt(torch.Tensor(alphas_cumprod)) / (2. * 1 - torch.Tensor(alphas_cumprod))
|
||||
else:
|
||||
raise NotImplementedError("mu not supported")
|
||||
# TODO how to choose this term
|
||||
lvlb_weights[0] = lvlb_weights[1]
|
||||
self.register_buffer('lvlb_weights', lvlb_weights, persistent=False)
|
||||
assert not torch.isnan(self.lvlb_weights).all()
|
||||
@@ -631,7 +630,7 @@ class LatentDiffusion(DDPM):
|
||||
weighting = weighting * L_weighting
|
||||
return weighting
|
||||
|
||||
def get_fold_unfold(self, x, kernel_size, stride, uf=1, df=1): # todo load once not every time, shorten code
|
||||
def get_fold_unfold(self, x, kernel_size, stride, uf=1, df=1):
|
||||
"""
|
||||
:param x: img of size (bs, c, h, w)
|
||||
:return: n img crops of size (n, bs, c, kernel_size[0], kernel_size[1])
|
||||
@@ -887,7 +886,7 @@ class LatentDiffusion(DDPM):
|
||||
assert c is not None
|
||||
if self.cond_stage_trainable:
|
||||
c = self.get_learned_conditioning(c)
|
||||
if self.shorten_cond_schedule: # TODO: drop this option
|
||||
if self.shorten_cond_schedule:
|
||||
tc = self.cond_ids[t].to(self.device)
|
||||
c = self.q_sample(x_start=c, t=tc, noise=torch.randn_like(c.float()))
|
||||
return self.p_losses(x, c, t, *args, **kwargs)
|
||||
@@ -919,7 +918,7 @@ class LatentDiffusion(DDPM):
|
||||
z_list = [z[:, :, :, :, i] for i in range(z.shape[-1])]
|
||||
|
||||
if self.cond_stage_key in ["image", "LR_image", "segmentation",
|
||||
'bbox_img'] and self.model.conditioning_key: # todo check for completeness
|
||||
'bbox_img'] and self.model.conditioning_key:
|
||||
c_key = next(iter(cond.keys())) # get key
|
||||
c = next(iter(cond.values())) # get value
|
||||
assert (len(c) == 1) # todo extend to list with more than one elem
|
||||
@@ -973,12 +972,11 @@ class LatentDiffusion(DDPM):
|
||||
cond_list = [{'c_crossattn': [e]} for e in adapted_cond]
|
||||
|
||||
else:
|
||||
cond_list = [cond for i in range(z.shape[-1])] # Todo make this more efficient
|
||||
cond_list = [cond for i in range(z.shape[-1])]
|
||||
|
||||
# apply model by loop over crops
|
||||
output_list = [self.model(z_list[i], t, **cond_list[i]) for i in range(z.shape[-1])]
|
||||
assert not isinstance(output_list[0],
|
||||
tuple) # todo cant deal with multiple model outputs check this never happens
|
||||
assert not isinstance(output_list[0], tuple)
|
||||
|
||||
o = torch.stack(output_list, axis=-1)
|
||||
o = o * weighting
|
||||
@@ -1431,7 +1429,6 @@ class DiffusionWrapper(pl.LightningModule):
|
||||
|
||||
|
||||
class Layout2ImgDiffusion(LatentDiffusion):
|
||||
# TODO: move all layout-specific hacks to this class
|
||||
def __init__(self, cond_stage_key, *args, **kwargs):
|
||||
assert cond_stage_key == 'coordinates_bbox', 'Layout2ImgDiffusion only for cond_stage_key="coordinates_bbox"'
|
||||
super().__init__(*args, cond_stage_key=cond_stage_key, **kwargs)
|
||||
|
||||
@@ -76,6 +76,7 @@ def create_paths(opts):
|
||||
create_path(fix_path('hypernetwork_dir'))
|
||||
create_path(fix_path('ckpt_dir'))
|
||||
create_path(fix_path('vae_dir'))
|
||||
create_path(fix_path('diffusers_dir'))
|
||||
create_path(fix_path('embeddings_dir'))
|
||||
create_path(fix_path('outdir_samples'))
|
||||
create_path(fix_path('outdir_txt2img_samples'))
|
||||
|
||||
+133
-42
@@ -26,6 +26,7 @@ import modules.images as images
|
||||
import modules.styles
|
||||
import modules.sd_models as sd_models
|
||||
import modules.sd_vae as sd_vae
|
||||
from modules.lora_diffusers import lora_state, unload_diffusers_lora
|
||||
|
||||
|
||||
opt_C = 4
|
||||
@@ -222,8 +223,9 @@ class StableDiffusionProcessing:
|
||||
source_image = devices.cond_cast_float(source_image)
|
||||
# HACK: Using introspection as the Depth2Image model doesn't appear to uniquely
|
||||
# identify itself with a field common to all models. The conditioning_key is also hybrid.
|
||||
if backend == Backend.DIFFUSERS: # TODO: Diffusers img2img_image_conditioning
|
||||
return latent_image.new_zeros(latent_image.shape[0], 5, 1, 1)
|
||||
if backend == Backend.DIFFUSERS:
|
||||
log.warning('Diffusers not implemented: img2img_image_conditioning')
|
||||
return None
|
||||
if isinstance(self.sd_model, LatentDepth2ImageDiffusion):
|
||||
return self.depth2img_image_conditioning(source_image)
|
||||
if self.sd_model.cond_stage_key == "edit":
|
||||
@@ -445,24 +447,23 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
|
||||
if uses_ensd:
|
||||
uses_ensd = sd_samplers_common.is_sampler_using_eta_noise_seed_delta(p)
|
||||
|
||||
|
||||
generation_params = {
|
||||
"Steps": p.steps,
|
||||
"Sampler": p.sampler_name,
|
||||
"CFG scale": p.cfg_scale,
|
||||
"Image CFG scale": getattr(p, 'image_cfg_scale', None),
|
||||
"Seed": all_seeds[index],
|
||||
"Face restoration": (opts.face_restoration_model if p.restore_faces else None),
|
||||
"Face restoration": opts.face_restoration_model if p.restore_faces else None,
|
||||
"Size": f"{p.width}x{p.height}",
|
||||
"Model hash": getattr(p, 'sd_model_hash', None if not opts.add_model_hash_to_info or not shared.sd_model.sd_model_hash else shared.sd_model.sd_model_hash),
|
||||
"Model": (None if not opts.add_model_name_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')),
|
||||
"VAE": (None if not opts.add_model_name_to_info or sd_vae.loaded_vae_file is None else os.path.splitext(os.path.basename(sd_vae.loaded_vae_file))[0]),
|
||||
"Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]),
|
||||
"Variation seed strength": (None if p.subseed_strength == 0 else p.subseed_strength),
|
||||
"Seed resize from": (None if p.seed_resize_from_w == 0 or p.seed_resize_from_h == 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}"),
|
||||
"Model": None if not opts.add_model_name_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', ''),
|
||||
"VAE": None if not opts.add_model_name_to_info or sd_vae.loaded_vae_file is None else os.path.splitext(os.path.basename(sd_vae.loaded_vae_file))[0],
|
||||
"Variation seed": None if p.subseed_strength == 0 else all_subseeds[index],
|
||||
"Variation seed strength": None if p.subseed_strength == 0 else p.subseed_strength,
|
||||
"Seed resize from": None if p.seed_resize_from_w == 0 or p.seed_resize_from_h == 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}",
|
||||
"Denoising strength": getattr(p, 'denoising_strength', None),
|
||||
"Conditional mask weight": getattr(p, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) if p.is_using_inpainting_conditioning else None,
|
||||
"Clip skip": p.clip_skip,
|
||||
"Clip skip": p.clip_skip if p.clip_skip > 1 else None,
|
||||
"ENSD": opts.eta_noise_seed_delta if uses_ensd else None,
|
||||
"Init image hash": getattr(p, 'init_img_hash', None),
|
||||
"Version": git_commit,
|
||||
@@ -520,7 +521,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
if k == 'sd_vae':
|
||||
sd_vae.reload_vae_weights()
|
||||
|
||||
sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio())
|
||||
if not shared.opts.cuda_compile:
|
||||
sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio())
|
||||
|
||||
if cmd_opts.profile:
|
||||
"""
|
||||
@@ -538,7 +540,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
else:
|
||||
res = process_images_inner(p)
|
||||
finally:
|
||||
sd_models.apply_token_merging(p.sd_model, 0)
|
||||
if not shared.opts.cuda_compile:
|
||||
sd_models.apply_token_merging(p.sd_model, 0)
|
||||
if p.override_settings_restore_afterwards: # restore opts to original state
|
||||
for k, v in stored_opts.items():
|
||||
setattr(opts, k, v)
|
||||
@@ -557,6 +560,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
assert len(p.prompt) > 0
|
||||
else:
|
||||
assert p.prompt is not None
|
||||
|
||||
seed = get_fixed_seed(p.seed)
|
||||
subseed = get_fixed_seed(p.subseed)
|
||||
if backend == Backend.ORIGINAL:
|
||||
@@ -678,31 +682,91 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
x_samples_ddim = torch.stack(x_samples_ddim).float()
|
||||
x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0)
|
||||
del samples_ddim
|
||||
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
|
||||
lowvram.send_everything_to_cpu()
|
||||
devices.torch_gc()
|
||||
if p.scripts is not None:
|
||||
p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)
|
||||
else: # TODO Diffusers main processing
|
||||
generator = [torch.Generator(device="cpu").manual_seed(s) for s in seeds]
|
||||
if shared.sd_model.scheduler.name != p.sampler_name:
|
||||
|
||||
elif backend == Backend.DIFFUSERS:
|
||||
generator_device = 'cpu' if shared.opts.diffusers_generator_device == "cpu" else shared.device
|
||||
generator = [torch.Generator(generator_device).manual_seed(s) for s in seeds]
|
||||
if (not hasattr(shared.sd_model.scheduler, 'name')) or (shared.sd_model.scheduler.name != p.sampler_name):
|
||||
sampler = sd_samplers.all_samplers_map.get(p.sampler_name, None)
|
||||
if sampler is None:
|
||||
sampler = sd_samplers.all_samplers_map.get("UniPC")
|
||||
scheduler = sampler.constructor(shared.sd_model.sd_checkpoint_info.filename)
|
||||
shared.sd_model.scheduler = scheduler.sampler
|
||||
output = shared.sd_model(
|
||||
shared.sd_model.scheduler = sd_samplers.create_sampler(sampler.name, shared.sd_model) # TODO(Patrick): For wrapped pipelines this is currently a no-op
|
||||
|
||||
cross_attention_kwargs={}
|
||||
if lora_state['active']:
|
||||
cross_attention_kwargs['scale'] = lora_state['multiplier']
|
||||
task_specific_kwargs={}
|
||||
if sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.TEXT_2_IMAGE:
|
||||
task_specific_kwargs = {"height": p.height, "width": p.width}
|
||||
elif sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.IMAGE_2_IMAGE:
|
||||
task_specific_kwargs = {"image": p.init_images[0], "strength": p.denoising_strength}
|
||||
elif sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.INPAINTING:
|
||||
# TODO(PVP): change out to latents once possible with `diffusers`
|
||||
task_specific_kwargs = {"image": p.init_images[0], "mask_image": p.image_mask, "strength": p.denoising_strength}
|
||||
|
||||
# TODO Diffusers limited callbacks
|
||||
# TODO Diffusers processing is not using p.sample so second pass is ignored
|
||||
def diffusers_callback(step: int, _timestep: int, latents: torch.FloatTensor):
|
||||
shared.state.sampling_step = step
|
||||
shared.state.sampling_steps = p.steps
|
||||
shared.state.current_latent = latents
|
||||
shared.state.set_current_image()
|
||||
|
||||
# shared.sd_model.to(devices.device)
|
||||
output = shared.sd_model( # pylint: disable=not-callable
|
||||
prompt=prompts,
|
||||
negative_prompt=negative_prompts,
|
||||
num_inference_steps=p.steps,
|
||||
guidance_scale=p.cfg_scale,
|
||||
height=p.height,
|
||||
width=p.width,
|
||||
generator=generator,
|
||||
output_type="np",
|
||||
callback_steps = 1,
|
||||
callback = diffusers_callback,
|
||||
output_type='np' if shared.sd_refiner is None else 'latent',
|
||||
cross_attention_kwargs=cross_attention_kwargs,
|
||||
**task_specific_kwargs
|
||||
)
|
||||
# if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
|
||||
# shared.sd_model.to('cpu')
|
||||
# devices.torch_gc(force=True)
|
||||
|
||||
if shared.sd_refiner is not None:
|
||||
# shared.sd_refiner.to(devices.device)
|
||||
devices.torch_gc()
|
||||
init_image = output.images[0]
|
||||
output = shared.sd_refiner( # pylint: disable=not-callable
|
||||
prompt=prompts,
|
||||
negative_prompt=negative_prompts,
|
||||
num_inference_steps=p.steps,
|
||||
guidance_scale=p.cfg_scale,
|
||||
generator=generator,
|
||||
callback_steps = 1,
|
||||
callback = diffusers_callback,
|
||||
output_type='np',
|
||||
cross_attention_kwargs=cross_attention_kwargs,
|
||||
image=init_image
|
||||
)
|
||||
# if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
|
||||
# shared.sd_refiner.to('cpu')
|
||||
# devices.torch_gc(force=True)
|
||||
|
||||
|
||||
x_samples_ddim = output.images
|
||||
|
||||
if p.enable_hr:
|
||||
log.warning('Diffusers not implemented: hires fix')
|
||||
|
||||
if lora_state['active']:
|
||||
unload_diffusers_lora()
|
||||
|
||||
else:
|
||||
raise ValueError(f"Unknown backend {backend}")
|
||||
|
||||
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
|
||||
lowvram.send_everything_to_cpu()
|
||||
devices.torch_gc()
|
||||
if p.scripts is not None:
|
||||
p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)
|
||||
|
||||
for i, x_sample in enumerate(x_samples_ddim):
|
||||
p.batch_index = i
|
||||
if backend == Backend.ORIGINAL:
|
||||
@@ -820,8 +884,12 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
self.applied_old_hires_behavior_to = None
|
||||
|
||||
def init(self, all_prompts, all_seeds, all_subseeds):
|
||||
if backend == Backend.DIFFUSERS:
|
||||
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.TEXT_2_IMAGE)
|
||||
|
||||
self.width = self.width or 512
|
||||
self.height = self.height or 512
|
||||
|
||||
if self.enable_hr:
|
||||
if opts.use_old_hires_fix_width_height and self.applied_old_hires_behavior_to != (self.width, self.height):
|
||||
self.hr_resize_x = self.width
|
||||
@@ -872,20 +940,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
if self.hr_upscaler is not None:
|
||||
self.extra_generation_params["Hires upscaler"] = self.hr_upscaler
|
||||
|
||||
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts): # TODO this is majority of processing time
|
||||
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
|
||||
latent_scale_mode = shared.latent_upscale_modes.get(self.hr_upscaler, None) if self.hr_upscaler is not None else shared.latent_upscale_modes.get(shared.latent_upscale_default_mode, "nearest")
|
||||
if self.enable_hr and latent_scale_mode is None:
|
||||
if len([x for x in shared.sd_upscalers if x.name == self.hr_upscaler]) == 0:
|
||||
log.warning("Could not find upscaler to use with hrfix")
|
||||
self.enable_hr = False
|
||||
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
||||
samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning, image_conditioning=self.txt2img_image_conditioning(x))
|
||||
if not self.enable_hr or state.interrupted or state.skipped:
|
||||
return samples
|
||||
self.is_hr_pass = True
|
||||
target_width = self.hr_upscale_to_x
|
||||
target_height = self.hr_upscale_to_y
|
||||
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts):
|
||||
|
||||
def save_intermediate(image, index):
|
||||
"""saves image before applying hires fix, if enabled in options; takes as an argument either an image or batch with latent space images"""
|
||||
@@ -902,6 +957,23 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
self.restore_faces = orig2
|
||||
images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], opts.samples_format, info=info, suffix="-before-highres-fix")
|
||||
|
||||
if backend == Backend.DIFFUSERS:
|
||||
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.TEXT_2_IMAGE)
|
||||
|
||||
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
|
||||
latent_scale_mode = shared.latent_upscale_modes.get(self.hr_upscaler, None) if self.hr_upscaler is not None else shared.latent_upscale_modes.get(shared.latent_upscale_default_mode, "nearest")
|
||||
if self.enable_hr and latent_scale_mode is None:
|
||||
if len([x for x in shared.sd_upscalers if x.name == self.hr_upscaler]) == 0:
|
||||
log.warning("Could not find upscaler to use with hrfix")
|
||||
self.enable_hr = False
|
||||
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
||||
samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning, image_conditioning=self.txt2img_image_conditioning(x))
|
||||
if not self.enable_hr or state.interrupted or state.skipped:
|
||||
return samples
|
||||
self.is_hr_pass = True
|
||||
target_width = self.hr_upscale_to_x
|
||||
target_height = self.hr_upscale_to_y
|
||||
|
||||
if latent_scale_mode is not None:
|
||||
for i in range(samples.shape[0]):
|
||||
save_intermediate(samples, i)
|
||||
@@ -978,12 +1050,18 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
self.image_conditioning = None
|
||||
|
||||
def init(self, all_prompts, all_seeds, all_subseeds):
|
||||
image_mask = self.image_mask
|
||||
if backend == Backend.DIFFUSERS and image_mask is None:
|
||||
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
|
||||
elif backend == Backend.DIFFUSERS and image_mask is not None:
|
||||
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.INPAINTING)
|
||||
self.sd_model.dtype = self.sd_model.unet.dtype
|
||||
|
||||
force_latent_upscaler = shared.opts.data.get('force_latent_sampler')
|
||||
if self.sampler_name in ['PLMS']:
|
||||
self.sampler_name = force_latent_upscaler if force_latent_upscaler != 'None' else shared.opts.fallback_sampler # PLMS does not support img2img, use fallback instead
|
||||
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
|
||||
crop_region = None
|
||||
image_mask = self.image_mask
|
||||
if image_mask is not None:
|
||||
image_mask = image_mask.convert('L')
|
||||
if self.inpainting_mask_invert:
|
||||
@@ -1048,7 +1126,13 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
image = torch.from_numpy(batch_images)
|
||||
image = 2. * image - 1.
|
||||
image = image.to(shared.device)
|
||||
self.init_latent = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(image))
|
||||
|
||||
if backend == Backend.ORIGINAL:
|
||||
self.init_latent = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(image))
|
||||
else:
|
||||
# we don't pre-encode the latents for diffusers to allow the UI to stay general for different model types
|
||||
self.init_latent = None
|
||||
|
||||
if self.resize_mode == 3:
|
||||
self.init_latent = torch.nn.functional.interpolate(self.init_latent, size=(self.height // opt_f, self.width // opt_f), mode="bilinear")
|
||||
if image_mask is not None:
|
||||
@@ -1068,6 +1152,13 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
self.image_conditioning = self.img2img_image_conditioning(image, self.init_latent, image_mask)
|
||||
|
||||
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts):
|
||||
if backend == Backend.DIFFUSERS:
|
||||
if self.init_mask is None: # pylint: disable=no-member
|
||||
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
|
||||
else:
|
||||
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.INPAINTING)
|
||||
self.sd_model.dtype = self.sd_model.unet.dtype
|
||||
|
||||
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
||||
if self.initial_noise_multiplier != 1.0:
|
||||
self.extra_generation_params["Noise multiplier"] = self.initial_noise_multiplier
|
||||
|
||||
@@ -173,17 +173,17 @@ class StableDiffusionModelHijack:
|
||||
if m.cond_stage_key == "edit":
|
||||
sd_hijack_unet.hijack_ddpm_edit()
|
||||
|
||||
import logging
|
||||
if opts.cuda_compile and opts.cuda_compile_mode == 'ipex':
|
||||
import logging
|
||||
if devices.backend == 'ipex':
|
||||
shared.log.info("Model compile enabled: IPEX Optimize Graph Mode")
|
||||
else:
|
||||
shared.log.warning("Model compile skipped: IPEX Method is for Intel GPU's with OneAPI")
|
||||
elif opts.cuda_compile and opts.cuda_compile_mode != 'none':
|
||||
elif opts.cuda_compile and opts.cuda_compile_mode != 'none' and shared.backend == shared.Backend.ORIGINAL:
|
||||
try:
|
||||
import logging
|
||||
import torch._dynamo as dynamo # pylint: disable=unused-import
|
||||
torch._dynamo.config.log_level = logging.WARNING if opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access
|
||||
import torch._dynamo # pylint: disable=unused-import
|
||||
log_level = logging.WARNING if opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access
|
||||
torch._logging.set_logs(dynamo=log_level, aot=log_level, inductor=log_level) # pylint: disable=protected-access
|
||||
torch._dynamo.config.verbose = opts.cuda_compile_verbose # pylint: disable=protected-access
|
||||
torch._dynamo.config.suppress_errors = opts.cuda_compile_errors # pylint: disable=protected-access
|
||||
torch.backends.cudnn.benchmark = True
|
||||
@@ -191,7 +191,7 @@ class StableDiffusionModelHijack:
|
||||
import hidet
|
||||
hidet.torch.dynamo_config.use_tensor_core(True)
|
||||
hidet.torch.dynamo_config.search_space(2)
|
||||
m.model = torch.compile(m.model, mode="default", backend=opts.cuda_compile_mode, fullgraph=False, dynamic=False)
|
||||
m.model = torch.compile(m.model, mode="default", backend=opts.cuda_compile_mode, fullgraph=opts.cuda_compile_fullgraph, dynamic=False)
|
||||
shared.log.info(f"Model compile enabled: {opts.cuda_compile_mode}")
|
||||
except Exception as err:
|
||||
shared.log.warning(f"Model compile not supported: {err}")
|
||||
|
||||
+382
-76
@@ -6,6 +6,7 @@ import json
|
||||
import threading
|
||||
from os import mkdir
|
||||
from urllib import request
|
||||
from enum import Enum
|
||||
import filelock
|
||||
from rich import progress # pylint: disable=redefined-builtin
|
||||
import torch
|
||||
@@ -15,12 +16,14 @@ import tomesd
|
||||
from transformers import logging as transformers_logging
|
||||
import ldm.modules.midas as midas
|
||||
from ldm.util import instantiate_from_config
|
||||
import diffusers
|
||||
from modules import paths, shared, modelloader, devices, script_callbacks, sd_vae, sd_disable_initialization, errors, hashes, sd_models_config
|
||||
from modules.sd_hijack_inpainting import do_inpainting_hijack
|
||||
from modules.timer import Timer
|
||||
from modules.memstats import memory_stats
|
||||
from modules.paths_internal import models_path
|
||||
|
||||
|
||||
transformers_logging.set_verbosity_error()
|
||||
model_dir = "Stable-diffusion"
|
||||
model_path = os.path.abspath(os.path.join(paths.models_path, model_dir))
|
||||
@@ -39,8 +42,10 @@ class CheckpointInfo:
|
||||
self.name = None
|
||||
self.hash = None
|
||||
self.filename = filename
|
||||
self.type = ''
|
||||
abspath = os.path.abspath(filename)
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
|
||||
if os.path.isfile(abspath): # ckpt or safetensor
|
||||
if shared.opts.ckpt_dir is not None and abspath.startswith(shared.opts.ckpt_dir):
|
||||
name = abspath.replace(shared.opts.ckpt_dir, '')
|
||||
elif abspath.startswith(model_path):
|
||||
@@ -52,7 +57,11 @@ class CheckpointInfo:
|
||||
self.name = name
|
||||
self.hash = model_hash(self.filename)
|
||||
self.sha256 = hashes.sha256_from_cache(self.filename, f"checkpoint/{name}")
|
||||
else: # TODO Diffusers
|
||||
self.path = abspath
|
||||
self.type = abspath.split('.')[-1].lower()
|
||||
self.name_for_extra = os.path.splitext(os.path.basename(filename))[0]
|
||||
self.model_name = os.path.splitext(name.replace("/", "_").replace("\\", "_"))[0]
|
||||
else: # maybe a diffuser
|
||||
repo = [r for r in modelloader.diffuser_repos if filename == r['filename']]
|
||||
if len(repo) == 0:
|
||||
error_message = f'Cannot find diffuser model: {filename}'
|
||||
@@ -61,8 +70,15 @@ class CheckpointInfo:
|
||||
self.name = repo[0]['name']
|
||||
self.hash = repo[0]['hash'][:8]
|
||||
self.sha256 = repo[0]['hash']
|
||||
self.name_for_extra = os.path.splitext(os.path.basename(filename))[0]
|
||||
self.model_name = os.path.splitext(name.replace("/", "_").replace("\\", "_"))[0]
|
||||
self.path = repo[0]['path']
|
||||
self.type = 'diffusers'
|
||||
self.name_for_extra = repo[0]['name']
|
||||
self.model_name = repo[0]['name']
|
||||
if os.path.isfile(repo[0]['model_info']):
|
||||
file_path = repo[0]['model_info']
|
||||
with open(file_path, "r", encoding="utf-8") as json_file:
|
||||
self.model_info = json.load(json_file)
|
||||
|
||||
self.shorthash = self.sha256[0:10] if self.sha256 else None
|
||||
self.title = self.name if self.shorthash is None else f'{self.name} [{self.shorthash}]'
|
||||
self.ids = [self.hash, self.model_name, self.title, self.name, f'{self.name} [{self.hash}]'] + ([self.shorthash, self.sha256, f'{self.name} [{self.shorthash}]'] if self.shorthash else [])
|
||||
@@ -110,13 +126,13 @@ def checkpoint_tiles():
|
||||
def list_models():
|
||||
checkpoints_list.clear()
|
||||
checkpoint_aliases.clear()
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
ext_filter=[".safetensors"] if shared.opts.sd_disable_ckpt else [".ckpt", ".safetensors"]
|
||||
model_list = modelloader.load_models(model_path=os.path.join(models_path, 'Stable-diffusion'), model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=ext_filter, download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
|
||||
else:
|
||||
global model_path # pylint: disable=global-statement
|
||||
model_path = os.path.join(models_path, 'Diffusers')
|
||||
model_list = modelloader.load_diffusers(model_path=model_path, command_path=shared.opts.diffusers_dir)
|
||||
ext_filter=[".safetensors"] if shared.opts.sd_disable_ckpt else [".ckpt", ".safetensors"]
|
||||
model_list = []
|
||||
if shared.backend == shared.Backend.ORIGINAL or shared.opts.diffusers_allow_safetensors:
|
||||
model_list += modelloader.load_models(model_path=model_path, model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=ext_filter, download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
|
||||
if shared.backend == shared.Backend.DIFFUSERS:
|
||||
model_list += modelloader.load_diffusers_models(model_path=os.path.join(models_path, 'Diffusers'), command_path=shared.opts.diffusers_dir)
|
||||
|
||||
for filename in sorted(model_list, key=str.lower):
|
||||
checkpoint_info = CheckpointInfo(filename)
|
||||
if checkpoint_info.name is not None:
|
||||
@@ -143,15 +159,15 @@ def list_models():
|
||||
shared.opts.data['sd_model_checkpoint'] = "v1-5-pruned-emaonly.safetensors"
|
||||
model_list = modelloader.load_models(model_path=model_path, model_url=model_url, command_path=shared.opts.ckpt_dir, ext_filter=[".ckpt", ".safetensors"], download_name="v1-5-pruned-emaonly.safetensors", ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
|
||||
else:
|
||||
hub_url = "runwayml/stable-diffusion-v1-5"
|
||||
model_list = modelloader.load_diffusers(model_path=model_path, hub_url=hub_url, command_path=shared.opts.diffusers_dir)
|
||||
default_model_id = "runwayml/stable-diffusion-v1-5"
|
||||
modelloader.download_diffusers_model(default_model_id, shared.opts.diffusers_dir)
|
||||
model_list = modelloader.load_diffusers_models(model_path=os.path.join(models_path, 'Diffusers'), command_path=shared.opts.diffusers_dir)
|
||||
|
||||
for filename in sorted(model_list, key=str.lower):
|
||||
checkpoint_info = CheckpointInfo(filename)
|
||||
if checkpoint_info.name is not None:
|
||||
checkpoint_info.register()
|
||||
|
||||
|
||||
def update_model_hashes():
|
||||
txt = []
|
||||
lst = [ckpt for ckpt in checkpoints_list.values() if ckpt.hash is None]
|
||||
@@ -196,11 +212,18 @@ def model_hash(filename):
|
||||
return 'NOHASH'
|
||||
|
||||
|
||||
def select_checkpoint(model=True):
|
||||
model_checkpoint = shared.opts.sd_model_checkpoint if model else shared.opts.sd_model_dict
|
||||
def select_checkpoint(op='model'):
|
||||
if op == 'model':
|
||||
model_checkpoint = shared.opts.sd_model_checkpoint
|
||||
elif op == 'dict':
|
||||
model_checkpoint = shared.opts.sd_model_dict
|
||||
elif op == 'refiner':
|
||||
model_checkpoint = shared.opts.data.get('sd_model_refiner', None)
|
||||
if model_checkpoint is None or model_checkpoint == 'None':
|
||||
return None
|
||||
checkpoint_info = get_closet_checkpoint_match(model_checkpoint)
|
||||
if checkpoint_info is not None:
|
||||
shared.log.debug(f'Select checkpoint: {checkpoint_info.title if checkpoint_info is not None else None}')
|
||||
shared.log.debug(f'Select checkpoint: {op} {checkpoint_info.title if checkpoint_info is not None else None}')
|
||||
return checkpoint_info
|
||||
if len(checkpoints_list) == 0:
|
||||
shared.log.error("Cannot run without a checkpoint")
|
||||
@@ -209,7 +232,8 @@ def select_checkpoint(model=True):
|
||||
checkpoint_info = next(iter(checkpoints_list.values()))
|
||||
if model_checkpoint is not None:
|
||||
shared.log.warning(f"Selected checkpoint not found: {model_checkpoint}")
|
||||
shared.log.warning(f"Loading fallback checkpoint: {checkpoint_info.title}")
|
||||
# shared.log.warning(f"Loading fallback checkpoint: {checkpoint_info.title}")
|
||||
shared.opts.data['sd_checkpoint'] = checkpoint_info.title
|
||||
shared.log.debug(f'Select checkpoint: {checkpoint_info.title if checkpoint_info is not None else None}')
|
||||
return checkpoint_info
|
||||
|
||||
@@ -443,9 +467,10 @@ sd1_clip_weight = 'cond_stage_model.transformer.text_model.embeddings.token_embe
|
||||
sd2_clip_weight = 'cond_stage_model.model.transformer.resblocks.0.attn.in_proj_weight'
|
||||
|
||||
|
||||
class SdModelData:
|
||||
class ModelData:
|
||||
def __init__(self):
|
||||
self.sd_model = None
|
||||
self.sd_refiner = None
|
||||
self.sd_dict = 'None'
|
||||
self.initial = True
|
||||
self.lock = threading.Lock()
|
||||
@@ -455,11 +480,11 @@ class SdModelData:
|
||||
with self.lock:
|
||||
try:
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
reload_model_weights()
|
||||
reload_model_weights(op='model')
|
||||
elif shared.backend == shared.Backend.DIFFUSERS:
|
||||
load_diffuser()
|
||||
load_diffuser(op='model')
|
||||
else:
|
||||
shared.log.error(f"Unknown Stable Diffusion backend: {shared.opts.sd_backend}")
|
||||
shared.log.error(f"Unknown Stable Diffusion backend: {shared.backend}")
|
||||
self.initial = False
|
||||
except Exception as e:
|
||||
shared.log.error("Failed to load stable diffusion model")
|
||||
@@ -468,82 +493,346 @@ class SdModelData:
|
||||
return self.sd_model
|
||||
|
||||
def set_sd_model(self, v):
|
||||
shared.log.debug(f"Class model: {v}")
|
||||
self.sd_model = v
|
||||
|
||||
def get_sd_refiner(self):
|
||||
if self.sd_model is None:
|
||||
with self.lock:
|
||||
try:
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
reload_model_weights(op='refiner')
|
||||
elif shared.backend == shared.Backend.DIFFUSERS:
|
||||
load_diffuser(op='refiner')
|
||||
else:
|
||||
shared.log.error(f"Unknown Stable Diffusion backend: {shared.backend}")
|
||||
self.initial = False
|
||||
except Exception as e:
|
||||
shared.log.error("Failed to load stable diffusion model")
|
||||
errors.display(e, "loading stable diffusion model")
|
||||
self.sd_refiner = None
|
||||
return self.sd_refiner
|
||||
|
||||
model_data = SdModelData()
|
||||
def set_sd_refiner(self, v):
|
||||
shared.log.debug(f"Class refiner: {v}")
|
||||
self.sd_refiner = v
|
||||
|
||||
model_data = ModelData()
|
||||
|
||||
class PriorPipeline:
|
||||
def __init__(self, prior, main):
|
||||
self.prior = prior
|
||||
self.main = main
|
||||
self.scheduler = main.scheduler
|
||||
self.tokenizer = self.prior.tokenizer
|
||||
|
||||
def to(self, *args, **kwargs):
|
||||
# only the prior is moved to CUDA in a first step
|
||||
self.prior.to(*args, **kwargs)
|
||||
|
||||
def enable_model_cpu_offload(self, *args, **kwargs):
|
||||
self.prior.enable_model_cpu_offload(*args, **kwargs)
|
||||
self.main.enable_model_cpu_offload(*args, **kwargs)
|
||||
|
||||
def enable_sequential_cpu_offload(self, *args, **kwargs):
|
||||
self.prior.enable_sequential_cpu_offload(*args, **kwargs)
|
||||
self.main.enable_sequential_cpu_offload(*args, **kwargs)
|
||||
|
||||
def enable_xformers_memory_efficient_attention(self, *args, **kwargs):
|
||||
self.prior.enable_xformers_memory_efficient_attention(*args, **kwargs)
|
||||
self.main.enable_xformers_memory_efficient_attention(*args, **kwargs)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
unclip_outputs = self.prior(prompt=kwargs.get("prompt"), negative_prompt=kwargs.get("negative_prompt"))
|
||||
|
||||
if self.prior.device.type == "cuda" or self.prior.device.type == "xpu":
|
||||
prior_device = self.prior.device
|
||||
self.prior.to("cpu")
|
||||
self.main.to(prior_device)
|
||||
|
||||
kwargs = {**kwargs, **unclip_outputs}
|
||||
result = self.main(*args, **kwargs)
|
||||
|
||||
if self.main.device.type == "cuda" or self.main.device.type == "xpu":
|
||||
main_device = self.main.device
|
||||
self.main.to("cpu")
|
||||
self.prior.to(main_device)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=None): # pylint: disable=unused-argument
|
||||
def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'): # pylint: disable=unused-argument
|
||||
import torch # pylint: disable=reimported,redefined-outer-name
|
||||
if timer is None:
|
||||
timer = Timer()
|
||||
import diffusers
|
||||
import logging
|
||||
logging.getLogger("diffusers").setLevel(logging.ERROR)
|
||||
timer.record("diffusers")
|
||||
diffusor_config = {
|
||||
"force_download": False,
|
||||
"safety_checker": None,
|
||||
"resume_download": True,
|
||||
diffusers_load_config = {
|
||||
"low_cpu_mem_usage": True,
|
||||
"use_safetensors": True,
|
||||
"cache_dir": shared.opts.diffusers_dir,
|
||||
"torch_dtype": devices.dtype,
|
||||
"safety_checker": None,
|
||||
"requires_safety_checker": False,
|
||||
"load_safety_checker": False,
|
||||
# "use_safetensors": True, # TODO(PVP) - we can't enable this for all checkpoints just yet
|
||||
}
|
||||
if shared.opts.data['sd_model_checkpoint'] == 'model.ckpt':
|
||||
if devices.dtype == torch.float16:
|
||||
diffusers_load_config['variant'] = 'fp16'
|
||||
|
||||
if shared.opts.data.get('sd_model_checkpoint', '') == 'model.ckpt' or shared.opts.data.get('sd_model_checkpoint', '') == '':
|
||||
shared.opts.data['sd_model_checkpoint'] = "runwayml/stable-diffusion-v1-5"
|
||||
|
||||
if op == 'model' or op == 'dict':
|
||||
if (model_data.sd_model is not None) and (checkpoint_info is not None) and (checkpoint_info.hash == model_data.sd_model.sd_checkpoint_info.hash): # trying to load the same model
|
||||
return
|
||||
else:
|
||||
if (model_data.sd_refiner is not None) and (checkpoint_info is not None) and (checkpoint_info.hash == model_data.sd_refiner.sd_checkpoint_info.hash): # trying to load the same model
|
||||
return
|
||||
|
||||
shared.log.debug(f'Diffusers load config: {diffusers_load_config}')
|
||||
sd_model = None
|
||||
try:
|
||||
devices.set_cuda_params()
|
||||
if shared.cmd_opts.ckpt is not None and model_data.initial: # initial load
|
||||
model_name = modelloader.find_diffuser(shared.cmd_opts.ckpt)
|
||||
if model_name is not None:
|
||||
shared.log.info(f'Loading diffuser model: {model_name}')
|
||||
scheduler = diffusers.UniPCMultistepScheduler.from_pretrained(model_name, subfolder="scheduler")
|
||||
sd_model = diffusers.DiffusionPipeline.from_pretrained(model_name, scheduler=scheduler, **diffusor_config)
|
||||
shared.log.info(f'Loading diffuser {op}: {model_name}')
|
||||
model_file = modelloader.download_diffusers_model(hub_id=model_name)
|
||||
try:
|
||||
sd_model = diffusers.DiffusionPipeline.from_pretrained(model_file, **diffusers_load_config)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Diffusers failed loading model: {model_file} {e}')
|
||||
list_models() # rescan for downloaded model
|
||||
checkpoint_info = CheckpointInfo(model_name)
|
||||
|
||||
if sd_model is None:
|
||||
checkpoint_info = checkpoint_info or select_checkpoint()
|
||||
shared.log.info(f'Loading diffuser model: {checkpoint_info.filename}')
|
||||
scheduler = diffusers.UniPCMultistepScheduler.from_pretrained(checkpoint_info.filename, subfolder="scheduler")
|
||||
sd_model = diffusers.DiffusionPipeline.from_pretrained(checkpoint_info.filename, scheduler=scheduler, **diffusor_config)
|
||||
if shared.cmd_opts.medvram:
|
||||
sd_model.enable_model_cpu_offload()
|
||||
if shared.cmd_opts.lowvram:
|
||||
sd_model.enable_sequential_cpu_offload()
|
||||
checkpoint_info = checkpoint_info or select_checkpoint(op=op)
|
||||
if checkpoint_info is None:
|
||||
unload_model_weights(op=op)
|
||||
return
|
||||
shared.log.info(f'Loading diffuser {op}: {checkpoint_info.filename}')
|
||||
|
||||
vae_file, vae_source = sd_vae.resolve_vae(checkpoint_info.filename)
|
||||
vae = sd_vae.load_vae_diffusers(None, vae_file, vae_source)
|
||||
if vae is not None:
|
||||
diffusers_load_config["vae"] = vae
|
||||
|
||||
if not os.path.isfile(checkpoint_info.path):
|
||||
try:
|
||||
sd_model = diffusers.DiffusionPipeline.from_pretrained(checkpoint_info.path, **diffusers_load_config)
|
||||
except Exception as e:
|
||||
shared.log.error(f'Diffusers failed loading model: {checkpoint_info.path} {e}')
|
||||
else:
|
||||
diffusers_load_config["local_files_only "] = True
|
||||
diffusers_load_config["extract_ema"] = shared.opts.diffusers_extract_ema
|
||||
try:
|
||||
if shared.opts.diffusers_pipeline == shared.pipelines[0]:
|
||||
pipeline = diffusers.StableDiffusionPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[1]:
|
||||
pipeline = diffusers.StableDiffusionXLPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[2]:
|
||||
pipeline = diffusers.KandinskyPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[3]:
|
||||
pipeline = diffusers.KandinskyV22Pipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[4]:
|
||||
pipeline = diffusers.IFPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[5]:
|
||||
pipeline = diffusers.ShapEPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[6]:
|
||||
pipeline = diffusers.StableDiffusionImg2ImgPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[7]:
|
||||
pipeline = diffusers.StableDiffusionXLImg2ImgPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[8]:
|
||||
pipeline = diffusers.KandinskyImg2ImgPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[9]:
|
||||
pipeline = diffusers.KandinskyV22Img2ImgPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[10]:
|
||||
pipeline = diffusers.IFImg2ImgPipeline
|
||||
elif shared.opts.diffusers_pipeline == shared.pipelines[11]:
|
||||
pipeline = diffusers.ShapEImg2ImgPipeline
|
||||
else:
|
||||
shared.log.error(f'Diffusers unknown pipeline: {shared.opts.diffusers_pipeline}')
|
||||
except Exception as e:
|
||||
shared.log.error(f'Diffusers failed initializing pipeline: {shared.opts.diffusers_pipeline} {e}')
|
||||
return
|
||||
try:
|
||||
if hasattr(pipeline, 'from_single_file'):
|
||||
diffusers_load_config['use_safetensors'] = True
|
||||
sd_model = pipeline.from_single_file(checkpoint_info.path, **diffusers_load_config)
|
||||
elif hasattr(pipeline, 'from_ckpt'):
|
||||
sd_model = pipeline.from_ckpt(checkpoint_info.path, **diffusers_load_config)
|
||||
else:
|
||||
shared.log.error(f'Diffusers cannot load safetensor model: {checkpoint_info.path} {shared.opts.diffusers_pipeline}')
|
||||
return
|
||||
if sd_model is not None:
|
||||
shared.log.debug(f'Diffusers pipeline: {type(sd_model)}') # pylint: disable=protected-access
|
||||
except Exception as e:
|
||||
shared.log.error(f'Diffusers failed loading model using pipeline: {checkpoint_info.path} {shared.opts.diffusers_pipeline} {e}')
|
||||
return
|
||||
|
||||
if "StableDiffusion" in sd_model.__class__.__name__:
|
||||
pass # scheduler is created on first use
|
||||
elif "Kandinsky" in sd_model.__class__.__name__:
|
||||
sd_model.scheduler.name = 'DDIM'
|
||||
|
||||
# Prior pipelines
|
||||
if hasattr(checkpoint_info, 'model_info') and checkpoint_info.model_info is not None and "prior" in checkpoint_info.model_info:
|
||||
prior_id = checkpoint_info.model_info["prior"]
|
||||
shared.log.info(f"Loading diffuser prior: {checkpoint_info.filename} {prior_id}")
|
||||
prior = diffusers.DiffusionPipeline.from_pretrained(prior_id, **diffusers_load_config)
|
||||
sd_model = PriorPipeline(prior=prior, main=sd_model) # wrap sd_model
|
||||
|
||||
if hasattr(sd_model, "enable_model_cpu_offload"):
|
||||
if shared.cmd_opts.medvram or shared.opts.diffusers_model_cpu_offload:
|
||||
shared.log.debug('Diffusers: enable model CPU offload')
|
||||
sd_model.enable_model_cpu_offload()
|
||||
if hasattr(sd_model, "enable_sequential_cpu_offload"):
|
||||
if shared.opts.diffusers_seq_cpu_offload:
|
||||
sd_model.enable_sequential_cpu_offload()
|
||||
shared.log.debug('Diffusers: enable sequential CPU offload')
|
||||
if hasattr(sd_model, "enable_vae_slicing"):
|
||||
if shared.cmd_opts.lowvram or shared.opts.diffusers_vae_slicing:
|
||||
shared.log.debug('Diffusers: enable VAE slicing')
|
||||
sd_model.enable_vae_slicing()
|
||||
else:
|
||||
sd_model.disable_vae_slicing()
|
||||
if hasattr(sd_model, "enable_vae_tiling"):
|
||||
if shared.cmd_opts.lowvram or shared.opts.diffusers_vae_tiling:
|
||||
shared.log.debug('Diffusers: enable VAE tiling')
|
||||
sd_model.enable_vae_tiling()
|
||||
else:
|
||||
sd_model.disable_vae_tiling()
|
||||
if hasattr(sd_model, "enable_attention_slicing"):
|
||||
if shared.cmd_opts.lowvram or shared.opts.diffusers_attention_slicing:
|
||||
shared.log.debug('Diffusers: enable attention slicing')
|
||||
sd_model.enable_attention_slicing()
|
||||
else:
|
||||
sd_model.disable_attention_slicing()
|
||||
if shared.opts.cross_attention_optimization == "xFormers":
|
||||
sd_model.enable_xformers_memory_efficient_attention()
|
||||
sd_model.sd_checkpoint_info = checkpoint_info
|
||||
sd_model.sd_model_checkpoint = checkpoint_info.filename
|
||||
sd_model.sd_model_hash = checkpoint_info.hash
|
||||
scheduler.name = 'UniPC'
|
||||
if shared.opts.opt_channelslast:
|
||||
shared.log.debug('Diffusers: enable channels last')
|
||||
sd_model.unet.to(memory_format=torch.channels_last)
|
||||
if shared.opts.cuda_compile and torch.cuda.is_available():
|
||||
sd_model.to(devices.device)
|
||||
import torch._dynamo # pylint: disable=unused-import,redefined-outer-name
|
||||
log_level = logging.WARNING if shared.opts.cuda_compile_verbose else logging.CRITICAL # pylint: disable=protected-access
|
||||
torch._logging.set_logs(dynamo=log_level, aot=log_level, inductor=log_level) # pylint: disable=protected-access
|
||||
torch._dynamo.config.verbose = shared.opts.cuda_compile_verbose # pylint: disable=protected-access
|
||||
torch._dynamo.config.suppress_errors = shared.opts.cuda_compile_errors # pylint: disable=protected-access
|
||||
sd_model.unet = torch.compile(sd_model.unet, mode=shared.opts.cuda_compile_mode, fullgraph=shared.opts.cuda_compile_fullgraph) # pylint: disable=attribute-defined-outside-init
|
||||
shared.log.info(f"Compiling pipeline={sd_model.__class__.__name__} shape={8 * sd_model.unet.config.sample_size} mode={shared.opts.cuda_compile_mode}")
|
||||
sd_model("dummy prompt")
|
||||
shared.log.info("Complilation done.")
|
||||
|
||||
if sd_model is None:
|
||||
shared.log.error('Diffuser model not loaded')
|
||||
return
|
||||
sd_model.sd_checkpoint_info = checkpoint_info # pylint: disable=attribute-defined-outside-init
|
||||
sd_model.sd_model_checkpoint = checkpoint_info.filename # pylint: disable=attribute-defined-outside-init
|
||||
sd_model.sd_model_hash = checkpoint_info.hash # pylint: disable=attribute-defined-outside-init
|
||||
sd_model.to(devices.device)
|
||||
except Exception as e:
|
||||
shared.log.error("Failed to load diffusers model")
|
||||
errors.display(e, "loading Diffusers model")
|
||||
shared.sd_model = sd_model
|
||||
|
||||
if op == 'refiner':
|
||||
model_data.sd_refiner = sd_model
|
||||
else:
|
||||
model_data.sd_model = sd_model
|
||||
|
||||
from modules.textual_inversion import textual_inversion
|
||||
embedding_db = textual_inversion.EmbeddingDatabase()
|
||||
embedding_db.add_embedding_dir(shared.opts.embeddings_dir)
|
||||
embedding_db.load_textual_inversion_embeddings(force_reload=True)
|
||||
|
||||
timer.record("load")
|
||||
shared.log.info(f"Model loaded in {timer.summary()}")
|
||||
devices.torch_gc(force=True)
|
||||
shared.log.info(f'Model load finished: {memory_stats()}')
|
||||
|
||||
|
||||
class DiffusersTaskType(Enum):
|
||||
TEXT_2_IMAGE = 1
|
||||
IMAGE_2_IMAGE = 2
|
||||
INPAINTING = 3
|
||||
|
||||
def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None):
|
||||
def set_diffuser_pipe(pipe, new_pipe_type):
|
||||
wrapper_pipe = None
|
||||
|
||||
sd_checkpoint_info = pipe.sd_checkpoint_info
|
||||
sd_model_checkpoint = pipe.sd_model_checkpoint
|
||||
sd_model_hash = pipe.sd_model_hash
|
||||
|
||||
if pipe.__class__ == PriorPipeline:
|
||||
wrapper_pipe = pipe
|
||||
pipe = pipe.main
|
||||
|
||||
pipe_name = pipe.__class__.__name__
|
||||
pipe_name = pipe_name.replace("Img2Img", "").replace("Inpaint", "")
|
||||
if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE:
|
||||
new_pipe_cls_str = pipe_name
|
||||
elif new_pipe_type == DiffusersTaskType.IMAGE_2_IMAGE:
|
||||
new_pipe_cls_str = pipe_name.replace("Pipeline", "Img2ImgPipeline")
|
||||
elif new_pipe_type == DiffusersTaskType.INPAINTING:
|
||||
new_pipe_cls_str = pipe_name.replace("Pipeline", "InpaintPipeline")
|
||||
|
||||
new_pipe_cls = getattr(diffusers, new_pipe_cls_str)
|
||||
|
||||
if pipe.__class__ == new_pipe_cls:
|
||||
return
|
||||
|
||||
new_pipe = new_pipe_cls(**pipe.components)
|
||||
|
||||
if wrapper_pipe is not None:
|
||||
wrapper_pipe.main = new_pipe
|
||||
new_pipe = wrapper_pipe
|
||||
|
||||
new_pipe.sd_checkpoint_info = sd_checkpoint_info
|
||||
new_pipe.sd_model_checkpoint = sd_model_checkpoint
|
||||
new_pipe.sd_model_hash = sd_model_hash
|
||||
|
||||
model_data.sd_model = new_pipe
|
||||
shared.log.info(f"Pipeline class changed from {pipe.__class__.__name__} to {new_pipe_cls.__name__}")
|
||||
|
||||
|
||||
def get_diffusers_task(pipe: diffusers.DiffusionPipeline) -> DiffusersTaskType:
|
||||
if pipe.__class__ == PriorPipeline:
|
||||
pipe = pipe.main
|
||||
|
||||
if "Img2Img" in pipe.__class__.__name__:
|
||||
return DiffusersTaskType.IMAGE_2_IMAGE
|
||||
elif "Inpaint" in pipe.__class__.__name__:
|
||||
return DiffusersTaskType.INPAINTING
|
||||
return DiffusersTaskType.TEXT_2_IMAGE
|
||||
|
||||
|
||||
def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'):
|
||||
from modules import lowvram, sd_hijack
|
||||
checkpoint_info = checkpoint_info or select_checkpoint()
|
||||
checkpoint_info = checkpoint_info or select_checkpoint(op=op)
|
||||
if checkpoint_info is None:
|
||||
return
|
||||
if model_data.sd_model is not None and (checkpoint_info.hash == model_data.sd_model.sd_checkpoint_info.hash): # trying to load the same model
|
||||
return
|
||||
shared.log.debug(f'Load model: name={checkpoint_info.filename} dict={already_loaded_state_dict is not None}')
|
||||
if op == 'model' or op == 'dict':
|
||||
if model_data.sd_model is not None and (checkpoint_info.hash == model_data.sd_model.sd_checkpoint_info.hash): # trying to load the same model
|
||||
return
|
||||
else:
|
||||
if model_data.sd_refiner is not None and (checkpoint_info.hash == model_data.sd_refiner.sd_checkpoint_info.hash): # trying to load the same model
|
||||
return
|
||||
shared.log.debug(f'Load {op}: name={checkpoint_info.filename} dict={already_loaded_state_dict is not None}')
|
||||
if timer is None:
|
||||
timer = Timer()
|
||||
current_checkpoint_info = None
|
||||
if model_data.sd_model is not None:
|
||||
sd_hijack.model_hijack.undo_hijack(model_data.sd_model)
|
||||
current_checkpoint_info = model_data.sd_model.sd_checkpoint_info
|
||||
unload_model_weights()
|
||||
if op == 'model' or op == 'dict':
|
||||
if model_data.sd_model is not None:
|
||||
sd_hijack.model_hijack.undo_hijack(model_data.sd_model)
|
||||
current_checkpoint_info = model_data.sd_model.sd_checkpoint_info
|
||||
unload_model_weights(op=op)
|
||||
else:
|
||||
if model_data.sd_refiner is not None:
|
||||
sd_hijack.model_hijack.undo_hijack(model_data.sd_refiner)
|
||||
current_checkpoint_info = model_data.sd_refiner.sd_checkpoint_info
|
||||
unload_model_weights(op=op)
|
||||
|
||||
do_inpainting_hijack()
|
||||
devices.set_cuda_params()
|
||||
if already_loaded_state_dict is not None:
|
||||
@@ -589,7 +878,10 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None)
|
||||
sd_model = torch.xpu.optimize(sd_model, dtype=devices.dtype, auto_kernel_selection=True, optimize_lstm=True,
|
||||
graph_mode=True if shared.opts.cuda_compile and shared.opts.cuda_compile_mode == 'ipex' else False)
|
||||
shared.log.info("Applied IPEX Optimize")
|
||||
model_data.sd_model = sd_model
|
||||
if op == 'refiner':
|
||||
model_data.sd_refiner = sd_model
|
||||
else:
|
||||
model_data.sd_model = sd_model
|
||||
sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings(force_reload=True) # Reload embeddings after model load as they may or may not fit the model
|
||||
timer.record("embeddings")
|
||||
script_callbacks.model_loaded_callback(sd_model)
|
||||
@@ -600,7 +892,7 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None)
|
||||
shared.log.info(f'Model load finished: {memory_stats()} cached={len(checkpoints_loaded.keys())}')
|
||||
|
||||
|
||||
def reload_model_weights(sd_model=None, info=None, reuse_dict=False):
|
||||
def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model'):
|
||||
load_dict = shared.opts.sd_model_dict != model_data.sd_dict
|
||||
global skip_next_load # pylint: disable=global-statement
|
||||
if skip_next_load:
|
||||
@@ -608,15 +900,18 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False):
|
||||
skip_next_load = False
|
||||
return
|
||||
from modules import lowvram, sd_hijack
|
||||
checkpoint_info = info or select_checkpoint(model=not load_dict) # are we selecting model or dictionary
|
||||
next_checkpoint_info = info or select_checkpoint(model=load_dict) if load_dict else None
|
||||
checkpoint_info = info or select_checkpoint(op=op) # are we selecting model or dictionary
|
||||
next_checkpoint_info = info or select_checkpoint(op='dict' if load_dict else 'model') if load_dict else None
|
||||
if checkpoint_info is None:
|
||||
unload_model_weights(op=op)
|
||||
return
|
||||
if load_dict:
|
||||
shared.log.debug(f'Model dict: existing={sd_model is not None} target={checkpoint_info.filename} info={info}')
|
||||
else:
|
||||
model_data.sd_dict = 'None'
|
||||
shared.log.debug(f'Load model weights: existing={sd_model is not None} target={checkpoint_info.filename} info={info}')
|
||||
if not sd_model:
|
||||
sd_model = model_data.sd_model
|
||||
sd_model = model_data.sd_model if op == 'model' or op == 'dict' else model_data.sd_refiner
|
||||
if sd_model is None: # previous model load failed
|
||||
current_checkpoint_info = None
|
||||
else:
|
||||
@@ -631,7 +926,7 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False):
|
||||
shared.log.info('Reusing previous model dictionary')
|
||||
sd_hijack.model_hijack.undo_hijack(sd_model)
|
||||
else:
|
||||
unload_model_weights()
|
||||
unload_model_weights(op=op)
|
||||
sd_model = None
|
||||
timer = Timer()
|
||||
state_dict = get_checkpoint_state_dict(checkpoint_info, timer)
|
||||
@@ -640,14 +935,14 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False):
|
||||
if sd_model is None or checkpoint_config != sd_model.used_config:
|
||||
del sd_model
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
load_model(checkpoint_info, already_loaded_state_dict=state_dict, timer=timer)
|
||||
load_model(checkpoint_info, already_loaded_state_dict=state_dict, timer=timer, op=op)
|
||||
else:
|
||||
load_diffuser(checkpoint_info, already_loaded_state_dict=state_dict, timer=timer)
|
||||
load_diffuser(checkpoint_info, already_loaded_state_dict=state_dict, timer=timer, op=op)
|
||||
if load_dict and next_checkpoint_info is not None:
|
||||
model_data.sd_dict = shared.opts.sd_model_dict
|
||||
shared.opts.data["sd_model_checkpoint"] = next_checkpoint_info.title
|
||||
reload_model_weights(reuse_dict=True) # ok we loaded dict now lets redo and load model on top of it
|
||||
return model_data.sd_model
|
||||
return model_data.sd_model if op == 'model' or op == 'dict' else model_data.sd_refiner
|
||||
try:
|
||||
load_model_weights(sd_model, checkpoint_info, state_dict, timer)
|
||||
except Exception:
|
||||
@@ -664,17 +959,23 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False):
|
||||
shared.log.info(f"Weights loaded in {timer.summary()}")
|
||||
|
||||
|
||||
def unload_model_weights(sd_model=None, _info=None):
|
||||
def unload_model_weights(op='model'):
|
||||
from modules import sd_hijack
|
||||
if model_data.sd_model:
|
||||
model_data.sd_model.to(devices.cpu)
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
sd_hijack.model_hijack.undo_hijack(model_data.sd_model)
|
||||
sd_model = None
|
||||
model_data.sd_model = None
|
||||
devices.torch_gc(force=True)
|
||||
shared.log.debug(f'Model weights unloaded: {memory_stats()}')
|
||||
return sd_model
|
||||
if op == 'model' or op == 'dict':
|
||||
if model_data.sd_model:
|
||||
model_data.sd_model.to(devices.cpu)
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
sd_hijack.model_hijack.undo_hijack(model_data.sd_model)
|
||||
model_data.sd_model = None
|
||||
shared.log.debug(f'Weights unloaded {op}: {memory_stats()}')
|
||||
else:
|
||||
if model_data.sd_refiner:
|
||||
model_data.sd_refiner.to(devices.cpu)
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
sd_hijack.model_hijack.undo_hijack(model_data.sd_refiner)
|
||||
model_data.sd_refiner = None
|
||||
shared.log.debug(f'Weights unloaded {op}: {memory_stats()}')
|
||||
devices.torch_gc(force=True)
|
||||
|
||||
|
||||
def apply_token_merging(sd_model, token_merging_ratio):
|
||||
@@ -684,6 +985,11 @@ def apply_token_merging(sd_model, token_merging_ratio):
|
||||
return
|
||||
if current_token_merging_ratio > 0:
|
||||
tomesd.remove_patch(sd_model)
|
||||
|
||||
if sd_model.__class__ == PriorPipeline:
|
||||
# token merging is not supported for PriorPipelines currently
|
||||
return
|
||||
|
||||
if token_merging_ratio > 0:
|
||||
tomesd.apply_patch(
|
||||
sd_model,
|
||||
|
||||
+7
-10
@@ -1,16 +1,11 @@
|
||||
from modules import sd_samplers_compvis, sd_samplers_kdiffusion, sd_samplers_diffusors, shared
|
||||
from modules import sd_samplers_compvis, sd_samplers_kdiffusion, sd_samplers_diffusers, shared
|
||||
from modules.sd_samplers_common import samples_to_image_grid, sample_to_image # pylint: disable=unused-import
|
||||
from modules.shared import backend, Backend
|
||||
|
||||
if backend == Backend.ORIGINAL:
|
||||
all_samplers = [
|
||||
*sd_samplers_kdiffusion.samplers_data_k_diffusion,
|
||||
*sd_samplers_compvis.samplers_data_compvis,
|
||||
]
|
||||
all_samplers = [*sd_samplers_kdiffusion.samplers_data_k_diffusion, *sd_samplers_compvis.samplers_data_compvis]
|
||||
else:
|
||||
all_samplers = [
|
||||
*sd_samplers_diffusors.samplers_data_diffusors,
|
||||
]
|
||||
all_samplers = [*sd_samplers_diffusers.samplers_data_diffusers]
|
||||
all_samplers_map = {x.name: x for x in all_samplers}
|
||||
samplers = all_samplers
|
||||
samplers_for_img2img = all_samplers
|
||||
@@ -34,10 +29,12 @@ def create_sampler(name, model):
|
||||
sampler = config.constructor(model)
|
||||
sampler.config = config
|
||||
return sampler
|
||||
else:
|
||||
sampler = config.constructor(model.sd_checkpoint_info.filename)
|
||||
elif backend == Backend.DIFFUSERS:
|
||||
sampler = config.constructor(model)
|
||||
model.scheduler = sampler.sampler
|
||||
return sampler.sampler
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def set_samplers():
|
||||
|
||||
@@ -37,7 +37,6 @@ class VanillaStableDiffusionSampler:
|
||||
self.eta = None
|
||||
self.config = None
|
||||
self.last_latent = None
|
||||
|
||||
self.conditioning_key = sd_model.model.conditioning_key
|
||||
|
||||
def number_of_needed_noises(self, p): # pylint: disable=unused-argument
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
from diffusers import (
|
||||
DDIMScheduler,
|
||||
DDPMScheduler,
|
||||
DEISMultistepScheduler,
|
||||
DPMSolverMultistepScheduler,
|
||||
DPMSolverSinglestepScheduler,
|
||||
EulerAncestralDiscreteScheduler,
|
||||
EulerDiscreteScheduler,
|
||||
HeunDiscreteScheduler,
|
||||
# KDPM2DiscreteScheduler,
|
||||
PNDMScheduler,
|
||||
UniPCMultistepScheduler,
|
||||
)
|
||||
from modules import sd_samplers_common
|
||||
|
||||
config = {
|
||||
'All': { 'num_train_timesteps': 1000, 'beta_start': 0.0001, 'beta_end': 0.02, 'beta_schedule': 'linear', 'prediction_type': 'epsilon' },
|
||||
'UniPC': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'predict_x0': 'bh2', 'lower_order_final': True },
|
||||
'DDIM': { 'clip_sample': True, 'set_alpha_to_one': True, 'steps_offset': 0, 'thresholding': False, 'clip_sample_range': 1.0, 'sample_max_value': 1.0, 'timestep_spacing': 'leading', 'rescale_betas_zero_snr': False },
|
||||
'DDPM': { 'variance_type': "fixed_small", 'clip_sample': True, 'thresholding': False, 'clip_sample_range': 1.0, 'sample_max_value': 1.0 },
|
||||
'DEIS': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "deis", 'solver_type': "logrho", 'lower_order_final': True },
|
||||
'Euler': { 'interpolation_type': "linear", 'use_karras_sigmas': False },
|
||||
'Euler a': {},
|
||||
'Heun': { 'use_karras_sigmas': False },
|
||||
'PNDM': { 'skip_prk_steps': False, 'set_alpha_to_one': False, 'steps_offset': 0 },
|
||||
'DPM 1S': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False },
|
||||
'DPM 2M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False },
|
||||
}
|
||||
|
||||
samplers_data_diffusers = [
|
||||
sd_samplers_common.SamplerData('UniPC', lambda model: DiffusionSampler('UniPC', UniPCMultistepScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DDIM', lambda model: DiffusionSampler('DDIM', DDIMScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DDPM', lambda model: DiffusionSampler('DDPM', DDPMScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DEIS', lambda model: DiffusionSampler('DEIS', DEISMultistepScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DPM 1S', lambda model: DiffusionSampler('DPM++ 1S', DPMSolverSinglestepScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DPM 2M', lambda model: DiffusionSampler('DPM++ 2M', DPMSolverMultistepScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('Euler', lambda model: DiffusionSampler('Euler', EulerDiscreteScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('Euler a', lambda model: DiffusionSampler('Euler a', EulerAncestralDiscreteScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('Heun', lambda model: DiffusionSampler('Heun', HeunDiscreteScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('PNDM', lambda model: DiffusionSampler('PNDM', PNDMScheduler, model), [], {}),
|
||||
]
|
||||
|
||||
class DiffusionSampler:
|
||||
def __init__(self, name, constructor, model, **kwargs):
|
||||
from modules.shared import opts, log
|
||||
self.config = config['All'].copy()
|
||||
for key, value in config.get(name, {}).items(): # diffusers defaults
|
||||
self.config[key] = value
|
||||
for key, value in model.scheduler.config.items(): # model defaults
|
||||
if key in self.config:
|
||||
self.config[key] = value
|
||||
for key, value in kwargs.items(): # user args
|
||||
if key in self.config:
|
||||
self.config[key] = value
|
||||
if opts.schedulers_prediction_type != 'default':
|
||||
self.config['prediction_type'] = opts.schedulers_prediction_type
|
||||
if opts.schedulers_beta_schedule != 'default':
|
||||
self.config['beta_schedule'] = opts.schedulers_beta_schedule
|
||||
if 'use_karras_sigmas' in self.config:
|
||||
self.config['use_karras_sigmas'] = opts.schedulers_use_karras
|
||||
if 'thresholding' in self.config:
|
||||
self.config['thresholding'] = opts.schedulers_use_thresholding
|
||||
if 'lower_order_final' in self.config:
|
||||
self.config['lower_order_final'] = opts.schedulers_use_loworder
|
||||
if 'solver_order' in self.config:
|
||||
self.config['solver_order'] = opts.schedulers_solver_order
|
||||
if name.startswith('DPM'):
|
||||
self.config['algorithm_type'] = opts.schedulers_dpm_solver
|
||||
self.sampler = constructor(**self.config)
|
||||
self.sampler.name = name
|
||||
log.debug(f'Diffusers sampler: {name} {self.config}')
|
||||
@@ -1,45 +0,0 @@
|
||||
from diffusers import (
|
||||
DDIMScheduler,
|
||||
DDPMScheduler,
|
||||
DEISMultistepScheduler,
|
||||
DPMSolverMultistepScheduler,
|
||||
EulerAncestralDiscreteScheduler,
|
||||
EulerDiscreteScheduler,
|
||||
HeunDiscreteScheduler,
|
||||
IPNDMScheduler,
|
||||
KDPM2AncestralDiscreteScheduler,
|
||||
PNDMScheduler,
|
||||
UniPCMultistepScheduler,
|
||||
# KarrasVeScheduler,
|
||||
# RePaintScheduler,
|
||||
# ScoreSdeVeScheduler,
|
||||
# UnCLIPScheduler,
|
||||
# VQDiffusionScheduler,
|
||||
)
|
||||
from modules import sd_samplers_common
|
||||
# scheduler = diffusers.UniPCMultistepScheduler.from_pretrained(shared.cmd_opts.ckpt, subfolder="scheduler")
|
||||
|
||||
samplers_data_diffusors = [
|
||||
sd_samplers_common.SamplerData('UniPC', lambda model: DiffusionSampler('UniPC', UniPCMultistepScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DDIM', lambda model: DiffusionSampler('DDIM', DDIMScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DDPMS', lambda model: DiffusionSampler('DDPMS', DDPMScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DEIS', lambda model: DiffusionSampler('DEIS', DEISMultistepScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('DPMSolver', lambda model: DiffusionSampler('DPMSolver', DPMSolverMultistepScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('Euler', lambda model: DiffusionSampler('Euler', EulerDiscreteScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('EulerAncestral', lambda model: DiffusionSampler('EulerAncestral', EulerAncestralDiscreteScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('Heun', lambda model: DiffusionSampler('Heun', HeunDiscreteScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('IPNDM', lambda model: DiffusionSampler('IPNDM', IPNDMScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('KDPM2Ancestral', lambda model: DiffusionSampler('KDPM2Ancestral', KDPM2AncestralDiscreteScheduler, model), [], {}),
|
||||
sd_samplers_common.SamplerData('PNDMS', lambda model: DiffusionSampler('PNDMS', PNDMScheduler, model), [], {}),
|
||||
# sd_samplers_common.SamplerData('KarrasVe', lambda model: DiffusionSampler('KarrasVe', KarrasVeScheduler, model), [], {}),
|
||||
# sd_samplers_common.SamplerData('RePaint', lambda model: DiffusionSampler('RePaint', RePaintScheduler, model), [], {}),
|
||||
# sd_samplers_common.SamplerData('ScoreSdeVe', lambda model: DiffusionSampler('ScoreSdeVe', ScoreSdeVeScheduler, model), [], {}),
|
||||
# sd_samplers_common.SamplerData('UnCLIP', lambda model: DiffusionSampler('UnCLIP', UnCLIPScheduler, model), [], {}),
|
||||
# sd_samplers_common.SamplerData('VQDiffusion', lambda model: DiffusionSampler('VQDiffusion', VQDiffusionScheduler, model), [], {}),
|
||||
]
|
||||
|
||||
|
||||
class DiffusionSampler:
|
||||
def __init__(self, name, constructor, sd_model):
|
||||
self.sampler = constructor.from_pretrained(sd_model, subfolder="scheduler")
|
||||
self.sampler.name = name
|
||||
+41
-6
@@ -5,6 +5,7 @@ from copy import deepcopy
|
||||
import torch
|
||||
from modules import shared, paths, devices, script_callbacks, sd_models
|
||||
|
||||
|
||||
vae_ignore_keys = {"model_ema.decay", "model_ema.num_updates"}
|
||||
vae_dict = {}
|
||||
base_vae = None
|
||||
@@ -13,6 +14,7 @@ checkpoint_info = None
|
||||
vae_path = os.path.abspath(os.path.join(paths.models_path, 'VAE'))
|
||||
checkpoints_loaded = collections.OrderedDict()
|
||||
|
||||
|
||||
def get_base_vae(model):
|
||||
if base_vae is not None and checkpoint_info == model.sd_checkpoint_info and model:
|
||||
return base_vae
|
||||
@@ -147,6 +149,34 @@ def load_vae(model, vae_file=None, vae_source="from unknown source"):
|
||||
loaded_vae_file = vae_file
|
||||
|
||||
|
||||
def load_vae_diffusers(_model, vae_file=None, vae_source="from unknown source"):
|
||||
global loaded_vae_file # pylint: disable=global-statement
|
||||
if loaded_vae_file == vae_file:
|
||||
return
|
||||
loaded_vae_file = None
|
||||
if vae_file is None:
|
||||
return
|
||||
if not os.path.isfile(vae_file):
|
||||
shared.log.error('VAE not found: {vae_file}')
|
||||
return
|
||||
shared.log.info(f"Loading diffusers VAE: {vae_source}: {vae_file}")
|
||||
diffusers_load_config = {
|
||||
"low_cpu_mem_usage": True,
|
||||
"torch_dtype": devices.dtype_vae,
|
||||
"use_safetensors": True,
|
||||
}
|
||||
if devices.dtype_vae == torch.float16:
|
||||
diffusers_load_config['variant'] = 'fp16'
|
||||
shared.log.debug(f'Diffusers VAE load config: {diffusers_load_config}')
|
||||
try:
|
||||
import diffusers
|
||||
diffusers_vae = diffusers.AutoencoderKL.from_pretrained(vae_file, **diffusers_load_config)
|
||||
except Exception as e:
|
||||
shared.log.error(f"Loading diffusers VAE failed: {vae_file} {e}")
|
||||
diffusers_vae = None
|
||||
return diffusers_vae
|
||||
|
||||
|
||||
# don't call this from outside
|
||||
def _load_vae_dict(model, vae_dict_1):
|
||||
model.first_stage_model.load_state_dict(vae_dict_1)
|
||||
@@ -178,12 +208,17 @@ def reload_vae_weights(sd_model=None, vae_file=unspecified):
|
||||
lowvram.send_everything_to_cpu()
|
||||
else:
|
||||
sd_model.to(devices.cpu)
|
||||
sd_hijack.model_hijack.undo_hijack(sd_model)
|
||||
if shared.cmd_opts.rollback_vae and devices.dtype_vae == torch.bfloat16:
|
||||
devices.dtype_vae = torch.float16
|
||||
load_vae(sd_model, vae_file, vae_source)
|
||||
sd_hijack.model_hijack.hijack(sd_model)
|
||||
script_callbacks.model_loaded_callback(sd_model)
|
||||
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
sd_hijack.model_hijack.undo_hijack(sd_model)
|
||||
if shared.cmd_opts.rollback_vae and devices.dtype_vae == torch.bfloat16:
|
||||
devices.dtype_vae = torch.float16
|
||||
load_vae(sd_model, vae_file, vae_source)
|
||||
sd_hijack.model_hijack.hijack(sd_model)
|
||||
script_callbacks.model_loaded_callback(sd_model)
|
||||
elif shared.backend == shared.Backend.DIFFUSERS:
|
||||
load_vae_diffusers(sd_model, vae_file, vae_source)
|
||||
|
||||
if not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram:
|
||||
sd_model.to(devices.device)
|
||||
shared.log.info(f"VAE weights loaded: {vae_file}")
|
||||
|
||||
+109
-36
@@ -4,6 +4,7 @@ import time
|
||||
import json
|
||||
import datetime
|
||||
import urllib.request
|
||||
from urllib.parse import urlparse
|
||||
from enum import Enum
|
||||
import gradio as gr
|
||||
import tqdm
|
||||
@@ -37,6 +38,10 @@ hypernetworks = {}
|
||||
loaded_hypernetworks = []
|
||||
gradio_theme = gr.themes.Base()
|
||||
settings_components = None
|
||||
pipelines = [
|
||||
'Stable Diffusion', 'Stable Diffusion XL', 'Kandinsky V1', 'Kandinsky V2', 'DeepFloyd IF', 'Shap-E',
|
||||
'Stable Diffusion Img2Img', 'Stable Diffusion XL Img2Img', 'Kandinsky V1 Img2Img', 'Kandinsky V2 Img2Img', 'DeepFloyd IF Img2Img', 'Shap-E Img2Img'
|
||||
]
|
||||
latent_upscale_default_mode = "Latent"
|
||||
latent_upscale_modes = {
|
||||
"Latent": {"mode": "bilinear", "antialias": False},
|
||||
@@ -72,6 +77,11 @@ ui_reorder_categories = [
|
||||
]
|
||||
|
||||
|
||||
def is_url(string):
|
||||
parsed_url = urlparse(string)
|
||||
return all([parsed_url.scheme, parsed_url.netloc])
|
||||
|
||||
|
||||
class Backend(Enum):
|
||||
ORIGINAL = 1
|
||||
DIFFUSERS = 2
|
||||
@@ -182,10 +192,12 @@ class State:
|
||||
|
||||
state = State()
|
||||
state.server_start = time.time()
|
||||
backend = Backend.DIFFUSERS if (cmd_opts.backend is not None) and (cmd_opts.backend.lower() == 'diffusers') else Backend.ORIGINAL
|
||||
log.info(f'Pipeline: {backend}')
|
||||
|
||||
|
||||
class OptionInfo:
|
||||
def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, section=None, refresh=None, comment_before='', comment_after=''):
|
||||
def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, section=None, refresh=None, submit=None, comment_before='', comment_after=''):
|
||||
self.default = default
|
||||
self.label = label
|
||||
self.component = component
|
||||
@@ -195,6 +207,7 @@ class OptionInfo:
|
||||
self.refresh = refresh
|
||||
self.comment_before = comment_before # HTML text that will be added after label in UI
|
||||
self.comment_after = comment_after # HTML text that will be added before label in UI
|
||||
self.submit = submit
|
||||
|
||||
def link(self, label, uri):
|
||||
self.comment_before += f"[<a href='{uri}' target='_blank'>{label}</a>]"
|
||||
@@ -208,6 +221,10 @@ class OptionInfo:
|
||||
self.comment_after += f"<span class='info'>({info})</span>"
|
||||
return self
|
||||
|
||||
def html(self, info):
|
||||
self.comment_after += f"<span class='info'>{info}</span>"
|
||||
return self
|
||||
|
||||
def needs_restart(self):
|
||||
self.comment_after += " <span class='info'>(requires restart)</span>"
|
||||
return self
|
||||
@@ -223,7 +240,6 @@ def list_checkpoint_tiles():
|
||||
import modules.sd_models # pylint: disable=W0621
|
||||
return modules.sd_models.checkpoint_tiles()
|
||||
|
||||
|
||||
default_checkpoint = list_checkpoint_tiles()[0] if len(list_checkpoint_tiles()) > 0 else "model.ckpt"
|
||||
|
||||
|
||||
@@ -251,12 +267,17 @@ def list_themes():
|
||||
return themes
|
||||
|
||||
|
||||
def lora_disable():
|
||||
def disable_extensions():
|
||||
if opts.lora_disable:
|
||||
if 'Lora' not in opts.disabled_extensions:
|
||||
opts.data['disabled_extensions'].append('Lora')
|
||||
else:
|
||||
opts.data['disabled_extensions'] = [x for x in opts.disabled_extensions if x != 'Lora']
|
||||
if backend == Backend.DIFFUSERS:
|
||||
for ext in ['sd-webui-controlnet', 'sd-dynamic-thresholding', 'multidiffusion-upscaler-for-automatic1111', 'a1111-sd-webui-lycoris']:
|
||||
if ext not in opts.disabled_extensions:
|
||||
log.warning(f'Diffusers disabling uncompatible extension: {ext}')
|
||||
opts.data['disabled_extensions'].append(ext)
|
||||
|
||||
|
||||
def refresh_themes():
|
||||
@@ -287,8 +308,9 @@ else: # cuda
|
||||
cross_attention_optimization_default ="Scaled-Dot-Product"
|
||||
|
||||
options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
||||
"sd_model_checkpoint": OptionInfo(default_checkpoint, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_checkpoint_autoload": OptionInfo(True, "Stable Diffusion checkpoint autoload on server start"),
|
||||
"sd_model_checkpoint": OptionInfo(default_checkpoint, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_model_refiner": OptionInfo('None', "Stable Diffusion refiner", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_checkpoint_cache": OptionInfo(0, "Number of cached model checkpoints", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae_checkpoint_cache": OptionInfo(0, "Number of cached VAE checkpoints", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae": OptionInfo("Automatic", "Select VAE", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list),
|
||||
@@ -299,7 +321,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
||||
"prompt_mean_norm": OptionInfo(True, "Prompt attention mean normalization"),
|
||||
"comma_padding_backtrack": OptionInfo(20, "Prompt padding for long prompts", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }),
|
||||
"sd_disable_ckpt": OptionInfo(False, "Disallow usage of checkpoints in ckpt format"),
|
||||
"sd_backend": OptionInfo("Original", "Stable Diffusion backend (experimental)", gr.Radio, lambda: {"choices": ["Original", "Diffusers"] }),
|
||||
"sd_backend": OptionInfo("original", "Stable Diffusion backend (experimental)", gr.Radio, lambda: {"choices": ["original", "diffusers"] }),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('optimizations', "Optimizations"), {
|
||||
@@ -329,10 +351,23 @@ options_templates.update(options_section(('cuda', "Compute Settings"), {
|
||||
"cuda_allow_tf32": OptionInfo(True, "Allow TF32 math ops"),
|
||||
"cuda_allow_tf16_reduced": OptionInfo(True, "Allow TF16 reduced precision math ops"),
|
||||
"cuda_compile": OptionInfo(False, "Enable model compile (experimental)"),
|
||||
"cuda_compile_mode": OptionInfo("none", "Model compile mode (experimental)", gr.Radio, lambda: {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex']}),
|
||||
"cuda_compile_mode": OptionInfo("none", "Model compile mode (experimental)", gr.Radio, lambda: {"choices": ['none', 'inductor', 'reduce-overhead', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex']}),
|
||||
"cuda_compile_fullgraph": OptionInfo(False, "Model compile fullgraph"),
|
||||
"cuda_compile_verbose": OptionInfo(False, "Model compile verbose mode"),
|
||||
"cuda_compile_errors": OptionInfo(True, "Model compile suppress errors"),
|
||||
"disable_gc": OptionInfo(False, "Disable Torch memory garbage collection"),
|
||||
"disable_gc": OptionInfo(True, "Disable Torch memory garbage collection on each generation"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('diffusers', "Diffusers Settings"), {
|
||||
"diffusers_allow_safetensors": OptionInfo(False, 'Diffuser Pipeline when loading from safetensors'),
|
||||
"diffusers_pipeline": OptionInfo(pipelines[0], 'Diffuser Pipeline when loading from safetensors', gr.Dropdown, lambda: {"choices": pipelines}),
|
||||
"diffusers_extract_ema": OptionInfo(True, "Use model EMA weights when possible"),
|
||||
"diffusers_generator_device": OptionInfo("default", "Generator device", gr.Radio, lambda: {"choices": ["default", "cpu"]}),
|
||||
"diffusers_seq_cpu_offload": OptionInfo(False, "Enable sequential CPU offload"),
|
||||
"diffusers_model_cpu_offload": OptionInfo(False, "Enable model CPU offload"),
|
||||
"diffusers_vae_slicing": OptionInfo(False, "Enable VAE slicing"),
|
||||
"diffusers_vae_tiling": OptionInfo(False, "Enable VAE tiling"),
|
||||
"diffusers_attention_slicing": OptionInfo(False, "Enable attention slicing"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('system-paths', "System Paths"), {
|
||||
@@ -401,7 +436,7 @@ options_templates.update(options_section(('image-processing', "Image Processing"
|
||||
}))
|
||||
|
||||
|
||||
options_templates.update(options_section(('saving-paths', "Output Paths"), {
|
||||
options_templates.update(options_section(('saving-paths', "Image Paths"), {
|
||||
"outdir_samples": OptionInfo("", "Output directory for images", component_args=hide_dirs),
|
||||
"outdir_txt2img_samples": OptionInfo("outputs/text", 'Output directory for txt2img images', component_args=hide_dirs),
|
||||
"outdir_img2img_samples": OptionInfo("outputs/image", 'Output directory for img2img images', component_args=hide_dirs),
|
||||
@@ -432,7 +467,6 @@ options_templates.update(options_section(('ui', "User Interface"), {
|
||||
"ui_tab_reorder": OptionInfo("From Text, From Image, Process Image", "UI tabs order"),
|
||||
"ui_scripts_reorder": OptionInfo("Enable Dynamic Thresholding, ControlNet", "UI scripts order"),
|
||||
"ui_reorder": OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"),
|
||||
"ui_extra_networks_tab_reorder": OptionInfo("Checkpoints, Lora, LyCORIS, Textual Inversion, Hypernetworks", "Extra networks tab order"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('live-preview', "Live Previews"), {
|
||||
@@ -449,27 +483,59 @@ options_templates.update(options_section(('live-preview', "Live Previews"), {
|
||||
"logmonitor_refresh_period": OptionInfo(5000, "Log view update period, in milliseconds", gr.Slider, {"minimum": 0, "maximum": 30000, "step": 25}),
|
||||
}))
|
||||
|
||||
|
||||
options_templates.update(options_section(('sampler-params', "Sampler Settings"), {
|
||||
"show_samplers": OptionInfo(["Euler a", "UniPC", "DDIM", "DPM++ 2M SDE", "DPM++ 2M SDE Karras", "DPM2 Karras", "DPM++ 2M Karras"], "Show samplers in user interface", gr.CheckboxGroup, lambda: {"choices": [x.name for x in list_samplers() if x.name != "PLMS"]}),
|
||||
"show_samplers": OptionInfo(["Euler a", "UniPC", "DEIS", "DDIM", "DPM 1S", "DPM 2M", "DPM++ 2M SDE", "DPM++ 2M SDE Karras", "DPM2 Karras", "DPM++ 2M Karras"], "Show samplers in user interface", gr.CheckboxGroup, lambda: {"choices": [x.name for x in list_samplers() if x.name != "PLMS"]}),
|
||||
"fallback_sampler": OptionInfo("Euler a", "Secondary sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
|
||||
"force_latent_sampler": OptionInfo("None", "Force latent upscaler sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
|
||||
"always_batch_cond_uncond": OptionInfo(False, "Disable conditional batching enabled on low memory systems"),
|
||||
"enable_quantization": OptionInfo(True, "Enable samplers quantization for sharper and cleaner results"),
|
||||
"eta_ancestral": OptionInfo(1.0, "Noise multiplier for ancestral samplers (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"eta_ddim": OptionInfo(0.0, "Noise multiplier for DDIM (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"ddim_discretize": OptionInfo('uniform', "DDIM discretize img2img", gr.Radio, {"choices": ['uniform', 'quad']}),
|
||||
's_churn': OptionInfo(0.0, "sigma churn", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
's_min_uncond': OptionInfo(0, "sigma negative guidance minimum ", gr.Slider, {"minimum": 0.0, "maximum": 4.0, "step": 0.01}),
|
||||
's_tmin': OptionInfo(0.0, "sigma tmin", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
's_noise': OptionInfo(1.0, "sigma noise", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
'eta_noise_seed_delta': OptionInfo(0, "Noise seed delta (eta)", gr.Number, {"precision": 0}),
|
||||
'always_discard_next_to_last_sigma': OptionInfo(False, "Always discard next-to-last sigma"),
|
||||
'uni_pc_variant': OptionInfo("bh1", "UniPC variant", gr.Radio, {"choices": ["bh1", "bh2", "vary_coeff"]}),
|
||||
'uni_pc_skip_type': OptionInfo("time_uniform", "UniPC skip type", gr.Radio, {"choices": ["time_uniform", "time_quadratic", "logSNR"]}),
|
||||
'uni_pc_order': OptionInfo(3, "UniPC order (must be < sampling steps)", gr.Slider, {"minimum": 1, "maximum": 10, "step": 1}),
|
||||
'uni_pc_lower_order_final': OptionInfo(True, "UniPC lower order final"),
|
||||
}))
|
||||
|
||||
if backend == Backend.ORIGINAL:
|
||||
options_templates.update(options_section(('sampler-params', "Sampler Settings"), {
|
||||
"always_batch_cond_uncond": OptionInfo(False, "Disable conditional batching enabled on low memory systems"),
|
||||
"enable_quantization": OptionInfo(True, "Enable samplers quantization for sharper and cleaner results"),
|
||||
"eta_ancestral": OptionInfo(1.0, "Noise multiplier for ancestral samplers (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"eta_ddim": OptionInfo(0.0, "Noise multiplier for DDIM (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"ddim_discretize": OptionInfo('uniform', "DDIM discretize img2img", gr.Radio, {"choices": ['uniform', 'quad']}),
|
||||
's_churn': OptionInfo(0.0, "sigma churn", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
's_min_uncond': OptionInfo(0, "sigma negative guidance minimum ", gr.Slider, {"minimum": 0.0, "maximum": 4.0, "step": 0.01}),
|
||||
's_tmin': OptionInfo(0.0, "sigma tmin", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
's_noise': OptionInfo(1.0, "sigma noise", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
'eta_noise_seed_delta': OptionInfo(0, "Noise seed delta (eta)", gr.Number, {"precision": 0}),
|
||||
'always_discard_next_to_last_sigma': OptionInfo(False, "Always discard next-to-last sigma"),
|
||||
'uni_pc_variant': OptionInfo("bh1", "UniPC variant", gr.Radio, {"choices": ["bh1", "bh2", "vary_coeff"]}),
|
||||
'uni_pc_skip_type': OptionInfo("time_uniform", "UniPC skip type", gr.Radio, {"choices": ["time_uniform", "time_quadratic", "logSNR"]}),
|
||||
'uni_pc_order': OptionInfo(3, "UniPC order (must be < sampling steps)", gr.Slider, {"minimum": 1, "maximum": 10, "step": 1}),
|
||||
'uni_pc_lower_order_final': OptionInfo(True, "UniPC lower order final"),
|
||||
}))
|
||||
elif backend == Backend.DIFFUSERS:
|
||||
options_templates.update(options_section(('sampler-params', "Sampler Settings"), {
|
||||
# hidden - included for compatibility only
|
||||
"always_batch_cond_uncond": OptionInfo(False, "Disable conditional batching enabled on low memory systems", gr.Checkbox, { "visible": False}),
|
||||
"enable_quantization": OptionInfo(True, "Enable samplers quantization for sharper and cleaner results", gr.Checkbox, { "visible": False}),
|
||||
"eta_ancestral": OptionInfo(1.0, "Noise multiplier for ancestral samplers (eta)", gr.Number, { "visible": False}),
|
||||
"eta_ddim": OptionInfo(0.0, "Noise multiplier for DDIM (eta)", gr.Number, { "visible": False}),
|
||||
"ddim_discretize": OptionInfo('uniform', "", gr.Text, { "visible": False}),
|
||||
's_churn': OptionInfo(0.0, "sigma churn", gr.Number, { "visible": False}),
|
||||
's_min_uncond': OptionInfo(0, "sigma negative guidance minimum ", gr.Number, { "visible": False}),
|
||||
's_tmin': OptionInfo(0.0, "sigma tmin", gr.Number, { "visible": False}),
|
||||
's_noise': OptionInfo(1.0, "sigma noise", gr.Number, { "visible": False}),
|
||||
'eta_noise_seed_delta': OptionInfo(0, "Noise seed delta (eta)", gr.Number, {"precision": 0}, { "visible": False}),
|
||||
'always_discard_next_to_last_sigma': OptionInfo(False, "Always discard next-to-last sigma", gr.Checkbox, { "visible": False}),
|
||||
#'uni_pc_variant': OptionInfo("bh1", "UniPC variant", gr.Radio, {"choices": ["bh1", "bh2", "vary_coeff"]}, { "visible": False}),
|
||||
#'uni_pc_skip_type': OptionInfo("time_uniform", "UniPC skip type", gr.Radio, {"choices": ["time_uniform", "time_quadratic", "logSNR"]}, { "visible": False}),
|
||||
#'uni_pc_order': OptionInfo(3, "UniPC order (must be < sampling steps)", gr.Slider, {"minimum": 1, "maximum": 10, "step": 1}, { "visible": False}),
|
||||
#'uni_pc_lower_order_final': OptionInfo(True, "UniPC lower order final", { "visible": False}),
|
||||
# diffuser specific
|
||||
"schedulers_prediction_type": OptionInfo("default", "Samplers override model prediction type", gr.Radio, lambda: {"choices": ['default', 'epsilon', 'sample', 'v-prediction']}),
|
||||
"schedulers_beta_schedule": OptionInfo("default", "Samplers override beta schedule", gr.Radio, lambda: {"choices": ['default', 'linear', 'scaled_linear', 'squaredcos_cap_v2']}),
|
||||
"schedulers_solver_order": OptionInfo(2, "Samplers solver order where applicable", gr.Slider, {"minimum": 1, "maximum": 5, "step": 1}),
|
||||
"schedulers_use_karras": OptionInfo(True, "Samplers should use Karras sigmas where applicable"),
|
||||
"schedulers_use_loworder": OptionInfo(True, "Samplers should use use lower-order solvers in the final steps where applicable"),
|
||||
"schedulers_use_thresholding": OptionInfo(False, "Samplers should use dynamic thresholding where applicable"),
|
||||
"schedulers_dpm_solver": OptionInfo("sde-dpmsolver++", "Samplers DPM solver algorithm", gr.Radio, lambda: {"choices": ['dpmsolver', 'dpmsolver++', 'sde-dpmsolver++']}),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('postprocessing', "Postprocessing"), {
|
||||
'postprocessing_enable_in_main_ui': OptionInfo([], "Enable addtional postprocessing operations", ui_components.DropdownMulti, lambda: {"choices": [x.name for x in shared_items.postprocessing_scripts()]}),
|
||||
'postprocessing_operation_order': OptionInfo([], "Postprocessing operation order", ui_components.DropdownMulti, lambda: {"choices": [x.name for x in shared_items.postprocessing_scripts()]}),
|
||||
@@ -521,13 +587,17 @@ options_templates.update(options_section(('upscaling', "Upscaling"), {
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
|
||||
"ui_extra_networks_tab_reorder": OptionInfo("Checkpoints, Lora, LyCORIS, Textual Inversion, Hypernetworks", "Extra networks tab order"),
|
||||
"extra_networks_card_cover": OptionInfo("inline", "UI position", gr.Radio, lambda: {"choices": ["cover", "inline", "sidebar"]}),
|
||||
"extra_networks_height": OptionInfo(47, "UI height (%)", gr.Slider, {"minimum": 10, "maximum": 100, "step": 1}),
|
||||
"extra_networks_sidebar_width": OptionInfo(35, "UI sidebar width (%)", gr.Slider, {"minimum": 10, "maximum": 80, "step": 1}),
|
||||
"extra_networks_card_lazy": OptionInfo(True, "UI card preview lazy loading"),
|
||||
"extra_networks_card_size": OptionInfo(200, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
|
||||
"extra_networks_card_square": OptionInfo(False, "UI disable variable aspect ratio"),
|
||||
"extra_networks_card_square": OptionInfo(True, "UI disable variable aspect ratio"),
|
||||
"extra_networks_card_fit": OptionInfo("cover", "UI image contain method", gr.Radio, lambda: {"choices": ["contain", "cover", "fill"]}),
|
||||
"extra_network_skip_indexing": OptionInfo(False, "Do not automatically build extra network pages", gr.Checkbox),
|
||||
"lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all Lora types", gr.Checkbox),
|
||||
"lora_disable": OptionInfo(False, "Disable built-in Lora handler", gr.Checkbox, { "visible": True }, onchange=lora_disable),
|
||||
"lora_disable": OptionInfo(False, "Disable built-in Lora handler", gr.Checkbox, { "visible": True }, onchange=disable_extensions),
|
||||
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox),
|
||||
"extra_networks_add_text_separator": OptionInfo(" ", "Extra text to add before <...> when adding extra network to prompt", gr.Text, { "visible": False }),
|
||||
"extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
@@ -682,13 +752,6 @@ opts = Options()
|
||||
config_filename = cmd_opts.config
|
||||
opts.load(config_filename)
|
||||
cmd_opts = cmd_args.compatibility_args(opts, cmd_opts)
|
||||
if cmd_opts.backend == 'diffusers':
|
||||
log.info('Overriding backend to Diffusers')
|
||||
opts.data['sd_backend'] = 'Diffusers'
|
||||
if cmd_opts.backend == 'original':
|
||||
log.info('Overriding backend to Diffusers')
|
||||
opts.data['sd_backend'] = 'Original'
|
||||
backend = Backend.DIFFUSERS if opts.sd_backend == 'Diffusers' else Backend.ORIGINAL
|
||||
|
||||
prompt_styles = modules.styles.StyleDatabase(opts.styles_dir)
|
||||
cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or (cmd_opts.server_name or False)) and not cmd_opts.insecure
|
||||
@@ -860,7 +923,6 @@ class Shared(sys.modules[__name__].__class__):
|
||||
@property
|
||||
def sd_model(self):
|
||||
import modules.sd_models # pylint: disable=W0621
|
||||
# return modules.sd_models.model_data.sd_model
|
||||
return modules.sd_models.model_data.get_sd_model()
|
||||
|
||||
@sd_model.setter
|
||||
@@ -868,6 +930,17 @@ class Shared(sys.modules[__name__].__class__):
|
||||
import modules.sd_models # pylint: disable=W0621
|
||||
modules.sd_models.model_data.set_sd_model(value)
|
||||
|
||||
# sd_model: LatentDiffusion = None # this var is here just for IDE's type checking; it cannot be accessed because the class field above will be accessed instead
|
||||
@property
|
||||
def sd_refiner(self):
|
||||
import modules.sd_models # pylint: disable=W0621
|
||||
return modules.sd_models.model_data.get_sd_refiner()
|
||||
|
||||
@sd_refiner.setter
|
||||
def sd_refiner(self, value):
|
||||
import modules.sd_models # pylint: disable=W0621
|
||||
modules.sd_models.model_data.set_sd_refiner(value)
|
||||
|
||||
|
||||
sd_model = None
|
||||
sd_refiner = None
|
||||
sys.modules[__name__].__class__ = Shared
|
||||
|
||||
@@ -42,7 +42,7 @@ def lcg(m=2**32, a=1664525, c=1013904223, seed=0):
|
||||
|
||||
def xor_block(block):
|
||||
g = lcg()
|
||||
randblock = np.array([next(g) for _ in range(np.product(block.shape))]).astype(np.uint8).reshape(block.shape)
|
||||
randblock = np.array([next(g) for _ in range(np.prod(block.shape))]).astype(np.uint8).reshape(block.shape)
|
||||
return np.bitwise_xor(block.astype(np.uint8), randblock & 0x0F)
|
||||
|
||||
|
||||
|
||||
@@ -113,33 +113,56 @@ class EmbeddingDatabase:
|
||||
|
||||
def register_embedding(self, embedding, model):
|
||||
self.word_embeddings[embedding.name] = embedding
|
||||
|
||||
ids = model.cond_stage_model.tokenize([embedding.name])[0]
|
||||
|
||||
first_id = ids[0]
|
||||
if first_id not in self.ids_lookup:
|
||||
self.ids_lookup[first_id] = []
|
||||
|
||||
self.ids_lookup[first_id] = sorted(self.ids_lookup[first_id] + [(ids, embedding)], key=lambda x: len(x[0]), reverse=True)
|
||||
|
||||
return embedding
|
||||
|
||||
def get_expected_shape(self):
|
||||
if shared.sd_model is None:
|
||||
shared.log.error('Model not loaded')
|
||||
return 0
|
||||
if shared.backend == shared.Backend.DIFFUSERS:
|
||||
return 0
|
||||
vec = shared.sd_model.cond_stage_model.encode_embedding_init_text(",", 1)
|
||||
return vec.shape[1]
|
||||
|
||||
def load_diffusers_embedding(self, filename: str, path: str):
|
||||
fn, ext = os.path.splitext(filename)
|
||||
if ext.lower() != ".pt" and ext.lower() != ".safetensors":
|
||||
return
|
||||
pipe = shared.sd_model
|
||||
if filename == "":
|
||||
pipe.tokenizer = pipe.tokenizer.__class__.from_pretrained(pipe.tokenizer.name_or_path)
|
||||
pipe.text_encoder.resize_token_embeddings(len(pipe.tokenizer))
|
||||
return
|
||||
name = os.path.basename(fn)
|
||||
embedding = Embedding(vec=None, name=name)
|
||||
try:
|
||||
pipe.load_textual_inversion(path, cache_dir=shared.opts.data["diffusers_dir"], local_files_only=True)
|
||||
self.word_embeddings[name] = embedding
|
||||
except Exception:
|
||||
self.skipped_embeddings[name] = embedding
|
||||
try:
|
||||
text_inv_tokens = pipe.tokenizer.added_tokens_encoder.keys()
|
||||
text_inv_tokens = [t for t in text_inv_tokens if not (len(t.split("_")) > 1 and t.split("_")[-1].isdigit())]
|
||||
except Exception:
|
||||
text_inv_tokens = []
|
||||
pass
|
||||
|
||||
def load_from_file(self, path, filename):
|
||||
name, ext = os.path.splitext(filename)
|
||||
ext = ext.upper()
|
||||
if shared.backend == shared.Backend.DIFFUSERS:
|
||||
self.load_diffusers_embedding(filename, path)
|
||||
return
|
||||
|
||||
if ext in ['.PNG', '.WEBP', '.JXL', '.AVIF']:
|
||||
_, second_ext = os.path.splitext(name)
|
||||
if second_ext.upper() == '.PREVIEW':
|
||||
return
|
||||
|
||||
embed_image = Image.open(path)
|
||||
if hasattr(embed_image, 'text') and 'sd-ti-embedding' in embed_image.text:
|
||||
data = embedding_from_b64(embed_image.text['sd-ti-embedding'])
|
||||
@@ -206,15 +229,12 @@ class EmbeddingDatabase:
|
||||
continue
|
||||
|
||||
def load_textual_inversion_embeddings(self, force_reload=False):
|
||||
if shared.backend == shared.Backend.DIFFUSERS: # TODO Diffusers
|
||||
return
|
||||
if not force_reload:
|
||||
need_reload = False
|
||||
for embdir in self.embedding_dirs.values():
|
||||
if embdir.has_changed():
|
||||
need_reload = True
|
||||
break
|
||||
|
||||
if not need_reload:
|
||||
return
|
||||
|
||||
@@ -241,32 +261,25 @@ class EmbeddingDatabase:
|
||||
def find_embedding_at_position(self, tokens, offset):
|
||||
token = tokens[offset]
|
||||
possible_matches = self.ids_lookup.get(token, None)
|
||||
|
||||
if possible_matches is None:
|
||||
return None, None
|
||||
|
||||
for ids, embedding in possible_matches:
|
||||
if tokens[offset:offset + len(ids)] == ids:
|
||||
return embedding, len(ids)
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
def create_embedding(name, num_vectors_per_token, overwrite_old, init_text='*'):
|
||||
cond_model = shared.sd_model.cond_stage_model
|
||||
|
||||
with devices.autocast():
|
||||
cond_model([""]) # will send cond model to GPU if lowvram/medvram is active
|
||||
|
||||
#cond_model expects at least some text, so we provide '*' as backup.
|
||||
embedded = cond_model.encode_embedding_init_text(init_text or '*', num_vectors_per_token)
|
||||
vec = torch.zeros((num_vectors_per_token, embedded.shape[1]), device=devices.device)
|
||||
|
||||
#Only copy if we provided an init_text, otherwise keep vectors as zeros
|
||||
if init_text:
|
||||
for i in range(num_vectors_per_token):
|
||||
vec[i] = embedded[i * int(embedded.shape[0]) // num_vectors_per_token]
|
||||
|
||||
# Remove illegal characters from name.
|
||||
name = "".join( x for x in name if (x.isalnum() or x in "._- "))
|
||||
fn = os.path.join(shared.opts.embeddings_dir, f"{name}.pt")
|
||||
@@ -299,29 +312,33 @@ def write_loss(log_directory, filename, step, epoch_len, values):
|
||||
**values,
|
||||
})
|
||||
|
||||
|
||||
def tensorboard_setup(log_directory):
|
||||
os.makedirs(os.path.join(log_directory, "tensorboard"), exist_ok=True)
|
||||
return SummaryWriter(
|
||||
log_dir=os.path.join(log_directory, "tensorboard"),
|
||||
flush_secs=shared.opts.training_tensorboard_flush_every)
|
||||
|
||||
|
||||
def tensorboard_add(tensorboard_writer, loss, global_step, step, learn_rate, epoch_num):
|
||||
tensorboard_add_scaler(tensorboard_writer, "Loss/train", loss, global_step)
|
||||
tensorboard_add_scaler(tensorboard_writer, f"Loss/train/epoch-{epoch_num}", loss, step)
|
||||
tensorboard_add_scaler(tensorboard_writer, "Learn rate/train", learn_rate, global_step)
|
||||
tensorboard_add_scaler(tensorboard_writer, f"Learn rate/train/epoch-{epoch_num}", learn_rate, step)
|
||||
|
||||
|
||||
def tensorboard_add_scaler(tensorboard_writer, tag, value, step):
|
||||
tensorboard_writer.add_scalar(tag=tag, scalar_value=value, global_step=step)
|
||||
|
||||
|
||||
def tensorboard_add_image(tensorboard_writer, tag, pil_image, step):
|
||||
# Convert a pil image to a torch tensor
|
||||
img_tensor = torch.as_tensor(np.array(pil_image, copy=True))
|
||||
img_tensor = img_tensor.view(pil_image.size[1], pil_image.size[0], len(pil_image.getbands()))
|
||||
img_tensor = img_tensor.permute((2, 0, 1))
|
||||
|
||||
tensorboard_writer.add_image(tag, img_tensor, global_step=step)
|
||||
|
||||
|
||||
def validate_train_inputs(model_name, learn_rate, batch_size, gradient_step, data_root, template_file, template_filename, steps, save_model_every, create_image_every, log_directory, name="embedding"):
|
||||
assert model_name, f"{name} not selected"
|
||||
assert learn_rate, "Learning rate is empty or 0"
|
||||
@@ -383,15 +400,12 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
images_embeds_dir = None
|
||||
|
||||
hijack = sd_hijack.model_hijack
|
||||
|
||||
embedding = hijack.embedding_db.word_embeddings[embedding_name]
|
||||
checkpoint = sd_models.select_checkpoint()
|
||||
|
||||
initial_step = embedding.step or 0
|
||||
if initial_step >= steps:
|
||||
shared.state.textinfo = "Model has already been trained beyond specified max steps"
|
||||
return embedding, filename
|
||||
|
||||
scheduler = LearnRateScheduler(learn_rate, steps, initial_step)
|
||||
clip_grad = torch.nn.utils.clip_grad_value_ if clip_grad_mode == "value" else \
|
||||
torch.nn.utils.clip_grad_norm_ if clip_grad_mode == "norm" else \
|
||||
|
||||
+42
-21
@@ -13,7 +13,7 @@ from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_grad
|
||||
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, extra_networks, ui_common, ui_postprocessing, ui_loadsave, ui_train, ui_models
|
||||
from modules.ui_components import FormRow, FormColumn, FormGroup, ToolButton, FormHTML # pylint: disable=unused-import
|
||||
from modules.paths import script_path, data_path
|
||||
from modules.shared import opts, cmd_opts, backend, Backend
|
||||
from modules.shared import opts, cmd_opts
|
||||
from modules import prompt_parser
|
||||
import modules.codeformer_model
|
||||
import modules.generation_parameters_copypaste as parameters_copypaste
|
||||
@@ -198,13 +198,21 @@ def update_token_counter(text, steps):
|
||||
prompt_schedules = [[[steps, text]]]
|
||||
flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
|
||||
prompts = [prompt_text for step, prompt_text in flat_prompts]
|
||||
if backend == Backend.ORIGINAL:
|
||||
if modules.shared.backend == modules.shared.Backend.ORIGINAL:
|
||||
token_count, max_length = max([sd_hijack.model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
|
||||
else:
|
||||
tokenizer = modules.shared.sd_model.tokenizer
|
||||
has_bos_token, has_eos_token = tokenizer.bos_token_id is not None, tokenizer.eos_token_id is not None
|
||||
token_count = max([len(modules.shared.sd_model.tokenizer(prompt)) for prompt in prompts]) - int(has_bos_token) - int(has_eos_token)
|
||||
max_length = tokenizer.model_max_length - int(has_bos_token) - int(has_eos_token)
|
||||
elif modules.shared.backend == modules.shared.Backend.DIFFUSERS:
|
||||
if modules.shared.sd_model is not None:
|
||||
tokenizer = modules.shared.sd_model.tokenizer
|
||||
has_bos_token = tokenizer.bos_token_id is not None
|
||||
has_eos_token = tokenizer.eos_token_id is not None
|
||||
ids = [modules.shared.sd_model.tokenizer(prompt) for prompt in prompts]
|
||||
if len(ids) > 0 and hasattr(ids[0], 'input_ids'):
|
||||
ids = [x.input_ids for x in ids]
|
||||
token_count = max([len(x) for x in ids]) - int(has_bos_token) - int(has_eos_token)
|
||||
max_length = tokenizer.model_max_length - int(has_bos_token) - int(has_eos_token)
|
||||
else:
|
||||
token_count = 0
|
||||
max_length = 75
|
||||
return f"<span class='gr-box gr-text-input'>{token_count}/{max_length}</span>"
|
||||
|
||||
|
||||
@@ -321,7 +329,10 @@ def create_override_settings_dropdown(tabname, row): # pylint: disable=unused-ar
|
||||
return dropdown
|
||||
|
||||
|
||||
def create_ui():
|
||||
def create_ui(startup_timer = None):
|
||||
if startup_timer is None:
|
||||
from modules import timer
|
||||
startup_timer = timer.Timer()
|
||||
import modules.img2img # pylint: disable=redefined-outer-name
|
||||
import modules.txt2img # pylint: disable=redefined-outer-name
|
||||
reload_javascript()
|
||||
@@ -334,7 +345,7 @@ def create_ui():
|
||||
txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False)
|
||||
with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks_ui:
|
||||
from modules import ui_extra_networks
|
||||
extra_networks_ui = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'txt2img')
|
||||
extra_networks_ui = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'txt2img', skip_indexing=opts.extra_network_skip_indexing)
|
||||
with gr.Row().style(equal_height=False, elem_id="txt2img_interface"):
|
||||
with gr.Column(variant='compact', elem_id="txt2img_settings"):
|
||||
for category in ordered_ui_categories():
|
||||
@@ -492,9 +503,10 @@ def create_ui():
|
||||
|
||||
ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery)
|
||||
|
||||
startup_timer.record("ui-txt2img")
|
||||
|
||||
modules.scripts.scripts_current = modules.scripts.scripts_img2img
|
||||
modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True)
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as img2img_interface:
|
||||
img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=True)
|
||||
|
||||
@@ -502,7 +514,7 @@ def create_ui():
|
||||
|
||||
with FormRow(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks_ui:
|
||||
from modules import ui_extra_networks
|
||||
extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'img2img')
|
||||
extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'img2img', skip_indexing=opts.extra_network_skip_indexing)
|
||||
|
||||
with FormRow().style(equal_height=False, elem_id="img2img_interface"):
|
||||
with gr.Column(variant='compact', elem_id="img2img_settings"):
|
||||
@@ -849,16 +861,21 @@ def create_ui():
|
||||
paste_button=img2img_paste, tabname="img2img", source_text_component=img2img_prompt, source_image_component=None,
|
||||
))
|
||||
|
||||
startup_timer.record("ui-img2img")
|
||||
|
||||
modules.scripts.scripts_current = None
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as extras_interface:
|
||||
ui_postprocessing.create_ui()
|
||||
startup_timer.record("ui-extras")
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as train_interface:
|
||||
ui_train.create_ui(txt2img_preview_params = [txt2img_prompt, txt2img_negative_prompt, steps, sampler_index, cfg_scale, seed, width, height])
|
||||
startup_timer.record("ui-train")
|
||||
|
||||
with gr.Blocks(analytics_enabled=False) as models_interface:
|
||||
ui_models.create_ui()
|
||||
startup_timer.record("ui-models")
|
||||
|
||||
def create_setting_component(key, is_quicksettings=False):
|
||||
def fun():
|
||||
@@ -897,9 +914,13 @@ def create_ui():
|
||||
res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
|
||||
create_refresh_button(res, info.refresh, info.component_args, f"refresh_{key}")
|
||||
else:
|
||||
res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
|
||||
try:
|
||||
res = comp(label=info.label, value=fun(), elem_id=elem_id, **(args or {}))
|
||||
except Exception as e:
|
||||
modules.shared.log.error(f'Error creating setting: {key} {e}')
|
||||
res = None
|
||||
|
||||
if not is_quicksettings:
|
||||
if res is not None and not is_quicksettings:
|
||||
res.change(fn=None, inputs=res, _js=f'(val) => markIfModified("{key}", val)')
|
||||
dirty_indicator.click(fn=lambda: getattr(opts, key), outputs=res, show_progress=False)
|
||||
dirtyable_setting.__exit__()
|
||||
@@ -971,6 +992,7 @@ def create_ui():
|
||||
quicksettings_names = opts.quicksettings_list
|
||||
quicksettings_names = {x: i for i, x in enumerate(quicksettings_names) if x != 'quicksettings'}
|
||||
quicksettings_list = []
|
||||
|
||||
previous_section = []
|
||||
tab_item_keys = []
|
||||
current_tab = None
|
||||
@@ -1017,7 +1039,8 @@ def create_ui():
|
||||
create_dirty_indicator("show_all_pages", [], interactive=False)
|
||||
|
||||
def unload_sd_weights():
|
||||
modules.sd_models.unload_model_weights()
|
||||
modules.sd_models.unload_model_weights(op='model')
|
||||
modules.sd_models.unload_model_weights(op='refiner')
|
||||
|
||||
def reload_sd_weights():
|
||||
modules.sd_models.reload_model_weights()
|
||||
@@ -1048,6 +1071,7 @@ def create_ui():
|
||||
outputs=[dummy_component]
|
||||
)
|
||||
|
||||
startup_timer.record("ui-settings")
|
||||
|
||||
interfaces = [
|
||||
(txt2img_interface, "From Text", "txt2img"),
|
||||
@@ -1060,6 +1084,7 @@ def create_ui():
|
||||
interfaces += [(settings_interface, "Settings", "settings")]
|
||||
extensions_interface = ui_extensions.create_ui()
|
||||
interfaces += [(extensions_interface, "Extensions", "extensions")]
|
||||
startup_timer.record("ui-extensions")
|
||||
|
||||
modules.shared.tab_names = []
|
||||
for _interface, label, _ifid in interfaces:
|
||||
@@ -1135,6 +1160,8 @@ def create_ui():
|
||||
queue=False,
|
||||
)
|
||||
|
||||
startup_timer.record("ui-defaults")
|
||||
|
||||
loadsave.dump_defaults()
|
||||
demo.ui_loadsave = loadsave
|
||||
|
||||
@@ -1146,7 +1173,6 @@ def webpath(fn):
|
||||
web_path = os.path.relpath(fn, script_path).replace('\\', '/')
|
||||
else:
|
||||
web_path = os.path.abspath(fn)
|
||||
|
||||
return f'file={web_path}?{os.path.getmtime(fn)}'
|
||||
|
||||
|
||||
@@ -1171,12 +1197,7 @@ def html_body():
|
||||
body = ''
|
||||
inline = ''
|
||||
if opts.theme_style != 'Auto':
|
||||
if opts.gradio_theme == 'black-orange':
|
||||
modules.shared.log.info('Theme does not support custom mode')
|
||||
else:
|
||||
inline += f"set_theme('{opts.theme_style.lower()}');"
|
||||
if opts.gradio_theme == 'black-orange':
|
||||
inline += "set_theme('dark');"
|
||||
inline += f"set_theme('{opts.theme_style.lower()}');"
|
||||
body += f'<script type="text/javascript">{inline}</script>\n'
|
||||
return body
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ sort_ordering = {
|
||||
"default": (True, lambda x: x.get('sort_default', '')),
|
||||
"user extensions": (True, lambda x: x.get('sort_user', '')),
|
||||
"trending": (True, lambda x: x.get('sort_trending', -1)),
|
||||
"update avilable": (True, lambda x: x.get('sort_update', '')),
|
||||
"update available": (True, lambda x: x.get('sort_update', '')),
|
||||
"updated date": (True, lambda x: x.get('updated', '2000-01-01T00:00')),
|
||||
"created date": (True, lambda x: x.get('created', '2000-01-01T00:00')),
|
||||
"name": (False, lambda x: x.get('name', '').lower()),
|
||||
|
||||
@@ -66,6 +66,7 @@ class ExtraNetworksPage:
|
||||
self.allow_negative_prompt = False
|
||||
self.metadata = {}
|
||||
self.info = {}
|
||||
self.html = ''
|
||||
self.items = []
|
||||
self.missing_thumbs = []
|
||||
self.card = '''
|
||||
@@ -82,7 +83,7 @@ class ExtraNetworksPage:
|
||||
<span title="Read info" onclick={card_read_info}>ℹ️</span>
|
||||
</div>
|
||||
</div>
|
||||
<img class='preview' src='{preview}' style='width: {width}px; height: {height}px; object-fit: {fit}' loading='lazy'></img>
|
||||
<img class='preview' src='{preview}' style='width: {width}px; height: {height}px; object-fit: {fit}' loading='{loading}'></img>
|
||||
</div>
|
||||
''' # noqa: RUF001
|
||||
|
||||
@@ -133,25 +134,32 @@ class ExtraNetworksPage:
|
||||
fn = f'{fn}.thumb.jpg'
|
||||
if os.path.exists(fn):
|
||||
continue
|
||||
created += 1
|
||||
img = Image.open(f)
|
||||
img = img.convert('RGB')
|
||||
img.thumbnail((512, 512), Image.HAMMING)
|
||||
img.save(fn)
|
||||
img.close()
|
||||
try:
|
||||
img = Image.open(f)
|
||||
img = img.convert('RGB')
|
||||
img.thumbnail((512, 512), Image.HAMMING)
|
||||
img.save(fn)
|
||||
img.close()
|
||||
created += 1
|
||||
except Exception as e:
|
||||
shared.log.error(f'Extra network error creating thumbnail: {f} {e}')
|
||||
if len(self.missing_thumbs) > 0:
|
||||
shared.log.info(f"Extra network created thumbnails: {self.name} {created}")
|
||||
self.missing_thumbs.clear()
|
||||
|
||||
def create_html(self, tabname):
|
||||
items_html = ''
|
||||
def create_html(self, tabname, skip = False):
|
||||
self_name_id = self.name.replace(" ", "_")
|
||||
if skip:
|
||||
return f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'></div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>Extra network page not ready<br>Click refresh to try again</div>"
|
||||
subdirs = {}
|
||||
allowed_folders = [os.path.abspath(x) for x in self.allowed_directories_for_previews()]
|
||||
for parentdir in [*set(allowed_folders)]:
|
||||
for root, dirs, _files in os.walk(parentdir, followlinks=True):
|
||||
for dirname in dirs:
|
||||
x = os.path.join(root, dirname)
|
||||
if not os.path.isdir(x):
|
||||
if shared.opts.diffusers_dir in x:
|
||||
subdirs[os.path.basename(shared.opts.diffusers_dir)] = 1
|
||||
if (not os.path.isdir(x)) or ('models--' in x):
|
||||
continue
|
||||
subdir = os.path.abspath(x)[len(parentdir):].replace("\\", "/")
|
||||
while subdir.startswith("/"):
|
||||
@@ -166,28 +174,26 @@ class ExtraNetworksPage:
|
||||
{html.escape(subdir) if subdir!="" else "all"}
|
||||
</button><br>""" for subdir in subdirs])
|
||||
try:
|
||||
if len(self.html) > 0:
|
||||
res = 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>"
|
||||
return res
|
||||
self.html = ''
|
||||
self.items = list(self.list_items())
|
||||
self.create_xyz_grid()
|
||||
for item in self.items:
|
||||
self.metadata[item["name"]] = item.get("metadata", {})
|
||||
self.info[item["name"]] = self.find_info(item['filename'])
|
||||
items_html += self.create_html_for_item(item, tabname)
|
||||
# if items_html == '':
|
||||
# dirs = "".join([f"<li>{x}</li>" for x in self.allowed_directories_for_previews()])
|
||||
# items_html = f'<div class="nocards">No models found: {dirs}</div>'
|
||||
self_name_id = self.name.replace(" ", "_")
|
||||
if len(subdirs_html) > 0 or len(items_html) > 0:
|
||||
res = 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'>{items_html}</div>
|
||||
"""
|
||||
self.html += self.create_html_for_item(item, tabname)
|
||||
if len(subdirs_html) > 0 or len(self.html) > 0:
|
||||
res = 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>"
|
||||
else:
|
||||
return ''
|
||||
shared.log.debug(f'Extra networks: {self.name} items={len(self.items)} subdirs={len(subdirs)}')
|
||||
threading.Thread(target=self.create_thumb).start()
|
||||
return res
|
||||
except Exception as e:
|
||||
shared.log.error(f'Extra networks page error: {e}')
|
||||
return ''
|
||||
return f"<div id='{tabname}_{self_name_id}_subdirs' class='extra-network-subdirs'></div><div id='{tabname}_{self_name_id}_cards' class='extra-network-cards'>Extra network error<br>{e}</div>"
|
||||
|
||||
def list_items(self):
|
||||
raise NotImplementedError
|
||||
@@ -208,6 +214,7 @@ class ExtraNetworksPage:
|
||||
"name": item["name"],
|
||||
"description": (item.get("description") or ""),
|
||||
"search_term": item.get("search_term", ""),
|
||||
"loading": "lazy" if shared.opts.extra_networks_card_lazy else "eager",
|
||||
"card_click": item.get("onclick", '"' + html.escape(f"""return cardClicked({json.dumps(tabname)}, {item.get("prompt", None)}, {"true" if self.allow_negative_prompt else "false"})""") + '"'),
|
||||
"card_save_desc": '"' + html.escape(f"""return saveCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
"card_save_preview": '"' + html.escape(f"""return saveCardPreview(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
@@ -290,7 +297,7 @@ def sort_extra_pages(pages):
|
||||
return sorted(pages, key=lambda x: tab_scores[x.name])
|
||||
|
||||
|
||||
def create_ui(container, button, tabname):
|
||||
def create_ui(container, button, tabname, skip_indexing = False):
|
||||
ui = ExtraNetworksUi()
|
||||
ui.pages = []
|
||||
ui.stored_extra_pages = sort_extra_pages(extra_pages)
|
||||
@@ -308,7 +315,7 @@ def create_ui(container, button, tabname):
|
||||
ui.description_target_filename = gr.Textbox('Description save filename', elem_id=tabname+"_description_filename", visible=False)
|
||||
|
||||
for page in ui.stored_extra_pages:
|
||||
page_html = page.create_html(ui.tabname)
|
||||
page_html = page.create_html(ui.tabname, skip_indexing)
|
||||
if len(page_html) > 0:
|
||||
with gr.Tab(page.title, id=page.title.lower().replace(" ", "_"), elem_classes="extra-networks-tab"):
|
||||
page_elem = gr.HTML(page_html, elem_id=tabname+page.name+"_extra_page", elem_classes="extra-networks-page")
|
||||
@@ -326,6 +333,7 @@ def create_ui(container, button, tabname):
|
||||
def refresh():
|
||||
res = []
|
||||
for pg in ui.stored_extra_pages:
|
||||
pg.html = ''
|
||||
pg.refresh()
|
||||
res.append(pg.create_html(ui.tabname))
|
||||
ui.search.update(value = ui.search.value)
|
||||
|
||||
@@ -21,10 +21,10 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
|
||||
"filename": path,
|
||||
"preview": self.find_preview(path),
|
||||
"description": self.find_description(path),
|
||||
"search_term": self.search_terms_from_path(checkpoint.filename) + " " + (checkpoint.sha256 or ""),
|
||||
"search_term": f'{self.search_terms_from_path(checkpoint.filename)} {(checkpoint.sha256 or "")} /{checkpoint.type}/',
|
||||
"onclick": '"' + html.escape(f"""return selectCheckpoint({json.dumps(name)})""") + '"',
|
||||
"local_preview": f"{path}.{shared.opts.samples_format}",
|
||||
}
|
||||
|
||||
def allowed_directories_for_previews(self):
|
||||
return [v for v in [shared.opts.ckpt_dir, sd_models.model_path] if v is not None]
|
||||
return [v for v in [shared.opts.ckpt_dir, shared.opts.diffusers_dir, sd_models.model_path] if v is not None]
|
||||
|
||||
@@ -19,7 +19,7 @@ class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage):
|
||||
"preview": self.find_preview(path),
|
||||
"description": self.find_description(path),
|
||||
"search_term": self.search_terms_from_path(path),
|
||||
"prompt": json.dumps(f"<hypernet:{name}:") + " + opts.extra_networks_default_multiplier + " + json.dumps(">"),
|
||||
"prompt": json.dumps(f"<hypernet:{name}:") + " + shared.opts.extra_networks_default_multiplier + " + json.dumps(">"),
|
||||
"local_preview": f"{path}.preview.{shared.opts.samples_format}",
|
||||
}
|
||||
|
||||
|
||||
@@ -161,3 +161,63 @@ def create_ui():
|
||||
return model_data, txt
|
||||
|
||||
model_list_btn.click(fn=list_models, inputs=[], outputs=[model_table, models_outcome])
|
||||
|
||||
with gr.Tab(label="Huggingface"):
|
||||
data = []
|
||||
os.environ.setdefault('HF_HUB_DISABLE_EXPERIMENTAL_WARNING', '1')
|
||||
os.environ.setdefault('HF_HUB_DISABLE_SYMLINKS_WARNING', '1')
|
||||
os.environ.setdefault('HF_HUB_DISABLE_IMPLICIT_TOKEN', '1')
|
||||
os.environ.setdefault('HUGGINGFACE_HUB_VERBOSITY', 'warning')
|
||||
|
||||
def hf_search(keyword):
|
||||
import huggingface_hub as hf
|
||||
hf_api = hf.HfApi()
|
||||
model_filter = hf.ModelFilter(
|
||||
model_name=keyword,
|
||||
task='text-to-image',
|
||||
library=['diffusers'],
|
||||
)
|
||||
models = hf_api.list_models(filter=model_filter, full=True, limit=50, sort="downloads", direction=-1)
|
||||
data.clear()
|
||||
for model in models:
|
||||
tags = [t for t in model.tags if not t.startswith('diffusers') and not t.startswith('license') and not t.startswith('arxiv') and len(t) > 2]
|
||||
data.append([model.modelId, model.pipeline_tag, tags, model.downloads, model.lastModified, f'https://huggingface.co/{model.modelId}'])
|
||||
return data
|
||||
|
||||
def hf_select(evt: gr.SelectData, data):
|
||||
return data[evt.index[0]][0]
|
||||
|
||||
def hf_download_model(hub_id: str, token):
|
||||
from modules.shared import log, opts
|
||||
from modules.modelloader import download_diffusers_model
|
||||
try:
|
||||
download_diffusers_model(hub_id, cache_dir=opts.diffusers_dir, token=token)
|
||||
except Exception as e:
|
||||
log.error(f"Diffuser model downloaded error: model={hub_id} {e}")
|
||||
return f"Diffuser model downloaded error: model={hub_id} {e}"
|
||||
from modules.sd_models import list_models # pylint: disable=W0621
|
||||
list_models()
|
||||
log.info(f"Diffuser model downloaded: model={hub_id}")
|
||||
return f'Diffuser model downloaded: model={hub_id}'
|
||||
|
||||
with gr.Column(scale=6):
|
||||
with gr.Row():
|
||||
hf_search_text = gr.Textbox('', label = 'Seach models', placeholder='search huggingface models')
|
||||
with gr.Row():
|
||||
hf_selected = gr.Textbox('', label = 'Select model', placeholder='select model from search results or enter model name manually')
|
||||
with gr.Row():
|
||||
hf_token = gr.Textbox('', label = 'Huggingface token', placeholder='optional access token for private or gated models')
|
||||
with gr.Column(scale=1):
|
||||
hf_download_model_btn = gr.Button(value="Download model", variant='primary')
|
||||
|
||||
with gr.Row():
|
||||
hf_headers = ['Name', 'Pipeline', 'Tags', 'Downloads', 'Updated', 'URL']
|
||||
hf_types = ['str', 'str', 'str', 'number', 'date', 'markdown']
|
||||
hf_results = gr.DataFrame([], label = 'Search results', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = hf_headers, datatype = hf_types, type='array')
|
||||
|
||||
hf_search_text.submit(fn=hf_search, inputs=[hf_search_text], outputs=[hf_results])
|
||||
hf_results.select(fn=hf_select, inputs=[hf_results], outputs=[hf_selected])
|
||||
hf_download_model_btn.click(fn=hf_download_model, inputs=[hf_selected, hf_token], outputs=[models_outcome])
|
||||
|
||||
# with gr.Tab(label="CivitAI"):
|
||||
# pass
|
||||
|
||||
@@ -9,18 +9,16 @@ from modules.ui_common import infotext_to_html
|
||||
|
||||
def wrap_pnginfo(image):
|
||||
_, geninfo, info = run_pnginfo(image)
|
||||
return '', infotext_to_html(geninfo), info, geninfo
|
||||
return infotext_to_html(geninfo), info, geninfo
|
||||
|
||||
|
||||
def submit_click(tab_index, extras_image, image_batch, extras_batch_input_dir, extras_batch_output_dir, show_extras_results, *script_inputs):
|
||||
|
||||
result_images, geninfo, js_info = postprocessing.run_postprocessing(tab_index, extras_image, image_batch, extras_batch_input_dir, extras_batch_output_dir, show_extras_results, *script_inputs)
|
||||
return result_images, geninfo, json.dumps(js_info), ''
|
||||
|
||||
|
||||
def create_ui():
|
||||
tab_index = gr.State(value=0) # pylint: disable=abstract-class-instantiated
|
||||
|
||||
with gr.Row().style(equal_height=False, variant='compact'):
|
||||
with gr.Column(variant='compact'):
|
||||
with gr.Tabs(elem_id="mode_extras"):
|
||||
@@ -53,11 +51,10 @@ def create_ui():
|
||||
tab_single.select(fn=lambda: 0, inputs=[], outputs=[tab_index])
|
||||
tab_batch.select(fn=lambda: 1, inputs=[], outputs=[tab_index])
|
||||
tab_batch_dir.select(fn=lambda: 2, inputs=[], outputs=[tab_index])
|
||||
_dummy = gr.HTML(visible=False)
|
||||
extras_image.change(
|
||||
fn=wrap_gradio_call(wrap_pnginfo),
|
||||
inputs=[extras_image],
|
||||
outputs=[_dummy, html_info_formatted, exif_info, gen_info],
|
||||
outputs=[html_info_formatted, exif_info, gen_info],
|
||||
)
|
||||
submit.click(
|
||||
_js="submit_postprocessing",
|
||||
|
||||
+7
-6
@@ -26,7 +26,6 @@ omegaconf
|
||||
open-clip-torch
|
||||
opencv-contrib-python
|
||||
piexif
|
||||
Pillow
|
||||
psutil
|
||||
pyyaml
|
||||
realesrgan
|
||||
@@ -43,13 +42,14 @@ yapf
|
||||
scikit-image
|
||||
basicsr
|
||||
compel
|
||||
typing-extensions==4.6.3
|
||||
pydantic==1.10.9
|
||||
typing-extensions==4.7.1
|
||||
antlr4-python3-runtime==4.9.3
|
||||
pydantic==1.10.11
|
||||
requests==2.31.0
|
||||
tqdm==4.65.0
|
||||
accelerate==0.20.3
|
||||
opencv-python==4.7.0.72
|
||||
diffusers==0.17.1
|
||||
diffusers==0.18.1
|
||||
einops==0.4.1
|
||||
gradio==3.32.0
|
||||
numexpr==2.8.4
|
||||
@@ -58,7 +58,8 @@ numba==0.57.0
|
||||
pandas==1.5.3
|
||||
protobuf==3.20.3
|
||||
pytorch_lightning==1.9.4
|
||||
transformers==4.26.1
|
||||
timm==0.6.13
|
||||
transformers==4.30.2
|
||||
tomesd==0.1.3
|
||||
urllib3==1.26.15
|
||||
Pillow==9.5.0
|
||||
timm==0.6.13
|
||||
|
||||
@@ -99,7 +99,7 @@ def get_matched_noise(_np_src_image, np_mask_rgb, noise_q=1, color_variation=0.0
|
||||
shaped_noise_fft = _fft2(noise_rgb)
|
||||
shaped_noise_fft[:, :, :] = np.absolute(shaped_noise_fft[:, :, :]) ** 2 * (src_dist ** noise_q) * src_phase # perform the actual shaping
|
||||
|
||||
brightness_variation = 0. # color_variation # todo: temporarily tieing brightness variation to color variation for now
|
||||
brightness_variation = 0. # color_variation
|
||||
contrast_adjusted_np_src = _np_src_image[:] * (brightness_variation + 1.) - brightness_variation * 2.
|
||||
|
||||
# scikit-image is used for histogram matching, very convenient!
|
||||
|
||||
+3
-3
@@ -410,9 +410,9 @@ class Script(scripts.Script):
|
||||
with gr.Row(variant="compact", elem_id="axis_options"):
|
||||
margin_size = gr.Slider(label="Grid margins", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
|
||||
with gr.Row(variant="compact", elem_id="swap_axes"):
|
||||
swap_xy_axes_button = gr.Button(value="Swap X/Y axes", elem_id="xy_grid_swap_axes_button")
|
||||
swap_yz_axes_button = gr.Button(value="Swap Y/Z axes", elem_id="yz_grid_swap_axes_button")
|
||||
swap_xz_axes_button = gr.Button(value="Swap X/Z axes", elem_id="xz_grid_swap_axes_button")
|
||||
swap_xy_axes_button = gr.Button(value="Swap X/Y", elem_id="xy_grid_swap_axes_button", variant="secondary")
|
||||
swap_yz_axes_button = gr.Button(value="Swap Y/Z", elem_id="yz_grid_swap_axes_button", variant="secondary")
|
||||
swap_xz_axes_button = gr.Button(value="Swap X/Z", elem_id="xz_grid_swap_axes_button", variant="secondary")
|
||||
|
||||
def swap_axes(axis1_type, axis1_values, axis1_values_dropdown, axis2_type, axis2_values, axis2_values_dropdown):
|
||||
return self.current_axis_options[axis2_type].label, axis2_values, axis2_values_dropdown, self.current_axis_options[axis1_type].label, axis1_values, axis1_values_dropdown
|
||||
|
||||
@@ -101,6 +101,7 @@ def check_rollback_vae():
|
||||
|
||||
def initialize():
|
||||
log.debug('Entering initialize')
|
||||
shared.disable_extensions()
|
||||
check_rollback_vae()
|
||||
|
||||
modules.sd_vae.refresh_vae_list()
|
||||
@@ -167,14 +168,18 @@ def load_model():
|
||||
if opts.sd_checkpoint_autoload:
|
||||
shared.state.begin()
|
||||
shared.state.job = 'load model'
|
||||
thread = Thread(target=lambda: shared.sd_model)
|
||||
thread.start()
|
||||
thread_model = Thread(target=lambda: shared.sd_model)
|
||||
thread_model.start()
|
||||
thread_refiner = Thread(target=lambda: shared.sd_refiner)
|
||||
thread_refiner.start()
|
||||
shared.state.end()
|
||||
thread.join()
|
||||
thread_model.join()
|
||||
thread_refiner.join()
|
||||
else:
|
||||
log.debug('Model auto load disabled')
|
||||
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()), call=False)
|
||||
shared.opts.onchange("sd_model_dict", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()), call=False)
|
||||
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(op='model')), call=False)
|
||||
shared.opts.onchange("sd_model_refiner", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(op='refiner')), call=False)
|
||||
shared.opts.onchange("sd_model_dict", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(op='dict')), call=False)
|
||||
startup_timer.record("checkpoint")
|
||||
|
||||
|
||||
@@ -229,7 +234,7 @@ def start_ui():
|
||||
log.debug('Creating UI')
|
||||
modules.script_callbacks.before_ui_callback()
|
||||
startup_timer.record("before-ui")
|
||||
shared.demo = modules.ui.create_ui()
|
||||
shared.demo = modules.ui.create_ui(startup_timer)
|
||||
startup_timer.record("ui")
|
||||
if cmd_opts.disable_queue:
|
||||
log.info('Server queues disabled')
|
||||
|
||||
+1
-1
Submodule wiki updated: f941746c0e...e5da783bef
Reference in New Issue
Block a user