From 9e737cbadcdc89c23b119701815275e7c209ff00 Mon Sep 17 00:00:00 2001 From: Alexandre Simard Date: Mon, 26 Sep 2022 17:18:57 -0400 Subject: [PATCH 001/460] Solve issue #962 Fix by @MrAcademy --- .gitignore | 3 ++- javascript/ui.js | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 9d78853af..fa1ab43e7 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ __pycache__ /webui-user.sh /interrogate /user.css -/.idea \ No newline at end of file +/.idea +/SwinIR diff --git a/javascript/ui.js b/javascript/ui.js index 076e9436c..7db4db48d 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -1,9 +1,8 @@ // various functions for interation with ui.py not large enough to warrant putting them in separate files function selected_gallery_index(){ - var gr = gradioApp() - var buttons = gradioApp().querySelectorAll(".gallery-item") - var button = gr.querySelector(".gallery-item.\\!ring-2") + var buttons = gradioApp().querySelectorAll('[style="display: block;"].tabitem .gallery-item') + var button = gradioApp().querySelector('[style="display: block;"].tabitem .gallery-item.\\!ring-2') var result = -1 buttons.forEach(function(v, i){ if(v==button) { result = i } }) From 03ee67bfd34b9e872b33eb05fef5db83410b16f3 Mon Sep 17 00:00:00 2001 From: WDevelopsWebApps <97454358+WDevelopsWebApps@users.noreply.github.com> Date: Wed, 28 Sep 2022 10:53:40 +0200 Subject: [PATCH 002/460] add advanced saving for save button --- modules/images.py | 5 ++++- modules/ui.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/modules/images.py b/modules/images.py index 9458bf8d4..923f81dfb 100644 --- a/modules/images.py +++ b/modules/images.py @@ -290,7 +290,10 @@ def apply_filename_pattern(x, p, seed, prompt): x = x.replace("[cfg]", str(p.cfg_scale)) x = x.replace("[width]", str(p.width)) x = x.replace("[height]", str(p.height)) - x = x.replace("[styles]", sanitize_filename_part(", ".join(p.styles), replace_spaces=False)) + #currently disabled if using the save button, will work otherwise + # if enabled it will cause a bug because styles is not included in the save_files data dictionary + if hasattr(p, "styles"): + x = x.replace("[styles]", sanitize_filename_part(", ".join(p.styles), replace_spaces=False)) x = x.replace("[sampler]", sanitize_filename_part(sd_samplers.samplers[p.sampler_index].name, replace_spaces=False)) x = x.replace("[model_hash]", shared.sd_model.sd_model_hash) diff --git a/modules/ui.py b/modules/ui.py index 7db8edbd8..87a86a45d 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -28,6 +28,7 @@ import modules.gfpgan_model import modules.codeformer_model import modules.styles import modules.generation_parameters_copypaste +from modules.images import apply_filename_pattern, get_next_sequence_number # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI mimetypes.init() @@ -90,13 +91,26 @@ def send_gradio_gallery_to_image(x): def save_files(js_data, images, index): - import csv - - os.makedirs(opts.outdir_save, exist_ok=True) - + import csv filenames = [] + #quick dictionary to class object conversion. Its neccesary due apply_filename_pattern requiring it + class MyObject: + def __init__(self, d=None): + if d is not None: + for key, value in d.items(): + setattr(self, key, value) + data = json.loads(js_data) + p = MyObject(data) + path = opts.outdir_save + save_to_dirs = opts.save_to_dirs + + if save_to_dirs: + dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, p.seed, p.prompt) + path = os.path.join(opts.outdir_save, dirname) + + os.makedirs(path, exist_ok=True) if index > -1 and opts.save_selected_only and (index > 0 or not opts.return_grid): # ensures we are looking at a specific non-grid picture, and we have save_selected_only images = [images[index]] @@ -107,11 +121,18 @@ def save_files(js_data, images, index): writer = csv.writer(file) if at_start: writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"]) + file_decoration = opts.samples_filename_pattern or "[seed]-[prompt_spaces]" + if file_decoration != "": + file_decoration = "-" + file_decoration.lower() + file_decoration = apply_filename_pattern(file_decoration, p, p.seed, p.prompt) + truncated = (file_decoration[:240] + '..') if len(file_decoration) > 240 else file_decoration + filename_base = truncated - filename_base = str(int(time.time() * 1000)) + basecount = get_next_sequence_number(path, "") for i, filedata in enumerate(images): - filename = filename_base + ("" if len(images) == 1 else "-" + str(i + 1)) + ".png" - filepath = os.path.join(opts.outdir_save, filename) + file_number = f"{basecount+i:05}" + filename = file_number + filename_base + ".png" + filepath = os.path.join(path, filename) if filedata.startswith("data:image/png;base64,"): filedata = filedata[len("data:image/png;base64,"):] From c938679de7b87b4f14894d9f57fe0f40dd6e3c06 Mon Sep 17 00:00:00 2001 From: Jairo Correa Date: Wed, 28 Sep 2022 22:14:13 -0300 Subject: [PATCH 003/460] Fix memory leak and reduce memory usage --- modules/codeformer_model.py | 6 ++++-- modules/devices.py | 3 ++- modules/extras.py | 2 ++ modules/gfpgan_model.py | 11 +++++------ modules/processing.py | 33 ++++++++++++++++++++++++++------- webui.py | 3 +++ 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/modules/codeformer_model.py b/modules/codeformer_model.py index 8fbdea249..2177291a7 100644 --- a/modules/codeformer_model.py +++ b/modules/codeformer_model.py @@ -89,7 +89,7 @@ def setup_codeformer(): output = self.net(cropped_face_t, w=w if w is not None else shared.opts.code_former_weight, adain=True)[0] restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1)) del output - torch.cuda.empty_cache() + devices.torch_gc() except Exception as error: print(f'\tFailed inference for CodeFormer: {error}', file=sys.stderr) restored_face = tensor2img(cropped_face_t, rgb2bgr=True, min_max=(-1, 1)) @@ -106,7 +106,9 @@ def setup_codeformer(): restored_img = cv2.resize(restored_img, (0, 0), fx=original_resolution[1]/restored_img.shape[1], fy=original_resolution[0]/restored_img.shape[0], interpolation=cv2.INTER_LINEAR) if shared.opts.face_restoration_unload: - self.net.to(devices.cpu) + self.net = None + self.face_helper = None + devices.torch_gc() return restored_img diff --git a/modules/devices.py b/modules/devices.py index 07bb23397..df63dd88e 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -1,4 +1,5 @@ import torch +import gc # has_mps is only available in nightly pytorch (for now), `getattr` for compatibility from modules import errors @@ -17,8 +18,8 @@ def get_optimal_device(): return cpu - def torch_gc(): + gc.collect() if torch.cuda.is_available(): torch.cuda.empty_cache() torch.cuda.ipc_collect() diff --git a/modules/extras.py b/modules/extras.py index 9a825530f..38b861675 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -98,6 +98,8 @@ def run_extras(extras_mode, image, image_folder, gfpgan_visibility, codeformer_v outputs.append(image) + devices.torch_gc() + return outputs, plaintext_to_html(info), '' diff --git a/modules/gfpgan_model.py b/modules/gfpgan_model.py index 44c5dc6ca..b1288f0ca 100644 --- a/modules/gfpgan_model.py +++ b/modules/gfpgan_model.py @@ -49,6 +49,7 @@ def gfpgan(): def gfpgan_fix_faces(np_image): + global loaded_gfpgan_model model = gfpgan() np_image_bgr = np_image[:, :, ::-1] @@ -56,7 +57,9 @@ def gfpgan_fix_faces(np_image): np_image = gfpgan_output_bgr[:, :, ::-1] if shared.opts.face_restoration_unload: - model.gfpgan.to(devices.cpu) + del model + loaded_gfpgan_model = None + devices.torch_gc() return np_image @@ -83,11 +86,7 @@ def setup_gfpgan(): return "GFPGAN" def restore(self, np_image): - np_image_bgr = np_image[:, :, ::-1] - cropped_faces, restored_faces, gfpgan_output_bgr = gfpgan().enhance(np_image_bgr, has_aligned=False, only_center_face=False, paste_back=True) - np_image = gfpgan_output_bgr[:, :, ::-1] - - return np_image + return gfpgan_fix_faces(np_image) shared.face_restorers.append(FaceRestorerGFPGAN()) except Exception: diff --git a/modules/processing.py b/modules/processing.py index 4ecdfcd2d..de5cda793 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -12,7 +12,7 @@ import cv2 from skimage import exposure import modules.sd_hijack -from modules import devices, prompt_parser, masking +from modules import devices, prompt_parser, masking, lowvram from modules.sd_hijack import model_hijack from modules.sd_samplers import samplers, samplers_for_img2img from modules.shared import opts, cmd_opts, state @@ -335,7 +335,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if state.job_count == -1: state.job_count = p.n_iter - for n in range(p.n_iter): + for n in range(p.n_iter): + with torch.no_grad(), precision_scope("cuda"), ema_scope(): if state.interrupted: break @@ -368,22 +369,32 @@ def process_images(p: StableDiffusionProcessing) -> Processed: x_samples_ddim = p.sd_model.decode_first_stage(samples_ddim) 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 opts.filter_nsfw: import modules.safety as safety x_samples_ddim = modules.safety.censor_batch(x_samples_ddim) - for i, x_sample in enumerate(x_samples_ddim): + for i, x_sample in enumerate(x_samples_ddim): + with torch.no_grad(), precision_scope("cuda"), ema_scope(): x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2) x_sample = x_sample.astype(np.uint8) - if p.restore_faces: + if p.restore_faces: + with torch.no_grad(), precision_scope("cuda"), ema_scope(): if opts.save and not p.do_not_save_samples and opts.save_images_before_face_restoration: images.save_image(Image.fromarray(x_sample), p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-face-restoration") - devices.torch_gc() - x_sample = modules.face_restoration.restore_faces(x_sample) + devices.torch_gc() + + with torch.no_grad(), precision_scope("cuda"), ema_scope(): image = Image.fromarray(x_sample) if p.color_corrections is not None and i < len(p.color_corrections): @@ -411,8 +422,13 @@ def process_images(p: StableDiffusionProcessing) -> Processed: infotexts.append(infotext(n, i)) output_images.append(image) - state.nextjob() + del x_samples_ddim + devices.torch_gc() + + state.nextjob() + + with torch.no_grad(), precision_scope("cuda"), ema_scope(): p.color_corrections = None index_of_first_image = 0 @@ -648,4 +664,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): if self.mask is not None: samples = samples * self.nmask + self.init_latent * self.mask + del x + devices.torch_gc() + return samples diff --git a/webui.py b/webui.py index c70a11c7c..b61a318db 100644 --- a/webui.py +++ b/webui.py @@ -22,7 +22,10 @@ import modules.txt2img import modules.img2img import modules.swinir as swinir import modules.sd_models +from torch.nn.functional import silu +import ldm +ldm.modules.diffusionmodules.model.nonlinearity = silu modules.codeformer_model.setup_codeformer() modules.gfpgan_model.setup_gfpgan() From c2d5b29040132c171bc4d77f1f63da972306f22c Mon Sep 17 00:00:00 2001 From: Jairo Correa Date: Thu, 29 Sep 2022 01:14:54 -0300 Subject: [PATCH 004/460] Move silu to sd_hijack --- modules/sd_hijack.py | 12 +++--------- webui.py | 3 --- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index bfbd07f9a..4bc58fa2b 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -12,6 +12,7 @@ from ldm.util import default from einops import rearrange import ldm.modules.attention import ldm.modules.diffusionmodules.model +from torch.nn.functional import silu # see https://github.com/basujindal/stable-diffusion/pull/117 for discussion @@ -100,14 +101,6 @@ def split_cross_attention_forward(self, x, context=None, mask=None): return self.to_out(r2) -def nonlinearity_hijack(x): - # swish - t = torch.sigmoid(x) - x *= t - del t - - return x - def cross_attention_attnblock_forward(self, x): h_ = x h_ = self.norm(h_) @@ -245,11 +238,12 @@ class StableDiffusionModelHijack: m.cond_stage_model = FrozenCLIPEmbedderWithCustomWords(m.cond_stage_model, self) self.clip = m.cond_stage_model + ldm.modules.diffusionmodules.model.nonlinearity = silu + if cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = split_cross_attention_forward_v1 elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): ldm.modules.attention.CrossAttention.forward = split_cross_attention_forward - ldm.modules.diffusionmodules.model.nonlinearity = nonlinearity_hijack ldm.modules.diffusionmodules.model.AttnBlock.forward = cross_attention_attnblock_forward def flatten(el): diff --git a/webui.py b/webui.py index b61a318db..c70a11c7c 100644 --- a/webui.py +++ b/webui.py @@ -22,10 +22,7 @@ import modules.txt2img import modules.img2img import modules.swinir as swinir import modules.sd_models -from torch.nn.functional import silu -import ldm -ldm.modules.diffusionmodules.model.nonlinearity = silu modules.codeformer_model.setup_codeformer() modules.gfpgan_model.setup_gfpgan() From e82ea202997cbcd2ab72891cd075d9ba270eb67d Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 30 Sep 2022 15:26:18 -0500 Subject: [PATCH 005/460] Optimize model loader Child classes only get populated to __subclassess__ when they are imported. We don't actually need to import any of them to webui any more, so clean up webUI imports and make sure loader imports children. Also, fix command line paths not actually being passed to the scalers. --- modules/modelloader.py | 19 ++++++++++++++++--- webui.py | 13 +++---------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/modules/modelloader.py b/modules/modelloader.py index 1106aeb7f..b1721671b 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -4,7 +4,6 @@ import importlib from urllib.parse import urlparse from basicsr.utils.download_util import load_file_from_url - from modules import shared from modules.upscaler import Upscaler from modules.paths import script_path, models_path @@ -120,16 +119,30 @@ def move_files(src_path: str, dest_path: str, ext_filter: str = None): def load_upscalers(): + sd = shared.script_path + # We can only do this 'magic' method to dynamically load upscalers if they are referenced, + # so we'll try to import any _model.py files before looking in __subclasses__ + modules_dir = os.path.join(sd, "modules") + for file in os.listdir(modules_dir): + if "_model.py" in file: + model_name = file.replace("_model.py", "") + full_model = f"modules.{model_name}_model" + try: + importlib.import_module(full_model) + except: + pass datas = [] + c_o = vars(shared.cmd_opts) for cls in Upscaler.__subclasses__(): name = cls.__name__ module_name = cls.__module__ module = importlib.import_module(module_name) class_ = getattr(module, name) - cmd_name = f"{name.lower().replace('upscaler', '')}-models-path" + cmd_name = f"{name.lower().replace('upscaler', '')}_models_path" opt_string = None try: - opt_string = shared.opts.__getattr__(cmd_name) + if cmd_name in c_o: + opt_string = c_o[cmd_name] except: pass scaler = class_(opt_string) diff --git a/webui.py b/webui.py index b8cccd546..ebe39a170 100644 --- a/webui.py +++ b/webui.py @@ -1,28 +1,21 @@ import os -import threading - -from modules import devices -from modules.paths import script_path import signal import threading -import modules.paths + import modules.codeformer_model as codeformer -import modules.esrgan_model as esrgan -import modules.bsrgan_model as bsrgan import modules.extras import modules.face_restoration import modules.gfpgan_model as gfpgan import modules.img2img -import modules.ldsr_model as ldsr import modules.lowvram -import modules.realesrgan_model as realesrgan +import modules.paths import modules.scripts import modules.sd_hijack import modules.sd_models import modules.shared as shared -import modules.swinir_model as swinir import modules.txt2img import modules.ui +from modules import devices from modules import modelloader from modules.paths import script_path from modules.shared import cmd_opts From 8deae077004f0332ca607fc3a5d568b1a4705bec Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Fri, 30 Sep 2022 15:28:37 -0500 Subject: [PATCH 006/460] Add ScuNET DeNoiser/Upscaler Q&D Implementation of ScuNET, thanks to our handy model loader. :P https://github.com/cszn/SCUNet --- modules/scunet_model.py | 90 ++++++++++++ modules/scunet_model_arch.py | 265 +++++++++++++++++++++++++++++++++++ modules/shared.py | 1 + 3 files changed, 356 insertions(+) create mode 100644 modules/scunet_model.py create mode 100644 modules/scunet_model_arch.py diff --git a/modules/scunet_model.py b/modules/scunet_model.py new file mode 100644 index 000000000..7987ac145 --- /dev/null +++ b/modules/scunet_model.py @@ -0,0 +1,90 @@ +import os.path +import sys +import traceback + +import PIL.Image +import numpy as np +import torch +from basicsr.utils.download_util import load_file_from_url + +import modules.upscaler +from modules import shared, modelloader +from modules.paths import models_path +from modules.scunet_model_arch import SCUNet as net + + +class UpscalerScuNET(modules.upscaler.Upscaler): + def __init__(self, dirname): + self.name = "ScuNET" + self.model_path = os.path.join(models_path, self.name) + self.model_name = "ScuNET GAN" + self.model_name2 = "ScuNET PSNR" + self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/scunet_color_real_gan.pth" + self.model_url2 = "https://github.com/cszn/KAIR/releases/download/v1.0/scunet_color_real_psnr.pth" + self.user_path = dirname + super().__init__() + model_paths = self.find_models(ext_filter=[".pth"]) + scalers = [] + add_model2 = True + for file in model_paths: + if "http" in file: + name = self.model_name + else: + name = modelloader.friendly_name(file) + if name == self.model_name2 or file == self.model_url2: + add_model2 = False + try: + scaler_data = modules.upscaler.UpscalerData(name, file, self, 4) + scalers.append(scaler_data) + except Exception: + print(f"Error loading ScuNET model: {file}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + if add_model2: + scaler_data2 = modules.upscaler.UpscalerData(self.model_name2, self.model_url2, self) + scalers.append(scaler_data2) + self.scalers = scalers + + def do_upscale(self, img: PIL.Image, selected_file): + torch.cuda.empty_cache() + + model = self.load_model(selected_file) + if model is None: + return img + + device = shared.device + img = np.array(img) + img = img[:, :, ::-1] + img = np.moveaxis(img, 2, 0) / 255 + img = torch.from_numpy(img).float() + img = img.unsqueeze(0).to(shared.device) + + img = img.to(device) + with torch.no_grad(): + output = model(img) + output = output.squeeze().float().cpu().clamp_(0, 1).numpy() + output = 255. * np.moveaxis(output, 0, 2) + output = output.astype(np.uint8) + output = output[:, :, ::-1] + torch.cuda.empty_cache() + return PIL.Image.fromarray(output, 'RGB') + + def load_model(self, path: str): + device = shared.device + if "http" in path: + filename = load_file_from_url(url=self.model_url, model_dir=self.model_path, file_name="%s.pth" % self.name, + progress=True) + else: + filename = path + if not os.path.exists(os.path.join(self.model_path, filename)) or filename is None: + print(f"ScuNET: Unable to load model from {filename}", file=sys.stderr) + return None + + model = net(in_nc=3, config=[4, 4, 4, 4, 4, 4, 4], dim=64) + model.load_state_dict(torch.load(filename), strict=True) + model.eval() + for k, v in model.named_parameters(): + v.requires_grad = False + model = model.to(device) + + return model + diff --git a/modules/scunet_model_arch.py b/modules/scunet_model_arch.py new file mode 100644 index 000000000..972a2639a --- /dev/null +++ b/modules/scunet_model_arch.py @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- +import numpy as np +import torch +import torch.nn as nn +from einops import rearrange +from einops.layers.torch import Rearrange +from timm.models.layers import trunc_normal_, DropPath + + +class WMSA(nn.Module): + """ Self-attention module in Swin Transformer + """ + + def __init__(self, input_dim, output_dim, head_dim, window_size, type): + super(WMSA, self).__init__() + self.input_dim = input_dim + self.output_dim = output_dim + self.head_dim = head_dim + self.scale = self.head_dim ** -0.5 + self.n_heads = input_dim // head_dim + self.window_size = window_size + self.type = type + self.embedding_layer = nn.Linear(self.input_dim, 3 * self.input_dim, bias=True) + + self.relative_position_params = nn.Parameter( + torch.zeros((2 * window_size - 1) * (2 * window_size - 1), self.n_heads)) + + self.linear = nn.Linear(self.input_dim, self.output_dim) + + trunc_normal_(self.relative_position_params, std=.02) + self.relative_position_params = torch.nn.Parameter( + self.relative_position_params.view(2 * window_size - 1, 2 * window_size - 1, self.n_heads).transpose(1, + 2).transpose( + 0, 1)) + + def generate_mask(self, h, w, p, shift): + """ generating the mask of SW-MSA + Args: + shift: shift parameters in CyclicShift. + Returns: + attn_mask: should be (1 1 w p p), + """ + # supporting sqaure. + attn_mask = torch.zeros(h, w, p, p, p, p, dtype=torch.bool, device=self.relative_position_params.device) + if self.type == 'W': + return attn_mask + + s = p - shift + attn_mask[-1, :, :s, :, s:, :] = True + attn_mask[-1, :, s:, :, :s, :] = True + attn_mask[:, -1, :, :s, :, s:] = True + attn_mask[:, -1, :, s:, :, :s] = True + attn_mask = rearrange(attn_mask, 'w1 w2 p1 p2 p3 p4 -> 1 1 (w1 w2) (p1 p2) (p3 p4)') + return attn_mask + + def forward(self, x): + """ Forward pass of Window Multi-head Self-attention module. + Args: + x: input tensor with shape of [b h w c]; + attn_mask: attention mask, fill -inf where the value is True; + Returns: + output: tensor shape [b h w c] + """ + if self.type != 'W': x = torch.roll(x, shifts=(-(self.window_size // 2), -(self.window_size // 2)), dims=(1, 2)) + x = rearrange(x, 'b (w1 p1) (w2 p2) c -> b w1 w2 p1 p2 c', p1=self.window_size, p2=self.window_size) + h_windows = x.size(1) + w_windows = x.size(2) + # sqaure validation + # assert h_windows == w_windows + + x = rearrange(x, 'b w1 w2 p1 p2 c -> b (w1 w2) (p1 p2) c', p1=self.window_size, p2=self.window_size) + qkv = self.embedding_layer(x) + q, k, v = rearrange(qkv, 'b nw np (threeh c) -> threeh b nw np c', c=self.head_dim).chunk(3, dim=0) + sim = torch.einsum('hbwpc,hbwqc->hbwpq', q, k) * self.scale + # Adding learnable relative embedding + sim = sim + rearrange(self.relative_embedding(), 'h p q -> h 1 1 p q') + # Using Attn Mask to distinguish different subwindows. + if self.type != 'W': + attn_mask = self.generate_mask(h_windows, w_windows, self.window_size, shift=self.window_size // 2) + sim = sim.masked_fill_(attn_mask, float("-inf")) + + probs = nn.functional.softmax(sim, dim=-1) + output = torch.einsum('hbwij,hbwjc->hbwic', probs, v) + output = rearrange(output, 'h b w p c -> b w p (h c)') + output = self.linear(output) + output = rearrange(output, 'b (w1 w2) (p1 p2) c -> b (w1 p1) (w2 p2) c', w1=h_windows, p1=self.window_size) + + if self.type != 'W': output = torch.roll(output, shifts=(self.window_size // 2, self.window_size // 2), + dims=(1, 2)) + return output + + def relative_embedding(self): + cord = torch.tensor(np.array([[i, j] for i in range(self.window_size) for j in range(self.window_size)])) + relation = cord[:, None, :] - cord[None, :, :] + self.window_size - 1 + # negative is allowed + return self.relative_position_params[:, relation[:, :, 0].long(), relation[:, :, 1].long()] + + +class Block(nn.Module): + def __init__(self, input_dim, output_dim, head_dim, window_size, drop_path, type='W', input_resolution=None): + """ SwinTransformer Block + """ + super(Block, self).__init__() + self.input_dim = input_dim + self.output_dim = output_dim + assert type in ['W', 'SW'] + self.type = type + if input_resolution <= window_size: + self.type = 'W' + + self.ln1 = nn.LayerNorm(input_dim) + self.msa = WMSA(input_dim, input_dim, head_dim, window_size, self.type) + self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() + self.ln2 = nn.LayerNorm(input_dim) + self.mlp = nn.Sequential( + nn.Linear(input_dim, 4 * input_dim), + nn.GELU(), + nn.Linear(4 * input_dim, output_dim), + ) + + def forward(self, x): + x = x + self.drop_path(self.msa(self.ln1(x))) + x = x + self.drop_path(self.mlp(self.ln2(x))) + return x + + +class ConvTransBlock(nn.Module): + def __init__(self, conv_dim, trans_dim, head_dim, window_size, drop_path, type='W', input_resolution=None): + """ SwinTransformer and Conv Block + """ + super(ConvTransBlock, self).__init__() + self.conv_dim = conv_dim + self.trans_dim = trans_dim + self.head_dim = head_dim + self.window_size = window_size + self.drop_path = drop_path + self.type = type + self.input_resolution = input_resolution + + assert self.type in ['W', 'SW'] + if self.input_resolution <= self.window_size: + self.type = 'W' + + self.trans_block = Block(self.trans_dim, self.trans_dim, self.head_dim, self.window_size, self.drop_path, + self.type, self.input_resolution) + self.conv1_1 = nn.Conv2d(self.conv_dim + self.trans_dim, self.conv_dim + self.trans_dim, 1, 1, 0, bias=True) + self.conv1_2 = nn.Conv2d(self.conv_dim + self.trans_dim, self.conv_dim + self.trans_dim, 1, 1, 0, bias=True) + + self.conv_block = nn.Sequential( + nn.Conv2d(self.conv_dim, self.conv_dim, 3, 1, 1, bias=False), + nn.ReLU(True), + nn.Conv2d(self.conv_dim, self.conv_dim, 3, 1, 1, bias=False) + ) + + def forward(self, x): + conv_x, trans_x = torch.split(self.conv1_1(x), (self.conv_dim, self.trans_dim), dim=1) + conv_x = self.conv_block(conv_x) + conv_x + trans_x = Rearrange('b c h w -> b h w c')(trans_x) + trans_x = self.trans_block(trans_x) + trans_x = Rearrange('b h w c -> b c h w')(trans_x) + res = self.conv1_2(torch.cat((conv_x, trans_x), dim=1)) + x = x + res + + return x + + +class SCUNet(nn.Module): + # def __init__(self, in_nc=3, config=[2, 2, 2, 2, 2, 2, 2], dim=64, drop_path_rate=0.0, input_resolution=256): + def __init__(self, in_nc=3, config=None, dim=64, drop_path_rate=0.0, input_resolution=256): + super(SCUNet, self).__init__() + if config is None: + config = [2, 2, 2, 2, 2, 2, 2] + self.config = config + self.dim = dim + self.head_dim = 32 + self.window_size = 8 + + # drop path rate for each layer + dpr = [x.item() for x in torch.linspace(0, drop_path_rate, sum(config))] + + self.m_head = [nn.Conv2d(in_nc, dim, 3, 1, 1, bias=False)] + + begin = 0 + self.m_down1 = [ConvTransBlock(dim // 2, dim // 2, self.head_dim, self.window_size, dpr[i + begin], + 'W' if not i % 2 else 'SW', input_resolution) + for i in range(config[0])] + \ + [nn.Conv2d(dim, 2 * dim, 2, 2, 0, bias=False)] + + begin += config[0] + self.m_down2 = [ConvTransBlock(dim, dim, self.head_dim, self.window_size, dpr[i + begin], + 'W' if not i % 2 else 'SW', input_resolution // 2) + for i in range(config[1])] + \ + [nn.Conv2d(2 * dim, 4 * dim, 2, 2, 0, bias=False)] + + begin += config[1] + self.m_down3 = [ConvTransBlock(2 * dim, 2 * dim, self.head_dim, self.window_size, dpr[i + begin], + 'W' if not i % 2 else 'SW', input_resolution // 4) + for i in range(config[2])] + \ + [nn.Conv2d(4 * dim, 8 * dim, 2, 2, 0, bias=False)] + + begin += config[2] + self.m_body = [ConvTransBlock(4 * dim, 4 * dim, self.head_dim, self.window_size, dpr[i + begin], + 'W' if not i % 2 else 'SW', input_resolution // 8) + for i in range(config[3])] + + begin += config[3] + self.m_up3 = [nn.ConvTranspose2d(8 * dim, 4 * dim, 2, 2, 0, bias=False), ] + \ + [ConvTransBlock(2 * dim, 2 * dim, self.head_dim, self.window_size, dpr[i + begin], + 'W' if not i % 2 else 'SW', input_resolution // 4) + for i in range(config[4])] + + begin += config[4] + self.m_up2 = [nn.ConvTranspose2d(4 * dim, 2 * dim, 2, 2, 0, bias=False), ] + \ + [ConvTransBlock(dim, dim, self.head_dim, self.window_size, dpr[i + begin], + 'W' if not i % 2 else 'SW', input_resolution // 2) + for i in range(config[5])] + + begin += config[5] + self.m_up1 = [nn.ConvTranspose2d(2 * dim, dim, 2, 2, 0, bias=False), ] + \ + [ConvTransBlock(dim // 2, dim // 2, self.head_dim, self.window_size, dpr[i + begin], + 'W' if not i % 2 else 'SW', input_resolution) + for i in range(config[6])] + + self.m_tail = [nn.Conv2d(dim, in_nc, 3, 1, 1, bias=False)] + + self.m_head = nn.Sequential(*self.m_head) + self.m_down1 = nn.Sequential(*self.m_down1) + self.m_down2 = nn.Sequential(*self.m_down2) + self.m_down3 = nn.Sequential(*self.m_down3) + self.m_body = nn.Sequential(*self.m_body) + self.m_up3 = nn.Sequential(*self.m_up3) + self.m_up2 = nn.Sequential(*self.m_up2) + self.m_up1 = nn.Sequential(*self.m_up1) + self.m_tail = nn.Sequential(*self.m_tail) + # self.apply(self._init_weights) + + def forward(self, x0): + + h, w = x0.size()[-2:] + paddingBottom = int(np.ceil(h / 64) * 64 - h) + paddingRight = int(np.ceil(w / 64) * 64 - w) + x0 = nn.ReplicationPad2d((0, paddingRight, 0, paddingBottom))(x0) + + x1 = self.m_head(x0) + x2 = self.m_down1(x1) + x3 = self.m_down2(x2) + x4 = self.m_down3(x3) + x = self.m_body(x4) + x = self.m_up3(x + x4) + x = self.m_up2(x + x3) + x = self.m_up1(x + x2) + x = self.m_tail(x + x1) + + x = x[..., :h, :w] + + return x + + def _init_weights(self, m): + if isinstance(m, nn.Linear): + trunc_normal_(m.weight, std=.02) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm): + nn.init.constant_(m.bias, 0) + nn.init.constant_(m.weight, 1.0) \ No newline at end of file diff --git a/modules/shared.py b/modules/shared.py index 8428c7a38..a48b995ad 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -40,6 +40,7 @@ parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory wi parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(model_path, 'ESRGAN')) parser.add_argument("--bsrgan-models-path", type=str, help="Path to directory with BSRGAN model file(s).", default=os.path.join(model_path, 'BSRGAN')) parser.add_argument("--realesrgan-models-path", type=str, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(model_path, 'RealESRGAN')) +parser.add_argument("--scunet-models-path", type=str, help="Path to directory with ScuNET model file(s).", default=os.path.join(model_path, 'ScuNET')) parser.add_argument("--swinir-models-path", type=str, help="Path to directory with SwinIR model file(s).", default=os.path.join(model_path, 'SwinIR')) parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(model_path, 'LDSR')) parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") From abdbf1de646f007b6d76cfb3f416fdfaadb57903 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 29 Sep 2022 14:40:47 -0400 Subject: [PATCH 007/460] token counters now update when roll artist and style buttons are pressed https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/1194#issuecomment-1261203893 --- javascript/ui.js | 28 ++++++++++++++++++++++------ modules/ui.py | 6 +++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/javascript/ui.js b/javascript/ui.js index bfe024108..88fd45ae9 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -199,12 +199,21 @@ let txt2img_textarea, img2img_textarea = undefined; let wait_time = 800 let token_timeout; -function submit_prompt(event, generate_button_id) { - if (event.altKey && event.keyCode === 13) { - event.preventDefault(); - gradioApp().getElementById(generate_button_id).click(); - return; - } +function roll_artist_txt2img(prompt_text) { + update_token_counter("txt2img_token_button") + return prompt_text; +} +function roll_artist_img2img(prompt_text) { + update_token_counter("img2img_token_button") + return prompt_text; +} +function update_style_txt2img(prompt_text, negative_prompt, style1, style2) { + update_token_counter("txt2img_token_button") + return [prompt_text, negative_prompt, style1, style2] +} +function update_style_img2img(prompt_text, negative_prompt, style1, style2) { + update_token_counter("img2img_token_button") + return [prompt_text, negative_prompt, style1, style2] } function update_token_counter(button_id) { @@ -212,3 +221,10 @@ function update_token_counter(button_id) { clearTimeout(token_timeout); token_timeout = setTimeout(() => gradioApp().getElementById(button_id)?.click(), wait_time); } +function submit_prompt(event, generate_button_id) { + if (event.altKey && event.keyCode === 13) { + event.preventDefault(); + gradioApp().getElementById(generate_button_id).click(); + return; + } +} \ No newline at end of file diff --git a/modules/ui.py b/modules/ui.py index 15572bb0a..5eea18606 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -539,6 +539,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): roll.click( fn=roll_artist, + _js="roll_artist_txt2img", inputs=[ txt2img_prompt, ], @@ -743,6 +744,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): roll.click( fn=roll_artist, + _js="roll_artist_img2img", inputs=[ img2img_prompt, ], @@ -753,6 +755,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)] style_dropdowns = [(txt2img_prompt_style, txt2img_prompt_style2), (img2img_prompt_style, img2img_prompt_style2)] + style_js_funcs = ["update_style_txt2img", "update_style_img2img"] for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts): button.click( @@ -764,9 +767,10 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): outputs=[txt2img_prompt_style, img2img_prompt_style, txt2img_prompt_style2, img2img_prompt_style2], ) - for button, (prompt, negative_prompt), (style1, style2) in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns): + for button, (prompt, negative_prompt), (style1, style2), js_func in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns, style_js_funcs): button.click( fn=apply_styles, + _js=js_func, inputs=[prompt, negative_prompt, style1, style2], outputs=[prompt, negative_prompt, style1, style2], ) From ff8dc1908af088d0ed43fb85baad662733c5ca9c Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 29 Sep 2022 15:47:06 -0400 Subject: [PATCH 008/460] fixed token counter for prompt editing --- modules/ui.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 5eea18606..6bf28562c 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -11,6 +11,7 @@ import time import traceback import platform import subprocess as sp +from functools import reduce import numpy as np import torch @@ -32,6 +33,7 @@ import modules.gfpgan_model import modules.codeformer_model import modules.styles import modules.generation_parameters_copypaste +from modules.prompt_parser import get_learned_conditioning_prompt_schedules # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI mimetypes.init() @@ -345,8 +347,11 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: outputs=[seed, dummy_component] ) -def update_token_counter(text): - tokens, token_count, max_length = model_hijack.tokenize(text) +def update_token_counter(text, steps): + prompt_schedules = get_learned_conditioning_prompt_schedules([text], steps) + flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules) + prompts = [prompt_text for step,prompt_text in flat_prompts] + tokens, token_count, max_length = max([model_hijack.tokenize(prompt) for prompt in prompts], key=lambda args: args[1]) style_class = ' class="red"' if (token_count > max_length) else "" return f"{token_count}/{max_length}" @@ -364,8 +369,7 @@ def create_toprow(is_img2img): roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0) paste = gr.Button(value=paste_symbol, elem_id="paste") token_counter = gr.HTML(value="", elem_id=f"{id_part}_token_counter") - hidden_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button") - hidden_button.click(fn=update_token_counter, inputs=[prompt], outputs=[token_counter]) + token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button") with gr.Column(scale=10, elem_id="style_pos_col"): prompt_style = gr.Dropdown(label="Style 1", elem_id=f"{id_part}_style_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())), visible=len(shared.prompt_styles.styles) > 1) @@ -396,7 +400,7 @@ def create_toprow(is_img2img): prompt_style_apply = gr.Button('Apply style', elem_id="style_apply") save_style = gr.Button('Create style', elem_id="style_create") - return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, paste + return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, paste, token_counter, token_button def setup_progressbar(progressbar, preview, id_part): @@ -419,7 +423,7 @@ def setup_progressbar(progressbar, preview, id_part): def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): with gr.Blocks(analytics_enabled=False) as txt2img_interface: - txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, paste = create_toprow(is_img2img=False) + txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) with gr.Row(elem_id='txt2img_progress_row'): @@ -568,9 +572,10 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)), ] modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt) + token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) with gr.Blocks(analytics_enabled=False) as img2img_interface: - img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style, paste = create_toprow(is_img2img=True) + img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) with gr.Row(elem_id='img2img_progress_row'): with gr.Column(scale=1): @@ -793,6 +798,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): (denoising_strength, "Denoising strength"), ] modules.generation_parameters_copypaste.connect_paste(paste, img2img_paste_fields, img2img_prompt) + token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter]) with gr.Blocks(analytics_enabled=False) as extras_interface: with gr.Row().style(equal_height=False): From 3c6a049fc3c6b54ada3736710a7e86663ea7f3d9 Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 30 Sep 2022 12:12:44 -0400 Subject: [PATCH 009/460] consolidated token counter functions --- javascript/ui.js | 21 +++++++++------------ modules/ui.py | 6 +++--- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/javascript/ui.js b/javascript/ui.js index 88fd45ae9..f94ed081d 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -199,21 +199,18 @@ let txt2img_textarea, img2img_textarea = undefined; let wait_time = 800 let token_timeout; -function roll_artist_txt2img(prompt_text) { +function update_txt2img_tokens(...args) { update_token_counter("txt2img_token_button") - return prompt_text; + if (args.length == 2) + return args[0] + return args; } -function roll_artist_img2img(prompt_text) { + +function update_img2img_tokens(...args) { update_token_counter("img2img_token_button") - return prompt_text; -} -function update_style_txt2img(prompt_text, negative_prompt, style1, style2) { - update_token_counter("txt2img_token_button") - return [prompt_text, negative_prompt, style1, style2] -} -function update_style_img2img(prompt_text, negative_prompt, style1, style2) { - update_token_counter("img2img_token_button") - return [prompt_text, negative_prompt, style1, style2] + if (args.length == 2) + return args[0] + return args; } function update_token_counter(button_id) { diff --git a/modules/ui.py b/modules/ui.py index 6bf28562c..40c089841 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -543,7 +543,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): roll.click( fn=roll_artist, - _js="roll_artist_txt2img", + _js="update_txt2img_tokens", inputs=[ txt2img_prompt, ], @@ -749,7 +749,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): roll.click( fn=roll_artist, - _js="roll_artist_img2img", + _js="update_img2img_tokens", inputs=[ img2img_prompt, ], @@ -760,7 +760,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)] style_dropdowns = [(txt2img_prompt_style, txt2img_prompt_style2), (img2img_prompt_style, img2img_prompt_style2)] - style_js_funcs = ["update_style_txt2img", "update_style_img2img"] + style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"] for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts): button.click( From bdaa36c84470adbdce3e98c01a69af5e95adfb02 Mon Sep 17 00:00:00 2001 From: brkirch Date: Fri, 30 Sep 2022 23:53:25 -0400 Subject: [PATCH 010/460] When device is MPS, use CPU for GFPGAN instead GFPGAN will not work if the device is MPS, so default to CPU instead. --- modules/devices.py | 2 +- modules/gfpgan_model.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/devices.py b/modules/devices.py index 07bb23397..08bb26d6f 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -34,7 +34,7 @@ errors.run(enable_tf32, "Enabling TF32") device = get_optimal_device() -device_codeformer = cpu if has_mps else device +device_gfpgan = device_codeformer = cpu if device.type == 'mps' else device def randn(seed, shape): diff --git a/modules/gfpgan_model.py b/modules/gfpgan_model.py index bb30d7330..fcd8544a5 100644 --- a/modules/gfpgan_model.py +++ b/modules/gfpgan_model.py @@ -21,7 +21,7 @@ def gfpgann(): global loaded_gfpgan_model global model_path if loaded_gfpgan_model is not None: - loaded_gfpgan_model.gfpgan.to(shared.device) + loaded_gfpgan_model.gfpgan.to(devices.device_gfpgan) return loaded_gfpgan_model if gfpgan_constructor is None: @@ -36,8 +36,8 @@ def gfpgann(): else: print("Unable to load gfpgan model!") return None - model = gfpgan_constructor(model_path=model_file, upscale=1, arch='clean', channel_multiplier=2, bg_upsampler=None) - model.gfpgan.to(shared.device) + model = gfpgan_constructor(model_path=model_file, upscale=1, arch='clean', channel_multiplier=2, bg_upsampler=None, device=devices.device_gfpgan) + model.gfpgan.to(devices.device_gfpgan) loaded_gfpgan_model = model return model From 4c2478a68a4f11959fe4887d38e0436eac19f97e Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 18:30:53 +0100 Subject: [PATCH 011/460] add script reload method --- modules/scripts.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/scripts.py b/modules/scripts.py index 7c3bd5e74..3c14b9e32 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -165,3 +165,12 @@ class ScriptRunner: scripts_txt2img = ScriptRunner() scripts_img2img = ScriptRunner() + +def reload_scripts(basedir): + global scripts_txt2img,scripts_img2img + + scripts_data.clear() + load_scripts(basedir) + + scripts_txt2img = ScriptRunner() + scripts_img2img = ScriptRunner() From 95f35d04ab1636e08f69ca9c0ae2446714870e80 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 18:31:58 +0100 Subject: [PATCH 012/460] Host busy thread, check for reload --- webui.py | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/webui.py b/webui.py index b8cccd546..4948c394f 100644 --- a/webui.py +++ b/webui.py @@ -86,22 +86,38 @@ def webui(): signal.signal(signal.SIGINT, sigint_handler) - demo = modules.ui.create_ui( - txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img), - img2img=wrap_gradio_gpu_call(modules.img2img.img2img), - run_extras=wrap_gradio_gpu_call(modules.extras.run_extras), - run_pnginfo=modules.extras.run_pnginfo, - run_modelmerger=modules.extras.run_modelmerger - ) + while 1: - demo.launch( - share=cmd_opts.share, - server_name="0.0.0.0" if cmd_opts.listen else None, - server_port=cmd_opts.port, - debug=cmd_opts.gradio_debug, - auth=[tuple(cred.split(':')) for cred in cmd_opts.gradio_auth.strip('"').split(',')] if cmd_opts.gradio_auth else None, - inbrowser=cmd_opts.autolaunch, - ) + demo = modules.ui.create_ui( + txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img), + img2img=wrap_gradio_gpu_call(modules.img2img.img2img), + run_extras=wrap_gradio_gpu_call(modules.extras.run_extras), + run_pnginfo=modules.extras.run_pnginfo, + run_modelmerger=modules.extras.run_modelmerger + ) + + + demo.launch( + share=cmd_opts.share, + server_name="0.0.0.0" if cmd_opts.listen else None, + server_port=cmd_opts.port, + debug=cmd_opts.gradio_debug, + auth=[tuple(cred.split(':')) for cred in cmd_opts.gradio_auth.strip('"').split(',')] if cmd_opts.gradio_auth else None, + inbrowser=cmd_opts.autolaunch, + prevent_thread_lock=True + ) + + while 1: + time.sleep(0.5) + if getattr(demo,'do_restart',False): + time.sleep(0.5) + demo.close() + time.sleep(0.5) + break + + print('Reloading Scripts') + modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) + print('Restarting Gradio') if __name__ == "__main__": From 4f8490cd5630823ac44de8b5c5e4325bdbbea7fa Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 18:33:31 +0100 Subject: [PATCH 013/460] add restart button --- modules/ui.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index 15572bb0a..ec6aaa288 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1002,6 +1002,17 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): _js='function(){}' ) + def request_restart(): + settings_interface.gradio_ref.do_restart = True + + restart_gradio = gr.Button(value='Restart Gradio and Refresh Scripts') + restart_gradio.click( + fn=request_restart, + inputs=[], + outputs=[], + _js='function(){document.body.innerHTML=\'

Reloading

\';setTimeout(function(){location.reload()},2000)}' + ) + if column is not None: column.__exit__() @@ -1026,7 +1037,9 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): css += css_hide_progressbar with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo: - + + settings_interface.gradio_ref = demo + with gr.Tabs() as tabs: for interface, label, ifid in interfaces: with gr.TabItem(label, id=ifid): From 121ed7d36febe94995774973b5edc1ba2ba84aad Mon Sep 17 00:00:00 2001 From: Alexandre Simard Date: Sat, 1 Oct 2022 14:04:20 -0400 Subject: [PATCH 014/460] Add progress bar for SwinIR in cmd I do not know how to add them to the UI... --- modules/swinir_model.py | 25 ++++++++++++++----------- webui-user.bat | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/modules/swinir_model.py b/modules/swinir_model.py index 41fda5a7c..9bd454c69 100644 --- a/modules/swinir_model.py +++ b/modules/swinir_model.py @@ -5,6 +5,7 @@ import numpy as np import torch from PIL import Image from basicsr.utils.download_util import load_file_from_url +from tqdm import tqdm from modules import modelloader from modules.paths import models_path @@ -122,18 +123,20 @@ def inference(img, model, tile, tile_overlap, window_size, scale): E = torch.zeros(b, c, h * sf, w * sf, dtype=torch.half, device=device).type_as(img) W = torch.zeros_like(E, dtype=torch.half, device=device) - for h_idx in h_idx_list: - for w_idx in w_idx_list: - in_patch = img[..., h_idx: h_idx + tile, w_idx: w_idx + tile] - out_patch = model(in_patch) - out_patch_mask = torch.ones_like(out_patch) + with tqdm(total=len(h_idx_list) * len(w_idx_list), desc="SwinIR tiles") as pbar: + for h_idx in h_idx_list: + for w_idx in w_idx_list: + in_patch = img[..., h_idx: h_idx + tile, w_idx: w_idx + tile] + out_patch = model(in_patch) + out_patch_mask = torch.ones_like(out_patch) - E[ - ..., h_idx * sf: (h_idx + tile) * sf, w_idx * sf: (w_idx + tile) * sf - ].add_(out_patch) - W[ - ..., h_idx * sf: (h_idx + tile) * sf, w_idx * sf: (w_idx + tile) * sf - ].add_(out_patch_mask) + E[ + ..., h_idx * sf: (h_idx + tile) * sf, w_idx * sf: (w_idx + tile) * sf + ].add_(out_patch) + W[ + ..., h_idx * sf: (h_idx + tile) * sf, w_idx * sf: (w_idx + tile) * sf + ].add_(out_patch_mask) + pbar.update(1) output = E.div_(W) return output diff --git a/webui-user.bat b/webui-user.bat index e5a257bef..5c7789535 100644 --- a/webui-user.bat +++ b/webui-user.bat @@ -3,6 +3,6 @@ set PYTHON= set GIT= set VENV_DIR= -set COMMANDLINE_ARGS= +set COMMANDLINE_ARGS=--autolaunch call webui.bat From b8a2b0453b62e4e99d0e5c049313402bc79056b5 Mon Sep 17 00:00:00 2001 From: Alexandre Simard Date: Sat, 1 Oct 2022 14:07:20 -0400 Subject: [PATCH 015/460] Set launch options to default --- webui-user.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webui-user.bat b/webui-user.bat index 5c7789535..e5a257bef 100644 --- a/webui-user.bat +++ b/webui-user.bat @@ -3,6 +3,6 @@ set PYTHON= set GIT= set VENV_DIR= -set COMMANDLINE_ARGS=--autolaunch +set COMMANDLINE_ARGS= call webui.bat From a9044475c06204deb886d2a69467d0d3a9f5c9be Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 21:47:42 +0100 Subject: [PATCH 016/460] add time import --- webui.py | 1 + 1 file changed, 1 insertion(+) diff --git a/webui.py b/webui.py index 4948c394f..e2c4c2baa 100644 --- a/webui.py +++ b/webui.py @@ -1,5 +1,6 @@ import os import threading +import time from modules import devices from modules.paths import script_path From afaa03c5fd05f48ed9c9f15558ea6f0bc4f61628 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:43:45 +0100 Subject: [PATCH 017/460] add redefinition guard to gradio_routes_templates_response --- modules/ui.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index ec6aaa288..fd057916e 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1219,12 +1219,13 @@ for filename in sorted(os.listdir(jsdir)): javascript += f"\n" -def template_response(*args, **kwargs): - res = gradio_routes_templates_response(*args, **kwargs) - res.body = res.body.replace(b'', f'{javascript}'.encode("utf8")) - res.init_headers() - return res +if 'gradio_routes_templates_response' not in globals(): + def template_response(*args, **kwargs): + res = gradio_routes_templates_response(*args, **kwargs) + res.body = res.body.replace(b'', f'{javascript}'.encode("utf8")) + res.init_headers() + return res + gradio_routes_templates_response = gradio.routes.templates.TemplateResponse + gradio.routes.templates.TemplateResponse = template_response -gradio_routes_templates_response = gradio.routes.templates.TemplateResponse -gradio.routes.templates.TemplateResponse = template_response From 30f2e3565840544dd66470c6ef216ec664db6432 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 22:50:03 +0100 Subject: [PATCH 018/460] add importlib.reload --- webui.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/webui.py b/webui.py index e2c4c2baa..ab200045a 100644 --- a/webui.py +++ b/webui.py @@ -1,7 +1,7 @@ import os import threading import time - +import importlib from modules import devices from modules.paths import script_path import signal @@ -116,8 +116,10 @@ def webui(): time.sleep(0.5) break - print('Reloading Scripts') + print('Reloading Custom Scripts') modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) + print('Reloading modules: modules.ui') + importlib.reload(modules.ui) print('Restarting Gradio') From 6048002dade91b82b1ce9fea3c6ff5b5c1f8c990 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 23:10:07 +0100 Subject: [PATCH 019/460] Add scope warning to refresh button --- modules/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index fd057916e..72846a122 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1005,7 +1005,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): def request_restart(): settings_interface.gradio_ref.do_restart = True - restart_gradio = gr.Button(value='Restart Gradio and Refresh Scripts') + restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') restart_gradio.click( fn=request_restart, inputs=[], From 027c5aae5546ff3650347cb3c2b87df4415ab900 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 1 Oct 2022 23:29:26 +0100 Subject: [PATCH 020/460] update reloading message style --- modules/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index 72846a122..7b2359c20 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1010,7 +1010,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): fn=request_restart, inputs=[], outputs=[], - _js='function(){document.body.innerHTML=\'

Reloading

\';setTimeout(function(){location.reload()},2000)}' + _js='function(){document.body.innerHTML=\'

Reloading...

\';setTimeout(function(){location.reload()},2000)}' ) if column is not None: From 55b046312c51bb7b2329d3b5b7f1c05956f821bf Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 2 Oct 2022 00:12:49 +0100 Subject: [PATCH 021/460] move JavaScript into ui.js --- javascript/ui.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/javascript/ui.js b/javascript/ui.js index bfe024108..e8f289b44 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -212,3 +212,8 @@ function update_token_counter(button_id) { clearTimeout(token_timeout); token_timeout = setTimeout(() => gradioApp().getElementById(button_id)?.click(), wait_time); } + +function restart_reload(){ + document.body.innerHTML='

Reloading...

'; + setTimeout(function(){location.reload()},2000) +} From 0aa354bd5e811e2b41b17a3052cf5d4c8190d533 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 2 Oct 2022 00:13:47 +0100 Subject: [PATCH 022/460] remove styling from python side --- modules/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index 7b2359c20..cb859ac45 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1010,7 +1010,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): fn=request_restart, inputs=[], outputs=[], - _js='function(){document.body.innerHTML=\'

Reloading...

\';setTimeout(function(){location.reload()},2000)}' + _js='function(){restart_reload()}' ) if column is not None: From cf33268d686986a24f2e04eb615f01ed53bfe308 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 2 Oct 2022 01:18:42 +0100 Subject: [PATCH 023/460] add script body only refresh --- modules/scripts.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/modules/scripts.py b/modules/scripts.py index 3c14b9e32..788397f53 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -162,10 +162,33 @@ class ScriptRunner: return processed + def reload_sources(self): + for si,script in list(enumerate(self.scripts)): + with open(script.filename, "r", encoding="utf8") as file: + args_from = script.args_from + args_to = script.args_to + filename = script.filename + text = file.read() + + from types import ModuleType + compiled = compile(text, filename, 'exec') + module = ModuleType(script.filename) + exec(compiled, module.__dict__) + + for key, script_class in module.__dict__.items(): + if type(script_class) == type and issubclass(script_class, Script): + self.scripts[si] = script_class() + self.scripts[si].filename = filename + self.scripts[si].args_from = args_from + self.scripts[si].args_to = args_to scripts_txt2img = ScriptRunner() scripts_img2img = ScriptRunner() +def reload_script_body_only(): + scripts_txt2img.reload_sources() + scripts_img2img.reload_sources() + def reload_scripts(basedir): global scripts_txt2img,scripts_img2img From 07e40ad7f23472fc1c781fe1cc6c1ee403413918 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 2 Oct 2022 01:19:55 +0100 Subject: [PATCH 024/460] add custom script body only refresh option --- modules/ui.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/ui.py b/modules/ui.py index cb859ac45..eb7c05852 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1012,6 +1012,17 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): outputs=[], _js='function(){restart_reload()}' ) + + def reload_scripts(): + modules.scripts.reload_script_body_only() + + reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='primary') + reload_script_bodies.click( + fn=reload_scripts, + inputs=[], + outputs=[], + _js='function(){}' + ) if column is not None: column.__exit__() From 2deea867814272f1f089b60e9ba8d587c16b2fb1 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 2 Oct 2022 01:36:30 +0100 Subject: [PATCH 025/460] Put reload buttons in row and add secondary style --- modules/ui.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index eb7c05852..963a2c611 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1002,27 +1002,30 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): _js='function(){}' ) - def request_restart(): - settings_interface.gradio_ref.do_restart = True + with gr.Row(): + reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary') + restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') - restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') - restart_gradio.click( - fn=request_restart, - inputs=[], - outputs=[], - _js='function(){restart_reload()}' - ) def reload_scripts(): modules.scripts.reload_script_body_only() - reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='primary') reload_script_bodies.click( fn=reload_scripts, inputs=[], outputs=[], _js='function(){}' ) + + def request_restart(): + settings_interface.gradio_ref.do_restart = True + + restart_gradio.click( + fn=request_restart, + inputs=[], + outputs=[], + _js='function(){restart_reload()}' + ) if column is not None: column.__exit__() From 3cf1a96006daffedb8ecd0ae142eca4c4da06105 Mon Sep 17 00:00:00 2001 From: RnDMonkey Date: Sat, 1 Oct 2022 21:11:03 -0700 Subject: [PATCH 026/460] added safety for blank directory naming patterns --- modules/images.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/images.py b/modules/images.py index f1aed5d6b..e7894b4cd 100644 --- a/modules/images.py +++ b/modules/images.py @@ -311,7 +311,7 @@ def apply_filename_pattern(x, p, seed, prompt): x = x.replace("[cfg]", str(p.cfg_scale)) x = x.replace("[width]", str(p.width)) x = x.replace("[height]", str(p.height)) - x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]), replace_spaces=False)) + x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]) or "No styles", replace_spaces=False)) x = x.replace("[sampler]", sanitize_filename_part(sd_samplers.samplers[p.sampler_index].name, replace_spaces=False)) x = x.replace("[model_hash]", shared.sd_model.sd_model_hash) @@ -374,7 +374,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i save_to_dirs = (grid and opts.grid_save_to_dirs) or (not grid and opts.save_to_dirs and not no_prompt) if save_to_dirs: - dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt) + dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt).strip('\\ ') path = os.path.join(path, dirname) os.makedirs(path, exist_ok=True) From 70f526704721a303ae045f6406439dcceee4302e Mon Sep 17 00:00:00 2001 From: RnDMonkey Date: Sat, 1 Oct 2022 21:18:15 -0700 Subject: [PATCH 027/460] use os.path.normpath for better safety checking --- modules/images.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/images.py b/modules/images.py index e7894b4cd..5ef7eb926 100644 --- a/modules/images.py +++ b/modules/images.py @@ -374,8 +374,8 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i save_to_dirs = (grid and opts.grid_save_to_dirs) or (not grid and opts.save_to_dirs and not no_prompt) if save_to_dirs: - dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt).strip('\\ ') - path = os.path.join(path, dirname) + dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt) + path = os.path.normpath(os.path.join(path, dirname)) os.makedirs(path, exist_ok=True) From 32edf1732f27a1fad5133667c22b948adda1b070 Mon Sep 17 00:00:00 2001 From: RnDMonkey Date: Sat, 1 Oct 2022 21:37:14 -0700 Subject: [PATCH 028/460] os.path.normpath wasn't working, reverting to manual strip --- modules/images.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/images.py b/modules/images.py index 5ef7eb926..4998e92cf 100644 --- a/modules/images.py +++ b/modules/images.py @@ -374,8 +374,8 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i save_to_dirs = (grid and opts.grid_save_to_dirs) or (not grid and opts.save_to_dirs and not no_prompt) if save_to_dirs: - dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt) - path = os.path.normpath(os.path.join(path, dirname)) + dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt).strip('\\ /') + path = os.path.join(path, dirname) os.makedirs(path, exist_ok=True) From 820f1dc96b1979d7e92170c161db281ee8bd988b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 15:03:39 +0300 Subject: [PATCH 029/460] initial support for training textual inversion --- .gitignore | 1 + javascript/progressbar.js | 1 + javascript/textualInversion.js | 8 + modules/devices.py | 3 +- modules/processing.py | 13 +- modules/sd_hijack.py | 324 +++--------------- modules/sd_hijack_optimizations.py | 164 +++++++++ modules/sd_models.py | 4 +- modules/shared.py | 3 +- modules/textual_inversion/dataset.py | 76 ++++ .../textual_inversion/textual_inversion.py | 258 ++++++++++++++ modules/textual_inversion/ui.py | 32 ++ modules/ui.py | 139 +++++++- style.css | 10 +- textual_inversion_templates/style.txt | 19 + .../style_filewords.txt | 19 + textual_inversion_templates/subject.txt | 27 ++ .../subject_filewords.txt | 27 ++ webui.py | 15 +- 19 files changed, 828 insertions(+), 315 deletions(-) create mode 100644 javascript/textualInversion.js create mode 100644 modules/sd_hijack_optimizations.py create mode 100644 modules/textual_inversion/dataset.py create mode 100644 modules/textual_inversion/textual_inversion.py create mode 100644 modules/textual_inversion/ui.py create mode 100644 textual_inversion_templates/style.txt create mode 100644 textual_inversion_templates/style_filewords.txt create mode 100644 textual_inversion_templates/subject.txt create mode 100644 textual_inversion_templates/subject_filewords.txt diff --git a/.gitignore b/.gitignore index 3532dab37..7afc93953 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ __pycache__ /.idea notification.mp3 /SwinIR +/textual_inversion diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 21f25b38d..1e297abbe 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -30,6 +30,7 @@ function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_inte onUiUpdate(function(){ check_progressbar('txt2img', 'txt2img_progressbar', 'txt2img_progress_span', 'txt2img_interrupt', 'txt2img_preview', 'txt2img_gallery') check_progressbar('img2img', 'img2img_progressbar', 'img2img_progress_span', 'img2img_interrupt', 'img2img_preview', 'img2img_gallery') + check_progressbar('ti', 'ti_progressbar', 'ti_progress_span', 'ti_interrupt', 'ti_preview', 'ti_gallery') }) function requestMoreProgress(id_part, id_progressbar_span, id_interrupt){ diff --git a/javascript/textualInversion.js b/javascript/textualInversion.js new file mode 100644 index 000000000..8061be089 --- /dev/null +++ b/javascript/textualInversion.js @@ -0,0 +1,8 @@ + + +function start_training_textual_inversion(){ + requestProgress('ti') + gradioApp().querySelector('#ti_error').innerHTML='' + + return args_to_array(arguments) +} diff --git a/modules/devices.py b/modules/devices.py index 07bb23397..ff82f2f64 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -32,10 +32,9 @@ def enable_tf32(): errors.run(enable_tf32, "Enabling TF32") - device = get_optimal_device() device_codeformer = cpu if has_mps else device - +dtype = torch.float16 def randn(seed, shape): # Pytorch currently doesn't handle setting randomness correctly when the metal backend is used. diff --git a/modules/processing.py b/modules/processing.py index 7eeb5191c..8223423ab 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -56,7 +56,7 @@ class StableDiffusionProcessing: self.prompt: str = prompt self.prompt_for_display: str = None self.negative_prompt: str = (negative_prompt or "") - self.styles: str = styles + self.styles: list = styles or [] self.seed: int = seed self.subseed: int = subseed self.subseed_strength: float = subseed_strength @@ -271,7 +271,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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), - "Eta": (None if p.sampler.eta == p.sampler.default_eta else p.sampler.eta), + "Eta": (None if p.sampler is None or p.sampler.eta == p.sampler.default_eta else p.sampler.eta), } generation_params.update(p.extra_generation_params) @@ -295,8 +295,11 @@ def process_images(p: StableDiffusionProcessing) -> Processed: fix_seed(p) - os.makedirs(p.outpath_samples, exist_ok=True) - os.makedirs(p.outpath_grids, exist_ok=True) + if p.outpath_samples is not None: + os.makedirs(p.outpath_samples, exist_ok=True) + + if p.outpath_grids is not None: + os.makedirs(p.outpath_grids, exist_ok=True) modules.sd_hijack.model_hijack.apply_circular(p.tiling) @@ -323,7 +326,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: return create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration, position_in_batch) if os.path.exists(cmd_opts.embeddings_dir): - model_hijack.load_textual_inversion_embeddings(cmd_opts.embeddings_dir, p.sd_model) + model_hijack.embedding_db.load_textual_inversion_embeddings() infotexts = [] output_images = [] diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index fa7eaeb89..fd57e5c54 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -6,244 +6,41 @@ import torch import numpy as np from torch import einsum -from modules import prompt_parser +import modules.textual_inversion.textual_inversion +from modules import prompt_parser, devices, sd_hijack_optimizations, shared from modules.shared import opts, device, cmd_opts -from ldm.util import default -from einops import rearrange import ldm.modules.attention import ldm.modules.diffusionmodules.model - -# see https://github.com/basujindal/stable-diffusion/pull/117 for discussion -def split_cross_attention_forward_v1(self, x, context=None, mask=None): - h = self.heads - - q = self.to_q(x) - context = default(context, x) - k = self.to_k(context) - v = self.to_v(context) - del context, x - - q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) - - r1 = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device) - for i in range(0, q.shape[0], 2): - end = i + 2 - s1 = einsum('b i d, b j d -> b i j', q[i:end], k[i:end]) - s1 *= self.scale - - s2 = s1.softmax(dim=-1) - del s1 - - r1[i:end] = einsum('b i j, b j d -> b i d', s2, v[i:end]) - del s2 - - r2 = rearrange(r1, '(b h) n d -> b n (h d)', h=h) - del r1 - - return self.to_out(r2) +attention_CrossAttention_forward = ldm.modules.attention.CrossAttention.forward +diffusionmodules_model_nonlinearity = ldm.modules.diffusionmodules.model.nonlinearity +diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.AttnBlock.forward -# taken from https://github.com/Doggettx/stable-diffusion -def split_cross_attention_forward(self, x, context=None, mask=None): - h = self.heads +def apply_optimizations(): + if cmd_opts.opt_split_attention_v1: + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 + elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward + ldm.modules.diffusionmodules.model.nonlinearity = sd_hijack_optimizations.nonlinearity_hijack + ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward - q_in = self.to_q(x) - context = default(context, x) - k_in = self.to_k(context) * self.scale - v_in = self.to_v(context) - del context, x - q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q_in, k_in, v_in)) - del q_in, k_in, v_in +def undo_optimizations(): + ldm.modules.attention.CrossAttention.forward = attention_CrossAttention_forward + ldm.modules.diffusionmodules.model.nonlinearity = diffusionmodules_model_nonlinearity + ldm.modules.diffusionmodules.model.AttnBlock.forward = diffusionmodules_model_AttnBlock_forward - r1 = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device, dtype=q.dtype) - - stats = torch.cuda.memory_stats(q.device) - mem_active = stats['active_bytes.all.current'] - mem_reserved = stats['reserved_bytes.all.current'] - mem_free_cuda, _ = torch.cuda.mem_get_info(torch.cuda.current_device()) - mem_free_torch = mem_reserved - mem_active - mem_free_total = mem_free_cuda + mem_free_torch - - gb = 1024 ** 3 - tensor_size = q.shape[0] * q.shape[1] * k.shape[1] * q.element_size() - modifier = 3 if q.element_size() == 2 else 2.5 - mem_required = tensor_size * modifier - steps = 1 - - if mem_required > mem_free_total: - steps = 2 ** (math.ceil(math.log(mem_required / mem_free_total, 2))) - # print(f"Expected tensor size:{tensor_size/gb:0.1f}GB, cuda free:{mem_free_cuda/gb:0.1f}GB " - # f"torch free:{mem_free_torch/gb:0.1f} total:{mem_free_total/gb:0.1f} steps:{steps}") - - if steps > 64: - max_res = math.floor(math.sqrt(math.sqrt(mem_free_total / 2.5)) / 8) * 64 - raise RuntimeError(f'Not enough memory, use lower resolution (max approx. {max_res}x{max_res}). ' - f'Need: {mem_required / 64 / gb:0.1f}GB free, Have:{mem_free_total / gb:0.1f}GB free') - - slice_size = q.shape[1] // steps if (q.shape[1] % steps) == 0 else q.shape[1] - for i in range(0, q.shape[1], slice_size): - end = i + slice_size - s1 = einsum('b i d, b j d -> b i j', q[:, i:end], k) - - s2 = s1.softmax(dim=-1, dtype=q.dtype) - del s1 - - r1[:, i:end] = einsum('b i j, b j d -> b i d', s2, v) - del s2 - - del q, k, v - - r2 = rearrange(r1, '(b h) n d -> b n (h d)', h=h) - del r1 - - return self.to_out(r2) - -def nonlinearity_hijack(x): - # swish - t = torch.sigmoid(x) - x *= t - del t - - return x - -def cross_attention_attnblock_forward(self, x): - h_ = x - h_ = self.norm(h_) - q1 = self.q(h_) - k1 = self.k(h_) - v = self.v(h_) - - # compute attention - b, c, h, w = q1.shape - - q2 = q1.reshape(b, c, h*w) - del q1 - - q = q2.permute(0, 2, 1) # b,hw,c - del q2 - - k = k1.reshape(b, c, h*w) # b,c,hw - del k1 - - h_ = torch.zeros_like(k, device=q.device) - - stats = torch.cuda.memory_stats(q.device) - mem_active = stats['active_bytes.all.current'] - mem_reserved = stats['reserved_bytes.all.current'] - mem_free_cuda, _ = torch.cuda.mem_get_info(torch.cuda.current_device()) - mem_free_torch = mem_reserved - mem_active - mem_free_total = mem_free_cuda + mem_free_torch - - tensor_size = q.shape[0] * q.shape[1] * k.shape[2] * q.element_size() - mem_required = tensor_size * 2.5 - steps = 1 - - if mem_required > mem_free_total: - steps = 2**(math.ceil(math.log(mem_required / mem_free_total, 2))) - - slice_size = q.shape[1] // steps if (q.shape[1] % steps) == 0 else q.shape[1] - for i in range(0, q.shape[1], slice_size): - end = i + slice_size - - w1 = torch.bmm(q[:, i:end], k) # b,hw,hw w[b,i,j]=sum_c q[b,i,c]k[b,c,j] - w2 = w1 * (int(c)**(-0.5)) - del w1 - w3 = torch.nn.functional.softmax(w2, dim=2, dtype=q.dtype) - del w2 - - # attend to values - v1 = v.reshape(b, c, h*w) - w4 = w3.permute(0, 2, 1) # b,hw,hw (first hw of k, second of q) - del w3 - - h_[:, :, i:end] = torch.bmm(v1, w4) # b, c,hw (hw of q) h_[b,c,j] = sum_i v[b,c,i] w_[b,i,j] - del v1, w4 - - h2 = h_.reshape(b, c, h, w) - del h_ - - h3 = self.proj_out(h2) - del h2 - - h3 += x - - return h3 class StableDiffusionModelHijack: - ids_lookup = {} - word_embeddings = {} - word_embeddings_checksums = {} fixes = None comments = [] - dir_mtime = None layers = None circular_enabled = False clip = None - def load_textual_inversion_embeddings(self, dirname, model): - mt = os.path.getmtime(dirname) - if self.dir_mtime is not None and mt <= self.dir_mtime: - return - - self.dir_mtime = mt - self.ids_lookup.clear() - self.word_embeddings.clear() - - tokenizer = model.cond_stage_model.tokenizer - - def const_hash(a): - r = 0 - for v in a: - r = (r * 281 ^ int(v) * 997) & 0xFFFFFFFF - return r - - def process_file(path, filename): - name = os.path.splitext(filename)[0] - - data = torch.load(path, map_location="cpu") - - # textual inversion embeddings - if 'string_to_param' in data: - param_dict = data['string_to_param'] - if hasattr(param_dict, '_parameters'): - param_dict = getattr(param_dict, '_parameters') # fix for torch 1.12.1 loading saved file from torch 1.11 - assert len(param_dict) == 1, 'embedding file has multiple terms in it' - emb = next(iter(param_dict.items()))[1] - # diffuser concepts - elif type(data) == dict and type(next(iter(data.values()))) == torch.Tensor: - assert len(data.keys()) == 1, 'embedding file has multiple terms in it' - - emb = next(iter(data.values())) - if len(emb.shape) == 1: - emb = emb.unsqueeze(0) - - self.word_embeddings[name] = emb.detach().to(device) - self.word_embeddings_checksums[name] = f'{const_hash(emb.reshape(-1)*100)&0xffff:04x}' - - ids = tokenizer([name], add_special_tokens=False)['input_ids'][0] - - first_id = ids[0] - if first_id not in self.ids_lookup: - self.ids_lookup[first_id] = [] - self.ids_lookup[first_id].append((ids, name)) - - for fn in os.listdir(dirname): - try: - fullfn = os.path.join(dirname, fn) - - if os.stat(fullfn).st_size == 0: - continue - - process_file(fullfn, fn) - except Exception: - print(f"Error loading emedding {fn}:", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - continue - - print(f"Loaded a total of {len(self.word_embeddings)} textual inversion embeddings.") + embedding_db = modules.textual_inversion.textual_inversion.EmbeddingDatabase(cmd_opts.embeddings_dir) def hijack(self, m): model_embeddings = m.cond_stage_model.transformer.text_model.embeddings @@ -253,12 +50,7 @@ class StableDiffusionModelHijack: self.clip = m.cond_stage_model - if cmd_opts.opt_split_attention_v1: - ldm.modules.attention.CrossAttention.forward = split_cross_attention_forward_v1 - elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): - ldm.modules.attention.CrossAttention.forward = split_cross_attention_forward - ldm.modules.diffusionmodules.model.nonlinearity = nonlinearity_hijack - ldm.modules.diffusionmodules.model.AttnBlock.forward = cross_attention_attnblock_forward + apply_optimizations() def flatten(el): flattened = [flatten(children) for children in el.children()] @@ -296,7 +88,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): def __init__(self, wrapped, hijack): super().__init__() self.wrapped = wrapped - self.hijack = hijack + self.hijack: StableDiffusionModelHijack = hijack self.tokenizer = wrapped.tokenizer self.max_length = wrapped.max_length self.token_mults = {} @@ -317,7 +109,6 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): if mult != 1.0: self.token_mults[ident] = mult - def tokenize_line(self, line, used_custom_terms, hijack_comments): id_start = self.wrapped.tokenizer.bos_token_id id_end = self.wrapped.tokenizer.eos_token_id @@ -339,28 +130,19 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): while i < len(tokens): token = tokens[i] - possible_matches = self.hijack.ids_lookup.get(token, None) + embedding = self.hijack.embedding_db.find_embedding_at_position(tokens, i) - if possible_matches is None: + if embedding is None: remade_tokens.append(token) multipliers.append(weight) + i += 1 else: - found = False - for ids, word in possible_matches: - if tokens[i:i + len(ids)] == ids: - emb_len = int(self.hijack.word_embeddings[word].shape[0]) - fixes.append((len(remade_tokens), word)) - remade_tokens += [0] * emb_len - multipliers += [weight] * emb_len - i += len(ids) - 1 - found = True - used_custom_terms.append((word, self.hijack.word_embeddings_checksums[word])) - break - - if not found: - remade_tokens.append(token) - multipliers.append(weight) - i += 1 + emb_len = int(embedding.vec.shape[0]) + fixes.append((len(remade_tokens), embedding)) + remade_tokens += [0] * emb_len + multipliers += [weight] * emb_len + used_custom_terms.append((embedding.name, embedding.checksum())) + i += emb_len if len(remade_tokens) > maxlen - 2: vocab = {v: k for k, v in self.wrapped.tokenizer.get_vocab().items()} @@ -431,32 +213,23 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): while i < len(tokens): token = tokens[i] - possible_matches = self.hijack.ids_lookup.get(token, None) + embedding = self.hijack.embedding_db.find_embedding_at_position(tokens, i) mult_change = self.token_mults.get(token) if opts.enable_emphasis else None if mult_change is not None: mult *= mult_change - elif possible_matches is None: + i += 1 + elif embedding is None: remade_tokens.append(token) multipliers.append(mult) + i += 1 else: - found = False - for ids, word in possible_matches: - if tokens[i:i+len(ids)] == ids: - emb_len = int(self.hijack.word_embeddings[word].shape[0]) - fixes.append((len(remade_tokens), word)) - remade_tokens += [0] * emb_len - multipliers += [mult] * emb_len - i += len(ids) - 1 - found = True - used_custom_terms.append((word, self.hijack.word_embeddings_checksums[word])) - break - - if not found: - remade_tokens.append(token) - multipliers.append(mult) - - i += 1 + emb_len = int(embedding.vec.shape[0]) + fixes.append((len(remade_tokens), embedding)) + remade_tokens += [0] * emb_len + multipliers += [mult] * emb_len + used_custom_terms.append((embedding.name, embedding.checksum())) + i += emb_len if len(remade_tokens) > maxlen - 2: vocab = {v: k for k, v in self.wrapped.tokenizer.get_vocab().items()} @@ -464,6 +237,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): overflowing_words = [vocab.get(int(x), "") for x in ovf] overflowing_text = self.wrapped.tokenizer.convert_tokens_to_string(''.join(overflowing_words)) hijack_comments.append(f"Warning: too many input tokens; some ({len(overflowing_words)}) have been truncated:\n{overflowing_text}\n") + token_count = len(remade_tokens) remade_tokens = remade_tokens + [id_end] * (maxlen - 2 - len(remade_tokens)) remade_tokens = [id_start] + remade_tokens[0:maxlen-2] + [id_end] @@ -484,7 +258,6 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): else: batch_multipliers, remade_batch_tokens, used_custom_terms, hijack_comments, hijack_fixes, token_count = self.process_text(text) - self.hijack.fixes = hijack_fixes self.hijack.comments = hijack_comments @@ -517,14 +290,19 @@ class EmbeddingsWithFixes(torch.nn.Module): inputs_embeds = self.wrapped(input_ids) - if batch_fixes is not None: - for fixes, tensor in zip(batch_fixes, inputs_embeds): - for offset, word in fixes: - emb = self.embeddings.word_embeddings[word] - emb_len = min(tensor.shape[0]-offset-1, emb.shape[0]) - tensor[offset+1:offset+1+emb_len] = self.embeddings.word_embeddings[word][0:emb_len] + if batch_fixes is None or len(batch_fixes) == 0 or max([len(x) for x in batch_fixes]) == 0: + return inputs_embeds - return inputs_embeds + vecs = [] + for fixes, tensor in zip(batch_fixes, inputs_embeds): + for offset, embedding in fixes: + emb = embedding.vec + emb_len = min(tensor.shape[0]-offset-1, emb.shape[0]) + tensor = torch.cat([tensor[0:offset+1], emb[0:emb_len], tensor[offset+1+emb_len:]]) + + vecs.append(tensor) + + return torch.stack(vecs) def add_circular_option_to_conv_2d(): diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py new file mode 100644 index 000000000..9c079e578 --- /dev/null +++ b/modules/sd_hijack_optimizations.py @@ -0,0 +1,164 @@ +import math +import torch +from torch import einsum + +from ldm.util import default +from einops import rearrange + + +# see https://github.com/basujindal/stable-diffusion/pull/117 for discussion +def split_cross_attention_forward_v1(self, x, context=None, mask=None): + h = self.heads + + q = self.to_q(x) + context = default(context, x) + k = self.to_k(context) + v = self.to_v(context) + del context, x + + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) + + r1 = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device) + for i in range(0, q.shape[0], 2): + end = i + 2 + s1 = einsum('b i d, b j d -> b i j', q[i:end], k[i:end]) + s1 *= self.scale + + s2 = s1.softmax(dim=-1) + del s1 + + r1[i:end] = einsum('b i j, b j d -> b i d', s2, v[i:end]) + del s2 + + r2 = rearrange(r1, '(b h) n d -> b n (h d)', h=h) + del r1 + + return self.to_out(r2) + + +# taken from https://github.com/Doggettx/stable-diffusion +def split_cross_attention_forward(self, x, context=None, mask=None): + h = self.heads + + q_in = self.to_q(x) + context = default(context, x) + k_in = self.to_k(context) * self.scale + v_in = self.to_v(context) + del context, x + + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q_in, k_in, v_in)) + del q_in, k_in, v_in + + r1 = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device, dtype=q.dtype) + + stats = torch.cuda.memory_stats(q.device) + mem_active = stats['active_bytes.all.current'] + mem_reserved = stats['reserved_bytes.all.current'] + mem_free_cuda, _ = torch.cuda.mem_get_info(torch.cuda.current_device()) + mem_free_torch = mem_reserved - mem_active + mem_free_total = mem_free_cuda + mem_free_torch + + gb = 1024 ** 3 + tensor_size = q.shape[0] * q.shape[1] * k.shape[1] * q.element_size() + modifier = 3 if q.element_size() == 2 else 2.5 + mem_required = tensor_size * modifier + steps = 1 + + if mem_required > mem_free_total: + steps = 2 ** (math.ceil(math.log(mem_required / mem_free_total, 2))) + # print(f"Expected tensor size:{tensor_size/gb:0.1f}GB, cuda free:{mem_free_cuda/gb:0.1f}GB " + # f"torch free:{mem_free_torch/gb:0.1f} total:{mem_free_total/gb:0.1f} steps:{steps}") + + if steps > 64: + max_res = math.floor(math.sqrt(math.sqrt(mem_free_total / 2.5)) / 8) * 64 + raise RuntimeError(f'Not enough memory, use lower resolution (max approx. {max_res}x{max_res}). ' + f'Need: {mem_required / 64 / gb:0.1f}GB free, Have:{mem_free_total / gb:0.1f}GB free') + + slice_size = q.shape[1] // steps if (q.shape[1] % steps) == 0 else q.shape[1] + for i in range(0, q.shape[1], slice_size): + end = i + slice_size + s1 = einsum('b i d, b j d -> b i j', q[:, i:end], k) + + s2 = s1.softmax(dim=-1, dtype=q.dtype) + del s1 + + r1[:, i:end] = einsum('b i j, b j d -> b i d', s2, v) + del s2 + + del q, k, v + + r2 = rearrange(r1, '(b h) n d -> b n (h d)', h=h) + del r1 + + return self.to_out(r2) + +def nonlinearity_hijack(x): + # swish + t = torch.sigmoid(x) + x *= t + del t + + return x + +def cross_attention_attnblock_forward(self, x): + h_ = x + h_ = self.norm(h_) + q1 = self.q(h_) + k1 = self.k(h_) + v = self.v(h_) + + # compute attention + b, c, h, w = q1.shape + + q2 = q1.reshape(b, c, h*w) + del q1 + + q = q2.permute(0, 2, 1) # b,hw,c + del q2 + + k = k1.reshape(b, c, h*w) # b,c,hw + del k1 + + h_ = torch.zeros_like(k, device=q.device) + + stats = torch.cuda.memory_stats(q.device) + mem_active = stats['active_bytes.all.current'] + mem_reserved = stats['reserved_bytes.all.current'] + mem_free_cuda, _ = torch.cuda.mem_get_info(torch.cuda.current_device()) + mem_free_torch = mem_reserved - mem_active + mem_free_total = mem_free_cuda + mem_free_torch + + tensor_size = q.shape[0] * q.shape[1] * k.shape[2] * q.element_size() + mem_required = tensor_size * 2.5 + steps = 1 + + if mem_required > mem_free_total: + steps = 2**(math.ceil(math.log(mem_required / mem_free_total, 2))) + + slice_size = q.shape[1] // steps if (q.shape[1] % steps) == 0 else q.shape[1] + for i in range(0, q.shape[1], slice_size): + end = i + slice_size + + w1 = torch.bmm(q[:, i:end], k) # b,hw,hw w[b,i,j]=sum_c q[b,i,c]k[b,c,j] + w2 = w1 * (int(c)**(-0.5)) + del w1 + w3 = torch.nn.functional.softmax(w2, dim=2, dtype=q.dtype) + del w2 + + # attend to values + v1 = v.reshape(b, c, h*w) + w4 = w3.permute(0, 2, 1) # b,hw,hw (first hw of k, second of q) + del w3 + + h_[:, :, i:end] = torch.bmm(v1, w4) # b, c,hw (hw of q) h_[b,c,j] = sum_i v[b,c,i] w_[b,i,j] + del v1, w4 + + h2 = h_.reshape(b, c, h, w) + del h_ + + h3 = self.proj_out(h2) + del h2 + + h3 += x + + return h3 diff --git a/modules/sd_models.py b/modules/sd_models.py index 2539f14cd..5b3dbdc79 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -8,7 +8,7 @@ from omegaconf import OmegaConf from ldm.util import instantiate_from_config -from modules import shared, modelloader +from modules import shared, modelloader, devices from modules.paths import models_path model_dir = "Stable-diffusion" @@ -134,6 +134,8 @@ def load_model_weights(model, checkpoint_file, sd_model_hash): if not shared.cmd_opts.no_half: model.half() + devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16 + model.sd_model_hash = sd_model_hash model.sd_model_checkpint = checkpoint_file diff --git a/modules/shared.py b/modules/shared.py index ac968b2d2..ac0bc480c 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -78,6 +78,7 @@ class State: current_latent = None current_image = None current_image_sampling_step = 0 + textinfo = None def interrupt(self): self.interrupted = True @@ -88,7 +89,7 @@ class State: self.current_image_sampling_step = 0 def get_job_timestamp(self): - return datetime.datetime.now().strftime("%Y%m%d%H%M%S") + return datetime.datetime.now().strftime("%Y%m%d%H%M%S") # shouldn't this return job_timestamp? state = State() diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py new file mode 100644 index 000000000..7e134a08f --- /dev/null +++ b/modules/textual_inversion/dataset.py @@ -0,0 +1,76 @@ +import os +import numpy as np +import PIL +import torch +from PIL import Image +from torch.utils.data import Dataset +from torchvision import transforms + +import random +import tqdm + + +class PersonalizedBase(Dataset): + def __init__(self, data_root, size=None, repeats=100, flip_p=0.5, placeholder_token="*", width=512, height=512, model=None, device=None, template_file=None): + + self.placeholder_token = placeholder_token + + self.size = size + self.width = width + self.height = height + self.flip = transforms.RandomHorizontalFlip(p=flip_p) + + self.dataset = [] + + with open(template_file, "r") as file: + lines = [x.strip() for x in file.readlines()] + + self.lines = lines + + assert data_root, 'dataset directory not specified' + + self.image_paths = [os.path.join(data_root, file_path) for file_path in os.listdir(data_root)] + print("Preparing dataset...") + for path in tqdm.tqdm(self.image_paths): + image = Image.open(path) + image = image.convert('RGB') + image = image.resize((self.width, self.height), PIL.Image.BICUBIC) + + filename = os.path.basename(path) + filename_tokens = os.path.splitext(filename)[0].replace('_', '-').replace(' ', '-').split('-') + filename_tokens = [token for token in filename_tokens if token.isalpha()] + + npimage = np.array(image).astype(np.uint8) + npimage = (npimage / 127.5 - 1.0).astype(np.float32) + + torchdata = torch.from_numpy(npimage).to(device=device, dtype=torch.float32) + torchdata = torch.moveaxis(torchdata, 2, 0) + + init_latent = model.get_first_stage_encoding(model.encode_first_stage(torchdata.unsqueeze(dim=0))).squeeze() + + self.dataset.append((init_latent, filename_tokens)) + + self.length = len(self.dataset) * repeats + + self.initial_indexes = np.arange(self.length) % len(self.dataset) + self.indexes = None + self.shuffle() + + def shuffle(self): + self.indexes = self.initial_indexes[torch.randperm(self.initial_indexes.shape[0])] + + def __len__(self): + return self.length + + def __getitem__(self, i): + if i % len(self.dataset) == 0: + self.shuffle() + + index = self.indexes[i % len(self.indexes)] + x, filename_tokens = self.dataset[index] + + text = random.choice(self.lines) + text = text.replace("[name]", self.placeholder_token) + text = text.replace("[filewords]", ' '.join(filename_tokens)) + + return x, text diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py new file mode 100644 index 000000000..c0baaace2 --- /dev/null +++ b/modules/textual_inversion/textual_inversion.py @@ -0,0 +1,258 @@ +import os +import sys +import traceback + +import torch +import tqdm +import html +import datetime + +from modules import shared, devices, sd_hijack, processing +import modules.textual_inversion.dataset + + +class Embedding: + def __init__(self, vec, name, step=None): + self.vec = vec + self.name = name + self.step = step + self.cached_checksum = None + + def save(self, filename): + embedding_data = { + "string_to_token": {"*": 265}, + "string_to_param": {"*": self.vec}, + "name": self.name, + "step": self.step, + } + + torch.save(embedding_data, filename) + + def checksum(self): + if self.cached_checksum is not None: + return self.cached_checksum + + def const_hash(a): + r = 0 + for v in a: + r = (r * 281 ^ int(v) * 997) & 0xFFFFFFFF + return r + + self.cached_checksum = f'{const_hash(self.vec.reshape(-1) * 100) & 0xffff:04x}' + return self.cached_checksum + +class EmbeddingDatabase: + def __init__(self, embeddings_dir): + self.ids_lookup = {} + self.word_embeddings = {} + self.dir_mtime = None + self.embeddings_dir = embeddings_dir + + def register_embedding(self, embedding, model): + + self.word_embeddings[embedding.name] = embedding + + ids = model.cond_stage_model.tokenizer([embedding.name], add_special_tokens=False)['input_ids'][0] + + first_id = ids[0] + if first_id not in self.ids_lookup: + self.ids_lookup[first_id] = [] + self.ids_lookup[first_id].append((ids, embedding)) + + return embedding + + def load_textual_inversion_embeddings(self): + mt = os.path.getmtime(self.embeddings_dir) + if self.dir_mtime is not None and mt <= self.dir_mtime: + return + + self.dir_mtime = mt + self.ids_lookup.clear() + self.word_embeddings.clear() + + def process_file(path, filename): + name = os.path.splitext(filename)[0] + + data = torch.load(path, map_location="cpu") + + # textual inversion embeddings + if 'string_to_param' in data: + param_dict = data['string_to_param'] + if hasattr(param_dict, '_parameters'): + param_dict = getattr(param_dict, '_parameters') # fix for torch 1.12.1 loading saved file from torch 1.11 + assert len(param_dict) == 1, 'embedding file has multiple terms in it' + emb = next(iter(param_dict.items()))[1] + # diffuser concepts + elif type(data) == dict and type(next(iter(data.values()))) == torch.Tensor: + assert len(data.keys()) == 1, 'embedding file has multiple terms in it' + + emb = next(iter(data.values())) + if len(emb.shape) == 1: + emb = emb.unsqueeze(0) + else: + raise Exception(f"Couldn't identify {filename} as neither textual inversion embedding nor diffuser concept.") + + vec = emb.detach().to(devices.device, dtype=torch.float32) + embedding = Embedding(vec, name) + embedding.step = data.get('step', None) + self.register_embedding(embedding, shared.sd_model) + + for fn in os.listdir(self.embeddings_dir): + try: + fullfn = os.path.join(self.embeddings_dir, fn) + + if os.stat(fullfn).st_size == 0: + continue + + process_file(fullfn, fn) + except Exception: + print(f"Error loading emedding {fn}:", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + continue + + print(f"Loaded a total of {len(self.word_embeddings)} textual inversion embeddings.") + + 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 + + for ids, embedding in possible_matches: + if tokens[offset:offset + len(ids)] == ids: + return embedding + + return None + + + +def create_embedding(name, num_vectors_per_token): + init_text = '*' + + cond_model = shared.sd_model.cond_stage_model + embedding_layer = cond_model.wrapped.transformer.text_model.embeddings + + ids = cond_model.tokenizer(init_text, max_length=num_vectors_per_token, return_tensors="pt", add_special_tokens=False)["input_ids"] + embedded = embedding_layer(ids.to(devices.device)).squeeze(0) + vec = torch.zeros((num_vectors_per_token, embedded.shape[1]), device=devices.device) + + for i in range(num_vectors_per_token): + vec[i] = embedded[i * int(embedded.shape[0]) // num_vectors_per_token] + + fn = os.path.join(shared.cmd_opts.embeddings_dir, f"{name}.pt") + assert not os.path.exists(fn), f"file {fn} already exists" + + embedding = Embedding(vec, name) + embedding.step = 0 + embedding.save(fn) + + return fn + + +def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, create_image_every, save_embedding_every, template_file): + assert embedding_name, 'embedding not selected' + + shared.state.textinfo = "Initializing textual inversion training..." + shared.state.job_count = steps + + filename = os.path.join(shared.cmd_opts.embeddings_dir, f'{embedding_name}.pt') + + log_directory = os.path.join(log_directory, datetime.datetime.now().strftime("%Y-%d-%m"), embedding_name) + + if save_embedding_every > 0: + embedding_dir = os.path.join(log_directory, "embeddings") + os.makedirs(embedding_dir, exist_ok=True) + else: + embedding_dir = None + + if create_image_every > 0: + images_dir = os.path.join(log_directory, "images") + os.makedirs(images_dir, exist_ok=True) + else: + images_dir = None + + cond_model = shared.sd_model.cond_stage_model + + shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." + with torch.autocast("cuda"): + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=512, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) + + hijack = sd_hijack.model_hijack + + embedding = hijack.embedding_db.word_embeddings[embedding_name] + embedding.vec.requires_grad = True + + optimizer = torch.optim.AdamW([embedding.vec], lr=learn_rate) + + losses = torch.zeros((32,)) + + last_saved_file = "" + last_saved_image = "" + + ititial_step = embedding.step or 0 + if ititial_step > steps: + return embedding, filename + + pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) + for i, (x, text) in pbar: + embedding.step = i + ititial_step + + if embedding.step > steps: + break + + if shared.state.interrupted: + break + + with torch.autocast("cuda"): + c = cond_model([text]) + loss = shared.sd_model(x.unsqueeze(0), c)[0] + + losses[embedding.step % losses.shape[0]] = loss.item() + + optimizer.zero_grad() + loss.backward() + optimizer.step() + + pbar.set_description(f"loss: {losses.mean():.7f}") + + if embedding.step > 0 and embedding_dir is not None and embedding.step % save_embedding_every == 0: + last_saved_file = os.path.join(embedding_dir, f'{embedding_name}-{embedding.step}.pt') + embedding.save(last_saved_file) + + if embedding.step > 0 and images_dir is not None and embedding.step % create_image_every == 0: + last_saved_image = os.path.join(images_dir, f'{embedding_name}-{embedding.step}.png') + + p = processing.StableDiffusionProcessingTxt2Img( + sd_model=shared.sd_model, + prompt=text, + steps=20, + do_not_save_grid=True, + do_not_save_samples=True, + ) + + processed = processing.process_images(p) + image = processed.images[0] + + shared.state.current_image = image + image.save(last_saved_image) + + last_saved_image += f", prompt: {text}" + + shared.state.job_no = embedding.step + + shared.state.textinfo = f""" +

+Loss: {losses.mean():.7f}
+Step: {embedding.step}
+Last prompt: {html.escape(text)}
+Last saved embedding: {html.escape(last_saved_file)}
+Last saved image: {html.escape(last_saved_image)}
+

+""" + + embedding.cached_checksum = None + embedding.save(filename) + + return embedding, filename + diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py new file mode 100644 index 000000000..ce3677a98 --- /dev/null +++ b/modules/textual_inversion/ui.py @@ -0,0 +1,32 @@ +import html + +import gradio as gr + +import modules.textual_inversion.textual_inversion as ti +from modules import sd_hijack, shared + + +def create_embedding(name, nvpt): + filename = ti.create_embedding(name, nvpt) + + sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() + + return gr.Dropdown.update(choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())), f"Created: {filename}", "" + + +def train_embedding(*args): + + try: + sd_hijack.undo_optimizations() + + embedding, filename = ti.train_embedding(*args) + + res = f""" +Training {'interrupted' if shared.state.interrupted else 'finished'} after {embedding.step} steps. +Embedding saved to {html.escape(filename)} +""" + return res, "" + except Exception: + raise + finally: + sd_hijack.apply_optimizations() diff --git a/modules/ui.py b/modules/ui.py index 15572bb0a..57aef6ff1 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -21,6 +21,7 @@ import gradio as gr import gradio.utils import gradio.routes +from modules import sd_hijack from modules.paths import script_path from modules.shared import opts, cmd_opts import modules.shared as shared @@ -32,6 +33,7 @@ import modules.gfpgan_model import modules.codeformer_model import modules.styles import modules.generation_parameters_copypaste +import modules.textual_inversion.ui # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI mimetypes.init() @@ -142,8 +144,8 @@ def save_files(js_data, images, index): return '', '', plaintext_to_html(f"Saved: {filenames[0]}") -def wrap_gradio_call(func): - def f(*args, **kwargs): +def wrap_gradio_call(func, extra_outputs=None): + def f(*args, extra_outputs_array=extra_outputs, **kwargs): run_memmon = opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled if run_memmon: shared.mem_mon.monitor() @@ -159,7 +161,10 @@ def wrap_gradio_call(func): shared.state.job = "" shared.state.job_count = 0 - res = [None, '', f"
{plaintext_to_html(type(e).__name__+': '+str(e))}
"] + if extra_outputs_array is None: + extra_outputs_array = [None, ''] + + res = extra_outputs_array + [f"
{plaintext_to_html(type(e).__name__+': '+str(e))}
"] elapsed = time.perf_counter() - t @@ -179,6 +184,7 @@ def wrap_gradio_call(func): res[-1] += f"

Time taken: {elapsed:.2f}s

{vram_html}
" shared.state.interrupted = False + shared.state.job_count = 0 return tuple(res) @@ -187,7 +193,7 @@ def wrap_gradio_call(func): def check_progress_call(id_part): if shared.state.job_count == 0: - return "", gr_show(False), gr_show(False) + return "", gr_show(False), gr_show(False), gr_show(False) progress = 0 @@ -219,13 +225,19 @@ def check_progress_call(id_part): else: preview_visibility = gr_show(True) - return f"

{progressbar}

", preview_visibility, image + if shared.state.textinfo is not None: + textinfo_result = gr.HTML.update(value=shared.state.textinfo, visible=True) + else: + textinfo_result = gr_show(False) + + return f"

{progressbar}

", preview_visibility, image, textinfo_result def check_progress_call_initial(id_part): shared.state.job_count = -1 shared.state.current_latent = None shared.state.current_image = None + shared.state.textinfo = None return check_progress_call(id_part) @@ -399,13 +411,16 @@ def create_toprow(is_img2img): return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, paste -def setup_progressbar(progressbar, preview, id_part): +def setup_progressbar(progressbar, preview, id_part, textinfo=None): + if textinfo is None: + textinfo = gr.HTML(visible=False) + check_progress = gr.Button('Check progress', elem_id=f"{id_part}_check_progress", visible=False) check_progress.click( fn=lambda: check_progress_call(id_part), show_progress=False, inputs=[], - outputs=[progressbar, preview, preview], + outputs=[progressbar, preview, preview, textinfo], ) check_progress_initial = gr.Button('Check progress (first)', elem_id=f"{id_part}_check_progress_initial", visible=False) @@ -413,11 +428,14 @@ def setup_progressbar(progressbar, preview, id_part): fn=lambda: check_progress_call_initial(id_part), show_progress=False, inputs=[], - outputs=[progressbar, preview, preview], + outputs=[progressbar, preview, preview, textinfo], ) -def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): +def create_ui(wrap_gradio_gpu_call): + import modules.img2img + import modules.txt2img + with gr.Blocks(analytics_enabled=False) as txt2img_interface: txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, paste = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) @@ -483,7 +501,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) txt2img_args = dict( - fn=txt2img, + fn=wrap_gradio_gpu_call(modules.txt2img.txt2img), _js="submit", inputs=[ txt2img_prompt, @@ -675,7 +693,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): ) img2img_args = dict( - fn=img2img, + fn=wrap_gradio_gpu_call(modules.img2img.img2img), _js="submit_img2img", inputs=[ dummy_component, @@ -828,7 +846,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): open_extras_folder = gr.Button('Open output directory', elem_id=button_id) submit.click( - fn=run_extras, + fn=wrap_gradio_gpu_call(modules.extras.run_extras), _js="get_extras_tab_index", inputs=[ dummy_component, @@ -878,7 +896,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): pnginfo_send_to_img2img = gr.Button('Send to img2img') image.change( - fn=wrap_gradio_call(run_pnginfo), + fn=wrap_gradio_call(modules.extras.run_pnginfo), inputs=[image], outputs=[html, generation_info, html2], ) @@ -887,7 +905,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): with gr.Row().style(equal_height=False): with gr.Column(variant='panel'): gr.HTML(value="

A merger of the two checkpoints will be generated in your checkpoint directory.

") - + with gr.Row(): primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary Model Name") secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary Model Name") @@ -896,10 +914,96 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): interp_method = gr.Radio(choices=["Weighted Sum", "Sigmoid", "Inverse Sigmoid"], value="Weighted Sum", label="Interpolation Method") save_as_half = gr.Checkbox(value=False, label="Safe as float16") modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary') - + with gr.Column(variant='panel'): submit_result = gr.Textbox(elem_id="modelmerger_result", show_label=False) + sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() + + with gr.Blocks() as textual_inversion_interface: + with gr.Row().style(equal_height=False): + with gr.Column(): + with gr.Group(): + gr.HTML(value="

Create a new embedding

") + + new_embedding_name = gr.Textbox(label="Name") + nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1) + + with gr.Row(): + with gr.Column(scale=3): + gr.HTML(value="") + + with gr.Column(): + create_embedding = gr.Button(value="Create", variant='primary') + + with gr.Group(): + gr.HTML(value="

Train an embedding; must specify a directory with a set of 512x512 images

") + train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) + learn_rate = gr.Number(label='Learning rate', value=5.0e-03) + dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") + log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") + template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) + steps = gr.Number(label='Max steps', value=100000, precision=0) + create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=1000, precision=0) + save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=1000, precision=0) + + with gr.Row(): + with gr.Column(scale=2): + gr.HTML(value="") + + with gr.Column(): + with gr.Row(): + interrupt_training = gr.Button(value="Interrupt") + train_embedding = gr.Button(value="Train", variant='primary') + + with gr.Column(): + progressbar = gr.HTML(elem_id="ti_progressbar") + ti_output = gr.Text(elem_id="ti_output", value="", show_label=False) + + ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(grid=4) + ti_preview = gr.Image(elem_id='ti_preview', visible=False) + ti_progress = gr.HTML(elem_id="ti_progress", value="") + ti_outcome = gr.HTML(elem_id="ti_error", value="") + setup_progressbar(progressbar, ti_preview, 'ti', textinfo=ti_progress) + + create_embedding.click( + fn=modules.textual_inversion.ui.create_embedding, + inputs=[ + new_embedding_name, + nvpt, + ], + outputs=[ + train_embedding_name, + ti_output, + ti_outcome, + ] + ) + + train_embedding.click( + fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]), + _js="start_training_textual_inversion", + inputs=[ + train_embedding_name, + learn_rate, + dataset_directory, + log_directory, + steps, + create_image_every, + save_embedding_every, + template_file, + ], + outputs=[ + ti_output, + ti_outcome, + ] + ) + + interrupt_training.click( + fn=lambda: shared.state.interrupt(), + inputs=[], + outputs=[], + ) + def create_setting_component(key): def fun(): return opts.data[key] if key in opts.data else opts.data_labels[key].default @@ -1011,6 +1115,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): (extras_interface, "Extras", "extras"), (pnginfo_interface, "PNG Info", "pnginfo"), (modelmerger_interface, "Checkpoint Merger", "modelmerger"), + (textual_inversion_interface, "Textual inversion", "ti"), (settings_interface, "Settings", "settings"), ] @@ -1044,11 +1149,11 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): def modelmerger(*args): try: - results = run_modelmerger(*args) + results = modules.extras.run_modelmerger(*args) except Exception as e: print("Error loading/saving model file:", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) - modules.sd_models.list_models() #To remove the potentially missing models from the list + modules.sd_models.list_models() # to remove the potentially missing models from the list return ["Error loading/saving model file. It doesn't exist or the name contains illegal characters"] + [gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(3)] return results diff --git a/style.css b/style.css index 79d6bb0dc..39586bf18 100644 --- a/style.css +++ b/style.css @@ -157,7 +157,7 @@ button{ max-width: 10em; } -#txt2img_preview, #img2img_preview{ +#txt2img_preview, #img2img_preview, #ti_preview{ position: absolute; width: 320px; left: 0; @@ -172,18 +172,18 @@ button{ } @media screen and (min-width: 768px) { - #txt2img_preview, #img2img_preview { + #txt2img_preview, #img2img_preview, #ti_preview { position: absolute; } } @media screen and (max-width: 767px) { - #txt2img_preview, #img2img_preview { + #txt2img_preview, #img2img_preview, #ti_preview { position: relative; } } -#txt2img_preview div.left-0.top-0, #img2img_preview div.left-0.top-0{ +#txt2img_preview div.left-0.top-0, #img2img_preview div.left-0.top-0, #ti_preview div.left-0.top-0{ display: none; } @@ -247,7 +247,7 @@ input[type="range"]{ #txt2img_negative_prompt, #img2img_negative_prompt{ } -#txt2img_progressbar, #img2img_progressbar{ +#txt2img_progressbar, #img2img_progressbar, #ti_progressbar{ position: absolute; z-index: 1000; right: 0; diff --git a/textual_inversion_templates/style.txt b/textual_inversion_templates/style.txt new file mode 100644 index 000000000..15af2d6b8 --- /dev/null +++ b/textual_inversion_templates/style.txt @@ -0,0 +1,19 @@ +a painting, art by [name] +a rendering, art by [name] +a cropped painting, art by [name] +the painting, art by [name] +a clean painting, art by [name] +a dirty painting, art by [name] +a dark painting, art by [name] +a picture, art by [name] +a cool painting, art by [name] +a close-up painting, art by [name] +a bright painting, art by [name] +a cropped painting, art by [name] +a good painting, art by [name] +a close-up painting, art by [name] +a rendition, art by [name] +a nice painting, art by [name] +a small painting, art by [name] +a weird painting, art by [name] +a large painting, art by [name] diff --git a/textual_inversion_templates/style_filewords.txt b/textual_inversion_templates/style_filewords.txt new file mode 100644 index 000000000..b3a8159a8 --- /dev/null +++ b/textual_inversion_templates/style_filewords.txt @@ -0,0 +1,19 @@ +a painting of [filewords], art by [name] +a rendering of [filewords], art by [name] +a cropped painting of [filewords], art by [name] +the painting of [filewords], art by [name] +a clean painting of [filewords], art by [name] +a dirty painting of [filewords], art by [name] +a dark painting of [filewords], art by [name] +a picture of [filewords], art by [name] +a cool painting of [filewords], art by [name] +a close-up painting of [filewords], art by [name] +a bright painting of [filewords], art by [name] +a cropped painting of [filewords], art by [name] +a good painting of [filewords], art by [name] +a close-up painting of [filewords], art by [name] +a rendition of [filewords], art by [name] +a nice painting of [filewords], art by [name] +a small painting of [filewords], art by [name] +a weird painting of [filewords], art by [name] +a large painting of [filewords], art by [name] diff --git a/textual_inversion_templates/subject.txt b/textual_inversion_templates/subject.txt new file mode 100644 index 000000000..79f36aa05 --- /dev/null +++ b/textual_inversion_templates/subject.txt @@ -0,0 +1,27 @@ +a photo of a [name] +a rendering of a [name] +a cropped photo of the [name] +the photo of a [name] +a photo of a clean [name] +a photo of a dirty [name] +a dark photo of the [name] +a photo of my [name] +a photo of the cool [name] +a close-up photo of a [name] +a bright photo of the [name] +a cropped photo of a [name] +a photo of the [name] +a good photo of the [name] +a photo of one [name] +a close-up photo of the [name] +a rendition of the [name] +a photo of the clean [name] +a rendition of a [name] +a photo of a nice [name] +a good photo of a [name] +a photo of the nice [name] +a photo of the small [name] +a photo of the weird [name] +a photo of the large [name] +a photo of a cool [name] +a photo of a small [name] diff --git a/textual_inversion_templates/subject_filewords.txt b/textual_inversion_templates/subject_filewords.txt new file mode 100644 index 000000000..008652a6b --- /dev/null +++ b/textual_inversion_templates/subject_filewords.txt @@ -0,0 +1,27 @@ +a photo of a [name], [filewords] +a rendering of a [name], [filewords] +a cropped photo of the [name], [filewords] +the photo of a [name], [filewords] +a photo of a clean [name], [filewords] +a photo of a dirty [name], [filewords] +a dark photo of the [name], [filewords] +a photo of my [name], [filewords] +a photo of the cool [name], [filewords] +a close-up photo of a [name], [filewords] +a bright photo of the [name], [filewords] +a cropped photo of a [name], [filewords] +a photo of the [name], [filewords] +a good photo of the [name], [filewords] +a photo of one [name], [filewords] +a close-up photo of the [name], [filewords] +a rendition of the [name], [filewords] +a photo of the clean [name], [filewords] +a rendition of a [name], [filewords] +a photo of a nice [name], [filewords] +a good photo of a [name], [filewords] +a photo of the nice [name], [filewords] +a photo of the small [name], [filewords] +a photo of the weird [name], [filewords] +a photo of the large [name], [filewords] +a photo of a cool [name], [filewords] +a photo of a small [name], [filewords] diff --git a/webui.py b/webui.py index b8cccd546..19fdcdd4d 100644 --- a/webui.py +++ b/webui.py @@ -12,7 +12,6 @@ import modules.bsrgan_model as bsrgan import modules.extras import modules.face_restoration import modules.gfpgan_model as gfpgan -import modules.img2img import modules.ldsr_model as ldsr import modules.lowvram import modules.realesrgan_model as realesrgan @@ -21,7 +20,6 @@ import modules.sd_hijack import modules.sd_models import modules.shared as shared import modules.swinir_model as swinir -import modules.txt2img import modules.ui from modules import modelloader from modules.paths import script_path @@ -46,7 +44,7 @@ def wrap_queued_call(func): return f -def wrap_gradio_gpu_call(func): +def wrap_gradio_gpu_call(func, extra_outputs=None): def f(*args, **kwargs): devices.torch_gc() @@ -58,6 +56,7 @@ def wrap_gradio_gpu_call(func): shared.state.current_image = None shared.state.current_image_sampling_step = 0 shared.state.interrupted = False + shared.state.textinfo = None with queue_lock: res = func(*args, **kwargs) @@ -69,7 +68,7 @@ def wrap_gradio_gpu_call(func): return res - return modules.ui.wrap_gradio_call(f) + return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) modules.scripts.load_scripts(os.path.join(script_path, "scripts")) @@ -86,13 +85,7 @@ def webui(): signal.signal(signal.SIGINT, sigint_handler) - demo = modules.ui.create_ui( - txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img), - img2img=wrap_gradio_gpu_call(modules.img2img.img2img), - run_extras=wrap_gradio_gpu_call(modules.extras.run_extras), - run_pnginfo=modules.extras.run_pnginfo, - run_modelmerger=modules.extras.run_modelmerger - ) + demo = modules.ui.create_ui(wrap_gradio_gpu_call=wrap_gradio_gpu_call) demo.launch( share=cmd_opts.share, From 0114057ad672a581bd0b598870b58b674b1a3624 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 15:49:42 +0300 Subject: [PATCH 030/460] fix incorrect use of glob in modelloader for #1410 --- modules/modelloader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/modelloader.py b/modules/modelloader.py index 8c862b42f..015aeafa3 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -43,7 +43,7 @@ def load_models(model_path: str, model_url: str = None, command_path: str = None for place in places: if os.path.exists(place): for file in glob.iglob(place + '**/**', recursive=True): - full_path = os.path.join(place, file) + full_path = file if os.path.isdir(full_path): continue if len(ext_filter) != 0: From 4e72a1aab6d1b3a8d8c09fadc81843a07c05cc18 Mon Sep 17 00:00:00 2001 From: ClashSAN <98228077+ClashSAN@users.noreply.github.com> Date: Sat, 1 Oct 2022 00:15:43 +0000 Subject: [PATCH 031/460] Grammar Fix --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5ded94f98..15e224e8f 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,12 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - One click install and run script (but you still must install python and git) - Outpainting - Inpainting -- Prompt -- Stable Diffusion upscale +- Prompt Matrix +- Stable Diffusion Upscale - Attention, specify parts of text that the model should pay more attention to - - a man in a ((txuedo)) - will pay more attentinoto tuxedo - - a man in a (txuedo:1.21) - alternative syntax -- Loopback, run img2img procvessing multiple times + - a man in a ((tuxedo)) - will pay more attention to tuxedo + - a man in a (tuxedo:1.21) - alternative syntax +- Loopback, run img2img processing multiple times - X/Y plot, a way to draw a 2 dimensional plot of images with different parameters - Textual Inversion - have as many embeddings as you want and use any names you like for them @@ -35,15 +35,15 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - 4GB video card support (also reports of 2GB working) - Correct seeds for batches - Prompt length validation - - get length of prompt in tokensas you type - - get a warning after geenration if some text was truncated + - get length of prompt in tokens as you type + - get a warning after generation if some text was truncated - Generation parameters - parameters you used to generate images are saved with that image - in PNG chunks for PNG, in EXIF for JPEG - can drag the image to PNG info tab to restore generation parameters and automatically copy them into UI - can be disabled in settings - Settings page -- Running arbitrary python code from UI (must run with commandline flag to enable) +- Running arbitrary python code from UI (must run with --allow-code to enable) - Mouseover hints for most UI elements - Possible to change defaults/mix/max/step values for UI elements via text config - Random artist button From 0758f6e641b5790ce566a998d43e0ea74a627766 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 17:24:50 +0300 Subject: [PATCH 032/460] fix --ckpt option breaking model selection --- modules/sd_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 5b3dbdc79..9259d69e7 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -69,7 +69,7 @@ def list_models(): h = model_hash(cmd_ckpt) title, short_model_name = modeltitle(cmd_ckpt, h) checkpoints_list[title] = CheckpointInfo(cmd_ckpt, title, h, short_model_name) - shared.opts.sd_model_checkpoint = title + shared.opts.data['sd_model_checkpoint'] = title elif cmd_ckpt is not None and cmd_ckpt != shared.default_sd_model_file: print(f"Checkpoint in --ckpt argument not found (Possible it was moved to {model_path}: {cmd_ckpt}", file=sys.stderr) for filename in model_list: From 53a3dc601fb734ce433505b1ca68770919106bad Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 18:21:56 +0300 Subject: [PATCH 033/460] move CLIP out of requirements and into launcher to make it possible to launch the program offline --- launch.py | 4 ++++ requirements.txt | 2 -- requirements_versions.txt | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/launch.py b/launch.py index d2793ed20..57405feab 100644 --- a/launch.py +++ b/launch.py @@ -15,6 +15,7 @@ requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") commandline_args = os.environ.get('COMMANDLINE_ARGS', "") gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379") +clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1") stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc") taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6") @@ -111,6 +112,9 @@ if not skip_torch_cuda_test: if not is_installed("gfpgan"): run_pip(f"install {gfpgan_package}", "gfpgan") +if not is_installed("clip"): + run_pip(f"install {clip_package}", "clip") + os.makedirs(dir_repos, exist_ok=True) git_clone("https://github.com/CompVis/stable-diffusion.git", repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) diff --git a/requirements.txt b/requirements.txt index 7cb9d3293..d4b337fce 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,14 +13,12 @@ Pillow pytorch_lightning realesrgan scikit-image>=0.19 -git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379 timm==0.4.12 transformers==4.19.2 torch einops jsonmerge clean-fid -git+https://github.com/openai/CLIP@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1 resize-right torchdiffeq kornia diff --git a/requirements_versions.txt b/requirements_versions.txt index 1e8006e05..8a9acf205 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -18,7 +18,6 @@ piexif==1.1.3 einops==0.4.1 jsonmerge==1.8.0 clean-fid==0.1.29 -git+https://github.com/openai/CLIP@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1 resize-right==0.0.2 torchdiffeq==0.2.3 kornia==0.6.7 From 88ec0cf5571883d84abd09196652b3679e359f2e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 19:40:51 +0300 Subject: [PATCH 034/460] fix for incorrect embedding token length calculation (will break seeds that use embeddings, you're welcome!) add option to input initialization text for embeddings --- modules/sd_hijack.py | 8 ++++---- modules/textual_inversion/textual_inversion.py | 13 +++++-------- modules/textual_inversion/ui.py | 4 ++-- modules/ui.py | 2 ++ 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index fd57e5c54..3fa062422 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -130,7 +130,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): while i < len(tokens): token = tokens[i] - embedding = self.hijack.embedding_db.find_embedding_at_position(tokens, i) + embedding, embedding_length_in_tokens = self.hijack.embedding_db.find_embedding_at_position(tokens, i) if embedding is None: remade_tokens.append(token) @@ -142,7 +142,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): remade_tokens += [0] * emb_len multipliers += [weight] * emb_len used_custom_terms.append((embedding.name, embedding.checksum())) - i += emb_len + i += embedding_length_in_tokens if len(remade_tokens) > maxlen - 2: vocab = {v: k for k, v in self.wrapped.tokenizer.get_vocab().items()} @@ -213,7 +213,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): while i < len(tokens): token = tokens[i] - embedding = self.hijack.embedding_db.find_embedding_at_position(tokens, i) + embedding, embedding_length_in_tokens = self.hijack.embedding_db.find_embedding_at_position(tokens, i) mult_change = self.token_mults.get(token) if opts.enable_emphasis else None if mult_change is not None: @@ -229,7 +229,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): remade_tokens += [0] * emb_len multipliers += [mult] * emb_len used_custom_terms.append((embedding.name, embedding.checksum())) - i += emb_len + i += embedding_length_in_tokens if len(remade_tokens) > maxlen - 2: vocab = {v: k for k, v in self.wrapped.tokenizer.get_vocab().items()} diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index c0baaace2..0c50161db 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -117,24 +117,21 @@ class EmbeddingDatabase: possible_matches = self.ids_lookup.get(token, None) if possible_matches is None: - return None + return None, None for ids, embedding in possible_matches: if tokens[offset:offset + len(ids)] == ids: - return embedding + return embedding, len(ids) - return None + return None, None - -def create_embedding(name, num_vectors_per_token): - init_text = '*' - +def create_embedding(name, num_vectors_per_token, init_text='*'): cond_model = shared.sd_model.cond_stage_model embedding_layer = cond_model.wrapped.transformer.text_model.embeddings ids = cond_model.tokenizer(init_text, max_length=num_vectors_per_token, return_tensors="pt", add_special_tokens=False)["input_ids"] - embedded = embedding_layer(ids.to(devices.device)).squeeze(0) + embedded = embedding_layer.token_embedding.wrapped(ids.to(devices.device)).squeeze(0) vec = torch.zeros((num_vectors_per_token, embedded.shape[1]), device=devices.device) for i in range(num_vectors_per_token): diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py index ce3677a98..66c43ffbe 100644 --- a/modules/textual_inversion/ui.py +++ b/modules/textual_inversion/ui.py @@ -6,8 +6,8 @@ import modules.textual_inversion.textual_inversion as ti from modules import sd_hijack, shared -def create_embedding(name, nvpt): - filename = ti.create_embedding(name, nvpt) +def create_embedding(name, initialization_text, nvpt): + filename = ti.create_embedding(name, nvpt, init_text=initialization_text) sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() diff --git a/modules/ui.py b/modules/ui.py index 3b81a4f74..eca50df0f 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -954,6 +954,7 @@ def create_ui(wrap_gradio_gpu_call): gr.HTML(value="

Create a new embedding

") new_embedding_name = gr.Textbox(label="Name") + initialization_text = gr.Textbox(label="Initialization text", value="*") nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1) with gr.Row(): @@ -997,6 +998,7 @@ def create_ui(wrap_gradio_gpu_call): fn=modules.textual_inversion.ui.create_embedding, inputs=[ new_embedding_name, + initialization_text, nvpt, ], outputs=[ From 71fe7fa49f5eb1a2c89932a9d217ed153c12fc8b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 19:56:37 +0300 Subject: [PATCH 035/460] fix using aaaa-100 embedding when the prompt has aaaa-10000 and you have both aaaa-100 and aaaa-10000 in the directory with embeddings. --- modules/textual_inversion/textual_inversion.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 0c50161db..9d2241cef 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -57,7 +57,8 @@ class EmbeddingDatabase: first_id = ids[0] if first_id not in self.ids_lookup: self.ids_lookup[first_id] = [] - self.ids_lookup[first_id].append((ids, embedding)) + + self.ids_lookup[first_id] = sorted(self.ids_lookup[first_id] + [(ids, embedding)], key=lambda x: len(x[0]), reverse=True) return embedding From 4ec4af6e0b7addeee5221a03f32d117ccdc875d9 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 20:15:25 +0300 Subject: [PATCH 036/460] add checkpoint info to saved embeddings --- modules/textual_inversion/textual_inversion.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 9d2241cef..1183aab76 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -7,7 +7,7 @@ import tqdm import html import datetime -from modules import shared, devices, sd_hijack, processing +from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset @@ -17,6 +17,8 @@ class Embedding: self.name = name self.step = step self.cached_checksum = None + self.sd_checkpoint = None + self.sd_checkpoint_name = None def save(self, filename): embedding_data = { @@ -24,6 +26,8 @@ class Embedding: "string_to_param": {"*": self.vec}, "name": self.name, "step": self.step, + "sd_checkpoint": self.sd_checkpoint, + "sd_checkpoint_name": self.sd_checkpoint_name, } torch.save(embedding_data, filename) @@ -41,6 +45,7 @@ class Embedding: self.cached_checksum = f'{const_hash(self.vec.reshape(-1) * 100) & 0xffff:04x}' return self.cached_checksum + class EmbeddingDatabase: def __init__(self, embeddings_dir): self.ids_lookup = {} @@ -96,6 +101,8 @@ class EmbeddingDatabase: vec = emb.detach().to(devices.device, dtype=torch.float32) embedding = Embedding(vec, name) embedding.step = data.get('step', None) + embedding.sd_checkpoint = data.get('hash', None) + embedding.sd_checkpoint_name = data.get('sd_checkpoint_name', None) self.register_embedding(embedding, shared.sd_model) for fn in os.listdir(self.embeddings_dir): @@ -249,6 +256,10 @@ Last saved image: {html.escape(last_saved_image)}

""" + checkpoint = sd_models.select_checkpoint() + + embedding.sd_checkpoint = checkpoint.hash + embedding.sd_checkpoint_name = checkpoint.model_name embedding.cached_checksum = None embedding.save(filename) From 3ff0de2c594b786ef948a89efb1814c59bb42117 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 20:23:40 +0300 Subject: [PATCH 037/460] added --disable-console-progressbars to disable progressbars in console disabled printing prompts to console by default, enabled by --enable-console-prompts --- modules/img2img.py | 4 +++- modules/sd_samplers.py | 8 ++++++-- modules/shared.py | 7 +++++-- modules/txt2img.py | 4 +++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/modules/img2img.py b/modules/img2img.py index 03e934e96..f4455c90f 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -103,7 +103,9 @@ def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, pro inpaint_full_res_padding=inpaint_full_res_padding, inpainting_mask_invert=inpainting_mask_invert, ) - print(f"\nimg2img: {prompt}", file=shared.progress_print_out) + + if shared.cmd_opts.enable_console_prompts: + print(f"\nimg2img: {prompt}", file=shared.progress_print_out) p.extra_generation_params["Mask blur"] = mask_blur diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 925222148..9316875ab 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -77,7 +77,9 @@ def extended_tdqm(sequence, *args, desc=None, **kwargs): state.sampling_steps = len(sequence) state.sampling_step = 0 - for x in tqdm.tqdm(sequence, *args, desc=state.job, file=shared.progress_print_out, **kwargs): + seq = sequence if cmd_opts.disable_console_progressbars else tqdm.tqdm(sequence, *args, desc=state.job, file=shared.progress_print_out, **kwargs) + + for x in seq: if state.interrupted: break @@ -207,7 +209,9 @@ def extended_trange(sampler, count, *args, **kwargs): state.sampling_steps = count state.sampling_step = 0 - for x in tqdm.trange(count, *args, desc=state.job, file=shared.progress_print_out, **kwargs): + seq = range(count) if cmd_opts.disable_console_progressbars else tqdm.trange(count, *args, desc=state.job, file=shared.progress_print_out, **kwargs) + + for x in seq: if state.interrupted: break diff --git a/modules/shared.py b/modules/shared.py index 5a591dc99..1bf7a6c14 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -58,6 +58,9 @@ parser.add_argument("--opt-channelslast", action='store_true', help="change memo parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(script_path, 'styles.csv')) parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False) parser.add_argument("--use-textbox-seed", action='store_true', help="use textbox for seeds in UI (no up/down, but possible to input long seeds)", default=False) +parser.add_argument("--disable-console-progressbars", action='store_true', help="do not output progressbars to console", default=False) +parser.add_argument("--enable-console-prompts", action='store_true', help="print prompts to console when generating with txt2img and img2img", default=False) + cmd_opts = parser.parse_args() device = get_optimal_device() @@ -320,14 +323,14 @@ class TotalTQDM: ) def update(self): - if not opts.multiple_tqdm: + if not opts.multiple_tqdm or cmd_opts.disable_console_progressbars: return if self._tqdm is None: self.reset() self._tqdm.update() def updateTotal(self, new_total): - if not opts.multiple_tqdm: + if not opts.multiple_tqdm or cmd_opts.disable_console_progressbars: return if self._tqdm is None: self.reset() diff --git a/modules/txt2img.py b/modules/txt2img.py index 5368e4d00..d4406c3c0 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -34,7 +34,9 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: denoising_strength=denoising_strength if enable_hr else None, ) - print(f"\ntxt2img: {prompt}", file=shared.progress_print_out) + if cmd_opts.enable_console_prompts: + print(f"\ntxt2img: {prompt}", file=shared.progress_print_out) + processed = modules.scripts.scripts_txt2img.run(p, *args) if processed is None: From 6365a41f5981efa506dfe4e8fa878b43ca2d8d0c Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Sun, 2 Oct 2022 12:58:17 -0500 Subject: [PATCH 038/460] Update esrgan_model.py Use alternate ESRGAN Model download path. --- modules/esrgan_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py index ea91abfe8..4aed9283c 100644 --- a/modules/esrgan_model.py +++ b/modules/esrgan_model.py @@ -73,8 +73,8 @@ def fix_model_layers(crt_model, pretrained_net): class UpscalerESRGAN(Upscaler): def __init__(self, dirname): self.name = "ESRGAN" - self.model_url = "https://drive.google.com/u/0/uc?id=1TPrz5QKd8DHHt1k8SRtm6tMiPjz_Qene&export=download" - self.model_name = "ESRGAN 4x" + self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/ESRGAN.pth" + self.model_name = "ESRGAN_4x" self.scalers = [] self.user_path = dirname self.model_path = os.path.join(models_path, self.name) From a1cde7e6468f80584030525a1b07cbf0f4ee42eb Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 21:09:10 +0300 Subject: [PATCH 039/460] disabled SD model download after multiple complaints --- modules/sd_models.py | 18 ++++++++---------- modules/textual_inversion/ui.py | 2 +- webui.py | 2 +- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 9259d69e7..9a6b568f0 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -13,9 +13,6 @@ from modules.paths import models_path model_dir = "Stable-diffusion" model_path = os.path.abspath(os.path.join(models_path, model_dir)) -model_name = "sd-v1-4.ckpt" -model_url = "https://drive.yerf.org/wl/?id=EBfTrmcCCUAGaQBXVIj5lJmEhjoP1tgl&mode=grid&download=1" -user_dir = None CheckpointInfo = namedtuple("CheckpointInfo", ['filename', 'title', 'hash', 'model_name']) checkpoints_list = {} @@ -30,12 +27,10 @@ except Exception: pass -def setup_model(dirname): - global user_dir - user_dir = dirname +def setup_model(): if not os.path.exists(model_path): os.makedirs(model_path) - checkpoints_list.clear() + list_models() @@ -45,7 +40,7 @@ def checkpoint_tiles(): def list_models(): checkpoints_list.clear() - model_list = modelloader.load_models(model_path=model_path, model_url=model_url, command_path=user_dir, ext_filter=[".ckpt"], download_name=model_name) + model_list = modelloader.load_models(model_path=model_path, command_path=shared.cmd_opts.ckpt_dir, ext_filter=[".ckpt"]) def modeltitle(path, shorthash): abspath = os.path.abspath(path) @@ -106,8 +101,11 @@ def select_checkpoint(): if len(checkpoints_list) == 0: print(f"No checkpoints found. When searching for checkpoints, looked at:", file=sys.stderr) - print(f" - file {os.path.abspath(shared.cmd_opts.ckpt)}", file=sys.stderr) - print(f" - directory {os.path.abspath(shared.cmd_opts.ckpt_dir)}", file=sys.stderr) + if shared.cmd_opts.ckpt is not None: + print(f" - file {os.path.abspath(shared.cmd_opts.ckpt)}", file=sys.stderr) + print(f" - directory {model_path}", file=sys.stderr) + if shared.cmd_opts.ckpt_dir is not None: + print(f" - directory {os.path.abspath(shared.cmd_opts.ckpt_dir)}", file=sys.stderr) print(f"Can't run without a checkpoint. Find and place a .ckpt file into any of those locations. The program will exit.", file=sys.stderr) exit(1) diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py index 66c43ffbe..633037d8e 100644 --- a/modules/textual_inversion/ui.py +++ b/modules/textual_inversion/ui.py @@ -22,7 +22,7 @@ def train_embedding(*args): embedding, filename = ti.train_embedding(*args) res = f""" -Training {'interrupted' if shared.state.interrupted else 'finished'} after {embedding.step} steps. +Training {'interrupted' if shared.state.interrupted else 'finished'} at {embedding.step} steps. Embedding saved to {html.escape(filename)} """ return res, "" diff --git a/webui.py b/webui.py index 424ab9751..dc72ceb8a 100644 --- a/webui.py +++ b/webui.py @@ -23,7 +23,7 @@ from modules.paths import script_path from modules.shared import cmd_opts modelloader.cleanup_models() -modules.sd_models.setup_model(cmd_opts.ckpt_dir) +modules.sd_models.setup_model() codeformer.setup_model(cmd_opts.codeformer_models_path) gfpgan.setup_model(cmd_opts.gfpgan_models_path) shared.face_restorers.append(modules.face_restoration.FaceRestoration()) From 852fd90c0dcda9cb5fbbfdf0c7308ce58034935c Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 21:22:20 +0300 Subject: [PATCH 040/460] emergency fix for disabling SD model download after multiple complaints --- modules/sd_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 9a6b568f0..5f9920647 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -45,8 +45,8 @@ def list_models(): def modeltitle(path, shorthash): abspath = os.path.abspath(path) - if user_dir is not None and abspath.startswith(user_dir): - name = abspath.replace(user_dir, '') + if shared.cmd_opts.ckpt_dir is not None and abspath.startswith(shared.cmd_opts.ckpt_dir): + name = abspath.replace(shared.cmd_opts.ckpt_dir, '') elif abspath.startswith(model_path): name = abspath.replace(model_path, '') else: From e808096cf641d868f88465515d70d40fc46125d4 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 2 Oct 2022 19:26:06 +0100 Subject: [PATCH 041/460] correct indent --- modules/scripts.py | 48 ++++++++++++++++++++++++---------------------- modules/ui.py | 23 +++++++++++----------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/modules/scripts.py b/modules/scripts.py index 788397f53..45230f9a1 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -163,37 +163,39 @@ class ScriptRunner: return processed def reload_sources(self): - for si,script in list(enumerate(self.scripts)): - with open(script.filename, "r", encoding="utf8") as file: - args_from = script.args_from - args_to = script.args_to - filename = script.filename - text = file.read() + for si, script in list(enumerate(self.scripts)): + with open(script.filename, "r", encoding="utf8") as file: + args_from = script.args_from + args_to = script.args_to + filename = script.filename + text = file.read() - from types import ModuleType - compiled = compile(text, filename, 'exec') - module = ModuleType(script.filename) - exec(compiled, module.__dict__) + from types import ModuleType - for key, script_class in module.__dict__.items(): - if type(script_class) == type and issubclass(script_class, Script): - self.scripts[si] = script_class() - self.scripts[si].filename = filename - self.scripts[si].args_from = args_from - self.scripts[si].args_to = args_to + compiled = compile(text, filename, 'exec') + module = ModuleType(script.filename) + exec(compiled, module.__dict__) + + for key, script_class in module.__dict__.items(): + if type(script_class) == type and issubclass(script_class, Script): + self.scripts[si] = script_class() + self.scripts[si].filename = filename + self.scripts[si].args_from = args_from + self.scripts[si].args_to = args_to scripts_txt2img = ScriptRunner() scripts_img2img = ScriptRunner() def reload_script_body_only(): - scripts_txt2img.reload_sources() - scripts_img2img.reload_sources() + scripts_txt2img.reload_sources() + scripts_img2img.reload_sources() + def reload_scripts(basedir): - global scripts_txt2img,scripts_img2img + global scripts_txt2img, scripts_img2img - scripts_data.clear() - load_scripts(basedir) + scripts_data.clear() + load_scripts(basedir) - scripts_txt2img = ScriptRunner() - scripts_img2img = ScriptRunner() + scripts_txt2img = ScriptRunner() + scripts_img2img = ScriptRunner() diff --git a/modules/ui.py b/modules/ui.py index 963a2c611..6b30f84ba 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1003,12 +1003,12 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): ) with gr.Row(): - reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary') - restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') + reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary') + restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') def reload_scripts(): - modules.scripts.reload_script_body_only() + modules.scripts.reload_script_body_only() reload_script_bodies.click( fn=reload_scripts, @@ -1018,7 +1018,7 @@ def create_ui(txt2img, img2img, run_extras, run_pnginfo, run_modelmerger): ) def request_restart(): - settings_interface.gradio_ref.do_restart = True + settings_interface.gradio_ref.do_restart = True restart_gradio.click( fn=request_restart, @@ -1234,12 +1234,11 @@ for filename in sorted(os.listdir(jsdir)): if 'gradio_routes_templates_response' not in globals(): - def template_response(*args, **kwargs): - res = gradio_routes_templates_response(*args, **kwargs) - res.body = res.body.replace(b'', f'{javascript}'.encode("utf8")) - res.init_headers() - return res - - gradio_routes_templates_response = gradio.routes.templates.TemplateResponse - gradio.routes.templates.TemplateResponse = template_response + def template_response(*args, **kwargs): + res = gradio_routes_templates_response(*args, **kwargs) + res.body = res.body.replace(b'', f'{javascript}'.encode("utf8")) + res.init_headers() + return res + gradio_routes_templates_response = gradio.routes.templates.TemplateResponse + gradio.routes.templates.TemplateResponse = template_response From a634c3226fd69486ce96df56f95f3fd63172305c Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 2 Oct 2022 19:26:38 +0100 Subject: [PATCH 042/460] correct indent --- webui.py | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/webui.py b/webui.py index ab200045a..140040ca1 100644 --- a/webui.py +++ b/webui.py @@ -89,38 +89,38 @@ def webui(): while 1: - demo = modules.ui.create_ui( - txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img), - img2img=wrap_gradio_gpu_call(modules.img2img.img2img), - run_extras=wrap_gradio_gpu_call(modules.extras.run_extras), - run_pnginfo=modules.extras.run_pnginfo, - run_modelmerger=modules.extras.run_modelmerger - ) + demo = modules.ui.create_ui( + txt2img=wrap_gradio_gpu_call(modules.txt2img.txt2img), + img2img=wrap_gradio_gpu_call(modules.img2img.img2img), + run_extras=wrap_gradio_gpu_call(modules.extras.run_extras), + run_pnginfo=modules.extras.run_pnginfo, + run_modelmerger=modules.extras.run_modelmerger + ) - demo.launch( - share=cmd_opts.share, - server_name="0.0.0.0" if cmd_opts.listen else None, - server_port=cmd_opts.port, - debug=cmd_opts.gradio_debug, - auth=[tuple(cred.split(':')) for cred in cmd_opts.gradio_auth.strip('"').split(',')] if cmd_opts.gradio_auth else None, - inbrowser=cmd_opts.autolaunch, - prevent_thread_lock=True - ) + demo.launch( + share=cmd_opts.share, + server_name="0.0.0.0" if cmd_opts.listen else None, + server_port=cmd_opts.port, + debug=cmd_opts.gradio_debug, + auth=[tuple(cred.split(':')) for cred in cmd_opts.gradio_auth.strip('"').split(',')] if cmd_opts.gradio_auth else None, + inbrowser=cmd_opts.autolaunch, + prevent_thread_lock=True + ) - while 1: - time.sleep(0.5) - if getattr(demo,'do_restart',False): - time.sleep(0.5) - demo.close() - time.sleep(0.5) - break + while 1: + time.sleep(0.5) + if getattr(demo,'do_restart',False): + time.sleep(0.5) + demo.close() + time.sleep(0.5) + break - print('Reloading Custom Scripts') - modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) - print('Reloading modules: modules.ui') - importlib.reload(modules.ui) - print('Restarting Gradio') + print('Reloading Custom Scripts') + modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) + print('Reloading modules: modules.ui') + importlib.reload(modules.ui) + print('Restarting Gradio') if __name__ == "__main__": From c0389eb3071870240bc158263e5dfb4351ec8eba Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 21:35:29 +0300 Subject: [PATCH 043/460] hello --- webui.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/webui.py b/webui.py index 634956978..47848ba58 100644 --- a/webui.py +++ b/webui.py @@ -103,11 +103,11 @@ def webui(): while 1: time.sleep(0.5) - if getattr(demo,'do_restart',False): - time.sleep(0.5) - demo.close() - time.sleep(0.5) - break + if getattr(demo, 'do_restart', False): + time.sleep(0.5) + demo.close() + time.sleep(0.5) + break print('Reloading Custom Scripts') modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) From 2ef69df9a7c7b6793401f29ced71fb8a781fad4c Mon Sep 17 00:00:00 2001 From: Jocke Date: Sun, 2 Oct 2022 16:10:41 +0200 Subject: [PATCH 044/460] Prevent upscaling when None is selected for SD upscale --- scripts/sd_upscale.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/sd_upscale.py b/scripts/sd_upscale.py index 2653e2d40..cb37ff7e8 100644 --- a/scripts/sd_upscale.py +++ b/scripts/sd_upscale.py @@ -34,7 +34,11 @@ class Script(scripts.Script): seed = p.seed init_img = p.init_images[0] - img = upscaler.scaler.upscale(init_img, 2, upscaler.data_path) + + if(upscaler.name != "None"): + img = upscaler.scaler.upscale(init_img, 2, upscaler.data_path) + else: + img = init_img devices.torch_gc() From 91f327f22bb2feb780c424c74723cc0629dc34a1 Mon Sep 17 00:00:00 2001 From: Lopyter Date: Sun, 2 Oct 2022 18:15:31 +0200 Subject: [PATCH 045/460] make save to dirs optional for imgs saved from ui --- modules/shared.py | 1 + modules/ui.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 1bf7a6c14..785e7af6f 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -173,6 +173,7 @@ options_templates.update(options_section(('saving-to-dirs', "Saving to a directo "grid_save_to_dirs": OptionInfo(False, "Save grids to subdirectory"), "directories_filename_pattern": OptionInfo("", "Directory name pattern"), "directories_max_prompt_words": OptionInfo(8, "Max prompt words", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1}), + "use_save_to_dirs_for_ui": OptionInfo(False, "Use \"Save images to a subdirectory\" option for images saved from UI"), })) options_templates.update(options_section(('upscaling', "Upscaling"), { diff --git a/modules/ui.py b/modules/ui.py index 78a15d83a..8912deff4 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -113,7 +113,7 @@ def save_files(js_data, images, index): p = MyObject(data) path = opts.outdir_save - save_to_dirs = opts.save_to_dirs + save_to_dirs = opts.use_save_to_dirs_for_ui if save_to_dirs: dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, p.seed, p.prompt) From c4445225f79f1c57afe52358ff4b205864eb7aac Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 21:50:14 +0300 Subject: [PATCH 046/460] change wording for options --- modules/shared.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 785e7af6f..7246eadc6 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -170,10 +170,10 @@ options_templates.update(options_section(('saving-paths', "Paths for saving"), { options_templates.update(options_section(('saving-to-dirs', "Saving to a directory"), { "save_to_dirs": OptionInfo(False, "Save images to a subdirectory"), - "grid_save_to_dirs": OptionInfo(False, "Save grids to subdirectory"), + "grid_save_to_dirs": OptionInfo(False, "Save grids to a subdirectory"), + "use_save_to_dirs_for_ui": OptionInfo(False, "When using \"Save\" button, save images to a subdirectory"), "directories_filename_pattern": OptionInfo("", "Directory name pattern"), - "directories_max_prompt_words": OptionInfo(8, "Max prompt words", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1}), - "use_save_to_dirs_for_ui": OptionInfo(False, "Use \"Save images to a subdirectory\" option for images saved from UI"), + "directories_max_prompt_words": OptionInfo(8, "Max prompt words for [prompt_words] pattern", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1}), })) options_templates.update(options_section(('upscaling', "Upscaling"), { From c7543d4940da672d970124ae8f2fec9de7bdc1da Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 22:41:21 +0300 Subject: [PATCH 047/460] preprocessing for textual inversion added --- modules/interrogate.py | 1 + modules/textual_inversion/preprocess.py | 75 +++++++++++++++++++ .../textual_inversion/textual_inversion.py | 1 + modules/textual_inversion/ui.py | 14 +++- modules/ui.py | 36 +++++++++ 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 modules/textual_inversion/preprocess.py diff --git a/modules/interrogate.py b/modules/interrogate.py index f62a47458..eed87144f 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -21,6 +21,7 @@ Category = namedtuple("Category", ["name", "topn", "items"]) re_topn = re.compile(r"\.top(\d+)\.") + class InterrogateModels: blip_model = None clip_model = None diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py new file mode 100644 index 000000000..209e928ff --- /dev/null +++ b/modules/textual_inversion/preprocess.py @@ -0,0 +1,75 @@ +import os +from PIL import Image, ImageOps +import tqdm + +from modules import shared, images + + +def preprocess(process_src, process_dst, process_flip, process_split, process_caption): + size = 512 + src = os.path.abspath(process_src) + dst = os.path.abspath(process_dst) + + assert src != dst, 'same directory specified as source and desitnation' + + os.makedirs(dst, exist_ok=True) + + files = os.listdir(src) + + shared.state.textinfo = "Preprocessing..." + shared.state.job_count = len(files) + + if process_caption: + shared.interrogator.load() + + def save_pic_with_caption(image, index): + if process_caption: + caption = "-" + shared.interrogator.generate_caption(image) + else: + caption = "" + + image.save(os.path.join(dst, f"{index:05}-{subindex[0]}{caption}.png")) + subindex[0] += 1 + + def save_pic(image, index): + save_pic_with_caption(image, index) + + if process_flip: + save_pic_with_caption(ImageOps.mirror(image), index) + + for index, imagefile in enumerate(tqdm.tqdm(files)): + subindex = [0] + filename = os.path.join(src, imagefile) + img = Image.open(filename).convert("RGB") + + if shared.state.interrupted: + break + + ratio = img.height / img.width + is_tall = ratio > 1.35 + is_wide = ratio < 1 / 1.35 + + if process_split and is_tall: + img = img.resize((size, size * img.height // img.width)) + + top = img.crop((0, 0, size, size)) + save_pic(top, index) + + bot = img.crop((0, img.height - size, size, img.height)) + save_pic(bot, index) + elif process_split and is_wide: + img = img.resize((size * img.width // img.height, size)) + + left = img.crop((0, 0, size, size)) + save_pic(left, index) + + right = img.crop((img.width - size, 0, img.width, size)) + save_pic(right, index) + else: + img = images.resize_image(1, img, size, size) + save_pic(img, index) + + shared.state.nextjob() + + if process_caption: + shared.interrogator.send_blip_to_ram() diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 1183aab76..d4e250d87 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -7,6 +7,7 @@ import tqdm import html import datetime + from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py index 633037d8e..f19ac5e02 100644 --- a/modules/textual_inversion/ui.py +++ b/modules/textual_inversion/ui.py @@ -2,24 +2,31 @@ import html import gradio as gr -import modules.textual_inversion.textual_inversion as ti +import modules.textual_inversion.textual_inversion +import modules.textual_inversion.preprocess from modules import sd_hijack, shared def create_embedding(name, initialization_text, nvpt): - filename = ti.create_embedding(name, nvpt, init_text=initialization_text) + filename = modules.textual_inversion.textual_inversion.create_embedding(name, nvpt, init_text=initialization_text) sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() return gr.Dropdown.update(choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())), f"Created: {filename}", "" +def preprocess(*args): + modules.textual_inversion.preprocess.preprocess(*args) + + return "Preprocessing finished.", "" + + def train_embedding(*args): try: sd_hijack.undo_optimizations() - embedding, filename = ti.train_embedding(*args) + embedding, filename = modules.textual_inversion.textual_inversion.train_embedding(*args) res = f""" Training {'interrupted' if shared.state.interrupted else 'finished'} at {embedding.step} steps. @@ -30,3 +37,4 @@ Embedding saved to {html.escape(filename)} raise finally: sd_hijack.apply_optimizations() + diff --git a/modules/ui.py b/modules/ui.py index 8912deff4..e7bde53bf 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -961,6 +961,8 @@ def create_ui(wrap_gradio_gpu_call): with gr.Row().style(equal_height=False): with gr.Column(): with gr.Group(): + gr.HTML(value="

See wiki for detailed explanation.

") + gr.HTML(value="

Create a new embedding

") new_embedding_name = gr.Textbox(label="Name") @@ -974,6 +976,24 @@ def create_ui(wrap_gradio_gpu_call): with gr.Column(): create_embedding = gr.Button(value="Create", variant='primary') + with gr.Group(): + gr.HTML(value="

Preprocess images

") + + process_src = gr.Textbox(label='Source directory') + process_dst = gr.Textbox(label='Destination directory') + + with gr.Row(): + process_flip = gr.Checkbox(label='Flip') + process_split = gr.Checkbox(label='Split into two') + process_caption = gr.Checkbox(label='Add caption') + + with gr.Row(): + with gr.Column(scale=3): + gr.HTML(value="") + + with gr.Column(): + run_preprocess = gr.Button(value="Preprocess", variant='primary') + with gr.Group(): gr.HTML(value="

Train an embedding; must specify a directory with a set of 512x512 images

") train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) @@ -1018,6 +1038,22 @@ def create_ui(wrap_gradio_gpu_call): ] ) + run_preprocess.click( + fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), + _js="start_training_textual_inversion", + inputs=[ + process_src, + process_dst, + process_flip, + process_split, + process_caption, + ], + outputs=[ + ti_output, + ti_outcome, + ], + ) + train_embedding.click( fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]), _js="start_training_textual_inversion", From 6785331e22d6a488fbf5905fab56d7fec867e038 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 22:59:01 +0300 Subject: [PATCH 048/460] keep textual inversion dataset latents in CPU memory to save a bit of VRAM --- modules/textual_inversion/dataset.py | 2 ++ modules/textual_inversion/textual_inversion.py | 3 +++ modules/ui.py | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index 7e134a08f..e8394ff65 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -8,6 +8,7 @@ from torchvision import transforms import random import tqdm +from modules import devices class PersonalizedBase(Dataset): @@ -47,6 +48,7 @@ class PersonalizedBase(Dataset): torchdata = torch.moveaxis(torchdata, 2, 0) init_latent = model.get_first_stage_encoding(model.encode_first_stage(torchdata.unsqueeze(dim=0))).squeeze() + init_latent = init_latent.to(devices.cpu) self.dataset.append((init_latent, filename_tokens)) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index d4e250d87..8686f5347 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -212,7 +212,10 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, with torch.autocast("cuda"): c = cond_model([text]) + + x = x.to(devices.device) loss = shared.sd_model(x.unsqueeze(0), c)[0] + del x losses[embedding.step % losses.shape[0]] = loss.item() diff --git a/modules/ui.py b/modules/ui.py index e7bde53bf..d9d02ecef 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1002,8 +1002,8 @@ def create_ui(wrap_gradio_gpu_call): log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) steps = gr.Number(label='Max steps', value=100000, precision=0) - create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=1000, precision=0) - save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=1000, precision=0) + create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) + save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) with gr.Row(): with gr.Column(scale=2): From 166283653cfe7521a422c91e8fb801f3ecb4adc8 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 23:18:13 +0300 Subject: [PATCH 049/460] remove LDSR warning --- modules/paths.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/paths.py b/modules/paths.py index ceb804171..606f7d666 100644 --- a/modules/paths.py +++ b/modules/paths.py @@ -20,7 +20,6 @@ path_dirs = [ (os.path.join(sd_path, '../taming-transformers'), 'taming', 'Taming Transformers', []), (os.path.join(sd_path, '../CodeFormer'), 'inference_codeformer.py', 'CodeFormer', []), (os.path.join(sd_path, '../BLIP'), 'models/blip.py', 'BLIP', []), - (os.path.join(sd_path, '../latent-diffusion'), 'LDSR.py', 'LDSR', []), (os.path.join(sd_path, '../k-diffusion'), 'k_diffusion/sampling.py', 'k_diffusion', ["atstart"]), ] From 4c2eccf8e96825333ed400f8a8a2be78141ed8ec Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 2 Oct 2022 23:22:48 +0300 Subject: [PATCH 050/460] credit Rinon Gal --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 15e224e8f..ec3d7532d 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ The documentation was moved from this README over to the project's [wiki](https: - LDSR - https://github.com/Hafiidz/latent-diffusion - Ideas for optimizations - https://github.com/basujindal/stable-diffusion - Doggettx - Cross Attention layer optimization - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing. +- Rinon Gal - Textual Inversion - https://github.com/rinongal/textual_inversion (we're not using his code, but we are using his ideas). - Idea for SD upscale - https://github.com/jquesnelle/txt2imghd - Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot - CLIP interrogator idea and borrowing some code - https://github.com/pharmapsychotic/clip-interrogator From 138662734c25dab4e73e632b7eaff9ad9c0ce2b4 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 3 Oct 2022 07:57:59 +0300 Subject: [PATCH 051/460] use dropdown instead of radio for img2img upscaler selection --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 7246eadc6..2a599e9cf 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -183,7 +183,7 @@ options_templates.update(options_section(('upscaling', "Upscaling"), { "SWIN_tile": OptionInfo(192, "Tile size for all SwinIR.", gr.Slider, {"minimum": 16, "maximum": 512, "step": 16}), "SWIN_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for SwinIR. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}), "ldsr_steps": OptionInfo(100, "LDSR processing steps. Lower = faster", gr.Slider, {"minimum": 1, "maximum": 200, "step": 1}), - "upscaler_for_img2img": OptionInfo(None, "Upscaler for img2img", gr.Radio, lambda: {"choices": [x.name for x in sd_upscalers]}), + "upscaler_for_img2img": OptionInfo(None, "Upscaler for img2img", gr.Dropdown, lambda: {"choices": [x.name for x in sd_upscalers]}), })) options_templates.update(options_section(('face-restoration', "Face restoration"), { From e615d4f9d101e2712c7c2d0e3e8feb19cb430c74 Mon Sep 17 00:00:00 2001 From: Hanusz Leszek Date: Sun, 2 Oct 2022 21:08:23 +0200 Subject: [PATCH 052/460] Convert folder icon surrogate pair to valid utf8 --- javascript/hints.js | 2 +- modules/ui.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index 84694eeb3..e72e93381 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -15,7 +15,7 @@ titles = { "\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomed", "\u{1f3a8}": "Add a random artist to the prompt.", "\u2199\ufe0f": "Read generation parameters from prompt into user interface.", - "\uD83D\uDCC2": "Open images output directory", + "\u{1f4c2}": "Open images output directory", "Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt", "SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back", diff --git a/modules/ui.py b/modules/ui.py index d9d02ecef..164321512 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -69,7 +69,7 @@ random_symbol = '\U0001f3b2\ufe0f' # 🎲️ reuse_symbol = '\u267b\ufe0f' # ♻️ art_symbol = '\U0001f3a8' # 🎨 paste_symbol = '\u2199\ufe0f' # ↙ -folder_symbol = '\uD83D\uDCC2' +folder_symbol = '\U0001f4c2' # 📂 def plaintext_to_html(text): text = "

" + "
\n".join([f"{html.escape(x)}" for x in text.split('\n')]) + "

" From 34c638142eaa57f89b86545ba3c72085036398bb Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Fri, 30 Sep 2022 22:38:14 +0100 Subject: [PATCH 053/460] Fixed when eta = 0 Unexpected behavior when using eta = 0 in something like XY, but your default eta was set to something not 0. --- modules/sd_samplers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 9316875ab..dbf570d2c 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -127,7 +127,7 @@ class VanillaStableDiffusionSampler: return res def initialize(self, p): - self.eta = p.eta or opts.eta_ddim + self.eta = p.eta if p.eta is not None else opts.eta_ddim for fieldname in ['p_sample_ddim', 'p_sample_plms']: if hasattr(self.sampler, fieldname): From 36ea4ac0f5844e5c8dec124edbdb714ccdd6013c Mon Sep 17 00:00:00 2001 From: RnDMonkey Date: Sun, 2 Oct 2022 22:21:16 -0700 Subject: [PATCH 054/460] moved no-style return outside join function --- modules/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images.py b/modules/images.py index bba55158e..1a046aca6 100644 --- a/modules/images.py +++ b/modules/images.py @@ -315,7 +315,7 @@ def apply_filename_pattern(x, p, seed, prompt): #currently disabled if using the save button, will work otherwise # if enabled it will cause a bug because styles is not included in the save_files data dictionary if hasattr(p, "styles"): - x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"] or "None"), replace_spaces=False)) + x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]) or "None", replace_spaces=False)) x = x.replace("[sampler]", sanitize_filename_part(sd_samplers.samplers[p.sampler_index].name, replace_spaces=False)) From 6491b09c24ea77f1f69990ea80a216f9ce319589 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 3 Oct 2022 08:53:52 +0300 Subject: [PATCH 055/460] use existing function for gfpgan --- modules/gfpgan_model.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/modules/gfpgan_model.py b/modules/gfpgan_model.py index bb30d7330..dd3fbcab1 100644 --- a/modules/gfpgan_model.py +++ b/modules/gfpgan_model.py @@ -97,11 +97,7 @@ def setup_model(dirname): return "GFPGAN" def restore(self, np_image): - np_image_bgr = np_image[:, :, ::-1] - cropped_faces, restored_faces, gfpgan_output_bgr = gfpgann().enhance(np_image_bgr, has_aligned=False, only_center_face=False, paste_back=True) - np_image = gfpgan_output_bgr[:, :, ::-1] - - return np_image + return gfpgan_fix_faces(np_image) shared.face_restorers.append(FaceRestorerGFPGAN()) except Exception: From 43a74fa595003321200a40bd2431e56c245e75ed Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 3 Oct 2022 11:48:19 +0300 Subject: [PATCH 056/460] batch processing for img2img with an empty output directory, by request --- modules/img2img.py | 7 +++++-- modules/ui.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/img2img.py b/modules/img2img.py index f4455c90f..2ff8e2617 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -23,8 +23,10 @@ def process_batch(p, input_dir, output_dir, args): print(f"Will process {len(images)} images, creating {p.n_iter * p.batch_size} new images for each.") + save_normally = output_dir == '' + p.do_not_save_grid = True - p.do_not_save_samples = True + p.do_not_save_samples = not save_normally state.job_count = len(images) * p.n_iter @@ -48,7 +50,8 @@ def process_batch(p, input_dir, output_dir, args): left, right = os.path.splitext(filename) filename = f"{left}-{n}{right}" - processed_image.save(os.path.join(output_dir, filename)) + if not save_normally: + processed_image.save(os.path.join(output_dir, filename)) def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, init_img, init_img_with_mask, init_img_inpaint, init_mask_inpaint, mask_mode, steps: int, sampler_index: int, mask_blur: int, inpainting_fill: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_input_dir: str, img2img_batch_output_dir: str, *args): diff --git a/modules/ui.py b/modules/ui.py index 164321512..55f7aa953 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -658,7 +658,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.TabItem('Batch img2img', id='batch'): hidden = '
Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else '' - gr.HTML(f"

Process images in a directory on the same machine where the server is running.{hidden}

") + gr.HTML(f"

Process images in a directory on the same machine where the server is running.
Use an empty output directory to save pictures normally instead of writing to the output directory.{hidden}

") img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs) img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs) From 2865ef4b9ab16d56326cc805541bebcf01d099bc Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 3 Oct 2022 13:10:03 +0300 Subject: [PATCH 057/460] fix broken date in TI --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 8686f5347..cd9f34984 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -164,7 +164,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, filename = os.path.join(shared.cmd_opts.embeddings_dir, f'{embedding_name}.pt') - log_directory = os.path.join(log_directory, datetime.datetime.now().strftime("%Y-%d-%m"), embedding_name) + log_directory = os.path.join(log_directory, datetime.datetime.now().strftime("%Y-%m-%d"), embedding_name) if save_embedding_every > 0: embedding_dir = os.path.join(log_directory, "embeddings") From 2a7f48cdb8dcf9acb02610cccae0d1ee5d260bc2 Mon Sep 17 00:00:00 2001 From: fuzzytent Date: Fri, 30 Sep 2022 16:02:16 +0200 Subject: [PATCH 058/460] Improve styling of gallery items, particularly in dark mode --- style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/style.css b/style.css index 9709c4eec..e11316b96 100644 --- a/style.css +++ b/style.css @@ -403,3 +403,7 @@ input[type="range"]{ .red { color: red; } + +.gallery-item { + --tw-bg-opacity: 0 !important; +} From 5ef0baf5eaec7f21a1666af424405cbee19f3764 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 08:52:11 +0300 Subject: [PATCH 059/460] add support for gelbooru tags in filenames for textual inversion --- modules/textual_inversion/dataset.py | 7 +++++-- modules/textual_inversion/preprocess.py | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index e8394ff65..7c44ea5be 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -9,6 +9,9 @@ from torchvision import transforms import random import tqdm from modules import devices +import re + +re_tag = re.compile(r"[a-zA-Z][_\w\d()]+") class PersonalizedBase(Dataset): @@ -38,8 +41,8 @@ class PersonalizedBase(Dataset): image = image.resize((self.width, self.height), PIL.Image.BICUBIC) filename = os.path.basename(path) - filename_tokens = os.path.splitext(filename)[0].replace('_', '-').replace(' ', '-').split('-') - filename_tokens = [token for token in filename_tokens if token.isalpha()] + filename_tokens = os.path.splitext(filename)[0] + filename_tokens = re_tag.findall(filename_tokens) npimage = np.array(image).astype(np.uint8) npimage = (npimage / 127.5 - 1.0).astype(np.float32) diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index 209e928ff..f545a9937 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -26,7 +26,9 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca if process_caption: caption = "-" + shared.interrogator.generate_caption(image) else: - caption = "" + caption = filename + caption = os.path.splitext(caption)[0] + caption = os.path.basename(caption) image.save(os.path.join(dst, f"{index:05}-{subindex[0]}{caption}.png")) subindex[0] += 1 From 1c5604791da7e57f40880698666b6617a1754c65 Mon Sep 17 00:00:00 2001 From: DoTheSneedful Date: Mon, 3 Oct 2022 22:20:09 -0400 Subject: [PATCH 060/460] Add a prompt order option to XY plot script --- scripts/xy_grid.py | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 146663b0a..044c30e61 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -1,5 +1,6 @@ from collections import namedtuple from copy import copy +from itertools import permutations import random from PIL import Image @@ -28,6 +29,27 @@ def apply_prompt(p, x, xs): p.prompt = p.prompt.replace(xs[0], x) p.negative_prompt = p.negative_prompt.replace(xs[0], x) +def apply_order(p, x, xs): + token_order = [] + + # Initally grab the tokens from the prompt so they can be later be replaced in order of earliest seen in the prompt + for token in x: + token_order.append((p.prompt.find(token), token)) + + token_order.sort(key=lambda t: t[0]) + + search_from_pos = 0 + for idx, token in enumerate(x): + original_pos, old_token = token_order[idx] + + # Get position of the token again as it will likely change as tokens are being replaced + pos = p.prompt.find(old_token) + if original_pos >= 0: + # Avoid trying to replace what was just replaced by searching later in the prompt string + p.prompt = p.prompt[0:search_from_pos] + p.prompt[search_from_pos:].replace(old_token, token, 1) + + search_from_pos = pos + len(token) + samplers_dict = {} for i, sampler in enumerate(modules.sd_samplers.samplers): @@ -60,7 +82,8 @@ def format_value_add_label(p, opt, x): def format_value(p, opt, x): if type(x) == float: x = round(x, 8) - + if type(x) == type(list()): + x = str(x) return x def do_nothing(p, x, xs): @@ -89,6 +112,7 @@ axis_options = [ AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label), AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label), AxisOption("Eta", float, apply_field("eta"), format_value_add_label), + AxisOption("Prompt order", type(list()), apply_order, format_value), AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label), # as it is now all AxisOptionImg2Img items must go after AxisOption ones ] @@ -159,7 +183,11 @@ class Script(scripts.Script): if opt.label == 'Nothing': return [0] - valslist = [x.strip() for x in vals.split(",")] + if opt.type == type(list()): + valslist = [x for x in vals] + else: + valslist = [x.strip() for x in vals.split(",")] + if opt.type == int: valslist_ext = [] @@ -212,9 +240,17 @@ class Script(scripts.Script): return valslist x_opt = axis_options[x_type] + + if x_opt.label == "Prompt order": + x_values = list(permutations([x.strip() for x in x_values.split(",")])) + xs = process_axis(x_opt, x_values) y_opt = axis_options[y_type] + + if y_opt.label == "Prompt order": + y_values = list(permutations([y.strip() for y in y_values.split(",")])) + ys = process_axis(y_opt, y_values) def fix_axis_seeds(axis_opt, axis_list): From 1a6d40db35656083d5bf9d3a3430b45fda4e85eb Mon Sep 17 00:00:00 2001 From: DoTheSneedful Date: Tue, 4 Oct 2022 00:18:15 -0400 Subject: [PATCH 061/460] Fix token ordering in prompt order XY plot --- scripts/xy_grid.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 044c30e61..5bcd39217 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -32,24 +32,21 @@ def apply_prompt(p, x, xs): def apply_order(p, x, xs): token_order = [] - # Initally grab the tokens from the prompt so they can be later be replaced in order of earliest seen in the prompt + # Initally grab the tokens from the prompt so they can be be replaced in order of earliest seen for token in x: token_order.append((p.prompt.find(token), token)) token_order.sort(key=lambda t: t[0]) search_from_pos = 0 - for idx, token in enumerate(x): - original_pos, old_token = token_order[idx] - + for idx, (original_pos, old_token) in enumerate(token_order): # Get position of the token again as it will likely change as tokens are being replaced - pos = p.prompt.find(old_token) + pos = search_from_pos + p.prompt[search_from_pos:].find(old_token) if original_pos >= 0: # Avoid trying to replace what was just replaced by searching later in the prompt string - p.prompt = p.prompt[0:search_from_pos] + p.prompt[search_from_pos:].replace(old_token, token, 1) - - search_from_pos = pos + len(token) + p.prompt = p.prompt[0:search_from_pos] + p.prompt[search_from_pos:].replace(old_token, x[idx], 1) + search_from_pos = pos + len(x[idx]) samplers_dict = {} for i, sampler in enumerate(modules.sd_samplers.samplers): From 56371153b545e3a43c3a5f206264019af361f3af Mon Sep 17 00:00:00 2001 From: DoTheSneedful Date: Tue, 4 Oct 2022 01:07:36 -0400 Subject: [PATCH 062/460] XY plot prompt order simplify logic --- scripts/xy_grid.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 5bcd39217..7def47f57 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -38,15 +38,21 @@ def apply_order(p, x, xs): token_order.sort(key=lambda t: t[0]) - search_from_pos = 0 - for idx, (original_pos, old_token) in enumerate(token_order): - # Get position of the token again as it will likely change as tokens are being replaced - pos = search_from_pos + p.prompt[search_from_pos:].find(old_token) - if original_pos >= 0: - # Avoid trying to replace what was just replaced by searching later in the prompt string - p.prompt = p.prompt[0:search_from_pos] + p.prompt[search_from_pos:].replace(old_token, x[idx], 1) + prompt_parts = [] - search_from_pos = pos + len(x[idx]) + # Split the prompt up, taking out the tokens + for _, token in token_order: + n = p.prompt.find(token) + prompt_parts.append(p.prompt[0:n]) + p.prompt = p.prompt[n + len(token):] + + # Rebuild the prompt with the tokens in the order we want + prompt_tmp = "" + for idx, part in enumerate(prompt_parts): + prompt_tmp += part + prompt_tmp += x[idx] + p.prompt = prompt_tmp + p.prompt + samplers_dict = {} for i, sampler in enumerate(modules.sd_samplers.samplers): From 556c36b9607e3f4eacdddc85f8e7a78b29476ea7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 09:18:00 +0300 Subject: [PATCH 063/460] add hint, refactor code for #1607 --- javascript/hints.js | 1 + scripts/xy_grid.py | 35 ++++++++++++++++++----------------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index e72e93381..8adcd983e 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -47,6 +47,7 @@ titles = { "Custom code": "Run Python code. Advanced user only. Must run program with --allow-code for this to work", "Prompt S/R": "Separate a list of words with commas, and the first word will be used as a keyword: script will search for this word in the prompt, and replace it with others", + "Prompt order": "Separate a list of words with commas, and the script will make a variation of prompt with those words for their every possible order", "Tiling": "Produce an image that can be tiled.", "Tile overlap": "For SD upscale, how much overlap in pixels should there be between tiles. Tiles overlap so that when they are merged back into one picture, there is no clearly visible seam.", diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 7def47f57..1237e754d 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -29,10 +29,11 @@ def apply_prompt(p, x, xs): p.prompt = p.prompt.replace(xs[0], x) p.negative_prompt = p.negative_prompt.replace(xs[0], x) + def apply_order(p, x, xs): token_order = [] - # Initally grab the tokens from the prompt so they can be be replaced in order of earliest seen + # Initally grab the tokens from the prompt, so they can be replaced in order of earliest seen for token in x: token_order.append((p.prompt.find(token), token)) @@ -85,17 +86,26 @@ def format_value_add_label(p, opt, x): def format_value(p, opt, x): if type(x) == float: x = round(x, 8) - if type(x) == type(list()): - x = str(x) return x + +def format_value_join_list(p, opt, x): + return ", ".join(x) + + def do_nothing(p, x, xs): pass + def format_nothing(p, opt, x): return "" +def str_permutations(x): + """dummy function for specifying it in AxisOption's type when you want to get a list of permutations""" + return x + + AxisOption = namedtuple("AxisOption", ["label", "type", "apply", "format_value"]) AxisOptionImg2Img = namedtuple("AxisOptionImg2Img", ["label", "type", "apply", "format_value"]) @@ -108,6 +118,7 @@ axis_options = [ AxisOption("Steps", int, apply_field("steps"), format_value_add_label), AxisOption("CFG Scale", float, apply_field("cfg_scale"), format_value_add_label), AxisOption("Prompt S/R", str, apply_prompt, format_value), + AxisOption("Prompt order", str_permutations, apply_order, format_value_join_list), AxisOption("Sampler", str, apply_sampler, format_value), AxisOption("Checkpoint name", str, apply_checkpoint, format_value), AxisOption("Sigma Churn", float, apply_field("s_churn"), format_value_add_label), @@ -115,7 +126,6 @@ axis_options = [ AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label), AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label), AxisOption("Eta", float, apply_field("eta"), format_value_add_label), - AxisOption("Prompt order", type(list()), apply_order, format_value), AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label), # as it is now all AxisOptionImg2Img items must go after AxisOption ones ] @@ -158,6 +168,7 @@ re_range_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d re_range_count = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\[(\d+)\s*\])?\s*") re_range_count_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\[(\d+(?:.\d*)?)\s*\])?\s*") + class Script(scripts.Script): def title(self): return "X/Y plot" @@ -186,11 +197,7 @@ class Script(scripts.Script): if opt.label == 'Nothing': return [0] - if opt.type == type(list()): - valslist = [x for x in vals] - else: - valslist = [x.strip() for x in vals.split(",")] - + valslist = [x.strip() for x in vals.split(",")] if opt.type == int: valslist_ext = [] @@ -237,23 +244,17 @@ class Script(scripts.Script): valslist_ext.append(val) valslist = valslist_ext + elif opt.type == str_permutations: + valslist = list(permutations(valslist)) valslist = [opt.type(x) for x in valslist] return valslist x_opt = axis_options[x_type] - - if x_opt.label == "Prompt order": - x_values = list(permutations([x.strip() for x in x_values.split(",")])) - xs = process_axis(x_opt, x_values) y_opt = axis_options[y_type] - - if y_opt.label == "Prompt order": - y_values = list(permutations([y.strip() for y in y_values.split(",")])) - ys = process_axis(y_opt, y_values) def fix_axis_seeds(axis_opt, axis_list): From eeab7aedf532680a6ae9058ee272450bb07e41eb Mon Sep 17 00:00:00 2001 From: brkirch Date: Tue, 4 Oct 2022 04:24:35 -0400 Subject: [PATCH 064/460] Add --use-cpu command line option Remove MPS detection to use CPU for GFPGAN / CodeFormer and add a --use-cpu command line option. --- modules/devices.py | 5 ++--- modules/esrgan_model.py | 9 ++++----- modules/scunet_model.py | 8 ++++---- modules/shared.py | 9 +++++++-- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/modules/devices.py b/modules/devices.py index 5d9c7a076..b5a0cd29e 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -1,8 +1,8 @@ import torch -# has_mps is only available in nightly pytorch (for now), `getattr` for compatibility from modules import errors +# has_mps is only available in nightly pytorch (for now), `getattr` for compatibility has_mps = getattr(torch, 'has_mps', False) cpu = torch.device("cpu") @@ -32,8 +32,7 @@ def enable_tf32(): errors.run(enable_tf32, "Enabling TF32") -device = get_optimal_device() -device_gfpgan = device_codeformer = cpu if device.type == 'mps' else device +device = device_gfpgan = device_esrgan = device_scunet = device_codeformer = get_optimal_device() dtype = torch.float16 def randn(seed, shape): diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py index 4aed9283c..d17e730f9 100644 --- a/modules/esrgan_model.py +++ b/modules/esrgan_model.py @@ -6,8 +6,7 @@ from PIL import Image from basicsr.utils.download_util import load_file_from_url import modules.esrgam_model_arch as arch -from modules import shared, modelloader, images -from modules.devices import has_mps +from modules import shared, modelloader, images, devices from modules.paths import models_path from modules.upscaler import Upscaler, UpscalerData from modules.shared import opts @@ -97,7 +96,7 @@ class UpscalerESRGAN(Upscaler): model = self.load_model(selected_model) if model is None: return img - model.to(shared.device) + model.to(devices.device_esrgan) img = esrgan_upscale(model, img) return img @@ -112,7 +111,7 @@ class UpscalerESRGAN(Upscaler): print("Unable to load %s from %s" % (self.model_path, filename)) return None - pretrained_net = torch.load(filename, map_location='cpu' if has_mps else None) + pretrained_net = torch.load(filename, map_location='cpu' if shared.device.type == 'mps' else None) crt_model = arch.RRDBNet(3, 3, 64, 23, gc=32) pretrained_net = fix_model_layers(crt_model, pretrained_net) @@ -127,7 +126,7 @@ def upscale_without_tiling(model, img): img = img[:, :, ::-1] img = np.moveaxis(img, 2, 0) / 255 img = torch.from_numpy(img).float() - img = img.unsqueeze(0).to(shared.device) + img = img.unsqueeze(0).to(devices.device_esrgan) with torch.no_grad(): output = model(img) output = output.squeeze().float().cpu().clamp_(0, 1).numpy() diff --git a/modules/scunet_model.py b/modules/scunet_model.py index 7987ac145..fb64b7409 100644 --- a/modules/scunet_model.py +++ b/modules/scunet_model.py @@ -8,7 +8,7 @@ import torch from basicsr.utils.download_util import load_file_from_url import modules.upscaler -from modules import shared, modelloader +from modules import devices, modelloader from modules.paths import models_path from modules.scunet_model_arch import SCUNet as net @@ -51,12 +51,12 @@ class UpscalerScuNET(modules.upscaler.Upscaler): if model is None: return img - device = shared.device + device = devices.device_scunet img = np.array(img) img = img[:, :, ::-1] img = np.moveaxis(img, 2, 0) / 255 img = torch.from_numpy(img).float() - img = img.unsqueeze(0).to(shared.device) + img = img.unsqueeze(0).to(device) img = img.to(device) with torch.no_grad(): @@ -69,7 +69,7 @@ class UpscalerScuNET(modules.upscaler.Upscaler): return PIL.Image.fromarray(output, 'RGB') def load_model(self, path: str): - device = shared.device + device = devices.device_scunet if "http" in path: filename = load_file_from_url(url=self.model_url, model_dir=self.model_path, file_name="%s.pth" % self.name, progress=True) diff --git a/modules/shared.py b/modules/shared.py index 2a599e9cf..7899ab8d1 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -12,7 +12,7 @@ import modules.interrogate import modules.memmon import modules.sd_models import modules.styles -from modules.devices import get_optimal_device +import modules.devices as devices from modules.paths import script_path, sd_path sd_model_file = os.path.join(script_path, 'model.ckpt') @@ -46,6 +46,7 @@ parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") +parser.add_argument("--use-cpu", nargs='+',choices=['SD', 'GFPGAN', 'ESRGAN', 'SCUNet', 'CodeFormer'], help="use CPU for specified modules", default=[]) parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests") parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None) parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False) @@ -63,7 +64,11 @@ parser.add_argument("--enable-console-prompts", action='store_true', help="print cmd_opts = parser.parse_args() -device = get_optimal_device() + +devices.device, devices.device_gfpgan, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \ +(devices.cpu if x in cmd_opts.use_cpu else devices.get_optimal_device() for x in ['SD', 'GFPGAN', 'ESRGAN', 'SCUNet', 'CodeFormer']) + +device = devices.device batch_cond_uncond = cmd_opts.always_batch_cond_uncond or not (cmd_opts.lowvram or cmd_opts.medvram) parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram From 27ddc24fdee1fbe709054a43235ab7f9c51b3e9f Mon Sep 17 00:00:00 2001 From: brkirch Date: Tue, 4 Oct 2022 05:18:17 -0400 Subject: [PATCH 065/460] Add BSRGAN to --add-cpu --- modules/bsrgan_model.py | 6 +++--- modules/devices.py | 2 +- modules/shared.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/bsrgan_model.py b/modules/bsrgan_model.py index e62c66577..3bd80791a 100644 --- a/modules/bsrgan_model.py +++ b/modules/bsrgan_model.py @@ -8,7 +8,7 @@ import torch from basicsr.utils.download_util import load_file_from_url import modules.upscaler -from modules import shared, modelloader +from modules import devices, modelloader from modules.bsrgan_model_arch import RRDBNet from modules.paths import models_path @@ -44,13 +44,13 @@ class UpscalerBSRGAN(modules.upscaler.Upscaler): model = self.load_model(selected_file) if model is None: return img - model.to(shared.device) + model.to(devices.device_bsrgan) torch.cuda.empty_cache() img = np.array(img) img = img[:, :, ::-1] img = np.moveaxis(img, 2, 0) / 255 img = torch.from_numpy(img).float() - img = img.unsqueeze(0).to(shared.device) + img = img.unsqueeze(0).to(devices.device_bsrgan) with torch.no_grad(): output = model(img) output = output.squeeze().float().cpu().clamp_(0, 1).numpy() diff --git a/modules/devices.py b/modules/devices.py index b5a0cd29e..b78996322 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -32,7 +32,7 @@ def enable_tf32(): errors.run(enable_tf32, "Enabling TF32") -device = device_gfpgan = device_esrgan = device_scunet = device_codeformer = get_optimal_device() +device = device_gfpgan = device_bsrgan = device_esrgan = device_scunet = device_codeformer = get_optimal_device() dtype = torch.float16 def randn(seed, shape): diff --git a/modules/shared.py b/modules/shared.py index 7899ab8d1..95b98a06e 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -46,7 +46,7 @@ parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") -parser.add_argument("--use-cpu", nargs='+',choices=['SD', 'GFPGAN', 'ESRGAN', 'SCUNet', 'CodeFormer'], help="use CPU for specified modules", default=[]) +parser.add_argument("--use-cpu", nargs='+',choices=['SD', 'GFPGAN', 'BSRGAN', 'ESRGAN', 'SCUNet', 'CodeFormer'], help="use CPU for specified modules", default=[]) parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests") parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None) parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False) @@ -65,8 +65,8 @@ parser.add_argument("--enable-console-prompts", action='store_true', help="print cmd_opts = parser.parse_args() -devices.device, devices.device_gfpgan, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \ -(devices.cpu if x in cmd_opts.use_cpu else devices.get_optimal_device() for x in ['SD', 'GFPGAN', 'ESRGAN', 'SCUNet', 'CodeFormer']) +devices.device, devices.device_gfpgan, devices.device_bsrgan, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \ +(devices.cpu if x in cmd_opts.use_cpu else devices.get_optimal_device() for x in ['SD', 'GFPGAN', 'BSRGAN', 'ESRGAN', 'SCUNet', 'CodeFormer']) device = devices.device From dc9c5a97742e3a34d37da7108642d8adc0dc5858 Mon Sep 17 00:00:00 2001 From: brkirch Date: Tue, 4 Oct 2022 05:22:50 -0400 Subject: [PATCH 066/460] Modify --add-cpu description --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 95b98a06e..25aff5b0e 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -46,7 +46,7 @@ parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") -parser.add_argument("--use-cpu", nargs='+',choices=['SD', 'GFPGAN', 'BSRGAN', 'ESRGAN', 'SCUNet', 'CodeFormer'], help="use CPU for specified modules", default=[]) +parser.add_argument("--use-cpu", nargs='+',choices=['SD', 'GFPGAN', 'BSRGAN', 'ESRGAN', 'SCUNet', 'CodeFormer'], help="use CPU as torch device for specified modules", default=[]) parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests") parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None) parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False) From 6c6ae28bf5fd1e8bc3e8f64a3430b6f29f338f77 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 12:32:22 +0300 Subject: [PATCH 067/460] send all three of GFPGAN's and codeformer's models to CPU memory instead of just one for #1283 --- modules/codeformer_model.py | 12 ++++++++++-- modules/devices.py | 10 ++++++++++ modules/gfpgan_model.py | 14 ++++++++++++-- modules/processing.py | 16 +++++++++------- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/modules/codeformer_model.py b/modules/codeformer_model.py index a29f38550..e6d9fa4f4 100644 --- a/modules/codeformer_model.py +++ b/modules/codeformer_model.py @@ -69,10 +69,14 @@ def setup_model(dirname): self.net = net self.face_helper = face_helper - self.net.to(devices.device_codeformer) return net, face_helper + def send_model_to(self, device): + self.net.to(device) + self.face_helper.face_det.to(device) + self.face_helper.face_parse.to(device) + def restore(self, np_image, w=None): np_image = np_image[:, :, ::-1] @@ -82,6 +86,8 @@ def setup_model(dirname): if self.net is None or self.face_helper is None: return np_image + self.send_model_to(devices.device_codeformer) + self.face_helper.clean_all() self.face_helper.read_image(np_image) self.face_helper.get_face_landmarks_5(only_center_face=False, resize=640, eye_dist_threshold=5) @@ -113,8 +119,10 @@ def setup_model(dirname): if original_resolution != restored_img.shape[0:2]: restored_img = cv2.resize(restored_img, (0, 0), fx=original_resolution[1]/restored_img.shape[1], fy=original_resolution[0]/restored_img.shape[0], interpolation=cv2.INTER_LINEAR) + self.face_helper.clean_all() + if shared.opts.face_restoration_unload: - self.net.to(devices.cpu) + self.send_model_to(devices.cpu) return restored_img diff --git a/modules/devices.py b/modules/devices.py index ff82f2f64..12aab6652 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -1,3 +1,5 @@ +import contextlib + import torch # has_mps is only available in nightly pytorch (for now), `getattr` for compatibility @@ -57,3 +59,11 @@ def randn_without_seed(shape): return torch.randn(shape, device=device) + +def autocast(): + from modules import shared + + if dtype == torch.float32 or shared.cmd_opts.precision == "full": + return contextlib.nullcontext() + + return torch.autocast("cuda") diff --git a/modules/gfpgan_model.py b/modules/gfpgan_model.py index dd3fbcab1..5586b554b 100644 --- a/modules/gfpgan_model.py +++ b/modules/gfpgan_model.py @@ -37,22 +37,32 @@ def gfpgann(): print("Unable to load gfpgan model!") return None model = gfpgan_constructor(model_path=model_file, upscale=1, arch='clean', channel_multiplier=2, bg_upsampler=None) - model.gfpgan.to(shared.device) loaded_gfpgan_model = model return model +def send_model_to(model, device): + model.gfpgan.to(device) + model.face_helper.face_det.to(device) + model.face_helper.face_parse.to(device) + + def gfpgan_fix_faces(np_image): model = gfpgann() if model is None: return np_image + + send_model_to(model, devices.device) + np_image_bgr = np_image[:, :, ::-1] cropped_faces, restored_faces, gfpgan_output_bgr = model.enhance(np_image_bgr, has_aligned=False, only_center_face=False, paste_back=True) np_image = gfpgan_output_bgr[:, :, ::-1] + model.face_helper.clean_all() + if shared.opts.face_restoration_unload: - model.gfpgan.to(devices.cpu) + send_model_to(model, devices.cpu) return np_image diff --git a/modules/processing.py b/modules/processing.py index 0a4b6198f..9cbecdd83 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -1,4 +1,3 @@ -import contextlib import json import math import os @@ -330,9 +329,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: infotexts = [] output_images = [] - precision_scope = torch.autocast if cmd_opts.precision == "autocast" else contextlib.nullcontext - ema_scope = (contextlib.nullcontext if cmd_opts.lowvram else p.sd_model.ema_scope) - with torch.no_grad(), precision_scope("cuda"), ema_scope(): + + with torch.no_grad(): p.init(all_prompts, all_seeds, all_subseeds) if state.job_count == -1: @@ -351,8 +349,9 @@ def process_images(p: StableDiffusionProcessing) -> Processed: #uc = p.sd_model.get_learned_conditioning(len(prompts) * [p.negative_prompt]) #c = p.sd_model.get_learned_conditioning(prompts) - uc = prompt_parser.get_learned_conditioning(len(prompts) * [p.negative_prompt], p.steps) - c = prompt_parser.get_learned_conditioning(prompts, p.steps) + with devices.autocast(): + uc = prompt_parser.get_learned_conditioning(len(prompts) * [p.negative_prompt], p.steps) + c = prompt_parser.get_learned_conditioning(prompts, p.steps) if len(model_hijack.comments) > 0: for comment in model_hijack.comments: @@ -361,7 +360,9 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if p.n_iter > 1: shared.state.job = f"Batch {n+1} out of {p.n_iter}" - samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength) + with devices.autocast(): + samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength).to(devices.dtype) + if state.interrupted: # if we are interruped, sample returns just noise @@ -386,6 +387,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: devices.torch_gc() x_sample = modules.face_restoration.restore_faces(x_sample) + devices.torch_gc() image = Image.fromarray(x_sample) From 2f1b61d97987ae0a52a7dfc6bc99c68928bdb594 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 3 Oct 2022 19:25:36 +0800 Subject: [PATCH 068/460] Allow nested structures inside schedules --- modules/prompt_parser.py | 119 +++++++++++++++++--------------------- requirements.txt | 1 + requirements_versions.txt | 1 + 3 files changed, 55 insertions(+), 66 deletions(-) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index e811eb9ec..99c8ed99c 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -1,20 +1,11 @@ import re from collections import namedtuple import torch +from lark import Lark, Transformer, Visitor +import functools import modules.shared as shared -re_prompt = re.compile(r''' -(.*?) -\[ - ([^]:]+): - (?:([^]:]*):)? - ([0-9]*\.?[0-9]+) -] -| -(.+) -''', re.X) - # a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]" # will be represented with prompt_schedule like this (assuming steps=100): # [25, 'fantasy landscape with a mountain and an oak in foreground shoddy'] @@ -25,61 +16,57 @@ re_prompt = re.compile(r''' def get_learned_conditioning_prompt_schedules(prompts, steps): - res = [] - cache = {} - - for prompt in prompts: - prompt_schedule: list[list[str | int]] = [[steps, ""]] - - cached = cache.get(prompt, None) - if cached is not None: - res.append(cached) - continue - - for m in re_prompt.finditer(prompt): - plaintext = m.group(1) if m.group(5) is None else m.group(5) - concept_from = m.group(2) - concept_to = m.group(3) - if concept_to is None: - concept_to = concept_from - concept_from = "" - swap_position = float(m.group(4)) if m.group(4) is not None else None - - if swap_position is not None: - if swap_position < 1: - swap_position = swap_position * steps - swap_position = int(min(swap_position, steps)) - - swap_index = None - found_exact_index = False - for i in range(len(prompt_schedule)): - end_step = prompt_schedule[i][0] - prompt_schedule[i][1] += plaintext - - if swap_position is not None and swap_index is None: - if swap_position == end_step: - swap_index = i - found_exact_index = True - - if swap_position < end_step: - swap_index = i - - if swap_index is not None: - if not found_exact_index: - prompt_schedule.insert(swap_index, [swap_position, prompt_schedule[swap_index][1]]) - - for i in range(len(prompt_schedule)): - end_step = prompt_schedule[i][0] - must_replace = swap_position < end_step - - prompt_schedule[i][1] += concept_to if must_replace else concept_from - - res.append(prompt_schedule) - cache[prompt] = prompt_schedule - #for t in prompt_schedule: - # print(t) - - return res + grammar = r""" + start: prompt + prompt: (emphasized | scheduled | weighted | plain)* + !emphasized: "(" prompt ")" + | "(" prompt ":" prompt ")" + | "[" prompt "]" + scheduled: "[" (prompt ":")? prompt ":" NUMBER "]" + !weighted: "{" weighted_item ("|" weighted_item)* "}" + !weighted_item: prompt (":" prompt)? + plain: /([^\\\[\](){}:|]|\\.)+/ + %import common.SIGNED_NUMBER -> NUMBER + """ + parser = Lark(grammar, parser='lalr') + def collect_steps(steps, tree): + l = [steps] + class CollectSteps(Visitor): + def scheduled(self, tree): + tree.children[-1] = float(tree.children[-1]) + if tree.children[-1] < 1: + tree.children[-1] *= steps + tree.children[-1] = min(steps, int(tree.children[-1])) + l.append(tree.children[-1]) + CollectSteps().visit(tree) + return sorted(set(l)) + def at_step(step, tree): + class AtStep(Transformer): + def scheduled(self, args): + if len(args) == 2: + before, after, when = (), *args + else: + before, after, when = args + yield before if step <= when else after + def start(self, args): + def flatten(x): + if type(x) == str: + yield x + else: + for gen in x: + yield from flatten(gen) + return ''.join(flatten(args[0])) + def plain(self, args): + yield args[0].value + def __default__(self, data, children, meta): + for child in children: + yield from child + return AtStep().transform(tree) + @functools.cache + def get_schedule(prompt): + tree = parser.parse(prompt) + return [[t, at_step(t, tree)] for t in collect_steps(steps, tree)] + return [get_schedule(prompt) for prompt in prompts] ScheduledPromptConditioning = namedtuple("ScheduledPromptConditioning", ["end_at_step", "cond"]) diff --git a/requirements.txt b/requirements.txt index d4b337fce..631fe616a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,3 +22,4 @@ clean-fid resize-right torchdiffeq kornia +lark diff --git a/requirements_versions.txt b/requirements_versions.txt index 8a9acf205..fdff26878 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -21,3 +21,4 @@ clean-fid==0.1.29 resize-right==0.0.2 torchdiffeq==0.2.3 kornia==0.6.7 +lark==1.1.2 From 61652461242951966e5b4cee83ce359cefa91c17 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 14:23:22 +0300 Subject: [PATCH 069/460] support interrupting after the previous change --- modules/processing.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index 9cbecdd83..6f5599c7d 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -361,7 +361,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: shared.state.job = f"Batch {n+1} out of {p.n_iter}" with devices.autocast(): - samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength).to(devices.dtype) + samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength) if state.interrupted: @@ -369,6 +369,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: # use the image collected previously in sampler loop samples_ddim = shared.state.current_latent + samples_ddim = samples_ddim.to(devices.dtype) + x_samples_ddim = p.sd_model.decode_first_stage(samples_ddim) x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0) From d5bba20a58f43a9f984bb67b4e17f48661f6b818 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 14:35:12 +0300 Subject: [PATCH 070/460] ignore errors in parse for purposes of token counting for #1564 --- modules/ui.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 55f7aa953..20dc8c379 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -386,14 +386,22 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: outputs=[seed, dummy_component] ) + def update_token_counter(text, steps): - prompt_schedules = get_learned_conditioning_prompt_schedules([text], steps) + try: + prompt_schedules = get_learned_conditioning_prompt_schedules([text], steps) + except Exception: + # a parsing error can happen here during typing, and we don't want to bother the user with + # messages related to it in console + prompt_schedules = [[[steps, text]]] + flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules) - prompts = [prompt_text for step,prompt_text in flat_prompts] + prompts = [prompt_text for step, prompt_text in flat_prompts] tokens, token_count, max_length = max([model_hijack.tokenize(prompt) for prompt in prompts], key=lambda args: args[1]) style_class = ' class="red"' if (token_count > max_length) else "" return f"{token_count}/{max_length}" + def create_toprow(is_img2img): id_part = "img2img" if is_img2img else "txt2img" From accd00d6b8258c12b5168918a4c546b02357924a Mon Sep 17 00:00:00 2001 From: Justin Riddiough Date: Tue, 4 Oct 2022 01:14:28 -0500 Subject: [PATCH 071/460] Explain how to use second progress bar in pycharm --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 25aff5b0e..11bdf01a7 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -200,7 +200,7 @@ options_templates.update(options_section(('face-restoration', "Face restoration" options_templates.update(options_section(('system', "System"), { "memmon_poll_rate": OptionInfo(8, "VRAM usage polls per second during generation. Set to 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}), "samples_log_stdout": OptionInfo(False, "Always print all generation info to standard output"), - "multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job. Broken in PyCharm console."), + "multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job. In PyCharm select 'emulate terminal in console output'."), })) options_templates.update(options_section(('sd', "Stable Diffusion"), { From ea6b0d98a64290a0305e27126ea59ce1da7959a2 Mon Sep 17 00:00:00 2001 From: Justin Riddiough Date: Tue, 4 Oct 2022 06:38:45 -0500 Subject: [PATCH 072/460] Remove pycharm note, fix typo --- modules/shared.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 11bdf01a7..a7d13b2d4 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -200,7 +200,7 @@ options_templates.update(options_section(('face-restoration', "Face restoration" options_templates.update(options_section(('system', "System"), { "memmon_poll_rate": OptionInfo(8, "VRAM usage polls per second during generation. Set to 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}), "samples_log_stdout": OptionInfo(False, "Always print all generation info to standard output"), - "multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job. In PyCharm select 'emulate terminal in console output'."), + "multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job."), })) options_templates.update(options_section(('sd', "Stable Diffusion"), { @@ -209,7 +209,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"), "img2img_fix_steps": OptionInfo(False, "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising)."), "enable_quantization": OptionInfo(False, "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply."), - "enable_emphasis": OptionInfo(True, "Eemphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention"), + "enable_emphasis": OptionInfo(True, "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention"), "use_old_emphasis_implementation": OptionInfo(False, "Use old emphasis implementation. Can be useful to reproduce old seeds."), "enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"), "filter_nsfw": OptionInfo(False, "Filter NSFW content"), From eec1b39bd54711ca31e43022d2d6ac8c6d7281da Mon Sep 17 00:00:00 2001 From: Milly Date: Tue, 4 Oct 2022 20:16:52 +0900 Subject: [PATCH 073/460] Apply prompt pattern last --- modules/images.py | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/modules/images.py b/modules/images.py index bba55158e..5b56c7e37 100644 --- a/modules/images.py +++ b/modules/images.py @@ -287,32 +287,13 @@ def apply_filename_pattern(x, p, seed, prompt): if seed is not None: x = x.replace("[seed]", str(seed)) - if prompt is not None: - x = x.replace("[prompt]", sanitize_filename_part(prompt)) - if "[prompt_no_styles]" in x: - prompt_no_style = prompt - for style in shared.prompt_styles.get_style_prompts(p.styles): - if len(style) > 0: - style_parts = [y for y in style.split("{prompt}")] - for part in style_parts: - prompt_no_style = prompt_no_style.replace(part, "").replace(", ,", ",").strip().strip(',') - prompt_no_style = prompt_no_style.replace(style, "").strip().strip(',').strip() - x = x.replace("[prompt_no_styles]", sanitize_filename_part(prompt_no_style, replace_spaces=False)) - - x = x.replace("[prompt_spaces]", sanitize_filename_part(prompt, replace_spaces=False)) - if "[prompt_words]" in x: - words = [x for x in re_nonletters.split(prompt or "") if len(x) > 0] - if len(words) == 0: - words = ["empty"] - x = x.replace("[prompt_words]", sanitize_filename_part(" ".join(words[0:max_prompt_words]), replace_spaces=False)) - if p is not None: x = x.replace("[steps]", str(p.steps)) x = x.replace("[cfg]", str(p.cfg_scale)) x = x.replace("[width]", str(p.width)) x = x.replace("[height]", str(p.height)) - - #currently disabled if using the save button, will work otherwise + + #currently disabled if using the save button, will work otherwise # if enabled it will cause a bug because styles is not included in the save_files data dictionary if hasattr(p, "styles"): x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"] or "None"), replace_spaces=False)) @@ -324,6 +305,26 @@ def apply_filename_pattern(x, p, seed, prompt): x = x.replace("[datetime]", datetime.datetime.now().strftime("%Y%m%d%H%M%S")) x = x.replace("[job_timestamp]", shared.state.job_timestamp) + # Apply [prompt] at last. Because it may contain any replacement word.^M + if prompt is not None: + x = x.replace("[prompt]", sanitize_filename_part(prompt)) + if "[prompt_no_styles]" in x: + prompt_no_style = prompt + for style in shared.prompt_styles.get_style_prompts(p.styles): + if len(style) > 0: + style_parts = [y for y in style.split("{prompt}")] + for part in style_parts: + prompt_no_style = prompt_no_style.replace(part, "").replace(", ,", ",").strip().strip(',') + prompt_no_style = prompt_no_style.replace(style, "").strip().strip(',').strip() + x = x.replace("[prompt_no_styles]", sanitize_filename_part(prompt_no_style, replace_spaces=False)) + + x = x.replace("[prompt_spaces]", sanitize_filename_part(prompt, replace_spaces=False)) + if "[prompt_words]" in x: + words = [x for x in re_nonletters.split(prompt or "") if len(x) > 0] + if len(words) == 0: + words = ["empty"] + x = x.replace("[prompt_words]", sanitize_filename_part(" ".join(words[0:max_prompt_words]), replace_spaces=False)) + if cmd_opts.hide_ui_dir_config: x = re.sub(r'^[\\/]+|\.{2,}[\\/]+|[\\/]+\.{2,}', '', x) From 52cef36f6ba169a8e606ecdcaed73d47378f0e8e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 16:54:31 +0300 Subject: [PATCH 074/460] emergency fix for img2img --- modules/processing.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index 6f5599c7d..e9c453942 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -331,7 +331,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: output_images = [] with torch.no_grad(): - p.init(all_prompts, all_seeds, all_subseeds) + with devices.autocast(): + p.init(all_prompts, all_seeds, all_subseeds) if state.job_count == -1: state.job_count = p.n_iter From 957e29a8e9cb8ca069799ec69263e188c89ed6a6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 17:23:48 +0300 Subject: [PATCH 075/460] option to not show images in web ui --- modules/img2img.py | 3 +++ modules/shared.py | 1 + modules/txt2img.py | 3 +++ 3 files changed, 7 insertions(+) diff --git a/modules/img2img.py b/modules/img2img.py index 2ff8e2617..da212d72b 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -129,4 +129,7 @@ def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, pro if opts.samples_log_stdout: print(generation_info_js) + if opts.do_not_show_images: + processed.images = [] + return processed.images, generation_info_js, plaintext_to_html(processed.info) diff --git a/modules/shared.py b/modules/shared.py index a7d13b2d4..ff4e5fa39 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -229,6 +229,7 @@ options_templates.update(options_section(('ui', "User interface"), { "show_progressbar": OptionInfo(True, "Show progressbar"), "show_progress_every_n_steps": OptionInfo(0, "Show show image creation progress every N sampling steps. Set 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}), "return_grid": OptionInfo(True, "Show grid in results for web"), + "do_not_show_images": OptionInfo(False, "Do not show any images in results for web"), "add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"), "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), diff --git a/modules/txt2img.py b/modules/txt2img.py index d4406c3c0..e985242b3 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -48,5 +48,8 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: if opts.samples_log_stdout: print(generation_info_js) + if opts.do_not_show_images: + processed.images = [] + return processed.images, generation_info_js, plaintext_to_html(processed.info) From e1b128d8e46bddb9c0b2fd3ee0eefd57e0527ee0 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 17:36:39 +0300 Subject: [PATCH 076/460] do not touch p.seed/p.subseed during processing #1181 --- modules/processing.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index e9c453942..8180c63d8 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -248,9 +248,16 @@ def create_random_tensors(shape, seeds, subseeds=None, subseed_strength=0.0, see return x +def get_fixed_seed(seed): + if seed is None or seed == '' or seed == -1: + return int(random.randrange(4294967294)) + + return seed + + def fix_seed(p): - p.seed = int(random.randrange(4294967294)) if p.seed is None or p.seed == '' or p.seed == -1 else p.seed - p.subseed = int(random.randrange(4294967294)) if p.subseed is None or p.subseed == '' or p.subseed == -1 else p.subseed + p.seed = get_fixed_seed(p.seed) + p.subseed = get_fixed_seed(p.subseed) def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration=0, position_in_batch=0): @@ -292,7 +299,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: devices.torch_gc() - fix_seed(p) + seed = get_fixed_seed(p.seed) + subseed = get_fixed_seed(p.subseed) if p.outpath_samples is not None: os.makedirs(p.outpath_samples, exist_ok=True) @@ -311,15 +319,15 @@ def process_images(p: StableDiffusionProcessing) -> Processed: else: all_prompts = p.batch_size * p.n_iter * [p.prompt] - if type(p.seed) == list: - all_seeds = p.seed + if type(seed) == list: + all_seeds = seed else: - all_seeds = [int(p.seed) + (x if p.subseed_strength == 0 else 0) for x in range(len(all_prompts))] + all_seeds = [int(seed) + (x if p.subseed_strength == 0 else 0) for x in range(len(all_prompts))] - if type(p.subseed) == list: - all_subseeds = p.subseed + if type(subseed) == list: + all_subseeds = subseed else: - all_subseeds = [int(p.subseed) + x for x in range(len(all_prompts))] + all_subseeds = [int(subseed) + x for x in range(len(all_prompts))] def infotext(iteration=0, position_in_batch=0): return create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration, position_in_batch) From 1eb588cbf19924333b88beaa1ac0041904966640 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 18:02:01 +0300 Subject: [PATCH 077/460] remove functools.cache as some people are having issues with it --- modules/prompt_parser.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 99c8ed99c..5d58c4ed9 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -29,6 +29,7 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): %import common.SIGNED_NUMBER -> NUMBER """ parser = Lark(grammar, parser='lalr') + def collect_steps(steps, tree): l = [steps] class CollectSteps(Visitor): @@ -40,6 +41,7 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): l.append(tree.children[-1]) CollectSteps().visit(tree) return sorted(set(l)) + def at_step(step, tree): class AtStep(Transformer): def scheduled(self, args): @@ -62,11 +64,13 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): for child in children: yield from child return AtStep().transform(tree) - @functools.cache + def get_schedule(prompt): tree = parser.parse(prompt) return [[t, at_step(t, tree)] for t in collect_steps(steps, tree)] - return [get_schedule(prompt) for prompt in prompts] + + promptdict = {prompt: get_schedule(prompt) for prompt in set(prompts)} + return [promptdict[prompt] for prompt in prompts] ScheduledPromptConditioning = namedtuple("ScheduledPromptConditioning", ["end_at_step", "cond"]) From 90e911fd546e76f879b38a764473569911a0f845 Mon Sep 17 00:00:00 2001 From: Rae Fu Date: Tue, 4 Oct 2022 09:49:51 -0600 Subject: [PATCH 078/460] prompt_parser: allow spaces in schedules, add test, log/ignore errors Only build the parser once (at import time) instead of for each step. doctest is run by simply executing modules/prompt_parser.py --- modules/processing.py | 10 +-- modules/prompt_parser.py | 139 +++++++++++++++++++++++++-------------- 2 files changed, 95 insertions(+), 54 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 8180c63d8..bb94033b1 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -84,7 +84,7 @@ class StableDiffusionProcessing: self.s_tmin = opts.s_tmin self.s_tmax = float('inf') # not representable as a standard ui option self.s_noise = opts.s_noise - + if not seed_enable_extras: self.subseed = -1 self.subseed_strength = 0 @@ -296,7 +296,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: assert(len(p.prompt) > 0) else: assert p.prompt is not None - + devices.torch_gc() seed = get_fixed_seed(p.seed) @@ -359,8 +359,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: #uc = p.sd_model.get_learned_conditioning(len(prompts) * [p.negative_prompt]) #c = p.sd_model.get_learned_conditioning(prompts) with devices.autocast(): - uc = prompt_parser.get_learned_conditioning(len(prompts) * [p.negative_prompt], p.steps) - c = prompt_parser.get_learned_conditioning(prompts, p.steps) + uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps) + c = prompt_parser.get_learned_conditioning(shared.sd_model, prompts, p.steps) if len(model_hijack.comments) > 0: for comment in model_hijack.comments: @@ -527,7 +527,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): # GC now before running the next img2img to prevent running out of memory x = None devices.torch_gc() - + samples = self.sampler.sample_img2img(self, samples, noise, conditioning, unconditional_conditioning, steps=self.steps) return samples diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 5d58c4ed9..a3b124219 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -1,10 +1,7 @@ import re from collections import namedtuple -import torch -from lark import Lark, Transformer, Visitor -import functools -import modules.shared as shared +import lark # a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]" # will be represented with prompt_schedule like this (assuming steps=100): @@ -14,25 +11,48 @@ import modules.shared as shared # [75, 'fantasy landscape with a lake and an oak in background masterful'] # [100, 'fantasy landscape with a lake and a christmas tree in background masterful'] +schedule_parser = lark.Lark(r""" +!start: (prompt | /[][():]/+)* +prompt: (emphasized | scheduled | plain | WHITESPACE)* +!emphasized: "(" prompt ")" + | "(" prompt ":" prompt ")" + | "[" prompt "]" +scheduled: "[" [prompt ":"] prompt ":" [WHITESPACE] NUMBER "]" +WHITESPACE: /\s+/ +plain: /([^\\\[\]():]|\\.)+/ +%import common.SIGNED_NUMBER -> NUMBER +""") def get_learned_conditioning_prompt_schedules(prompts, steps): - grammar = r""" - start: prompt - prompt: (emphasized | scheduled | weighted | plain)* - !emphasized: "(" prompt ")" - | "(" prompt ":" prompt ")" - | "[" prompt "]" - scheduled: "[" (prompt ":")? prompt ":" NUMBER "]" - !weighted: "{" weighted_item ("|" weighted_item)* "}" - !weighted_item: prompt (":" prompt)? - plain: /([^\\\[\](){}:|]|\\.)+/ - %import common.SIGNED_NUMBER -> NUMBER """ - parser = Lark(grammar, parser='lalr') + >>> g = lambda p: get_learned_conditioning_prompt_schedules([p], 10)[0] + >>> g("test") + [[10, 'test']] + >>> g("a [b:3]") + [[3, 'a '], [10, 'a b']] + >>> g("a [b: 3]") + [[3, 'a '], [10, 'a b']] + >>> g("a [[[b]]:2]") + [[2, 'a '], [10, 'a [[b]]']] + >>> g("[(a:2):3]") + [[3, ''], [10, '(a:2)']] + >>> g("a [b : c : 1] d") + [[1, 'a b d'], [10, 'a c d']] + >>> g("a[b:[c:d:2]:1]e") + [[1, 'abe'], [2, 'ace'], [10, 'ade']] + >>> g("a [unbalanced") + [[10, 'a [unbalanced']] + >>> g("a [b:.5] c") + [[5, 'a c'], [10, 'a b c']] + >>> g("a [{b|d{:.5] c") # not handling this right now + [[5, 'a c'], [10, 'a {b|d{ c']] + >>> g("((a][:b:c [d:3]") + [[3, '((a][:b:c '], [10, '((a][:b:c d']] + """ def collect_steps(steps, tree): l = [steps] - class CollectSteps(Visitor): + class CollectSteps(lark.Visitor): def scheduled(self, tree): tree.children[-1] = float(tree.children[-1]) if tree.children[-1] < 1: @@ -43,13 +63,10 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): return sorted(set(l)) def at_step(step, tree): - class AtStep(Transformer): + class AtStep(lark.Transformer): def scheduled(self, args): - if len(args) == 2: - before, after, when = (), *args - else: - before, after, when = args - yield before if step <= when else after + before, after, _, when = args + yield before or () if step <= when else after def start(self, args): def flatten(x): if type(x) == str: @@ -57,16 +74,22 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): else: for gen in x: yield from flatten(gen) - return ''.join(flatten(args[0])) + return ''.join(flatten(args)) def plain(self, args): yield args[0].value def __default__(self, data, children, meta): for child in children: yield from child return AtStep().transform(tree) - + def get_schedule(prompt): - tree = parser.parse(prompt) + try: + tree = schedule_parser.parse(prompt) + except lark.exceptions.LarkError as e: + if 0: + import traceback + traceback.print_exc() + return [[steps, prompt]] return [[t, at_step(t, tree)] for t in collect_steps(steps, tree)] promptdict = {prompt: get_schedule(prompt) for prompt in set(prompts)} @@ -77,8 +100,7 @@ ScheduledPromptConditioning = namedtuple("ScheduledPromptConditioning", ["end_at ScheduledPromptBatch = namedtuple("ScheduledPromptBatch", ["shape", "schedules"]) -def get_learned_conditioning(prompts, steps): - +def get_learned_conditioning(model, prompts, steps): res = [] prompt_schedules = get_learned_conditioning_prompt_schedules(prompts, steps) @@ -92,7 +114,7 @@ def get_learned_conditioning(prompts, steps): continue texts = [x[1] for x in prompt_schedule] - conds = shared.sd_model.get_learned_conditioning(texts) + conds = model.get_learned_conditioning(texts) cond_schedule = [] for i, (end_at_step, text) in enumerate(prompt_schedule): @@ -105,12 +127,13 @@ def get_learned_conditioning(prompts, steps): def reconstruct_cond_batch(c: ScheduledPromptBatch, current_step): - res = torch.zeros(c.shape, device=shared.device, dtype=next(shared.sd_model.parameters()).dtype) + param = c.schedules[0][0].cond + res = torch.zeros(c.shape, device=param.device, dtype=param.dtype) for i, cond_schedule in enumerate(c.schedules): target_index = 0 - for curret_index, (end_at, cond) in enumerate(cond_schedule): + for current, (end_at, cond) in enumerate(cond_schedule): if current_step <= end_at: - target_index = curret_index + target_index = current break res[i] = cond_schedule[target_index].cond @@ -148,23 +171,26 @@ def parse_prompt_attention(text): \\ - literal character '\' anything else - just text - Example: - - 'a (((house:1.3)) [on] a (hill:0.5), sun, (((sky))).' - - produces: - - [ - ['a ', 1.0], - ['house', 1.5730000000000004], - [' ', 1.1], - ['on', 1.0], - [' a ', 1.1], - ['hill', 0.55], - [', sun, ', 1.1], - ['sky', 1.4641000000000006], - ['.', 1.1] - ] + >>> parse_prompt_attention('normal text') + [['normal text', 1.0]] + >>> parse_prompt_attention('an (important) word') + [['an ', 1.0], ['important', 1.1], [' word', 1.0]] + >>> parse_prompt_attention('(unbalanced') + [['unbalanced', 1.1]] + >>> parse_prompt_attention('\(literal\]') + [['(literal]', 1.0]] + >>> parse_prompt_attention('(unnecessary)(parens)') + [['unnecessaryparens', 1.1]] + >>> parse_prompt_attention('a (((house:1.3)) [on] a (hill:0.5), sun, (((sky))).') + [['a ', 1.0], + ['house', 1.5730000000000004], + [' ', 1.1], + ['on', 1.0], + [' a ', 1.1], + ['hill', 0.55], + [', sun, ', 1.1], + ['sky', 1.4641000000000006], + ['.', 1.1]] """ res = [] @@ -206,4 +232,19 @@ def parse_prompt_attention(text): if len(res) == 0: res = [["", 1.0]] + # merge runs of identical weights + i = 0 + while i + 1 < len(res): + if res[i][1] == res[i + 1][1]: + res[i][0] += res[i + 1][0] + res.pop(i + 1) + else: + i += 1 + return res + +if __name__ == "__main__": + import doctest + doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE) +else: + import torch # doctest faster From b32852ef037251eb3d846af76e2965594e1ac7a5 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 4 Oct 2022 20:49:54 +0300 Subject: [PATCH 079/460] add editor to img2img --- modules/shared.py | 1 + modules/ui.py | 2 +- style.css | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index ff4e5fa39..e52c9b1d1 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -55,6 +55,7 @@ parser.add_argument("--hide-ui-dir-config", action='store_true', help="hide dire parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui settings", default=os.path.join(script_path, 'config.json')) parser.add_argument("--gradio-debug", action='store_true', help="launch gradio with --debug option") parser.add_argument("--gradio-auth", type=str, help='set gradio authentication like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None) +parser.add_argument("--gradio-img2img-tool", type=str, help='gradio image uploader tool: can be either editor for ctopping, or color-sketch for drawing', choices=["color-sketch", "editor"], default="color-sketch") parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last") parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(script_path, 'styles.csv')) parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False) diff --git a/modules/ui.py b/modules/ui.py index 20dc8c379..6cd6761b8 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -644,7 +644,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Tabs(elem_id="mode_img2img") as tabs_img2img_mode: with gr.TabItem('img2img', id='img2img'): - init_img = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil") + init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool=cmd_opts.gradio_img2img_tool) with gr.TabItem('Inpaint', id='inpaint'): init_img_with_mask = gr.Image(label="Image for inpainting with mask", show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA") diff --git a/style.css b/style.css index 39586bf18..e8f4cb752 100644 --- a/style.css +++ b/style.css @@ -403,3 +403,7 @@ input[type="range"]{ .red { color: red; } + +#img2img_image div.h-60{ + height: 480px; +} \ No newline at end of file From ef40e4cd4d383a3405e03f1da3f5b5a1820a8f53 Mon Sep 17 00:00:00 2001 From: xpscyho Date: Tue, 4 Oct 2022 15:12:38 -0400 Subject: [PATCH 080/460] Display time taken in mins, secs when relevant Fixes #1656 --- modules/ui.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index 6cd6761b8..de6342a48 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -196,6 +196,11 @@ def wrap_gradio_call(func, extra_outputs=None): res = extra_outputs_array + [f"
{plaintext_to_html(type(e).__name__+': '+str(e))}
"] elapsed = time.perf_counter() - t + elapsed_m = int(elapsed // 60) + elapsed_s = elapsed % 60 + elapsed_text = f"{elapsed_s:.2f}s" + if (elapsed_m > 0): + elapsed_text = f"{elapsed_m}m "+elapsed_text if run_memmon: mem_stats = {k: -(v//-(1024*1024)) for k, v in shared.mem_mon.stop().items()} @@ -210,7 +215,7 @@ def wrap_gradio_call(func, extra_outputs=None): vram_html = '' # last item is always HTML - res[-1] += f"

Time taken: {elapsed:.2f}s

{vram_html}
" + res[-1] += f"

Time taken: {elapsed_text}

{vram_html}
" shared.state.interrupted = False shared.state.job_count = 0 From 82380d9ac18614c87bebba1b4cfd4b147cc76a18 Mon Sep 17 00:00:00 2001 From: Jairo Correa Date: Tue, 4 Oct 2022 22:28:50 -0300 Subject: [PATCH 081/460] Removing parts no longer needed to fix vram --- modules/devices.py | 3 +-- modules/processing.py | 21 ++++++++------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/modules/devices.py b/modules/devices.py index 6db4e57c9..0158b11fc 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -1,7 +1,6 @@ import contextlib import torch -import gc from modules import errors @@ -20,8 +19,8 @@ def get_optimal_device(): return cpu + def torch_gc(): - gc.collect() if torch.cuda.is_available(): torch.cuda.empty_cache() torch.cuda.ipc_collect() diff --git a/modules/processing.py b/modules/processing.py index e7f9c85e1..f666ba811 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -345,8 +345,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if state.job_count == -1: state.job_count = p.n_iter - for n in range(p.n_iter): - with torch.no_grad(), precision_scope("cuda"), ema_scope(): + for n in range(p.n_iter): if state.interrupted: break @@ -395,22 +394,19 @@ def process_images(p: StableDiffusionProcessing) -> Processed: import modules.safety as safety x_samples_ddim = modules.safety.censor_batch(x_samples_ddim) - for i, x_sample in enumerate(x_samples_ddim): - with torch.no_grad(), precision_scope("cuda"), ema_scope(): + for i, x_sample in enumerate(x_samples_ddim): x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2) x_sample = x_sample.astype(np.uint8) - if p.restore_faces: - with torch.no_grad(), precision_scope("cuda"), ema_scope(): + if p.restore_faces: if opts.save and not p.do_not_save_samples and opts.save_images_before_face_restoration: images.save_image(Image.fromarray(x_sample), p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-face-restoration") + devices.torch_gc() + x_sample = modules.face_restoration.restore_faces(x_sample) devices.torch_gc() - devices.torch_gc() - - with torch.no_grad(), precision_scope("cuda"), ema_scope(): image = Image.fromarray(x_sample) if p.color_corrections is not None and i < len(p.color_corrections): @@ -438,13 +434,12 @@ def process_images(p: StableDiffusionProcessing) -> Processed: infotexts.append(infotext(n, i)) output_images.append(image) - del x_samples_ddim + del x_samples_ddim - devices.torch_gc() + devices.torch_gc() - state.nextjob() + state.nextjob() - with torch.no_grad(), precision_scope("cuda"), ema_scope(): p.color_corrections = None index_of_first_image = 0 From bbdbbd36eda870cf0bd49fdf28476c78919a123e Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Wed, 5 Oct 2022 04:43:05 +0100 Subject: [PATCH 082/460] shared.state.interrupt when restart is requested --- modules/ui.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ui.py b/modules/ui.py index de6342a48..523ab25b3 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1210,6 +1210,7 @@ def create_ui(wrap_gradio_gpu_call): ) def request_restart(): + shared.state.interrupt() settings_interface.gradio_ref.do_restart = True restart_gradio.click( From 67d011b02eddc20202b654dfea56528de3d5edf7 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Wed, 5 Oct 2022 04:44:22 +0100 Subject: [PATCH 083/460] Show generation progress in window title --- javascript/progressbar.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 1e297abbe..3e3220c3f 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -4,6 +4,21 @@ global_progressbars = {} function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_interrupt, id_preview, id_gallery){ var progressbar = gradioApp().getElementById(id_progressbar) var interrupt = gradioApp().getElementById(id_interrupt) + + if(progressbar && progressbar.offsetParent){ + if(progressbar.innerText){ + let newtitle = 'Stable Diffusion - ' + progressbar.innerText + if(document.title != newtitle){ + document.title = newtitle; + } + }else{ + let newtitle = 'Stable Diffusion' + if(document.title != newtitle){ + document.title = newtitle; + } + } + } + if(progressbar!= null && progressbar != global_progressbars[id_progressbar]){ global_progressbars[id_progressbar] = progressbar From 59a2b9e5afc27d2fda72069ca0635070535d18fe Mon Sep 17 00:00:00 2001 From: Greendayle Date: Wed, 5 Oct 2022 20:50:10 +0200 Subject: [PATCH 084/460] deepdanbooru interrogator --- ... deepbooru release project folder here.txt | 0 modules/deepbooru.py | 60 +++++++++++++++++++ modules/ui.py | 24 ++++++-- requirements.txt | 3 + requirements_versions.txt | 3 + style.css | 7 ++- 6 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 models/deepbooru/Put your deepbooru release project folder here.txt create mode 100644 modules/deepbooru.py diff --git a/models/deepbooru/Put your deepbooru release project folder here.txt b/models/deepbooru/Put your deepbooru release project folder here.txt new file mode 100644 index 000000000..e69de29bb diff --git a/modules/deepbooru.py b/modules/deepbooru.py new file mode 100644 index 000000000..958b1c3d8 --- /dev/null +++ b/modules/deepbooru.py @@ -0,0 +1,60 @@ +import os.path +from concurrent.futures import ProcessPoolExecutor + +import numpy as np +import deepdanbooru as dd +import tensorflow as tf + + +def _load_tf_and_return_tags(pil_image, threshold): + this_folder = os.path.dirname(__file__) + model_path = os.path.join(this_folder, '..', 'models', 'deepbooru', 'deepdanbooru-v3-20211112-sgd-e28') + if not os.path.exists(model_path): + return "Download https://github.com/KichangKim/DeepDanbooru/releases/download/v3-20211112-sgd-e28/deepdanbooru-v3-20211112-sgd-e28.zip unpack and put into models/deepbooru" + + tags = dd.project.load_tags_from_project(model_path) + model = dd.project.load_model_from_project( + model_path, compile_model=True + ) + + width = model.input_shape[2] + height = model.input_shape[1] + image = np.array(pil_image) + image = tf.image.resize( + image, + size=(height, width), + method=tf.image.ResizeMethod.AREA, + preserve_aspect_ratio=True, + ) + image = image.numpy() # EagerTensor to np.array + image = dd.image.transform_and_pad_image(image, width, height) + image = image / 255.0 + image_shape = image.shape + image = image.reshape((1, image_shape[0], image_shape[1], image_shape[2])) + + y = model.predict(image)[0] + + result_dict = {} + + for i, tag in enumerate(tags): + result_dict[tag] = y[i] + + + + result_tags_out = [] + result_tags_print = [] + for tag in tags: + if result_dict[tag] >= threshold: + result_tags_out.append(tag) + result_tags_print.append(f'{result_dict[tag]} {tag}') + + print('\n'.join(sorted(result_tags_print, reverse=True))) + + return ', '.join(result_tags_out) + + +def get_deepbooru_tags(pil_image, threshold=0.5): + with ProcessPoolExecutor() as executor: + f = executor.submit(_load_tf_and_return_tags, pil_image, threshold) + ret = f.result() # will rethrow any exceptions + return ret \ No newline at end of file diff --git a/modules/ui.py b/modules/ui.py index 20dc8c379..ae98219a6 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -23,6 +23,7 @@ import gradio.utils import gradio.routes from modules import sd_hijack +from modules.deepbooru import get_deepbooru_tags from modules.paths import script_path from modules.shared import opts, cmd_opts import modules.shared as shared @@ -312,6 +313,11 @@ def interrogate(image): return gr_show(True) if prompt is None else prompt +def interrogate_deepbooru(image): + prompt = get_deepbooru_tags(image) + return gr_show(True) if prompt is None else prompt + + def create_seed_inputs(): with gr.Row(): with gr.Box(): @@ -439,15 +445,17 @@ def create_toprow(is_img2img): outputs=[], ) - with gr.Row(): + with gr.Row(scale=1): if is_img2img: - interrogate = gr.Button('Interrogate', elem_id="interrogate") + interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate") + deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru") else: interrogate = None + deepbooru = None prompt_style_apply = gr.Button('Apply style', elem_id="style_apply") save_style = gr.Button('Create style', elem_id="style_create") - return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, prompt_style_apply, save_style, paste, token_counter, token_button + return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, deepbooru, prompt_style_apply, save_style, paste, token_counter, token_button def setup_progressbar(progressbar, preview, id_part, textinfo=None): @@ -476,7 +484,7 @@ def create_ui(wrap_gradio_gpu_call): import modules.txt2img with gr.Blocks(analytics_enabled=False) as txt2img_interface: - txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, txt2img_prompt_style_apply, txt2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=False) + txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) with gr.Row(elem_id='txt2img_progress_row'): @@ -628,7 +636,7 @@ def create_ui(wrap_gradio_gpu_call): token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) with gr.Blocks(analytics_enabled=False) as img2img_interface: - img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) + img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) with gr.Row(elem_id='img2img_progress_row'): with gr.Column(scale=1): @@ -785,6 +793,12 @@ def create_ui(wrap_gradio_gpu_call): outputs=[img2img_prompt], ) + img2img_deepbooru.click( + fn=interrogate_deepbooru, + inputs=[init_img], + outputs=[img2img_prompt], + ) + save.click( fn=wrap_gradio_call(save_files), _js="(x, y, z) => [x, y, selected_gallery_index()]", diff --git a/requirements.txt b/requirements.txt index 631fe616a..cab101f88 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,3 +23,6 @@ resize-right torchdiffeq kornia lark +deepdanbooru +tensorflow +tensorflow-io diff --git a/requirements_versions.txt b/requirements_versions.txt index fdff26878..811953c68 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -22,3 +22,6 @@ resize-right==0.0.2 torchdiffeq==0.2.3 kornia==0.6.7 lark==1.1.2 +git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] +tensorflow==2.10.0 +tensorflow-io==0.27.0 diff --git a/style.css b/style.css index 39586bf18..2fd351f91 100644 --- a/style.css +++ b/style.css @@ -103,7 +103,12 @@ #style_apply, #style_create, #interrogate{ margin: 0.75em 0.25em 0.25em 0.25em; - min-width: 3em; + min-width: 5em; +} + +#style_apply, #style_create, #deepbooru{ + margin: 0.75em 0.25em 0.25em 0.25em; + min-width: 5em; } #style_pos_col, #style_neg_col{ From 1506fab29ad54beb9f52236912abc432209c8089 Mon Sep 17 00:00:00 2001 From: Greendayle Date: Wed, 5 Oct 2022 21:15:08 +0200 Subject: [PATCH 085/460] removing problematic tag --- modules/deepbooru.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 958b1c3d8..841cb9c5f 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -38,13 +38,12 @@ def _load_tf_and_return_tags(pil_image, threshold): for i, tag in enumerate(tags): result_dict[tag] = y[i] - - - result_tags_out = [] result_tags_print = [] for tag in tags: if result_dict[tag] >= threshold: + if tag.startswith("rating:"): + continue result_tags_out.append(tag) result_tags_print.append(f'{result_dict[tag]} {tag}') From 17a99baf0c929e5df4dfc4b2a96aa3890a141112 Mon Sep 17 00:00:00 2001 From: Greendayle Date: Wed, 5 Oct 2022 22:05:24 +0200 Subject: [PATCH 086/460] better model search --- modules/deepbooru.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 841cb9c5f..a64fd9cd1 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -9,8 +9,15 @@ import tensorflow as tf def _load_tf_and_return_tags(pil_image, threshold): this_folder = os.path.dirname(__file__) model_path = os.path.join(this_folder, '..', 'models', 'deepbooru', 'deepdanbooru-v3-20211112-sgd-e28') - if not os.path.exists(model_path): - return "Download https://github.com/KichangKim/DeepDanbooru/releases/download/v3-20211112-sgd-e28/deepdanbooru-v3-20211112-sgd-e28.zip unpack and put into models/deepbooru" + + model_good = False + for path_candidate in [model_path, os.path.dirname(model_path)]: + if os.path.exists(os.path.join(path_candidate, 'project.json')): + model_path = path_candidate + model_good = True + if not model_good: + return ("Download https://github.com/KichangKim/DeepDanbooru/releases/download/v3-20211112-sgd-e28/" + "deepdanbooru-v3-20211112-sgd-e28.zip unpack and put into models/deepbooru") tags = dd.project.load_tags_from_project(model_path) model = dd.project.load_model_from_project( From c26732fbee2a57e621ac22bf70decf7496daa4cd Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 5 Oct 2022 23:16:27 +0300 Subject: [PATCH 087/460] added support for AND from https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/ --- modules/processing.py | 2 +- modules/prompt_parser.py | 114 ++++++++++++++++++++++++++++++++++++--- modules/sd_samplers.py | 35 ++++++++---- modules/ui.py | 6 ++- 4 files changed, 138 insertions(+), 19 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index bb94033b1..d8c6b8d57 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -360,7 +360,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: #c = p.sd_model.get_learned_conditioning(prompts) with devices.autocast(): uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps) - c = prompt_parser.get_learned_conditioning(shared.sd_model, prompts, p.steps) + c = prompt_parser.get_multicond_learned_conditioning(shared.sd_model, prompts, p.steps) if len(model_hijack.comments) > 0: for comment in model_hijack.comments: diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index a3b124219..f7420daf9 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -97,10 +97,26 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): ScheduledPromptConditioning = namedtuple("ScheduledPromptConditioning", ["end_at_step", "cond"]) -ScheduledPromptBatch = namedtuple("ScheduledPromptBatch", ["shape", "schedules"]) def get_learned_conditioning(model, prompts, steps): + """converts a list of prompts into a list of prompt schedules - each schedule is a list of ScheduledPromptConditioning, specifying the comdition (cond), + and the sampling step at which this condition is to be replaced by the next one. + + Input: + (model, ['a red crown', 'a [blue:green:5] jeweled crown'], 20) + + Output: + [ + [ + ScheduledPromptConditioning(end_at_step=20, cond=tensor([[-0.3886, 0.0229, -0.0523, ..., -0.4901, -0.3066, 0.0674], ..., [ 0.3317, -0.5102, -0.4066, ..., 0.4119, -0.7647, -1.0160]], device='cuda:0')) + ], + [ + ScheduledPromptConditioning(end_at_step=5, cond=tensor([[-0.3886, 0.0229, -0.0522, ..., -0.4901, -0.3067, 0.0673], ..., [-0.0192, 0.3867, -0.4644, ..., 0.1135, -0.3696, -0.4625]], device='cuda:0')), + ScheduledPromptConditioning(end_at_step=20, cond=tensor([[-0.3886, 0.0229, -0.0522, ..., -0.4901, -0.3067, 0.0673], ..., [-0.7352, -0.4356, -0.7888, ..., 0.6994, -0.4312, -1.2593]], device='cuda:0')) + ] + ] + """ res = [] prompt_schedules = get_learned_conditioning_prompt_schedules(prompts, steps) @@ -123,13 +139,75 @@ def get_learned_conditioning(model, prompts, steps): cache[prompt] = cond_schedule res.append(cond_schedule) - return ScheduledPromptBatch((len(prompts),) + res[0][0].cond.shape, res) + return res -def reconstruct_cond_batch(c: ScheduledPromptBatch, current_step): - param = c.schedules[0][0].cond - res = torch.zeros(c.shape, device=param.device, dtype=param.dtype) - for i, cond_schedule in enumerate(c.schedules): +re_AND = re.compile(r"\bAND\b") +re_weight = re.compile(r"^(.*?)(?:\s*:\s*([-+]?\s*(?:\d+|\d*\.\d+)?))?\s*$") + + +def get_multicond_prompt_list(prompts): + res_indexes = [] + + prompt_flat_list = [] + prompt_indexes = {} + + for prompt in prompts: + subprompts = re_AND.split(prompt) + + indexes = [] + for subprompt in subprompts: + text, weight = re_weight.search(subprompt).groups() + + weight = float(weight) if weight is not None else 1.0 + + index = prompt_indexes.get(text, None) + if index is None: + index = len(prompt_flat_list) + prompt_flat_list.append(text) + prompt_indexes[text] = index + + indexes.append((index, weight)) + + res_indexes.append(indexes) + + return res_indexes, prompt_flat_list, prompt_indexes + + +class ComposableScheduledPromptConditioning: + def __init__(self, schedules, weight=1.0): + self.schedules: list[ScheduledPromptConditioning] = schedules + self.weight: float = weight + + +class MulticondLearnedConditioning: + def __init__(self, shape, batch): + self.shape: tuple = shape # the shape field is needed to send this object to DDIM/PLMS + self.batch: list[list[ComposableScheduledPromptConditioning]] = batch + + +def get_multicond_learned_conditioning(model, prompts, steps) -> MulticondLearnedConditioning: + """same as get_learned_conditioning, but returns a list of ScheduledPromptConditioning along with the weight objects for each prompt. + For each prompt, the list is obtained by splitting the prompt using the AND separator. + + https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/ + """ + + res_indexes, prompt_flat_list, prompt_indexes = get_multicond_prompt_list(prompts) + + learned_conditioning = get_learned_conditioning(model, prompt_flat_list, steps) + + res = [] + for indexes in res_indexes: + res.append([ComposableScheduledPromptConditioning(learned_conditioning[i], weight) for i, weight in indexes]) + + return MulticondLearnedConditioning(shape=(len(prompts),), batch=res) + + +def reconstruct_cond_batch(c: list[list[ScheduledPromptConditioning]], current_step): + param = c[0][0].cond + res = torch.zeros((len(c),) + param.shape, device=param.device, dtype=param.dtype) + for i, cond_schedule in enumerate(c): target_index = 0 for current, (end_at, cond) in enumerate(cond_schedule): if current_step <= end_at: @@ -140,6 +218,30 @@ def reconstruct_cond_batch(c: ScheduledPromptBatch, current_step): return res +def reconstruct_multicond_batch(c: MulticondLearnedConditioning, current_step): + param = c.batch[0][0].schedules[0].cond + + tensors = [] + conds_list = [] + + for batch_no, composable_prompts in enumerate(c.batch): + conds_for_batch = [] + + for cond_index, composable_prompt in enumerate(composable_prompts): + target_index = 0 + for current, (end_at, cond) in enumerate(composable_prompt.schedules): + if current_step <= end_at: + target_index = current + break + + conds_for_batch.append((len(tensors), composable_prompt.weight)) + tensors.append(composable_prompt.schedules[target_index].cond) + + conds_list.append(conds_for_batch) + + return conds_list, torch.stack(tensors).to(device=param.device, dtype=param.dtype) + + re_attention = re.compile(r""" \\\(| \\\)| diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index dbf570d2c..d27c547b3 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -109,9 +109,12 @@ class VanillaStableDiffusionSampler: return 0 def p_sample_ddim_hook(self, x_dec, cond, ts, unconditional_conditioning, *args, **kwargs): - cond = prompt_parser.reconstruct_cond_batch(cond, self.step) + conds_list, tensor = prompt_parser.reconstruct_multicond_batch(cond, self.step) unconditional_conditioning = prompt_parser.reconstruct_cond_batch(unconditional_conditioning, self.step) + assert all([len(conds) == 1 for conds in conds_list]), 'composition via AND is not supported for DDIM/PLMS samplers' + cond = tensor + if self.mask is not None: img_orig = self.sampler.model.q_sample(self.init_latent, ts) x_dec = img_orig * self.mask + self.nmask * x_dec @@ -183,19 +186,31 @@ class CFGDenoiser(torch.nn.Module): self.step = 0 def forward(self, x, sigma, uncond, cond, cond_scale): - cond = prompt_parser.reconstruct_cond_batch(cond, self.step) + conds_list, tensor = prompt_parser.reconstruct_multicond_batch(cond, self.step) uncond = prompt_parser.reconstruct_cond_batch(uncond, self.step) + batch_size = len(conds_list) + repeats = [len(conds_list[i]) for i in range(batch_size)] + + x_in = torch.cat([torch.stack([x[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [x]) + sigma_in = torch.cat([torch.stack([sigma[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [sigma]) + cond_in = torch.cat([tensor, uncond]) + if shared.batch_cond_uncond: - x_in = torch.cat([x] * 2) - sigma_in = torch.cat([sigma] * 2) - cond_in = torch.cat([uncond, cond]) - uncond, cond = self.inner_model(x_in, sigma_in, cond=cond_in).chunk(2) - denoised = uncond + (cond - uncond) * cond_scale + x_out = self.inner_model(x_in, sigma_in, cond=cond_in) else: - uncond = self.inner_model(x, sigma, cond=uncond) - cond = self.inner_model(x, sigma, cond=cond) - denoised = uncond + (cond - uncond) * cond_scale + x_out = torch.zeros_like(x_in) + for batch_offset in range(0, x_out.shape[0], batch_size): + a = batch_offset + b = a + batch_size + x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=cond_in[a:b]) + + denoised_uncond = x_out[-batch_size:] + denoised = torch.clone(denoised_uncond) + + for i, conds in enumerate(conds_list): + for cond_index, weight in conds: + denoised[i] += (x_out[cond_index] - denoised_uncond[i]) * (weight * cond_scale) if self.mask is not None: denoised = self.init_latent * self.mask + self.nmask * denoised diff --git a/modules/ui.py b/modules/ui.py index 523ab25b3..9620350fc 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -34,7 +34,7 @@ import modules.gfpgan_model import modules.codeformer_model import modules.styles import modules.generation_parameters_copypaste -from modules.prompt_parser import get_learned_conditioning_prompt_schedules +from modules import prompt_parser from modules.images import apply_filename_pattern, get_next_sequence_number import modules.textual_inversion.ui @@ -394,7 +394,9 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: def update_token_counter(text, steps): try: - prompt_schedules = get_learned_conditioning_prompt_schedules([text], steps) + _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text]) + prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps) + except Exception: # a parsing error can happen here during typing, and we don't want to bother the user with # messages related to it in console From 4320f386d9641c7c234589c4cb0c0c6cbeb156ad Mon Sep 17 00:00:00 2001 From: Greendayle Date: Wed, 5 Oct 2022 22:39:32 +0200 Subject: [PATCH 088/460] removing underscores and colons --- modules/deepbooru.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index a64fd9cd1..fb5018a6c 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -56,7 +56,7 @@ def _load_tf_and_return_tags(pil_image, threshold): print('\n'.join(sorted(result_tags_print, reverse=True))) - return ', '.join(result_tags_out) + return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') def get_deepbooru_tags(pil_image, threshold=0.5): From f8e41a96bb30a04dd5e294c7e1178c1c3b09d481 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 5 Oct 2022 23:52:05 +0300 Subject: [PATCH 089/460] fix various float parsing errors --- modules/prompt_parser.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index f7420daf9..800b12c75 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -143,8 +143,7 @@ def get_learned_conditioning(model, prompts, steps): re_AND = re.compile(r"\bAND\b") -re_weight = re.compile(r"^(.*?)(?:\s*:\s*([-+]?\s*(?:\d+|\d*\.\d+)?))?\s*$") - +re_weight = re.compile(r"^(.*?)(?:\s*:\s*([-+]?(?:\d+\.?|\d*\.\d+)))?\s*$") def get_multicond_prompt_list(prompts): res_indexes = [] From 20f8ec877a99ce2ebf193cb1e2e773cfc77b7c41 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 00:09:32 +0300 Subject: [PATCH 090/460] remove type annotations in new code because presumably they don't work in 3.7 --- modules/prompt_parser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 800b12c75..ee4c5d02d 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -175,14 +175,14 @@ def get_multicond_prompt_list(prompts): class ComposableScheduledPromptConditioning: def __init__(self, schedules, weight=1.0): - self.schedules: list[ScheduledPromptConditioning] = schedules + self.schedules = schedules # : list[ScheduledPromptConditioning] self.weight: float = weight class MulticondLearnedConditioning: def __init__(self, shape, batch): self.shape: tuple = shape # the shape field is needed to send this object to DDIM/PLMS - self.batch: list[list[ComposableScheduledPromptConditioning]] = batch + self.batch = batch # : list[list[ComposableScheduledPromptConditioning]] def get_multicond_learned_conditioning(model, prompts, steps) -> MulticondLearnedConditioning: @@ -203,7 +203,7 @@ def get_multicond_learned_conditioning(model, prompts, steps) -> MulticondLearne return MulticondLearnedConditioning(shape=(len(prompts),), batch=res) -def reconstruct_cond_batch(c: list[list[ScheduledPromptConditioning]], current_step): +def reconstruct_cond_batch(c, current_step): # c: list[list[ScheduledPromptConditioning]] param = c[0][0].cond res = torch.zeros((len(c),) + param.shape, device=param.device, dtype=param.dtype) for i, cond_schedule in enumerate(c): From 34c358d10d52817f7a889ae4c52096ee654f3fe6 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Wed, 5 Oct 2022 22:11:30 +0100 Subject: [PATCH 091/460] use typing.list in prompt_parser.py for wider python version support --- modules/prompt_parser.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 800b12c75..fdfa21ae6 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -1,6 +1,6 @@ import re from collections import namedtuple - +from typing import List import lark # a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]" @@ -175,14 +175,14 @@ def get_multicond_prompt_list(prompts): class ComposableScheduledPromptConditioning: def __init__(self, schedules, weight=1.0): - self.schedules: list[ScheduledPromptConditioning] = schedules + self.schedules: List[ScheduledPromptConditioning] = schedules self.weight: float = weight class MulticondLearnedConditioning: def __init__(self, shape, batch): self.shape: tuple = shape # the shape field is needed to send this object to DDIM/PLMS - self.batch: list[list[ComposableScheduledPromptConditioning]] = batch + self.batch: List[List[ComposableScheduledPromptConditioning]] = batch def get_multicond_learned_conditioning(model, prompts, steps) -> MulticondLearnedConditioning: @@ -203,7 +203,7 @@ def get_multicond_learned_conditioning(model, prompts, steps) -> MulticondLearne return MulticondLearnedConditioning(shape=(len(prompts),), batch=res) -def reconstruct_cond_batch(c: list[list[ScheduledPromptConditioning]], current_step): +def reconstruct_cond_batch(c: List[List[ScheduledPromptConditioning]], current_step): param = c[0][0].cond res = torch.zeros((len(c),) + param.shape, device=param.device, dtype=param.dtype) for i, cond_schedule in enumerate(c): From 55400c981b7c1389482057a35ed6ea11f08da194 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Thu, 6 Oct 2022 03:11:15 +0100 Subject: [PATCH 092/460] Set gradio-img2img-tool default to 'editor' --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index e52c9b1d1..bab0fe6ee 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -55,7 +55,7 @@ parser.add_argument("--hide-ui-dir-config", action='store_true', help="hide dire parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui settings", default=os.path.join(script_path, 'config.json')) parser.add_argument("--gradio-debug", action='store_true', help="launch gradio with --debug option") parser.add_argument("--gradio-auth", type=str, help='set gradio authentication like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None) -parser.add_argument("--gradio-img2img-tool", type=str, help='gradio image uploader tool: can be either editor for ctopping, or color-sketch for drawing', choices=["color-sketch", "editor"], default="color-sketch") +parser.add_argument("--gradio-img2img-tool", type=str, help='gradio image uploader tool: can be either editor for ctopping, or color-sketch for drawing', choices=["color-sketch", "editor"], default="editor") parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last") parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(script_path, 'styles.csv')) parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False) From 2499fb4e1910d31ff12c24110f161b20641b8835 Mon Sep 17 00:00:00 2001 From: Raphael Stoeckli Date: Wed, 5 Oct 2022 21:57:18 +0200 Subject: [PATCH 093/460] Add sanitizer for captions in Textual inversion --- modules/textual_inversion/preprocess.py | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index f545a9937..4f3df4bd9 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -1,5 +1,8 @@ +from cmath import log import os from PIL import Image, ImageOps +import platform +import sys import tqdm from modules import shared, images @@ -25,6 +28,7 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca def save_pic_with_caption(image, index): if process_caption: caption = "-" + shared.interrogator.generate_caption(image) + caption = sanitize_caption(os.path.join(dst, f"{index:05}-{subindex[0]}"), caption, ".png") else: caption = filename caption = os.path.splitext(caption)[0] @@ -75,3 +79,27 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca if process_caption: shared.interrogator.send_blip_to_ram() + +def sanitize_caption(base_path, original_caption, suffix): + operating_system = platform.system().lower() + if (operating_system == "windows"): + invalid_path_characters = "\\/:*?\"<>|" + max_path_length = 259 + else: + invalid_path_characters = "/" #linux/macos + max_path_length = 1023 + caption = original_caption + for invalid_character in invalid_path_characters: + caption = caption.replace(invalid_character, "") + fixed_path_length = len(base_path) + len(suffix) + if fixed_path_length + len(caption) <= max_path_length: + return caption + caption_tokens = caption.split() + new_caption = "" + for token in caption_tokens: + last_caption = new_caption + new_caption = new_caption + token + " " + if (len(new_caption) + fixed_path_length - 1 > max_path_length): + break + print(f"\nPath will be too long. Truncated caption: {original_caption}\nto: {last_caption}", file=sys.stderr) + return last_caption.strip() From 4288e53fc2ea25fa49715bf5b7f14603553c9e38 Mon Sep 17 00:00:00 2001 From: Raphael Stoeckli Date: Wed, 5 Oct 2022 23:11:32 +0200 Subject: [PATCH 094/460] removed unused import, fixed typo --- modules/textual_inversion/preprocess.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index 4f3df4bd9..f1c002a2b 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -1,4 +1,3 @@ -from cmath import log import os from PIL import Image, ImageOps import platform @@ -13,7 +12,7 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) - assert src != dst, 'same directory specified as source and desitnation' + assert src != dst, 'same directory specified as source and destination' os.makedirs(dst, exist_ok=True) From a93c3ffbfd264ed6b5d989922352300c9d3efbe4 Mon Sep 17 00:00:00 2001 From: Jocke Date: Wed, 5 Oct 2022 16:31:48 +0200 Subject: [PATCH 095/460] Outpainting mk2, prevent generation of a completely random image every time even when global seed is static --- scripts/outpainting_mk_2.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/outpainting_mk_2.py b/scripts/outpainting_mk_2.py index 11613ca36..a6468e09a 100644 --- a/scripts/outpainting_mk_2.py +++ b/scripts/outpainting_mk_2.py @@ -85,8 +85,11 @@ def get_matched_noise(_np_src_image, np_mask_rgb, noise_q=1, color_variation=0.0 src_dist = np.absolute(src_fft) src_phase = src_fft / src_dist + # create a generator with a static seed to make outpainting deterministic / only follow global seed + rng = np.random.default_rng(0) + noise_window = _get_gaussian_window(width, height, mode=1) # start with simple gaussian noise - noise_rgb = np.random.random_sample((width, height, num_channels)) + noise_rgb = rng.random((width, height, num_channels)) noise_grey = (np.sum(noise_rgb, axis=2) / 3.) noise_rgb *= color_variation # the colorfulness of the starting noise is blended to greyscale with a parameter for c in range(num_channels): From 6e7057b31b9762a9720282c7da486e4f264dee28 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 12:08:06 +0300 Subject: [PATCH 096/460] support for downloading new commit hash for git repos --- launch.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/launch.py b/launch.py index 57405feab..2f91f586c 100644 --- a/launch.py +++ b/launch.py @@ -86,6 +86,15 @@ def git_clone(url, dir, name, commithash=None): # TODO clone into temporary dir and move if successful if os.path.exists(dir): + if commithash is None: + return + + current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, "Couldn't determine {name}'s hash: {commithash}").strip() + if current_hash == commithash: + return + + run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}") + run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commint for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}") return run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}") From 5f24b7bcf4a074fbdec757617fcd1bc82e76551b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 12:08:48 +0300 Subject: [PATCH 097/460] option to let users select which samplers they want to hide --- modules/processing.py | 13 ++++++------- modules/sd_samplers.py | 19 +++++++++++++++++-- modules/shared.py | 15 +++++++++------ webui.py | 4 +++- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index d8c6b8d57..e01c8b3f6 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -11,9 +11,8 @@ import cv2 from skimage import exposure import modules.sd_hijack -from modules import devices, prompt_parser, masking +from modules import devices, prompt_parser, masking, sd_samplers from modules.sd_hijack import model_hijack -from modules.sd_samplers import samplers, samplers_for_img2img from modules.shared import opts, cmd_opts, state import modules.shared as shared import modules.face_restoration @@ -110,7 +109,7 @@ class Processed: self.width = p.width self.height = p.height self.sampler_index = p.sampler_index - self.sampler = samplers[p.sampler_index].name + self.sampler = sd_samplers.samplers[p.sampler_index].name self.cfg_scale = p.cfg_scale self.steps = p.steps self.batch_size = p.batch_size @@ -265,7 +264,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration generation_params = { "Steps": p.steps, - "Sampler": samplers[p.sampler_index].name, + "Sampler": sd_samplers.samplers[p.sampler_index].name, "CFG scale": p.cfg_scale, "Seed": all_seeds[index], "Face restoration": (opts.face_restoration_model if p.restore_faces else None), @@ -478,7 +477,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): self.firstphase_height_truncated = int(scale * self.height) def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength): - self.sampler = samplers[self.sampler_index].constructor(self.sd_model) + self.sampler = sd_samplers.samplers[self.sampler_index].constructor(self.sd_model) if not self.enable_hr: 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) @@ -521,7 +520,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): shared.state.nextjob() - self.sampler = samplers[self.sampler_index].constructor(self.sd_model) + self.sampler = sd_samplers.samplers[self.sampler_index].constructor(self.sd_model) noise = create_random_tensors(samples.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self) # GC now before running the next img2img to prevent running out of memory @@ -556,7 +555,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.nmask = None def init(self, all_prompts, all_seeds, all_subseeds): - self.sampler = samplers_for_img2img[self.sampler_index].constructor(self.sd_model) + self.sampler = sd_samplers.samplers_for_img2img[self.sampler_index].constructor(self.sd_model) crop_region = None if self.image_mask is not None: diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index d27c547b3..2e1f77153 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -32,12 +32,27 @@ samplers_data_k_diffusion = [ if hasattr(k_diffusion.sampling, funcname) ] -samplers = [ +all_samplers = [ *samplers_data_k_diffusion, SamplerData('DDIM', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.ddim.DDIMSampler, model), []), SamplerData('PLMS', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.plms.PLMSSampler, model), []), ] -samplers_for_img2img = [x for x in samplers if x.name not in ['PLMS', 'DPM fast', 'DPM adaptive']] + +samplers = [] +samplers_for_img2img = [] + + +def set_samplers(): + global samplers, samplers_for_img2img + + hidden = set(opts.hide_samplers) + hidden_img2img = set(opts.hide_samplers + ['PLMS', 'DPM fast', 'DPM adaptive']) + + samplers = [x for x in all_samplers if x.name not in hidden] + samplers_for_img2img = [x for x in all_samplers if x.name not in hidden_img2img] + + +set_samplers() sampler_extra_params = { 'sample_euler': ['s_churn', 's_tmin', 's_tmax', 's_noise'], diff --git a/modules/shared.py b/modules/shared.py index bab0fe6ee..ca2e4c742 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -13,6 +13,7 @@ import modules.memmon import modules.sd_models import modules.styles import modules.devices as devices +from modules import sd_samplers from modules.paths import script_path, sd_path sd_model_file = os.path.join(script_path, 'model.ckpt') @@ -238,14 +239,16 @@ options_templates.update(options_section(('ui', "User interface"), { })) options_templates.update(options_section(('sampler-params', "Sampler parameters"), { - "eta_ddim": OptionInfo(0.0, "eta (noise multiplier) for DDIM", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), - "eta_ancestral": OptionInfo(1.0, "eta (noise multiplier) for ancestral samplers", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), - "ddim_discretize": OptionInfo('uniform', "img2img DDIM discretize", gr.Radio, {"choices": ['uniform', 'quad']}), - 's_churn': OptionInfo(0.0, "sigma churn", gr.Slider, {"minimum": 0.0, "maximum": 1.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}), + "hide_samplers": OptionInfo([], "Hide samplers in user interface (requires restart)", gr.CheckboxGroup, lambda: {"choices": [x.name for x in sd_samplers.all_samplers]}), + "eta_ddim": OptionInfo(0.0, "eta (noise multiplier) for DDIM", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + "eta_ancestral": OptionInfo(1.0, "eta (noise multiplier) for ancestral samplers", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + "ddim_discretize": OptionInfo('uniform', "img2img DDIM discretize", gr.Radio, {"choices": ['uniform', 'quad']}), + 's_churn': OptionInfo(0.0, "sigma churn", gr.Slider, {"minimum": 0.0, "maximum": 1.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}), })) + class Options: data = None data_labels = options_templates diff --git a/webui.py b/webui.py index 47848ba58..9ef124274 100644 --- a/webui.py +++ b/webui.py @@ -2,7 +2,7 @@ import os import threading import time import importlib -from modules import devices +from modules import devices, sd_samplers from modules.paths import script_path import signal import threading @@ -109,6 +109,8 @@ def webui(): time.sleep(0.5) break + sd_samplers.set_samplers() + print('Reloading Custom Scripts') modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) print('Reloading modules: modules.ui') From 2d3ea42a2d1e909bbccdb6b49561b187c60a9402 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 13:21:12 +0300 Subject: [PATCH 098/460] workaround for a mysterious bug where prompt weights can't be matched --- modules/prompt_parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index a7a6aa314..f00256f28 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -156,7 +156,9 @@ def get_multicond_prompt_list(prompts): indexes = [] for subprompt in subprompts: - text, weight = re_weight.search(subprompt).groups() + match = re_weight.search(subprompt) + + text, weight = match.groups() if match is not None else (subprompt, 1.0) weight = float(weight) if weight is not None else 1.0 From 2a532804957e47bc36c67c8f5b104dcfa8e8f3f0 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 13:21:32 +0300 Subject: [PATCH 099/460] reorder imports to fix the bug with k-diffusion on some version --- webui.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webui.py b/webui.py index 9ef124274..480360fe0 100644 --- a/webui.py +++ b/webui.py @@ -2,11 +2,12 @@ import os import threading import time import importlib -from modules import devices, sd_samplers -from modules.paths import script_path import signal import threading +from modules.paths import script_path + +from modules import devices, sd_samplers import modules.codeformer_model as codeformer import modules.extras import modules.face_restoration From c30c06db207a580d76544fd10fc1e03cd58ce85e Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:48:16 +0300 Subject: [PATCH 100/460] update k-diffusion --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index 2f91f586c..c2713c645 100644 --- a/launch.py +++ b/launch.py @@ -19,7 +19,7 @@ clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLI stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc") taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6") -k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "a7ec1974d4ccb394c2dca275f42cd97490618924") +k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "567e11f7062ba20ae32b5a8cd07fb0fc4b9410cf") codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af") blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9") From c1a068ed0acc788774afc1541ca69342fd1d94ad Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:49:17 +0300 Subject: [PATCH 101/460] Create alternate_sampler_noise_schedules.py --- scripts/alternate_sampler_noise_schedules.py | 53 ++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 scripts/alternate_sampler_noise_schedules.py diff --git a/scripts/alternate_sampler_noise_schedules.py b/scripts/alternate_sampler_noise_schedules.py new file mode 100644 index 000000000..4f3ed8fb1 --- /dev/null +++ b/scripts/alternate_sampler_noise_schedules.py @@ -0,0 +1,53 @@ +import inspect +from modules.processing import Processed, process_images +import gradio as gr +import modules.scripts as scripts +import k_diffusion.sampling +import torch + + +class Script(scripts.Script): + + def title(self): + return "Alternate Sampler Noise Schedules" + + def ui(self, is_img2img): + noise_scheduler = gr.Dropdown(label="Noise Scheduler", choices=['Default','Karras','Exponential', 'Variance Preserving'], value='Default', type="index") + sched_smin = gr.Slider(value=0.1, label="Sigma min", minimum=0.0, maximum=100.0, step=0.5,) + sched_smax = gr.Slider(value=10.0, label="Sigma max", minimum=0.0, maximum=100.0, step=0.5) + sched_rho = gr.Slider(value=7.0, label="Sigma rho (Karras only)", minimum=7.0, maximum=100.0, step=0.5) + sched_beta_d = gr.Slider(value=19.9, label="Beta distribution (VP only)",minimum=0.0, maximum=40.0, step=0.5) + sched_beta_min = gr.Slider(value=0.1, label="Beta min (VP only)", minimum=0.0, maximum=40.0, step=0.1) + sched_eps_s = gr.Slider(value=0.001, label="Epsilon (VP only)", minimum=0.001, maximum=1.0, step=0.001) + + return [noise_scheduler, sched_smin, sched_smax, sched_rho, sched_beta_d, sched_beta_min, sched_eps_s] + + def run(self, p, noise_scheduler, sched_smin, sched_smax, sched_rho, sched_beta_d, sched_beta_min, sched_eps_s): + + noise_scheduler_func_name = ['-','get_sigmas_karras','get_sigmas_exponential','get_sigmas_vp'][noise_scheduler] + + base_params = { + "sigma_min":sched_smin, + "sigma_max":sched_smax, + "rho":sched_rho, + "beta_d":sched_beta_d, + "beta_min":sched_beta_min, + "eps_s":sched_eps_s, + "device":"cuda" if torch.cuda.is_available() else "cpu" + } + + if hasattr(k_diffusion.sampling,noise_scheduler_func_name): + + sigma_func = getattr(k_diffusion.sampling,noise_scheduler_func_name) + sigma_func_kwargs = {} + + for k,v in base_params.items(): + if k in inspect.signature(sigma_func).parameters: + sigma_func_kwargs[k] = v + + def substitute_noise_scheduler(n): + return sigma_func(n,**sigma_func_kwargs) + + p.sampler_noise_scheduler_override = substitute_noise_scheduler + + return process_images(p) From 71901b3d3bea1d035bf4a7229d19356b4b062151 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Wed, 5 Oct 2022 14:30:57 +0300 Subject: [PATCH 102/460] add karras scheduling variants --- modules/sd_samplers.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 2e1f77153..8d6eb7620 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -26,6 +26,17 @@ samplers_k_diffusion = [ ('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad']), ] +if opts.show_karras_scheduler_variants: + k_diffusion.sampling.sample_dpm_2_ka = k_diffusion.sampling.sample_dpm_2 + k_diffusion.sampling.sample_dpm_2_ancestral_ka = k_diffusion.sampling.sample_dpm_2_ancestral + k_diffusion.sampling.sample_lms_ka = k_diffusion.sampling.sample_lms + samplers_k_diffusion_ka = [ + ('LMS K Scheduling', 'sample_lms_ka', ['k_lms_ka']), + ('DPM2 K Scheduling', 'sample_dpm_2_ka', ['k_dpm_2_ka']), + ('DPM2 a K Scheduling', 'sample_dpm_2_ancestral_ka', ['k_dpm_2_a_ka']), + ] + samplers_k_diffusion.extend(samplers_k_diffusion_ka) + samplers_data_k_diffusion = [ SamplerData(label, lambda model, funcname=funcname: KDiffusionSampler(funcname, model), aliases) for label, funcname, aliases in samplers_k_diffusion @@ -345,6 +356,8 @@ class KDiffusionSampler: if p.sampler_noise_scheduler_override: sigmas = p.sampler_noise_scheduler_override(steps) + elif self.funcname.endswith('ka'): + sigmas = k_diffusion.sampling.get_sigmas_karras(n=steps, sigma_min=0.1, sigma_max=10, device=shared.device) else: sigmas = self.model_wrap.get_sigmas(steps) x = x * sigmas[0] From 3ddf80a9db8793188e2fe9488233d2b272cceb33 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Wed, 5 Oct 2022 14:31:51 +0300 Subject: [PATCH 103/460] add variant setting --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index ca2e4c742..9e4860a28 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -236,6 +236,7 @@ options_templates.update(options_section(('ui', "User interface"), { "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), "js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), + "show_karras_scheduler_variants": OptionInfo(True, "Show Karras scheduling variants for select samplers. Try these variants if your K sampled images suffer from excessive noise."), })) options_templates.update(options_section(('sampler-params', "Sampler parameters"), { From a971e4a767118ec41ec0f129770122babfb16a16 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Thu, 6 Oct 2022 13:34:42 +0300 Subject: [PATCH 104/460] update k-diff once again --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index c2713c645..9fe0fd675 100644 --- a/launch.py +++ b/launch.py @@ -19,7 +19,7 @@ clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLI stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc") taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6") -k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "567e11f7062ba20ae32b5a8cd07fb0fc4b9410cf") +k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "f4e99857772fc3a126ba886aadf795a332774878") codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af") blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9") From 5993df24a1026225cb8af89237547c1d9101ce69 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 14:12:52 +0300 Subject: [PATCH 105/460] integrate the new samplers PR --- modules/processing.py | 7 ++- modules/sd_samplers.py | 59 ++++++++++---------- modules/shared.py | 1 - scripts/alternate_sampler_noise_schedules.py | 53 ------------------ scripts/img2imgalt.py | 3 +- 5 files changed, 36 insertions(+), 87 deletions(-) delete mode 100644 scripts/alternate_sampler_noise_schedules.py diff --git a/modules/processing.py b/modules/processing.py index e01c8b3f6..e567956ce 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -477,7 +477,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): self.firstphase_height_truncated = int(scale * self.height) def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength): - self.sampler = sd_samplers.samplers[self.sampler_index].constructor(self.sd_model) + self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model) if not self.enable_hr: 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) @@ -520,7 +520,8 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): shared.state.nextjob() - self.sampler = sd_samplers.samplers[self.sampler_index].constructor(self.sd_model) + self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model) + noise = create_random_tensors(samples.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self) # GC now before running the next img2img to prevent running out of memory @@ -555,7 +556,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing): self.nmask = None def init(self, all_prompts, all_seeds, all_subseeds): - self.sampler = sd_samplers.samplers_for_img2img[self.sampler_index].constructor(self.sd_model) + self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers_for_img2img, self.sampler_index, self.sd_model) crop_region = None if self.image_mask is not None: diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 8d6eb7620..497df9430 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -13,46 +13,46 @@ from modules.shared import opts, cmd_opts, state import modules.shared as shared -SamplerData = namedtuple('SamplerData', ['name', 'constructor', 'aliases']) +SamplerData = namedtuple('SamplerData', ['name', 'constructor', 'aliases', 'options']) samplers_k_diffusion = [ - ('Euler a', 'sample_euler_ancestral', ['k_euler_a']), - ('Euler', 'sample_euler', ['k_euler']), - ('LMS', 'sample_lms', ['k_lms']), - ('Heun', 'sample_heun', ['k_heun']), - ('DPM2', 'sample_dpm_2', ['k_dpm_2']), - ('DPM2 a', 'sample_dpm_2_ancestral', ['k_dpm_2_a']), - ('DPM fast', 'sample_dpm_fast', ['k_dpm_fast']), - ('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad']), + ('Euler a', 'sample_euler_ancestral', ['k_euler_a'], {}), + ('Euler', 'sample_euler', ['k_euler'], {}), + ('LMS', 'sample_lms', ['k_lms'], {}), + ('Heun', 'sample_heun', ['k_heun'], {}), + ('DPM2', 'sample_dpm_2', ['k_dpm_2'], {}), + ('DPM2 a', 'sample_dpm_2_ancestral', ['k_dpm_2_a'], {}), + ('DPM fast', 'sample_dpm_fast', ['k_dpm_fast'], {}), + ('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad'], {}), + ('LMS Karras', 'sample_lms', ['k_lms_ka'], {'scheduler': 'karras'}), + ('DPM2 Karras', 'sample_dpm_2', ['k_dpm_2_ka'], {'scheduler': 'karras'}), + ('DPM2 a Karras', 'sample_dpm_2_ancestral', ['k_dpm_2_a_ka'], {'scheduler': 'karras'}), ] -if opts.show_karras_scheduler_variants: - k_diffusion.sampling.sample_dpm_2_ka = k_diffusion.sampling.sample_dpm_2 - k_diffusion.sampling.sample_dpm_2_ancestral_ka = k_diffusion.sampling.sample_dpm_2_ancestral - k_diffusion.sampling.sample_lms_ka = k_diffusion.sampling.sample_lms - samplers_k_diffusion_ka = [ - ('LMS K Scheduling', 'sample_lms_ka', ['k_lms_ka']), - ('DPM2 K Scheduling', 'sample_dpm_2_ka', ['k_dpm_2_ka']), - ('DPM2 a K Scheduling', 'sample_dpm_2_ancestral_ka', ['k_dpm_2_a_ka']), - ] - samplers_k_diffusion.extend(samplers_k_diffusion_ka) - samplers_data_k_diffusion = [ - SamplerData(label, lambda model, funcname=funcname: KDiffusionSampler(funcname, model), aliases) - for label, funcname, aliases in samplers_k_diffusion + SamplerData(label, lambda model, funcname=funcname: KDiffusionSampler(funcname, model), aliases, options) + for label, funcname, aliases, options in samplers_k_diffusion if hasattr(k_diffusion.sampling, funcname) ] all_samplers = [ *samplers_data_k_diffusion, - SamplerData('DDIM', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.ddim.DDIMSampler, model), []), - SamplerData('PLMS', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.plms.PLMSSampler, model), []), + SamplerData('DDIM', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.ddim.DDIMSampler, model), [], {}), + SamplerData('PLMS', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.plms.PLMSSampler, model), [], {}), ] samplers = [] samplers_for_img2img = [] +def create_sampler_with_index(list_of_configs, index, model): + config = list_of_configs[index] + sampler = config.constructor(model) + sampler.config = config + + return sampler + + def set_samplers(): global samplers, samplers_for_img2img @@ -130,6 +130,7 @@ class VanillaStableDiffusionSampler: self.step = 0 self.eta = None self.default_eta = 0.0 + self.config = None def number_of_needed_noises(self, p): return 0 @@ -291,6 +292,7 @@ class KDiffusionSampler: self.stop_at = None self.eta = None self.default_eta = 1.0 + self.config = None def callback_state(self, d): store_latent(d["denoised"]) @@ -355,11 +357,12 @@ class KDiffusionSampler: steps = steps or p.steps if p.sampler_noise_scheduler_override: - sigmas = p.sampler_noise_scheduler_override(steps) - elif self.funcname.endswith('ka'): - sigmas = k_diffusion.sampling.get_sigmas_karras(n=steps, sigma_min=0.1, sigma_max=10, device=shared.device) + sigmas = p.sampler_noise_scheduler_override(steps) + elif self.config is not None and self.config.options.get('scheduler', None) == 'karras': + sigmas = k_diffusion.sampling.get_sigmas_karras(n=steps, sigma_min=0.1, sigma_max=10, device=shared.device) else: - sigmas = self.model_wrap.get_sigmas(steps) + sigmas = self.model_wrap.get_sigmas(steps) + x = x * sigmas[0] extra_params_kwargs = self.initialize(p) diff --git a/modules/shared.py b/modules/shared.py index 9e4860a28..ca2e4c742 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -236,7 +236,6 @@ options_templates.update(options_section(('ui', "User interface"), { "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), "js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), - "show_karras_scheduler_variants": OptionInfo(True, "Show Karras scheduling variants for select samplers. Try these variants if your K sampled images suffer from excessive noise."), })) options_templates.update(options_section(('sampler-params', "Sampler parameters"), { diff --git a/scripts/alternate_sampler_noise_schedules.py b/scripts/alternate_sampler_noise_schedules.py deleted file mode 100644 index 4f3ed8fb1..000000000 --- a/scripts/alternate_sampler_noise_schedules.py +++ /dev/null @@ -1,53 +0,0 @@ -import inspect -from modules.processing import Processed, process_images -import gradio as gr -import modules.scripts as scripts -import k_diffusion.sampling -import torch - - -class Script(scripts.Script): - - def title(self): - return "Alternate Sampler Noise Schedules" - - def ui(self, is_img2img): - noise_scheduler = gr.Dropdown(label="Noise Scheduler", choices=['Default','Karras','Exponential', 'Variance Preserving'], value='Default', type="index") - sched_smin = gr.Slider(value=0.1, label="Sigma min", minimum=0.0, maximum=100.0, step=0.5,) - sched_smax = gr.Slider(value=10.0, label="Sigma max", minimum=0.0, maximum=100.0, step=0.5) - sched_rho = gr.Slider(value=7.0, label="Sigma rho (Karras only)", minimum=7.0, maximum=100.0, step=0.5) - sched_beta_d = gr.Slider(value=19.9, label="Beta distribution (VP only)",minimum=0.0, maximum=40.0, step=0.5) - sched_beta_min = gr.Slider(value=0.1, label="Beta min (VP only)", minimum=0.0, maximum=40.0, step=0.1) - sched_eps_s = gr.Slider(value=0.001, label="Epsilon (VP only)", minimum=0.001, maximum=1.0, step=0.001) - - return [noise_scheduler, sched_smin, sched_smax, sched_rho, sched_beta_d, sched_beta_min, sched_eps_s] - - def run(self, p, noise_scheduler, sched_smin, sched_smax, sched_rho, sched_beta_d, sched_beta_min, sched_eps_s): - - noise_scheduler_func_name = ['-','get_sigmas_karras','get_sigmas_exponential','get_sigmas_vp'][noise_scheduler] - - base_params = { - "sigma_min":sched_smin, - "sigma_max":sched_smax, - "rho":sched_rho, - "beta_d":sched_beta_d, - "beta_min":sched_beta_min, - "eps_s":sched_eps_s, - "device":"cuda" if torch.cuda.is_available() else "cpu" - } - - if hasattr(k_diffusion.sampling,noise_scheduler_func_name): - - sigma_func = getattr(k_diffusion.sampling,noise_scheduler_func_name) - sigma_func_kwargs = {} - - for k,v in base_params.items(): - if k in inspect.signature(sigma_func).parameters: - sigma_func_kwargs[k] = v - - def substitute_noise_scheduler(n): - return sigma_func(n,**sigma_func_kwargs) - - p.sampler_noise_scheduler_override = substitute_noise_scheduler - - return process_images(p) diff --git a/scripts/img2imgalt.py b/scripts/img2imgalt.py index 0ef137f7d..f9894cb01 100644 --- a/scripts/img2imgalt.py +++ b/scripts/img2imgalt.py @@ -8,7 +8,6 @@ import gradio as gr from modules import processing, shared, sd_samplers, prompt_parser from modules.processing import Processed -from modules.sd_samplers import samplers from modules.shared import opts, cmd_opts, state import torch @@ -159,7 +158,7 @@ class Script(scripts.Script): combined_noise = ((1 - randomness) * rec_noise + randomness * rand_noise) / ((randomness**2 + (1-randomness)**2) ** 0.5) - sampler = samplers[p.sampler_index].constructor(p.sd_model) + sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, p.sampler_index, p.sd_model) sigmas = sampler.model_wrap.get_sigmas(p.steps) From f5490674a8fd84162b4e80c045e675633afb9ee7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 17:41:49 +0300 Subject: [PATCH 106/460] fix bad output for error when updating a git repo --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index 9fe0fd675..75edb66a9 100644 --- a/launch.py +++ b/launch.py @@ -89,7 +89,7 @@ def git_clone(url, dir, name, commithash=None): if commithash is None: return - current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, "Couldn't determine {name}'s hash: {commithash}").strip() + current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip() if current_hash == commithash: return From be71115b1a1201d04f0e2a11e718fb31cbd26474 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Thu, 6 Oct 2022 01:09:44 +0100 Subject: [PATCH 107/460] Update shared.py --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index ca2e4c742..9f7c6efe5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -236,6 +236,7 @@ options_templates.update(options_section(('ui', "User interface"), { "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), "js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), + "show_progress_in_title": OptionInfo(False, "Show generation progress in window title."), })) options_templates.update(options_section(('sampler-params', "Sampler parameters"), { From c06298d1d003aa034007978ee7508af636c18124 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Thu, 6 Oct 2022 01:10:38 +0100 Subject: [PATCH 108/460] add check for progress in title setting --- javascript/progressbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 3e3220c3f..f9e9290e2 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -5,7 +5,7 @@ function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_inte var progressbar = gradioApp().getElementById(id_progressbar) var interrupt = gradioApp().getElementById(id_interrupt) - if(progressbar && progressbar.offsetParent){ + if(opts.show_progress_in_title && progressbar && progressbar.offsetParent){ if(progressbar.innerText){ let newtitle = 'Stable Diffusion - ' + progressbar.innerText if(document.title != newtitle){ From fec71e4de24b65b0f205a3c071b71651bbcb0dfc Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Thu, 6 Oct 2022 01:35:07 +0100 Subject: [PATCH 109/460] Default window title progress updates on --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 9f7c6efe5..5c16f0257 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -236,7 +236,7 @@ options_templates.update(options_section(('ui', "User interface"), { "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), "js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), - "show_progress_in_title": OptionInfo(False, "Show generation progress in window title."), + "show_progress_in_title": OptionInfo(True, "Show generation progress in window title."), })) options_templates.update(options_section(('sampler-params', "Sampler parameters"), { From 5d0e6ab8567bda2ee8f5ed31f332ca07c1b84b98 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Thu, 6 Oct 2022 04:04:50 +0100 Subject: [PATCH 110/460] Allow escaping of commas in xy_grid --- scripts/xy_grid.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 1237e754d..210829a79 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -168,6 +168,7 @@ re_range_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d re_range_count = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\[(\d+)\s*\])?\s*") re_range_count_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\[(\d+(?:.\d*)?)\s*\])?\s*") +re_non_escaped_comma = re.compile(r"(? Date: Thu, 6 Oct 2022 11:55:21 +0100 Subject: [PATCH 111/460] use csv.reader --- scripts/xy_grid.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 210829a79..1a625898f 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -1,8 +1,9 @@ from collections import namedtuple from copy import copy -from itertools import permutations +from itertools import permutations, chain import random - +import csv +from io import StringIO from PIL import Image import numpy as np @@ -168,8 +169,6 @@ re_range_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d re_range_count = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\[(\d+)\s*\])?\s*") re_range_count_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\[(\d+(?:.\d*)?)\s*\])?\s*") -re_non_escaped_comma = re.compile(r"(? Date: Thu, 6 Oct 2022 12:32:17 +0100 Subject: [PATCH 112/460] strip() split comma delimited lines --- scripts/xy_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 1a625898f..ec27e58bc 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -197,7 +197,7 @@ class Script(scripts.Script): if opt.label == 'Nothing': return [0] - valslist = list(chain.from_iterable(csv.reader(StringIO(s)))) + valslist = list(map(str.strip,chain.from_iterable(csv.reader(StringIO(s))))) if opt.type == int: valslist_ext = [] From 82eb8ea452b1e63535c58d15ec6db2ad2342faa8 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Thu, 6 Oct 2022 15:22:51 +0100 Subject: [PATCH 113/460] Update xy_grid.py split vals not 's' from tests --- scripts/xy_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index ec27e58bc..210c7b6e9 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -197,7 +197,7 @@ class Script(scripts.Script): if opt.label == 'Nothing': return [0] - valslist = list(map(str.strip,chain.from_iterable(csv.reader(StringIO(s))))) + valslist = list(map(str.strip,chain.from_iterable(csv.reader(StringIO(vals))))) if opt.type == int: valslist_ext = [] From 0bb458f0ca06a7be27cf1a1003c536d1f06a5bd3 Mon Sep 17 00:00:00 2001 From: Milly Date: Wed, 5 Oct 2022 01:19:50 +0900 Subject: [PATCH 114/460] Removed duplicate image saving codes Use `modules.images.save_image()` instead. --- modules/images.py | 7 ++++--- modules/ui.py | 46 ++++++++++------------------------------------ 2 files changed, 14 insertions(+), 39 deletions(-) diff --git a/modules/images.py b/modules/images.py index c2fadab99..810f1446e 100644 --- a/modules/images.py +++ b/modules/images.py @@ -353,7 +353,7 @@ def get_next_sequence_number(path, basename): return result + 1 -def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix=""): +def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None): if short_filename or prompt is None or seed is None: file_decoration = "" elif opts.save_to_dirs: @@ -377,7 +377,8 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i else: pnginfo = None - save_to_dirs = (grid and opts.grid_save_to_dirs) or (not grid and opts.save_to_dirs and not no_prompt) + if save_to_dirs is None: + save_to_dirs = (grid and opts.grid_save_to_dirs) or (not grid and opts.save_to_dirs and not no_prompt) if save_to_dirs: dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt).strip('\\ /') @@ -431,4 +432,4 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i with open(f"{fullfn_without_extension}.txt", "w", encoding="utf8") as file: file.write(info + "\n") - + return fullfn diff --git a/modules/ui.py b/modules/ui.py index 9620350fc..4f18126fb 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -35,7 +35,7 @@ import modules.codeformer_model import modules.styles import modules.generation_parameters_copypaste from modules import prompt_parser -from modules.images import apply_filename_pattern, get_next_sequence_number +from modules.images import save_image import modules.textual_inversion.ui # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI @@ -114,20 +114,13 @@ def save_files(js_data, images, index): p = MyObject(data) path = opts.outdir_save save_to_dirs = opts.use_save_to_dirs_for_ui - - if save_to_dirs: - dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, p.seed, p.prompt) - path = os.path.join(opts.outdir_save, dirname) - - os.makedirs(path, exist_ok=True) - + extension: str = opts.samples_format + start_index = 0 if index > -1 and opts.save_selected_only and (index >= data["index_of_first_image"]): # ensures we are looking at a specific non-grid picture, and we have save_selected_only images = [images[index]] - infotexts = [data["infotexts"][index]] - else: - infotexts = data["infotexts"] + start_index = index with open(os.path.join(opts.outdir_save, "log.csv"), "a", encoding="utf8", newline='') as file: at_start = file.tell() == 0 @@ -135,37 +128,18 @@ def save_files(js_data, images, index): if at_start: writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"]) - file_decoration = opts.samples_filename_pattern or "[seed]-[prompt_spaces]" - if file_decoration != "": - file_decoration = "-" + file_decoration.lower() - file_decoration = apply_filename_pattern(file_decoration, p, p.seed, p.prompt) - truncated = (file_decoration[:240] + '..') if len(file_decoration) > 240 else file_decoration - filename_base = truncated - extension = opts.samples_format.lower() - - basecount = get_next_sequence_number(path, "") - for i, filedata in enumerate(images): - file_number = f"{basecount+i:05}" - filename = file_number + filename_base + f".{extension}" - filepath = os.path.join(path, filename) - - + for image_index, filedata in enumerate(images, start_index): if filedata.startswith("data:image/png;base64,"): filedata = filedata[len("data:image/png;base64,"):] image = Image.open(io.BytesIO(base64.decodebytes(filedata.encode('utf-8')))) - if opts.enable_pnginfo and extension == 'png': - pnginfo = PngImagePlugin.PngInfo() - pnginfo.add_text('parameters', infotexts[i]) - image.save(filepath, pnginfo=pnginfo) - else: - image.save(filepath, quality=opts.jpeg_quality) - if opts.enable_pnginfo and extension in ("jpg", "jpeg", "webp"): - piexif.insert(piexif.dump({"Exif": { - piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(infotexts[i], encoding="unicode") - }}), filepath) + is_grid = image_index < p.index_of_first_image + i = 0 if is_grid else (image_index - p.index_of_first_image) + fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) + + filename = os.path.relpath(fullfn, path) filenames.append(filename) writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]]) From 1069ec49a35d04c1e85c92534e92a2d6aa59cb75 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 20:16:21 +0300 Subject: [PATCH 115/460] revert back to using list comprehension rather than list and map --- scripts/xy_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 210c7b6e9..6344e612f 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -197,7 +197,7 @@ class Script(scripts.Script): if opt.label == 'Nothing': return [0] - valslist = list(map(str.strip,chain.from_iterable(csv.reader(StringIO(vals))))) + valslist = [x.strip() for x in chain.from_iterable(csv.reader(StringIO(vals)))] if opt.type == int: valslist_ext = [] From dbc8a4d35129b08eab30776bbbaf3a2e7ac10a6c Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 20:27:50 +0300 Subject: [PATCH 116/460] add generation parameters to images shown in web ui --- modules/processing.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index de818d5b9..8faf90956 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -430,7 +430,9 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if opts.samples_save and not p.do_not_save_samples: images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p) - infotexts.append(infotext(n, i)) + text = infotext(n, i) + infotexts.append(text) + image.info["parameters"] = text output_images.append(image) del x_samples_ddim @@ -447,7 +449,9 @@ def process_images(p: StableDiffusionProcessing) -> Processed: grid = images.image_grid(output_images, p.batch_size) if opts.return_grid: - infotexts.insert(0, infotext()) + text = infotext() + infotexts.insert(0, text) + grid.info["parameters"] = text output_images.insert(0, grid) index_of_first_image = 1 From cf7c784fcc0c84a8a4edd8d3aca4dda4c7025c43 Mon Sep 17 00:00:00 2001 From: Milly Date: Fri, 7 Oct 2022 00:19:52 +0900 Subject: [PATCH 117/460] Removed duplicate defined models_path Use `modules.paths.models_path` instead `modules.shared.model_path`. --- modules/shared.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 5c16f0257..25bb6e6c9 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -14,11 +14,10 @@ import modules.sd_models import modules.styles import modules.devices as devices from modules import sd_samplers -from modules.paths import script_path, sd_path +from modules.paths import models_path, script_path, sd_path sd_model_file = os.path.join(script_path, 'model.ckpt') default_sd_model_file = sd_model_file -model_path = os.path.join(script_path, 'models') parser = argparse.ArgumentParser() parser.add_argument("--config", type=str, default=os.path.join(sd_path, "configs/stable-diffusion/v1-inference.yaml"), help="path to config which constructs model",) parser.add_argument("--ckpt", type=str, default=sd_model_file, help="path to checkpoint of stable diffusion model; if specified, this checkpoint will be added to the list of checkpoints and loaded",) @@ -36,14 +35,14 @@ parser.add_argument("--always-batch-cond-uncond", action='store_true', help="dis parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.") parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast") parser.add_argument("--share", action='store_true', help="use share=True for gradio and make the UI accessible through their site (doesn't work for me but you might have better luck)") -parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(model_path, 'Codeformer')) -parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory with GFPGAN model file(s).", default=os.path.join(model_path, 'GFPGAN')) -parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(model_path, 'ESRGAN')) -parser.add_argument("--bsrgan-models-path", type=str, help="Path to directory with BSRGAN model file(s).", default=os.path.join(model_path, 'BSRGAN')) -parser.add_argument("--realesrgan-models-path", type=str, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(model_path, 'RealESRGAN')) -parser.add_argument("--scunet-models-path", type=str, help="Path to directory with ScuNET model file(s).", default=os.path.join(model_path, 'ScuNET')) -parser.add_argument("--swinir-models-path", type=str, help="Path to directory with SwinIR model file(s).", default=os.path.join(model_path, 'SwinIR')) -parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(model_path, 'LDSR')) +parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer')) +parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory with GFPGAN model file(s).", default=os.path.join(models_path, 'GFPGAN')) +parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN')) +parser.add_argument("--bsrgan-models-path", type=str, help="Path to directory with BSRGAN model file(s).", default=os.path.join(models_path, 'BSRGAN')) +parser.add_argument("--realesrgan-models-path", type=str, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(models_path, 'RealESRGAN')) +parser.add_argument("--scunet-models-path", type=str, help="Path to directory with ScuNET model file(s).", default=os.path.join(models_path, 'ScuNET')) +parser.add_argument("--swinir-models-path", type=str, help="Path to directory with SwinIR model file(s).", default=os.path.join(models_path, 'SwinIR')) +parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(models_path, 'LDSR')) parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") From 070b7d60cf5dac6387b3bfc8f3b3977b620e4fd5 Mon Sep 17 00:00:00 2001 From: Milly Date: Wed, 5 Oct 2022 02:13:09 +0900 Subject: [PATCH 118/460] Added styles to Processed So `[styles]` pattern can use in saving image UI. --- modules/images.py | 7 +------ modules/processing.py | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/images.py b/modules/images.py index 810f1446e..fa0714fd1 100644 --- a/modules/images.py +++ b/modules/images.py @@ -292,12 +292,7 @@ def apply_filename_pattern(x, p, seed, prompt): x = x.replace("[cfg]", str(p.cfg_scale)) x = x.replace("[width]", str(p.width)) x = x.replace("[height]", str(p.height)) - - #currently disabled if using the save button, will work otherwise - # if enabled it will cause a bug because styles is not included in the save_files data dictionary - if hasattr(p, "styles"): - x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]) or "None", replace_spaces=False)) - + x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]) or "None", replace_spaces=False)) x = x.replace("[sampler]", sanitize_filename_part(sd_samplers.samplers[p.sampler_index].name, replace_spaces=False)) x = x.replace("[model_hash]", shared.sd_model.sd_model_hash) diff --git a/modules/processing.py b/modules/processing.py index 8faf90956..706dbfa87 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -121,6 +121,7 @@ class Processed: self.denoising_strength = getattr(p, 'denoising_strength', None) self.extra_generation_params = p.extra_generation_params self.index_of_first_image = index_of_first_image + self.styles = p.styles self.eta = p.eta self.ddim_discretize = p.ddim_discretize @@ -165,6 +166,7 @@ class Processed: "extra_generation_params": self.extra_generation_params, "index_of_first_image": self.index_of_first_image, "infotexts": self.infotexts, + "styles": self.styles, } return json.dumps(obj) From 1cc36d170ac15e7f04208df32db27af1b10c867c Mon Sep 17 00:00:00 2001 From: Milly Date: Wed, 5 Oct 2022 02:17:15 +0900 Subject: [PATCH 119/460] Added job_timestamp to Processed So `[job_timestamp]` pattern can use in saving image UI. --- modules/images.py | 2 +- modules/processing.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/images.py b/modules/images.py index fa0714fd1..669d76af6 100644 --- a/modules/images.py +++ b/modules/images.py @@ -298,7 +298,7 @@ def apply_filename_pattern(x, p, seed, prompt): x = x.replace("[model_hash]", shared.sd_model.sd_model_hash) x = x.replace("[date]", datetime.date.today().isoformat()) x = x.replace("[datetime]", datetime.datetime.now().strftime("%Y%m%d%H%M%S")) - x = x.replace("[job_timestamp]", shared.state.job_timestamp) + x = x.replace("[job_timestamp]", getattr(p, "job_timestamp", shared.state.job_timestamp)) # Apply [prompt] at last. Because it may contain any replacement word.^M if prompt is not None: diff --git a/modules/processing.py b/modules/processing.py index 706dbfa87..f773a30ef 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -122,6 +122,7 @@ class Processed: self.extra_generation_params = p.extra_generation_params self.index_of_first_image = index_of_first_image self.styles = p.styles + self.job_timestamp = state.job_timestamp self.eta = p.eta self.ddim_discretize = p.ddim_discretize @@ -167,6 +168,7 @@ class Processed: "index_of_first_image": self.index_of_first_image, "infotexts": self.infotexts, "styles": self.styles, + "job_timestamp": self.job_timestamp, } return json.dumps(obj) From 405c8171d1acbb994084d98770bbcb97d01d9406 Mon Sep 17 00:00:00 2001 From: Milly Date: Thu, 6 Oct 2022 00:59:04 +0900 Subject: [PATCH 120/460] Prefer using `Processed.sd_model_hash` attribute when filename pattern --- modules/images.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images.py b/modules/images.py index 669d76af6..29c5ee249 100644 --- a/modules/images.py +++ b/modules/images.py @@ -295,7 +295,7 @@ def apply_filename_pattern(x, p, seed, prompt): x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]) or "None", replace_spaces=False)) x = x.replace("[sampler]", sanitize_filename_part(sd_samplers.samplers[p.sampler_index].name, replace_spaces=False)) - x = x.replace("[model_hash]", shared.sd_model.sd_model_hash) + x = x.replace("[model_hash]", getattr(p, "sd_model_hash", shared.sd_model.sd_model_hash)) x = x.replace("[date]", datetime.date.today().isoformat()) x = x.replace("[datetime]", datetime.datetime.now().strftime("%Y%m%d%H%M%S")) x = x.replace("[job_timestamp]", getattr(p, "job_timestamp", shared.state.job_timestamp)) From b34b25b4c941819d34f29be6c4c1ec01e64585b4 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 23:27:01 +0300 Subject: [PATCH 121/460] karras samplers for img2img? --- modules/sd_samplers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 497df9430..df17e93ca 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -338,9 +338,11 @@ class KDiffusionSampler: steps, t_enc = setup_img2img_steps(p, steps) if p.sampler_noise_scheduler_override: - sigmas = p.sampler_noise_scheduler_override(steps) + sigmas = p.sampler_noise_scheduler_override(steps) + elif self.config is not None and self.config.options.get('scheduler', None) == 'karras': + sigmas = k_diffusion.sampling.get_sigmas_karras(n=steps, sigma_min=0.1, sigma_max=10, device=shared.device) else: - sigmas = self.model_wrap.get_sigmas(steps) + sigmas = self.model_wrap.get_sigmas(steps) noise = noise * sigmas[steps - t_enc - 1] xi = x + noise From 2995107fa24cfd72b0a991e18271dcde148c2807 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 6 Oct 2022 23:44:54 +0300 Subject: [PATCH 122/460] added ctrl+up or ctrl+down hotkeys for attention --- README.md | 4 ++++ javascript/edit-attention.js | 41 ++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 javascript/edit-attention.js diff --git a/README.md b/README.md index ec3d7532d..a14a63306 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - Attention, specify parts of text that the model should pay more attention to - a man in a ((tuxedo)) - will pay more attention to tuxedo - a man in a (tuxedo:1.21) - alternative syntax + - select text and press ctrl+up or ctrl+down to aduotmatically adjust attention to selected text - Loopback, run img2img processing multiple times - X/Y plot, a way to draw a 2 dimensional plot of images with different parameters - Textual Inversion @@ -61,6 +62,9 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - Reloading checkpoints on the fly - Checkpoint Merger, a tab that allows you to merge two checkpoints into one - [Custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Scripts) with many extensions from community +- [Composable-Diffusion](https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/), a way to use multiple prompts at once + - separate prompts using uppercase `AND` + - also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2` ## Installation and Running Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js new file mode 100644 index 000000000..c67ed5794 --- /dev/null +++ b/javascript/edit-attention.js @@ -0,0 +1,41 @@ +addEventListener('keydown', (event) => { + let target = event.originalTarget; + if (!target.hasAttribute("placeholder")) return; + if (!target.placeholder.toLowerCase().includes("prompt")) return; + + let plus = "ArrowUp" + let minus = "ArrowDown" + if (event.key != plus && event.key != minus) return; + + selectionStart = target.selectionStart; + selectionEnd = target.selectionEnd; + if(selectionStart == selectionEnd) return; + + event.preventDefault(); + + if (selectionStart == 0 || target.value[selectionStart - 1] != "(") { + target.value = target.value.slice(0, selectionStart) + + "(" + target.value.slice(selectionStart, selectionEnd) + ":1.0)" + + target.value.slice(selectionEnd); + + target.focus(); + target.selectionStart = selectionStart + 1; + target.selectionEnd = selectionEnd + 1; + + } else { + end = target.value.slice(selectionEnd + 1).indexOf(")") + 1; + weight = parseFloat(target.value.slice(selectionEnd + 1, selectionEnd + 1 + end)); + if (event.key == minus) weight -= 0.1; + if (event.key == plus) weight += 0.1; + + weight = parseFloat(weight.toPrecision(12)); + + target.value = target.value.slice(0, selectionEnd + 1) + + weight + + target.value.slice(selectionEnd + 1 + end - 1); + + target.focus(); + target.selectionStart = selectionStart; + target.selectionEnd = selectionEnd; + } +}); From f174fb29228a04955fb951b32b0bab79e33ec2b8 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Fri, 7 Oct 2022 05:21:49 +0300 Subject: [PATCH 123/460] add xformers attention --- modules/sd_hijack_optimizations.py | 39 +++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index ea4cfdfcd..da1b76e1c 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -1,7 +1,9 @@ import math import torch from torch import einsum - +import xformers.ops +import functorch +xformers._is_functorch_available=True from ldm.util import default from einops import rearrange @@ -92,6 +94,41 @@ def split_cross_attention_forward(self, x, context=None, mask=None): return self.to_out(r2) +def _maybe_init(self, x): + """ + Initialize the attention operator, if required We expect the head dimension to be exposed here, meaning that x + : B, Head, Length + """ + if self.attention_op is not None: + return + _, M, K = x.shape + try: + self.attention_op = xformers.ops.AttentionOpDispatch( + dtype=x.dtype, + device=x.device, + k=K, + attn_bias_type=type(None), + has_dropout=False, + kv_len=M, + q_len=M, + ).op + except NotImplementedError as err: + raise NotImplementedError(f"Please install xformers with the flash attention / cutlass components.\n{err}") + +def xformers_attention_forward(self, x, context=None, mask=None): + h = self.heads + q_in = self.to_q(x) + context = default(context, x) + k_in = self.to_k(context) + v_in = self.to_v(context) + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q_in, k_in, v_in)) + del q_in, k_in, v_in + self._maybe_init(q) + out = xformers.ops.memory_efficient_attention(q, k, v, attn_bias=None, op=self.attention_op) + + out = rearrange(out, '(b h) n d -> b n (h d)', h=h) + return self.to_out(out) + def cross_attention_attnblock_forward(self, x): h_ = x h_ = self.norm(h_) From 2eb911b056ce6ff4434f673366782ed34f2b2f12 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Fri, 7 Oct 2022 05:22:28 +0300 Subject: [PATCH 124/460] Update sd_hijack.py --- modules/sd_hijack.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index a6fa890c4..6221ed5ac 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -20,12 +20,17 @@ diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.At def apply_optimizations(): - ldm.modules.diffusionmodules.model.nonlinearity = silu - if cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 - elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): - ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward + if cmd_opts.opt_split_attention: + ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward + ldm.modules.diffusionmodules.model.nonlinearity = sd_hijack_optimizations.nonlinearity_hijack + ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward + elif not cmd_opts.disable_opt_xformers_attention: + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward + ldm.modules.attention.CrossAttention._maybe_init = sd_hijack_optimizations._maybe_init + ldm.modules.attention.CrossAttention.attention_op = None + ldm.modules.diffusionmodules.model.nonlinearity = sd_hijack_optimizations.nonlinearity_hijack ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward From da4ab2707b4cb0611cf181ba248a271d1937433e Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Fri, 7 Oct 2022 05:23:06 +0300 Subject: [PATCH 125/460] Update shared.py --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index 25bb6e6c9..8cc3b2fe2 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -43,6 +43,7 @@ parser.add_argument("--realesrgan-models-path", type=str, help="Path to director parser.add_argument("--scunet-models-path", type=str, help="Path to directory with ScuNET model file(s).", default=os.path.join(models_path, 'ScuNET')) parser.add_argument("--swinir-models-path", type=str, help="Path to directory with SwinIR model file(s).", default=os.path.join(models_path, 'SwinIR')) parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(models_path, 'LDSR')) +parser.add_argument("--disable-opt-xformers-attention", action='store_true', help="force-disables xformers attention optimization") parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") From cd8bb597c6bcb6c59b538b7a1ab8f2face764fc5 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Fri, 7 Oct 2022 05:23:25 +0300 Subject: [PATCH 126/460] Update requirements.txt --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 631fe616a..304a066a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,3 +23,5 @@ resize-right torchdiffeq kornia lark +functorch +#xformers? From 35d6b231628d18d53d166c3a92fea1523e88d51e Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Fri, 7 Oct 2022 05:31:53 +0300 Subject: [PATCH 127/460] Update sd_hijack.py --- modules/sd_hijack.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 6221ed5ac..a006c0a3b 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -20,17 +20,16 @@ diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.At def apply_optimizations(): + ldm.modules.diffusionmodules.model.nonlinearity = silu if cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 if cmd_opts.opt_split_attention: ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward - ldm.modules.diffusionmodules.model.nonlinearity = sd_hijack_optimizations.nonlinearity_hijack ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward elif not cmd_opts.disable_opt_xformers_attention: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.attention.CrossAttention._maybe_init = sd_hijack_optimizations._maybe_init ldm.modules.attention.CrossAttention.attention_op = None - ldm.modules.diffusionmodules.model.nonlinearity = sd_hijack_optimizations.nonlinearity_hijack ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward From 5303df24282ba06abb34a423f2967354d37d078e Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Fri, 7 Oct 2022 06:01:14 +0300 Subject: [PATCH 128/460] Update sd_hijack.py --- modules/sd_hijack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index a006c0a3b..ddacb0ad8 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -23,10 +23,10 @@ def apply_optimizations(): ldm.modules.diffusionmodules.model.nonlinearity = silu if cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 - if cmd_opts.opt_split_attention: + elif cmd_opts.opt_split_attention: ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward - elif not cmd_opts.disable_opt_xformers_attention: + elif not cmd_opts.disable_opt_xformers_attention and not cmd_opts.opt_split_attention: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.attention.CrossAttention._maybe_init = sd_hijack_optimizations._maybe_init ldm.modules.attention.CrossAttention.attention_op = None From 5e3ff846c56dc8e1d5c76ea04a8f2f74d7da07fc Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Fri, 7 Oct 2022 06:38:01 +0300 Subject: [PATCH 129/460] Update sd_hijack.py --- modules/sd_hijack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index ddacb0ad8..cbdb9d3c7 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -26,7 +26,7 @@ def apply_optimizations(): elif cmd_opts.opt_split_attention: ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward - elif not cmd_opts.disable_opt_xformers_attention and not cmd_opts.opt_split_attention: + elif not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip): ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.attention.CrossAttention._maybe_init = sd_hijack_optimizations._maybe_init ldm.modules.attention.CrossAttention.attention_op = None From bad7cb29cecac51c5c0f39afec332b007ed73133 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 7 Oct 2022 10:17:52 +0300 Subject: [PATCH 130/460] added support for hypernetworks (???) --- modules/hypernetwork.py | 55 ++++++++++++++++++++++++++++++ modules/sd_hijack_optimizations.py | 17 +++++++-- modules/shared.py | 9 ++++- scripts/xy_grid.py | 10 ++++++ 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 modules/hypernetwork.py diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py new file mode 100644 index 000000000..9ed1eed9b --- /dev/null +++ b/modules/hypernetwork.py @@ -0,0 +1,55 @@ +import glob +import os +import torch +from modules import devices + + +class HypernetworkModule(torch.nn.Module): + def __init__(self, dim, state_dict): + super().__init__() + + self.linear1 = torch.nn.Linear(dim, dim * 2) + self.linear2 = torch.nn.Linear(dim * 2, dim) + + self.load_state_dict(state_dict, strict=True) + self.to(devices.device) + + def forward(self, x): + return x + (self.linear2(self.linear1(x))) + + +class Hypernetwork: + filename = None + name = None + + def __init__(self, filename): + self.filename = filename + self.name = os.path.splitext(os.path.basename(filename))[0] + self.layers = {} + + state_dict = torch.load(filename, map_location='cpu') + for size, sd in state_dict.items(): + self.layers[size] = (HypernetworkModule(size, sd[0]), HypernetworkModule(size, sd[1])) + + +def load_hypernetworks(path): + res = {} + + for filename in glob.iglob(path + '**/*.pt', recursive=True): + hn = Hypernetwork(filename) + res[hn.name] = hn + + return res + +def apply(self, x, context=None, mask=None, original=None): + + + if CrossAttention.hypernetwork is not None and context.shape[2] in CrossAttention.hypernetwork: + if context.shape[1] == 77 and CrossAttention.noise_cond: + context = context + (torch.randn_like(context) * 0.1) + h_k, h_v = CrossAttention.hypernetwork[context.shape[2]] + k = self.to_k(h_k(context)) + v = self.to_v(h_v(context)) + else: + k = self.to_k(context) + v = self.to_v(context) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index ea4cfdfcd..d9cca4851 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -5,6 +5,8 @@ from torch import einsum from ldm.util import default from einops import rearrange +from modules import shared + # see https://github.com/basujindal/stable-diffusion/pull/117 for discussion def split_cross_attention_forward_v1(self, x, context=None, mask=None): @@ -42,8 +44,19 @@ def split_cross_attention_forward(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - k_in = self.to_k(context) * self.scale - v_in = self.to_v(context) + + hypernetwork = shared.selected_hypernetwork() + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + + if hypernetwork_layers is not None: + k_in = self.to_k(hypernetwork_layers[0](context)) + v_in = self.to_v(hypernetwork_layers[1](context)) + else: + k_in = self.to_k(context) + v_in = self.to_v(context) + + k_in *= self.scale + del context, x q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q_in, k_in, v_in)) diff --git a/modules/shared.py b/modules/shared.py index 25bb6e6c9..879d8424a 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -13,7 +13,7 @@ import modules.memmon import modules.sd_models import modules.styles import modules.devices as devices -from modules import sd_samplers +from modules import sd_samplers, hypernetwork from modules.paths import models_path, script_path, sd_path sd_model_file = os.path.join(script_path, 'model.ckpt') @@ -76,6 +76,12 @@ parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram config_filename = cmd_opts.ui_settings_file +hypernetworks = hypernetwork.load_hypernetworks(os.path.join(models_path, 'hypernetworks')) + + +def selected_hypernetwork(): + return hypernetworks.get(opts.sd_hypernetwork, None) + class State: interrupted = False @@ -206,6 +212,7 @@ options_templates.update(options_section(('system', "System"), { options_templates.update(options_section(('sd', "Stable Diffusion"), { "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}), + "sd_hypernetwork": OptionInfo("None", "Stable Diffusion finetune hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), "save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"), "img2img_fix_steps": OptionInfo(False, "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising)."), diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 6344e612f..c0c364df8 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -77,6 +77,11 @@ def apply_checkpoint(p, x, xs): modules.sd_models.reload_model_weights(shared.sd_model, info) +def apply_hypernetwork(p, x, xs): + hn = shared.hypernetworks.get(x, None) + opts.data["sd_hypernetwork"] = hn.name if hn is not None else 'None' + + def format_value_add_label(p, opt, x): if type(x) == float: x = round(x, 8) @@ -122,6 +127,7 @@ axis_options = [ AxisOption("Prompt order", str_permutations, apply_order, format_value_join_list), AxisOption("Sampler", str, apply_sampler, format_value), AxisOption("Checkpoint name", str, apply_checkpoint, format_value), + AxisOption("Hypernetwork", str, apply_hypernetwork, format_value), AxisOption("Sigma Churn", float, apply_field("s_churn"), format_value_add_label), AxisOption("Sigma min", float, apply_field("s_tmin"), format_value_add_label), AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label), @@ -193,6 +199,8 @@ class Script(scripts.Script): modules.processing.fix_seed(p) p.batch_size = 1 + initial_hn = opts.sd_hypernetwork + def process_axis(opt, vals): if opt.label == 'Nothing': return [0] @@ -300,4 +308,6 @@ class Script(scripts.Script): # restore checkpoint in case it was changed by axes modules.sd_models.reload_model_weights(shared.sd_model) + opts.data["sd_hypernetwork"] = initial_hn + return processed From d15b3ec0013c10f02f0fb80e8448bac8872a151f Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 7 Oct 2022 10:40:22 +0300 Subject: [PATCH 131/460] support loading VAE --- modules/sd_models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/sd_models.py b/modules/sd_models.py index 5f9920647..8f794b479 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -134,6 +134,14 @@ def load_model_weights(model, checkpoint_file, sd_model_hash): devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16 + vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt" + if os.path.exists(vae_file): + print(f"Loading VAE weights from: {vae_file}") + vae_ckpt = torch.load(vae_file, map_location="cpu") + vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} + + model.first_stage_model.load_state_dict(vae_dict) + model.sd_model_hash = sd_model_hash model.sd_model_checkpint = checkpoint_file From 97bc0b9504572d2df80598d0b694703bcd626de6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 7 Oct 2022 13:22:50 +0300 Subject: [PATCH 132/460] do not stop working on failed hypernetwork load --- modules/hypernetwork.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py index 9ed1eed9b..c5cf4afa4 100644 --- a/modules/hypernetwork.py +++ b/modules/hypernetwork.py @@ -1,5 +1,8 @@ import glob import os +import sys +import traceback + import torch from modules import devices @@ -36,8 +39,12 @@ def load_hypernetworks(path): res = {} for filename in glob.iglob(path + '**/*.pt', recursive=True): - hn = Hypernetwork(filename) - res[hn.name] = hn + try: + hn = Hypernetwork(filename) + res[hn.name] = hn + except Exception: + print(f"Error loading hypernetwork {filename}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) return res From f7c787eb7c295c27439f4fbdf78c26b8389560be Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 7 Oct 2022 16:39:51 +0300 Subject: [PATCH 133/460] make it possible to use hypernetworks without opt split attention --- modules/hypernetwork.py | 42 +++++++++++++++++++++++++++++++++-------- modules/sd_hijack.py | 6 ++++-- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py index c5cf4afa4..c7b866829 100644 --- a/modules/hypernetwork.py +++ b/modules/hypernetwork.py @@ -4,7 +4,12 @@ import sys import traceback import torch -from modules import devices + +from ldm.util import default +from modules import devices, shared +import torch +from torch import einsum +from einops import rearrange, repeat class HypernetworkModule(torch.nn.Module): @@ -48,15 +53,36 @@ def load_hypernetworks(path): return res -def apply(self, x, context=None, mask=None, original=None): +def attention_CrossAttention_forward(self, x, context=None, mask=None): + h = self.heads - if CrossAttention.hypernetwork is not None and context.shape[2] in CrossAttention.hypernetwork: - if context.shape[1] == 77 and CrossAttention.noise_cond: - context = context + (torch.randn_like(context) * 0.1) - h_k, h_v = CrossAttention.hypernetwork[context.shape[2]] - k = self.to_k(h_k(context)) - v = self.to_v(h_v(context)) + q = self.to_q(x) + context = default(context, x) + + hypernetwork = shared.selected_hypernetwork() + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + + if hypernetwork_layers is not None: + k = self.to_k(hypernetwork_layers[0](context)) + v = self.to_v(hypernetwork_layers[1](context)) else: k = self.to_k(context) v = self.to_v(context) + + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) + + sim = einsum('b i d, b j d -> b i j', q, k) * self.scale + + if mask is not None: + mask = rearrange(mask, 'b ... -> b (...)') + max_neg_value = -torch.finfo(sim.dtype).max + mask = repeat(mask, 'b j -> (b h) () j', h=h) + sim.masked_fill_(~mask, max_neg_value) + + # attention, what we cannot get enough of + attn = sim.softmax(dim=-1) + + out = einsum('b i j, b j d -> b i d', attn, v) + out = rearrange(out, '(b h) n d -> b n (h d)', h=h) + return self.to_out(out) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index a6fa890c4..d68f89cc2 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -8,7 +8,7 @@ from torch import einsum from torch.nn.functional import silu import modules.textual_inversion.textual_inversion -from modules import prompt_parser, devices, sd_hijack_optimizations, shared +from modules import prompt_parser, devices, sd_hijack_optimizations, shared, hypernetwork from modules.shared import opts, device, cmd_opts import ldm.modules.attention @@ -20,6 +20,8 @@ diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.At def apply_optimizations(): + undo_optimizations() + ldm.modules.diffusionmodules.model.nonlinearity = silu if cmd_opts.opt_split_attention_v1: @@ -30,7 +32,7 @@ def apply_optimizations(): def undo_optimizations(): - ldm.modules.attention.CrossAttention.forward = attention_CrossAttention_forward + ldm.modules.attention.CrossAttention.forward = hypernetwork.attention_CrossAttention_forward ldm.modules.diffusionmodules.model.nonlinearity = diffusionmodules_model_nonlinearity ldm.modules.diffusionmodules.model.AttnBlock.forward = diffusionmodules_model_AttnBlock_forward From 54fa613c8391e3973cca9d94cdf539061932508b Mon Sep 17 00:00:00 2001 From: Greendayle Date: Fri, 7 Oct 2022 20:37:43 +0200 Subject: [PATCH 134/460] loading tf only in interrogation process --- modules/deepbooru.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index fb5018a6c..79dc59bdf 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -1,12 +1,13 @@ import os.path from concurrent.futures import ProcessPoolExecutor -import numpy as np -import deepdanbooru as dd -import tensorflow as tf def _load_tf_and_return_tags(pil_image, threshold): + import deepdanbooru as dd + import tensorflow as tf + import numpy as np + this_folder = os.path.dirname(__file__) model_path = os.path.join(this_folder, '..', 'models', 'deepbooru', 'deepdanbooru-v3-20211112-sgd-e28') From fa2ea648db81f5723bb5d722f2fe0ebd7dfc319a Mon Sep 17 00:00:00 2001 From: Greendayle Date: Fri, 7 Oct 2022 20:46:38 +0200 Subject: [PATCH 135/460] even more powerfull fix --- modules/deepbooru.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 79dc59bdf..600943368 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -60,8 +60,13 @@ def _load_tf_and_return_tags(pil_image, threshold): return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') +def subprocess_init_no_cuda(): + import os + os.environ["CUDA_VISIBLE_DEVICES"] = "-1" + + def get_deepbooru_tags(pil_image, threshold=0.5): - with ProcessPoolExecutor() as executor: - f = executor.submit(_load_tf_and_return_tags, pil_image, threshold) + with ProcessPoolExecutor(initializer=subprocess_init_no_cuda) as executor: + f = executor.submit(_load_tf_and_return_tags, pil_image, threshold, ) ret = f.result() # will rethrow any exceptions return ret \ No newline at end of file From 5f12e7efd92ad802742f96788b4be3249ad02829 Mon Sep 17 00:00:00 2001 From: Greendayle Date: Fri, 7 Oct 2022 20:58:30 +0200 Subject: [PATCH 136/460] linux test --- modules/deepbooru.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 600943368..781b22492 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -1,6 +1,6 @@ import os.path from concurrent.futures import ProcessPoolExecutor - +from multiprocessing import get_context def _load_tf_and_return_tags(pil_image, threshold): @@ -66,7 +66,8 @@ def subprocess_init_no_cuda(): def get_deepbooru_tags(pil_image, threshold=0.5): - with ProcessPoolExecutor(initializer=subprocess_init_no_cuda) as executor: + context = get_context('spawn') + with ProcessPoolExecutor(initializer=subprocess_init_no_cuda, mp_context=context) as executor: f = executor.submit(_load_tf_and_return_tags, pil_image, threshold, ) ret = f.result() # will rethrow any exceptions return ret \ No newline at end of file From 12c4d5c6b5bf9dd50d0601c36af4f99b65316d58 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 7 Oct 2022 23:22:22 +0300 Subject: [PATCH 137/460] hypernetwork training mk1 --- modules/hypernetwork.py | 88 ------ modules/hypernetwork/hypernetwork.py | 267 +++++++++++++++++++ modules/hypernetwork/ui.py | 43 +++ modules/sd_hijack.py | 4 +- modules/sd_hijack_optimizations.py | 3 +- modules/shared.py | 13 +- modules/textual_inversion/ui.py | 1 - modules/ui.py | 58 +++- scripts/xy_grid.py | 7 +- textual_inversion_templates/hypernetwork.txt | 27 ++ textual_inversion_templates/none.txt | 1 + webui.py | 9 + 12 files changed, 414 insertions(+), 107 deletions(-) delete mode 100644 modules/hypernetwork.py create mode 100644 modules/hypernetwork/hypernetwork.py create mode 100644 modules/hypernetwork/ui.py create mode 100644 textual_inversion_templates/hypernetwork.txt create mode 100644 textual_inversion_templates/none.txt diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py deleted file mode 100644 index c7b866829..000000000 --- a/modules/hypernetwork.py +++ /dev/null @@ -1,88 +0,0 @@ -import glob -import os -import sys -import traceback - -import torch - -from ldm.util import default -from modules import devices, shared -import torch -from torch import einsum -from einops import rearrange, repeat - - -class HypernetworkModule(torch.nn.Module): - def __init__(self, dim, state_dict): - super().__init__() - - self.linear1 = torch.nn.Linear(dim, dim * 2) - self.linear2 = torch.nn.Linear(dim * 2, dim) - - self.load_state_dict(state_dict, strict=True) - self.to(devices.device) - - def forward(self, x): - return x + (self.linear2(self.linear1(x))) - - -class Hypernetwork: - filename = None - name = None - - def __init__(self, filename): - self.filename = filename - self.name = os.path.splitext(os.path.basename(filename))[0] - self.layers = {} - - state_dict = torch.load(filename, map_location='cpu') - for size, sd in state_dict.items(): - self.layers[size] = (HypernetworkModule(size, sd[0]), HypernetworkModule(size, sd[1])) - - -def load_hypernetworks(path): - res = {} - - for filename in glob.iglob(path + '**/*.pt', recursive=True): - try: - hn = Hypernetwork(filename) - res[hn.name] = hn - except Exception: - print(f"Error loading hypernetwork {filename}", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - - return res - - -def attention_CrossAttention_forward(self, x, context=None, mask=None): - h = self.heads - - q = self.to_q(x) - context = default(context, x) - - hypernetwork = shared.selected_hypernetwork() - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) - - if hypernetwork_layers is not None: - k = self.to_k(hypernetwork_layers[0](context)) - v = self.to_v(hypernetwork_layers[1](context)) - else: - k = self.to_k(context) - v = self.to_v(context) - - q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) - - sim = einsum('b i d, b j d -> b i j', q, k) * self.scale - - if mask is not None: - mask = rearrange(mask, 'b ... -> b (...)') - max_neg_value = -torch.finfo(sim.dtype).max - mask = repeat(mask, 'b j -> (b h) () j', h=h) - sim.masked_fill_(~mask, max_neg_value) - - # attention, what we cannot get enough of - attn = sim.softmax(dim=-1) - - out = einsum('b i j, b j d -> b i d', attn, v) - out = rearrange(out, '(b h) n d -> b n (h d)', h=h) - return self.to_out(out) diff --git a/modules/hypernetwork/hypernetwork.py b/modules/hypernetwork/hypernetwork.py new file mode 100644 index 000000000..a3d6a47ef --- /dev/null +++ b/modules/hypernetwork/hypernetwork.py @@ -0,0 +1,267 @@ +import datetime +import glob +import html +import os +import sys +import traceback +import tqdm + +import torch + +from ldm.util import default +from modules import devices, shared, processing, sd_models +import torch +from torch import einsum +from einops import rearrange, repeat +import modules.textual_inversion.dataset + + +class HypernetworkModule(torch.nn.Module): + def __init__(self, dim, state_dict=None): + super().__init__() + + self.linear1 = torch.nn.Linear(dim, dim * 2) + self.linear2 = torch.nn.Linear(dim * 2, dim) + + if state_dict is not None: + self.load_state_dict(state_dict, strict=True) + else: + self.linear1.weight.data.fill_(0.0001) + self.linear1.bias.data.fill_(0.0001) + self.linear2.weight.data.fill_(0.0001) + self.linear2.bias.data.fill_(0.0001) + + self.to(devices.device) + + def forward(self, x): + return x + (self.linear2(self.linear1(x))) + + +class Hypernetwork: + filename = None + name = None + + def __init__(self, name=None): + self.filename = None + self.name = name + self.layers = {} + self.step = 0 + self.sd_checkpoint = None + self.sd_checkpoint_name = None + + for size in [320, 640, 768, 1280]: + self.layers[size] = (HypernetworkModule(size), HypernetworkModule(size)) + + def weights(self): + res = [] + + for k, layers in self.layers.items(): + for layer in layers: + layer.train() + res += [layer.linear1.weight, layer.linear1.bias, layer.linear2.weight, layer.linear2.bias] + + return res + + def save(self, filename): + state_dict = {} + + for k, v in self.layers.items(): + state_dict[k] = (v[0].state_dict(), v[1].state_dict()) + + state_dict['step'] = self.step + state_dict['name'] = self.name + state_dict['sd_checkpoint'] = self.sd_checkpoint + state_dict['sd_checkpoint_name'] = self.sd_checkpoint_name + + torch.save(state_dict, filename) + + def load(self, filename): + self.filename = filename + if self.name is None: + self.name = os.path.splitext(os.path.basename(filename))[0] + + state_dict = torch.load(filename, map_location='cpu') + + for size, sd in state_dict.items(): + if type(size) == int: + self.layers[size] = (HypernetworkModule(size, sd[0]), HypernetworkModule(size, sd[1])) + + self.name = state_dict.get('name', self.name) + self.step = state_dict.get('step', 0) + self.sd_checkpoint = state_dict.get('sd_checkpoint', None) + self.sd_checkpoint_name = state_dict.get('sd_checkpoint_name', None) + + +def load_hypernetworks(path): + res = {} + + for filename in glob.iglob(path + '**/*.pt', recursive=True): + try: + hn = Hypernetwork() + hn.load(filename) + res[hn.name] = hn + except Exception: + print(f"Error loading hypernetwork {filename}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + + return res + + +def attention_CrossAttention_forward(self, x, context=None, mask=None): + h = self.heads + + q = self.to_q(x) + context = default(context, x) + + hypernetwork_layers = (shared.hypernetwork.layers if shared.hypernetwork is not None else {}).get(context.shape[2], None) + + if hypernetwork_layers is not None: + hypernetwork_k, hypernetwork_v = hypernetwork_layers + + self.hypernetwork_k = hypernetwork_k + self.hypernetwork_v = hypernetwork_v + + context_k = hypernetwork_k(context) + context_v = hypernetwork_v(context) + else: + context_k = context + context_v = context + + k = self.to_k(context_k) + v = self.to_v(context_v) + + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) + + sim = einsum('b i d, b j d -> b i j', q, k) * self.scale + + if mask is not None: + mask = rearrange(mask, 'b ... -> b (...)') + max_neg_value = -torch.finfo(sim.dtype).max + mask = repeat(mask, 'b j -> (b h) () j', h=h) + sim.masked_fill_(~mask, max_neg_value) + + # attention, what we cannot get enough of + attn = sim.softmax(dim=-1) + + out = einsum('b i j, b j d -> b i d', attn, v) + out = rearrange(out, '(b h) n d -> b n (h d)', h=h) + return self.to_out(out) + + +def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_image_prompt): + assert hypernetwork_name, 'embedding not selected' + + shared.hypernetwork = shared.hypernetworks[hypernetwork_name] + + shared.state.textinfo = "Initializing hypernetwork training..." + shared.state.job_count = steps + + filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') + + log_directory = os.path.join(log_directory, datetime.datetime.now().strftime("%Y-%m-%d"), hypernetwork_name) + + if save_hypernetwork_every > 0: + hypernetwork_dir = os.path.join(log_directory, "hypernetworks") + os.makedirs(hypernetwork_dir, exist_ok=True) + else: + hypernetwork_dir = None + + if create_image_every > 0: + images_dir = os.path.join(log_directory, "images") + os.makedirs(images_dir, exist_ok=True) + else: + images_dir = None + + cond_model = shared.sd_model.cond_stage_model + + shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." + with torch.autocast("cuda"): + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=512, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file) + + hypernetwork = shared.hypernetworks[hypernetwork_name] + weights = hypernetwork.weights() + for weight in weights: + weight.requires_grad = True + + optimizer = torch.optim.AdamW(weights, lr=learn_rate) + + losses = torch.zeros((32,)) + + last_saved_file = "" + last_saved_image = "" + + ititial_step = hypernetwork.step or 0 + if ititial_step > steps: + return hypernetwork, filename + + pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) + for i, (x, text) in pbar: + hypernetwork.step = i + ititial_step + + if hypernetwork.step > steps: + break + + if shared.state.interrupted: + break + + with torch.autocast("cuda"): + c = cond_model([text]) + + x = x.to(devices.device) + loss = shared.sd_model(x.unsqueeze(0), c)[0] + del x + + losses[hypernetwork.step % losses.shape[0]] = loss.item() + + optimizer.zero_grad() + loss.backward() + optimizer.step() + + pbar.set_description(f"loss: {losses.mean():.7f}") + + if hypernetwork.step > 0 and hypernetwork_dir is not None and hypernetwork.step % save_hypernetwork_every == 0: + last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name}-{hypernetwork.step}.pt') + hypernetwork.save(last_saved_file) + + if hypernetwork.step > 0 and images_dir is not None and hypernetwork.step % create_image_every == 0: + last_saved_image = os.path.join(images_dir, f'{hypernetwork_name}-{hypernetwork.step}.png') + + preview_text = text if preview_image_prompt == "" else preview_image_prompt + + p = processing.StableDiffusionProcessingTxt2Img( + sd_model=shared.sd_model, + prompt=preview_text, + steps=20, + do_not_save_grid=True, + do_not_save_samples=True, + ) + + processed = processing.process_images(p) + image = processed.images[0] + + shared.state.current_image = image + image.save(last_saved_image) + + last_saved_image += f", prompt: {preview_text}" + + shared.state.job_no = hypernetwork.step + + shared.state.textinfo = f""" +

+Loss: {losses.mean():.7f}
+Step: {hypernetwork.step}
+Last prompt: {html.escape(text)}
+Last saved embedding: {html.escape(last_saved_file)}
+Last saved image: {html.escape(last_saved_image)}
+

+""" + + checkpoint = sd_models.select_checkpoint() + + hypernetwork.sd_checkpoint = checkpoint.hash + hypernetwork.sd_checkpoint_name = checkpoint.model_name + hypernetwork.save(filename) + + return hypernetwork, filename + + diff --git a/modules/hypernetwork/ui.py b/modules/hypernetwork/ui.py new file mode 100644 index 000000000..525f978c5 --- /dev/null +++ b/modules/hypernetwork/ui.py @@ -0,0 +1,43 @@ +import html +import os + +import gradio as gr + +import modules.textual_inversion.textual_inversion +import modules.textual_inversion.preprocess +from modules import sd_hijack, shared + + +def create_hypernetwork(name): + fn = os.path.join(shared.cmd_opts.hypernetwork_dir, f"{name}.pt") + assert not os.path.exists(fn), f"file {fn} already exists" + + hypernetwork = modules.hypernetwork.hypernetwork.Hypernetwork(name=name) + hypernetwork.save(fn) + + shared.reload_hypernetworks() + shared.hypernetwork = shared.hypernetworks.get(shared.opts.sd_hypernetwork, None) + + return gr.Dropdown.update(choices=sorted([x for x in shared.hypernetworks.keys()])), f"Created: {fn}", "" + + +def train_hypernetwork(*args): + + initial_hypernetwork = shared.hypernetwork + + try: + sd_hijack.undo_optimizations() + + hypernetwork, filename = modules.hypernetwork.hypernetwork.train_hypernetwork(*args) + + res = f""" +Training {'interrupted' if shared.state.interrupted else 'finished'} at {hypernetwork.step} steps. +Hypernetwork saved to {html.escape(filename)} +""" + return res, "" + except Exception: + raise + finally: + shared.hypernetwork = initial_hypernetwork + sd_hijack.apply_optimizations() + diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index d68f89cc2..ec8c9d4b2 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -8,7 +8,7 @@ from torch import einsum from torch.nn.functional import silu import modules.textual_inversion.textual_inversion -from modules import prompt_parser, devices, sd_hijack_optimizations, shared, hypernetwork +from modules import prompt_parser, devices, sd_hijack_optimizations, shared from modules.shared import opts, device, cmd_opts import ldm.modules.attention @@ -32,6 +32,8 @@ def apply_optimizations(): def undo_optimizations(): + from modules.hypernetwork import hypernetwork + ldm.modules.attention.CrossAttention.forward = hypernetwork.attention_CrossAttention_forward ldm.modules.diffusionmodules.model.nonlinearity = diffusionmodules_model_nonlinearity ldm.modules.diffusionmodules.model.AttnBlock.forward = diffusionmodules_model_AttnBlock_forward diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index d9cca4851..3f32e0209 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -45,8 +45,7 @@ def split_cross_attention_forward(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - hypernetwork = shared.selected_hypernetwork() - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + hypernetwork_layers = (shared.hypernetwork.layers if shared.hypernetwork is not None else {}).get(context.shape[2], None) if hypernetwork_layers is not None: k_in = self.to_k(hypernetwork_layers[0](context)) diff --git a/modules/shared.py b/modules/shared.py index 879d8424a..c5a893e8d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -13,7 +13,7 @@ import modules.memmon import modules.sd_models import modules.styles import modules.devices as devices -from modules import sd_samplers, hypernetwork +from modules import sd_samplers from modules.paths import models_path, script_path, sd_path sd_model_file = os.path.join(script_path, 'model.ckpt') @@ -28,6 +28,7 @@ parser.add_argument("--no-half", action='store_true', help="do not switch the mo parser.add_argument("--no-progressbar-hiding", action='store_true', help="do not hide progressbar in gradio UI (we hide it because it slows down ML if you have hardware acceleration in browser)") parser.add_argument("--max-batch-count", type=int, default=16, help="maximum batch count value for the UI") parser.add_argument("--embeddings-dir", type=str, default=os.path.join(script_path, 'embeddings'), help="embeddings directory for textual inversion (default: embeddings)") +parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_path, 'hypernetworks'), help="hypernetwork directory") parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui") parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage") parser.add_argument("--lowvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a lot of speed for very low VRM usage") @@ -76,11 +77,15 @@ parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram config_filename = cmd_opts.ui_settings_file -hypernetworks = hypernetwork.load_hypernetworks(os.path.join(models_path, 'hypernetworks')) + +def reload_hypernetworks(): + from modules.hypernetwork import hypernetwork + hypernetworks.clear() + hypernetworks.update(hypernetwork.load_hypernetworks(cmd_opts.hypernetwork_dir)) -def selected_hypernetwork(): - return hypernetworks.get(opts.sd_hypernetwork, None) +hypernetworks = {} +hypernetwork = None class State: diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py index f19ac5e02..c57de1f94 100644 --- a/modules/textual_inversion/ui.py +++ b/modules/textual_inversion/ui.py @@ -22,7 +22,6 @@ def preprocess(*args): def train_embedding(*args): - try: sd_hijack.undo_optimizations() diff --git a/modules/ui.py b/modules/ui.py index 4f18126fb..051908c1c 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -37,6 +37,7 @@ import modules.generation_parameters_copypaste from modules import prompt_parser from modules.images import save_image import modules.textual_inversion.ui +import modules.hypernetwork.ui # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI mimetypes.init() @@ -965,6 +966,18 @@ def create_ui(wrap_gradio_gpu_call): with gr.Column(): create_embedding = gr.Button(value="Create", variant='primary') + with gr.Group(): + gr.HTML(value="

Create a new hypernetwork

") + + new_hypernetwork_name = gr.Textbox(label="Name") + + with gr.Row(): + with gr.Column(scale=3): + gr.HTML(value="") + + with gr.Column(): + create_hypernetwork = gr.Button(value="Create", variant='primary') + with gr.Group(): gr.HTML(value="

Preprocess images

") @@ -986,6 +999,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Group(): gr.HTML(value="

Train an embedding; must specify a directory with a set of 512x512 images

") train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) + train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', choices=[x for x in shared.hypernetworks.keys()]) learn_rate = gr.Number(label='Learning rate', value=5.0e-03) dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") @@ -993,15 +1007,12 @@ def create_ui(wrap_gradio_gpu_call): steps = gr.Number(label='Max steps', value=100000, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) + preview_image_prompt = gr.Textbox(label='Preview prompt', value="") with gr.Row(): - with gr.Column(scale=2): - gr.HTML(value="") - - with gr.Column(): - with gr.Row(): - interrupt_training = gr.Button(value="Interrupt") - train_embedding = gr.Button(value="Train", variant='primary') + interrupt_training = gr.Button(value="Interrupt") + train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary') + train_embedding = gr.Button(value="Train Embedding", variant='primary') with gr.Column(): progressbar = gr.HTML(elem_id="ti_progressbar") @@ -1027,6 +1038,18 @@ def create_ui(wrap_gradio_gpu_call): ] ) + create_hypernetwork.click( + fn=modules.hypernetwork.ui.create_hypernetwork, + inputs=[ + new_hypernetwork_name, + ], + outputs=[ + train_hypernetwork_name, + ti_output, + ti_outcome, + ] + ) + run_preprocess.click( fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), _js="start_training_textual_inversion", @@ -1062,12 +1085,33 @@ def create_ui(wrap_gradio_gpu_call): ] ) + train_hypernetwork.click( + fn=wrap_gradio_gpu_call(modules.hypernetwork.ui.train_hypernetwork, extra_outputs=[gr.update()]), + _js="start_training_textual_inversion", + inputs=[ + train_hypernetwork_name, + learn_rate, + dataset_directory, + log_directory, + steps, + create_image_every, + save_embedding_every, + template_file, + preview_image_prompt, + ], + outputs=[ + ti_output, + ti_outcome, + ] + ) + interrupt_training.click( fn=lambda: shared.state.interrupt(), inputs=[], outputs=[], ) + def create_setting_component(key): def fun(): return opts.data[key] if key in opts.data else opts.data_labels[key].default diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index c0c364df8..5b504de6b 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -78,8 +78,7 @@ def apply_checkpoint(p, x, xs): def apply_hypernetwork(p, x, xs): - hn = shared.hypernetworks.get(x, None) - opts.data["sd_hypernetwork"] = hn.name if hn is not None else 'None' + shared.hypernetwork = shared.hypernetworks.get(x, None) def format_value_add_label(p, opt, x): @@ -199,7 +198,7 @@ class Script(scripts.Script): modules.processing.fix_seed(p) p.batch_size = 1 - initial_hn = opts.sd_hypernetwork + initial_hn = shared.hypernetwork def process_axis(opt, vals): if opt.label == 'Nothing': @@ -308,6 +307,6 @@ class Script(scripts.Script): # restore checkpoint in case it was changed by axes modules.sd_models.reload_model_weights(shared.sd_model) - opts.data["sd_hypernetwork"] = initial_hn + shared.hypernetwork = initial_hn return processed diff --git a/textual_inversion_templates/hypernetwork.txt b/textual_inversion_templates/hypernetwork.txt new file mode 100644 index 000000000..91e068905 --- /dev/null +++ b/textual_inversion_templates/hypernetwork.txt @@ -0,0 +1,27 @@ +a photo of a [filewords] +a rendering of a [filewords] +a cropped photo of the [filewords] +the photo of a [filewords] +a photo of a clean [filewords] +a photo of a dirty [filewords] +a dark photo of the [filewords] +a photo of my [filewords] +a photo of the cool [filewords] +a close-up photo of a [filewords] +a bright photo of the [filewords] +a cropped photo of a [filewords] +a photo of the [filewords] +a good photo of the [filewords] +a photo of one [filewords] +a close-up photo of the [filewords] +a rendition of the [filewords] +a photo of the clean [filewords] +a rendition of a [filewords] +a photo of a nice [filewords] +a good photo of a [filewords] +a photo of the nice [filewords] +a photo of the small [filewords] +a photo of the weird [filewords] +a photo of the large [filewords] +a photo of a cool [filewords] +a photo of a small [filewords] diff --git a/textual_inversion_templates/none.txt b/textual_inversion_templates/none.txt new file mode 100644 index 000000000..f77af4612 --- /dev/null +++ b/textual_inversion_templates/none.txt @@ -0,0 +1 @@ +picture diff --git a/webui.py b/webui.py index 480360fe0..60f9061f9 100644 --- a/webui.py +++ b/webui.py @@ -74,6 +74,15 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) +def set_hypernetwork(): + shared.hypernetwork = shared.hypernetworks.get(shared.opts.sd_hypernetwork, None) + + +shared.reload_hypernetworks() +shared.opts.onchange("sd_hypernetwork", set_hypernetwork) +set_hypernetwork() + + modules.scripts.load_scripts(os.path.join(script_path, "scripts")) shared.sd_model = modules.sd_models.load_model() From c9cc65b201679ea43c763b0d85e749d40bbc5433 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 04:09:18 +0300 Subject: [PATCH 138/460] switch to the proper way of calling xformers --- modules/sd_hijack_optimizations.py | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index da1b76e1c..7fb4a45e3 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -94,39 +94,17 @@ def split_cross_attention_forward(self, x, context=None, mask=None): return self.to_out(r2) -def _maybe_init(self, x): - """ - Initialize the attention operator, if required We expect the head dimension to be exposed here, meaning that x - : B, Head, Length - """ - if self.attention_op is not None: - return - _, M, K = x.shape - try: - self.attention_op = xformers.ops.AttentionOpDispatch( - dtype=x.dtype, - device=x.device, - k=K, - attn_bias_type=type(None), - has_dropout=False, - kv_len=M, - q_len=M, - ).op - except NotImplementedError as err: - raise NotImplementedError(f"Please install xformers with the flash attention / cutlass components.\n{err}") - def xformers_attention_forward(self, x, context=None, mask=None): h = self.heads q_in = self.to_q(x) context = default(context, x) k_in = self.to_k(context) v_in = self.to_v(context) - q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q_in, k_in, v_in)) + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b n h d', h=h), (q_in, k_in, v_in)) del q_in, k_in, v_in - self._maybe_init(q) - out = xformers.ops.memory_efficient_attention(q, k, v, attn_bias=None, op=self.attention_op) + out = xformers.ops.memory_efficient_attention(q, k, v, attn_bias=None) - out = rearrange(out, '(b h) n d -> b n (h d)', h=h) + out = rearrange(out, 'b n h d -> b n (h d)', h=h) return self.to_out(out) def cross_attention_attnblock_forward(self, x): From b70eaeb2005a5a9593119e7fd32b8072c2a208d5 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 04:10:35 +0300 Subject: [PATCH 139/460] delete broken and unnecessary aliases --- modules/sd_hijack.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index cbdb9d3c7..0e99c3192 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -21,16 +21,14 @@ diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.At def apply_optimizations(): ldm.modules.diffusionmodules.model.nonlinearity = silu - if cmd_opts.opt_split_attention_v1: + if not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip): + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward + ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward + elif cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 elif cmd_opts.opt_split_attention: ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward - elif not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip): - ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward - ldm.modules.attention.CrossAttention._maybe_init = sd_hijack_optimizations._maybe_init - ldm.modules.attention.CrossAttention.attention_op = None - ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward def undo_optimizations(): From a958f9b3fdea95c01d360aba1b6fe0ce3ea6b349 Mon Sep 17 00:00:00 2001 From: Jairo Correa Date: Fri, 7 Oct 2022 20:05:47 -0300 Subject: [PATCH 140/460] edit-attention browser compatibility and readme typo --- README.md | 2 +- javascript/edit-attention.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a14a63306..0516c2cd8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - Attention, specify parts of text that the model should pay more attention to - a man in a ((tuxedo)) - will pay more attention to tuxedo - a man in a (tuxedo:1.21) - alternative syntax - - select text and press ctrl+up or ctrl+down to aduotmatically adjust attention to selected text + - select text and press ctrl+up or ctrl+down to automatically adjust attention to selected text - Loopback, run img2img processing multiple times - X/Y plot, a way to draw a 2 dimensional plot of images with different parameters - Textual Inversion diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js index c67ed5794..0280c603f 100644 --- a/javascript/edit-attention.js +++ b/javascript/edit-attention.js @@ -1,5 +1,5 @@ addEventListener('keydown', (event) => { - let target = event.originalTarget; + let target = event.originalTarget || event.composedPath()[0]; if (!target.hasAttribute("placeholder")) return; if (!target.placeholder.toLowerCase().includes("prompt")) return; From f2055cb1d4ce45d7aaacc49d8ab5bec7791a8f47 Mon Sep 17 00:00:00 2001 From: brkirch Date: Sat, 8 Oct 2022 01:47:02 -0400 Subject: [PATCH 141/460] Add hypernetwork support to split cross attention v1 * Add hypernetwork support to split_cross_attention_forward_v1 * Fix device check in esrgan_model.py to use devices.device_esrgan instead of shared.device --- modules/esrgan_model.py | 2 +- modules/sd_hijack_optimizations.py | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py index d17e730f9..285481242 100644 --- a/modules/esrgan_model.py +++ b/modules/esrgan_model.py @@ -111,7 +111,7 @@ class UpscalerESRGAN(Upscaler): print("Unable to load %s from %s" % (self.model_path, filename)) return None - pretrained_net = torch.load(filename, map_location='cpu' if shared.device.type == 'mps' else None) + pretrained_net = torch.load(filename, map_location='cpu' if devices.device_esrgan.type == 'mps' else None) crt_model = arch.RRDBNet(3, 3, 64, 23, gc=32) pretrained_net = fix_model_layers(crt_model, pretrained_net) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index d9cca4851..3351c7409 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -12,13 +12,22 @@ from modules import shared def split_cross_attention_forward_v1(self, x, context=None, mask=None): h = self.heads - q = self.to_q(x) + q_in = self.to_q(x) context = default(context, x) - k = self.to_k(context) - v = self.to_v(context) + + hypernetwork = shared.selected_hypernetwork() + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + + if hypernetwork_layers is not None: + k_in = self.to_k(hypernetwork_layers[0](context)) + v_in = self.to_v(hypernetwork_layers[1](context)) + else: + k_in = self.to_k(context) + v_in = self.to_v(context) del context, x - q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q_in, k_in, v_in)) + del q_in, k_in, v_in r1 = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device) for i in range(0, q.shape[0], 2): @@ -31,6 +40,7 @@ def split_cross_attention_forward_v1(self, x, context=None, mask=None): r1[i:end] = einsum('b i j, b j d -> b i d', s2, v[i:end]) del s2 + del q, k, v r2 = rearrange(r1, '(b h) n d -> b n (h d)', h=h) del r1 From e21e4732531299ef4895baccdb7a6493a3886924 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 8 Oct 2022 05:34:17 +0100 Subject: [PATCH 142/460] Context Menus --- javascript/contextMenus.js | 165 +++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 javascript/contextMenus.js diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js new file mode 100644 index 000000000..99d1d3f7d --- /dev/null +++ b/javascript/contextMenus.js @@ -0,0 +1,165 @@ + +contextMenuInit = function(){ + let eventListenerApplied=false; + let menuSpecs = new Map(); + + const uid = function(){ + return Date.now().toString(36) + Math.random().toString(36).substr(2); + } + + function showContextMenu(event,element,menuEntries){ + let posx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; + let posy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop; + + let oldMenu = gradioApp().querySelector('#context-menu') + if(oldMenu){ + oldMenu.remove() + } + + let tabButton = gradioApp().querySelector('button') + let baseStyle = window.getComputedStyle(tabButton) + + const contextMenu = document.createElement('nav') + contextMenu.id = "context-menu" + contextMenu.style.background = baseStyle.background + contextMenu.style.color = baseStyle.color + contextMenu.style.fontFamily = baseStyle.fontFamily + contextMenu.style.top = posy+'px' + contextMenu.style.left = posx+'px' + + + + const contextMenuList = document.createElement('ul') + contextMenuList.className = 'context-menu-items'; + contextMenu.append(contextMenuList); + + menuEntries.forEach(function(entry){ + let contextMenuEntry = document.createElement('a') + contextMenuEntry.innerHTML = entry['name'] + contextMenuEntry.addEventListener("click", function(e) { + entry['func'](); + }) + contextMenuList.append(contextMenuEntry); + + }) + + gradioApp().getRootNode().appendChild(contextMenu) + + let menuWidth = contextMenu.offsetWidth + 4; + let menuHeight = contextMenu.offsetHeight + 4; + + let windowWidth = window.innerWidth; + let windowHeight = window.innerHeight; + + if ( (windowWidth - posx) < menuWidth ) { + contextMenu.style.left = windowWidth - menuWidth + "px"; + } + + if ( (windowHeight - posy) < menuHeight ) { + contextMenu.style.top = windowHeight - menuHeight + "px"; + } + + } + + function appendContextMenuOption(targetEmementSelector,entryName,entryFunction){ + + currentItems = menuSpecs.get(targetEmementSelector) + + if(!currentItems){ + currentItems = [] + menuSpecs.set(targetEmementSelector,currentItems); + } + let newItem = {'id':targetEmementSelector+'_'+uid(), + 'name':entryName, + 'func':entryFunction, + 'isNew':true} + + currentItems.push(newItem) + return newItem['id'] + } + + function removeContextMenuOption(uid){ + + } + + function addContextMenuEventListener(){ + if(eventListenerApplied){ + return; + } + gradioApp().addEventListener("click", function(e) { + let source = e.composedPath()[0] + if(source.id && source.indexOf('check_progress')>-1){ + return + } + + let oldMenu = gradioApp().querySelector('#context-menu') + if(oldMenu){ + oldMenu.remove() + } + }); + gradioApp().addEventListener("contextmenu", function(e) { + let oldMenu = gradioApp().querySelector('#context-menu') + if(oldMenu){ + oldMenu.remove() + } + menuSpecs.forEach(function(v,k) { + if(e.composedPath()[0].matches(k)){ + showContextMenu(e,e.composedPath()[0],v) + e.preventDefault() + return + } + }) + }); + eventListenerApplied=true + + } + + return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener] +} + +initResponse = contextMenuInit() +appendContextMenuOption = initResponse[0] +removeContextMenuOption = initResponse[1] +addContextMenuEventListener = initResponse[2] + + +//Start example Context Menu Items +generateOnRepeatId = appendContextMenuOption('#txt2img_generate','Generate forever',function(){ + let genbutton = gradioApp().querySelector('#txt2img_generate'); + let interruptbutton = gradioApp().querySelector('#txt2img_interrupt'); + if(!interruptbutton.offsetParent){ + genbutton.click(); + } + clearInterval(window.generateOnRepeatInterval) + window.generateOnRepeatInterval = setInterval(function(){ + if(!interruptbutton.offsetParent){ + genbutton.click(); + } + }, + 500)} +) + +cancelGenerateForever = function(){ + clearInterval(window.generateOnRepeatInterval) + let interruptbutton = gradioApp().querySelector('#txt2img_interrupt'); + if(interruptbutton.offsetParent){ + interruptbutton.click(); + } +} + +appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever) +appendContextMenuOption('#txt2img_generate','Cancel generate forever',cancelGenerateForever) + +appendContextMenuOption('#roll','Roll three', + function(){ + let rollbutton = gradioApp().querySelector('#roll'); + setTimeout(function(){rollbutton.click()},100) + setTimeout(function(){rollbutton.click()},200) + setTimeout(function(){rollbutton.click()},300) + } +) +//End example Context Menu Items + +onUiUpdate(function(){ + addContextMenuEventListener() +}); \ No newline at end of file From 83749bfc72923b946abb825ebf4fdcc8b6035c8e Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 8 Oct 2022 05:35:03 +0100 Subject: [PATCH 143/460] context menu styling --- style.css | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/style.css b/style.css index da0729a25..50c5e557c 100644 --- a/style.css +++ b/style.css @@ -410,4 +410,31 @@ input[type="range"]{ #img2img_image div.h-60{ height: 480px; -} \ No newline at end of file +} + +#context-menu{ + z-index:9999; + position:absolute; + display:block; + padding:0px 0; + border:2px solid #a55000; + border-radius:8px; + box-shadow:1px 1px 2px #CE6400; + width: 200px; +} + +.context-menu-items{ + list-style: none; + margin: 0; + padding: 0; +} + +.context-menu-items a{ + display:block; + padding:5px; + cursor:pointer; +} + +.context-menu-items a:hover{ + background: #a55000; +} From 21679435e531e729a4aea494e6cb9b7152ecdf75 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 8 Oct 2022 05:46:42 +0100 Subject: [PATCH 144/460] implement removal --- javascript/contextMenus.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index 99d1d3f7d..2d82269fc 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -79,7 +79,13 @@ contextMenuInit = function(){ } function removeContextMenuOption(uid){ - + menuSpecs.forEach(function(v,k) { + let index = -1 + v.forEach(function(e,ei){if(e['id']==uid){index=ei}}) + if(index>=0){ + v.splice(index, 1); + } + }) } function addContextMenuEventListener(){ @@ -148,7 +154,8 @@ cancelGenerateForever = function(){ } appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever) -appendContextMenuOption('#txt2img_generate','Cancel generate forever',cancelGenerateForever) +appendContextMenuOption('#txt2img_generate', 'Cancel generate forever',cancelGenerateForever) + appendContextMenuOption('#roll','Roll three', function(){ @@ -162,4 +169,4 @@ appendContextMenuOption('#roll','Roll three', onUiUpdate(function(){ addContextMenuEventListener() -}); \ No newline at end of file +}); From 87db6f01cc6b118fe0c82c36c6686d72d060c417 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 10:15:29 +0300 Subject: [PATCH 145/460] add info about cross attention javascript shortcut code --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0516c2cd8..d6e1d50bd 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - Attention, specify parts of text that the model should pay more attention to - a man in a ((tuxedo)) - will pay more attention to tuxedo - a man in a (tuxedo:1.21) - alternative syntax - - select text and press ctrl+up or ctrl+down to automatically adjust attention to selected text + - select text and press ctrl+up or ctrl+down to automatically adjust attention to selected text (code contributed by anonymous user) - Loopback, run img2img processing multiple times - X/Y plot, a way to draw a 2 dimensional plot of images with different parameters - Textual Inversion From 5d54f35c583bd5a3b0ee271a862827f1ca81ef09 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 11:55:02 +0300 Subject: [PATCH 146/460] add xformers attnblock and hypernetwork support --- modules/sd_hijack_optimizations.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 7fb4a45e3..c78d58382 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -98,8 +98,14 @@ def xformers_attention_forward(self, x, context=None, mask=None): h = self.heads q_in = self.to_q(x) context = default(context, x) - k_in = self.to_k(context) - v_in = self.to_v(context) + hypernetwork = shared.selected_hypernetwork() + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + if hypernetwork_layers is not None: + k_in = self.to_k(hypernetwork_layers[0](context)) + v_in = self.to_v(hypernetwork_layers[1](context)) + else: + k_in = self.to_k(context) + v_in = self.to_v(context) q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b n h d', h=h), (q_in, k_in, v_in)) del q_in, k_in, v_in out = xformers.ops.memory_efficient_attention(q, k, v, attn_bias=None) @@ -169,3 +175,13 @@ def cross_attention_attnblock_forward(self, x): h3 += x return h3 + + def xformers_attnblock_forward(self, x): + h_ = x + h_ = self.norm(h_) + q1 = self.q(h_).contiguous() + k1 = self.k(h_).contiguous() + v = self.v(h_).contiguous() + out = xformers.ops.memory_efficient_attention(q1, k1, v) + out = self.proj_out(out) + return x+out From 76a616fa6b814c681eaf6edc87eb3001b8c2b6be Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 11:55:38 +0300 Subject: [PATCH 147/460] Update sd_hijack_optimizations.py --- modules/sd_hijack_optimizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index c78d58382..ee58c7e4e 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -176,7 +176,7 @@ def cross_attention_attnblock_forward(self, x): return h3 - def xformers_attnblock_forward(self, x): +def xformers_attnblock_forward(self, x): h_ = x h_ = self.norm(h_) q1 = self.q(h_).contiguous() From 91d66f5520df416db718103d460550ad495e952d Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 11:56:01 +0300 Subject: [PATCH 148/460] use new attnblock for xformers path --- modules/sd_hijack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 0e99c3192..3da8c8ce2 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -23,7 +23,7 @@ def apply_optimizations(): ldm.modules.diffusionmodules.model.nonlinearity = silu if not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip): ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward - ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward + ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 elif cmd_opts.opt_split_attention: From 616b7218f7c469d25c138634472017a7e18e742e Mon Sep 17 00:00:00 2001 From: leko Date: Fri, 7 Oct 2022 23:09:21 +0800 Subject: [PATCH 149/460] fix: handles when state_dict does not exist --- modules/sd_models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 8f794b479..9409d0707 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -122,7 +122,11 @@ def load_model_weights(model, checkpoint_file, sd_model_hash): pl_sd = torch.load(checkpoint_file, map_location="cpu") if "global_step" in pl_sd: print(f"Global Step: {pl_sd['global_step']}") - sd = pl_sd["state_dict"] + + if "state_dict" in pl_sd: + sd = pl_sd["state_dict"] + else: + sd = pl_sd model.load_state_dict(sd, strict=False) From 706d5944a075a6523ea7f00165d630efc085ca22 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 13:38:57 +0300 Subject: [PATCH 150/460] let user choose his own prompt token count limit --- modules/processing.py | 6 ++++++ modules/sd_hijack.py | 13 +++++++------ modules/shared.py | 5 +++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index f773a30ef..d814d5acd 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -123,6 +123,7 @@ class Processed: self.index_of_first_image = index_of_first_image self.styles = p.styles self.job_timestamp = state.job_timestamp + self.max_prompt_tokens = opts.max_prompt_tokens self.eta = p.eta self.ddim_discretize = p.ddim_discretize @@ -141,6 +142,7 @@ class Processed: self.all_subseeds = all_subseeds or [self.subseed] self.infotexts = infotexts or [info] + def js(self): obj = { "prompt": self.prompt, @@ -169,6 +171,7 @@ class Processed: "infotexts": self.infotexts, "styles": self.styles, "job_timestamp": self.job_timestamp, + "max_prompt_tokens": self.max_prompt_tokens, } return json.dumps(obj) @@ -266,6 +269,8 @@ def fix_seed(p): def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration=0, position_in_batch=0): index = position_in_batch + iteration * p.batch_size + max_tokens = getattr(p, 'max_prompt_tokens', opts.max_prompt_tokens) + generation_params = { "Steps": p.steps, "Sampler": sd_samplers.samplers[p.sampler_index].name, @@ -281,6 +286,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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), "Eta": (None if p.sampler is None or p.sampler.eta == p.sampler.default_eta else p.sampler.eta), + "Max tokens": (None if max_tokens == shared.vanilla_max_prompt_tokens else max_tokens) } generation_params.update(p.extra_generation_params) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index d68f89cc2..340329c0b 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -18,7 +18,6 @@ attention_CrossAttention_forward = ldm.modules.attention.CrossAttention.forward diffusionmodules_model_nonlinearity = ldm.modules.diffusionmodules.model.nonlinearity diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.AttnBlock.forward - def apply_optimizations(): undo_optimizations() @@ -83,7 +82,7 @@ class StableDiffusionModelHijack: layer.padding_mode = 'circular' if enable else 'zeros' def tokenize(self, text): - max_length = self.clip.max_length - 2 + max_length = opts.max_prompt_tokens - 2 _, remade_batch_tokens, _, _, _, token_count = self.clip.process_text([text]) return remade_batch_tokens[0], token_count, max_length @@ -94,7 +93,6 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): self.wrapped = wrapped self.hijack: StableDiffusionModelHijack = hijack self.tokenizer = wrapped.tokenizer - self.max_length = wrapped.max_length self.token_mults = {} tokens_with_parens = [(k, v) for k, v in self.tokenizer.get_vocab().items() if '(' in k or ')' in k or '[' in k or ']' in k] @@ -116,7 +114,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): def tokenize_line(self, line, used_custom_terms, hijack_comments): id_start = self.wrapped.tokenizer.bos_token_id id_end = self.wrapped.tokenizer.eos_token_id - maxlen = self.wrapped.max_length + maxlen = opts.max_prompt_tokens if opts.enable_emphasis: parsed = prompt_parser.parse_prompt_attention(line) @@ -191,7 +189,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): def process_text_old(self, text): id_start = self.wrapped.tokenizer.bos_token_id id_end = self.wrapped.tokenizer.eos_token_id - maxlen = self.wrapped.max_length + maxlen = self.wrapped.max_length # you get to stay at 77 used_custom_terms = [] remade_batch_tokens = [] overflowing_words = [] @@ -268,8 +266,11 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): if len(used_custom_terms) > 0: self.hijack.comments.append("Used embeddings: " + ", ".join([f'{word} [{checksum}]' for word, checksum in used_custom_terms])) + position_ids_array = [min(x, 75) for x in range(len(remade_batch_tokens[0])-1)] + [76] + position_ids = torch.asarray(position_ids_array, device=devices.device).expand((1, -1)) + tokens = torch.asarray(remade_batch_tokens).to(device) - outputs = self.wrapped.transformer(input_ids=tokens) + outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids) z = outputs.last_hidden_state # restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise diff --git a/modules/shared.py b/modules/shared.py index 879d8424a..864e772cf 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -118,8 +118,8 @@ prompt_styles = modules.styles.StyleDatabase(styles_filename) interrogator = modules.interrogate.InterrogateModels("interrogate") face_restorers = [] -# This was moved to webui.py with the other model "setup" calls. -# modules.sd_models.list_models() + +vanilla_max_prompt_tokens = 77 def realesrgan_models_names(): @@ -221,6 +221,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "use_old_emphasis_implementation": OptionInfo(False, "Use old emphasis implementation. Can be useful to reproduce old seeds."), "enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"), "filter_nsfw": OptionInfo(False, "Filter NSFW content"), + "max_prompt_tokens": OptionInfo(vanilla_max_prompt_tokens, f"Max prompt token count. Two tokens are reserved for for start and end. Default is {vanilla_max_prompt_tokens}. Setting this to a different value will result in different pictures for same seed.", gr.Number, {"precision": 0}), "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), })) From 786d9f63aaa4515df82eb2cf357ea92f3dae1e29 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Tue, 4 Oct 2022 22:56:30 -0500 Subject: [PATCH 151/460] Add button to skip the current iteration --- javascript/hints.js | 1 + javascript/progressbar.js | 20 ++++++++++++++------ modules/img2img.py | 4 ++++ modules/processing.py | 4 ++++ modules/shared.py | 5 +++++ modules/ui.py | 8 ++++++++ style.css | 14 ++++++++++++-- webui.py | 1 + 8 files changed, 49 insertions(+), 8 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index 8adcd983e..8e352e94a 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -35,6 +35,7 @@ titles = { "Denoising strength": "Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies.", "Denoising strength change factor": "In loopback mode, on each loop the denoising strength is multiplied by this value. <1 means decreasing variety so your sequence will converge on a fixed picture. >1 means increasing variety so your sequence will become more and more chaotic.", + "Skip": "Stop processing current image and continue processing.", "Interrupt": "Stop processing images and return any results accumulated so far.", "Save": "Write image to a directory (default - log/images) and generation parameters into csv file.", diff --git a/javascript/progressbar.js b/javascript/progressbar.js index f9e9290e2..4395a2159 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -1,8 +1,9 @@ // code related to showing and updating progressbar shown as the image is being made global_progressbars = {} -function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_interrupt, id_preview, id_gallery){ +function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip, id_interrupt, id_preview, id_gallery){ var progressbar = gradioApp().getElementById(id_progressbar) + var skip = id_skip ? gradioApp().getElementById(id_skip) : null var interrupt = gradioApp().getElementById(id_interrupt) if(opts.show_progress_in_title && progressbar && progressbar.offsetParent){ @@ -32,30 +33,37 @@ function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_inte var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0; if(!progressDiv){ + if (skip) { + skip.style.display = "none" + } interrupt.style.display = "none" } } - window.setTimeout(function(){ requestMoreProgress(id_part, id_progressbar_span, id_interrupt) }, 500) + window.setTimeout(function() { requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt) }, 500) }); mutationObserver.observe( progressbar, { childList:true, subtree:true }) } } onUiUpdate(function(){ - check_progressbar('txt2img', 'txt2img_progressbar', 'txt2img_progress_span', 'txt2img_interrupt', 'txt2img_preview', 'txt2img_gallery') - check_progressbar('img2img', 'img2img_progressbar', 'img2img_progress_span', 'img2img_interrupt', 'img2img_preview', 'img2img_gallery') - check_progressbar('ti', 'ti_progressbar', 'ti_progress_span', 'ti_interrupt', 'ti_preview', 'ti_gallery') + check_progressbar('txt2img', 'txt2img_progressbar', 'txt2img_progress_span', 'txt2img_skip', 'txt2img_interrupt', 'txt2img_preview', 'txt2img_gallery') + check_progressbar('img2img', 'img2img_progressbar', 'img2img_progress_span', 'img2img_skip', 'img2img_interrupt', 'img2img_preview', 'img2img_gallery') + check_progressbar('ti', 'ti_progressbar', 'ti_progress_span', '', 'ti_interrupt', 'ti_preview', 'ti_gallery') }) -function requestMoreProgress(id_part, id_progressbar_span, id_interrupt){ +function requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt){ btn = gradioApp().getElementById(id_part+"_check_progress"); if(btn==null) return; btn.click(); var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0; + var skip = id_skip ? gradioApp().getElementById(id_skip) : null var interrupt = gradioApp().getElementById(id_interrupt) if(progressDiv && interrupt){ + if (skip) { + skip.style.display = "block" + } interrupt.style.display = "block" } } diff --git a/modules/img2img.py b/modules/img2img.py index da212d72b..e60b7e0ff 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -32,6 +32,10 @@ def process_batch(p, input_dir, output_dir, args): for i, image in enumerate(images): state.job = f"{i+1} out of {len(images)}" + if state.skipped: + state.skipped = False + state.interrupted = False + continue if state.interrupted: break diff --git a/modules/processing.py b/modules/processing.py index d814d5acd..6805039c1 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -355,6 +355,10 @@ def process_images(p: StableDiffusionProcessing) -> Processed: state.job_count = p.n_iter for n in range(p.n_iter): + if state.skipped: + state.skipped = False + state.interrupted = False + if state.interrupted: break diff --git a/modules/shared.py b/modules/shared.py index 864e772cf..7f802bd97 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -84,6 +84,7 @@ def selected_hypernetwork(): class State: + skipped = False interrupted = False job = "" job_no = 0 @@ -96,6 +97,10 @@ class State: current_image_sampling_step = 0 textinfo = None + def skip(self): + self.skipped = True + self.interrupted = True + def interrupt(self): self.interrupted = True diff --git a/modules/ui.py b/modules/ui.py index 4f18126fb..e3e62fdd5 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -191,6 +191,7 @@ def wrap_gradio_call(func, extra_outputs=None): # last item is always HTML res[-1] += f"

Time taken: {elapsed_text}

{vram_html}
" + shared.state.skipped = False shared.state.interrupted = False shared.state.job_count = 0 @@ -411,9 +412,16 @@ def create_toprow(is_img2img): with gr.Column(scale=1): with gr.Row(): + skip = gr.Button('Skip', elem_id=f"{id_part}_skip") interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt") submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary') + skip.click( + fn=lambda: shared.state.skip(), + inputs=[], + outputs=[], + ) + interrupt.click( fn=lambda: shared.state.interrupt(), inputs=[], diff --git a/style.css b/style.css index 50c5e557c..6904fc50e 100644 --- a/style.css +++ b/style.css @@ -393,10 +393,20 @@ input[type="range"]{ #txt2img_interrupt, #img2img_interrupt{ position: absolute; - width: 100%; + width: 50%; height: 72px; background: #b4c0cc; - border-radius: 8px; + border-radius: 0px; + display: none; +} + +#txt2img_skip, #img2img_skip{ + position: absolute; + width: 50%; + right: 0px; + height: 72px; + background: #b4c0cc; + border-radius: 0px; display: none; } diff --git a/webui.py b/webui.py index 480360fe0..3b4cf5e9d 100644 --- a/webui.py +++ b/webui.py @@ -58,6 +58,7 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): shared.state.current_latent = None shared.state.current_image = None shared.state.current_image_sampling_step = 0 + shared.state.skipped = False shared.state.interrupted = False shared.state.textinfo = None From 00117a07efbbe8482add12262a179326541467de Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Sat, 8 Oct 2022 05:33:21 -0500 Subject: [PATCH 152/460] check specifically for skipped --- modules/img2img.py | 2 -- modules/processing.py | 3 +-- modules/sd_samplers.py | 4 ++-- modules/shared.py | 1 - 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/modules/img2img.py b/modules/img2img.py index e60b7e0ff..241267745 100644 --- a/modules/img2img.py +++ b/modules/img2img.py @@ -34,8 +34,6 @@ def process_batch(p, input_dir, output_dir, args): state.job = f"{i+1} out of {len(images)}" if state.skipped: state.skipped = False - state.interrupted = False - continue if state.interrupted: break diff --git a/modules/processing.py b/modules/processing.py index 6805039c1..3657fe69b 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -357,7 +357,6 @@ def process_images(p: StableDiffusionProcessing) -> Processed: for n in range(p.n_iter): if state.skipped: state.skipped = False - state.interrupted = False if state.interrupted: break @@ -385,7 +384,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: with devices.autocast(): samples_ddim = p.sample(conditioning=c, unconditional_conditioning=uc, seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength) - if state.interrupted: + if state.interrupted or state.skipped: # if we are interruped, sample returns just noise # use the image collected previously in sampler loop diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index df17e93ca..13a8b3221 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -106,7 +106,7 @@ def extended_tdqm(sequence, *args, desc=None, **kwargs): seq = sequence if cmd_opts.disable_console_progressbars else tqdm.tqdm(sequence, *args, desc=state.job, file=shared.progress_print_out, **kwargs) for x in seq: - if state.interrupted: + if state.interrupted or state.skipped: break yield x @@ -254,7 +254,7 @@ def extended_trange(sampler, count, *args, **kwargs): seq = range(count) if cmd_opts.disable_console_progressbars else tqdm.trange(count, *args, desc=state.job, file=shared.progress_print_out, **kwargs) for x in seq: - if state.interrupted: + if state.interrupted or state.skipped: break if sampler.stop_at is not None and x > sampler.stop_at: diff --git a/modules/shared.py b/modules/shared.py index 7f802bd97..ca4626282 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -99,7 +99,6 @@ class State: def skip(self): self.skipped = True - self.interrupted = True def interrupt(self): self.interrupted = True From 4999eb2ef9b30e8c42ca7e4a94d4bbffe4d1f015 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 14:25:47 +0300 Subject: [PATCH 153/460] do not let user choose his own prompt token count limit --- README.md | 1 + modules/processing.py | 5 ----- modules/sd_hijack.py | 25 ++++++++++++------------- modules/shared.py | 3 --- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index d6e1d50bd..ef9b5e313 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - [Composable-Diffusion](https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/), a way to use multiple prompts at once - separate prompts using uppercase `AND` - also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2` +- No token limit for prompts (original stable diffusion lets you use up to 75 tokens) ## Installation and Running Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. diff --git a/modules/processing.py b/modules/processing.py index 3657fe69b..d5162ddc0 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -123,7 +123,6 @@ class Processed: self.index_of_first_image = index_of_first_image self.styles = p.styles self.job_timestamp = state.job_timestamp - self.max_prompt_tokens = opts.max_prompt_tokens self.eta = p.eta self.ddim_discretize = p.ddim_discretize @@ -171,7 +170,6 @@ class Processed: "infotexts": self.infotexts, "styles": self.styles, "job_timestamp": self.job_timestamp, - "max_prompt_tokens": self.max_prompt_tokens, } return json.dumps(obj) @@ -269,8 +267,6 @@ def fix_seed(p): def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration=0, position_in_batch=0): index = position_in_batch + iteration * p.batch_size - max_tokens = getattr(p, 'max_prompt_tokens', opts.max_prompt_tokens) - generation_params = { "Steps": p.steps, "Sampler": sd_samplers.samplers[p.sampler_index].name, @@ -286,7 +282,6 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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), "Eta": (None if p.sampler is None or p.sampler.eta == p.sampler.default_eta else p.sampler.eta), - "Max tokens": (None if max_tokens == shared.vanilla_max_prompt_tokens else max_tokens) } generation_params.update(p.extra_generation_params) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 340329c0b..2c1332c9f 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -36,6 +36,13 @@ def undo_optimizations(): ldm.modules.diffusionmodules.model.AttnBlock.forward = diffusionmodules_model_AttnBlock_forward +def get_target_prompt_token_count(token_count): + if token_count < 75: + return 75 + + return math.ceil(token_count / 10) * 10 + + class StableDiffusionModelHijack: fixes = None comments = [] @@ -84,7 +91,7 @@ class StableDiffusionModelHijack: def tokenize(self, text): max_length = opts.max_prompt_tokens - 2 _, remade_batch_tokens, _, _, _, token_count = self.clip.process_text([text]) - return remade_batch_tokens[0], token_count, max_length + return remade_batch_tokens[0], token_count, get_target_prompt_token_count(token_count) class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): @@ -114,7 +121,6 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): def tokenize_line(self, line, used_custom_terms, hijack_comments): id_start = self.wrapped.tokenizer.bos_token_id id_end = self.wrapped.tokenizer.eos_token_id - maxlen = opts.max_prompt_tokens if opts.enable_emphasis: parsed = prompt_parser.parse_prompt_attention(line) @@ -146,19 +152,12 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): used_custom_terms.append((embedding.name, embedding.checksum())) i += embedding_length_in_tokens - if len(remade_tokens) > maxlen - 2: - vocab = {v: k for k, v in self.wrapped.tokenizer.get_vocab().items()} - ovf = remade_tokens[maxlen - 2:] - overflowing_words = [vocab.get(int(x), "") for x in ovf] - overflowing_text = self.wrapped.tokenizer.convert_tokens_to_string(''.join(overflowing_words)) - hijack_comments.append(f"Warning: too many input tokens; some ({len(overflowing_words)}) have been truncated:\n{overflowing_text}\n") - token_count = len(remade_tokens) - remade_tokens = remade_tokens + [id_end] * (maxlen - 2 - len(remade_tokens)) - remade_tokens = [id_start] + remade_tokens[0:maxlen - 2] + [id_end] + prompt_target_length = get_target_prompt_token_count(token_count) + tokens_to_add = prompt_target_length - len(remade_tokens) + 1 - multipliers = multipliers + [1.0] * (maxlen - 2 - len(multipliers)) - multipliers = [1.0] + multipliers[0:maxlen - 2] + [1.0] + remade_tokens = [id_start] + remade_tokens + [id_end] * tokens_to_add + multipliers = [1.0] + multipliers + [1.0] * tokens_to_add return remade_tokens, fixes, multipliers, token_count diff --git a/modules/shared.py b/modules/shared.py index ca4626282..475d7e526 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -123,8 +123,6 @@ interrogator = modules.interrogate.InterrogateModels("interrogate") face_restorers = [] -vanilla_max_prompt_tokens = 77 - def realesrgan_models_names(): import modules.realesrgan_model @@ -225,7 +223,6 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "use_old_emphasis_implementation": OptionInfo(False, "Use old emphasis implementation. Can be useful to reproduce old seeds."), "enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"), "filter_nsfw": OptionInfo(False, "Filter NSFW content"), - "max_prompt_tokens": OptionInfo(vanilla_max_prompt_tokens, f"Max prompt token count. Two tokens are reserved for for start and end. Default is {vanilla_max_prompt_tokens}. Setting this to a different value will result in different pictures for same seed.", gr.Number, {"precision": 0}), "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), })) From 4201fd14f5769a4cf6723d2bc5495c3c84a2cd00 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 14:42:34 +0300 Subject: [PATCH 154/460] install xformers --- launch.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/launch.py b/launch.py index 75edb66a9..f3fbe16a5 100644 --- a/launch.py +++ b/launch.py @@ -124,6 +124,9 @@ if not is_installed("gfpgan"): if not is_installed("clip"): run_pip(f"install {clip_package}", "clip") +if not is_installed("xformers"): + run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") + os.makedirs(dir_repos, exist_ok=True) git_clone("https://github.com/CompVis/stable-diffusion.git", repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) From 3f166be1b60ff2ab33a6d2646809ec3f48796303 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 14:42:50 +0300 Subject: [PATCH 155/460] Update requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 304a066a3..81641d68f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,4 +24,3 @@ torchdiffeq kornia lark functorch -#xformers? From 77f4237d1c3af1756e7dab2699e3dcebad5619d6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 15:25:59 +0300 Subject: [PATCH 156/460] fix bugs related to variable prompt lengths --- modules/sd_hijack.py | 14 +++++++++----- modules/sd_samplers.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 2c1332c9f..7e7fde0f9 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -89,7 +89,6 @@ class StableDiffusionModelHijack: layer.padding_mode = 'circular' if enable else 'zeros' def tokenize(self, text): - max_length = opts.max_prompt_tokens - 2 _, remade_batch_tokens, _, _, _, token_count = self.clip.process_text([text]) return remade_batch_tokens[0], token_count, get_target_prompt_token_count(token_count) @@ -174,7 +173,8 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): if line in cache: remade_tokens, fixes, multipliers = cache[line] else: - remade_tokens, fixes, multipliers, token_count = self.tokenize_line(line, used_custom_terms, hijack_comments) + remade_tokens, fixes, multipliers, current_token_count = self.tokenize_line(line, used_custom_terms, hijack_comments) + token_count = max(current_token_count, token_count) cache[line] = (remade_tokens, fixes, multipliers) @@ -265,15 +265,19 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): if len(used_custom_terms) > 0: self.hijack.comments.append("Used embeddings: " + ", ".join([f'{word} [{checksum}]' for word, checksum in used_custom_terms])) - position_ids_array = [min(x, 75) for x in range(len(remade_batch_tokens[0])-1)] + [76] + target_token_count = get_target_prompt_token_count(token_count) + 2 + + position_ids_array = [min(x, 75) for x in range(target_token_count-1)] + [76] position_ids = torch.asarray(position_ids_array, device=devices.device).expand((1, -1)) - tokens = torch.asarray(remade_batch_tokens).to(device) + remade_batch_tokens_of_same_length = [x + [self.wrapped.tokenizer.eos_token_id] * (target_token_count - len(x)) for x in remade_batch_tokens] + tokens = torch.asarray(remade_batch_tokens_of_same_length).to(device) outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids) z = outputs.last_hidden_state # restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise - batch_multipliers = torch.asarray(batch_multipliers).to(device) + batch_multipliers_of_same_length = [x + [1.0] * (target_token_count - len(x)) for x in batch_multipliers] + batch_multipliers = torch.asarray(batch_multipliers_of_same_length).to(device) original_mean = z.mean() z *= batch_multipliers.reshape(batch_multipliers.shape + (1,)).expand(z.shape) new_mean = z.mean() diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 13a8b3221..eade0dbbd 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -142,6 +142,16 @@ class VanillaStableDiffusionSampler: assert all([len(conds) == 1 for conds in conds_list]), 'composition via AND is not supported for DDIM/PLMS samplers' cond = tensor + # for DDIM, shapes must match, we can't just process cond and uncond independently; + # filling unconditional_conditioning with repeats of the last vector to match length is + # not 100% correct but should work well enough + if unconditional_conditioning.shape[1] < cond.shape[1]: + last_vector = unconditional_conditioning[:, -1:] + last_vector_repeated = last_vector.repeat([1, cond.shape[1] - unconditional_conditioning.shape[1], 1]) + unconditional_conditioning = torch.hstack([unconditional_conditioning, last_vector_repeated]) + elif unconditional_conditioning.shape[1] > cond.shape[1]: + unconditional_conditioning = unconditional_conditioning[:, :cond.shape[1]] + if self.mask is not None: img_orig = self.sampler.model.q_sample(self.init_latent, ts) x_dec = img_orig * self.mask + self.nmask * x_dec @@ -221,18 +231,29 @@ class CFGDenoiser(torch.nn.Module): x_in = torch.cat([torch.stack([x[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [x]) sigma_in = torch.cat([torch.stack([sigma[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [sigma]) - cond_in = torch.cat([tensor, uncond]) - if shared.batch_cond_uncond: - x_out = self.inner_model(x_in, sigma_in, cond=cond_in) + if tensor.shape[1] == uncond.shape[1]: + cond_in = torch.cat([tensor, uncond]) + + if shared.batch_cond_uncond: + x_out = self.inner_model(x_in, sigma_in, cond=cond_in) + else: + x_out = torch.zeros_like(x_in) + for batch_offset in range(0, x_out.shape[0], batch_size): + a = batch_offset + b = a + batch_size + x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=cond_in[a:b]) else: x_out = torch.zeros_like(x_in) - for batch_offset in range(0, x_out.shape[0], batch_size): + batch_size = batch_size*2 if shared.batch_cond_uncond else batch_size + for batch_offset in range(0, tensor.shape[0], batch_size): a = batch_offset - b = a + batch_size - x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=cond_in[a:b]) + b = min(a + batch_size, tensor.shape[0]) + x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=tensor[a:b]) - denoised_uncond = x_out[-batch_size:] + x_out[-uncond.shape[0]:] = self.inner_model(x_in[-uncond.shape[0]:], sigma_in[-uncond.shape[0]:], cond=uncond) + + denoised_uncond = x_out[-uncond.shape[0]:] denoised = torch.clone(denoised_uncond) for i, conds in enumerate(conds_list): From 7001bffe0247804793dfabb69ac96d832572ccd0 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 15:43:25 +0300 Subject: [PATCH 157/460] fix AND broken for long prompts --- modules/prompt_parser.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index f00256f28..156660736 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -239,6 +239,15 @@ def reconstruct_multicond_batch(c: MulticondLearnedConditioning, current_step): conds_list.append(conds_for_batch) + # if prompts have wildly different lengths above the limit we'll get tensors fo different shapes + # and won't be able to torch.stack them. So this fixes that. + token_count = max([x.shape[0] for x in tensors]) + for i in range(len(tensors)): + if tensors[i].shape[0] != token_count: + last_vector = tensors[i][-1:] + last_vector_repeated = last_vector.repeat([token_count - tensors[i].shape[0], 1]) + tensors[i] = torch.vstack([tensors[i], last_vector_repeated]) + return conds_list, torch.stack(tensors).to(device=param.device, dtype=param.dtype) From 772db721a52da374d627b60994222051f26c27a7 Mon Sep 17 00:00:00 2001 From: ddPn08 Date: Fri, 7 Oct 2022 23:02:07 +0900 Subject: [PATCH 158/460] fix glob path in hypernetwork.py --- modules/hypernetwork.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py index c7b866829..7f0622428 100644 --- a/modules/hypernetwork.py +++ b/modules/hypernetwork.py @@ -43,7 +43,7 @@ class Hypernetwork: def load_hypernetworks(path): res = {} - for filename in glob.iglob(path + '**/*.pt', recursive=True): + for filename in glob.iglob(os.path.join(path, '**/*.pt'), recursive=True): try: hn = Hypernetwork(filename) res[hn.name] = hn From 32e428ff19c28c87bb2ed362316b928b372e3a70 Mon Sep 17 00:00:00 2001 From: guaneec Date: Sat, 8 Oct 2022 16:01:34 +0800 Subject: [PATCH 159/460] Remove duplicate event listeners --- javascript/imageviewer.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js index 3a0baac8c..4c0e8f4bb 100644 --- a/javascript/imageviewer.js +++ b/javascript/imageviewer.js @@ -86,6 +86,9 @@ function showGalleryImage(){ if(fullImg_preview != null){ fullImg_preview.forEach(function function_name(e) { + if (e.dataset.modded) + return; + e.dataset.modded = true; if(e && e.parentElement.tagName == 'DIV'){ e.style.cursor='pointer' From 5f85a74b00c0154bfd559dc67edfa7e30342b7c9 Mon Sep 17 00:00:00 2001 From: MrCheeze Date: Fri, 7 Oct 2022 17:48:34 -0400 Subject: [PATCH 160/460] fix bug where when using prompt composition, hijack_comments generated before the final AND will be dropped --- modules/processing.py | 1 + modules/sd_hijack.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index d5162ddc0..8240ee270 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -313,6 +313,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: os.makedirs(p.outpath_grids, exist_ok=True) modules.sd_hijack.model_hijack.apply_circular(p.tiling) + modules.sd_hijack.model_hijack.clear_comments() comments = {} diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 7e7fde0f9..ba808a397 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -88,6 +88,9 @@ class StableDiffusionModelHijack: for layer in [layer for layer in self.layers if type(layer) == torch.nn.Conv2d]: layer.padding_mode = 'circular' if enable else 'zeros' + def clear_comments(self): + self.comments = [] + def tokenize(self, text): _, remade_batch_tokens, _, _, _, token_count = self.clip.process_text([text]) return remade_batch_tokens[0], token_count, get_target_prompt_token_count(token_count) @@ -260,7 +263,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): batch_multipliers, remade_batch_tokens, used_custom_terms, hijack_comments, hijack_fixes, token_count = self.process_text(text) self.hijack.fixes = hijack_fixes - self.hijack.comments = hijack_comments + self.hijack.comments += hijack_comments if len(used_custom_terms) > 0: self.hijack.comments.append("Used embeddings: " + ", ".join([f'{word} [{checksum}]' for word, checksum in used_custom_terms])) From d0e85873ac72416d32dee8720dc9e93ab3d3e236 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 16:13:26 +0300 Subject: [PATCH 161/460] check for OS and env variable --- launch.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/launch.py b/launch.py index f3fbe16a5..a2089b3bc 100644 --- a/launch.py +++ b/launch.py @@ -4,6 +4,7 @@ import os import sys import importlib.util import shlex +import platform dir_repos = "repositories" dir_tmp = "tmp" @@ -31,6 +32,7 @@ def extract_arg(args, name): args, skip_torch_cuda_test = extract_arg(args, '--skip-torch-cuda-test') +args, xformers = extract_arg(args, '--xformers') def repo_dir(name): @@ -124,8 +126,11 @@ if not is_installed("gfpgan"): if not is_installed("clip"): run_pip(f"install {clip_package}", "clip") -if not is_installed("xformers"): - run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") +if not is_installed("xformers") and xformers: + if platform.system() == "Windows": + run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") + elif: + run_pip("install xformers", "xformers") os.makedirs(dir_repos, exist_ok=True) From 26b459a3799c5cdf71ca8ed5315a99f69c69f02c Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 16:20:04 +0300 Subject: [PATCH 162/460] default to split attention if cuda is available and xformers is not --- modules/sd_hijack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 3da8c8ce2..04adcf035 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -21,12 +21,12 @@ diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.At def apply_optimizations(): ldm.modules.diffusionmodules.model.nonlinearity = silu - if not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip): + if not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip or shared.xformers_available): ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 - elif cmd_opts.opt_split_attention: + elif cmd_opts.opt_split_attention or torch.cuda.is_available(): ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward From ddfa9a97865c732193023a71521c5b7b53d8571b Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 16:20:41 +0300 Subject: [PATCH 163/460] add xformers_available shared variable --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 8cc3b2fe2..6ed4b8021 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -74,7 +74,7 @@ device = devices.device batch_cond_uncond = cmd_opts.always_batch_cond_uncond or not (cmd_opts.lowvram or cmd_opts.medvram) parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram - +xformers_available = False config_filename = cmd_opts.ui_settings_file From 69d0053583757ce2942d62de81e8b89e6be07840 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 16:21:40 +0300 Subject: [PATCH 164/460] update sd_hijack_opt to respect new env variables --- modules/sd_hijack_optimizations.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index ee58c7e4e..be09ec8f4 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -1,9 +1,14 @@ import math import torch from torch import einsum -import xformers.ops -import functorch -xformers._is_functorch_available=True +try: + import xformers.ops + import functorch + xformers._is_functorch_available = True + shared.xformers_available = True +except: + print('Cannot find xformers, defaulting to split attention. Try setting --xformers in your webui-user file if you wish to install it.') + continue from ldm.util import default from einops import rearrange From ca5f0f149c29c344a6badd055b15b5e5fcd6e938 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 16:22:38 +0300 Subject: [PATCH 165/460] Update launch.py --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index a2089b3bc..a592e1ba7 100644 --- a/launch.py +++ b/launch.py @@ -129,7 +129,7 @@ if not is_installed("clip"): if not is_installed("xformers") and xformers: if platform.system() == "Windows": run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") - elif: + elif platform.system() == "Linux": run_pip("install xformers", "xformers") os.makedirs(dir_repos, exist_ok=True) From 7ffea1507813540b8cd9e73feb7bf23de1ac4e27 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 16:24:06 +0300 Subject: [PATCH 166/460] Update requirements_versions.txt --- requirements_versions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements_versions.txt b/requirements_versions.txt index fdff26878..fec3e9d5b 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -22,3 +22,4 @@ resize-right==0.0.2 torchdiffeq==0.2.3 kornia==0.6.7 lark==1.1.2 +functorch==0.2.1 From 970de9ee6891ff586821d0d80dde01c2f6c681b3 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 16:29:43 +0300 Subject: [PATCH 167/460] Update sd_hijack.py --- modules/sd_hijack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 04adcf035..5b30539fe 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -21,7 +21,7 @@ diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.At def apply_optimizations(): ldm.modules.diffusionmodules.model.nonlinearity = silu - if not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip or shared.xformers_available): + if not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip) and shared.xformers_available: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: From 7ff1170a2e11b6f00f587407326db0b9f8f51adf Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 16:33:39 +0300 Subject: [PATCH 168/460] emergency fix for xformers (continue + shared) --- modules/sd_hijack_optimizations.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index e43e2c7a3..05023b6fd 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -1,19 +1,19 @@ import math import torch from torch import einsum -try: - import xformers.ops - import functorch - xformers._is_functorch_available = True - shared.xformers_available = True -except: - print('Cannot find xformers, defaulting to split attention. Try setting --xformers in your webui-user file if you wish to install it.') - continue + from ldm.util import default from einops import rearrange from modules import shared +try: + import xformers.ops + import functorch + xformers._is_functorch_available = True + shared.xformers_available = True +except Exception: + print('Cannot find xformers, defaulting to split attention. Try adding --xformers commandline argument to your webui-user file if you wish to install it.') # see https://github.com/basujindal/stable-diffusion/pull/117 for discussion def split_cross_attention_forward_v1(self, x, context=None, mask=None): From dc1117233ef8f9b25ff1ac40b158f20b70ba2fcb Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 17:02:18 +0300 Subject: [PATCH 169/460] simplify xfrmers options: --xformers to enable and that's it --- launch.py | 2 +- modules/sd_hijack.py | 2 +- modules/sd_hijack_optimizations.py | 20 +++++++++++++------- modules/shared.py | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/launch.py b/launch.py index a592e1ba7..61f62096c 100644 --- a/launch.py +++ b/launch.py @@ -32,7 +32,7 @@ def extract_arg(args, name): args, skip_torch_cuda_test = extract_arg(args, '--skip-torch-cuda-test') -args, xformers = extract_arg(args, '--xformers') +xformers = '--xformers' in args def repo_dir(name): diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 5d93f7f6a..91e98c16b 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -22,7 +22,7 @@ def apply_optimizations(): undo_optimizations() ldm.modules.diffusionmodules.model.nonlinearity = silu - if not cmd_opts.disable_opt_xformers_attention and not (cmd_opts.opt_split_attention or torch.version.hip) and shared.xformers_available: + if cmd_opts.xformers and shared.xformers_available and not torch.version.hip: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 05023b6fd..d23d733b0 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -1,4 +1,7 @@ import math +import sys +import traceback + import torch from torch import einsum @@ -7,13 +10,16 @@ from einops import rearrange from modules import shared -try: - import xformers.ops - import functorch - xformers._is_functorch_available = True - shared.xformers_available = True -except Exception: - print('Cannot find xformers, defaulting to split attention. Try adding --xformers commandline argument to your webui-user file if you wish to install it.') +if shared.cmd_opts.xformers: + try: + import xformers.ops + import functorch + xformers._is_functorch_available = True + shared.xformers_available = True + except Exception: + print("Cannot import xformers", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + # see https://github.com/basujindal/stable-diffusion/pull/117 for discussion def split_cross_attention_forward_v1(self, x, context=None, mask=None): diff --git a/modules/shared.py b/modules/shared.py index d68df7511..02cb27228 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -43,7 +43,7 @@ parser.add_argument("--realesrgan-models-path", type=str, help="Path to director parser.add_argument("--scunet-models-path", type=str, help="Path to directory with ScuNET model file(s).", default=os.path.join(models_path, 'ScuNET')) parser.add_argument("--swinir-models-path", type=str, help="Path to directory with SwinIR model file(s).", default=os.path.join(models_path, 'SwinIR')) parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(models_path, 'LDSR')) -parser.add_argument("--disable-opt-xformers-attention", action='store_true', help="force-disables xformers attention optimization") +parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers") parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") From 27032c47df9c07ac21dd5b89fa7dc247bb8705b6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 17:10:05 +0300 Subject: [PATCH 170/460] restore old opt_split_attention/disable_opt_split_attention logic --- modules/sd_hijack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 91e98c16b..335a2bcfb 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -27,7 +27,7 @@ def apply_optimizations(): ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 - elif cmd_opts.opt_split_attention or torch.cuda.is_available(): + elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward From 4f33289d0fc5aa3a197f4a4c926d03d44f0d597e Mon Sep 17 00:00:00 2001 From: Milly Date: Sat, 8 Oct 2022 22:48:15 +0900 Subject: [PATCH 171/460] Fixed typo --- modules/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index e3e62fdd5..ffd75f6ac 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -946,7 +946,7 @@ def create_ui(wrap_gradio_gpu_call): custom_name = gr.Textbox(label="Custom Name (Optional)") interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation Amount', value=0.3) interp_method = gr.Radio(choices=["Weighted Sum", "Sigmoid", "Inverse Sigmoid"], value="Weighted Sum", label="Interpolation Method") - save_as_half = gr.Checkbox(value=False, label="Safe as float16") + save_as_half = gr.Checkbox(value=False, label="Save as float16") modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary') with gr.Column(variant='panel'): From cfc33f99d47d1f45af15499e5965834089d11858 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 17:28:58 +0300 Subject: [PATCH 172/460] why did you do this --- modules/sd_hijack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 335a2bcfb..ed271976b 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -28,7 +28,7 @@ def apply_optimizations(): elif cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): - ldm.modules.attention_CrossAttention_forward = sd_hijack_optimizations.split_cross_attention_forward + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward From 7e639cd49855ef59e087ae9a9122756a937007eb Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 17:22:20 +0300 Subject: [PATCH 173/460] check for 3.10 --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index 61f62096c..1d65a779c 100644 --- a/launch.py +++ b/launch.py @@ -126,7 +126,7 @@ if not is_installed("gfpgan"): if not is_installed("clip"): run_pip(f"install {clip_package}", "clip") -if not is_installed("xformers") and xformers: +if not is_installed("xformers") and xformers and platform.python_version().startswith("3.10"): if platform.system() == "Windows": run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") elif platform.system() == "Linux": From 017b6b8744f0771e498656ec043e12d5cc6969a7 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 17:27:21 +0300 Subject: [PATCH 174/460] check for ampere --- modules/sd_hijack.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index ed271976b..5e266d5e5 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -22,9 +22,10 @@ def apply_optimizations(): undo_optimizations() ldm.modules.diffusionmodules.model.nonlinearity = silu - if cmd_opts.xformers and shared.xformers_available and not torch.version.hip: - ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward - ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward + if cmd_opts.xformers and shared.xformers_available and torch.version.cuda: + if torch.cuda.get_device_capability(shared.device) == (8, 6): + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward + ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): From cc0258aea7b6605be3648900063cfa96ed7c5ffa Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sat, 8 Oct 2022 17:44:53 +0300 Subject: [PATCH 175/460] check for ampere without destroying the optimizations. again. --- modules/sd_hijack.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 5e266d5e5..a3e374f09 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -22,10 +22,9 @@ def apply_optimizations(): undo_optimizations() ldm.modules.diffusionmodules.model.nonlinearity = silu - if cmd_opts.xformers and shared.xformers_available and torch.version.cuda: - if torch.cuda.get_device_capability(shared.device) == (8, 6): - ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward - ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward + if cmd_opts.xformers and shared.xformers_available and torch.version.cuda and torch.cuda.get_device_capability(shared.device) == (8, 6): + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward + ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): From 34acad1628e98a5e0cbd459fa69ded915864f53d Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Fri, 7 Oct 2022 22:56:00 +0100 Subject: [PATCH 176/460] Add GZipMiddleware to root demo --- webui.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/webui.py b/webui.py index 3b4cf5e9d..18de8e165 100644 --- a/webui.py +++ b/webui.py @@ -5,6 +5,8 @@ import importlib import signal import threading +from fastapi.middleware.gzip import GZipMiddleware + from modules.paths import script_path from modules import devices, sd_samplers @@ -93,7 +95,7 @@ def webui(): demo = modules.ui.create_ui(wrap_gradio_gpu_call=wrap_gradio_gpu_call) - demo.launch( + app,local_url,share_url = demo.launch( share=cmd_opts.share, server_name="0.0.0.0" if cmd_opts.listen else None, server_port=cmd_opts.port, @@ -102,6 +104,8 @@ def webui(): inbrowser=cmd_opts.autolaunch, prevent_thread_lock=True ) + + app.add_middleware(GZipMiddleware,minimum_size=1000) while 1: time.sleep(0.5) From a5550f0213c3f145b1c984816ebcef92c48853ee Mon Sep 17 00:00:00 2001 From: Artem Zagidulin Date: Wed, 5 Oct 2022 19:10:39 +0300 Subject: [PATCH 177/460] alternate prompt --- modules/prompt_parser.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py index 156660736..919d5d31a 100644 --- a/modules/prompt_parser.py +++ b/modules/prompt_parser.py @@ -13,13 +13,14 @@ import lark schedule_parser = lark.Lark(r""" !start: (prompt | /[][():]/+)* -prompt: (emphasized | scheduled | plain | WHITESPACE)* +prompt: (emphasized | scheduled | alternate | plain | WHITESPACE)* !emphasized: "(" prompt ")" | "(" prompt ":" prompt ")" | "[" prompt "]" scheduled: "[" [prompt ":"] prompt ":" [WHITESPACE] NUMBER "]" +alternate: "[" prompt ("|" prompt)+ "]" WHITESPACE: /\s+/ -plain: /([^\\\[\]():]|\\.)+/ +plain: /([^\\\[\]():|]|\\.)+/ %import common.SIGNED_NUMBER -> NUMBER """) @@ -59,6 +60,8 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): tree.children[-1] *= steps tree.children[-1] = min(steps, int(tree.children[-1])) l.append(tree.children[-1]) + def alternate(self, tree): + l.extend(range(1, steps+1)) CollectSteps().visit(tree) return sorted(set(l)) @@ -67,6 +70,8 @@ def get_learned_conditioning_prompt_schedules(prompts, steps): def scheduled(self, args): before, after, _, when = args yield before or () if step <= when else after + def alternate(self, args): + yield next(args[(step - 1)%len(args)]) def start(self, args): def flatten(x): if type(x) == str: From 01f8cb44474e454903c11718e6a4f33dbde34bb8 Mon Sep 17 00:00:00 2001 From: Greendayle Date: Sat, 8 Oct 2022 18:02:56 +0200 Subject: [PATCH 178/460] made deepdanbooru optional, added to readme, automatic download of deepbooru model --- README.md | 2 ++ launch.py | 4 ++++ modules/deepbooru.py | 20 ++++++++++---------- modules/shared.py | 1 + modules/ui.py | 19 ++++++++++++------- requirements.txt | 3 --- requirements_versions.txt | 3 --- 7 files changed, 29 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index ef9b5e313..6cd7a1f9d 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - separate prompts using uppercase `AND` - also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2` - No token limit for prompts (original stable diffusion lets you use up to 75 tokens) +- DeepDanbooru integration, creates danbooru style tags for anime prompts (add --deepdanbooru to commandline args) ## Installation and Running Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. @@ -123,4 +124,5 @@ The documentation was moved from this README over to the project's [wiki](https: - Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot - CLIP interrogator idea and borrowing some code - https://github.com/pharmapsychotic/clip-interrogator - Initial Gradio script - posted on 4chan by an Anonymous user. Thank you Anonymous user. +- DeepDanbooru - interrogator for anime diffusors https://github.com/KichangKim/DeepDanbooru - (You) diff --git a/launch.py b/launch.py index 61f62096c..d46426eb3 100644 --- a/launch.py +++ b/launch.py @@ -33,6 +33,7 @@ def extract_arg(args, name): args, skip_torch_cuda_test = extract_arg(args, '--skip-torch-cuda-test') xformers = '--xformers' in args +deepdanbooru = '--deepdanbooru' in args def repo_dir(name): @@ -132,6 +133,9 @@ if not is_installed("xformers") and xformers: elif platform.system() == "Linux": run_pip("install xformers", "xformers") +if not is_installed("deepdanbooru") and deepdanbooru: + run_pip("install git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] tensorflow==2.10.0 tensorflow-io==0.27.0", "deepdanbooru") + os.makedirs(dir_repos, exist_ok=True) git_clone("https://github.com/CompVis/stable-diffusion.git", repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 781b22492..7e3c06182 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -9,16 +9,16 @@ def _load_tf_and_return_tags(pil_image, threshold): import numpy as np this_folder = os.path.dirname(__file__) - model_path = os.path.join(this_folder, '..', 'models', 'deepbooru', 'deepdanbooru-v3-20211112-sgd-e28') - - model_good = False - for path_candidate in [model_path, os.path.dirname(model_path)]: - if os.path.exists(os.path.join(path_candidate, 'project.json')): - model_path = path_candidate - model_good = True - if not model_good: - return ("Download https://github.com/KichangKim/DeepDanbooru/releases/download/v3-20211112-sgd-e28/" - "deepdanbooru-v3-20211112-sgd-e28.zip unpack and put into models/deepbooru") + model_path = os.path.abspath(os.path.join(this_folder, '..', 'models', 'deepbooru')) + if not os.path.exists(os.path.join(model_path, 'project.json')): + # there is no point importing these every time + import zipfile + from basicsr.utils.download_util import load_file_from_url + load_file_from_url(r"https://github.com/KichangKim/DeepDanbooru/releases/download/v3-20211112-sgd-e28/deepdanbooru-v3-20211112-sgd-e28.zip", + model_path) + with zipfile.ZipFile(os.path.join(model_path, "deepdanbooru-v3-20211112-sgd-e28.zip"), "r") as zip_ref: + zip_ref.extractall(model_path) + os.remove(os.path.join(model_path, "deepdanbooru-v3-20211112-sgd-e28.zip")) tags = dd.project.load_tags_from_project(model_path) model = dd.project.load_model_from_project( diff --git a/modules/shared.py b/modules/shared.py index 02cb27228..c87b726e7 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -44,6 +44,7 @@ parser.add_argument("--scunet-models-path", type=str, help="Path to directory wi parser.add_argument("--swinir-models-path", type=str, help="Path to directory with SwinIR model file(s).", default=os.path.join(models_path, 'SwinIR')) parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(models_path, 'LDSR')) parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers") +parser.add_argument("--deepdanbooru", action='store_true', help="enable deepdanbooru interrogator") parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") diff --git a/modules/ui.py b/modules/ui.py index 30583fe93..c5c11c3c9 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -23,9 +23,10 @@ import gradio.utils import gradio.routes from modules import sd_hijack -from modules.deepbooru import get_deepbooru_tags from modules.paths import script_path from modules.shared import opts, cmd_opts +if cmd_opts.deepdanbooru: + from modules.deepbooru import get_deepbooru_tags import modules.shared as shared from modules.sd_samplers import samplers, samplers_for_img2img from modules.sd_hijack import model_hijack @@ -437,7 +438,10 @@ def create_toprow(is_img2img): with gr.Row(scale=1): if is_img2img: interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate") - deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru") + if cmd_opts.deepdanbooru: + deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru") + else: + deepbooru = None else: interrogate = None deepbooru = None @@ -782,11 +786,12 @@ def create_ui(wrap_gradio_gpu_call): outputs=[img2img_prompt], ) - img2img_deepbooru.click( - fn=interrogate_deepbooru, - inputs=[init_img], - outputs=[img2img_prompt], - ) + if cmd_opts.deepdanbooru: + img2img_deepbooru.click( + fn=interrogate_deepbooru, + inputs=[init_img], + outputs=[img2img_prompt], + ) save.click( fn=wrap_gradio_call(save_files), diff --git a/requirements.txt b/requirements.txt index cd3953c6c..81641d68f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,4 @@ resize-right torchdiffeq kornia lark -deepdanbooru -tensorflow -tensorflow-io functorch diff --git a/requirements_versions.txt b/requirements_versions.txt index 2d256a54f..fec3e9d5b 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -22,7 +22,4 @@ resize-right==0.0.2 torchdiffeq==0.2.3 kornia==0.6.7 lark==1.1.2 -git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] -tensorflow==2.10.0 -tensorflow-io==0.27.0 functorch==0.2.1 From f9c5da159245bb1e7603b3c8b9e0703bcb1c2ff5 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 19:05:19 +0300 Subject: [PATCH 179/460] add fallback for xformers_attnblock_forward --- modules/sd_hijack_optimizations.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index d23d733b0..dba21192b 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -211,6 +211,7 @@ def cross_attention_attnblock_forward(self, x): return h3 def xformers_attnblock_forward(self, x): + try: h_ = x h_ = self.norm(h_) q1 = self.q(h_).contiguous() @@ -218,4 +219,6 @@ def xformers_attnblock_forward(self, x): v = self.v(h_).contiguous() out = xformers.ops.memory_efficient_attention(q1, k1, v) out = self.proj_out(out) - return x+out + return x + out + except NotImplementedError: + return cross_attention_attnblock_forward(self, x) From 3061cdb7b610d4ba7f1ea695d9d6364b591e5bc7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 19:22:15 +0300 Subject: [PATCH 180/460] add --force-enable-xformers option and also add messages to console regarding cross attention optimizations --- modules/sd_hijack.py | 6 +++++- modules/shared.py | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index a3e374f09..307cc67dd 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -22,12 +22,16 @@ def apply_optimizations(): undo_optimizations() ldm.modules.diffusionmodules.model.nonlinearity = silu - if cmd_opts.xformers and shared.xformers_available and torch.version.cuda and torch.cuda.get_device_capability(shared.device) == (8, 6): + + if cmd_opts.force_enable_xformers or (cmd_opts.xformers and shared.xformers_available and torch.version.cuda and torch.cuda.get_device_capability(shared.device) == (8, 6)): + print("Applying xformers cross attention optimization.") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward elif cmd_opts.opt_split_attention_v1: + print("Applying v1 cross attention optimization.") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): + print("Applying cross attention optimization.") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward diff --git a/modules/shared.py b/modules/shared.py index 02cb27228..8f9412262 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -44,6 +44,7 @@ parser.add_argument("--scunet-models-path", type=str, help="Path to directory wi parser.add_argument("--swinir-models-path", type=str, help="Path to directory with SwinIR model file(s).", default=os.path.join(models_path, 'SwinIR')) parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with LDSR model file(s).", default=os.path.join(models_path, 'LDSR')) parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers") +parser.add_argument("--force-enable-xformers", action='store_true', help="enable xformers for cross attention layers regardless of whether the checking code thinks you can run it; do not make bug reports if this fails to work") parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") From 15c4278f1a18b8104e135dd82690d10cff39a2e7 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 8 Oct 2022 17:50:01 +0100 Subject: [PATCH 181/460] TI preprocess wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I had to check the code to work out what splitting was 🤷🏿 --- modules/ui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index ffd75f6ac..d52d74c6d 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -980,9 +980,9 @@ def create_ui(wrap_gradio_gpu_call): process_dst = gr.Textbox(label='Destination directory') with gr.Row(): - process_flip = gr.Checkbox(label='Flip') - process_split = gr.Checkbox(label='Split into two') - process_caption = gr.Checkbox(label='Add caption') + process_flip = gr.Checkbox(label='Create flipped copies') + process_split = gr.Checkbox(label='Split oversized images into two') + process_caption = gr.Checkbox(label='Use CLIP caption as filename') with gr.Row(): with gr.Column(scale=3): From b458fa48fe5734a872bca83061d702609cb52940 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sat, 8 Oct 2022 17:56:28 +0100 Subject: [PATCH 182/460] Update ui.py --- modules/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index d52d74c6d..b09359aae 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -982,7 +982,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Row(): process_flip = gr.Checkbox(label='Create flipped copies') process_split = gr.Checkbox(label='Split oversized images into two') - process_caption = gr.Checkbox(label='Use CLIP caption as filename') + process_caption = gr.Checkbox(label='Use BLIP caption as filename') with gr.Row(): with gr.Column(scale=3): From 1371d7608b402d6f15c200ec2f5fde4579836a05 Mon Sep 17 00:00:00 2001 From: Fampai Date: Sat, 8 Oct 2022 14:28:22 -0400 Subject: [PATCH 183/460] Added ability to ignore last n layers in FrozenCLIPEmbedder --- modules/sd_hijack.py | 11 +++++++++-- modules/shared.py | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 307cc67dd..f12a9696f 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -281,8 +281,15 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): remade_batch_tokens_of_same_length = [x + [self.wrapped.tokenizer.eos_token_id] * (target_token_count - len(x)) for x in remade_batch_tokens] tokens = torch.asarray(remade_batch_tokens_of_same_length).to(device) - outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids) - z = outputs.last_hidden_state + + tmp = -opts.CLIP_ignore_last_layers + if (opts.CLIP_ignore_last_layers == 0): + outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids) + z = outputs.last_hidden_state + else: + outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids, output_hidden_states=tmp) + z = outputs.hidden_states[tmp] + z = self.wrapped.transformer.text_model.final_layer_norm(z) # restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise batch_multipliers_of_same_length = [x + [1.0] * (target_token_count - len(x)) for x in batch_multipliers] diff --git a/modules/shared.py b/modules/shared.py index 8f9412262..af8dc7447 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -225,6 +225,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "use_old_emphasis_implementation": OptionInfo(False, "Use old emphasis implementation. Can be useful to reproduce old seeds."), "enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"), "filter_nsfw": OptionInfo(False, "Filter NSFW content"), + 'CLIP_ignore_last_layers': OptionInfo(0, "Ignore last layers of CLIP model", gr.Slider, {"minimum": 0, "maximum": 5, "step": 1}), "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), })) From e6e42f98df2c928c4f49351ad6b466387ce87d42 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 19:25:10 +0300 Subject: [PATCH 184/460] make --force-enable-xformers work without needing --xformers --- modules/sd_hijack_optimizations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index dba21192b..c4396bb9b 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -10,7 +10,7 @@ from einops import rearrange from modules import shared -if shared.cmd_opts.xformers: +if shared.cmd_opts.xformers or shared.cmd_opts.force_enable_xformers: try: import xformers.ops import functorch From 3b2141c5fb6a3c2b8ab4b1e759a97ead77260129 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 22:21:15 +0300 Subject: [PATCH 185/460] add 'Ignore last layers of CLIP model' option as a parameter to the infotext --- modules/processing.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index 8240ee270..515fc91a3 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -123,6 +123,7 @@ class Processed: self.index_of_first_image = index_of_first_image self.styles = p.styles self.job_timestamp = state.job_timestamp + self.clip_skip = opts.CLIP_ignore_last_layers self.eta = p.eta self.ddim_discretize = p.ddim_discretize @@ -141,7 +142,6 @@ class Processed: self.all_subseeds = all_subseeds or [self.subseed] self.infotexts = infotexts or [info] - def js(self): obj = { "prompt": self.prompt, @@ -170,6 +170,7 @@ class Processed: "infotexts": self.infotexts, "styles": self.styles, "job_timestamp": self.job_timestamp, + "clip_skip": self.clip_skip, } return json.dumps(obj) @@ -267,6 +268,8 @@ def fix_seed(p): def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration=0, position_in_batch=0): index = position_in_batch + iteration * p.batch_size + clip_skip = getattr(p, 'clip_skip', opts.CLIP_ignore_last_layers) + generation_params = { "Steps": p.steps, "Sampler": sd_samplers.samplers[p.sampler_index].name, @@ -282,6 +285,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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), "Eta": (None if p.sampler is None or p.sampler.eta == p.sampler.default_eta else p.sampler.eta), + "Clip skip": None if clip_skip==0 else clip_skip, } generation_params.update(p.extra_generation_params) From 610a7f4e1480c0ffeedb2a07dc27ae86bf03c3a8 Mon Sep 17 00:00:00 2001 From: Edouard Leurent Date: Sat, 8 Oct 2022 16:49:43 +0100 Subject: [PATCH 186/460] Break after finding the local directory of stable diffusion Otherwise, we may override it with one of the next two path (. or ..) if it is present there, and then the local paths of other modules (taming transformers, codeformers, etc.) wont be found in sd_path/../. Fix https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/1085 --- modules/paths.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/paths.py b/modules/paths.py index 606f7d666..0519caa0a 100644 --- a/modules/paths.py +++ b/modules/paths.py @@ -12,6 +12,7 @@ possible_sd_paths = [os.path.join(script_path, 'repositories/stable-diffusion'), for possible_sd_path in possible_sd_paths: if os.path.exists(os.path.join(possible_sd_path, 'ldm/models/diffusion/ddpm.py')): sd_path = os.path.abspath(possible_sd_path) + break assert sd_path is not None, "Couldn't find Stable Diffusion in any of: " + str(possible_sd_paths) From 432782163ae53e605470bcefc9a6f796c4556912 Mon Sep 17 00:00:00 2001 From: Aidan Holland Date: Sat, 8 Oct 2022 15:12:24 -0400 Subject: [PATCH 187/460] chore: Fix typos --- README.md | 2 +- javascript/imageviewer.js | 2 +- modules/interrogate.py | 4 ++-- modules/processing.py | 2 +- modules/scunet_model_arch.py | 4 ++-- modules/sd_models.py | 4 ++-- modules/sd_samplers.py | 4 ++-- modules/shared.py | 6 +++--- modules/swinir_model_arch.py | 2 +- modules/ui.py | 4 ++-- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ef9b5e313..63dd0c187 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - Sampling method selection - Interrupt processing at any time - 4GB video card support (also reports of 2GB working) -- Correct seeds for batches +- Correct seeds for batches - Prompt length validation - get length of prompt in tokens as you type - get a warning after generation if some text was truncated diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js index 4c0e8f4bb..6a00c0da4 100644 --- a/javascript/imageviewer.js +++ b/javascript/imageviewer.js @@ -95,7 +95,7 @@ function showGalleryImage(){ e.addEventListener('click', function (evt) { if(!opts.js_modal_lightbox) return; - modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initialy_zoomed) + modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed) showModal(evt) },true); } diff --git a/modules/interrogate.py b/modules/interrogate.py index eed87144f..635e266e7 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -140,11 +140,11 @@ class InterrogateModels: res = caption - cilp_image = self.clip_preprocess(pil_image).unsqueeze(0).type(self.dtype).to(shared.device) + clip_image = self.clip_preprocess(pil_image).unsqueeze(0).type(self.dtype).to(shared.device) precision_scope = torch.autocast if shared.cmd_opts.precision == "autocast" else contextlib.nullcontext with torch.no_grad(), precision_scope("cuda"): - image_features = self.clip_model.encode_image(cilp_image).type(self.dtype) + image_features = self.clip_model.encode_image(clip_image).type(self.dtype) image_features /= image_features.norm(dim=-1, keepdim=True) diff --git a/modules/processing.py b/modules/processing.py index 515fc91a3..31220881e 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -386,7 +386,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if state.interrupted or state.skipped: - # if we are interruped, sample returns just noise + # if we are interrupted, sample returns just noise # use the image collected previously in sampler loop samples_ddim = shared.state.current_latent diff --git a/modules/scunet_model_arch.py b/modules/scunet_model_arch.py index 972a2639a..43ca8d36f 100644 --- a/modules/scunet_model_arch.py +++ b/modules/scunet_model_arch.py @@ -40,7 +40,7 @@ class WMSA(nn.Module): Returns: attn_mask: should be (1 1 w p p), """ - # supporting sqaure. + # supporting square. attn_mask = torch.zeros(h, w, p, p, p, p, dtype=torch.bool, device=self.relative_position_params.device) if self.type == 'W': return attn_mask @@ -65,7 +65,7 @@ class WMSA(nn.Module): x = rearrange(x, 'b (w1 p1) (w2 p2) c -> b w1 w2 p1 p2 c', p1=self.window_size, p2=self.window_size) h_windows = x.size(1) w_windows = x.size(2) - # sqaure validation + # square validation # assert h_windows == w_windows x = rearrange(x, 'b w1 w2 p1 p2 c -> b (w1 w2) (p1 p2) c', p1=self.window_size, p2=self.window_size) diff --git a/modules/sd_models.py b/modules/sd_models.py index 9409d0707..a09866ce6 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -147,7 +147,7 @@ def load_model_weights(model, checkpoint_file, sd_model_hash): model.first_stage_model.load_state_dict(vae_dict) model.sd_model_hash = sd_model_hash - model.sd_model_checkpint = checkpoint_file + model.sd_model_checkpoint = checkpoint_file def load_model(): @@ -175,7 +175,7 @@ def reload_model_weights(sd_model, info=None): from modules import lowvram, devices, sd_hijack checkpoint_info = info or select_checkpoint() - if sd_model.sd_model_checkpint == checkpoint_info.filename: + if sd_model.sd_model_checkpoint == checkpoint_info.filename: return if shared.cmd_opts.lowvram or shared.cmd_opts.medvram: diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index eade0dbbd..6e743f7e9 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -181,7 +181,7 @@ class VanillaStableDiffusionSampler: self.initialize(p) - # existing code fails with cetain step counts, like 9 + # existing code fails with certain step counts, like 9 try: self.sampler.make_schedule(ddim_num_steps=steps, ddim_eta=self.eta, ddim_discretize=p.ddim_discretize, verbose=False) except Exception: @@ -204,7 +204,7 @@ class VanillaStableDiffusionSampler: steps = steps or p.steps - # existing code fails with cetin step counts, like 9 + # existing code fails with certain step counts, like 9 try: samples_ddim, _ = self.sampler.sample(S=steps, conditioning=conditioning, batch_size=int(x.shape[0]), shape=x[0].shape, verbose=False, unconditional_guidance_scale=p.cfg_scale, unconditional_conditioning=unconditional_conditioning, x_T=x, eta=self.eta) except Exception: diff --git a/modules/shared.py b/modules/shared.py index af8dc7447..2dc092d68 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -141,9 +141,9 @@ class OptionInfo: self.section = None -def options_section(section_identifer, options_dict): +def options_section(section_identifier, options_dict): for k, v in options_dict.items(): - v.section = section_identifer + v.section = section_identifier return options_dict @@ -246,7 +246,7 @@ options_templates.update(options_section(('ui', "User interface"), { "add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"), "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), - "js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), + "js_modal_lightbox_initially_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), "show_progress_in_title": OptionInfo(True, "Show generation progress in window title."), })) diff --git a/modules/swinir_model_arch.py b/modules/swinir_model_arch.py index 461fb354c..863f42db6 100644 --- a/modules/swinir_model_arch.py +++ b/modules/swinir_model_arch.py @@ -166,7 +166,7 @@ class SwinTransformerBlock(nn.Module): Args: dim (int): Number of input channels. - input_resolution (tuple[int]): Input resulotion. + input_resolution (tuple[int]): Input resolution. num_heads (int): Number of attention heads. window_size (int): Window size. shift_size (int): Shift size for SW-MSA. diff --git a/modules/ui.py b/modules/ui.py index b09359aae..b51af1214 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -38,7 +38,7 @@ from modules import prompt_parser from modules.images import save_image import modules.textual_inversion.ui -# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI +# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI mimetypes.init() mimetypes.add_type('application/javascript', '.js') @@ -102,7 +102,7 @@ def save_files(js_data, images, index): import csv filenames = [] - #quick dictionary to class object conversion. Its neccesary due apply_filename_pattern requiring it + #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it class MyObject: def __init__(self, d=None): if d is not None: From 050a6a798cec90ae2f881c2ddd3f0221e69907dc Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 8 Oct 2022 23:26:48 +0300 Subject: [PATCH 188/460] support loading .yaml config with same name as model support EMA weights in processing (????) --- modules/processing.py | 2 +- modules/sd_models.py | 30 +++++++++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 31220881e..4fea6d567 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -347,7 +347,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: infotexts = [] output_images = [] - with torch.no_grad(): + with torch.no_grad(), p.sd_model.ema_scope(): with devices.autocast(): p.init(all_prompts, all_seeds, all_subseeds) diff --git a/modules/sd_models.py b/modules/sd_models.py index a09866ce6..cb3982b16 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -14,7 +14,7 @@ from modules.paths import models_path model_dir = "Stable-diffusion" model_path = os.path.abspath(os.path.join(models_path, model_dir)) -CheckpointInfo = namedtuple("CheckpointInfo", ['filename', 'title', 'hash', 'model_name']) +CheckpointInfo = namedtuple("CheckpointInfo", ['filename', 'title', 'hash', 'model_name', 'config']) checkpoints_list = {} try: @@ -63,14 +63,20 @@ def list_models(): if os.path.exists(cmd_ckpt): h = model_hash(cmd_ckpt) title, short_model_name = modeltitle(cmd_ckpt, h) - checkpoints_list[title] = CheckpointInfo(cmd_ckpt, title, h, short_model_name) + checkpoints_list[title] = CheckpointInfo(cmd_ckpt, title, h, short_model_name, shared.cmd_opts.config) shared.opts.data['sd_model_checkpoint'] = title elif cmd_ckpt is not None and cmd_ckpt != shared.default_sd_model_file: print(f"Checkpoint in --ckpt argument not found (Possible it was moved to {model_path}: {cmd_ckpt}", file=sys.stderr) for filename in model_list: h = model_hash(filename) title, short_model_name = modeltitle(filename, h) - checkpoints_list[title] = CheckpointInfo(filename, title, h, short_model_name) + + basename, _ = os.path.splitext(filename) + config = basename + ".yaml" + if not os.path.exists(config): + config = shared.cmd_opts.config + + checkpoints_list[title] = CheckpointInfo(filename, title, h, short_model_name, config) def get_closet_checkpoint_match(searchString): @@ -116,7 +122,10 @@ def select_checkpoint(): return checkpoint_info -def load_model_weights(model, checkpoint_file, sd_model_hash): +def load_model_weights(model, checkpoint_info): + checkpoint_file = checkpoint_info.filename + sd_model_hash = checkpoint_info.hash + print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}") pl_sd = torch.load(checkpoint_file, map_location="cpu") @@ -148,15 +157,19 @@ def load_model_weights(model, checkpoint_file, sd_model_hash): model.sd_model_hash = sd_model_hash model.sd_model_checkpoint = checkpoint_file + model.sd_checkpoint_info = checkpoint_info def load_model(): from modules import lowvram, sd_hijack checkpoint_info = select_checkpoint() - sd_config = OmegaConf.load(shared.cmd_opts.config) + if checkpoint_info.config != shared.cmd_opts.config: + print(f"Loading config from: {shared.cmd_opts.config}") + + sd_config = OmegaConf.load(checkpoint_info.config) sd_model = instantiate_from_config(sd_config.model) - load_model_weights(sd_model, checkpoint_info.filename, checkpoint_info.hash) + load_model_weights(sd_model, checkpoint_info) if shared.cmd_opts.lowvram or shared.cmd_opts.medvram: lowvram.setup_for_low_vram(sd_model, shared.cmd_opts.medvram) @@ -178,6 +191,9 @@ def reload_model_weights(sd_model, info=None): if sd_model.sd_model_checkpoint == checkpoint_info.filename: return + if sd_model.sd_checkpoint_info.config != checkpoint_info.config: + return load_model() + if shared.cmd_opts.lowvram or shared.cmd_opts.medvram: lowvram.send_everything_to_cpu() else: @@ -185,7 +201,7 @@ def reload_model_weights(sd_model, info=None): sd_hijack.model_hijack.undo_hijack(sd_model) - load_model_weights(sd_model, checkpoint_info.filename, checkpoint_info.hash) + load_model_weights(sd_model, checkpoint_info) sd_hijack.model_hijack.hijack(sd_model) From 5841990b0df04906da7321beef6f7f7902b7d57b Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 05:38:38 +0100 Subject: [PATCH 189/460] Update textual_inversion.py --- .../textual_inversion/textual_inversion.py | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index cd9f34984..f63160208 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -7,6 +7,9 @@ import tqdm import html import datetime +from PIL import Image, PngImagePlugin +import base64 +from io import BytesIO from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset @@ -80,7 +83,15 @@ class EmbeddingDatabase: def process_file(path, filename): name = os.path.splitext(filename)[0] - data = torch.load(path, map_location="cpu") + data = [] + + if filename.upper().endswith('.PNG'): + embed_image = Image.open(path) + if 'sd-embedding' in embed_image.text: + embeddingData = base64.b64decode(embed_image.text['sd-embedding']) + data = torch.load(BytesIO(embeddingData), map_location="cpu") + else: + data = torch.load(path, map_location="cpu") # textual inversion embeddings if 'string_to_param' in data: @@ -156,7 +167,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, create_image_every, save_embedding_every, template_file): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -244,7 +255,15 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, image = processed.images[0] shared.state.current_image = image - image.save(last_saved_image) + + if save_image_with_stored_embedding: + info = PngImagePlugin.PngInfo() + info.add_text("sd-embedding", base64.b64encode(open(last_saved_file,'rb').read())) + image.save(last_saved_image, "PNG", pnginfo=info) + else: + image.save(last_saved_image) + + last_saved_image += f", prompt: {text}" From cd8673bd9b2e59bddefee8d307340d643695fe11 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 05:40:57 +0100 Subject: [PATCH 190/460] add embed embedding to ui --- modules/ui.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index b51af1214..a59832041 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1001,7 +1001,8 @@ def create_ui(wrap_gradio_gpu_call): steps = gr.Number(label='Max steps', value=100000, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) - + save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True) + with gr.Row(): with gr.Column(scale=2): gr.HTML(value="") @@ -1063,6 +1064,7 @@ def create_ui(wrap_gradio_gpu_call): create_image_every, save_embedding_every, template_file, + save_image_with_stored_embedding, ], outputs=[ ti_output, From c77c89cc83c618472ad352cf8a28fde28c3a1377 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 10:23:31 +0300 Subject: [PATCH 191/460] make main model loading and model merger use the same code --- modules/extras.py | 6 +++--- modules/sd_models.py | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 1d9e64e55..ef6e6de7a 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -169,9 +169,9 @@ def run_modelmerger(primary_model_name, secondary_model_name, interp_method, int print(f"Loading {secondary_model_info.filename}...") secondary_model = torch.load(secondary_model_info.filename, map_location='cpu') - - theta_0 = primary_model['state_dict'] - theta_1 = secondary_model['state_dict'] + + theta_0 = sd_models.get_state_dict_from_checkpoint(primary_model) + theta_1 = sd_models.get_state_dict_from_checkpoint(secondary_model) theta_funcs = { "Weighted Sum": weighted_sum, diff --git a/modules/sd_models.py b/modules/sd_models.py index cb3982b16..18fb8c2ed 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -122,6 +122,13 @@ def select_checkpoint(): return checkpoint_info +def get_state_dict_from_checkpoint(pl_sd): + if "state_dict" in pl_sd: + return pl_sd["state_dict"] + + return pl_sd + + def load_model_weights(model, checkpoint_info): checkpoint_file = checkpoint_info.filename sd_model_hash = checkpoint_info.hash @@ -131,11 +138,8 @@ def load_model_weights(model, checkpoint_info): pl_sd = torch.load(checkpoint_file, map_location="cpu") if "global_step" in pl_sd: print(f"Global Step: {pl_sd['global_step']}") - - if "state_dict" in pl_sd: - sd = pl_sd["state_dict"] - else: - sd = pl_sd + + sd = get_state_dict_from_checkpoint(pl_sd) model.load_state_dict(sd, strict=False) From 4e569fd888f8e3c5632a072d51abbb6e4d17abd6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 10:31:47 +0300 Subject: [PATCH 192/460] fixed incorrect message about loading config; thanks anon! --- modules/sd_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 18fb8c2ed..2101b18da 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -169,7 +169,7 @@ def load_model(): checkpoint_info = select_checkpoint() if checkpoint_info.config != shared.cmd_opts.config: - print(f"Loading config from: {shared.cmd_opts.config}") + print(f"Loading config from: {checkpoint_info.config}") sd_config = OmegaConf.load(checkpoint_info.config) sd_model = instantiate_from_config(sd_config.model) From 5ab7e88d9b0bb0125af9f7237242a00a93360ce5 Mon Sep 17 00:00:00 2001 From: aoirusann <82883326+aoirusann@users.noreply.github.com> Date: Sat, 8 Oct 2022 13:09:29 +0800 Subject: [PATCH 193/460] Add `Download` & `Download as zip` --- modules/ui.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index b51af1214..fe7f10a73 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -98,9 +98,10 @@ def send_gradio_gallery_to_image(x): return image_from_url_text(x[0]) -def save_files(js_data, images, index): +def save_files(js_data, images, do_make_zip, index): import csv filenames = [] + fullfns = [] #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it class MyObject: @@ -141,10 +142,22 @@ def save_files(js_data, images, index): filename = os.path.relpath(fullfn, path) filenames.append(filename) + fullfns.append(fullfn) writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]]) - return '', '', plaintext_to_html(f"Saved: {filenames[0]}") + # Make Zip + if do_make_zip: + zip_filepath = os.path.join(path, "images.zip") + + from zipfile import ZipFile + with ZipFile(zip_filepath, "w") as zip_file: + for i in range(len(fullfns)): + with open(fullfns[i], mode="rb") as f: + zip_file.writestr(filenames[i], f.read()) + fullfns.insert(0, zip_filepath) + + return fullfns, '', '', plaintext_to_html(f"Saved: {filenames[0]}") def wrap_gradio_call(func, extra_outputs=None): @@ -521,6 +534,12 @@ def create_ui(wrap_gradio_gpu_call): button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder' open_txt2img_folder = gr.Button(folder_symbol, elem_id=button_id) + with gr.Row(): + do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) + + with gr.Row(): + download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False) + with gr.Group(): html_info = gr.HTML() generation_info = gr.Textbox(visible=False) @@ -570,13 +589,15 @@ def create_ui(wrap_gradio_gpu_call): save.click( fn=wrap_gradio_call(save_files), - _js="(x, y, z) => [x, y, selected_gallery_index()]", + _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]", inputs=[ generation_info, txt2img_gallery, + do_make_zip, html_info, ], outputs=[ + download_files, html_info, html_info, html_info, @@ -701,6 +722,12 @@ def create_ui(wrap_gradio_gpu_call): button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder' open_img2img_folder = gr.Button(folder_symbol, elem_id=button_id) + with gr.Row(): + do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) + + with gr.Row(): + download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False) + with gr.Group(): html_info = gr.HTML() generation_info = gr.Textbox(visible=False) @@ -776,13 +803,15 @@ def create_ui(wrap_gradio_gpu_call): save.click( fn=wrap_gradio_call(save_files), - _js="(x, y, z) => [x, y, selected_gallery_index()]", + _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]", inputs=[ generation_info, img2img_gallery, - html_info + do_make_zip, + html_info, ], outputs=[ + download_files, html_info, html_info, html_info, From 14192c5b207b16b1ec7a4c9c4ea538d1a6811a4d Mon Sep 17 00:00:00 2001 From: aoirusann Date: Sun, 9 Oct 2022 13:01:10 +0800 Subject: [PATCH 194/460] Support `Download` for txt files. --- modules/images.py | 39 +++++++++++++++++++++++++++++++++++++-- modules/ui.py | 5 ++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/modules/images.py b/modules/images.py index 29c5ee249..c0a906762 100644 --- a/modules/images.py +++ b/modules/images.py @@ -349,6 +349,38 @@ def get_next_sequence_number(path, basename): def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None): + '''Save an image. + + Args: + image (`PIL.Image`): + The image to be saved. + path (`str`): + The directory to save the image. Note, the option `save_to_dirs` will make the image to be saved into a sub directory. + basename (`str`): + The base filename which will be applied to `filename pattern`. + seed, prompt, short_filename, + extension (`str`): + Image file extension, default is `png`. + pngsectionname (`str`): + Specify the name of the section which `info` will be saved in. + info (`str` or `PngImagePlugin.iTXt`): + PNG info chunks. + existing_info (`dict`): + Additional PNG info. `existing_info == {pngsectionname: info, ...}` + no_prompt: + TODO I don't know its meaning. + p (`StableDiffusionProcessing`) + forced_filename (`str`): + If specified, `basename` and filename pattern will be ignored. + save_to_dirs (bool): + If true, the image will be saved into a subdirectory of `path`. + + Returns: (fullfn, txt_fullfn) + fullfn (`str`): + The full path of the saved imaged. + txt_fullfn (`str` or None): + If a text file is saved for this image, this will be its full path. Otherwise None. + ''' if short_filename or prompt is None or seed is None: file_decoration = "" elif opts.save_to_dirs: @@ -424,7 +456,10 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i piexif.insert(exif_bytes(), fullfn_without_extension + ".jpg") if opts.save_txt and info is not None: - with open(f"{fullfn_without_extension}.txt", "w", encoding="utf8") as file: + txt_fullfn = f"{fullfn_without_extension}.txt" + with open(txt_fullfn, "w", encoding="utf8") as file: file.write(info + "\n") + else: + txt_fullfn = None - return fullfn + return fullfn, txt_fullfn diff --git a/modules/ui.py b/modules/ui.py index fe7f10a73..debd8873b 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -138,11 +138,14 @@ def save_files(js_data, images, do_make_zip, index): is_grid = image_index < p.index_of_first_image i = 0 if is_grid else (image_index - p.index_of_first_image) - fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) + fullfn, txt_fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) filename = os.path.relpath(fullfn, path) filenames.append(filename) fullfns.append(fullfn) + if txt_fullfn: + filenames.append(os.path.basename(txt_fullfn)) + fullfns.append(txt_fullfn) writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]]) From 122d42687b97ec4df4c2a8c335d2de385cd1f1a1 Mon Sep 17 00:00:00 2001 From: Fampai Date: Sat, 8 Oct 2022 22:37:35 -0400 Subject: [PATCH 195/460] Fix VRAM Issue by only loading in hypernetwork when selected in settings --- modules/hypernetwork.py | 27 +++++++++++++++++---------- modules/sd_hijack_optimizations.py | 6 +++--- modules/shared.py | 7 ++----- webui.py | 3 +++ 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py index 7f0622428..19f1c2270 100644 --- a/modules/hypernetwork.py +++ b/modules/hypernetwork.py @@ -40,27 +40,34 @@ class Hypernetwork: self.layers[size] = (HypernetworkModule(size, sd[0]), HypernetworkModule(size, sd[1])) -def load_hypernetworks(path): +def list_hypernetworks(path): res = {} - for filename in glob.iglob(os.path.join(path, '**/*.pt'), recursive=True): - try: - hn = Hypernetwork(filename) - res[hn.name] = hn - except Exception: - print(f"Error loading hypernetwork {filename}", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - + name = os.path.splitext(os.path.basename(filename))[0] + res[name] = filename return res +def load_hypernetwork(filename): + print(f"Loading hypernetwork {filename}") + path = shared.hypernetworks.get(filename, None) + if (path is not None): + try: + shared.loaded_hypernetwork = Hypernetwork(path) + except Exception: + print(f"Error loading hypernetwork {path}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + else: + shared.loaded_hypernetwork = None + + def attention_CrossAttention_forward(self, x, context=None, mask=None): h = self.heads q = self.to_q(x) context = default(context, x) - hypernetwork = shared.selected_hypernetwork() + hypernetwork = shared.loaded_hypernetwork hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) if hypernetwork_layers is not None: diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index c4396bb9b..634fb4b24 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -28,7 +28,7 @@ def split_cross_attention_forward_v1(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - hypernetwork = shared.selected_hypernetwork() + hypernetwork = shared.loaded_hypernetwork hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) if hypernetwork_layers is not None: @@ -68,7 +68,7 @@ def split_cross_attention_forward(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - hypernetwork = shared.selected_hypernetwork() + hypernetwork = shared.loaded_hypernetwork hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) if hypernetwork_layers is not None: @@ -132,7 +132,7 @@ def xformers_attention_forward(self, x, context=None, mask=None): h = self.heads q_in = self.to_q(x) context = default(context, x) - hypernetwork = shared.selected_hypernetwork() + hypernetwork = shared.loaded_hypernetwork hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) if hypernetwork_layers is not None: k_in = self.to_k(hypernetwork_layers[0](context)) diff --git a/modules/shared.py b/modules/shared.py index b2c76a323..9dce6cb7b 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -79,11 +79,8 @@ parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram xformers_available = False config_filename = cmd_opts.ui_settings_file -hypernetworks = hypernetwork.load_hypernetworks(os.path.join(models_path, 'hypernetworks')) - - -def selected_hypernetwork(): - return hypernetworks.get(opts.sd_hypernetwork, None) +hypernetworks = hypernetwork.list_hypernetworks(os.path.join(models_path, 'hypernetworks')) +loaded_hypernetwork = None class State: diff --git a/webui.py b/webui.py index 18de8e165..270584f77 100644 --- a/webui.py +++ b/webui.py @@ -82,6 +82,9 @@ modules.scripts.load_scripts(os.path.join(script_path, "scripts")) shared.sd_model = modules.sd_models.load_model() shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) +loaded_hypernetwork = modules.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork) +shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) + def webui(): # make the program just exit at ctrl+c without waiting for anything From 03e570886f430f39020e504aba057a95f2e62484 Mon Sep 17 00:00:00 2001 From: frostydad <64224601+Cyberes@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:13:13 -0600 Subject: [PATCH 196/460] Fix incorrect sampler name in output --- modules/processing.py | 9 ++++++++- scripts/xy_grid.py | 16 +++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 4fea6d567..6b8664a07 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -1,3 +1,4 @@ + import json import math import os @@ -46,6 +47,12 @@ def apply_color_correction(correction, image): return image +def get_correct_sampler(p): + if isinstance(p, modules.processing.StableDiffusionProcessingTxt2Img): + return sd_samplers.samplers + elif isinstance(p, modules.processing.StableDiffusionProcessingImg2Img): + return sd_samplers.samplers_for_img2img + class StableDiffusionProcessing: def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt="", styles=None, seed=-1, subseed=-1, subseed_strength=0, seed_resize_from_h=-1, seed_resize_from_w=-1, seed_enable_extras=True, sampler_index=0, batch_size=1, n_iter=1, steps=50, cfg_scale=7.0, width=512, height=512, restore_faces=False, tiling=False, do_not_save_samples=False, do_not_save_grid=False, extra_generation_params=None, overlay_images=None, negative_prompt=None, eta=None): self.sd_model = sd_model @@ -272,7 +279,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration generation_params = { "Steps": p.steps, - "Sampler": sd_samplers.samplers[p.sampler_index].name, + "Sampler": get_correct_sampler(p)[p.sampler_index].name, "CFG scale": p.cfg_scale, "Seed": all_seeds[index], "Face restoration": (opts.face_restoration_model if p.restore_faces else None), diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index c0c364df8..26ae2199d 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -11,7 +11,7 @@ import modules.scripts as scripts import gradio as gr from modules import images -from modules.processing import process_images, Processed +from modules.processing import process_images, Processed, get_correct_sampler from modules.shared import opts, cmd_opts, state import modules.shared as shared import modules.sd_samplers @@ -56,15 +56,17 @@ def apply_order(p, x, xs): p.prompt = prompt_tmp + p.prompt -samplers_dict = {} -for i, sampler in enumerate(modules.sd_samplers.samplers): - samplers_dict[sampler.name.lower()] = i - for alias in sampler.aliases: - samplers_dict[alias.lower()] = i +def build_samplers_dict(p): + samplers_dict = {} + for i, sampler in enumerate(get_correct_sampler(p)): + samplers_dict[sampler.name.lower()] = i + for alias in sampler.aliases: + samplers_dict[alias.lower()] = i + return samplers_dict def apply_sampler(p, x, xs): - sampler_index = samplers_dict.get(x.lower(), None) + sampler_index = build_samplers_dict(p).get(x.lower(), None) if sampler_index is None: raise RuntimeError(f"Unknown sampler: {x}") From ef93acdc731b7a2b3c13651b6de1bce58af989d4 Mon Sep 17 00:00:00 2001 From: frostydad <64224601+Cyberes@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:15:35 -0600 Subject: [PATCH 197/460] remove line break --- modules/processing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index 6b8664a07..7fa1144e6 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -1,4 +1,3 @@ - import json import math import os From 1ffeb42d38d9276dc28918189d32f60d593a162c Mon Sep 17 00:00:00 2001 From: Nicolas Noullet Date: Sun, 9 Oct 2022 00:18:45 +0200 Subject: [PATCH 198/460] Fix typo --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 9dce6cb7b..dffa0094b 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -238,7 +238,7 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"), options_templates.update(options_section(('ui', "User interface"), { "show_progressbar": OptionInfo(True, "Show progressbar"), - "show_progress_every_n_steps": OptionInfo(0, "Show show image creation progress every N sampling steps. Set 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}), + "show_progress_every_n_steps": OptionInfo(0, "Show image creation progress every N sampling steps. Set 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}), "return_grid": OptionInfo(True, "Show grid in results for web"), "do_not_show_images": OptionInfo(False, "Do not show any images in results for web"), "add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"), From e2930f9821c197da94e208b5ae73711002844efc Mon Sep 17 00:00:00 2001 From: Tony Beeman Date: Fri, 7 Oct 2022 17:46:39 -0700 Subject: [PATCH 199/460] Fix for Prompts_from_file showing extra textbox. --- modules/scripts.py | 30 ++++++++++++++++++++++++++---- scripts/prompts_from_file.py | 4 ++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/modules/scripts.py b/modules/scripts.py index 45230f9a1..d8f87927e 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -1,4 +1,5 @@ import os +from pydoc import visiblename import sys import traceback @@ -31,6 +32,15 @@ class Script: def show(self, is_img2img): return True + + # Called when the ui for this script has been shown. + # Useful for hiding some controls, since the scripts module sets visibility to + # everything to true. The parameters will be the parameters returned by the ui method + # The return value should be gradio updates, similar to what you would return + # from a Gradio event handler. + def on_show(self, *args): + return [ui.gr_show(True)] * len(args) + # This is where the additional processing is implemented. The parameters include # self, the model object "p" (a StableDiffusionProcessing class, see # processing.py), and the parameters returned by the ui method. @@ -125,20 +135,32 @@ class ScriptRunner: inputs += controls script.args_to = len(inputs) - def select_script(script_index): + def select_script(*args): + script_index = args[0] + on_show_updates = [] if 0 < script_index <= len(self.scripts): script = self.scripts[script_index-1] args_from = script.args_from args_to = script.args_to + script_args = args[args_from:args_to] + on_show_updates = wrap_call(script.on_show, script.filename, "on_show", *script_args) else: args_from = 0 args_to = 0 - return [ui.gr_show(True if i == 0 else args_from <= i < args_to) for i in range(len(inputs))] + ret = [ ui.gr_show(True)] # always show the dropdown + for i in range(1, len(inputs)): + if (args_from <= i < args_to): + ret.append( on_show_updates[i - args_from] ) + else: + ret.append(ui.gr_show(False)) + return ret + + # return [ui.gr_show(True if (i == 0) else on_show_updates[i - args_from] if args_from <= i < args_to else False) for i in range(len(inputs))] dropdown.change( fn=select_script, - inputs=[dropdown], + inputs=inputs, outputs=inputs ) @@ -198,4 +220,4 @@ def reload_scripts(basedir): load_scripts(basedir) scripts_txt2img = ScriptRunner() - scripts_img2img = ScriptRunner() + scripts_img2img = ScriptRunner() \ No newline at end of file diff --git a/scripts/prompts_from_file.py b/scripts/prompts_from_file.py index 513d9a1c5..110889a66 100644 --- a/scripts/prompts_from_file.py +++ b/scripts/prompts_from_file.py @@ -10,6 +10,7 @@ from modules.processing import Processed, process_images from PIL import Image from modules.shared import opts, cmd_opts, state +g_txt_mode = False class Script(scripts.Script): def title(self): @@ -29,6 +30,9 @@ class Script(scripts.Script): checkbox_txt.change(fn=lambda x: [gr.File.update(visible = not x), gr.TextArea.update(visible = x)], inputs=[checkbox_txt], outputs=[file, prompt_txt]) return [checkbox_txt, file, prompt_txt] + def on_show(self, checkbox_txt, file, prompt_txt): + return [ gr.Checkbox.update(visible = True), gr.File.update(visible = not checkbox_txt), gr.TextArea.update(visible = checkbox_txt) ] + def run(self, p, checkbox_txt, data: bytes, prompt_txt: str): if (checkbox_txt): lines = [x.strip() for x in prompt_txt.splitlines()] From 86cb16886f8f48169cee4658ad0c5e5443beed2a Mon Sep 17 00:00:00 2001 From: Tony Beeman Date: Fri, 7 Oct 2022 23:51:50 -0700 Subject: [PATCH 200/460] Pull Request Code Review Fixes --- modules/scripts.py | 1 - scripts/prompts_from_file.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/modules/scripts.py b/modules/scripts.py index d8f87927e..8dfd4de94 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -1,5 +1,4 @@ import os -from pydoc import visiblename import sys import traceback diff --git a/scripts/prompts_from_file.py b/scripts/prompts_from_file.py index 110889a66..b24f1a806 100644 --- a/scripts/prompts_from_file.py +++ b/scripts/prompts_from_file.py @@ -10,8 +10,6 @@ from modules.processing import Processed, process_images from PIL import Image from modules.shared import opts, cmd_opts, state -g_txt_mode = False - class Script(scripts.Script): def title(self): return "Prompts from file or textbox" From cbf6dad02d04d98e5a2d5e870777ab99b5796b2d Mon Sep 17 00:00:00 2001 From: Tony Beeman Date: Sat, 8 Oct 2022 10:40:30 -0700 Subject: [PATCH 201/460] Handle case where on_show returns the wrong number of arguments --- modules/scripts.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/scripts.py b/modules/scripts.py index 8dfd4de94..7d89979d7 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -143,6 +143,8 @@ class ScriptRunner: args_to = script.args_to script_args = args[args_from:args_to] on_show_updates = wrap_call(script.on_show, script.filename, "on_show", *script_args) + if (len(on_show_updates) != (args_to - args_from)): + print("Error in custom script (" + script.filename + "): on_show() method should return the same number of arguments as ui().", file=sys.stderr) else: args_from = 0 args_to = 0 @@ -150,13 +152,14 @@ class ScriptRunner: ret = [ ui.gr_show(True)] # always show the dropdown for i in range(1, len(inputs)): if (args_from <= i < args_to): - ret.append( on_show_updates[i - args_from] ) + if (i - args_from) < len(on_show_updates): + ret.append( on_show_updates[i - args_from] ) + else: + ret.append(ui.gr_show(True)) else: ret.append(ui.gr_show(False)) return ret - # return [ui.gr_show(True if (i == 0) else on_show_updates[i - args_from] if args_from <= i < args_to else False) for i in range(len(inputs))] - dropdown.change( fn=select_script, inputs=inputs, From ab4fe4f44c3d2675a351269fe2ff1ddeac557aa6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 11:59:41 +0300 Subject: [PATCH 202/460] hide filenames for save button by default --- modules/ui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 8071b1cb6..e1ab26658 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -162,7 +162,7 @@ def save_files(js_data, images, do_make_zip, index): zip_file.writestr(filenames[i], f.read()) fullfns.insert(0, zip_filepath) - return fullfns, '', '', plaintext_to_html(f"Saved: {filenames[0]}") + return gr.File.update(value=fullfns, visible=True), '', '', plaintext_to_html(f"Saved: {filenames[0]}") def wrap_gradio_call(func, extra_outputs=None): @@ -553,7 +553,7 @@ def create_ui(wrap_gradio_gpu_call): do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) with gr.Row(): - download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False) + download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) with gr.Group(): html_info = gr.HTML() @@ -741,7 +741,7 @@ def create_ui(wrap_gradio_gpu_call): do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) with gr.Row(): - download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False) + download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) with gr.Group(): html_info = gr.HTML() From 0241d811d23427b99f6b1eda1540bdf8d87963d5 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 12:04:44 +0300 Subject: [PATCH 203/460] Revert "Fix for Prompts_from_file showing extra textbox." This reverts commit e2930f9821c197da94e208b5ae73711002844efc. --- modules/scripts.py | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/modules/scripts.py b/modules/scripts.py index 7d89979d7..45230f9a1 100644 --- a/modules/scripts.py +++ b/modules/scripts.py @@ -31,15 +31,6 @@ class Script: def show(self, is_img2img): return True - - # Called when the ui for this script has been shown. - # Useful for hiding some controls, since the scripts module sets visibility to - # everything to true. The parameters will be the parameters returned by the ui method - # The return value should be gradio updates, similar to what you would return - # from a Gradio event handler. - def on_show(self, *args): - return [ui.gr_show(True)] * len(args) - # This is where the additional processing is implemented. The parameters include # self, the model object "p" (a StableDiffusionProcessing class, see # processing.py), and the parameters returned by the ui method. @@ -134,35 +125,20 @@ class ScriptRunner: inputs += controls script.args_to = len(inputs) - def select_script(*args): - script_index = args[0] - on_show_updates = [] + def select_script(script_index): if 0 < script_index <= len(self.scripts): script = self.scripts[script_index-1] args_from = script.args_from args_to = script.args_to - script_args = args[args_from:args_to] - on_show_updates = wrap_call(script.on_show, script.filename, "on_show", *script_args) - if (len(on_show_updates) != (args_to - args_from)): - print("Error in custom script (" + script.filename + "): on_show() method should return the same number of arguments as ui().", file=sys.stderr) else: args_from = 0 args_to = 0 - ret = [ ui.gr_show(True)] # always show the dropdown - for i in range(1, len(inputs)): - if (args_from <= i < args_to): - if (i - args_from) < len(on_show_updates): - ret.append( on_show_updates[i - args_from] ) - else: - ret.append(ui.gr_show(True)) - else: - ret.append(ui.gr_show(False)) - return ret + return [ui.gr_show(True if i == 0 else args_from <= i < args_to) for i in range(len(inputs))] dropdown.change( fn=select_script, - inputs=inputs, + inputs=[dropdown], outputs=inputs ) @@ -222,4 +198,4 @@ def reload_scripts(basedir): load_scripts(basedir) scripts_txt2img = ScriptRunner() - scripts_img2img = ScriptRunner() \ No newline at end of file + scripts_img2img = ScriptRunner() From 6f6798ddabe10d320fe8ea05edf0fdcef0c51a8e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 12:33:37 +0300 Subject: [PATCH 204/460] prevent a possible code execution error (thanks, RyotaK) --- modules/ui.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/ui.py b/modules/ui.py index e1ab26658..dad509f3a 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1153,6 +1153,15 @@ def create_ui(wrap_gradio_gpu_call): component_dict = {} def open_folder(f): + if not os.path.isdir(f): + print(f""" +WARNING +An open_folder request was made with an argument that is not a folder. +This could be an error or a malicious attempt to run code on your computer. +Requested path was: {f} +""", file=sys.stderr) + return + if not shared.cmd_opts.hide_ui_dir_config: path = os.path.normpath(f) if platform.system() == "Windows": From d74c38108f95e44d83a1706ee5ab218124972868 Mon Sep 17 00:00:00 2001 From: Jesse Williams <33797815+xram64@users.noreply.github.com> Date: Sat, 8 Oct 2022 01:30:49 -0400 Subject: [PATCH 205/460] Confirm that options are valid before starting When using the 'Sampler' or 'Checkpoint' options, if one of the entered names has a typo, an error will only be thrown once the `draw_xy_grid` loop reaches that name. This can waste a lot of time for large grids with a typo near the end of a list, since the script needs to start over and re-generate any earlier images to finish making the grid. Also fixing typo in variable name in `draw_xy_grid`. --- scripts/xy_grid.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 26ae2199d..07040886a 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -145,7 +145,7 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend): ver_texts = [[images.GridAnnotation(y)] for y in y_labels] hor_texts = [[images.GridAnnotation(x)] for x in x_labels] - first_pocessed = None + first_processed = None state.job_count = len(xs) * len(ys) * p.n_iter @@ -154,8 +154,8 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend): state.job = f"{ix + iy * len(xs) + 1} out of {len(xs) * len(ys)}" processed = cell(x, y) - if first_pocessed is None: - first_pocessed = processed + if first_processed is None: + first_processed = processed try: res.append(processed.images[0]) @@ -166,9 +166,9 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend): if draw_legend: grid = images.draw_grid_annotations(grid, res[0].width, res[0].height, hor_texts, ver_texts) - first_pocessed.images = [grid] + first_processed.images = [grid] - return first_pocessed + return first_processed re_range = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\(([+-]\d+)\s*\))?\s*") @@ -216,7 +216,6 @@ class Script(scripts.Script): m = re_range.fullmatch(val) mc = re_range_count.fullmatch(val) if m is not None: - start = int(m.group(1)) end = int(m.group(2))+1 step = int(m.group(3)) if m.group(3) is not None else 1 @@ -258,6 +257,16 @@ class Script(scripts.Script): valslist = list(permutations(valslist)) valslist = [opt.type(x) for x in valslist] + + # Confirm options are valid before starting + if opt.label == "Sampler": + for sampler_val in valslist: + if sampler_val.lower() not in samplers_dict.keys(): + raise RuntimeError(f"Unknown sampler: {sampler_val}") + elif opt.label == "Checkpoint name": + for ckpt_val in valslist: + if modules.sd_models.get_closet_checkpoint_match(ckpt_val) is None: + raise RuntimeError(f"Checkpoint for {ckpt_val} not found") return valslist From a65a45272e8f26ee3bc52a5300b396266508a9a5 Mon Sep 17 00:00:00 2001 From: Brendan Byrd Date: Thu, 6 Oct 2022 19:31:36 -0400 Subject: [PATCH 206/460] Don't change the seed initially if "Keep -1 for seeds" is checked Fixes #1049 --- scripts/xy_grid.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 07040886a..a8f53befe 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -198,7 +198,9 @@ class Script(scripts.Script): return [x_type, x_values, y_type, y_values, draw_legend, no_fixed_seeds] def run(self, p, x_type, x_values, y_type, y_values, draw_legend, no_fixed_seeds): - modules.processing.fix_seed(p) + if not no_fixed_seeds: + modules.processing.fix_seed(p) + p.batch_size = 1 initial_hn = opts.sd_hypernetwork From 0609ce06c0778536cb368ac3867292f87c6d9fc7 Mon Sep 17 00:00:00 2001 From: Milly Date: Fri, 7 Oct 2022 03:36:08 +0900 Subject: [PATCH 207/460] Removed duplicate definition model_path --- modules/bsrgan_model.py | 2 -- modules/esrgan_model.py | 2 -- modules/ldsr_model.py | 2 -- modules/realesrgan_model.py | 2 -- modules/scunet_model.py | 2 -- modules/swinir_model.py | 2 -- modules/upscaler.py | 7 ++++--- 7 files changed, 4 insertions(+), 15 deletions(-) diff --git a/modules/bsrgan_model.py b/modules/bsrgan_model.py index 3bd80791a..737e1a761 100644 --- a/modules/bsrgan_model.py +++ b/modules/bsrgan_model.py @@ -10,13 +10,11 @@ from basicsr.utils.download_util import load_file_from_url import modules.upscaler from modules import devices, modelloader from modules.bsrgan_model_arch import RRDBNet -from modules.paths import models_path class UpscalerBSRGAN(modules.upscaler.Upscaler): def __init__(self, dirname): self.name = "BSRGAN" - self.model_path = os.path.join(models_path, self.name) self.model_name = "BSRGAN 4x" self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/BSRGAN.pth" self.user_path = dirname diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py index 285481242..3970e6e47 100644 --- a/modules/esrgan_model.py +++ b/modules/esrgan_model.py @@ -7,7 +7,6 @@ from basicsr.utils.download_util import load_file_from_url import modules.esrgam_model_arch as arch from modules import shared, modelloader, images, devices -from modules.paths import models_path from modules.upscaler import Upscaler, UpscalerData from modules.shared import opts @@ -76,7 +75,6 @@ class UpscalerESRGAN(Upscaler): self.model_name = "ESRGAN_4x" self.scalers = [] self.user_path = dirname - self.model_path = os.path.join(models_path, self.name) super().__init__() model_paths = self.find_models(ext_filter=[".pt", ".pth"]) scalers = [] diff --git a/modules/ldsr_model.py b/modules/ldsr_model.py index 1c1070fc6..8c4db44ad 100644 --- a/modules/ldsr_model.py +++ b/modules/ldsr_model.py @@ -7,13 +7,11 @@ from basicsr.utils.download_util import load_file_from_url from modules.upscaler import Upscaler, UpscalerData from modules.ldsr_model_arch import LDSR from modules import shared -from modules.paths import models_path class UpscalerLDSR(Upscaler): def __init__(self, user_path): self.name = "LDSR" - self.model_path = os.path.join(models_path, self.name) self.user_path = user_path self.model_url = "https://heibox.uni-heidelberg.de/f/578df07c8fc04ffbadf3/?dl=1" self.yaml_url = "https://heibox.uni-heidelberg.de/f/31a76b13ea27482981b4/?dl=1" diff --git a/modules/realesrgan_model.py b/modules/realesrgan_model.py index dc0123e02..3ac0b97ae 100644 --- a/modules/realesrgan_model.py +++ b/modules/realesrgan_model.py @@ -8,14 +8,12 @@ from basicsr.utils.download_util import load_file_from_url from realesrgan import RealESRGANer from modules.upscaler import Upscaler, UpscalerData -from modules.paths import models_path from modules.shared import cmd_opts, opts class UpscalerRealESRGAN(Upscaler): def __init__(self, path): self.name = "RealESRGAN" - self.model_path = os.path.join(models_path, self.name) self.user_path = path super().__init__() try: diff --git a/modules/scunet_model.py b/modules/scunet_model.py index fb64b7409..36a996bf0 100644 --- a/modules/scunet_model.py +++ b/modules/scunet_model.py @@ -9,14 +9,12 @@ from basicsr.utils.download_util import load_file_from_url import modules.upscaler from modules import devices, modelloader -from modules.paths import models_path from modules.scunet_model_arch import SCUNet as net class UpscalerScuNET(modules.upscaler.Upscaler): def __init__(self, dirname): self.name = "ScuNET" - self.model_path = os.path.join(models_path, self.name) self.model_name = "ScuNET GAN" self.model_name2 = "ScuNET PSNR" self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/scunet_color_real_gan.pth" diff --git a/modules/swinir_model.py b/modules/swinir_model.py index 9bd454c69..fbd11f843 100644 --- a/modules/swinir_model.py +++ b/modules/swinir_model.py @@ -8,7 +8,6 @@ from basicsr.utils.download_util import load_file_from_url from tqdm import tqdm from modules import modelloader -from modules.paths import models_path from modules.shared import cmd_opts, opts, device from modules.swinir_model_arch import SwinIR as net from modules.upscaler import Upscaler, UpscalerData @@ -25,7 +24,6 @@ class UpscalerSwinIR(Upscaler): "/003_realSR_BSRGAN_DFOWMFC_s64w8_SwinIR" \ "-L_x4_GAN.pth " self.model_name = "SwinIR 4x" - self.model_path = os.path.join(models_path, self.name) self.user_path = dirname super().__init__() scalers = [] diff --git a/modules/upscaler.py b/modules/upscaler.py index d9d7c5e2a..34672be70 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -36,10 +36,11 @@ class Upscaler: self.half = not modules.shared.cmd_opts.no_half self.pre_pad = 0 self.mod_scale = None - if self.name is not None and create_dirs: + + if self.model_path is not None and self.name: self.model_path = os.path.join(models_path, self.name) - if not os.path.exists(self.model_path): - os.makedirs(self.model_path) + if self.model_path and create_dirs: + os.makedirs(self.model_path, exist_ok=True) try: import cv2 From bd833409ac7b8337040d521f6b65ced51e1b2ea8 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 13:10:15 +0300 Subject: [PATCH 208/460] additional changes for saving pnginfo for #1803 --- modules/extras.py | 4 ++++ modules/processing.py | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index ef6e6de7a..39dd38060 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -98,6 +98,10 @@ def run_extras(extras_mode, image, image_folder, gfpgan_visibility, codeformer_v no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=existing_pnginfo, forced_filename=image_name if opts.use_original_name_batch else None) + if opts.enable_pnginfo: + image.info = existing_pnginfo + image.info["extras"] = info + outputs.append(image) devices.torch_gc() diff --git a/modules/processing.py b/modules/processing.py index 7fa1144e6..2c9913170 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -451,7 +451,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: text = infotext(n, i) infotexts.append(text) - image.info["parameters"] = text + if opts.enable_pnginfo: + image.info["parameters"] = text output_images.append(image) del x_samples_ddim @@ -470,7 +471,8 @@ def process_images(p: StableDiffusionProcessing) -> Processed: if opts.return_grid: text = infotext() infotexts.insert(0, text) - grid.info["parameters"] = text + if opts.enable_pnginfo: + grid.info["parameters"] = text output_images.insert(0, grid) index_of_first_image = 1 From f4578b343ded3b8ccd1879ea0c0b3cdadfcc3a5f Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 13:23:30 +0300 Subject: [PATCH 209/460] fix model switching not working properly if there is a different yaml config --- modules/sd_models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 2101b18da..d0c74dd84 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -196,7 +196,8 @@ def reload_model_weights(sd_model, info=None): return if sd_model.sd_checkpoint_info.config != checkpoint_info.config: - return load_model() + shared.sd_model = load_model() + return shared.sd_model if shared.cmd_opts.lowvram or shared.cmd_opts.medvram: lowvram.send_everything_to_cpu() From 77a719648db515f10136e8b8483d5b16bda2eaeb Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 13:48:04 +0300 Subject: [PATCH 210/460] fix logic error in #1832 --- modules/upscaler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/upscaler.py b/modules/upscaler.py index 34672be70..6ab2fb408 100644 --- a/modules/upscaler.py +++ b/modules/upscaler.py @@ -37,7 +37,7 @@ class Upscaler: self.pre_pad = 0 self.mod_scale = None - if self.model_path is not None and self.name: + if self.model_path is None and self.name: self.model_path = os.path.join(models_path, self.name) if self.model_path and create_dirs: os.makedirs(self.model_path, exist_ok=True) From 542a3d3a4a00c1383fbdaf938ceefef87cf834bb Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 14:33:22 +0300 Subject: [PATCH 211/460] fix btoken hypernetworks in XY plot --- modules/hypernetwork.py | 7 +++++-- scripts/xy_grid.py | 9 +++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py index 19f1c2270..498bc9d8f 100644 --- a/modules/hypernetwork.py +++ b/modules/hypernetwork.py @@ -49,15 +49,18 @@ def list_hypernetworks(path): def load_hypernetwork(filename): - print(f"Loading hypernetwork {filename}") path = shared.hypernetworks.get(filename, None) - if (path is not None): + if path is not None: + print(f"Loading hypernetwork {filename}") try: shared.loaded_hypernetwork = Hypernetwork(path) except Exception: print(f"Error loading hypernetwork {path}", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) else: + if shared.loaded_hypernetwork is not None: + print(f"Unloading hypernetwork") + shared.loaded_hypernetwork = None diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index a8f53befe..fe9490673 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -10,7 +10,7 @@ import numpy as np import modules.scripts as scripts import gradio as gr -from modules import images +from modules import images, hypernetwork from modules.processing import process_images, Processed, get_correct_sampler from modules.shared import opts, cmd_opts, state import modules.shared as shared @@ -80,8 +80,7 @@ def apply_checkpoint(p, x, xs): def apply_hypernetwork(p, x, xs): - hn = shared.hypernetworks.get(x, None) - opts.data["sd_hypernetwork"] = hn.name if hn is not None else 'None' + hypernetwork.load_hypernetwork(x) def format_value_add_label(p, opt, x): @@ -203,8 +202,6 @@ class Script(scripts.Script): p.batch_size = 1 - initial_hn = opts.sd_hypernetwork - def process_axis(opt, vals): if opt.label == 'Nothing': return [0] @@ -321,6 +318,6 @@ class Script(scripts.Script): # restore checkpoint in case it was changed by axes modules.sd_models.reload_model_weights(shared.sd_model) - opts.data["sd_hypernetwork"] = initial_hn + hypernetwork.load_hypernetwork(opts.sd_hypernetwork) return processed From d6d10a37bfd21568e74efb46137f906da96d5fdb Mon Sep 17 00:00:00 2001 From: William Moorehouse Date: Sun, 9 Oct 2022 04:58:40 -0400 Subject: [PATCH 212/460] Added extended model details to infotext --- modules/processing.py | 3 +++ modules/sd_models.py | 3 ++- modules/shared.py | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index 2c9913170..d1bcee4aa 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -284,6 +284,9 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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_extended_model_details_to_info or not shared.sd_model.sd_model_name else shared.sd_model.sd_model_name), + "Model VAE": (None if not opts.add_extended_model_details_to_info or not shared.sd_model.sd_model_vae_name else shared.sd_model.sd_model_vae_name), + "Model hypernetwork": (None if not opts.add_extended_model_details_to_info or not opts.sd_hypernetwork else opts.sd_hypernetwork), "Batch size": (None if p.batch_size < 2 else p.batch_size), "Batch pos": (None if p.batch_size < 2 else position_in_batch), "Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]), diff --git a/modules/sd_models.py b/modules/sd_models.py index d0c74dd84..3fa42329c 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -4,7 +4,7 @@ import sys from collections import namedtuple import torch from omegaconf import OmegaConf - +from pathlib import Path from ldm.util import instantiate_from_config @@ -158,6 +158,7 @@ def load_model_weights(model, checkpoint_info): vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} model.first_stage_model.load_state_dict(vae_dict) + model.sd_model_vae_name = Path(vae_file).stem model.sd_model_hash = sd_model_hash model.sd_model_checkpoint = checkpoint_file diff --git a/modules/shared.py b/modules/shared.py index dffa0094b..ca63f7d8e 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -242,6 +242,7 @@ options_templates.update(options_section(('ui', "User interface"), { "return_grid": OptionInfo(True, "Show grid in results for web"), "do_not_show_images": OptionInfo(False, "Do not show any images in results for web"), "add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"), + "add_extended_model_details_to_info": OptionInfo(False, "Add extended model details to generation information (model name, VAE, hypernetwork)"), "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), "js_modal_lightbox_initially_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), From 006791c13d70e582eee766b7d0499e9821a86bf9 Mon Sep 17 00:00:00 2001 From: William Moorehouse Date: Sun, 9 Oct 2022 05:09:18 -0400 Subject: [PATCH 213/460] Fix grabbing the model name for infotext --- modules/processing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index d1bcee4aa..c035c9902 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -284,7 +284,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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_extended_model_details_to_info or not shared.sd_model.sd_model_name else shared.sd_model.sd_model_name), + "Model": (None if not opts.add_extended_model_details_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name), "Model VAE": (None if not opts.add_extended_model_details_to_info or not shared.sd_model.sd_model_vae_name else shared.sd_model.sd_model_vae_name), "Model hypernetwork": (None if not opts.add_extended_model_details_to_info or not opts.sd_hypernetwork else opts.sd_hypernetwork), "Batch size": (None if p.batch_size < 2 else p.batch_size), From 594cbfd8fbe4078b43ceccf01509eeef3d6790c6 Mon Sep 17 00:00:00 2001 From: William Moorehouse Date: Sun, 9 Oct 2022 07:27:11 -0400 Subject: [PATCH 214/460] Sanitize infotext output (for now) --- modules/processing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index c035c9902..049f37698 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -284,9 +284,9 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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_extended_model_details_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name), - "Model VAE": (None if not opts.add_extended_model_details_to_info or not shared.sd_model.sd_model_vae_name else shared.sd_model.sd_model_vae_name), - "Model hypernetwork": (None if not opts.add_extended_model_details_to_info or not opts.sd_hypernetwork else opts.sd_hypernetwork), + "Model": (None if not opts.add_extended_model_details_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')), + "Model VAE": (None if not opts.add_extended_model_details_to_info or not shared.sd_model.sd_model_vae_name else shared.sd_model.sd_model_vae_name.replace(',', '').replace(':', '')), + "Model hypernetwork": (None if not opts.add_extended_model_details_to_info or not opts.sd_hypernetwork else opts.sd_hypernetwork.replace(',', '').replace(':', '')), "Batch size": (None if p.batch_size < 2 else p.batch_size), "Batch pos": (None if p.batch_size < 2 else position_in_batch), "Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]), From e6e8cabe0c9c335e0d72345602c069b198558b53 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 14:57:48 +0300 Subject: [PATCH 215/460] change up #2056 to make it work how i want it to plus make xy plot write correct values to images --- modules/processing.py | 5 ++--- modules/sd_models.py | 2 -- modules/shared.py | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 049f37698..04aed989d 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -284,9 +284,8 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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_extended_model_details_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')), - "Model VAE": (None if not opts.add_extended_model_details_to_info or not shared.sd_model.sd_model_vae_name else shared.sd_model.sd_model_vae_name.replace(',', '').replace(':', '')), - "Model hypernetwork": (None if not opts.add_extended_model_details_to_info or not opts.sd_hypernetwork else opts.sd_hypernetwork.replace(',', '').replace(':', '')), + "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(':', '')), + "Hypernet": (None if shared.loaded_hypernetwork is None else shared.loaded_hypernetwork.name.replace(',', '').replace(':', '')), "Batch size": (None if p.batch_size < 2 else p.batch_size), "Batch pos": (None if p.batch_size < 2 else position_in_batch), "Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]), diff --git a/modules/sd_models.py b/modules/sd_models.py index 3fa42329c..e63d3c292 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -4,7 +4,6 @@ import sys from collections import namedtuple import torch from omegaconf import OmegaConf -from pathlib import Path from ldm.util import instantiate_from_config @@ -158,7 +157,6 @@ def load_model_weights(model, checkpoint_info): vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} model.first_stage_model.load_state_dict(vae_dict) - model.sd_model_vae_name = Path(vae_file).stem model.sd_model_hash = sd_model_hash model.sd_model_checkpoint = checkpoint_file diff --git a/modules/shared.py b/modules/shared.py index ca63f7d8e..6ecc2503a 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -242,7 +242,7 @@ options_templates.update(options_section(('ui', "User interface"), { "return_grid": OptionInfo(True, "Show grid in results for web"), "do_not_show_images": OptionInfo(False, "Do not show any images in results for web"), "add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"), - "add_extended_model_details_to_info": OptionInfo(False, "Add extended model details to generation information (model name, VAE, hypernetwork)"), + "add_model_name_to_info": OptionInfo(False, "Add model name to generation information"), "font": OptionInfo("", "Font for image grids that have text"), "js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"), "js_modal_lightbox_initially_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"), From 2c52f4da7ff80a3ec277105f4db6146c6379898a Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 15:01:42 +0300 Subject: [PATCH 216/460] fix broken samplers in XY plot --- scripts/xy_grid.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index fe9490673..c89ca1a9b 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -259,6 +259,7 @@ class Script(scripts.Script): # Confirm options are valid before starting if opt.label == "Sampler": + samplers_dict = build_samplers_dict(p) for sampler_val in valslist: if sampler_val.lower() not in samplers_dict.keys(): raise RuntimeError(f"Unknown sampler: {sampler_val}") From 9d1138e2940c4ddcd2685bcba12c7d407e9e0ec5 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 15:08:10 +0300 Subject: [PATCH 217/460] fix typo in filename for ESRGAN arch --- modules/esrgan_model.py | 2 +- modules/{esrgam_model_arch.py => esrgan_model_arch.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename modules/{esrgam_model_arch.py => esrgan_model_arch.py} (100%) diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py index 3970e6e47..46ad0da3c 100644 --- a/modules/esrgan_model.py +++ b/modules/esrgan_model.py @@ -5,7 +5,7 @@ import torch from PIL import Image from basicsr.utils.download_util import load_file_from_url -import modules.esrgam_model_arch as arch +import modules.esrgan_model_arch as arch from modules import shared, modelloader, images, devices from modules.upscaler import Upscaler, UpscalerData from modules.shared import opts diff --git a/modules/esrgam_model_arch.py b/modules/esrgan_model_arch.py similarity index 100% rename from modules/esrgam_model_arch.py rename to modules/esrgan_model_arch.py From f8197976ef5f0523faffb2b237e9166fb2bedecd Mon Sep 17 00:00:00 2001 From: Greendayle Date: Sun, 9 Oct 2022 13:44:13 +0200 Subject: [PATCH 218/460] Shielded launch enviroment creation stuff from multiprocessing --- launch.py | 178 ++++++++++++++++++++++++++---------------------------- 1 file changed, 87 insertions(+), 91 deletions(-) diff --git a/launch.py b/launch.py index b0a59b6a1..d1a4fd6ae 100644 --- a/launch.py +++ b/launch.py @@ -6,40 +6,11 @@ import importlib.util import shlex import platform -dir_repos = "repositories" -dir_tmp = "tmp" - -python = sys.executable -git = os.environ.get('GIT', "git") -torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113") -requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") -commandline_args = os.environ.get('COMMANDLINE_ARGS', "") - -gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379") -clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1") - -stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc") -taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6") -k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "f4e99857772fc3a126ba886aadf795a332774878") -codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af") -blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9") - -args = shlex.split(commandline_args) - def extract_arg(args, name): return [x for x in args if x != name], name in args -args, skip_torch_cuda_test = extract_arg(args, '--skip-torch-cuda-test') -xformers = '--xformers' in args -deepdanbooru = '--deepdanbooru' in args - - -def repo_dir(name): - return os.path.join(dir_repos, name) - - def run(command, desc=None, errdesc=None): if desc is not None: print(desc) @@ -59,23 +30,11 @@ stderr: {result.stderr.decode(encoding="utf8", errors="ignore") if len(result.st return result.stdout.decode(encoding="utf8", errors="ignore") -def run_python(code, desc=None, errdesc=None): - return run(f'"{python}" -c "{code}"', desc, errdesc) - - -def run_pip(args, desc=None): - return run(f'"{python}" -m pip {args} --prefer-binary', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") - - def check_run(command): result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) return result.returncode == 0 -def check_run_python(code): - return check_run(f'"{python}" -c "{code}"') - - def is_installed(package): try: spec = importlib.util.find_spec(package) @@ -85,80 +44,117 @@ def is_installed(package): return spec is not None -def git_clone(url, dir, name, commithash=None): - # TODO clone into temporary dir and move if successful +def prepare_enviroment(): + dir_repos = "repositories" - if os.path.exists(dir): - if commithash is None: + python = sys.executable + git = os.environ.get('GIT', "git") + torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113") + requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") + commandline_args = os.environ.get('COMMANDLINE_ARGS', "") + + gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379") + clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1") + + stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc") + taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6") + k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "f4e99857772fc3a126ba886aadf795a332774878") + codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af") + blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9") + + args = shlex.split(commandline_args) + + args, skip_torch_cuda_test = extract_arg(args, '--skip-torch-cuda-test') + xformers = '--xformers' in args + deepdanbooru = '--deepdanbooru' in args + + def repo_dir(name): + return os.path.join(dir_repos, name) + + def run_python(code, desc=None, errdesc=None): + return run(f'"{python}" -c "{code}"', desc, errdesc) + + def run_pip(args, desc=None): + return run(f'"{python}" -m pip {args} --prefer-binary', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") + + def check_run_python(code): + return check_run(f'"{python}" -c "{code}"') + + def git_clone(url, dir, name, commithash=None): + # TODO clone into temporary dir and move if successful + + if os.path.exists(dir): + if commithash is None: + return + + current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip() + if current_hash == commithash: + return + + run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}") + run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commint for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}") return - current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip() - if current_hash == commithash: - return + run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}") - run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}") - run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commint for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}") - return + if commithash is not None: + run(f'"{git}" -C {dir} checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}") - run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}") + try: + commit = run(f"{git} rev-parse HEAD").strip() + except Exception: + commit = "" - if commithash is not None: - run(f'"{git}" -C {dir} checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}") + print(f"Python {sys.version}") + print(f"Commit hash: {commit}") + if not is_installed("torch") or not is_installed("torchvision"): + run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch") -try: - commit = run(f"{git} rev-parse HEAD").strip() -except Exception: - commit = "" + if not skip_torch_cuda_test: + run_python("import torch; assert torch.cuda.is_available(), 'Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'") -print(f"Python {sys.version}") -print(f"Commit hash: {commit}") + if not is_installed("gfpgan"): + run_pip(f"install {gfpgan_package}", "gfpgan") + if not is_installed("clip"): + run_pip(f"install {clip_package}", "clip") -if not is_installed("torch") or not is_installed("torchvision"): - run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch") + if not is_installed("xformers") and xformers and platform.python_version().startswith("3.10"): + if platform.system() == "Windows": + run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") + elif platform.system() == "Linux": + run_pip("install xformers", "xformers") -if not skip_torch_cuda_test: - run_python("import torch; assert torch.cuda.is_available(), 'Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'") + if not is_installed("deepdanbooru") and deepdanbooru: + run_pip("install git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] tensorflow==2.10.0 tensorflow-io==0.27.0", "deepdanbooru") -if not is_installed("gfpgan"): - run_pip(f"install {gfpgan_package}", "gfpgan") + os.makedirs(dir_repos, exist_ok=True) -if not is_installed("clip"): - run_pip(f"install {clip_package}", "clip") + git_clone("https://github.com/CompVis/stable-diffusion.git", repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) + git_clone("https://github.com/CompVis/taming-transformers.git", repo_dir('taming-transformers'), "Taming Transformers", taming_transformers_commit_hash) + git_clone("https://github.com/crowsonkb/k-diffusion.git", repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash) + git_clone("https://github.com/sczhou/CodeFormer.git", repo_dir('CodeFormer'), "CodeFormer", codeformer_commit_hash) + git_clone("https://github.com/salesforce/BLIP.git", repo_dir('BLIP'), "BLIP", blip_commit_hash) -if not is_installed("xformers") and xformers and platform.python_version().startswith("3.10"): - if platform.system() == "Windows": - run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") - elif platform.system() == "Linux": - run_pip("install xformers", "xformers") + if not is_installed("lpips"): + run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}", "requirements for CodeFormer") -if not is_installed("deepdanbooru") and deepdanbooru: - run_pip("install git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] tensorflow==2.10.0 tensorflow-io==0.27.0", "deepdanbooru") + run_pip(f"install -r {requirements_file}", "requirements for Web UI") -os.makedirs(dir_repos, exist_ok=True) + sys.argv += args -git_clone("https://github.com/CompVis/stable-diffusion.git", repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) -git_clone("https://github.com/CompVis/taming-transformers.git", repo_dir('taming-transformers'), "Taming Transformers", taming_transformers_commit_hash) -git_clone("https://github.com/crowsonkb/k-diffusion.git", repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash) -git_clone("https://github.com/sczhou/CodeFormer.git", repo_dir('CodeFormer'), "CodeFormer", codeformer_commit_hash) -git_clone("https://github.com/salesforce/BLIP.git", repo_dir('BLIP'), "BLIP", blip_commit_hash) + if "--exit" in args: + print("Exiting because of --exit argument") + exit(0) -if not is_installed("lpips"): - run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}", "requirements for CodeFormer") - -run_pip(f"install -r {requirements_file}", "requirements for Web UI") - -sys.argv += args - -if "--exit" in args: - print("Exiting because of --exit argument") - exit(0) def start_webui(): print(f"Launching Web UI with arguments: {' '.join(sys.argv[1:])}") import webui webui.webui() + if __name__ == "__main__": + prepare_enviroment() start_webui() From bba2ac8324ccd1a67c78e5f59babae8323ec7dc6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 15:22:51 +0300 Subject: [PATCH 219/460] reshuffle the code a bit in launcher to keep functions in one place for #2069 --- launch.py | 77 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/launch.py b/launch.py index d1a4fd6ae..f42f557de 100644 --- a/launch.py +++ b/launch.py @@ -6,6 +6,10 @@ import importlib.util import shlex import platform +dir_repos = "repositories" +python = sys.executable +git = os.environ.get('GIT', "git") + def extract_arg(args, name): return [x for x in args if x != name], name in args @@ -44,11 +48,44 @@ def is_installed(package): return spec is not None -def prepare_enviroment(): - dir_repos = "repositories" +def repo_dir(name): + return os.path.join(dir_repos, name) - python = sys.executable - git = os.environ.get('GIT', "git") + +def run_python(code, desc=None, errdesc=None): + return run(f'"{python}" -c "{code}"', desc, errdesc) + + +def run_pip(args, desc=None): + return run(f'"{python}" -m pip {args} --prefer-binary', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") + + +def check_run_python(code): + return check_run(f'"{python}" -c "{code}"') + + +def git_clone(url, dir, name, commithash=None): + # TODO clone into temporary dir and move if successful + + if os.path.exists(dir): + if commithash is None: + return + + current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip() + if current_hash == commithash: + return + + run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}") + run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commint for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}") + return + + run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}") + + if commithash is not None: + run(f'"{git}" -C {dir} checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}") + + +def prepare_enviroment(): torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113") requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") commandline_args = os.environ.get('COMMANDLINE_ARGS', "") @@ -68,38 +105,6 @@ def prepare_enviroment(): xformers = '--xformers' in args deepdanbooru = '--deepdanbooru' in args - def repo_dir(name): - return os.path.join(dir_repos, name) - - def run_python(code, desc=None, errdesc=None): - return run(f'"{python}" -c "{code}"', desc, errdesc) - - def run_pip(args, desc=None): - return run(f'"{python}" -m pip {args} --prefer-binary', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") - - def check_run_python(code): - return check_run(f'"{python}" -c "{code}"') - - def git_clone(url, dir, name, commithash=None): - # TODO clone into temporary dir and move if successful - - if os.path.exists(dir): - if commithash is None: - return - - current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip() - if current_hash == commithash: - return - - run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}") - run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commint for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}") - return - - run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}") - - if commithash is not None: - run(f'"{git}" -C {dir} checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}") - try: commit = run(f"{git} rev-parse HEAD").strip() except Exception: From 875ddfeecfaffad9eee24813301637cba310337d Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 17:58:43 +0300 Subject: [PATCH 220/460] added guard for torch.load to prevent loading pickles with unknown content --- modules/paths.py | 1 + modules/safe.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++ modules/shared.py | 1 + 3 files changed, 91 insertions(+) create mode 100644 modules/safe.py diff --git a/modules/paths.py b/modules/paths.py index 0519caa0a..1e7a2fbcf 100644 --- a/modules/paths.py +++ b/modules/paths.py @@ -1,6 +1,7 @@ import argparse import os import sys +import modules.safe script_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) models_path = os.path.join(script_path, "models") diff --git a/modules/safe.py b/modules/safe.py new file mode 100644 index 000000000..2d2c13716 --- /dev/null +++ b/modules/safe.py @@ -0,0 +1,89 @@ +# this code is adapted from the script contributed by anon from /h/ + +import io +import pickle +import collections +import sys +import traceback + +import torch +import numpy +import _codecs +import zipfile + + +def encode(*args): + out = _codecs.encode(*args) + return out + + +class RestrictedUnpickler(pickle.Unpickler): + def persistent_load(self, saved_id): + assert saved_id[0] == 'storage' + return torch.storage._TypedStorage() + + def find_class(self, module, name): + if module == 'collections' and name == 'OrderedDict': + return getattr(collections, name) + if module == 'torch._utils' and name in ['_rebuild_tensor_v2', '_rebuild_parameter']: + return getattr(torch._utils, name) + if module == 'torch' and name in ['FloatStorage', 'HalfStorage', 'IntStorage', 'LongStorage']: + return getattr(torch, name) + if module == 'torch.nn.modules.container' and name in ['ParameterDict']: + return getattr(torch.nn.modules.container, name) + if module == 'numpy.core.multiarray' and name == 'scalar': + return numpy.core.multiarray.scalar + if module == 'numpy' and name == 'dtype': + return numpy.dtype + if module == '_codecs' and name == 'encode': + return encode + if module == "pytorch_lightning.callbacks" and name == 'model_checkpoint': + import pytorch_lightning.callbacks + return pytorch_lightning.callbacks.model_checkpoint + if module == "pytorch_lightning.callbacks.model_checkpoint" and name == 'ModelCheckpoint': + import pytorch_lightning.callbacks.model_checkpoint + return pytorch_lightning.callbacks.model_checkpoint.ModelCheckpoint + if module == "__builtin__" and name == 'set': + return set + + # Forbid everything else. + raise pickle.UnpicklingError(f"global '{module}/{name}' is forbidden") + + +def check_pt(filename): + try: + + # new pytorch format is a zip file + with zipfile.ZipFile(filename) as z: + with z.open('archive/data.pkl') as file: + unpickler = RestrictedUnpickler(file) + unpickler.load() + + except zipfile.BadZipfile: + + # if it's not a zip file, it's an olf pytorch format, with five objects written to pickle + with open(filename, "rb") as file: + unpickler = RestrictedUnpickler(file) + for i in range(5): + unpickler.load() + + +def load(filename, *args, **kwargs): + from modules import shared + + try: + if not shared.cmd_opts.disable_safe_unpickle: + check_pt(filename) + + except Exception: + print(f"Error verifying pickled file from {filename}:", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + print(f"\nThe file may be malicious, so the program is not going to read it.", file=sys.stderr) + print(f"You can skip this check with --disable-safe-unpickle commandline argument.", file=sys.stderr) + return None + + return unsafe_torch_load(filename, *args, **kwargs) + + +unsafe_torch_load = torch.load +torch.load = load diff --git a/modules/shared.py b/modules/shared.py index 6ecc2503a..3d7f08e14 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -65,6 +65,7 @@ parser.add_argument("--autolaunch", action='store_true', help="open the webui UR parser.add_argument("--use-textbox-seed", action='store_true', help="use textbox for seeds in UI (no up/down, but possible to input long seeds)", default=False) parser.add_argument("--disable-console-progressbars", action='store_true', help="do not output progressbars to console", default=False) parser.add_argument("--enable-console-prompts", action='store_true', help="print prompts to console when generating with txt2img and img2img", default=False) +parser.add_argument("--disable-safe-unpickle", action='store_true', help="disable checking pytorch models for malicious code", default=False) cmd_opts = parser.parse_args() From d3cd46b0388918128af203fda37fa63461c46611 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 16:19:33 +0100 Subject: [PATCH 221/460] Update lightbox to change displayed image as soon as generation is complete (#1933) * add updateOnBackgroundChange * typo fixes. * reindent to 4 spaces --- javascript/imageviewer.js | 168 ++++++++++++++++++++++---------------- 1 file changed, 96 insertions(+), 72 deletions(-) diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js index 6a00c0da4..65a33dd78 100644 --- a/javascript/imageviewer.js +++ b/javascript/imageviewer.js @@ -1,72 +1,97 @@ // A full size 'lightbox' preview modal shown when left clicking on gallery previews - function closeModal() { - gradioApp().getElementById("lightboxModal").style.display = "none"; + gradioApp().getElementById("lightboxModal").style.display = "none"; } function showModal(event) { - const source = event.target || event.srcElement; - const modalImage = gradioApp().getElementById("modalImage") - const lb = gradioApp().getElementById("lightboxModal") - modalImage.src = source.src - if (modalImage.style.display === 'none') { - lb.style.setProperty('background-image', 'url(' + source.src + ')'); - } - lb.style.display = "block"; - lb.focus() - event.stopPropagation() + const source = event.target || event.srcElement; + const modalImage = gradioApp().getElementById("modalImage") + const lb = gradioApp().getElementById("lightboxModal") + modalImage.src = source.src + if (modalImage.style.display === 'none') { + lb.style.setProperty('background-image', 'url(' + source.src + ')'); + } + lb.style.display = "block"; + lb.focus() + event.stopPropagation() } function negmod(n, m) { - return ((n % m) + m) % m; + return ((n % m) + m) % m; } -function modalImageSwitch(offset){ - var allgalleryButtons = gradioApp().querySelectorAll(".gallery-item.transition-all") - var galleryButtons = [] - allgalleryButtons.forEach(function(elem){ - if(elem.parentElement.offsetParent){ - galleryButtons.push(elem); +function updateOnBackgroundChange() { + const modalImage = gradioApp().getElementById("modalImage") + if (modalImage && modalImage.offsetParent) { + let allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2") + let currentButton = null + allcurrentButtons.forEach(function(elem) { + if (elem.parentElement.offsetParent) { + currentButton = elem; + } + }) + + if (modalImage.src != currentButton.children[0].src) { + modalImage.src = currentButton.children[0].src; + if (modalImage.style.display === 'none') { + modal.style.setProperty('background-image', `url(${modalImage.src})`) + } + } } - }) +} - if(galleryButtons.length>1){ - var allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2") - var currentButton = null - allcurrentButtons.forEach(function(elem){ - if(elem.parentElement.offsetParent){ - currentButton = elem; +function modalImageSwitch(offset) { + var allgalleryButtons = gradioApp().querySelectorAll(".gallery-item.transition-all") + var galleryButtons = [] + allgalleryButtons.forEach(function(elem) { + if (elem.parentElement.offsetParent) { + galleryButtons.push(elem); } - }) + }) - var result = -1 - galleryButtons.forEach(function(v, i){ if(v==currentButton) { result = i } }) + if (galleryButtons.length > 1) { + var allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2") + var currentButton = null + allcurrentButtons.forEach(function(elem) { + if (elem.parentElement.offsetParent) { + currentButton = elem; + } + }) - if(result != -1){ - nextButton = galleryButtons[negmod((result+offset),galleryButtons.length)] - nextButton.click() - const modalImage = gradioApp().getElementById("modalImage"); - const modal = gradioApp().getElementById("lightboxModal"); - modalImage.src = nextButton.children[0].src; - if (modalImage.style.display === 'none') { - modal.style.setProperty('background-image', `url(${modalImage.src})`) + var result = -1 + galleryButtons.forEach(function(v, i) { + if (v == currentButton) { + result = i + } + }) + + if (result != -1) { + nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)] + nextButton.click() + const modalImage = gradioApp().getElementById("modalImage"); + const modal = gradioApp().getElementById("lightboxModal"); + modalImage.src = nextButton.children[0].src; + if (modalImage.style.display === 'none') { + modal.style.setProperty('background-image', `url(${modalImage.src})`) + } + setTimeout(function() { + modal.focus() + }, 10) } - setTimeout( function(){modal.focus()},10) - } - } + } } -function modalNextImage(event){ - modalImageSwitch(1) - event.stopPropagation() +function modalNextImage(event) { + modalImageSwitch(1) + event.stopPropagation() } -function modalPrevImage(event){ - modalImageSwitch(-1) - event.stopPropagation() +function modalPrevImage(event) { + modalImageSwitch(-1) + event.stopPropagation() } -function modalKeyHandler(event){ +function modalKeyHandler(event) { switch (event.key) { case "ArrowLeft": modalPrevImage(event) @@ -80,24 +105,22 @@ function modalKeyHandler(event){ } } -function showGalleryImage(){ +function showGalleryImage() { setTimeout(function() { fullImg_preview = gradioApp().querySelectorAll('img.w-full.object-contain') - - if(fullImg_preview != null){ + + if (fullImg_preview != null) { fullImg_preview.forEach(function function_name(e) { if (e.dataset.modded) return; e.dataset.modded = true; if(e && e.parentElement.tagName == 'DIV'){ - e.style.cursor='pointer' - e.addEventListener('click', function (evt) { if(!opts.js_modal_lightbox) return; modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed) showModal(evt) - },true); + }, true); } }); } @@ -105,21 +128,21 @@ function showGalleryImage(){ }, 100); } -function modalZoomSet(modalImage, enable){ - if( enable ){ +function modalZoomSet(modalImage, enable) { + if (enable) { modalImage.classList.add('modalImageFullscreen'); - } else{ + } else { modalImage.classList.remove('modalImageFullscreen'); } } -function modalZoomToggle(event){ +function modalZoomToggle(event) { modalImage = gradioApp().getElementById("modalImage"); modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen')) event.stopPropagation() } -function modalTileImageToggle(event){ +function modalTileImageToggle(event) { const modalImage = gradioApp().getElementById("modalImage"); const modal = gradioApp().getElementById("lightboxModal"); const isTiling = modalImage.style.display === 'none'; @@ -134,17 +157,18 @@ function modalTileImageToggle(event){ event.stopPropagation() } -function galleryImageHandler(e){ - if(e && e.parentElement.tagName == 'BUTTON'){ +function galleryImageHandler(e) { + if (e && e.parentElement.tagName == 'BUTTON') { e.onclick = showGalleryImage; } } -onUiUpdate(function(){ +onUiUpdate(function() { fullImg_preview = gradioApp().querySelectorAll('img.w-full') - if(fullImg_preview != null){ - fullImg_preview.forEach(galleryImageHandler); + if (fullImg_preview != null) { + fullImg_preview.forEach(galleryImageHandler); } + updateOnBackgroundChange(); }) document.addEventListener("DOMContentLoaded", function() { @@ -152,13 +176,13 @@ document.addEventListener("DOMContentLoaded", function() { const modal = document.createElement('div') modal.onclick = closeModal; modal.id = "lightboxModal"; - modal.tabIndex=0 + modal.tabIndex = 0 modal.addEventListener('keydown', modalKeyHandler, true) const modalControls = document.createElement('div') modalControls.className = 'modalControls gradio-container'; modal.append(modalControls); - + const modalZoom = document.createElement('span') modalZoom.className = 'modalZoom cursor'; modalZoom.innerHTML = '⤡' @@ -183,30 +207,30 @@ document.addEventListener("DOMContentLoaded", function() { const modalImage = document.createElement('img') modalImage.id = 'modalImage'; modalImage.onclick = closeModal; - modalImage.tabIndex=0 + modalImage.tabIndex = 0 modalImage.addEventListener('keydown', modalKeyHandler, true) modal.appendChild(modalImage) const modalPrev = document.createElement('a') modalPrev.className = 'modalPrev'; modalPrev.innerHTML = '❮' - modalPrev.tabIndex=0 - modalPrev.addEventListener('click',modalPrevImage,true); + modalPrev.tabIndex = 0 + modalPrev.addEventListener('click', modalPrevImage, true); modalPrev.addEventListener('keydown', modalKeyHandler, true) modal.appendChild(modalPrev) const modalNext = document.createElement('a') modalNext.className = 'modalNext'; modalNext.innerHTML = '❯' - modalNext.tabIndex=0 - modalNext.addEventListener('click',modalNextImage,true); + modalNext.tabIndex = 0 + modalNext.addEventListener('click', modalNextImage, true); modalNext.addEventListener('keydown', modalKeyHandler, true) modal.appendChild(modalNext) gradioApp().getRootNode().appendChild(modal) - + document.body.appendChild(modalFragment); - + }); From 9ecea0a8d6bdc434755e11128487fd62f1ff130f Mon Sep 17 00:00:00 2001 From: Artem Zagidulin Date: Sun, 9 Oct 2022 16:14:56 +0300 Subject: [PATCH 222/460] fix missing png info when Extras Batch Process --- modules/extras.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/extras.py b/modules/extras.py index 39dd38060..41e8612c7 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -29,7 +29,7 @@ def run_extras(extras_mode, image, image_folder, gfpgan_visibility, codeformer_v if extras_mode == 1: #convert file to pillow image for img in image_folder: - image = Image.fromarray(np.array(Image.open(img))) + image = Image.open(img) imageArr.append(image) imageNameArr.append(os.path.splitext(img.orig_name)[0]) else: From a2d70f25bf51264d8d68f4f36937b390f79334a7 Mon Sep 17 00:00:00 2001 From: supersteve3d <39339941+supersteve3d@users.noreply.github.com> Date: Sun, 9 Oct 2022 23:40:18 +0800 Subject: [PATCH 223/460] Add files via upload Updated txt2img screenshot (UI as of Oct 9th) for github webui / README.md --- txt2img_Screenshot.png | Bin 539132 -> 337094 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/txt2img_Screenshot.png b/txt2img_Screenshot.png index fedd538e3cc7ea14ff5bed224dfbcd9765ec35f4..6e2759a4c8aa2d05e1334e871b2a451f1104ba60 100644 GIT binary patch literal 337094 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ⅆiEvHNn%B@eZavtJN|WG2P^exy|}wtFyjKo zHB0juQ<^9H9+aB4R8e)x?Sgd&*RmZDn{q!dlDjQ;8H>YN_t`reo;}uoVSnW8<^Pu7 z`2Nm+Bvh6g_E7tUHji_>-*}fpEQ`tS8SVB<2Y-oeZb|yvkZqnBu77-alpvp+>W)ASt26X+9fX;KeP%CP|Ll- zYvX)t*_jiZ9c^EHm5;ZwRjB2e_^2evWXNbg-X;{2@yO1Y!8bO8A>CS~_j2iiw*saf zzn=MJ-P!GZ+_CvG2ZQe=OVLG&Q#b4Kb}bC+dn;+k6lV23dgbbs(jRoJJ*Q4~*}L=P zmFd%c{<7}QWYF?i=;$zak*x{KiQq|E2hw-&d~i>^C7}?Nx{QM%Q%1m3A&SqJ$-wdJ zPpuvM7|!vSFxyyPS=6^tvX3E}X$Qle2!{A#Sy7YgaenQ$wO* zb^kDDM#D1)$F3Ff3A+4V)2gp?3vi_?zSCupcF=qr$6$fBp)R^vIL0`ES98%MHmR@gL&SK^rT5nxu_>zk;9$*u74bOZPWG>T+CI+FjI+3J zu&kMxkvNO%Yr)RjA}8z^GW9H&U4(BOyUnm6apnQjoaWLSY;QTZuZXOB`e~bGjZTB9 zgQ>KstjJq?E*EFnl?wz8M59q;XgxLrAt^n`_HWi_~K-{!+_d|1$Ktlg4n&Z5EJlgd9v5CTC>%_b>Ew*m5RAA#?IZ^_e2E{Q8#L7o5^r<+nFo552^6T=~bDzM`lH#f{IRPe&}> za^She{h&h|LmnmWo3?YAl6yPr2GL78@t=L1?Yfg|?PMSAo3XC7C`0P+p}!_)ts>_7 z2Hz>4JawkY$-f$c0h^SXkN)M3$TZ1fkbZZZ<39hL`3Db)^i^kED8B#ep%zPm@P=jI zCBDmKF7)6G-5{2IV3yT&mK6tgs+|`&cHMZgq(ngX^L2In#~w8Y=UQK_Oyg{|7COIX zuB=Gr0*36Xo%6l!&X$VOE#P(Vy_?N+Eoq`q*75k?-1>)qe@ zrz@%%vyW}v7Jtd<|8nLl3^yKxct1CrvhC@A_myiF{3%0A;ro-8*E$9+=+#Vo()*sj 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

Pubs7G4@}^e$}a%6;FpjSIFL$$r-gD%?Ed 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

  • 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 z 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 literal 539132 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ȐohdxoFI9B=aW_cmu8jNO~0k{ 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

    5E8m&Ve7X{sG+0jo9yDy(WzathqC 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

    ^STt# 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%0A$2Z(& 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 z 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

    PCZSb){h>3NUpY8GR*9|@eYx!W8-9s9 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 KelF{r5}E)Ue!9s3 From 45bf9a6264b3507473e02cc3f9aa36559f24aca2 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 18:58:55 +0300 Subject: [PATCH 224/460] added clip skip to XY plot --- scripts/xy_grid.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index c89ca1a9b..7b0d90831 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -83,6 +83,10 @@ def apply_hypernetwork(p, x, xs): hypernetwork.load_hypernetwork(x) +def apply_clip_skip(p, x, xs): + opts.data["CLIP_ignore_last_layers"] = x + + def format_value_add_label(p, opt, x): if type(x) == float: x = round(x, 8) @@ -134,6 +138,7 @@ axis_options = [ AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label), AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label), AxisOption("Eta", float, apply_field("eta"), format_value_add_label), + AxisOption("Clip skip", int, apply_clip_skip, format_value_add_label), AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label), # as it is now all AxisOptionImg2Img items must go after AxisOption ones ] @@ -201,6 +206,7 @@ class Script(scripts.Script): modules.processing.fix_seed(p) p.batch_size = 1 + CLIP_ignore_last_layers = opts.CLIP_ignore_last_layers def process_axis(opt, vals): if opt.label == 'Nothing': @@ -321,4 +327,6 @@ class Script(scripts.Script): hypernetwork.load_hypernetwork(opts.sd_hypernetwork) + opts.data["CLIP_ignore_last_layers"] = CLIP_ignore_last_layers + return processed From 6c383d2e82045fc4475d665f83bdeeac8fd844d9 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 22:24:07 +0300 Subject: [PATCH 225/460] show model selection setting on top of page --- modules/shared.py | 5 +++-- modules/ui.py | 54 +++++++++++++++++++++++++++++++++++++++-------- style.css | 9 ++++++++ 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 3d7f08e14..270fa4025 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -131,13 +131,14 @@ def realesrgan_models_names(): class OptionInfo: - def __init__(self, default=None, label="", component=None, component_args=None, onchange=None): + def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, show_on_main_page=False): self.default = default self.label = label self.component = component self.component_args = component_args self.onchange = onchange self.section = None + self.show_on_main_page = show_on_main_page def options_section(section_identifier, options_dict): @@ -214,7 +215,7 @@ options_templates.update(options_section(('system', "System"), { })) options_templates.update(options_section(('sd', "Stable Diffusion"), { - "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}), + "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, show_on_main_page=True), "sd_hypernetwork": OptionInfo("None", "Stable Diffusion finetune hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), "save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"), diff --git a/modules/ui.py b/modules/ui.py index dad509f3a..2231a8ed8 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1175,10 +1175,13 @@ Requested path was: {f} changed = 0 for key, value, comp in zip(opts.data_labels.keys(), args, components): - if not opts.same_type(value, opts.data_labels[key].default): - return f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}" + if comp != dummy_component and not opts.same_type(value, opts.data_labels[key].default): + return f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}", opts.dumpjson() for key, value, comp in zip(opts.data_labels.keys(), args, components): + if comp == dummy_component: + continue + comp_args = opts.data_labels[key].component_args if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False: continue @@ -1196,6 +1199,21 @@ Requested path was: {f} return f'{changed} settings changed.', opts.dumpjson() + def run_settings_single(value, key): + if not opts.same_type(value, opts.data_labels[key].default): + return gr.update(visible=True), opts.dumpjson() + + oldval = opts.data.get(key, None) + opts.data[key] = value + + if oldval != value: + if opts.data_labels[key].onchange is not None: + opts.data_labels[key].onchange() + + opts.save(shared.config_filename) + + return gr.update(value=value), opts.dumpjson() + with gr.Blocks(analytics_enabled=False) as settings_interface: settings_submit = gr.Button(value="Apply settings", variant='primary') result = gr.HTML() @@ -1203,6 +1221,8 @@ Requested path was: {f} settings_cols = 3 items_per_col = int(len(opts.data_labels) * 0.9 / settings_cols) + quicksettings_list = [] + cols_displayed = 0 items_displayed = 0 previous_section = None @@ -1225,10 +1245,14 @@ Requested path was: {f} gr.HTML(elem_id="settings_header_text_{}".format(item.section[0]), value='

    {}

    '.format(item.section[1])) - component = create_setting_component(k) - component_dict[k] = component - components.append(component) - items_displayed += 1 + if item.show_on_main_page: + quicksettings_list.append((i, k, item)) + components.append(dummy_component) + else: + component = create_setting_component(k) + component_dict[k] = component + components.append(component) + items_displayed += 1 request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications") request_notifications.click( @@ -1242,7 +1266,6 @@ Requested path was: {f} reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary') restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') - def reload_scripts(): modules.scripts.reload_script_body_only() @@ -1289,7 +1312,11 @@ Requested path was: {f} css += css_hide_progressbar with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo: - + with gr.Row(elem_id="quicksettings"): + for i, k, item in quicksettings_list: + component = create_setting_component(k) + component_dict[k] = component + settings_interface.gradio_ref = demo with gr.Tabs() as tabs: @@ -1306,7 +1333,16 @@ Requested path was: {f} inputs=components, outputs=[result, text_settings], ) - + + for i, k, item in quicksettings_list: + component = component_dict[k] + + component.change( + fn=lambda value, k=k: run_settings_single(value, key=k), + inputs=[component], + outputs=[component, text_settings], + ) + def modelmerger(*args): try: results = modules.extras.run_modelmerger(*args) diff --git a/style.css b/style.css index 101d20520..28160bdf0 100644 --- a/style.css +++ b/style.css @@ -453,3 +453,12 @@ input[type="range"]{ .context-menu-items a:hover{ background: #a55000; } + +#quicksettings > div{ + border: none; +} + +#quicksettings > div > div{ + max-width: 32em; + padding: 0; +} From e59c66c0088422b27f64b401ef42c242f836725a Mon Sep 17 00:00:00 2001 From: Fampai Date: Sat, 8 Oct 2022 16:32:05 -0400 Subject: [PATCH 226/460] Optimized code for Ignoring last CLIP layers --- modules/sd_hijack.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index f12a9696f..4a2d21531 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -282,14 +282,10 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): remade_batch_tokens_of_same_length = [x + [self.wrapped.tokenizer.eos_token_id] * (target_token_count - len(x)) for x in remade_batch_tokens] tokens = torch.asarray(remade_batch_tokens_of_same_length).to(device) - tmp = -opts.CLIP_ignore_last_layers - if (opts.CLIP_ignore_last_layers == 0): - outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids) - z = outputs.last_hidden_state - else: - outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids, output_hidden_states=tmp) - z = outputs.hidden_states[tmp] - z = self.wrapped.transformer.text_model.final_layer_norm(z) + tmp = -opts.CLIP_stop_at_last_layers + outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids, output_hidden_states=tmp) + z = outputs.hidden_states[tmp] + z = self.wrapped.transformer.text_model.final_layer_norm(z) # restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise batch_multipliers_of_same_length = [x + [1.0] * (target_token_count - len(x)) for x in batch_multipliers] From a14f7bf113a2af9e06a1c4d06c2efa244f9c5730 Mon Sep 17 00:00:00 2001 From: Fampai Date: Sat, 8 Oct 2022 16:33:06 -0400 Subject: [PATCH 227/460] Corrected CLIP Layer Ignore description and updated its range to the max possible --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index 270fa4025..1995a99a7 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -225,7 +225,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "use_old_emphasis_implementation": OptionInfo(False, "Use old emphasis implementation. Can be useful to reproduce old seeds."), "enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"), "filter_nsfw": OptionInfo(False, "Filter NSFW content"), - 'CLIP_ignore_last_layers': OptionInfo(0, "Ignore last layers of CLIP model", gr.Slider, {"minimum": 0, "maximum": 5, "step": 1}), + 'CLIP_stop_at_last_layers': OptionInfo(1, "Stop At last layers of CLIP model", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}), "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), })) From ec2bd9be75865c9f3a8c898163ab381688c03b6e Mon Sep 17 00:00:00 2001 From: Fampai Date: Sat, 8 Oct 2022 17:28:42 -0400 Subject: [PATCH 228/460] Fix issues with CLIP ignore option name change --- modules/processing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 04aed989d..92a105a2c 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -129,7 +129,7 @@ class Processed: self.index_of_first_image = index_of_first_image self.styles = p.styles self.job_timestamp = state.job_timestamp - self.clip_skip = opts.CLIP_ignore_last_layers + self.clip_skip = opts.CLIP_stop_at_last_layers self.eta = p.eta self.ddim_discretize = p.ddim_discretize @@ -274,7 +274,7 @@ def fix_seed(p): def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration=0, position_in_batch=0): index = position_in_batch + iteration * p.batch_size - clip_skip = getattr(p, 'clip_skip', opts.CLIP_ignore_last_layers) + clip_skip = getattr(p, 'clip_skip', opts.CLIP_stop_at_last_layers) generation_params = { "Steps": p.steps, From ad3ae441081155dcd4fde805279e5082ca264695 Mon Sep 17 00:00:00 2001 From: Fampai Date: Sun, 9 Oct 2022 04:32:40 -0400 Subject: [PATCH 229/460] Updated code for legibility --- modules/sd_hijack.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 4a2d21531..7793d25be 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -284,8 +284,11 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): tmp = -opts.CLIP_stop_at_last_layers outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids, output_hidden_states=tmp) - z = outputs.hidden_states[tmp] - z = self.wrapped.transformer.text_model.final_layer_norm(z) + if tmp < -1: + z = outputs.hidden_states[tmp] + z = self.wrapped.transformer.text_model.final_layer_norm(z) + else: + z = outputs.last_hidden_state # restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise batch_multipliers_of_same_length = [x + [1.0] * (target_token_count - len(x)) for x in batch_multipliers] From 1824e9ee3ab4f94aee8908a62ea2569a01aeb3d7 Mon Sep 17 00:00:00 2001 From: Fampai Date: Sun, 9 Oct 2022 14:15:43 -0400 Subject: [PATCH 230/460] Removed unnecessary tmp variable --- modules/sd_hijack.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 7793d25be..437acce4c 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -282,10 +282,9 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): remade_batch_tokens_of_same_length = [x + [self.wrapped.tokenizer.eos_token_id] * (target_token_count - len(x)) for x in remade_batch_tokens] tokens = torch.asarray(remade_batch_tokens_of_same_length).to(device) - tmp = -opts.CLIP_stop_at_last_layers - outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids, output_hidden_states=tmp) - if tmp < -1: - z = outputs.hidden_states[tmp] + outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids, output_hidden_states=-opts.CLIP_stop_at_last_layers) + if opts.CLIP_stop_at_last_layers > 1: + z = outputs.hidden_states[-opts.CLIP_stop_at_last_layers] z = self.wrapped.transformer.text_model.final_layer_norm(z) else: z = outputs.last_hidden_state From 84ddd44113b36062e8ba6cb2e5db0fce4f48efb8 Mon Sep 17 00:00:00 2001 From: Fampai Date: Sun, 9 Oct 2022 14:57:17 -0400 Subject: [PATCH 231/460] Clip skip variable name change breaks x/y plot script. This fixes that --- scripts/xy_grid.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 7b0d90831..771eb8e49 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -84,7 +84,7 @@ def apply_hypernetwork(p, x, xs): def apply_clip_skip(p, x, xs): - opts.data["CLIP_ignore_last_layers"] = x + opts.data["CLIP_stop_at_last_layers"] = x def format_value_add_label(p, opt, x): @@ -206,7 +206,7 @@ class Script(scripts.Script): modules.processing.fix_seed(p) p.batch_size = 1 - CLIP_ignore_last_layers = opts.CLIP_ignore_last_layers + CLIP_stop_at_last_layers = opts.CLIP_stop_at_last_layers def process_axis(opt, vals): if opt.label == 'Nothing': @@ -327,6 +327,6 @@ class Script(scripts.Script): hypernetwork.load_hypernetwork(opts.sd_hypernetwork) - opts.data["CLIP_ignore_last_layers"] = CLIP_ignore_last_layers + opts.data["CLIP_stop_at_last_layers"] = CLIP_stop_at_last_layers return processed From 8d340cfb884e1dbff5b6f477f4ecf7d104279115 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 22:30:59 +0300 Subject: [PATCH 232/460] do not add clip skip to parameters if it's 1 or 0 --- modules/processing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index 92a105a2c..94d2dd62c 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -293,7 +293,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "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), "Eta": (None if p.sampler is None or p.sampler.eta == p.sampler.default_eta else p.sampler.eta), - "Clip skip": None if clip_skip==0 else clip_skip, + "Clip skip": None if clip_skip <= 1 else clip_skip, } generation_params.update(p.extra_generation_params) From fa0c5eb81b72bc1e562d0b9bbd92f30945d78b4e Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 20:41:22 +0100 Subject: [PATCH 233/460] Add pretty image captioning functions --- modules/images.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/modules/images.py b/modules/images.py index 29c5ee249..10963dc7f 100644 --- a/modules/images.py +++ b/modules/images.py @@ -428,3 +428,34 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i file.write(info + "\n") return fullfn + +def addCaptionLines(lines,image,initialx,textfont): + draw = ImageDraw.Draw(image) + hstart =initialx + for fill,line in lines: + fontSize = 32 + font = ImageFont.truetype(textfont, fontSize) + _,_,w, h = draw.textbbox((0,0),line,font=font) + fontSize = min( int(fontSize * ((image.size[0]-35)/w) ), 28) + font = ImageFont.truetype(textfont, fontSize) + _,_,w,h = draw.textbbox((0,0),line,font=font) + draw.text(((image.size[0]-w)/2,hstart), line, font=font, fill=fill) + hstart += h + return hstart + +def captionImge(image,prelines,postlines,background=(51, 51, 51),font=None): + if font is None: + try: + font = ImageFont.truetype(opts.font or Roboto, fontsize) + font = opts.font or Roboto + except Exception: + font = Roboto + + sampleImage = image + background = Image.new("RGBA", (sampleImage.size[0],sampleImage.size[1]+1024), background) + hoffset = addCaptionLines(prelines,background,5,font)+16 + background.paste(sampleImage,(0,hoffset)) + hoffset = hoffset+sampleImage.size[1]+8 + hoffset = addCaptionLines(postlines,background,hoffset,font) + background = background.crop((0,0,sampleImage.size[0],hoffset+8)) + return background From a65476718f08a35f527b973ef731e6f488bace5e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sun, 9 Oct 2022 23:38:49 +0300 Subject: [PATCH 234/460] add DoubleStorage to list of allowed classes for pickle --- modules/safe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/safe.py b/modules/safe.py index 2d2c13716..4d06f2a53 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -27,7 +27,7 @@ class RestrictedUnpickler(pickle.Unpickler): return getattr(collections, name) if module == 'torch._utils' and name in ['_rebuild_tensor_v2', '_rebuild_parameter']: return getattr(torch._utils, name) - if module == 'torch' and name in ['FloatStorage', 'HalfStorage', 'IntStorage', 'LongStorage']: + if module == 'torch' and name in ['FloatStorage', 'HalfStorage', 'IntStorage', 'LongStorage', 'DoubleStorage']: return getattr(torch, name) if module == 'torch.nn.modules.container' and name in ['ParameterDict']: return getattr(torch.nn.modules.container, name) From 03694e1f9915e34cf7d9a31073f1a1a9def2909f Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 21:58:14 +0100 Subject: [PATCH 235/460] add embedding load and save from b64 json --- .../textual_inversion/textual_inversion.py | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index f63160208..1b7f89062 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -7,9 +7,11 @@ import tqdm import html import datetime -from PIL import Image, PngImagePlugin +from PIL import Image,PngImagePlugin +from ..images import captionImge +import numpy as np import base64 -from io import BytesIO +import json from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset @@ -87,9 +89,9 @@ class EmbeddingDatabase: if filename.upper().endswith('.PNG'): embed_image = Image.open(path) - if 'sd-embedding' in embed_image.text: - embeddingData = base64.b64decode(embed_image.text['sd-embedding']) - data = torch.load(BytesIO(embeddingData), map_location="cpu") + if 'sd-ti-embedding' in embed_image.text: + data = embeddingFromB64(embed_image.text['sd-ti-embedding']) + name = data.get('name',name) else: data = torch.load(path, map_location="cpu") @@ -258,13 +260,23 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, if save_image_with_stored_embedding: info = PngImagePlugin.PngInfo() - info.add_text("sd-embedding", base64.b64encode(open(last_saved_file,'rb').read())) - image.save(last_saved_image, "PNG", pnginfo=info) + data = torch.load(last_saved_file) + info.add_text("sd-ti-embedding", embeddingToB64(data)) + + pre_lines = [((255, 207, 175),"<{}>".format(data.get('name','???')))] + + caption_checkpoint_hash = data.get('sd_checkpoint','UNK') + caption_checkpoint_hash = caption_checkpoint_hash.upper() if caption_checkpoint_hash else 'UNK' + caption_stepcount = data.get('step',0) + caption_stepcount = caption_stepcount if caption_stepcount else 0 + + post_lines = [((240, 223, 175),"Trained against checkpoint [{}] for {} steps".format(caption_checkpoint_hash, + caption_stepcount))] + captioned_image = captionImge(image,prelines=pre_lines,postlines=post_lines) + captioned_image.save(last_saved_image, "PNG", pnginfo=info) else: image.save(last_saved_image) - - last_saved_image += f", prompt: {text}" shared.state.job_no = embedding.step From 969bd8256e5b4f1007d3cc653723d4ad50a92528 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 22:02:28 +0100 Subject: [PATCH 236/460] add alternate checkpoint hash source --- modules/textual_inversion/textual_inversion.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 1b7f89062..d7813084a 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -265,8 +265,11 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, pre_lines = [((255, 207, 175),"<{}>".format(data.get('name','???')))] - caption_checkpoint_hash = data.get('sd_checkpoint','UNK') - caption_checkpoint_hash = caption_checkpoint_hash.upper() if caption_checkpoint_hash else 'UNK' + caption_checkpoint_hash = data.get('sd_checkpoint') + if caption_checkpoint_hash is None: + caption_checkpoint_hash = data.get('hash') + caption_checkpoint_hash = caption_checkpoint_hash.upper() if caption_checkpoint_hash else 'UNKNOWN' + caption_stepcount = data.get('step',0) caption_stepcount = caption_stepcount if caption_stepcount else 0 From 5d12ec82d3e13f5ff4c55db2930e4e10aed7015a Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 22:05:09 +0100 Subject: [PATCH 237/460] add encoder and decoder classes --- .../textual_inversion/textual_inversion.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index d7813084a..44d4e08bd 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -16,6 +16,27 @@ import json from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset +class EmbeddingEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, torch.Tensor): + return {'EMBEDDINGTENSOR':obj.cpu().detach().numpy().tolist()} + return json.JSONEncoder.default(self, o) + +class EmbeddingDecoder(json.JSONDecoder): + def __init__(self, *args, **kwargs): + json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) + def object_hook(self, d): + if 'EMBEDDINGTENSOR' in d: + return torch.from_numpy(np.array(d['EMBEDDINGTENSOR'])) + return d + +def embeddingToB64(data): + d = json.dumps(data,cls=EmbeddingEncoder) + return base64.b64encode(d.encode()) + +def EmbeddingFromB64(data): + d = base64.b64decode(data) + return json.loads(d,cls=EmbeddingDecoder) class Embedding: def __init__(self, vec, name, step=None): From d0184b8f76ce492da699f1926f34b57cd095242e Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 22:06:12 +0100 Subject: [PATCH 238/460] change json tensor key name --- modules/textual_inversion/textual_inversion.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 44d4e08bd..ae8d207d9 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -19,15 +19,15 @@ import modules.textual_inversion.dataset class EmbeddingEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, torch.Tensor): - return {'EMBEDDINGTENSOR':obj.cpu().detach().numpy().tolist()} + return {'TORCHTENSOR':obj.cpu().detach().numpy().tolist()} return json.JSONEncoder.default(self, o) class EmbeddingDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) def object_hook(self, d): - if 'EMBEDDINGTENSOR' in d: - return torch.from_numpy(np.array(d['EMBEDDINGTENSOR'])) + if 'TORCHTENSOR' in d: + return torch.from_numpy(np.array(d['TORCHTENSOR'])) return d def embeddingToB64(data): From 66846105103cfc282434d0dc2102910160b7a633 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 22:06:42 +0100 Subject: [PATCH 239/460] correct case on embeddingFromB64 --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index ae8d207d9..d2b95fa3b 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -34,7 +34,7 @@ def embeddingToB64(data): d = json.dumps(data,cls=EmbeddingEncoder) return base64.b64encode(d.encode()) -def EmbeddingFromB64(data): +def embeddingFromB64(data): d = base64.b64decode(data) return json.loads(d,cls=EmbeddingDecoder) From 96f1e6be59316ec640cab2435fa95b3688194906 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 22:14:50 +0100 Subject: [PATCH 240/460] source checkpoint hash from current checkpoint --- modules/textual_inversion/textual_inversion.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index d2b95fa3b..b16fa84ec 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -286,10 +286,8 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, pre_lines = [((255, 207, 175),"<{}>".format(data.get('name','???')))] - caption_checkpoint_hash = data.get('sd_checkpoint') - if caption_checkpoint_hash is None: - caption_checkpoint_hash = data.get('hash') - caption_checkpoint_hash = caption_checkpoint_hash.upper() if caption_checkpoint_hash else 'UNKNOWN' + checkpoint = sd_models.select_checkpoint() + caption_checkpoint_hash = checkpoint.hash caption_stepcount = data.get('step',0) caption_stepcount = caption_stepcount if caption_stepcount else 0 From 01fd9cf0d28d8b71a113ab1aa62accfe7f0d9c51 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Sun, 9 Oct 2022 22:17:02 +0100 Subject: [PATCH 241/460] change source of step count --- modules/textual_inversion/textual_inversion.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index b16fa84ec..e4f339b86 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -285,15 +285,9 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, info.add_text("sd-ti-embedding", embeddingToB64(data)) pre_lines = [((255, 207, 175),"<{}>".format(data.get('name','???')))] - checkpoint = sd_models.select_checkpoint() - caption_checkpoint_hash = checkpoint.hash - - caption_stepcount = data.get('step',0) - caption_stepcount = caption_stepcount if caption_stepcount else 0 - - post_lines = [((240, 223, 175),"Trained against checkpoint [{}] for {} steps".format(caption_checkpoint_hash, - caption_stepcount))] + post_lines = [((240, 223, 175),"Trained against checkpoint [{}] for {} steps".format(checkpoint.hash, + embedding.step))] captioned_image = captionImge(image,prelines=pre_lines,postlines=post_lines) captioned_image.save(last_saved_image, "PNG", pnginfo=info) else: From 45fbd1c5fec887988ab555aac75a999d4f3aff40 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 10 Oct 2022 00:42:18 +0300 Subject: [PATCH 242/460] remove background for quicksettings row (for dark theme) --- style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/style.css b/style.css index 28160bdf0..c0c3f2bb3 100644 --- a/style.css +++ b/style.css @@ -456,6 +456,7 @@ input[type="range"]{ #quicksettings > div{ border: none; + background: none; } #quicksettings > div > div{ From 0ac3a07eecbd7b98f3a19d01dc46f02dcda3443b Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:05:36 +0100 Subject: [PATCH 243/460] add caption image with overlay --- modules/images.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/modules/images.py b/modules/images.py index 10963dc7f..4a4fc9774 100644 --- a/modules/images.py +++ b/modules/images.py @@ -459,3 +459,49 @@ def captionImge(image,prelines,postlines,background=(51, 51, 51),font=None): hoffset = addCaptionLines(postlines,background,hoffset,font) background = background.crop((0,0,sampleImage.size[0],hoffset+8)) return background + +def captionImageOverlay(srcimage,title,footerLeft,footerMid,footerRight,textfont=None): + from math import cos + + image = srcimage.copy() + + if textfont is None: + try: + textfont = ImageFont.truetype(opts.font or Roboto, fontsize) + textfont = opts.font or Roboto + except Exception: + textfont = Roboto + + factor = 1.5 + gradient = Image.new('RGBA', (1,image.size[1]), color=(0,0,0,0)) + for y in range(image.size[1]): + mag = 1-cos(y/image.size[1]*factor) + mag = max(mag,1-cos((image.size[1]-y)/image.size[1]*factor*1.1)) + gradient.putpixel((0, y), (0,0,0,int(mag*255))) + image = Image.alpha_composite(image.convert('RGBA'), gradient.resize(image.size)) + + draw = ImageDraw.Draw(image) + fontSize = 32 + font = ImageFont.truetype(textfont, fontSize) + padding = 10 + + _,_,w, h = draw.textbbox((0,0),title,font=font) + fontSize = min( int(fontSize * (((image.size[0]*0.75)-(padding*4))/w) ), 72) + font = ImageFont.truetype(textfont, fontSize) + _,_,w,h = draw.textbbox((0,0),title,font=font) + draw.text((padding,padding), title, anchor='lt', font=font, fill=(255,255,255,230)) + + _,_,w, h = draw.textbbox((0,0),footerLeft,font=font) + fontSizeleft = min( int(fontSize * (((image.size[0]/3)-(padding))/w) ), 72) + _,_,w, h = draw.textbbox((0,0),footerMid,font=font) + fontSizemid = min( int(fontSize * (((image.size[0]/3)-(padding))/w) ), 72) + _,_,w, h = draw.textbbox((0,0),footerRight,font=font) + fontSizeright = min( int(fontSize * (((image.size[0]/3)-(padding))/w) ), 72) + + font = ImageFont.truetype(textfont, min(fontSizeleft,fontSizemid,fontSizeright)) + + draw.text((padding,image.size[1]-padding), footerLeft, anchor='ls', font=font, fill=(255,255,255,230)) + draw.text((image.size[0]/2,image.size[1]-padding), footerMid, anchor='ms', font=font, fill=(255,255,255,230)) + draw.text((image.size[0]-padding,image.size[1]-padding), footerRight, anchor='rs', font=font, fill=(255,255,255,230)) + + return image From d6a599ef9ba18a66ae79b50f2945af5788fdda8f Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:07:52 +0100 Subject: [PATCH 244/460] change caption method --- .../textual_inversion/textual_inversion.py | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index e4f339b86..21596e784 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -8,7 +8,7 @@ import html import datetime from PIL import Image,PngImagePlugin -from ..images import captionImge +from ..images import captionImageOverlay import numpy as np import base64 import json @@ -212,6 +212,12 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, else: images_dir = None + if create_image_every > 0 and save_image_with_stored_embedding: + images_embeds_dir = os.path.join(log_directory, "image_embeddings") + os.makedirs(images_embeds_dir, exist_ok=True) + else: + images_embeds_dir = None + cond_model = shared.sd_model.cond_stage_model shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." @@ -279,19 +285,25 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, shared.state.current_image = image - if save_image_with_stored_embedding: + if save_image_with_stored_embedding and os.path.exists(last_saved_file): + + last_saved_image_chunks = os.path.join(images_embeds_dir, f'{embedding_name}-{embedding.step}.png') + info = PngImagePlugin.PngInfo() data = torch.load(last_saved_file) info.add_text("sd-ti-embedding", embeddingToB64(data)) - pre_lines = [((255, 207, 175),"<{}>".format(data.get('name','???')))] + title = "<{}>".format(data.get('name','???')) checkpoint = sd_models.select_checkpoint() - post_lines = [((240, 223, 175),"Trained against checkpoint [{}] for {} steps".format(checkpoint.hash, - embedding.step))] - captioned_image = captionImge(image,prelines=pre_lines,postlines=post_lines) - captioned_image.save(last_saved_image, "PNG", pnginfo=info) - else: - image.save(last_saved_image) + footer_left = checkpoint.model_name + footer_mid = '[{}]'.format(checkpoint.hash) + footer_right = '[{}]'.format(embedding.step) + + captioned_image = captionImageOverlay(image,title,footer_left,footer_mid,footer_right) + + captioned_image.save(last_saved_image_chunks, "PNG", pnginfo=info) + + image.save(last_saved_image) last_saved_image += f", prompt: {text}" From e2c2925eb4d634b186de2c76798162ec56e2f869 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 00:12:53 +0100 Subject: [PATCH 245/460] remove braces from steps --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 21596e784..9a18ee5c8 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -297,7 +297,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, checkpoint = sd_models.select_checkpoint() footer_left = checkpoint.model_name footer_mid = '[{}]'.format(checkpoint.hash) - footer_right = '[{}]'.format(embedding.step) + footer_right = '{}'.format(embedding.step) captioned_image = captionImageOverlay(image,title,footer_left,footer_mid,footer_right) From 6435691bb11c5a35703720bfd2a875f24c066f86 Mon Sep 17 00:00:00 2001 From: Justin Maier Date: Sun, 9 Oct 2022 19:26:52 -0600 Subject: [PATCH 246/460] Add "Scale to" option to Extras --- javascript/ui.js | 3 ++- modules/extras.py | 28 +++++++++++++++++++++++----- modules/ui.py | 38 +++++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/javascript/ui.js b/javascript/ui.js index b1053201c..4100944e6 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -101,7 +101,8 @@ function create_tab_index_args(tabId, args){ } function get_extras_tab_index(){ - return create_tab_index_args('mode_extras', arguments) + const [,,...args] = [...arguments] + return [get_tab_index('mode_extras'), get_tab_index('extras_resize_mode'), ...args] } function create_submit_args(args){ diff --git a/modules/extras.py b/modules/extras.py index 41e8612c7..83ca70492 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -1,3 +1,4 @@ +import math import os import numpy as np @@ -19,7 +20,7 @@ import gradio as gr cached_images = {} -def run_extras(extras_mode, image, image_folder, gfpgan_visibility, codeformer_visibility, codeformer_weight, upscaling_resize, extras_upscaler_1, extras_upscaler_2, extras_upscaler_2_visibility): +def run_extras(extras_mode, resize_mode, image, image_folder, gfpgan_visibility, codeformer_visibility, codeformer_weight, upscaling_resize, upscaling_resize_w, upscaling_resize_h, upscaling_crop, extras_upscaler_1, extras_upscaler_2, extras_upscaler_2_visibility): devices.torch_gc() imageArr = [] @@ -67,8 +68,23 @@ def run_extras(extras_mode, image, image_folder, gfpgan_visibility, codeformer_v info += f"CodeFormer w: {round(codeformer_weight, 2)}, CodeFormer visibility:{round(codeformer_visibility, 2)}\n" image = res + if resize_mode == 1: + upscaling_resize = max(upscaling_resize_w/image.width, upscaling_resize_h/image.height) + crop_info = " (crop)" if upscaling_crop else "" + info += f"Resize to: {upscaling_resize_w:g}x{upscaling_resize_h:g}{crop_info}\n" + + def crop_upscaled_center(image, resize_w, resize_h): + left = int(math.ceil((image.width - resize_w) / 2)) + right = image.width - int(math.floor((image.width - resize_w) / 2)) + top = int(math.ceil((image.height - resize_h) / 2)) + bottom = image.height - int(math.floor((image.height - resize_h) / 2)) + + image = image.crop((left, top, right, bottom)) + return image + + if upscaling_resize != 1.0: - def upscale(image, scaler_index, resize): + def upscale(image, scaler_index, resize, mode, resize_w, resize_h, crop): small = image.crop((image.width // 2, image.height // 2, image.width // 2 + 10, image.height // 2 + 10)) pixels = tuple(np.array(small).flatten().tolist()) key = (resize, scaler_index, image.width, image.height, gfpgan_visibility, codeformer_visibility, codeformer_weight) + pixels @@ -77,15 +93,17 @@ def run_extras(extras_mode, image, image_folder, gfpgan_visibility, codeformer_v if c is None: upscaler = shared.sd_upscalers[scaler_index] c = upscaler.scaler.upscale(image, resize, upscaler.data_path) + if mode == 1 and crop: + c = crop_upscaled_center(c, resize_w, resize_h) cached_images[key] = c return c info += f"Upscale: {round(upscaling_resize, 3)}, model:{shared.sd_upscalers[extras_upscaler_1].name}\n" - res = upscale(image, extras_upscaler_1, upscaling_resize) + res = upscale(image, extras_upscaler_1, upscaling_resize, resize_mode, upscaling_resize_w, upscaling_resize_h, upscaling_crop) if extras_upscaler_2 != 0 and extras_upscaler_2_visibility > 0: - res2 = upscale(image, extras_upscaler_2, upscaling_resize) + res2 = upscale(image, extras_upscaler_2, upscaling_resize, resize_mode, upscaling_resize_w, upscaling_resize_h, upscaling_crop) info += f"Upscale: {round(upscaling_resize, 3)}, visibility: {round(extras_upscaler_2_visibility, 3)}, model:{shared.sd_upscalers[extras_upscaler_2].name}\n" res = Image.blend(res, res2, extras_upscaler_2_visibility) @@ -190,7 +208,7 @@ def run_modelmerger(primary_model_name, secondary_model_name, interp_method, int theta_0[key] = theta_func(theta_0[key], theta_1[key], (float(1.0) - interp_amount)) # Need to reverse the interp_amount to match the desired mix ration in the merged checkpoint if save_as_half: theta_0[key] = theta_0[key].half() - + for key in theta_1.keys(): if 'model' in key and key not in theta_0: theta_0[key] = theta_1[key] diff --git a/modules/ui.py b/modules/ui.py index 2231a8ed8..4bb2892b7 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -101,7 +101,7 @@ def send_gradio_gallery_to_image(x): def save_files(js_data, images, do_make_zip, index): - import csv + import csv filenames = [] fullfns = [] @@ -551,7 +551,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Row(): do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) - + with gr.Row(): download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) @@ -739,7 +739,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Row(): do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) - + with gr.Row(): download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) @@ -903,7 +903,15 @@ def create_ui(wrap_gradio_gpu_call): with gr.TabItem('Batch Process'): image_batch = gr.File(label="Batch Process", file_count="multiple", interactive=True, type="file") - upscaling_resize = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Resize", value=2) + with gr.Tabs(elem_id="extras_resize_mode"): + with gr.TabItem('Scale by'): + upscaling_resize = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Resize", value=2) + with gr.TabItem('Scale to'): + with gr.Group(): + with gr.Row(): + upscaling_resize_w = gr.Number(label="Width", value=512) + upscaling_resize_h = gr.Number(label="Height", value=512) + upscaling_crop = gr.Checkbox(label='Crop to fit', value=True) with gr.Group(): extras_upscaler_1 = gr.Radio(label='Upscaler 1', choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index") @@ -934,6 +942,7 @@ def create_ui(wrap_gradio_gpu_call): fn=wrap_gradio_gpu_call(modules.extras.run_extras), _js="get_extras_tab_index", inputs=[ + dummy_component, dummy_component, extras_image, image_batch, @@ -941,6 +950,9 @@ def create_ui(wrap_gradio_gpu_call): codeformer_visibility, codeformer_weight, upscaling_resize, + upscaling_resize_w, + upscaling_resize_h, + upscaling_crop, extras_upscaler_1, extras_upscaler_2, extras_upscaler_2_visibility, @@ -951,14 +963,14 @@ def create_ui(wrap_gradio_gpu_call): html_info, ] ) - + extras_send_to_img2img.click( fn=lambda x: image_from_url_text(x), _js="extract_image_from_gallery_img2img", inputs=[result_images], outputs=[init_img], ) - + extras_send_to_inpaint.click( fn=lambda x: image_from_url_text(x), _js="extract_image_from_gallery_img2img", @@ -1286,7 +1298,7 @@ Requested path was: {f} outputs=[], _js='function(){restart_reload()}' ) - + if column is not None: column.__exit__() @@ -1318,12 +1330,12 @@ Requested path was: {f} component_dict[k] = component settings_interface.gradio_ref = demo - + with gr.Tabs() as tabs: for interface, label, ifid in interfaces: with gr.TabItem(label, id=ifid): interface.render() - + if os.path.exists(os.path.join(script_path, "notification.mp3")): audio_notification = gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False) @@ -1456,10 +1468,10 @@ Requested path was: {f} if getattr(obj,'custom_script_source',None) is not None: key = 'customscript/' + obj.custom_script_source + '/' + key - + if getattr(obj, 'do_not_save_to_config', False): return - + saved_value = ui_settings.get(key, None) if saved_value is None: ui_settings[key] = getattr(obj, field) @@ -1483,10 +1495,10 @@ Requested path was: {f} if type(x) == gr.Textbox: apply_field(x, 'value') - + if type(x) == gr.Number: apply_field(x, 'value') - + visit(txt2img_interface, loadsave, "txt2img") visit(img2img_interface, loadsave, "img2img") visit(extras_interface, loadsave, "extras") From cc92dc1f8d73dd4d574c4c8ccab78b7fc61e440b Mon Sep 17 00:00:00 2001 From: ssysm Date: Sun, 9 Oct 2022 23:17:29 -0400 Subject: [PATCH 247/460] add vae path args --- modules/sd_models.py | 2 +- modules/shared.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index cb3982b16..b6979432d 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -147,7 +147,7 @@ def load_model_weights(model, checkpoint_info): devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16 - vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt" + vae_file = shared.cmd_opts.vae_path or os.path.splitext(checkpoint_file)[0] + ".vae.pt" if os.path.exists(vae_file): print(f"Loading VAE weights from: {vae_file}") vae_ckpt = torch.load(vae_file, map_location="cpu") diff --git a/modules/shared.py b/modules/shared.py index 2dc092d68..52ccfa6e3 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -64,7 +64,7 @@ parser.add_argument("--autolaunch", action='store_true', help="open the webui UR parser.add_argument("--use-textbox-seed", action='store_true', help="use textbox for seeds in UI (no up/down, but possible to input long seeds)", default=False) parser.add_argument("--disable-console-progressbars", action='store_true', help="do not output progressbars to console", default=False) parser.add_argument("--enable-console-prompts", action='store_true', help="print prompts to console when generating with txt2img and img2img", default=False) - +parser.add_argument('--vae-path', type=str, help='Path to Variational Autoencoders model', default=None) cmd_opts = parser.parse_args() From 1f92336be768d235c18a82acb2195b7135101ae7 Mon Sep 17 00:00:00 2001 From: JC_Array Date: Sun, 9 Oct 2022 23:58:18 -0500 Subject: [PATCH 248/460] refactored the deepbooru module to improve speed on running multiple interogations in a row. Added the option to generate deepbooru tags for textual inversion preproccessing. --- modules/deepbooru.py | 84 +++++++++++++++++++------ modules/textual_inversion/preprocess.py | 22 ++++++- modules/ui.py | 52 ++++++++++----- 3 files changed, 122 insertions(+), 36 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 7e3c06182..cee4a3b4a 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -1,21 +1,74 @@ import os.path from concurrent.futures import ProcessPoolExecutor -from multiprocessing import get_context +import multiprocessing -def _load_tf_and_return_tags(pil_image, threshold): +def get_deepbooru_tags(pil_image, threshold=0.5): + """ + This method is for running only one image at a time for simple use. Used to the img2img interrogate. + """ + from modules import shared # prevents circular reference + create_deepbooru_process(threshold) + shared.deepbooru_process_return["value"] = -1 + shared.deepbooru_process_queue.put(pil_image) + while shared.deepbooru_process_return["value"] == -1: + time.sleep(0.2) + release_process() + return ret + + +def deepbooru_process(queue, deepbooru_process_return, threshold): + model, tags = get_deepbooru_tags_model() + while True: # while process is running, keep monitoring queue for new image + pil_image = queue.get() + if pil_image == "QUIT": + break + else: + deepbooru_process_return["value"] = get_deepbooru_tags_from_model(model, tags, pil_image, threshold) + + +def create_deepbooru_process(threshold=0.5): + """ + Creates deepbooru process. A queue is created to send images into the process. This enables multiple images + to be processed in a row without reloading the model or creating a new process. To return the data, a shared + dictionary is created to hold the tags created. To wait for tags to be returned, a value of -1 is assigned + to the dictionary and the method adding the image to the queue should wait for this value to be updated with + the tags. + """ + from modules import shared # prevents circular reference + shared.deepbooru_process_manager = multiprocessing.Manager() + shared.deepbooru_process_queue = shared.deepbooru_process_manager.Queue() + shared.deepbooru_process_return = shared.deepbooru_process_manager.dict() + shared.deepbooru_process_return["value"] = -1 + shared.deepbooru_process = multiprocessing.Process(target=deepbooru_process, args=(shared.deepbooru_process_queue, shared.deepbooru_process_return, threshold)) + shared.deepbooru_process.start() + + +def release_process(): + """ + Stops the deepbooru process to return used memory + """ + from modules import shared # prevents circular reference + shared.deepbooru_process_queue.put("QUIT") + shared.deepbooru_process.join() + shared.deepbooru_process_queue = None + shared.deepbooru_process = None + shared.deepbooru_process_return = None + shared.deepbooru_process_manager = None + +def get_deepbooru_tags_model(): import deepdanbooru as dd import tensorflow as tf import numpy as np - this_folder = os.path.dirname(__file__) model_path = os.path.abspath(os.path.join(this_folder, '..', 'models', 'deepbooru')) if not os.path.exists(os.path.join(model_path, 'project.json')): # there is no point importing these every time import zipfile from basicsr.utils.download_util import load_file_from_url - load_file_from_url(r"https://github.com/KichangKim/DeepDanbooru/releases/download/v3-20211112-sgd-e28/deepdanbooru-v3-20211112-sgd-e28.zip", - model_path) + load_file_from_url( + r"https://github.com/KichangKim/DeepDanbooru/releases/download/v3-20211112-sgd-e28/deepdanbooru-v3-20211112-sgd-e28.zip", + model_path) with zipfile.ZipFile(os.path.join(model_path, "deepdanbooru-v3-20211112-sgd-e28.zip"), "r") as zip_ref: zip_ref.extractall(model_path) os.remove(os.path.join(model_path, "deepdanbooru-v3-20211112-sgd-e28.zip")) @@ -24,7 +77,13 @@ def _load_tf_and_return_tags(pil_image, threshold): model = dd.project.load_model_from_project( model_path, compile_model=True ) + return model, tags + +def get_deepbooru_tags_from_model(model, tags, pil_image, threshold=0.5): + import deepdanbooru as dd + import tensorflow as tf + import numpy as np width = model.input_shape[2] height = model.input_shape[1] image = np.array(pil_image) @@ -57,17 +116,4 @@ def _load_tf_and_return_tags(pil_image, threshold): print('\n'.join(sorted(result_tags_print, reverse=True))) - return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') - - -def subprocess_init_no_cuda(): - import os - os.environ["CUDA_VISIBLE_DEVICES"] = "-1" - - -def get_deepbooru_tags(pil_image, threshold=0.5): - context = get_context('spawn') - with ProcessPoolExecutor(initializer=subprocess_init_no_cuda, mp_context=context) as executor: - f = executor.submit(_load_tf_and_return_tags, pil_image, threshold, ) - ret = f.result() # will rethrow any exceptions - return ret \ No newline at end of file + return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') \ No newline at end of file diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index f1c002a2b..9f63c9a4f 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -3,11 +3,14 @@ from PIL import Image, ImageOps import platform import sys import tqdm +import time from modules import shared, images +from modules.shared import opts, cmd_opts +if cmd_opts.deepdanbooru: + import modules.deepbooru as deepbooru - -def preprocess(process_src, process_dst, process_flip, process_split, process_caption): +def preprocess(process_src, process_dst, process_flip, process_split, process_caption, process_caption_deepbooru=False): size = 512 src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) @@ -24,10 +27,21 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca if process_caption: shared.interrogator.load() + if process_caption_deepbooru: + deepbooru.create_deepbooru_process() + def save_pic_with_caption(image, index): if process_caption: caption = "-" + shared.interrogator.generate_caption(image) caption = sanitize_caption(os.path.join(dst, f"{index:05}-{subindex[0]}"), caption, ".png") + elif process_caption_deepbooru: + shared.deepbooru_process_return["value"] = -1 + shared.deepbooru_process_queue.put(image) + while shared.deepbooru_process_return["value"] == -1: + time.sleep(0.2) + caption = "-" + shared.deepbooru_process_return["value"] + caption = sanitize_caption(os.path.join(dst, f"{index:05}-{subindex[0]}"), caption, ".png") + shared.deepbooru_process_return["value"] = -1 else: caption = filename caption = os.path.splitext(caption)[0] @@ -79,6 +93,10 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca if process_caption: shared.interrogator.send_blip_to_ram() + if process_caption_deepbooru: + deepbooru.release_process() + + def sanitize_caption(base_path, original_caption, suffix): operating_system = platform.system().lower() if (operating_system == "windows"): diff --git a/modules/ui.py b/modules/ui.py index 2231a8ed8..179e3a83e 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1034,6 +1034,9 @@ def create_ui(wrap_gradio_gpu_call): process_flip = gr.Checkbox(label='Create flipped copies') process_split = gr.Checkbox(label='Split oversized images into two') process_caption = gr.Checkbox(label='Use BLIP caption as filename') + if cmd_opts.deepdanbooru: + process_caption_deepbooru = gr.Checkbox(label='Use deepbooru caption as filename') + with gr.Row(): with gr.Column(scale=3): @@ -1086,21 +1089,40 @@ def create_ui(wrap_gradio_gpu_call): ] ) - run_preprocess.click( - fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), - _js="start_training_textual_inversion", - inputs=[ - process_src, - process_dst, - process_flip, - process_split, - process_caption, - ], - outputs=[ - ti_output, - ti_outcome, - ], - ) + if cmd_opts.deepdanbooru: + # if process_caption_deepbooru is None, it will cause an error, as a result only include it if it is enabled + run_preprocess.click( + fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), + _js="start_training_textual_inversion", + inputs=[ + process_src, + process_dst, + process_flip, + process_split, + process_caption, + process_caption_deepbooru, + ], + outputs=[ + ti_output, + ti_outcome, + ], + ) + else: + run_preprocess.click( + fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), + _js="start_training_textual_inversion", + inputs=[ + process_src, + process_dst, + process_flip, + process_split, + process_caption, + ], + outputs=[ + ti_output, + ti_outcome, + ], + ) train_embedding.click( fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]), From 8acc901ba3a252dc6ab4fabcb41644cf64d1774c Mon Sep 17 00:00:00 2001 From: brkirch Date: Mon, 10 Oct 2022 00:38:55 -0400 Subject: [PATCH 249/460] Newer versions of PyTorch use TypedStorage instead Pytorch 1.13 and later will rename _TypedStorage to TypedStorage, so check for TypedStorage and use _TypedStorage if it is not available. Currently this is needed so that nightly builds of PyTorch work correctly. --- modules/safe.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/safe.py b/modules/safe.py index 4d06f2a53..059174632 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -12,6 +12,10 @@ import _codecs import zipfile +# PyTorch 1.13 and later have _TypedStorage renamed to TypedStorage +TypedStorage = torch.storage.TypedStorage if hasattr(torch.storage, 'TypedStorage') else torch.storage._TypedStorage + + def encode(*args): out = _codecs.encode(*args) return out @@ -20,7 +24,7 @@ def encode(*args): class RestrictedUnpickler(pickle.Unpickler): def persistent_load(self, saved_id): assert saved_id[0] == 'storage' - return torch.storage._TypedStorage() + return TypedStorage() def find_class(self, module, name): if module == 'collections' and name == 'OrderedDict': From 8a7c07a2140c98bceca858087525d77fd0352fda Mon Sep 17 00:00:00 2001 From: yfszzx Date: Mon, 10 Oct 2022 15:39:39 +0800 Subject: [PATCH 250/460] show image history --- javascript/images_history.js | 66 ++++++++++++++++++ javascript/jquery-3.6.0.min.js | 2 + modules/images_history.py | 90 ++++++++++++++++++++++++ modules/ui.py | 11 ++- repositorieslatent-diffusion | 1 + testui.py | 124 +++++++++++++++++++++++++++++++++ 6 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 javascript/images_history.js create mode 100644 javascript/jquery-3.6.0.min.js create mode 100644 modules/images_history.py create mode 160000 repositorieslatent-diffusion create mode 100644 testui.py diff --git a/javascript/images_history.js b/javascript/images_history.js new file mode 100644 index 000000000..f30b7eff3 --- /dev/null +++ b/javascript/images_history.js @@ -0,0 +1,66 @@ +function init_images_history(){ + if (gradioApp().getElementById('txt2img_images_history_first_page') == null) { + setTimeout(init_images_history, 1000) + } else { + tab_list = ["txt2img", "img2img"] + for (i in tab_list){ + tab = tab_list[i] + gradioApp().getElementById(tab + "_images_history_first_page").click() + $(gradioApp().getElementById(tab + '_images_history')).addClass("images_history_gallery") + item = $(gradioApp().getElementById(tab + '_images_history_set_index')) + item.addClass("images_history_set_index") + item.hide() + } + } + +} +setTimeout(init_images_history, 1000) +onUiUpdate(function(){ + fullImg_preview = gradioApp().querySelectorAll('#txt2img_images_history img.w-full') + if(fullImg_preview.length > 0){ + fullImg_preview.forEach(set_history_index_from_img); + } + fullImg_preview = gradioApp().querySelectorAll('#img2img_images_history img.w-full') + if(fullImg_preview.length > 0){ + fullImg_preview.forEach(set_history_index_from_img); + } +}) + +function set_history_gallery_index(item){ + buttons = item.find(".gallery-item") + // alert(item.attr("id") + " " + buttons.length) + index = -1 + i = 0 + buttons.each(function(){ + if($(this).hasClass("!ring-2")){ index = i } + i += 1 + }) + if (index == -1){ + setTimeout(set_history_gallery_index, 10, item) + } else { + item = item.find(".images_history_set_index").first() + item.attr("img_index", index) + item.click() + } +} +function set_history_index_from_img(e){ + if(e && e.parentElement.tagName == 'BUTTON'){ + bnt = $(e).parent() + if (bnt.hasClass("transform")){ + bnt.off("click").on("click",function(){ + set_history_gallery_index($(this).parents(".images_history_gallery").first()) + }) + } else { + bnt.off("mousedown").on("mousedown", function(){ + set_history_gallery_index($(this).parents(".images_history_gallery").first()) + }) + + } + } +} +function images_history_get_current_img(is_image2image){ + head = is_image2image?"img2img":"txt2img" + s = $(gradioApp().getElementById(head + '_images_history_set_index')).attr("img_index") + return s +} + diff --git a/javascript/jquery-3.6.0.min.js b/javascript/jquery-3.6.0.min.js new file mode 100644 index 000000000..c4c6022f2 --- /dev/null +++ b/javascript/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 max_page_index else page_index + idx_frm = (page_index - 1) * num + file_list = file_list[idx_frm:idx_frm + num] + print(f"Loading history page {page_index}") + return [os.path.join(dir_name, file) for file in file_list], page_index, file_list +def first_page_click(is_img2img, dir_name): + return get_recent_images(is_img2img, dir_name, 1, 0) +def end_page_click(is_img2img, dir_name): + return get_recent_images(is_img2img, dir_name, -1, 0) +def prev_page_click(is_img2img, dir_name, page_index): + return get_recent_images(is_img2img, dir_name, page_index, -1) +def next_page_click(is_img2img, dir_name, page_index): + return get_recent_images(is_img2img, dir_name, page_index, 1) +def page_index_change(is_img2img, dir_name, page_index): + return get_recent_images(is_img2img, dir_name, page_index, 0) +def show_image_info(num, filenames): + return filenames[int(num)] +def delete_image(is_img2img, dir_name, name, page_index, filenames): + path = os.path.join(dir_name, name) + if os.path.exists(path): + print(f"Delete file {path}") + os.remove(path) + i = 0 + for f in filenames: + if f == name: + break + i += 1 + images, page_index, file_list = get_recent_images(is_img2img, dir_name, page_index, 0) + current_file = file_list[i] if i < len(file_list) else None + return images, page_index, file_list, current_file + + +def show_images_history(gr, opts, is_img2img): + def id_name(is_img2img, name): + return ("img2img" if is_img2img else "txt2img") + "_" + name + with gr.Row(): + if is_img2img: + dir_name = opts.outdir_img2img_samples + else: + dir_name = opts.outdir_txt2img_samples + first_page = gr.Button('First Page', elem_id=id_name(is_img2img,"images_history_first_page")) + prev_page = gr.Button('Prev Page') + page_index = gr.Number(value=1) + next_page = gr.Button('Next Page') + end_page = gr.Button('End Page') + with gr.Row(): + delete = gr.Button('Delete') + Send = gr.Button('Send') + with gr.Row(): + with gr.Column(elem_id=id_name(is_img2img,"images_history")): + history_gallery = gr.Gallery(label="Images history").style(grid=6) + img_file_name = gr.Textbox() + img_file_info = gr.Textbox(dir_name) + img_path = gr.Textbox(dir_name, visible=False) + set_index = gr.Button('set_index', elem_id=id_name(is_img2img,"images_history_set_index")) + is_img2img_flag = gr.Checkbox(is_img2img, visible=False) + filenames = gr.State() + first_page.click(first_page_click, inputs=[is_img2img_flag, img_path], outputs=[history_gallery, page_index, filenames]) + next_page.click(next_page_click, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index, filenames]) + prev_page.click(prev_page_click, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index, filenames]) + end_page.click(end_page_click, inputs=[is_img2img_flag, img_path], outputs=[history_gallery, page_index, filenames]) + page_index.submit(page_index_change, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index, filenames]) + set_index.click(show_image_info, _js="images_history_get_current_img",inputs=[is_img2img_flag, filenames], outputs=img_file_name) + delete.click(delete_image, inputs=[is_img2img_flag, img_path, img_file_name, page_index, filenames], outputs=[history_gallery, page_index, filenames,img_file_name]) + #page_index.change(page_index_change, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index]) + +def create_history_tabs(gr, opts): + with gr.Blocks(analytics_enabled=False) as images_history: + with gr.Tabs() as tabs: + with gr.Tab("txt2img history", id="images_history_txt2img"): + with gr.Blocks(analytics_enabled=False) as images_history_txt2img: + show_images_history(gr, opts, is_img2img=False) + with gr.Tab("img2img history", id="images_history_img2img"): + with gr.Blocks(analytics_enabled=False) as images_history_img2img: + show_images_history(gr, opts, is_img2img=True) + return images_history diff --git a/modules/ui.py b/modules/ui.py index 4f18126fb..8762fcf54 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -37,6 +37,7 @@ import modules.generation_parameters_copypaste from modules import prompt_parser from modules.images import save_image import modules.textual_inversion.ui +import modules.images_history as img_his # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the bowser will not show any UI mimetypes.init() @@ -499,7 +500,6 @@ def create_ui(wrap_gradio_gpu_call): custom_inputs = modules.scripts.scripts_txt2img.setup_ui(is_img2img=False) with gr.Column(variant='panel'): - with gr.Group(): txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False) txt2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='txt2img_gallery').style(grid=4) @@ -516,6 +516,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Group(): html_info = gr.HTML() generation_info = gr.Textbox(visible=False) + connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) @@ -607,6 +608,7 @@ def create_ui(wrap_gradio_gpu_call): ] modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt) token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) + with gr.Blocks(analytics_enabled=False) as img2img_interface: img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) @@ -696,6 +698,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Group(): html_info = gr.HTML() generation_info = gr.Textbox(visible=False) + connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) @@ -1126,8 +1129,10 @@ def create_ui(wrap_gradio_gpu_call): opts.save(shared.config_filename) - return f'{changed} settings changed.', opts.dumpjson() + return f'{changed} settings changed.', opts.dumpjson() + + images_history = img_his.create_history_tabs(gr, opts) with gr.Blocks(analytics_enabled=False) as settings_interface: settings_submit = gr.Button(value="Apply settings", variant='primary') result = gr.HTML() @@ -1206,7 +1211,9 @@ def create_ui(wrap_gradio_gpu_call): (pnginfo_interface, "PNG Info", "pnginfo"), (modelmerger_interface, "Checkpoint Merger", "modelmerger"), (textual_inversion_interface, "Textual inversion", "ti"), + (images_history, "History", "images_history"), (settings_interface, "Settings", "settings"), + ] with open(os.path.join(script_path, "style.css"), "r", encoding="utf8") as file: diff --git a/repositorieslatent-diffusion b/repositorieslatent-diffusion new file mode 160000 index 000000000..abf33e700 --- /dev/null +++ b/repositorieslatent-diffusion @@ -0,0 +1 @@ +Subproject commit abf33e7002d59d9085081bce93ec798dcabd49af diff --git a/testui.py b/testui.py new file mode 100644 index 000000000..f54e4a622 --- /dev/null +++ b/testui.py @@ -0,0 +1,124 @@ +import os +import threading +import time +import importlib +import signal +import threading + +from modules.paths import script_path + +from modules import devices, sd_samplers +import modules.codeformer_model as codeformer +import modules.extras +import modules.face_restoration +import modules.gfpgan_model as gfpgan +import modules.img2img + +import modules.lowvram +import modules.paths +import modules.scripts +import modules.sd_hijack +import modules.sd_models +import modules.shared as shared +import modules.txt2img + +import modules.ui +from modules import devices +from modules import modelloader +from modules.paths import script_path +from modules.shared import cmd_opts + +modelloader.cleanup_models() +modules.sd_models.setup_model() +codeformer.setup_model(cmd_opts.codeformer_models_path) +gfpgan.setup_model(cmd_opts.gfpgan_models_path) +shared.face_restorers.append(modules.face_restoration.FaceRestoration()) +modelloader.load_upscalers() +queue_lock = threading.Lock() + + +def wrap_queued_call(func): + def f(*args, **kwargs): + with queue_lock: + res = func(*args, **kwargs) + + return res + + return f + + +def wrap_gradio_gpu_call(func, extra_outputs=None): + def f(*args, **kwargs): + devices.torch_gc() + + shared.state.sampling_step = 0 + shared.state.job_count = -1 + shared.state.job_no = 0 + shared.state.job_timestamp = shared.state.get_job_timestamp() + shared.state.current_latent = None + shared.state.current_image = None + shared.state.current_image_sampling_step = 0 + shared.state.interrupted = False + shared.state.textinfo = None + + with queue_lock: + res = func(*args, **kwargs) + + shared.state.job = "" + shared.state.job_count = 0 + + devices.torch_gc() + + return res + + return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) + + +modules.scripts.load_scripts(os.path.join(script_path, "scripts")) + +shared.sd_model = None #modules.sd_models.load_model() +#shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) + + +def webui(): + # make the program just exit at ctrl+c without waiting for anything + def sigint_handler(sig, frame): + print(f'Interrupted with signal {sig} in {frame}') + os._exit(0) + + signal.signal(signal.SIGINT, sigint_handler) + + while 1: + + demo = modules.ui.create_ui(wrap_gradio_gpu_call=wrap_gradio_gpu_call) + + demo.launch( + share=cmd_opts.share, + server_name="0.0.0.0" if cmd_opts.listen else None, + server_port=cmd_opts.port, + debug=cmd_opts.gradio_debug, + auth=[tuple(cred.split(':')) for cred in cmd_opts.gradio_auth.strip('"').split(',')] if cmd_opts.gradio_auth else None, + inbrowser=cmd_opts.autolaunch, + prevent_thread_lock=True + ) + + while 1: + time.sleep(0.5) + if getattr(demo, 'do_restart', False): + time.sleep(0.5) + demo.close() + time.sleep(0.5) + break + + sd_samplers.set_samplers() + + print('Reloading Custom Scripts') + modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) + print('Reloading modules: modules.ui') + importlib.reload(modules.ui) + print('Restarting Gradio') + + + +if __name__ == "__main__": + webui() From 3110f895b2718a3a25aae419fdf5c87c177ec9f4 Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Mon, 10 Oct 2022 17:07:46 +0900 Subject: [PATCH 251/460] Textual Inversion: Added custom training image size and number of repeats per input image in a single epoch --- modules/textual_inversion/dataset.py | 6 +++--- modules/textual_inversion/preprocess.py | 4 ++-- modules/textual_inversion/textual_inversion.py | 15 ++++++++++++--- modules/ui.py | 8 +++++++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index 7c44ea5be..acc4ce597 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -15,13 +15,13 @@ re_tag = re.compile(r"[a-zA-Z][_\w\d()]+") class PersonalizedBase(Dataset): - def __init__(self, data_root, size=None, repeats=100, flip_p=0.5, placeholder_token="*", width=512, height=512, model=None, device=None, template_file=None): + def __init__(self, data_root, size, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None): self.placeholder_token = placeholder_token self.size = size - self.width = width - self.height = height + self.width = size + self.height = size self.flip = transforms.RandomHorizontalFlip(p=flip_p) self.dataset = [] diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index f1c002a2b..b3de6fd7e 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -7,8 +7,8 @@ import tqdm from modules import shared, images -def preprocess(process_src, process_dst, process_flip, process_split, process_caption): - size = 512 +def preprocess(process_src, process_dst, process_size, process_flip, process_split, process_caption): + size = process_size src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index cd9f34984..e34dc2e81 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -6,6 +6,7 @@ import torch import tqdm import html import datetime +import math from modules import shared, devices, sd_hijack, processing, sd_models @@ -156,7 +157,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, create_image_every, save_embedding_every, template_file): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_size, steps, num_repeats, create_image_every, save_embedding_every, template_file): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -182,7 +183,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=512, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=training_size, repeats=num_repeats, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) hijack = sd_hijack.model_hijack @@ -200,6 +201,9 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, if ititial_step > steps: return embedding, filename + tr_img_len = len([os.path.join(data_root, file_path) for file_path in os.listdir(data_root)]) + epoch_len = (tr_img_len * num_repeats) + tr_img_len + pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) for i, (x, text) in pbar: embedding.step = i + ititial_step @@ -223,7 +227,10 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, loss.backward() optimizer.step() - pbar.set_description(f"loss: {losses.mean():.7f}") + epoch_num = math.floor(embedding.step / epoch_len) + epoch_step = embedding.step - (epoch_num * epoch_len) + + pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{epoch_len}]loss: {losses.mean():.7f}") if embedding.step > 0 and embedding_dir is not None and embedding.step % save_embedding_every == 0: last_saved_file = os.path.join(embedding_dir, f'{embedding_name}-{embedding.step}.pt') @@ -236,6 +243,8 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, sd_model=shared.sd_model, prompt=text, steps=20, + height=training_size, + width=training_size, do_not_save_grid=True, do_not_save_samples=True, ) diff --git a/modules/ui.py b/modules/ui.py index 2231a8ed8..f821fd8db 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1029,6 +1029,7 @@ def create_ui(wrap_gradio_gpu_call): process_src = gr.Textbox(label='Source directory') process_dst = gr.Textbox(label='Destination directory') + process_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) with gr.Row(): process_flip = gr.Checkbox(label='Create flipped copies') @@ -1043,13 +1044,15 @@ def create_ui(wrap_gradio_gpu_call): run_preprocess = gr.Button(value="Preprocess", variant='primary') with gr.Group(): - gr.HTML(value="

    Train an embedding; must specify a directory with a set of 512x512 images

    ") + gr.HTML(value="

    Train an embedding; must specify a directory with a set of 1:1 ratio images

    ") train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) learn_rate = gr.Number(label='Learning rate', value=5.0e-03) dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) + training_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) steps = gr.Number(label='Max steps', value=100000, precision=0) + num_repeats = gr.Number(label='Number of repeats for a single input image per epoch', value=100, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) @@ -1092,6 +1095,7 @@ def create_ui(wrap_gradio_gpu_call): inputs=[ process_src, process_dst, + process_size, process_flip, process_split, process_caption, @@ -1110,7 +1114,9 @@ def create_ui(wrap_gradio_gpu_call): learn_rate, dataset_directory, log_directory, + training_size, steps, + num_repeats, create_image_every, save_embedding_every, template_file, From 8ec069e64df48f8f202f8b93a08e91b69448eb39 Mon Sep 17 00:00:00 2001 From: JC_Array Date: Mon, 10 Oct 2022 03:23:24 -0500 Subject: [PATCH 252/460] removed duplicate run_preprocess.click by creating run_preprocess_inputs list and appending deepbooru variable to input list if in scope --- modules/ui.py | 49 +++++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 179e3a83e..22ca74c2c 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1089,40 +1089,25 @@ def create_ui(wrap_gradio_gpu_call): ] ) + run_preprocess_inputs = [ + process_src, + process_dst, + process_flip, + process_split, + process_caption, + ] if cmd_opts.deepdanbooru: # if process_caption_deepbooru is None, it will cause an error, as a result only include it if it is enabled - run_preprocess.click( - fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), - _js="start_training_textual_inversion", - inputs=[ - process_src, - process_dst, - process_flip, - process_split, - process_caption, - process_caption_deepbooru, - ], - outputs=[ - ti_output, - ti_outcome, - ], - ) - else: - run_preprocess.click( - fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), - _js="start_training_textual_inversion", - inputs=[ - process_src, - process_dst, - process_flip, - process_split, - process_caption, - ], - outputs=[ - ti_output, - ti_outcome, - ], - ) + run_preprocess_inputs.append(process_caption_deepbooru) + run_preprocess.click( + fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), + _js="start_training_textual_inversion", + inputs=run_preprocess_inputs, + outputs=[ + ti_output, + ti_outcome, + ], + ) train_embedding.click( fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]), From 4ee7519fc2e459ce8eff1f61f1655afba393357c Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Mon, 10 Oct 2022 17:31:33 +0900 Subject: [PATCH 253/460] Fixed progress bar output for epoch --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index e34dc2e81..769682ea5 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -228,7 +228,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini optimizer.step() epoch_num = math.floor(embedding.step / epoch_len) - epoch_step = embedding.step - (epoch_num * epoch_len) + epoch_step = embedding.step - (epoch_num * epoch_len) + 1 pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{epoch_len}]loss: {losses.mean():.7f}") From 2f94331df2cb1181439adecc28cfd758049f6501 Mon Sep 17 00:00:00 2001 From: JC_Array Date: Mon, 10 Oct 2022 03:34:00 -0500 Subject: [PATCH 254/460] removed change in last commit, simplified to adding the visible argument to process_caption_deepbooru and it set to False if deepdanbooru argument is not set --- modules/ui.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 22ca74c2c..f8adafb38 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1036,7 +1036,8 @@ def create_ui(wrap_gradio_gpu_call): process_caption = gr.Checkbox(label='Use BLIP caption as filename') if cmd_opts.deepdanbooru: process_caption_deepbooru = gr.Checkbox(label='Use deepbooru caption as filename') - + else: + process_caption_deepbooru = gr.Checkbox(label='Use deepbooru caption as filename', visible=False) with gr.Row(): with gr.Column(scale=3): @@ -1089,20 +1090,17 @@ def create_ui(wrap_gradio_gpu_call): ] ) - run_preprocess_inputs = [ - process_src, - process_dst, - process_flip, - process_split, - process_caption, - ] - if cmd_opts.deepdanbooru: - # if process_caption_deepbooru is None, it will cause an error, as a result only include it if it is enabled - run_preprocess_inputs.append(process_caption_deepbooru) run_preprocess.click( fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]), _js="start_training_textual_inversion", - inputs=run_preprocess_inputs, + inputs=[ + process_src, + process_dst, + process_flip, + process_split, + process_caption, + process_caption_deepbooru + ], outputs=[ ti_output, ti_outcome, From 23f2989799ee3911d2959cfceb74b921f20c9a51 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Mon, 10 Oct 2022 18:33:49 +0800 Subject: [PATCH 255/460] images history over --- javascript/images_history.js | 4 +- modules/images_history.py | 141 +++++++++++++++++++++-------------- modules/ui.py | 9 ++- testui.py | 124 ------------------------------ 4 files changed, 94 insertions(+), 184 deletions(-) delete mode 100644 testui.py diff --git a/javascript/images_history.js b/javascript/images_history.js index f30b7eff3..93d2b89ab 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -58,9 +58,9 @@ function set_history_index_from_img(e){ } } } -function images_history_get_current_img(is_image2image){ +function images_history_get_current_img(is_image2image, image_path, files){ head = is_image2image?"img2img":"txt2img" s = $(gradioApp().getElementById(head + '_images_history_set_index')).attr("img_index") - return s + return [s, image_path, files] } diff --git a/modules/images_history.py b/modules/images_history.py index 23d835573..0e0a48f3f 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -1,5 +1,6 @@ import os -def get_recent_images(is_img2img, dir_name, page_index, step): +def get_recent_images(dir_name, page_index, step, image_index): + print(image_index) page_index = int(page_index) f_list = os.listdir(dir_name) file_list = [] @@ -8,7 +9,7 @@ def get_recent_images(is_img2img, dir_name, page_index, step): continue file_list.append(file) file_list = sorted(file_list, key=lambda file: -os.path.getctime(os.path.join(dir_name, file))) - num = 24 + num = 48 max_page_index = len(file_list) // num + 1 page_index = max_page_index if page_index == -1 else page_index + step page_index = 1 if page_index < 1 else page_index @@ -16,75 +17,101 @@ def get_recent_images(is_img2img, dir_name, page_index, step): idx_frm = (page_index - 1) * num file_list = file_list[idx_frm:idx_frm + num] print(f"Loading history page {page_index}") - return [os.path.join(dir_name, file) for file in file_list], page_index, file_list -def first_page_click(is_img2img, dir_name): - return get_recent_images(is_img2img, dir_name, 1, 0) -def end_page_click(is_img2img, dir_name): - return get_recent_images(is_img2img, dir_name, -1, 0) -def prev_page_click(is_img2img, dir_name, page_index): - return get_recent_images(is_img2img, dir_name, page_index, -1) -def next_page_click(is_img2img, dir_name, page_index): - return get_recent_images(is_img2img, dir_name, page_index, 1) -def page_index_change(is_img2img, dir_name, page_index): - return get_recent_images(is_img2img, dir_name, page_index, 0) -def show_image_info(num, filenames): - return filenames[int(num)] -def delete_image(is_img2img, dir_name, name, page_index, filenames): + image_index = int(image_index) + if image_index < 0 or image_index > len(file_list) - 1: + current_file = None + hide_image = None + else: + current_file = file_list[int(image_index)] + hide_image = os.path.join(dir_name, current_file) + return [os.path.join(dir_name, file) for file in file_list], page_index, file_list, current_file, hide_image +def first_page_click(dir_name, page_index, image_index): + return get_recent_images(dir_name, 1, 0, image_index) +def end_page_click(dir_name, page_index, image_index): + return get_recent_images(dir_name, -1, 0, image_index) +def prev_page_click(dir_name, page_index, image_index): + return get_recent_images(dir_name, page_index, -1, image_index) +def next_page_click(dir_name, page_index, image_index): + return get_recent_images(dir_name, page_index, 1, image_index) +def page_index_change(dir_name, page_index, image_index): + return get_recent_images(dir_name, page_index, 0, image_index) + +def show_image_info(num, image_path, filenames): + file = filenames[int(num)] + return file, num, os.path.join(image_path, file) +def delete_image(is_img2img, dir_name, name, page_index, filenames, image_index): + print("filename", name) path = os.path.join(dir_name, name) if os.path.exists(path): print(f"Delete file {path}") os.remove(path) - i = 0 - for f in filenames: - if f == name: - break - i += 1 - images, page_index, file_list = get_recent_images(is_img2img, dir_name, page_index, 0) - current_file = file_list[i] if i < len(file_list) else None - return images, page_index, file_list, current_file + images, page_index, file_list, current_file, hide_image = get_recent_images(dir_name, page_index, 0, image_index) + return images, page_index, file_list, current_file, hide_image -def show_images_history(gr, opts, is_img2img): +def show_images_history(gr, opts, is_img2img, run_pnginfo, switch_dict): def id_name(is_img2img, name): return ("img2img" if is_img2img else "txt2img") + "_" + name - with gr.Row(): - if is_img2img: - dir_name = opts.outdir_img2img_samples - else: - dir_name = opts.outdir_txt2img_samples - first_page = gr.Button('First Page', elem_id=id_name(is_img2img,"images_history_first_page")) - prev_page = gr.Button('Prev Page') - page_index = gr.Number(value=1) - next_page = gr.Button('Next Page') - end_page = gr.Button('End Page') - with gr.Row(): - delete = gr.Button('Delete') - Send = gr.Button('Send') - with gr.Row(): - with gr.Column(elem_id=id_name(is_img2img,"images_history")): - history_gallery = gr.Gallery(label="Images history").style(grid=6) - img_file_name = gr.Textbox() - img_file_info = gr.Textbox(dir_name) - img_path = gr.Textbox(dir_name, visible=False) - set_index = gr.Button('set_index', elem_id=id_name(is_img2img,"images_history_set_index")) - is_img2img_flag = gr.Checkbox(is_img2img, visible=False) - filenames = gr.State() - first_page.click(first_page_click, inputs=[is_img2img_flag, img_path], outputs=[history_gallery, page_index, filenames]) - next_page.click(next_page_click, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index, filenames]) - prev_page.click(prev_page_click, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index, filenames]) - end_page.click(end_page_click, inputs=[is_img2img_flag, img_path], outputs=[history_gallery, page_index, filenames]) - page_index.submit(page_index_change, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index, filenames]) - set_index.click(show_image_info, _js="images_history_get_current_img",inputs=[is_img2img_flag, filenames], outputs=img_file_name) - delete.click(delete_image, inputs=[is_img2img_flag, img_path, img_file_name, page_index, filenames], outputs=[history_gallery, page_index, filenames,img_file_name]) + if is_img2img: + dir_name = opts.outdir_img2img_samples + else: + dir_name = opts.outdir_txt2img_samples + with gr.Row(): + first_page = gr.Button('First', elem_id=id_name(is_img2img,"images_history_first_page")) + prev_page = gr.Button('Prev') + page_index = gr.Number(value=1, label="Page Index") + next_page = gr.Button('Next') + end_page = gr.Button('End') + with gr.Row(elem_id=id_name(is_img2img,"images_history")): + with gr.Row(): + with gr.Column(): + history_gallery = gr.Gallery(show_label=False).style(grid=6) + with gr.Column(): + with gr.Row(): + delete = gr.Button('Delete') + pnginfo_send_to_txt2img = gr.Button('Send to txt2img') + pnginfo_send_to_img2img = gr.Button('Send to img2img') + with gr.Row(): + with gr.Column(): + img_file_info = gr.Textbox(dir_name, label="Generate Info") + img_file_name = gr.Textbox(label="File Name") + with gr.Row(): + # hiden items + img_path = gr.Textbox(dir_name, visible=False) + is_img2img_flag = gr.Checkbox(is_img2img, visible=False) + image_index = gr.Textbox(value=-1, visible=False) + set_index = gr.Button('set_index', elem_id=id_name(is_img2img,"images_history_set_index")) + filenames = gr.State() + hide_image = gr.Image(visible=False, type="pil") + info1 = gr.Textbox(visible=False) + info2 = gr.Textbox(visible=False) + + + # turn pages + gallery_inputs = [img_path, page_index, image_index] + gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hide_image] + first_page.click(first_page_click, inputs=gallery_inputs, outputs=gallery_outputs) + next_page.click(next_page_click, inputs=gallery_inputs, outputs=gallery_outputs) + prev_page.click(prev_page_click, inputs=gallery_inputs, outputs=gallery_outputs) + end_page.click(end_page_click, inputs=gallery_inputs, outputs=gallery_outputs) + page_index.submit(page_index_change, inputs=gallery_inputs, outputs=gallery_outputs) #page_index.change(page_index_change, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index]) + + #other funcitons + set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[is_img2img_flag, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) + delete.click(delete_image, inputs=[is_img2img_flag, img_path, img_file_name, page_index, filenames, image_index], outputs=gallery_outputs) + hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) + switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') + switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') + -def create_history_tabs(gr, opts): +def create_history_tabs(gr, opts, run_pnginfo, switch_dict): with gr.Blocks(analytics_enabled=False) as images_history: with gr.Tabs() as tabs: with gr.Tab("txt2img history", id="images_history_txt2img"): with gr.Blocks(analytics_enabled=False) as images_history_txt2img: - show_images_history(gr, opts, is_img2img=False) + show_images_history(gr, opts, False, run_pnginfo, switch_dict) with gr.Tab("img2img history", id="images_history_img2img"): with gr.Blocks(analytics_enabled=False) as images_history_img2img: - show_images_history(gr, opts, is_img2img=True) + show_images_history(gr, opts, True, run_pnginfo, switch_dict) return images_history diff --git a/modules/ui.py b/modules/ui.py index 8762fcf54..21c9236ba 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1131,8 +1131,15 @@ def create_ui(wrap_gradio_gpu_call): return f'{changed} settings changed.', opts.dumpjson() + #images history + images_history_switch_dict = { + "fn":modules.generation_parameters_copypaste.connect_paste, + "t2i":txt2img_paste_fields, + "i2i":img2img_paste_fields + } + images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict) - images_history = img_his.create_history_tabs(gr, opts) + with gr.Blocks(analytics_enabled=False) as settings_interface: settings_submit = gr.Button(value="Apply settings", variant='primary') result = gr.HTML() diff --git a/testui.py b/testui.py deleted file mode 100644 index f54e4a622..000000000 --- a/testui.py +++ /dev/null @@ -1,124 +0,0 @@ -import os -import threading -import time -import importlib -import signal -import threading - -from modules.paths import script_path - -from modules import devices, sd_samplers -import modules.codeformer_model as codeformer -import modules.extras -import modules.face_restoration -import modules.gfpgan_model as gfpgan -import modules.img2img - -import modules.lowvram -import modules.paths -import modules.scripts -import modules.sd_hijack -import modules.sd_models -import modules.shared as shared -import modules.txt2img - -import modules.ui -from modules import devices -from modules import modelloader -from modules.paths import script_path -from modules.shared import cmd_opts - -modelloader.cleanup_models() -modules.sd_models.setup_model() -codeformer.setup_model(cmd_opts.codeformer_models_path) -gfpgan.setup_model(cmd_opts.gfpgan_models_path) -shared.face_restorers.append(modules.face_restoration.FaceRestoration()) -modelloader.load_upscalers() -queue_lock = threading.Lock() - - -def wrap_queued_call(func): - def f(*args, **kwargs): - with queue_lock: - res = func(*args, **kwargs) - - return res - - return f - - -def wrap_gradio_gpu_call(func, extra_outputs=None): - def f(*args, **kwargs): - devices.torch_gc() - - shared.state.sampling_step = 0 - shared.state.job_count = -1 - shared.state.job_no = 0 - shared.state.job_timestamp = shared.state.get_job_timestamp() - shared.state.current_latent = None - shared.state.current_image = None - shared.state.current_image_sampling_step = 0 - shared.state.interrupted = False - shared.state.textinfo = None - - with queue_lock: - res = func(*args, **kwargs) - - shared.state.job = "" - shared.state.job_count = 0 - - devices.torch_gc() - - return res - - return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) - - -modules.scripts.load_scripts(os.path.join(script_path, "scripts")) - -shared.sd_model = None #modules.sd_models.load_model() -#shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) - - -def webui(): - # make the program just exit at ctrl+c without waiting for anything - def sigint_handler(sig, frame): - print(f'Interrupted with signal {sig} in {frame}') - os._exit(0) - - signal.signal(signal.SIGINT, sigint_handler) - - while 1: - - demo = modules.ui.create_ui(wrap_gradio_gpu_call=wrap_gradio_gpu_call) - - demo.launch( - share=cmd_opts.share, - server_name="0.0.0.0" if cmd_opts.listen else None, - server_port=cmd_opts.port, - debug=cmd_opts.gradio_debug, - auth=[tuple(cred.split(':')) for cred in cmd_opts.gradio_auth.strip('"').split(',')] if cmd_opts.gradio_auth else None, - inbrowser=cmd_opts.autolaunch, - prevent_thread_lock=True - ) - - while 1: - time.sleep(0.5) - if getattr(demo, 'do_restart', False): - time.sleep(0.5) - demo.close() - time.sleep(0.5) - break - - sd_samplers.set_samplers() - - print('Reloading Custom Scripts') - modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) - print('Reloading modules: modules.ui') - importlib.reload(modules.ui) - print('Restarting Gradio') - - - -if __name__ == "__main__": - webui() From a3578233395e585e68c2118d3630cb2a961d4a36 Mon Sep 17 00:00:00 2001 From: Bepis <36346617+bbepis@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:12:29 +1100 Subject: [PATCH 256/460] Add a pull request template --- .../pull_request_template.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 000000000..86009613e --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,28 @@ +# Please read the [contributing wiki page](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Contributing) before submitting a pull request! + +If you have a large change, pay special attention to this paragraph: + +> Before making changes, if you think that your feature will result in more than 100 lines changing, find me and talk to me about the feature you are proposing. It pains me to reject the hard work someone else did, but I won't add everything to the repo, and it's better if the rejection happens before you have to waste time working on the feature. + +Otherwise, after making sure you're following the rules described in wiki page, remove this section and continue on. + +**Describe what this pull request is trying to achieve.** + +A clear and concise description of what you're trying to accomplish with this, so your intent doesn't have to be extracted from your code. + +**Additional notes and description of your changes** + +More technical discussion about your changes go here, plus anything that a maintainer might have to specifically take a look at, or be wary of. + +**Environment this was tested in** + +List the environment you have developed / tested this on. As per the contributing page, changes should be able to work on Windows out of the box. + - OS: [e.g. Windows, Linux] + - Browser [e.g. chrome, safari] + - Graphics card [e.g. NVIDIA RTX 2080 8GB, AMD RX 6600 8GB] + +**Screenshots or videos of your changes** + +If applicable, screenshots or a video showing off your changes. If it edits an existing UI, it should ideally contain a comparison of what used to be there, before your changes were made. + +This is **required** for anything that touches the user interface. \ No newline at end of file From 7349088d32b080f64058b6e5de5f0380a71ecd09 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 10 Oct 2022 16:11:14 +0300 Subject: [PATCH 257/460] --no-half-vae --- modules/devices.py | 6 +++++- modules/processing.py | 11 +++++++++-- modules/sd_models.py | 3 +++ modules/sd_samplers.py | 4 ++-- modules/shared.py | 1 + 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/modules/devices.py b/modules/devices.py index 0158b11fc..03ef58f19 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -36,6 +36,7 @@ errors.run(enable_tf32, "Enabling TF32") device = device_gfpgan = device_bsrgan = device_esrgan = device_scunet = device_codeformer = get_optimal_device() dtype = torch.float16 +dtype_vae = torch.float16 def randn(seed, shape): # Pytorch currently doesn't handle setting randomness correctly when the metal backend is used. @@ -59,9 +60,12 @@ def randn_without_seed(shape): return torch.randn(shape, device=device) -def autocast(): +def autocast(disable=False): from modules import shared + if disable: + return contextlib.nullcontext() + if dtype == torch.float32 or shared.cmd_opts.precision == "full": return contextlib.nullcontext() diff --git a/modules/processing.py b/modules/processing.py index 94d2dd62c..ec8651ae2 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -259,6 +259,13 @@ def create_random_tensors(shape, seeds, subseeds=None, subseed_strength=0.0, see return x +def decode_first_stage(model, x): + with devices.autocast(disable=x.dtype == devices.dtype_vae): + x = model.decode_first_stage(x) + + return x + + def get_fixed_seed(seed): if seed is None or seed == '' or seed == -1: return int(random.randrange(4294967294)) @@ -400,7 +407,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: samples_ddim = samples_ddim.to(devices.dtype) - x_samples_ddim = p.sd_model.decode_first_stage(samples_ddim) + x_samples_ddim = decode_first_stage(p.sd_model, samples_ddim) x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0) del samples_ddim @@ -533,7 +540,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): if self.scale_latent: samples = torch.nn.functional.interpolate(samples, size=(self.height // opt_f, self.width // opt_f), mode="bilinear") else: - decoded_samples = self.sd_model.decode_first_stage(samples) + decoded_samples = decode_first_stage(self.sd_model, samples) if opts.upscaler_for_img2img is None or opts.upscaler_for_img2img == "None": decoded_samples = torch.nn.functional.interpolate(decoded_samples, size=(self.height, self.width), mode="bilinear") diff --git a/modules/sd_models.py b/modules/sd_models.py index e63d3c292..2cdcd84f3 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -149,6 +149,7 @@ def load_model_weights(model, checkpoint_info): model.half() devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16 + devices.dtype_vae = torch.float32 if shared.cmd_opts.no_half or shared.cmd_opts.no_half_vae else torch.float16 vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt" if os.path.exists(vae_file): @@ -158,6 +159,8 @@ def load_model_weights(model, checkpoint_info): model.first_stage_model.load_state_dict(vae_dict) + model.first_stage_model.to(devices.dtype_vae) + model.sd_model_hash = sd_model_hash model.sd_model_checkpoint = checkpoint_file model.sd_checkpoint_info = checkpoint_info diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 6e743f7e9..d168b938f 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -7,7 +7,7 @@ import inspect import k_diffusion.sampling import ldm.models.diffusion.ddim import ldm.models.diffusion.plms -from modules import prompt_parser +from modules import prompt_parser, devices, processing from modules.shared import opts, cmd_opts, state import modules.shared as shared @@ -83,7 +83,7 @@ def setup_img2img_steps(p, steps=None): def sample_to_image(samples): - x_sample = shared.sd_model.decode_first_stage(samples[0:1].type(shared.sd_model.dtype))[0] + x_sample = processing.decode_first_stage(shared.sd_model, samples[0:1])[0] x_sample = torch.clamp((x_sample + 1.0) / 2.0, min=0.0, max=1.0) x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2) x_sample = x_sample.astype(np.uint8) diff --git a/modules/shared.py b/modules/shared.py index 1995a99a7..5dfc344cc 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -25,6 +25,7 @@ parser.add_argument("--ckpt-dir", type=str, default=None, help="Path to director parser.add_argument("--gfpgan-dir", type=str, help="GFPGAN directory", default=('./src/gfpgan' if os.path.exists('./src/gfpgan') else './GFPGAN')) parser.add_argument("--gfpgan-model", type=str, help="GFPGAN model file name", default=None) parser.add_argument("--no-half", action='store_true', help="do not switch the model to 16-bit floats") +parser.add_argument("--no-half-vae", action='store_true', help="do not switch the VAE model to 16-bit floats") parser.add_argument("--no-progressbar-hiding", action='store_true', help="do not hide progressbar in gradio UI (we hide it because it slows down ML if you have hardware acceleration in browser)") parser.add_argument("--max-batch-count", type=int, default=16, help="maximum batch count value for the UI") parser.add_argument("--embeddings-dir", type=str, default=os.path.join(script_path, 'embeddings'), help="embeddings directory for textual inversion (default: embeddings)") From 04c745ea4f81518999927fee5f78500560c25e29 Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Mon, 10 Oct 2022 22:35:35 +0900 Subject: [PATCH 258/460] Custom Width and Height --- modules/textual_inversion/dataset.py | 7 +++---- modules/textual_inversion/preprocess.py | 19 ++++++++++--------- .../textual_inversion/textual_inversion.py | 11 +++++------ modules/ui.py | 12 ++++++++---- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index acc4ce597..bcf772d2f 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -15,13 +15,12 @@ re_tag = re.compile(r"[a-zA-Z][_\w\d()]+") class PersonalizedBase(Dataset): - def __init__(self, data_root, size, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None): + def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None): self.placeholder_token = placeholder_token - self.size = size - self.width = size - self.height = size + self.width = width + self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) self.dataset = [] diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index b3de6fd7e..d7efdef29 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -7,8 +7,9 @@ import tqdm from modules import shared, images -def preprocess(process_src, process_dst, process_size, process_flip, process_split, process_caption): - size = process_size +def preprocess(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption): + width = process_width + height = process_height src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) @@ -55,23 +56,23 @@ def preprocess(process_src, process_dst, process_size, process_flip, process_spl is_wide = ratio < 1 / 1.35 if process_split and is_tall: - img = img.resize((size, size * img.height // img.width)) + img = img.resize((width, height * img.height // img.width)) - top = img.crop((0, 0, size, size)) + top = img.crop((0, 0, width, height)) save_pic(top, index) - bot = img.crop((0, img.height - size, size, img.height)) + bot = img.crop((0, img.height - height, width, img.height)) save_pic(bot, index) elif process_split and is_wide: - img = img.resize((size * img.width // img.height, size)) + img = img.resize((width * img.width // img.height, height)) - left = img.crop((0, 0, size, size)) + left = img.crop((0, 0, width, height)) save_pic(left, index) - right = img.crop((img.width - size, 0, img.width, size)) + right = img.crop((img.width - width, 0, img.width, height)) save_pic(right, index) else: - img = images.resize_image(1, img, size, size) + img = images.resize_image(1, img, width, height) save_pic(img, index) shared.state.nextjob() diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 769682ea5..5965c5a06 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -6,7 +6,6 @@ import torch import tqdm import html import datetime -import math from modules import shared, devices, sd_hijack, processing, sd_models @@ -157,7 +156,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_size, steps, num_repeats, create_image_every, save_embedding_every, template_file): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -183,7 +182,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=training_size, repeats=num_repeats, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=num_repeats, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) hijack = sd_hijack.model_hijack @@ -227,7 +226,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini loss.backward() optimizer.step() - epoch_num = math.floor(embedding.step / epoch_len) + epoch_num = embedding.step // epoch_len epoch_step = embedding.step - (epoch_num * epoch_len) + 1 pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{epoch_len}]loss: {losses.mean():.7f}") @@ -243,8 +242,8 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini sd_model=shared.sd_model, prompt=text, steps=20, - height=training_size, - width=training_size, + height=training_height, + width=training_width, do_not_save_grid=True, do_not_save_samples=True, ) diff --git a/modules/ui.py b/modules/ui.py index f821fd8db..8c06ad7cc 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1029,7 +1029,8 @@ def create_ui(wrap_gradio_gpu_call): process_src = gr.Textbox(label='Source directory') process_dst = gr.Textbox(label='Destination directory') - process_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) + process_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512) + process_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512) with gr.Row(): process_flip = gr.Checkbox(label='Create flipped copies') @@ -1050,7 +1051,8 @@ def create_ui(wrap_gradio_gpu_call): dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) - training_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) + training_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512) + training_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512) steps = gr.Number(label='Max steps', value=100000, precision=0) num_repeats = gr.Number(label='Number of repeats for a single input image per epoch', value=100, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) @@ -1095,7 +1097,8 @@ def create_ui(wrap_gradio_gpu_call): inputs=[ process_src, process_dst, - process_size, + process_width, + process_height, process_flip, process_split, process_caption, @@ -1114,7 +1117,8 @@ def create_ui(wrap_gradio_gpu_call): learn_rate, dataset_directory, log_directory, - training_size, + training_width, + training_height, steps, num_repeats, create_image_every, From 8f1efdc130cf7ff47cb8d3722cdfc0dbeba3069e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 10 Oct 2022 17:03:45 +0300 Subject: [PATCH 259/460] --no-half-vae pt2 --- modules/processing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index ec8651ae2..50ba4fc5f 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -405,8 +405,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed: # use the image collected previously in sampler loop samples_ddim = shared.state.current_latent - samples_ddim = samples_ddim.to(devices.dtype) - + samples_ddim = samples_ddim.to(devices.dtype_vae) x_samples_ddim = decode_first_stage(p.sd_model, samples_ddim) x_samples_ddim = torch.clamp((x_samples_ddim + 1.0) / 2.0, min=0.0, max=1.0) From ea00c1624bbb0dcb5be07f59c9509061baddf5b1 Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Mon, 10 Oct 2022 17:07:46 +0900 Subject: [PATCH 260/460] Textual Inversion: Added custom training image size and number of repeats per input image in a single epoch --- modules/textual_inversion/dataset.py | 6 +++--- modules/textual_inversion/preprocess.py | 4 ++-- modules/textual_inversion/textual_inversion.py | 15 ++++++++++++--- modules/ui.py | 8 +++++++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index 7c44ea5be..acc4ce597 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -15,13 +15,13 @@ re_tag = re.compile(r"[a-zA-Z][_\w\d()]+") class PersonalizedBase(Dataset): - def __init__(self, data_root, size=None, repeats=100, flip_p=0.5, placeholder_token="*", width=512, height=512, model=None, device=None, template_file=None): + def __init__(self, data_root, size, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None): self.placeholder_token = placeholder_token self.size = size - self.width = width - self.height = height + self.width = size + self.height = size self.flip = transforms.RandomHorizontalFlip(p=flip_p) self.dataset = [] diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index f1c002a2b..b3de6fd7e 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -7,8 +7,8 @@ import tqdm from modules import shared, images -def preprocess(process_src, process_dst, process_flip, process_split, process_caption): - size = 512 +def preprocess(process_src, process_dst, process_size, process_flip, process_split, process_caption): + size = process_size src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index cd9f34984..e34dc2e81 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -6,6 +6,7 @@ import torch import tqdm import html import datetime +import math from modules import shared, devices, sd_hijack, processing, sd_models @@ -156,7 +157,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, create_image_every, save_embedding_every, template_file): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_size, steps, num_repeats, create_image_every, save_embedding_every, template_file): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -182,7 +183,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=512, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=training_size, repeats=num_repeats, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) hijack = sd_hijack.model_hijack @@ -200,6 +201,9 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, if ititial_step > steps: return embedding, filename + tr_img_len = len([os.path.join(data_root, file_path) for file_path in os.listdir(data_root)]) + epoch_len = (tr_img_len * num_repeats) + tr_img_len + pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) for i, (x, text) in pbar: embedding.step = i + ititial_step @@ -223,7 +227,10 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, loss.backward() optimizer.step() - pbar.set_description(f"loss: {losses.mean():.7f}") + epoch_num = math.floor(embedding.step / epoch_len) + epoch_step = embedding.step - (epoch_num * epoch_len) + + pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{epoch_len}]loss: {losses.mean():.7f}") if embedding.step > 0 and embedding_dir is not None and embedding.step % save_embedding_every == 0: last_saved_file = os.path.join(embedding_dir, f'{embedding_name}-{embedding.step}.pt') @@ -236,6 +243,8 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, steps, sd_model=shared.sd_model, prompt=text, steps=20, + height=training_size, + width=training_size, do_not_save_grid=True, do_not_save_samples=True, ) diff --git a/modules/ui.py b/modules/ui.py index 2231a8ed8..f821fd8db 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1029,6 +1029,7 @@ def create_ui(wrap_gradio_gpu_call): process_src = gr.Textbox(label='Source directory') process_dst = gr.Textbox(label='Destination directory') + process_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) with gr.Row(): process_flip = gr.Checkbox(label='Create flipped copies') @@ -1043,13 +1044,15 @@ def create_ui(wrap_gradio_gpu_call): run_preprocess = gr.Button(value="Preprocess", variant='primary') with gr.Group(): - gr.HTML(value="

    Train an embedding; must specify a directory with a set of 512x512 images

    ") + gr.HTML(value="

    Train an embedding; must specify a directory with a set of 1:1 ratio images

    ") train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) learn_rate = gr.Number(label='Learning rate', value=5.0e-03) dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) + training_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) steps = gr.Number(label='Max steps', value=100000, precision=0) + num_repeats = gr.Number(label='Number of repeats for a single input image per epoch', value=100, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) @@ -1092,6 +1095,7 @@ def create_ui(wrap_gradio_gpu_call): inputs=[ process_src, process_dst, + process_size, process_flip, process_split, process_caption, @@ -1110,7 +1114,9 @@ def create_ui(wrap_gradio_gpu_call): learn_rate, dataset_directory, log_directory, + training_size, steps, + num_repeats, create_image_every, save_embedding_every, template_file, From 6ad3a53e368d36535de1a4fca73b3bb78fd40654 Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Mon, 10 Oct 2022 17:31:33 +0900 Subject: [PATCH 261/460] Fixed progress bar output for epoch --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index e34dc2e81..769682ea5 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -228,7 +228,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini optimizer.step() epoch_num = math.floor(embedding.step / epoch_len) - epoch_step = embedding.step - (epoch_num * epoch_len) + epoch_step = embedding.step - (epoch_num * epoch_len) + 1 pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{epoch_len}]loss: {losses.mean():.7f}") From 7a20f914eddfdf09c0ccced157ec108205bc3d0f Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Mon, 10 Oct 2022 22:35:35 +0900 Subject: [PATCH 262/460] Custom Width and Height --- modules/textual_inversion/dataset.py | 7 +++---- modules/textual_inversion/preprocess.py | 19 ++++++++++--------- .../textual_inversion/textual_inversion.py | 11 +++++------ modules/ui.py | 12 ++++++++---- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index acc4ce597..bcf772d2f 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -15,13 +15,12 @@ re_tag = re.compile(r"[a-zA-Z][_\w\d()]+") class PersonalizedBase(Dataset): - def __init__(self, data_root, size, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None): + def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None): self.placeholder_token = placeholder_token - self.size = size - self.width = size - self.height = size + self.width = width + self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) self.dataset = [] diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index b3de6fd7e..d7efdef29 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -7,8 +7,9 @@ import tqdm from modules import shared, images -def preprocess(process_src, process_dst, process_size, process_flip, process_split, process_caption): - size = process_size +def preprocess(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption): + width = process_width + height = process_height src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) @@ -55,23 +56,23 @@ def preprocess(process_src, process_dst, process_size, process_flip, process_spl is_wide = ratio < 1 / 1.35 if process_split and is_tall: - img = img.resize((size, size * img.height // img.width)) + img = img.resize((width, height * img.height // img.width)) - top = img.crop((0, 0, size, size)) + top = img.crop((0, 0, width, height)) save_pic(top, index) - bot = img.crop((0, img.height - size, size, img.height)) + bot = img.crop((0, img.height - height, width, img.height)) save_pic(bot, index) elif process_split and is_wide: - img = img.resize((size * img.width // img.height, size)) + img = img.resize((width * img.width // img.height, height)) - left = img.crop((0, 0, size, size)) + left = img.crop((0, 0, width, height)) save_pic(left, index) - right = img.crop((img.width - size, 0, img.width, size)) + right = img.crop((img.width - width, 0, img.width, height)) save_pic(right, index) else: - img = images.resize_image(1, img, size, size) + img = images.resize_image(1, img, width, height) save_pic(img, index) shared.state.nextjob() diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 769682ea5..5965c5a06 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -6,7 +6,6 @@ import torch import tqdm import html import datetime -import math from modules import shared, devices, sd_hijack, processing, sd_models @@ -157,7 +156,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_size, steps, num_repeats, create_image_every, save_embedding_every, template_file): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -183,7 +182,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=training_size, repeats=num_repeats, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=num_repeats, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) hijack = sd_hijack.model_hijack @@ -227,7 +226,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini loss.backward() optimizer.step() - epoch_num = math.floor(embedding.step / epoch_len) + epoch_num = embedding.step // epoch_len epoch_step = embedding.step - (epoch_num * epoch_len) + 1 pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{epoch_len}]loss: {losses.mean():.7f}") @@ -243,8 +242,8 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini sd_model=shared.sd_model, prompt=text, steps=20, - height=training_size, - width=training_size, + height=training_height, + width=training_width, do_not_save_grid=True, do_not_save_samples=True, ) diff --git a/modules/ui.py b/modules/ui.py index f821fd8db..8c06ad7cc 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1029,7 +1029,8 @@ def create_ui(wrap_gradio_gpu_call): process_src = gr.Textbox(label='Source directory') process_dst = gr.Textbox(label='Destination directory') - process_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) + process_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512) + process_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512) with gr.Row(): process_flip = gr.Checkbox(label='Create flipped copies') @@ -1050,7 +1051,8 @@ def create_ui(wrap_gradio_gpu_call): dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) - training_size = gr.Slider(minimum=64, maximum=2048, step=64, label="Size (width and height)", value=512) + training_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512) + training_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512) steps = gr.Number(label='Max steps', value=100000, precision=0) num_repeats = gr.Number(label='Number of repeats for a single input image per epoch', value=100, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) @@ -1095,7 +1097,8 @@ def create_ui(wrap_gradio_gpu_call): inputs=[ process_src, process_dst, - process_size, + process_width, + process_height, process_flip, process_split, process_caption, @@ -1114,7 +1117,8 @@ def create_ui(wrap_gradio_gpu_call): learn_rate, dataset_directory, log_directory, - training_size, + training_width, + training_height, steps, num_repeats, create_image_every, From ce37fdd30e9fc0fe0bc5805a068ce8b11b42b5a3 Mon Sep 17 00:00:00 2001 From: Ben <110583491+TheLastBen@users.noreply.github.com> Date: Sat, 8 Oct 2022 22:03:00 +0100 Subject: [PATCH 263/460] maximize the view --- style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/style.css b/style.css index c0c3f2bb3..04bb9576e 100644 --- a/style.css +++ b/style.css @@ -1,3 +1,7 @@ +.container { + max-width: 100%; +} + .output-html p {margin: 0 0.5em;} .row > *, From 707a431100362645e914042bb344d08439f48ac8 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 15:34:49 +0100 Subject: [PATCH 264/460] add pixel data footer --- .../textual_inversion/textual_inversion.py | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 7a24192e4..6fb64691c 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -12,6 +12,7 @@ from ..images import captionImageOverlay import numpy as np import base64 import json +import zlib from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset @@ -20,7 +21,7 @@ class EmbeddingEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, torch.Tensor): return {'TORCHTENSOR':obj.cpu().detach().numpy().tolist()} - return json.JSONEncoder.default(self, o) + return json.JSONEncoder.default(self, obj) class EmbeddingDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): @@ -38,6 +39,45 @@ def embeddingFromB64(data): d = base64.b64decode(data) return json.loads(d,cls=EmbeddingDecoder) +def appendImageDataFooter(image,data): + d = 3 + data_compressed = zlib.compress( json.dumps(data,cls=EmbeddingEncoder).encode(),level=9) + dnp = np.frombuffer(data_compressed,np.uint8).copy() + w = image.size[0] + next_size = dnp.shape[0] + (w-(dnp.shape[0]%w)) + next_size = next_size + ((w*d)-(next_size%(w*d))) + dnp.resize(next_size) + dnp = dnp.reshape((-1,w,d)) + print(dnp.shape) + im = Image.fromarray(dnp,mode='RGB') + background = Image.new('RGB',(image.size[0],image.size[1]+im.size[1]+1),(0,0,0)) + background.paste(image,(0,0)) + background.paste(im,(0,image.size[1]+1)) + return background + +def crop_black(img,tol=0): + mask = (img>tol).all(2) + mask0,mask1 = mask.any(0),mask.any(1) + col_start,col_end = mask0.argmax(),mask.shape[1]-mask0[::-1].argmax() + row_start,row_end = mask1.argmax(),mask.shape[0]-mask1[::-1].argmax() + return img[row_start:row_end,col_start:col_end] + +def extractImageDataFooter(image): + d=3 + outarr = crop_black(np.array(image.getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) + lastRow = np.where( np.sum(outarr, axis=(1,2))==0) + if lastRow[0].shape[0] == 0: + print('Image data block not found.') + return None + lastRow = lastRow[0] + + lastRow = lastRow.max() + + dataBlock = outarr[lastRow+1::].astype(np.uint8).flatten().tobytes() + print(lastRow) + data = zlib.decompress(dataBlock) + return json.loads(data,cls=EmbeddingDecoder) + class Embedding: def __init__(self, vec, name, step=None): self.vec = vec @@ -113,6 +153,9 @@ class EmbeddingDatabase: if 'sd-ti-embedding' in embed_image.text: data = embeddingFromB64(embed_image.text['sd-ti-embedding']) name = data.get('name',name) + else: + data = extractImageDataFooter(embed_image) + name = data.get('name',name) else: data = torch.load(path, map_location="cpu") @@ -190,7 +233,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -308,6 +351,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini footer_right = '{}'.format(embedding.step) captioned_image = captionImageOverlay(image,title,footer_left,footer_mid,footer_right) + captioned_image = appendImageDataFooter(captioned_image,data) captioned_image.save(last_saved_image_chunks, "PNG", pnginfo=info) From df6d0d9286279c41c4c67460c3158fa268697524 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 15:43:09 +0100 Subject: [PATCH 265/460] convert back to rgb as some hosts add alpha --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 6fb64691c..667a7cf2b 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -64,7 +64,7 @@ def crop_black(img,tol=0): def extractImageDataFooter(image): d=3 - outarr = crop_black(np.array(image.getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) + outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) lastRow = np.where( np.sum(outarr, axis=(1,2))==0) if lastRow[0].shape[0] == 0: print('Image data block not found.') From f347ddfd808c56bb1bacdec0c4bedf826ff85cd8 Mon Sep 17 00:00:00 2001 From: RW21 Date: Mon, 10 Oct 2022 10:44:11 +0900 Subject: [PATCH 266/460] Remove max_batch_count from ui.py --- modules/ui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 8c06ad7cc..8ba84911b 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -524,7 +524,7 @@ def create_ui(wrap_gradio_gpu_call): denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) with gr.Row(): - batch_count = gr.Slider(minimum=1, maximum=cmd_opts.max_batch_count, step=1, label='Batch count', value=1) + batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1) batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1) cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0) @@ -710,7 +710,7 @@ def create_ui(wrap_gradio_gpu_call): tiling = gr.Checkbox(label='Tiling', value=False) with gr.Row(): - batch_count = gr.Slider(minimum=1, maximum=cmd_opts.max_batch_count, step=1, label='Batch count', value=1) + batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1) batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1) with gr.Group(): From b340439586d844e76782149ca1857c8de35773ec Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Mon, 10 Oct 2022 05:28:06 +0100 Subject: [PATCH 267/460] Unlimited Token Works Unlimited tokens actually work now. Works with textual inversion too. Replaces the previous not-so-much-working implementation. --- modules/sd_hijack.py | 69 +++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 437acce4c..8d5c77d89 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -43,10 +43,7 @@ def undo_optimizations(): def get_target_prompt_token_count(token_count): - if token_count < 75: - return 75 - - return math.ceil(token_count / 10) * 10 + return math.ceil(max(token_count, 1) / 75) * 75 class StableDiffusionModelHijack: @@ -127,7 +124,6 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): self.token_mults[ident] = mult def tokenize_line(self, line, used_custom_terms, hijack_comments): - id_start = self.wrapped.tokenizer.bos_token_id id_end = self.wrapped.tokenizer.eos_token_id if opts.enable_emphasis: @@ -154,7 +150,8 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): i += 1 else: emb_len = int(embedding.vec.shape[0]) - fixes.append((len(remade_tokens), embedding)) + iteration = len(remade_tokens) // 75 + fixes.append((iteration, (len(remade_tokens) % 75, embedding))) remade_tokens += [0] * emb_len multipliers += [weight] * emb_len used_custom_terms.append((embedding.name, embedding.checksum())) @@ -162,10 +159,10 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): token_count = len(remade_tokens) prompt_target_length = get_target_prompt_token_count(token_count) - tokens_to_add = prompt_target_length - len(remade_tokens) + 1 + tokens_to_add = prompt_target_length - len(remade_tokens) - remade_tokens = [id_start] + remade_tokens + [id_end] * tokens_to_add - multipliers = [1.0] + multipliers + [1.0] * tokens_to_add + remade_tokens = remade_tokens + [id_end] * tokens_to_add + multipliers = multipliers + [1.0] * tokens_to_add return remade_tokens, fixes, multipliers, token_count @@ -260,29 +257,55 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): hijack_fixes.append(fixes) batch_multipliers.append(multipliers) return batch_multipliers, remade_batch_tokens, used_custom_terms, hijack_comments, hijack_fixes, token_count - + def forward(self, text): - - if opts.use_old_emphasis_implementation: + use_old = opts.use_old_emphasis_implementation + if use_old: batch_multipliers, remade_batch_tokens, used_custom_terms, hijack_comments, hijack_fixes, token_count = self.process_text_old(text) else: batch_multipliers, remade_batch_tokens, used_custom_terms, hijack_comments, hijack_fixes, token_count = self.process_text(text) - self.hijack.fixes = hijack_fixes self.hijack.comments += hijack_comments if len(used_custom_terms) > 0: self.hijack.comments.append("Used embeddings: " + ", ".join([f'{word} [{checksum}]' for word, checksum in used_custom_terms])) + + if use_old: + self.hijack.fixes = hijack_fixes + return self.process_tokens(remade_batch_tokens, batch_multipliers) + + z = None + i = 0 + while max(map(len, remade_batch_tokens)) != 0: + rem_tokens = [x[75:] for x in remade_batch_tokens] + rem_multipliers = [x[75:] for x in batch_multipliers] + + self.hijack.fixes = [] + for unfiltered in hijack_fixes: + fixes = [] + for fix in unfiltered: + if fix[0] == i: + fixes.append(fix[1]) + self.hijack.fixes.append(fixes) + + z1 = self.process_tokens([x[:75] for x in remade_batch_tokens], [x[:75] for x in batch_multipliers]) + z = z1 if z is None else torch.cat((z, z1), axis=-2) + + remade_batch_tokens = rem_tokens + batch_multipliers = rem_multipliers + i += 1 + + return z + + + def process_tokens(self, remade_batch_tokens, batch_multipliers): + if not opts.use_old_emphasis_implementation: + remade_batch_tokens = [[self.wrapped.tokenizer.bos_token_id] + x[:75] + [self.wrapped.tokenizer.eos_token_id] for x in remade_batch_tokens] + batch_multipliers = [[1.0] + x[:75] + [1.0] for x in batch_multipliers] + + tokens = torch.asarray(remade_batch_tokens).to(device) + outputs = self.wrapped.transformer(input_ids=tokens) - target_token_count = get_target_prompt_token_count(token_count) + 2 - - position_ids_array = [min(x, 75) for x in range(target_token_count-1)] + [76] - position_ids = torch.asarray(position_ids_array, device=devices.device).expand((1, -1)) - - remade_batch_tokens_of_same_length = [x + [self.wrapped.tokenizer.eos_token_id] * (target_token_count - len(x)) for x in remade_batch_tokens] - tokens = torch.asarray(remade_batch_tokens_of_same_length).to(device) - - outputs = self.wrapped.transformer(input_ids=tokens, position_ids=position_ids, output_hidden_states=-opts.CLIP_stop_at_last_layers) if opts.CLIP_stop_at_last_layers > 1: z = outputs.hidden_states[-opts.CLIP_stop_at_last_layers] z = self.wrapped.transformer.text_model.final_layer_norm(z) @@ -290,7 +313,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): z = outputs.last_hidden_state # restoring original mean is likely not correct, but it seems to work well to prevent artifacts that happen otherwise - batch_multipliers_of_same_length = [x + [1.0] * (target_token_count - len(x)) for x in batch_multipliers] + batch_multipliers_of_same_length = [x + [1.0] * (75 - len(x)) for x in batch_multipliers] batch_multipliers = torch.asarray(batch_multipliers_of_same_length).to(device) original_mean = z.mean() z *= batch_multipliers.reshape(batch_multipliers.shape + (1,)).expand(z.shape) From 460bbae58726c177beddfcddf351f27e205d3fb2 Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Mon, 10 Oct 2022 16:09:06 +0100 Subject: [PATCH 268/460] Pad beginning of textual inversion embedding --- modules/sd_hijack.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 8d5c77d89..3a60cd635 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -151,6 +151,11 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): else: emb_len = int(embedding.vec.shape[0]) iteration = len(remade_tokens) // 75 + if (len(remade_tokens) + emb_len) // 75 != iteration: + rem = (75 * (iteration + 1) - len(remade_tokens)) + remade_tokens += [id_end] * rem + multipliers += [1.0] * rem + iteration += 1 fixes.append((iteration, (len(remade_tokens) % 75, embedding))) remade_tokens += [0] * emb_len multipliers += [weight] * emb_len From d5c14365fd468dbf89fa12a68bea5b217077273c Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Mon, 10 Oct 2022 16:13:47 +0100 Subject: [PATCH 269/460] Add back in output hidden states parameter --- modules/sd_hijack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 3a60cd635..3edc0e9d8 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -309,7 +309,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): batch_multipliers = [[1.0] + x[:75] + [1.0] for x in batch_multipliers] tokens = torch.asarray(remade_batch_tokens).to(device) - outputs = self.wrapped.transformer(input_ids=tokens) + outputs = self.wrapped.transformer(input_ids=tokens, output_hidden_states=-opts.CLIP_stop_at_last_layers) if opts.CLIP_stop_at_last_layers > 1: z = outputs.hidden_states[-opts.CLIP_stop_at_last_layers] From 6c36fe5719a824fa18f6ad3e02727783f095bc5f Mon Sep 17 00:00:00 2001 From: Melan Date: Mon, 10 Oct 2022 18:16:04 +0200 Subject: [PATCH 270/460] Add ctrl+enter as a shortcut to quickly start a generation. --- script.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/script.js b/script.js index cf9896053..a92c0f77d 100644 --- a/script.js +++ b/script.js @@ -40,6 +40,22 @@ document.addEventListener("DOMContentLoaded", function() { mutationObserver.observe( gradioApp(), { childList:true, subtree:true }) }); +/** + * Add a ctrl+enter as a shortcut to start a generation + */ + document.addEventListener('keydown', function(e) { + var handled = false; + if (e.key !== undefined) { + if((e.key == "Enter" && (e.metaKey || e.ctrlKey))) handled = true; + } else if (e.keyCode !== undefined) { + if((e.keyCode == 13 && (e.metaKey || e.ctrlKey))) handled = true; + } + if (handled) { + gradioApp().querySelector("#txt2img_generate").click(); + e.preventDefault(); + } +}) + /** * checks that a UI element is not in another hidden element or tab content */ From 9d33baba587637815d818e5e641d8f8b74c4900d Mon Sep 17 00:00:00 2001 From: Vladimir Repin <32306715+mezotaken@users.noreply.github.com> Date: Mon, 10 Oct 2022 18:46:48 +0300 Subject: [PATCH 271/460] Always show previous mask and fix extras_send dest --- modules/ui.py | 2 +- style.css | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index 8ba84911b..e8039d76c 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -961,7 +961,7 @@ def create_ui(wrap_gradio_gpu_call): extras_send_to_inpaint.click( fn=lambda x: image_from_url_text(x), - _js="extract_image_from_gallery_img2img", + _js="extract_image_from_gallery_inpaint", inputs=[result_images], outputs=[init_img_with_mask], ) diff --git a/style.css b/style.css index 04bb9576e..00a3d07fe 100644 --- a/style.css +++ b/style.css @@ -467,3 +467,10 @@ input[type="range"]{ max-width: 32em; padding: 0; } + +canvas[key="mask"] { + z-index: 12 !important; + filter: invert(); + mix-blend-mode: multiply; + pointer-events: none; +} From b8c38f2bbfa28904f67f0c4f9cabab4d85ebced2 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Mon, 10 Oct 2022 17:44:58 +0300 Subject: [PATCH 272/460] change prebuilt wheel --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index f42f557de..e1000f559 100644 --- a/launch.py +++ b/launch.py @@ -127,7 +127,7 @@ def prepare_enviroment(): if not is_installed("xformers") and xformers and platform.python_version().startswith("3.10"): if platform.system() == "Windows": - run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/a/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") + run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/c/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") elif platform.system() == "Linux": run_pip("install xformers", "xformers") From 623251ce2b8d152e242011f62984a8247a14a389 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Mon, 10 Oct 2022 17:45:38 +0300 Subject: [PATCH 273/460] allow pascal onwards --- modules/sd_hijack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 3edc0e9d8..827bf3045 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -23,7 +23,7 @@ def apply_optimizations(): ldm.modules.diffusionmodules.model.nonlinearity = silu - if cmd_opts.force_enable_xformers or (cmd_opts.xformers and shared.xformers_available and torch.version.cuda and torch.cuda.get_device_capability(shared.device) == (8, 6)): + if cmd_opts.force_enable_xformers or (cmd_opts.xformers and shared.xformers_available and torch.version.cuda and (6, 0) <= torch.cuda.get_device_capability(shared.device) <= (8, 6)): print("Applying xformers cross attention optimization.") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward From 3e7a981194ed9c454e951365846e4eba66fa7095 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Mon, 10 Oct 2022 17:51:05 +0300 Subject: [PATCH 274/460] remove functorch --- modules/sd_hijack_optimizations.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 634fb4b24..18408e629 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -13,8 +13,6 @@ from modules import shared if shared.cmd_opts.xformers or shared.cmd_opts.force_enable_xformers: try: import xformers.ops - import functorch - xformers._is_functorch_available = True shared.xformers_available = True except Exception: print("Cannot import xformers", file=sys.stderr) From 5c3254b3ee62ef46cb2e3a6ed14182efeb868f30 Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Mon, 10 Oct 2022 17:51:41 +0300 Subject: [PATCH 275/460] Update requirements.txt --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 81641d68f..631fe616a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,4 +23,3 @@ resize-right torchdiffeq kornia lark -functorch From e37d0cdd06772c8d6edb2272c0ef25c46c74cc6d Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Mon, 10 Oct 2022 17:51:53 +0300 Subject: [PATCH 276/460] Update requirements_versions.txt --- requirements_versions.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements_versions.txt b/requirements_versions.txt index fec3e9d5b..fdff26878 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -22,4 +22,3 @@ resize-right==0.0.2 torchdiffeq==0.2.3 kornia==0.6.7 lark==1.1.2 -functorch==0.2.1 From ece27fe98933eb0eda8ea94dc496dd7554f3a08f Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sun, 9 Oct 2022 18:55:33 +0300 Subject: [PATCH 277/460] Add files via upload --- modules/swinir_model_arch_v2.py | 1017 +++++++++++++++++++++++++++++++ 1 file changed, 1017 insertions(+) create mode 100644 modules/swinir_model_arch_v2.py diff --git a/modules/swinir_model_arch_v2.py b/modules/swinir_model_arch_v2.py new file mode 100644 index 000000000..0e28ae6ee --- /dev/null +++ b/modules/swinir_model_arch_v2.py @@ -0,0 +1,1017 @@ +# ----------------------------------------------------------------------------------- +# Swin2SR: Swin2SR: SwinV2 Transformer for Compressed Image Super-Resolution and Restoration, https://arxiv.org/abs/ +# Written by Conde and Choi et al. +# ----------------------------------------------------------------------------------- + +import math +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.utils.checkpoint as checkpoint +from timm.models.layers import DropPath, to_2tuple, trunc_normal_ + + +class Mlp(nn.Module): + def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.): + super().__init__() + out_features = out_features or in_features + hidden_features = hidden_features or in_features + self.fc1 = nn.Linear(in_features, hidden_features) + self.act = act_layer() + self.fc2 = nn.Linear(hidden_features, out_features) + self.drop = nn.Dropout(drop) + + def forward(self, x): + x = self.fc1(x) + x = self.act(x) + x = self.drop(x) + x = self.fc2(x) + x = self.drop(x) + return x + + +def window_partition(x, window_size): + """ + Args: + x: (B, H, W, C) + window_size (int): window size + Returns: + windows: (num_windows*B, window_size, window_size, C) + """ + B, H, W, C = x.shape + x = x.view(B, H // window_size, window_size, W // window_size, window_size, C) + windows = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(-1, window_size, window_size, C) + return windows + + +def window_reverse(windows, window_size, H, W): + """ + Args: + windows: (num_windows*B, window_size, window_size, C) + window_size (int): Window size + H (int): Height of image + W (int): Width of image + Returns: + x: (B, H, W, C) + """ + B = int(windows.shape[0] / (H * W / window_size / window_size)) + x = windows.view(B, H // window_size, W // window_size, window_size, window_size, -1) + x = x.permute(0, 1, 3, 2, 4, 5).contiguous().view(B, H, W, -1) + return x + +class WindowAttention(nn.Module): + r""" Window based multi-head self attention (W-MSA) module with relative position bias. + It supports both of shifted and non-shifted window. + Args: + dim (int): Number of input channels. + window_size (tuple[int]): The height and width of the window. + num_heads (int): Number of attention heads. + qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True + attn_drop (float, optional): Dropout ratio of attention weight. Default: 0.0 + proj_drop (float, optional): Dropout ratio of output. Default: 0.0 + pretrained_window_size (tuple[int]): The height and width of the window in pre-training. + """ + + def __init__(self, dim, window_size, num_heads, qkv_bias=True, attn_drop=0., proj_drop=0., + pretrained_window_size=[0, 0]): + + super().__init__() + self.dim = dim + self.window_size = window_size # Wh, Ww + self.pretrained_window_size = pretrained_window_size + self.num_heads = num_heads + + self.logit_scale = nn.Parameter(torch.log(10 * torch.ones((num_heads, 1, 1))), requires_grad=True) + + # mlp to generate continuous relative position bias + self.cpb_mlp = nn.Sequential(nn.Linear(2, 512, bias=True), + nn.ReLU(inplace=True), + nn.Linear(512, num_heads, bias=False)) + + # get relative_coords_table + relative_coords_h = torch.arange(-(self.window_size[0] - 1), self.window_size[0], dtype=torch.float32) + relative_coords_w = torch.arange(-(self.window_size[1] - 1), self.window_size[1], dtype=torch.float32) + relative_coords_table = torch.stack( + torch.meshgrid([relative_coords_h, + relative_coords_w])).permute(1, 2, 0).contiguous().unsqueeze(0) # 1, 2*Wh-1, 2*Ww-1, 2 + if pretrained_window_size[0] > 0: + relative_coords_table[:, :, :, 0] /= (pretrained_window_size[0] - 1) + relative_coords_table[:, :, :, 1] /= (pretrained_window_size[1] - 1) + else: + relative_coords_table[:, :, :, 0] /= (self.window_size[0] - 1) + relative_coords_table[:, :, :, 1] /= (self.window_size[1] - 1) + relative_coords_table *= 8 # normalize to -8, 8 + relative_coords_table = torch.sign(relative_coords_table) * torch.log2( + torch.abs(relative_coords_table) + 1.0) / np.log2(8) + + self.register_buffer("relative_coords_table", relative_coords_table) + + # get pair-wise relative position index for each token inside the window + coords_h = torch.arange(self.window_size[0]) + coords_w = torch.arange(self.window_size[1]) + coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww + coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww + relative_coords = coords_flatten[:, :, None] - coords_flatten[:, None, :] # 2, Wh*Ww, Wh*Ww + relative_coords = relative_coords.permute(1, 2, 0).contiguous() # Wh*Ww, Wh*Ww, 2 + relative_coords[:, :, 0] += self.window_size[0] - 1 # shift to start from 0 + relative_coords[:, :, 1] += self.window_size[1] - 1 + relative_coords[:, :, 0] *= 2 * self.window_size[1] - 1 + relative_position_index = relative_coords.sum(-1) # Wh*Ww, Wh*Ww + self.register_buffer("relative_position_index", relative_position_index) + + self.qkv = nn.Linear(dim, dim * 3, bias=False) + if qkv_bias: + self.q_bias = nn.Parameter(torch.zeros(dim)) + self.v_bias = nn.Parameter(torch.zeros(dim)) + else: + self.q_bias = None + self.v_bias = None + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(dim, dim) + self.proj_drop = nn.Dropout(proj_drop) + self.softmax = nn.Softmax(dim=-1) + + def forward(self, x, mask=None): + """ + Args: + x: input features with shape of (num_windows*B, N, C) + mask: (0/-inf) mask with shape of (num_windows, Wh*Ww, Wh*Ww) or None + """ + B_, N, C = x.shape + qkv_bias = None + if self.q_bias is not None: + qkv_bias = torch.cat((self.q_bias, torch.zeros_like(self.v_bias, requires_grad=False), self.v_bias)) + qkv = F.linear(input=x, weight=self.qkv.weight, bias=qkv_bias) + qkv = qkv.reshape(B_, N, 3, self.num_heads, -1).permute(2, 0, 3, 1, 4) + q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple) + + # cosine attention + attn = (F.normalize(q, dim=-1) @ F.normalize(k, dim=-1).transpose(-2, -1)) + logit_scale = torch.clamp(self.logit_scale, max=torch.log(torch.tensor(1. / 0.01)).to(self.logit_scale.device)).exp() + attn = attn * logit_scale + + relative_position_bias_table = self.cpb_mlp(self.relative_coords_table).view(-1, self.num_heads) + relative_position_bias = relative_position_bias_table[self.relative_position_index.view(-1)].view( + self.window_size[0] * self.window_size[1], self.window_size[0] * self.window_size[1], -1) # Wh*Ww,Wh*Ww,nH + relative_position_bias = relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww + relative_position_bias = 16 * torch.sigmoid(relative_position_bias) + attn = attn + relative_position_bias.unsqueeze(0) + + if mask is not None: + nW = mask.shape[0] + attn = attn.view(B_ // nW, nW, self.num_heads, N, N) + mask.unsqueeze(1).unsqueeze(0) + attn = attn.view(-1, self.num_heads, N, N) + attn = self.softmax(attn) + else: + attn = self.softmax(attn) + + attn = self.attn_drop(attn) + + x = (attn @ v).transpose(1, 2).reshape(B_, N, C) + x = self.proj(x) + x = self.proj_drop(x) + return x + + def extra_repr(self) -> str: + return f'dim={self.dim}, window_size={self.window_size}, ' \ + f'pretrained_window_size={self.pretrained_window_size}, num_heads={self.num_heads}' + + def flops(self, N): + # calculate flops for 1 window with token length of N + flops = 0 + # qkv = self.qkv(x) + flops += N * self.dim * 3 * self.dim + # attn = (q @ k.transpose(-2, -1)) + flops += self.num_heads * N * (self.dim // self.num_heads) * N + # x = (attn @ v) + flops += self.num_heads * N * N * (self.dim // self.num_heads) + # x = self.proj(x) + flops += N * self.dim * self.dim + return flops + +class SwinTransformerBlock(nn.Module): + r""" Swin Transformer Block. + Args: + dim (int): Number of input channels. + input_resolution (tuple[int]): Input resulotion. + num_heads (int): Number of attention heads. + window_size (int): Window size. + shift_size (int): Shift size for SW-MSA. + mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. + qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True + drop (float, optional): Dropout rate. Default: 0.0 + attn_drop (float, optional): Attention dropout rate. Default: 0.0 + drop_path (float, optional): Stochastic depth rate. Default: 0.0 + act_layer (nn.Module, optional): Activation layer. Default: nn.GELU + norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm + pretrained_window_size (int): Window size in pre-training. + """ + + def __init__(self, dim, input_resolution, num_heads, window_size=7, shift_size=0, + mlp_ratio=4., qkv_bias=True, drop=0., attn_drop=0., drop_path=0., + act_layer=nn.GELU, norm_layer=nn.LayerNorm, pretrained_window_size=0): + super().__init__() + self.dim = dim + self.input_resolution = input_resolution + self.num_heads = num_heads + self.window_size = window_size + self.shift_size = shift_size + self.mlp_ratio = mlp_ratio + if min(self.input_resolution) <= self.window_size: + # if window size is larger than input resolution, we don't partition windows + self.shift_size = 0 + self.window_size = min(self.input_resolution) + assert 0 <= self.shift_size < self.window_size, "shift_size must in 0-window_size" + + self.norm1 = norm_layer(dim) + self.attn = WindowAttention( + dim, window_size=to_2tuple(self.window_size), num_heads=num_heads, + qkv_bias=qkv_bias, attn_drop=attn_drop, proj_drop=drop, + pretrained_window_size=to_2tuple(pretrained_window_size)) + + self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity() + self.norm2 = norm_layer(dim) + mlp_hidden_dim = int(dim * mlp_ratio) + self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop) + + if self.shift_size > 0: + attn_mask = self.calculate_mask(self.input_resolution) + else: + attn_mask = None + + self.register_buffer("attn_mask", attn_mask) + + def calculate_mask(self, x_size): + # calculate attention mask for SW-MSA + H, W = x_size + img_mask = torch.zeros((1, H, W, 1)) # 1 H W 1 + h_slices = (slice(0, -self.window_size), + slice(-self.window_size, -self.shift_size), + slice(-self.shift_size, None)) + w_slices = (slice(0, -self.window_size), + slice(-self.window_size, -self.shift_size), + slice(-self.shift_size, None)) + cnt = 0 + for h in h_slices: + for w in w_slices: + img_mask[:, h, w, :] = cnt + cnt += 1 + + mask_windows = window_partition(img_mask, self.window_size) # nW, window_size, window_size, 1 + mask_windows = mask_windows.view(-1, self.window_size * self.window_size) + attn_mask = mask_windows.unsqueeze(1) - mask_windows.unsqueeze(2) + attn_mask = attn_mask.masked_fill(attn_mask != 0, float(-100.0)).masked_fill(attn_mask == 0, float(0.0)) + + return attn_mask + + def forward(self, x, x_size): + H, W = x_size + B, L, C = x.shape + #assert L == H * W, "input feature has wrong size" + + shortcut = x + x = x.view(B, H, W, C) + + # cyclic shift + if self.shift_size > 0: + shifted_x = torch.roll(x, shifts=(-self.shift_size, -self.shift_size), dims=(1, 2)) + else: + shifted_x = x + + # partition windows + x_windows = window_partition(shifted_x, self.window_size) # nW*B, window_size, window_size, C + x_windows = x_windows.view(-1, self.window_size * self.window_size, C) # nW*B, window_size*window_size, C + + # W-MSA/SW-MSA (to be compatible for testing on images whose shapes are the multiple of window size + if self.input_resolution == x_size: + attn_windows = self.attn(x_windows, mask=self.attn_mask) # nW*B, window_size*window_size, C + else: + attn_windows = self.attn(x_windows, mask=self.calculate_mask(x_size).to(x.device)) + + # merge windows + attn_windows = attn_windows.view(-1, self.window_size, self.window_size, C) + shifted_x = window_reverse(attn_windows, self.window_size, H, W) # B H' W' C + + # reverse cyclic shift + if self.shift_size > 0: + x = torch.roll(shifted_x, shifts=(self.shift_size, self.shift_size), dims=(1, 2)) + else: + x = shifted_x + x = x.view(B, H * W, C) + x = shortcut + self.drop_path(self.norm1(x)) + + # FFN + x = x + self.drop_path(self.norm2(self.mlp(x))) + + return x + + def extra_repr(self) -> str: + return f"dim={self.dim}, input_resolution={self.input_resolution}, num_heads={self.num_heads}, " \ + f"window_size={self.window_size}, shift_size={self.shift_size}, mlp_ratio={self.mlp_ratio}" + + def flops(self): + flops = 0 + H, W = self.input_resolution + # norm1 + flops += self.dim * H * W + # W-MSA/SW-MSA + nW = H * W / self.window_size / self.window_size + flops += nW * self.attn.flops(self.window_size * self.window_size) + # mlp + flops += 2 * H * W * self.dim * self.dim * self.mlp_ratio + # norm2 + flops += self.dim * H * W + return flops + +class PatchMerging(nn.Module): + r""" Patch Merging Layer. + Args: + input_resolution (tuple[int]): Resolution of input feature. + dim (int): Number of input channels. + norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm + """ + + def __init__(self, input_resolution, dim, norm_layer=nn.LayerNorm): + super().__init__() + self.input_resolution = input_resolution + self.dim = dim + self.reduction = nn.Linear(4 * dim, 2 * dim, bias=False) + self.norm = norm_layer(2 * dim) + + def forward(self, x): + """ + x: B, H*W, C + """ + H, W = self.input_resolution + B, L, C = x.shape + assert L == H * W, "input feature has wrong size" + assert H % 2 == 0 and W % 2 == 0, f"x size ({H}*{W}) are not even." + + x = x.view(B, H, W, C) + + x0 = x[:, 0::2, 0::2, :] # B H/2 W/2 C + x1 = x[:, 1::2, 0::2, :] # B H/2 W/2 C + x2 = x[:, 0::2, 1::2, :] # B H/2 W/2 C + x3 = x[:, 1::2, 1::2, :] # B H/2 W/2 C + x = torch.cat([x0, x1, x2, x3], -1) # B H/2 W/2 4*C + x = x.view(B, -1, 4 * C) # B H/2*W/2 4*C + + x = self.reduction(x) + x = self.norm(x) + + return x + + def extra_repr(self) -> str: + return f"input_resolution={self.input_resolution}, dim={self.dim}" + + def flops(self): + H, W = self.input_resolution + flops = (H // 2) * (W // 2) * 4 * self.dim * 2 * self.dim + flops += H * W * self.dim // 2 + return flops + +class BasicLayer(nn.Module): + """ A basic Swin Transformer layer for one stage. + Args: + dim (int): Number of input channels. + input_resolution (tuple[int]): Input resolution. + depth (int): Number of blocks. + num_heads (int): Number of attention heads. + window_size (int): Local window size. + mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. + qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True + drop (float, optional): Dropout rate. Default: 0.0 + attn_drop (float, optional): Attention dropout rate. Default: 0.0 + drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0 + norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm + downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None + use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False. + pretrained_window_size (int): Local window size in pre-training. + """ + + def __init__(self, dim, input_resolution, depth, num_heads, window_size, + mlp_ratio=4., qkv_bias=True, drop=0., attn_drop=0., + drop_path=0., norm_layer=nn.LayerNorm, downsample=None, use_checkpoint=False, + pretrained_window_size=0): + + super().__init__() + self.dim = dim + self.input_resolution = input_resolution + self.depth = depth + self.use_checkpoint = use_checkpoint + + # build blocks + self.blocks = nn.ModuleList([ + SwinTransformerBlock(dim=dim, input_resolution=input_resolution, + num_heads=num_heads, window_size=window_size, + shift_size=0 if (i % 2 == 0) else window_size // 2, + mlp_ratio=mlp_ratio, + qkv_bias=qkv_bias, + drop=drop, attn_drop=attn_drop, + drop_path=drop_path[i] if isinstance(drop_path, list) else drop_path, + norm_layer=norm_layer, + pretrained_window_size=pretrained_window_size) + for i in range(depth)]) + + # patch merging layer + if downsample is not None: + self.downsample = downsample(input_resolution, dim=dim, norm_layer=norm_layer) + else: + self.downsample = None + + def forward(self, x, x_size): + for blk in self.blocks: + if self.use_checkpoint: + x = checkpoint.checkpoint(blk, x, x_size) + else: + x = blk(x, x_size) + if self.downsample is not None: + x = self.downsample(x) + return x + + def extra_repr(self) -> str: + return f"dim={self.dim}, input_resolution={self.input_resolution}, depth={self.depth}" + + def flops(self): + flops = 0 + for blk in self.blocks: + flops += blk.flops() + if self.downsample is not None: + flops += self.downsample.flops() + return flops + + def _init_respostnorm(self): + for blk in self.blocks: + nn.init.constant_(blk.norm1.bias, 0) + nn.init.constant_(blk.norm1.weight, 0) + nn.init.constant_(blk.norm2.bias, 0) + nn.init.constant_(blk.norm2.weight, 0) + +class PatchEmbed(nn.Module): + r""" Image to Patch Embedding + Args: + img_size (int): Image size. Default: 224. + patch_size (int): Patch token size. Default: 4. + in_chans (int): Number of input image channels. Default: 3. + embed_dim (int): Number of linear projection output channels. Default: 96. + norm_layer (nn.Module, optional): Normalization layer. Default: None + """ + + def __init__(self, img_size=224, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None): + super().__init__() + img_size = to_2tuple(img_size) + patch_size = to_2tuple(patch_size) + patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]] + self.img_size = img_size + self.patch_size = patch_size + self.patches_resolution = patches_resolution + self.num_patches = patches_resolution[0] * patches_resolution[1] + + self.in_chans = in_chans + self.embed_dim = embed_dim + + self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size) + if norm_layer is not None: + self.norm = norm_layer(embed_dim) + else: + self.norm = None + + def forward(self, x): + B, C, H, W = x.shape + # FIXME look at relaxing size constraints + # assert H == self.img_size[0] and W == self.img_size[1], + # f"Input image size ({H}*{W}) doesn't match model ({self.img_size[0]}*{self.img_size[1]})." + x = self.proj(x).flatten(2).transpose(1, 2) # B Ph*Pw C + if self.norm is not None: + x = self.norm(x) + return x + + def flops(self): + Ho, Wo = self.patches_resolution + flops = Ho * Wo * self.embed_dim * self.in_chans * (self.patch_size[0] * self.patch_size[1]) + if self.norm is not None: + flops += Ho * Wo * self.embed_dim + return flops + +class RSTB(nn.Module): + """Residual Swin Transformer Block (RSTB). + + Args: + dim (int): Number of input channels. + input_resolution (tuple[int]): Input resolution. + depth (int): Number of blocks. + num_heads (int): Number of attention heads. + window_size (int): Local window size. + mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. + qkv_bias (bool, optional): If True, add a learnable bias to query, key, value. Default: True + drop (float, optional): Dropout rate. Default: 0.0 + attn_drop (float, optional): Attention dropout rate. Default: 0.0 + drop_path (float | tuple[float], optional): Stochastic depth rate. Default: 0.0 + norm_layer (nn.Module, optional): Normalization layer. Default: nn.LayerNorm + downsample (nn.Module | None, optional): Downsample layer at the end of the layer. Default: None + use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False. + img_size: Input image size. + patch_size: Patch size. + resi_connection: The convolutional block before residual connection. + """ + + def __init__(self, dim, input_resolution, depth, num_heads, window_size, + mlp_ratio=4., qkv_bias=True, drop=0., attn_drop=0., + drop_path=0., norm_layer=nn.LayerNorm, downsample=None, use_checkpoint=False, + img_size=224, patch_size=4, resi_connection='1conv'): + super(RSTB, self).__init__() + + self.dim = dim + self.input_resolution = input_resolution + + self.residual_group = BasicLayer(dim=dim, + input_resolution=input_resolution, + depth=depth, + num_heads=num_heads, + window_size=window_size, + mlp_ratio=mlp_ratio, + qkv_bias=qkv_bias, + drop=drop, attn_drop=attn_drop, + drop_path=drop_path, + norm_layer=norm_layer, + downsample=downsample, + use_checkpoint=use_checkpoint) + + if resi_connection == '1conv': + self.conv = nn.Conv2d(dim, dim, 3, 1, 1) + elif resi_connection == '3conv': + # to save parameters and memory + self.conv = nn.Sequential(nn.Conv2d(dim, dim // 4, 3, 1, 1), nn.LeakyReLU(negative_slope=0.2, inplace=True), + nn.Conv2d(dim // 4, dim // 4, 1, 1, 0), + nn.LeakyReLU(negative_slope=0.2, inplace=True), + nn.Conv2d(dim // 4, dim, 3, 1, 1)) + + self.patch_embed = PatchEmbed( + img_size=img_size, patch_size=patch_size, in_chans=dim, embed_dim=dim, + norm_layer=None) + + self.patch_unembed = PatchUnEmbed( + img_size=img_size, patch_size=patch_size, in_chans=dim, embed_dim=dim, + norm_layer=None) + + def forward(self, x, x_size): + return self.patch_embed(self.conv(self.patch_unembed(self.residual_group(x, x_size), x_size))) + x + + def flops(self): + flops = 0 + flops += self.residual_group.flops() + H, W = self.input_resolution + flops += H * W * self.dim * self.dim * 9 + flops += self.patch_embed.flops() + flops += self.patch_unembed.flops() + + return flops + +class PatchUnEmbed(nn.Module): + r""" Image to Patch Unembedding + + Args: + img_size (int): Image size. Default: 224. + patch_size (int): Patch token size. Default: 4. + in_chans (int): Number of input image channels. Default: 3. + embed_dim (int): Number of linear projection output channels. Default: 96. + norm_layer (nn.Module, optional): Normalization layer. Default: None + """ + + def __init__(self, img_size=224, patch_size=4, in_chans=3, embed_dim=96, norm_layer=None): + super().__init__() + img_size = to_2tuple(img_size) + patch_size = to_2tuple(patch_size) + patches_resolution = [img_size[0] // patch_size[0], img_size[1] // patch_size[1]] + self.img_size = img_size + self.patch_size = patch_size + self.patches_resolution = patches_resolution + self.num_patches = patches_resolution[0] * patches_resolution[1] + + self.in_chans = in_chans + self.embed_dim = embed_dim + + def forward(self, x, x_size): + B, HW, C = x.shape + x = x.transpose(1, 2).view(B, self.embed_dim, x_size[0], x_size[1]) # B Ph*Pw C + return x + + def flops(self): + flops = 0 + return flops + + +class Upsample(nn.Sequential): + """Upsample module. + + Args: + scale (int): Scale factor. Supported scales: 2^n and 3. + num_feat (int): Channel number of intermediate features. + """ + + def __init__(self, scale, num_feat): + m = [] + if (scale & (scale - 1)) == 0: # scale = 2^n + for _ in range(int(math.log(scale, 2))): + m.append(nn.Conv2d(num_feat, 4 * num_feat, 3, 1, 1)) + m.append(nn.PixelShuffle(2)) + elif scale == 3: + m.append(nn.Conv2d(num_feat, 9 * num_feat, 3, 1, 1)) + m.append(nn.PixelShuffle(3)) + else: + raise ValueError(f'scale {scale} is not supported. ' 'Supported scales: 2^n and 3.') + super(Upsample, self).__init__(*m) + +class Upsample_hf(nn.Sequential): + """Upsample module. + + Args: + scale (int): Scale factor. Supported scales: 2^n and 3. + num_feat (int): Channel number of intermediate features. + """ + + def __init__(self, scale, num_feat): + m = [] + if (scale & (scale - 1)) == 0: # scale = 2^n + for _ in range(int(math.log(scale, 2))): + m.append(nn.Conv2d(num_feat, 4 * num_feat, 3, 1, 1)) + m.append(nn.PixelShuffle(2)) + elif scale == 3: + m.append(nn.Conv2d(num_feat, 9 * num_feat, 3, 1, 1)) + m.append(nn.PixelShuffle(3)) + else: + raise ValueError(f'scale {scale} is not supported. ' 'Supported scales: 2^n and 3.') + super(Upsample_hf, self).__init__(*m) + + +class UpsampleOneStep(nn.Sequential): + """UpsampleOneStep module (the difference with Upsample is that it always only has 1conv + 1pixelshuffle) + Used in lightweight SR to save parameters. + + Args: + scale (int): Scale factor. Supported scales: 2^n and 3. + num_feat (int): Channel number of intermediate features. + + """ + + def __init__(self, scale, num_feat, num_out_ch, input_resolution=None): + self.num_feat = num_feat + self.input_resolution = input_resolution + m = [] + m.append(nn.Conv2d(num_feat, (scale ** 2) * num_out_ch, 3, 1, 1)) + m.append(nn.PixelShuffle(scale)) + super(UpsampleOneStep, self).__init__(*m) + + def flops(self): + H, W = self.input_resolution + flops = H * W * self.num_feat * 3 * 9 + return flops + + + +class Swin2SR(nn.Module): + r""" Swin2SR + A PyTorch impl of : `Swin2SR: SwinV2 Transformer for Compressed Image Super-Resolution and Restoration`. + + Args: + img_size (int | tuple(int)): Input image size. Default 64 + patch_size (int | tuple(int)): Patch size. Default: 1 + in_chans (int): Number of input image channels. Default: 3 + embed_dim (int): Patch embedding dimension. Default: 96 + depths (tuple(int)): Depth of each Swin Transformer layer. + num_heads (tuple(int)): Number of attention heads in different layers. + window_size (int): Window size. Default: 7 + mlp_ratio (float): Ratio of mlp hidden dim to embedding dim. Default: 4 + qkv_bias (bool): If True, add a learnable bias to query, key, value. Default: True + drop_rate (float): Dropout rate. Default: 0 + attn_drop_rate (float): Attention dropout rate. Default: 0 + drop_path_rate (float): Stochastic depth rate. Default: 0.1 + norm_layer (nn.Module): Normalization layer. Default: nn.LayerNorm. + ape (bool): If True, add absolute position embedding to the patch embedding. Default: False + patch_norm (bool): If True, add normalization after patch embedding. Default: True + use_checkpoint (bool): Whether to use checkpointing to save memory. Default: False + upscale: Upscale factor. 2/3/4/8 for image SR, 1 for denoising and compress artifact reduction + img_range: Image range. 1. or 255. + upsampler: The reconstruction reconstruction module. 'pixelshuffle'/'pixelshuffledirect'/'nearest+conv'/None + resi_connection: The convolutional block before residual connection. '1conv'/'3conv' + """ + + def __init__(self, img_size=64, patch_size=1, in_chans=3, + embed_dim=96, depths=[6, 6, 6, 6], num_heads=[6, 6, 6, 6], + window_size=7, mlp_ratio=4., qkv_bias=True, + drop_rate=0., attn_drop_rate=0., drop_path_rate=0.1, + norm_layer=nn.LayerNorm, ape=False, patch_norm=True, + use_checkpoint=False, upscale=2, img_range=1., upsampler='', resi_connection='1conv', + **kwargs): + super(Swin2SR, self).__init__() + num_in_ch = in_chans + num_out_ch = in_chans + num_feat = 64 + self.img_range = img_range + if in_chans == 3: + rgb_mean = (0.4488, 0.4371, 0.4040) + self.mean = torch.Tensor(rgb_mean).view(1, 3, 1, 1) + else: + self.mean = torch.zeros(1, 1, 1, 1) + self.upscale = upscale + self.upsampler = upsampler + self.window_size = window_size + + ##################################################################################################### + ################################### 1, shallow feature extraction ################################### + self.conv_first = nn.Conv2d(num_in_ch, embed_dim, 3, 1, 1) + + ##################################################################################################### + ################################### 2, deep feature extraction ###################################### + self.num_layers = len(depths) + self.embed_dim = embed_dim + self.ape = ape + self.patch_norm = patch_norm + self.num_features = embed_dim + self.mlp_ratio = mlp_ratio + + # split image into non-overlapping patches + self.patch_embed = PatchEmbed( + img_size=img_size, patch_size=patch_size, in_chans=embed_dim, embed_dim=embed_dim, + norm_layer=norm_layer if self.patch_norm else None) + num_patches = self.patch_embed.num_patches + patches_resolution = self.patch_embed.patches_resolution + self.patches_resolution = patches_resolution + + # merge non-overlapping patches into image + self.patch_unembed = PatchUnEmbed( + img_size=img_size, patch_size=patch_size, in_chans=embed_dim, embed_dim=embed_dim, + norm_layer=norm_layer if self.patch_norm else None) + + # absolute position embedding + if self.ape: + self.absolute_pos_embed = nn.Parameter(torch.zeros(1, num_patches, embed_dim)) + trunc_normal_(self.absolute_pos_embed, std=.02) + + self.pos_drop = nn.Dropout(p=drop_rate) + + # stochastic depth + dpr = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] # stochastic depth decay rule + + # build Residual Swin Transformer blocks (RSTB) + self.layers = nn.ModuleList() + for i_layer in range(self.num_layers): + layer = RSTB(dim=embed_dim, + input_resolution=(patches_resolution[0], + patches_resolution[1]), + depth=depths[i_layer], + num_heads=num_heads[i_layer], + window_size=window_size, + mlp_ratio=self.mlp_ratio, + qkv_bias=qkv_bias, + drop=drop_rate, attn_drop=attn_drop_rate, + drop_path=dpr[sum(depths[:i_layer]):sum(depths[:i_layer + 1])], # no impact on SR results + norm_layer=norm_layer, + downsample=None, + use_checkpoint=use_checkpoint, + img_size=img_size, + patch_size=patch_size, + resi_connection=resi_connection + + ) + self.layers.append(layer) + + if self.upsampler == 'pixelshuffle_hf': + self.layers_hf = nn.ModuleList() + for i_layer in range(self.num_layers): + layer = RSTB(dim=embed_dim, + input_resolution=(patches_resolution[0], + patches_resolution[1]), + depth=depths[i_layer], + num_heads=num_heads[i_layer], + window_size=window_size, + mlp_ratio=self.mlp_ratio, + qkv_bias=qkv_bias, + drop=drop_rate, attn_drop=attn_drop_rate, + drop_path=dpr[sum(depths[:i_layer]):sum(depths[:i_layer + 1])], # no impact on SR results + norm_layer=norm_layer, + downsample=None, + use_checkpoint=use_checkpoint, + img_size=img_size, + patch_size=patch_size, + resi_connection=resi_connection + + ) + self.layers_hf.append(layer) + + self.norm = norm_layer(self.num_features) + + # build the last conv layer in deep feature extraction + if resi_connection == '1conv': + self.conv_after_body = nn.Conv2d(embed_dim, embed_dim, 3, 1, 1) + elif resi_connection == '3conv': + # to save parameters and memory + self.conv_after_body = nn.Sequential(nn.Conv2d(embed_dim, embed_dim // 4, 3, 1, 1), + nn.LeakyReLU(negative_slope=0.2, inplace=True), + nn.Conv2d(embed_dim // 4, embed_dim // 4, 1, 1, 0), + nn.LeakyReLU(negative_slope=0.2, inplace=True), + nn.Conv2d(embed_dim // 4, embed_dim, 3, 1, 1)) + + ##################################################################################################### + ################################ 3, high quality image reconstruction ################################ + if self.upsampler == 'pixelshuffle': + # for classical SR + self.conv_before_upsample = nn.Sequential(nn.Conv2d(embed_dim, num_feat, 3, 1, 1), + nn.LeakyReLU(inplace=True)) + self.upsample = Upsample(upscale, num_feat) + self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) + elif self.upsampler == 'pixelshuffle_aux': + self.conv_bicubic = nn.Conv2d(num_in_ch, num_feat, 3, 1, 1) + self.conv_before_upsample = nn.Sequential( + nn.Conv2d(embed_dim, num_feat, 3, 1, 1), + nn.LeakyReLU(inplace=True)) + self.conv_aux = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) + self.conv_after_aux = nn.Sequential( + nn.Conv2d(3, num_feat, 3, 1, 1), + nn.LeakyReLU(inplace=True)) + self.upsample = Upsample(upscale, num_feat) + self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) + + elif self.upsampler == 'pixelshuffle_hf': + self.conv_before_upsample = nn.Sequential(nn.Conv2d(embed_dim, num_feat, 3, 1, 1), + nn.LeakyReLU(inplace=True)) + self.upsample = Upsample(upscale, num_feat) + self.upsample_hf = Upsample_hf(upscale, num_feat) + self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) + self.conv_first_hf = nn.Sequential(nn.Conv2d(num_feat, embed_dim, 3, 1, 1), + nn.LeakyReLU(inplace=True)) + self.conv_after_body_hf = nn.Conv2d(embed_dim, embed_dim, 3, 1, 1) + self.conv_before_upsample_hf = nn.Sequential( + nn.Conv2d(embed_dim, num_feat, 3, 1, 1), + nn.LeakyReLU(inplace=True)) + self.conv_last_hf = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) + + elif self.upsampler == 'pixelshuffledirect': + # for lightweight SR (to save parameters) + self.upsample = UpsampleOneStep(upscale, embed_dim, num_out_ch, + (patches_resolution[0], patches_resolution[1])) + elif self.upsampler == 'nearest+conv': + # for real-world SR (less artifacts) + assert self.upscale == 4, 'only support x4 now.' + self.conv_before_upsample = nn.Sequential(nn.Conv2d(embed_dim, num_feat, 3, 1, 1), + nn.LeakyReLU(inplace=True)) + self.conv_up1 = nn.Conv2d(num_feat, num_feat, 3, 1, 1) + self.conv_up2 = nn.Conv2d(num_feat, num_feat, 3, 1, 1) + self.conv_hr = nn.Conv2d(num_feat, num_feat, 3, 1, 1) + self.conv_last = nn.Conv2d(num_feat, num_out_ch, 3, 1, 1) + self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True) + else: + # for image denoising and JPEG compression artifact reduction + self.conv_last = nn.Conv2d(embed_dim, num_out_ch, 3, 1, 1) + + self.apply(self._init_weights) + + def _init_weights(self, m): + if isinstance(m, nn.Linear): + trunc_normal_(m.weight, std=.02) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm): + nn.init.constant_(m.bias, 0) + nn.init.constant_(m.weight, 1.0) + + @torch.jit.ignore + def no_weight_decay(self): + return {'absolute_pos_embed'} + + @torch.jit.ignore + def no_weight_decay_keywords(self): + return {'relative_position_bias_table'} + + def check_image_size(self, x): + _, _, h, w = x.size() + mod_pad_h = (self.window_size - h % self.window_size) % self.window_size + mod_pad_w = (self.window_size - w % self.window_size) % self.window_size + x = F.pad(x, (0, mod_pad_w, 0, mod_pad_h), 'reflect') + return x + + def forward_features(self, x): + x_size = (x.shape[2], x.shape[3]) + x = self.patch_embed(x) + if self.ape: + x = x + self.absolute_pos_embed + x = self.pos_drop(x) + + for layer in self.layers: + x = layer(x, x_size) + + x = self.norm(x) # B L C + x = self.patch_unembed(x, x_size) + + return x + + def forward_features_hf(self, x): + x_size = (x.shape[2], x.shape[3]) + x = self.patch_embed(x) + if self.ape: + x = x + self.absolute_pos_embed + x = self.pos_drop(x) + + for layer in self.layers_hf: + x = layer(x, x_size) + + x = self.norm(x) # B L C + x = self.patch_unembed(x, x_size) + + return x + + def forward(self, x): + H, W = x.shape[2:] + x = self.check_image_size(x) + + self.mean = self.mean.type_as(x) + x = (x - self.mean) * self.img_range + + if self.upsampler == 'pixelshuffle': + # for classical SR + x = self.conv_first(x) + x = self.conv_after_body(self.forward_features(x)) + x + x = self.conv_before_upsample(x) + x = self.conv_last(self.upsample(x)) + elif self.upsampler == 'pixelshuffle_aux': + bicubic = F.interpolate(x, size=(H * self.upscale, W * self.upscale), mode='bicubic', align_corners=False) + bicubic = self.conv_bicubic(bicubic) + x = self.conv_first(x) + x = self.conv_after_body(self.forward_features(x)) + x + x = self.conv_before_upsample(x) + aux = self.conv_aux(x) # b, 3, LR_H, LR_W + x = self.conv_after_aux(aux) + x = self.upsample(x)[:, :, :H * self.upscale, :W * self.upscale] + bicubic[:, :, :H * self.upscale, :W * self.upscale] + x = self.conv_last(x) + aux = aux / self.img_range + self.mean + elif self.upsampler == 'pixelshuffle_hf': + # for classical SR with HF + x = self.conv_first(x) + x = self.conv_after_body(self.forward_features(x)) + x + x_before = self.conv_before_upsample(x) + x_out = self.conv_last(self.upsample(x_before)) + + x_hf = self.conv_first_hf(x_before) + x_hf = self.conv_after_body_hf(self.forward_features_hf(x_hf)) + x_hf + x_hf = self.conv_before_upsample_hf(x_hf) + x_hf = self.conv_last_hf(self.upsample_hf(x_hf)) + x = x_out + x_hf + x_hf = x_hf / self.img_range + self.mean + + elif self.upsampler == 'pixelshuffledirect': + # for lightweight SR + x = self.conv_first(x) + x = self.conv_after_body(self.forward_features(x)) + x + x = self.upsample(x) + elif self.upsampler == 'nearest+conv': + # for real-world SR + x = self.conv_first(x) + x = self.conv_after_body(self.forward_features(x)) + x + x = self.conv_before_upsample(x) + x = self.lrelu(self.conv_up1(torch.nn.functional.interpolate(x, scale_factor=2, mode='nearest'))) + x = self.lrelu(self.conv_up2(torch.nn.functional.interpolate(x, scale_factor=2, mode='nearest'))) + x = self.conv_last(self.lrelu(self.conv_hr(x))) + else: + # for image denoising and JPEG compression artifact reduction + x_first = self.conv_first(x) + res = self.conv_after_body(self.forward_features(x_first)) + x_first + x = x + self.conv_last(res) + + x = x / self.img_range + self.mean + if self.upsampler == "pixelshuffle_aux": + return x[:, :, :H*self.upscale, :W*self.upscale], aux + + elif self.upsampler == "pixelshuffle_hf": + x_out = x_out / self.img_range + self.mean + return x_out[:, :, :H*self.upscale, :W*self.upscale], x[:, :, :H*self.upscale, :W*self.upscale], x_hf[:, :, :H*self.upscale, :W*self.upscale] + + else: + return x[:, :, :H*self.upscale, :W*self.upscale] + + def flops(self): + flops = 0 + H, W = self.patches_resolution + flops += H * W * 3 * self.embed_dim * 9 + flops += self.patch_embed.flops() + for i, layer in enumerate(self.layers): + flops += layer.flops() + flops += H * W * 3 * self.embed_dim * self.embed_dim + flops += self.upsample.flops() + return flops + + +if __name__ == '__main__': + upscale = 4 + window_size = 8 + height = (1024 // upscale // window_size + 1) * window_size + width = (720 // upscale // window_size + 1) * window_size + model = Swin2SR(upscale=2, img_size=(height, width), + window_size=window_size, img_range=1., depths=[6, 6, 6, 6], + embed_dim=60, num_heads=[6, 6, 6, 6], mlp_ratio=2, upsampler='pixelshuffledirect') + print(model) + print(height, width, model.flops() / 1e9) + + x = torch.randn((1, 3, height, width)) + x = model(x) + print(x.shape) \ No newline at end of file From ed769977f0d0f201d8e361d365102f18775fc62c Mon Sep 17 00:00:00 2001 From: C43H66N12O12S2 <36072735+C43H66N12O12S2@users.noreply.github.com> Date: Sun, 9 Oct 2022 18:56:59 +0300 Subject: [PATCH 278/460] add swinir v2 support --- modules/swinir_model.py | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/modules/swinir_model.py b/modules/swinir_model.py index fbd11f843..baa02e3d1 100644 --- a/modules/swinir_model.py +++ b/modules/swinir_model.py @@ -10,6 +10,7 @@ from tqdm import tqdm from modules import modelloader from modules.shared import cmd_opts, opts, device from modules.swinir_model_arch import SwinIR as net +from modules.swinir_model_arch_v2 import Swin2SR as net2 from modules.upscaler import Upscaler, UpscalerData precision_scope = ( @@ -57,22 +58,42 @@ class UpscalerSwinIR(Upscaler): filename = path if filename is None or not os.path.exists(filename): return None - model = net( + if filename.endswith(".v2.pth"): + model = net2( upscale=scale, in_chans=3, img_size=64, window_size=8, img_range=1.0, - depths=[6, 6, 6, 6, 6, 6, 6, 6, 6], - embed_dim=240, - num_heads=[8, 8, 8, 8, 8, 8, 8, 8, 8], + depths=[6, 6, 6, 6, 6, 6], + embed_dim=180, + num_heads=[6, 6, 6, 6, 6, 6], mlp_ratio=2, upsampler="nearest+conv", - resi_connection="3conv", - ) + resi_connection="1conv", + ) + params = None + else: + model = net( + upscale=scale, + in_chans=3, + img_size=64, + window_size=8, + img_range=1.0, + depths=[6, 6, 6, 6, 6, 6, 6, 6, 6], + embed_dim=240, + num_heads=[8, 8, 8, 8, 8, 8, 8, 8, 8], + mlp_ratio=2, + upsampler="nearest+conv", + resi_connection="3conv", + ) + params = "params_ema" pretrained_model = torch.load(filename) - model.load_state_dict(pretrained_model["params_ema"], strict=True) + if params is not None: + model.load_state_dict(pretrained_model[params], strict=True) + else: + model.load_state_dict(pretrained_model, strict=True) if not cmd_opts.no_half: model = model.half() return model From af62ad4d25dcd0454944368f4925d83101cdedbc Mon Sep 17 00:00:00 2001 From: ssysm Date: Mon, 10 Oct 2022 13:25:28 -0400 Subject: [PATCH 279/460] change vae loading method --- modules/sd_models.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index b0e1d8bda..7a42d924d 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -150,9 +150,16 @@ def load_model_weights(model, checkpoint_info): devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16 - vae_file = shared.cmd_opts.vae_path or os.path.splitext(checkpoint_file)[0] + ".vae.pt" + vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt" + if os.path.exists(vae_file): + print(f"Found VAE Weights: {vae_file}") + elif shared.cmd_opts.vae_path != None: + vae_file = shared.cmd_opts.vae_path + print(f'No VAE found for inside the model folder. Using CLI specified : {vae_file}') + else: + print("No VAE found for inside the model folder. Passing.") + if os.path.exists(vae_file): - print(f"Loading VAE weights from: {vae_file}") vae_ckpt = torch.load(vae_file, map_location="cpu") vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} From 39919c40dd18f5a14ae21403efea1b0f819756c7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 10 Oct 2022 20:32:37 +0300 Subject: [PATCH 280/460] add eta noise seed delta option --- javascript/hints.js | 1 + modules/processing.py | 6 +++++- modules/shared.py | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/hints.js b/javascript/hints.js index 8e352e94a..47b807764 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -79,6 +79,7 @@ titles = { "Highres. fix": "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition", "Scale latent": "Uscale the image in latent space. Alternative is to produce the full image from latent representation, upscale that, and then move it back to latent space.", + "Eta noise seed delta": "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing.", } diff --git a/modules/processing.py b/modules/processing.py index 50ba4fc5f..698b3069e 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -207,7 +207,7 @@ def create_random_tensors(shape, seeds, subseeds=None, subseed_strength=0.0, see # enables the generation of additional tensors with noise that the sampler will use during its processing. # Using those pre-generated tensors instead of simple torch.randn allows a batch with seeds [100, 101] to # produce the same images as with two batches [100], [101]. - if p is not None and p.sampler is not None and len(seeds) > 1 and opts.enable_batch_seeds: + if p is not None and p.sampler is not None and (len(seeds) > 1 and opts.enable_batch_seeds or opts.eta_noise_seed_delta > 0): sampler_noises = [[] for _ in range(p.sampler.number_of_needed_noises(p))] else: sampler_noises = None @@ -247,6 +247,9 @@ def create_random_tensors(shape, seeds, subseeds=None, subseed_strength=0.0, see if sampler_noises is not None: cnt = p.sampler.number_of_needed_noises(p) + if opts.eta_noise_seed_delta > 0: + torch.manual_seed(seed + opts.eta_noise_seed_delta) + for j in range(cnt): sampler_noises[j].append(devices.randn_without_seed(tuple(noise_shape))) @@ -301,6 +304,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration "Denoising strength": getattr(p, 'denoising_strength', None), "Eta": (None if p.sampler is None or p.sampler.eta == p.sampler.default_eta else p.sampler.eta), "Clip skip": None if clip_skip <= 1 else clip_skip, + "ENSD": None if opts.eta_noise_seed_delta == 0 else opts.eta_noise_seed_delta, } generation_params.update(p.extra_generation_params) diff --git a/modules/shared.py b/modules/shared.py index 5dfc344cc..b1c65ecf6 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -260,6 +260,7 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters" 's_churn': OptionInfo(0.0, "sigma churn", gr.Slider, {"minimum": 0.0, "maximum": 1.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, "Eta noise seed delta", gr.Number, {"precision": 0}), })) From 727e4d108674dc2813507e2a973a733ef21e8d53 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 10 Oct 2022 20:46:55 +0300 Subject: [PATCH 281/460] no to different messages plus fix using != to compare to None --- modules/sd_models.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 4c06051e5..0a55b4c32 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -152,15 +152,12 @@ def load_model_weights(model, checkpoint_info): devices.dtype_vae = torch.float32 if shared.cmd_opts.no_half or shared.cmd_opts.no_half_vae else torch.float16 vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt" - if os.path.exists(vae_file): - print(f"Found VAE Weights: {vae_file}") - elif shared.cmd_opts.vae_path != None: + + if not os.path.exists(vae_file) and shared.cmd_opts.vae_path is not None: vae_file = shared.cmd_opts.vae_path - print(f'No VAE found for inside the model folder. Using CLI specified : {vae_file}') - else: - print("No VAE found for inside the model folder. Passing.") if os.path.exists(vae_file): + print(f"Loading VAE weights from: {vae_file}") vae_ckpt = torch.load(vae_file, map_location="cpu") vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} From 1d64976dbc5a0f3124567b91fadd5014a9d93c5f Mon Sep 17 00:00:00 2001 From: Justin Maier Date: Mon, 10 Oct 2022 12:04:21 -0600 Subject: [PATCH 282/460] Simplify crop logic --- modules/extras.py | 14 +++----------- modules/ui.py | 4 ++-- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/modules/extras.py b/modules/extras.py index 83ca70492..b24d7de3f 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -73,16 +73,6 @@ def run_extras(extras_mode, resize_mode, image, image_folder, gfpgan_visibility, crop_info = " (crop)" if upscaling_crop else "" info += f"Resize to: {upscaling_resize_w:g}x{upscaling_resize_h:g}{crop_info}\n" - def crop_upscaled_center(image, resize_w, resize_h): - left = int(math.ceil((image.width - resize_w) / 2)) - right = image.width - int(math.floor((image.width - resize_w) / 2)) - top = int(math.ceil((image.height - resize_h) / 2)) - bottom = image.height - int(math.floor((image.height - resize_h) / 2)) - - image = image.crop((left, top, right, bottom)) - return image - - if upscaling_resize != 1.0: def upscale(image, scaler_index, resize, mode, resize_w, resize_h, crop): small = image.crop((image.width // 2, image.height // 2, image.width // 2 + 10, image.height // 2 + 10)) @@ -94,7 +84,9 @@ def run_extras(extras_mode, resize_mode, image, image_folder, gfpgan_visibility, upscaler = shared.sd_upscalers[scaler_index] c = upscaler.scaler.upscale(image, resize, upscaler.data_path) if mode == 1 and crop: - c = crop_upscaled_center(c, resize_w, resize_h) + cropped = Image.new("RGB", (resize_w, resize_h)) + cropped.paste(c, box=(resize_w // 2 - c.width // 2, resize_h // 2 - c.height // 2)) + c = cropped cached_images[key] = c return c diff --git a/modules/ui.py b/modules/ui.py index 4bb2892b7..1aabe18db 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -909,8 +909,8 @@ def create_ui(wrap_gradio_gpu_call): with gr.TabItem('Scale to'): with gr.Group(): with gr.Row(): - upscaling_resize_w = gr.Number(label="Width", value=512) - upscaling_resize_h = gr.Number(label="Height", value=512) + upscaling_resize_w = gr.Number(label="Width", value=512, precision=0) + upscaling_resize_h = gr.Number(label="Height", value=512, precision=0) upscaling_crop = gr.Checkbox(label='Crop to fit', value=True) with gr.Group(): From 5da1ba0e91a81804dc911d34c9a2e6956a23199c Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 10 Oct 2022 21:24:11 +0300 Subject: [PATCH 283/460] remove batch size restriction from X/Y plot --- scripts/xy_grid.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 771eb8e49..42e1489c4 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -205,7 +205,10 @@ class Script(scripts.Script): if not no_fixed_seeds: modules.processing.fix_seed(p) - p.batch_size = 1 + if not opts.return_grid: + p.batch_size = 1 + + CLIP_stop_at_last_layers = opts.CLIP_stop_at_last_layers def process_axis(opt, vals): From bc3e183b739913e7be91213a256f038b10eb71e9 Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Tue, 11 Oct 2022 04:30:13 +0900 Subject: [PATCH 284/460] Textual Inversion: Preprocess and Training will only pick-up image files --- modules/textual_inversion/dataset.py | 3 ++- modules/textual_inversion/preprocess.py | 3 ++- modules/textual_inversion/textual_inversion.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index bcf772d2f..d4baf0660 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -22,6 +22,7 @@ class PersonalizedBase(Dataset): self.width = width self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) + self.extns = [".jpg",".jpeg",".png"] self.dataset = [] @@ -32,7 +33,7 @@ class PersonalizedBase(Dataset): assert data_root, 'dataset directory not specified' - self.image_paths = [os.path.join(data_root, file_path) for file_path in os.listdir(data_root)] + self.image_paths = [os.path.join(data_root, file_path) for file_path in os.listdir(data_root) if os.path.splitext(file_path.casefold())[1] in self.extns] print("Preparing dataset...") for path in tqdm.tqdm(self.image_paths): image = Image.open(path) diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index d7efdef29..b6c78cf85 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -12,12 +12,13 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ height = process_height src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) + extns = [".jpg",".jpeg",".png"] assert src != dst, 'same directory specified as source and destination' os.makedirs(dst, exist_ok=True) - files = os.listdir(src) + files = [i for i in os.listdir(src) if os.path.splitext(i.casefold())[1] in extns] shared.state.textinfo = "Preprocessing..." shared.state.job_count = len(files) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 5965c5a06..45397be92 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -161,6 +161,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.textinfo = "Initializing textual inversion training..." shared.state.job_count = steps + extns = [".jpg",".jpeg",".png"] filename = os.path.join(shared.cmd_opts.embeddings_dir, f'{embedding_name}.pt') @@ -200,7 +201,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if ititial_step > steps: return embedding, filename - tr_img_len = len([os.path.join(data_root, file_path) for file_path in os.listdir(data_root)]) + tr_img_len = len([os.path.join(data_root, file_path) for file_path in os.listdir(data_root) if os.path.splitext(file_path.casefold())[1] in extns]) epoch_len = (tr_img_len * num_repeats) + tr_img_len pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) From f98338faa84ecce503e68d8ba13d5f7bbae52730 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Mon, 10 Oct 2022 23:15:48 +0300 Subject: [PATCH 285/460] add an option to not add watermark to created images --- javascript/hints.js | 1 + modules/shared.py | 1 + 2 files changed, 2 insertions(+) diff --git a/javascript/hints.js b/javascript/hints.js index 47b807764..045f2d3c1 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -80,6 +80,7 @@ titles = { "Scale latent": "Uscale the image in latent space. Alternative is to produce the full image from latent representation, upscale that, and then move it back to latent space.", "Eta noise seed delta": "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing.", + "Do not add watermark to images": "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be bevaing in an unethical manner.", } diff --git a/modules/shared.py b/modules/shared.py index da389f9c0..ecd15ef5d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -173,6 +173,7 @@ options_templates.update(options_section(('saving-images', "Saving images/grids" "use_original_name_batch": OptionInfo(False, "Use original name for output filename during batch process in extras tab"), "save_selected_only": OptionInfo(True, "When using 'Save' button, only save a single selected image"), + "do_not_add_watermark": OptionInfo(False, "Do not add watermark to images"), })) options_templates.update(options_section(('saving-paths', "Paths for saving"), { From 42bf5fa3256bff5e4640e5a626e750d4e49e01e1 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:54:21 +0100 Subject: [PATCH 286/460] Make cancel generate forever let the current gen complete (#2206) --- javascript/contextMenus.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index 2d82269fc..7852793c1 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -147,10 +147,6 @@ generateOnRepeatId = appendContextMenuOption('#txt2img_generate','Generate forev cancelGenerateForever = function(){ clearInterval(window.generateOnRepeatInterval) - let interruptbutton = gradioApp().querySelector('#txt2img_interrupt'); - if(interruptbutton.offsetParent){ - interruptbutton.click(); - } } appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever) From 2536ecbb1790da2af0d61b6a26f38732cba665cd Mon Sep 17 00:00:00 2001 From: Fampai <> Date: Mon, 10 Oct 2022 17:10:29 -0400 Subject: [PATCH 287/460] Refactored learning rate code --- .../textual_inversion/textual_inversion.py | 51 +++++++++++++++++-- modules/ui.py | 2 +- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 5965c5a06..c64a45987 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -189,8 +189,6 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini embedding = hijack.embedding_db.word_embeddings[embedding_name] embedding.vec.requires_grad = True - optimizer = torch.optim.AdamW([embedding.vec], lr=learn_rate) - losses = torch.zeros((32,)) last_saved_file = "" @@ -203,12 +201,24 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini tr_img_len = len([os.path.join(data_root, file_path) for file_path in os.listdir(data_root)]) epoch_len = (tr_img_len * num_repeats) + tr_img_len + scheduleIter = iter(LearnSchedule(learn_rate, steps, ititial_step)) + (learn_rate, end_step) = next(scheduleIter) + print(f'Training at rate of {learn_rate} until step {end_step}') + + optimizer = torch.optim.AdamW([embedding.vec], lr=learn_rate) + pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) for i, (x, text) in pbar: embedding.step = i + ititial_step - if embedding.step > steps: - break + if embedding.step > end_step: + try: + (learn_rate, end_step) = next(scheduleIter) + except: + break + tqdm.tqdm.write(f'Training at rate of {learn_rate} until step {end_step}') + for pg in optimizer.param_groups: + pg['lr'] = learn_rate if shared.state.interrupted: break @@ -277,3 +287,36 @@ Last saved image: {html.escape(last_saved_image)}
    return embedding, filename +class LearnSchedule: + def __init__(self, learn_rate, max_steps, cur_step=0): + pairs = learn_rate.split(',') + self.rates = [] + self.it = 0 + self.maxit = 0 + for i, pair in enumerate(pairs): + tmp = pair.split(':') + if len(tmp) == 2: + step = int(tmp[1]) + if step > cur_step: + self.rates.append((float(tmp[0]), min(step, max_steps))) + self.maxit += 1 + if step > max_steps: + return + elif step == -1: + self.rates.append((float(tmp[0]), max_steps)) + self.maxit += 1 + return + else: + self.rates.append((float(tmp[0]), max_steps)) + self.maxit += 1 + return + + def __iter__(self): + return self + + def __next__(self): + if self.it < self.maxit: + self.it += 1 + return self.rates[self.it - 1] + else: + raise StopIteration diff --git a/modules/ui.py b/modules/ui.py index 8c06ad7cc..c9e8355bf 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1047,7 +1047,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Group(): gr.HTML(value="

    Train an embedding; must specify a directory with a set of 1:1 ratio images

    ") train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) - learn_rate = gr.Number(label='Learning rate', value=5.0e-03) + learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value = "5.0e-03") dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) From 907a88b2d0be320575c2129d8d6a1d4f3a68f9eb Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Tue, 11 Oct 2022 06:33:08 +0900 Subject: [PATCH 288/460] Added .webp .bmp --- modules/textual_inversion/dataset.py | 2 +- modules/textual_inversion/preprocess.py | 2 +- modules/textual_inversion/textual_inversion.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index d4baf0660..0dc54fb70 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -22,7 +22,7 @@ class PersonalizedBase(Dataset): self.width = width self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) - self.extns = [".jpg",".jpeg",".png"] + self.extns = [".jpg",".jpeg",".png",".webp",".bmp"] self.dataset = [] diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index b6c78cf85..8290abe88 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -12,7 +12,7 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ height = process_height src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) - extns = [".jpg",".jpeg",".png"] + extns = [".jpg",".jpeg",".png",".webp",".bmp"] assert src != dst, 'same directory specified as source and destination' diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index a03b299c4..33c923d16 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -161,7 +161,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.textinfo = "Initializing textual inversion training..." shared.state.job_count = steps - extns = [".jpg",".jpeg",".png"] + extns = [".jpg",".jpeg",".png",".webp",".bmp"] filename = os.path.join(shared.cmd_opts.embeddings_dir, f'{embedding_name}.pt') From a1a05ad2d13d0b995dbf8ecead6315f17837ef81 Mon Sep 17 00:00:00 2001 From: JC_Array Date: Mon, 10 Oct 2022 16:47:58 -0500 Subject: [PATCH 289/460] import time missing, added to deepbooru fixxing error on get_deepbooru_tags --- modules/deepbooru.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index cee4a3b4a..12555b2e8 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -1,6 +1,7 @@ import os.path from concurrent.futures import ProcessPoolExecutor import multiprocessing +import time def get_deepbooru_tags(pil_image, threshold=0.5): From b980e7188c671fc55b26557f097076fb5c976ba0 Mon Sep 17 00:00:00 2001 From: JC_Array Date: Mon, 10 Oct 2022 16:52:54 -0500 Subject: [PATCH 290/460] corrected tag return in get_deepbooru_tags --- modules/deepbooru.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 12555b2e8..ebdba5e08 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -15,7 +15,6 @@ def get_deepbooru_tags(pil_image, threshold=0.5): while shared.deepbooru_process_return["value"] == -1: time.sleep(0.2) release_process() - return ret def deepbooru_process(queue, deepbooru_process_return, threshold): From 315d5a8ed975c88f670bc484f40a23fbf3a77b63 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:14:44 +0100 Subject: [PATCH 291/460] update data dis[play style --- .../textual_inversion/textual_inversion.py | 88 ++++++++++++++----- 1 file changed, 65 insertions(+), 23 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 667a7cf2b..95eebea7c 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -39,20 +39,59 @@ def embeddingFromB64(data): d = base64.b64decode(data) return json.loads(d,cls=EmbeddingDecoder) -def appendImageDataFooter(image,data): +def xorBlock(block): + return np.bitwise_xor(block.astype(np.uint8), + ((np.random.RandomState(0xDEADBEEF).random(block.shape)*255).astype(np.uint8)) & 0x0F ) + +def styleBlock(block,sequence): + im = Image.new('RGB',(block.shape[1],block.shape[0])) + draw = ImageDraw.Draw(im) + i=0 + for x in range(-6,im.size[0],8): + for yi,y in enumerate(range(-6,im.size[1],8)): + offset=0 + if yi%2==0: + offset=4 + shade = sequence[i%len(sequence)] + i+=1 + draw.ellipse((x+offset, y, x+6+offset, y+6), fill =(shade,shade,shade) ) + + fg = np.array(im).astype(np.uint8) & 0xF0 + return block ^ fg + +def insertImageDataEmbed(image,data): d = 3 data_compressed = zlib.compress( json.dumps(data,cls=EmbeddingEncoder).encode(),level=9) dnp = np.frombuffer(data_compressed,np.uint8).copy() - w = image.size[0] - next_size = dnp.shape[0] + (w-(dnp.shape[0]%w)) - next_size = next_size + ((w*d)-(next_size%(w*d))) - dnp.resize(next_size) - dnp = dnp.reshape((-1,w,d)) - print(dnp.shape) - im = Image.fromarray(dnp,mode='RGB') - background = Image.new('RGB',(image.size[0],image.size[1]+im.size[1]+1),(0,0,0)) - background.paste(image,(0,0)) - background.paste(im,(0,image.size[1]+1)) + dnphigh = dnp >> 4 + dnplow = dnp & 0x0F + + h = image.size[1] + next_size = dnplow.shape[0] + (h-(dnplow.shape[0]%h)) + next_size = next_size + ((h*d)-(next_size%(h*d))) + + dnplow.resize(next_size) + dnplow = dnplow.reshape((h,-1,d)) + + dnphigh.resize(next_size) + dnphigh = dnphigh.reshape((h,-1,d)) + + edgeStyleWeights = list(data['string_to_param'].values())[0].cpu().detach().numpy().tolist()[0][:1024] + edgeStyleWeights = (np.abs(edgeStyleWeights)/np.max(np.abs(edgeStyleWeights))*255).astype(np.uint8) + + dnplow = styleBlock(dnplow,sequence=edgeStyleWeights) + dnplow = xorBlock(dnplow) + dnphigh = styleBlock(dnphigh,sequence=edgeStyleWeights[::-1]) + dnphigh = xorBlock(dnphigh) + + imlow = Image.fromarray(dnplow,mode='RGB') + imhigh = Image.fromarray(dnphigh,mode='RGB') + + background = Image.new('RGB',(image.size[0]+imlow.size[0]+imhigh.size[0]+2,image.size[1]),(0,0,0)) + background.paste(imlow,(0,0)) + background.paste(image,(imlow.size[0]+1,0)) + background.paste(imhigh,(imlow.size[0]+1+image.size[0]+1,0)) + return background def crop_black(img,tol=0): @@ -62,19 +101,22 @@ def crop_black(img,tol=0): row_start,row_end = mask1.argmax(),mask.shape[0]-mask1[::-1].argmax() return img[row_start:row_end,col_start:col_end] -def extractImageDataFooter(image): +def extractImageDataEmbed(image): d=3 - outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) - lastRow = np.where( np.sum(outarr, axis=(1,2))==0) - if lastRow[0].shape[0] == 0: - print('Image data block not found.') + outarr = crop_black(np.array(image.getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) & 0x0F + blackCols = np.where( np.sum(outarr, axis=(0,2))==0) + if blackCols[0].shape[0] < 2: + print('No Image data blocks found.') return None - lastRow = lastRow[0] - - lastRow = lastRow.max() - dataBlock = outarr[lastRow+1::].astype(np.uint8).flatten().tobytes() - print(lastRow) + dataBlocklower = outarr[:,:blackCols[0].min(),:].astype(np.uint8) + dataBlockupper = outarr[:,blackCols[0].max()+1:,:].astype(np.uint8) + + dataBlocklower = xorBlock(dataBlocklower) + dataBlockupper = xorBlock(dataBlockupper) + + dataBlock = (dataBlockupper << 4) | (dataBlocklower) + dataBlock = dataBlock.flatten().tobytes() data = zlib.decompress(dataBlock) return json.loads(data,cls=EmbeddingDecoder) @@ -154,7 +196,7 @@ class EmbeddingDatabase: data = embeddingFromB64(embed_image.text['sd-ti-embedding']) name = data.get('name',name) else: - data = extractImageDataFooter(embed_image) + data = extractImageDataEmbed(embed_image) name = data.get('name',name) else: data = torch.load(path, map_location="cpu") @@ -351,7 +393,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini footer_right = '{}'.format(embedding.step) captioned_image = captionImageOverlay(image,title,footer_left,footer_mid,footer_right) - captioned_image = appendImageDataFooter(captioned_image,data) + captioned_image = insertImageDataEmbed(captioned_image,data) captioned_image.save(last_saved_image_chunks, "PNG", pnginfo=info) From 767202a4c324f9b49f63ab4dabbb5736fe9df6e5 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:20:52 +0100 Subject: [PATCH 292/460] add dependency --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 95eebea7c..f3cacaa05 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -7,7 +7,7 @@ import tqdm import html import datetime -from PIL import Image,PngImagePlugin +from PIL import Image,PngImagePlugin,ImageDraw from ..images import captionImageOverlay import numpy as np import base64 From e0fbe6d27e7b4505766c8cb5a4264e1114cf3721 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:26:24 +0100 Subject: [PATCH 293/460] colour depth conversion fix --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index f3cacaa05..ae8072684 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -103,7 +103,7 @@ def crop_black(img,tol=0): def extractImageDataEmbed(image): d=3 - outarr = crop_black(np.array(image.getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) & 0x0F + outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) & 0x0F blackCols = np.where( np.sum(outarr, axis=(0,2))==0) if blackCols[0].shape[0] < 2: print('No Image data blocks found.') From 76ef3d75f61253516c024553335d9083d9660a8a Mon Sep 17 00:00:00 2001 From: JC_Array Date: Mon, 10 Oct 2022 18:01:49 -0500 Subject: [PATCH 294/460] added deepbooru settings (threshold and sort by alpha or likelyhood) --- modules/deepbooru.py | 36 +++++++++++++++++++++++++----------- modules/shared.py | 6 ++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index ebdba5e08..e31e92c09 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -3,31 +3,32 @@ from concurrent.futures import ProcessPoolExecutor import multiprocessing import time - -def get_deepbooru_tags(pil_image, threshold=0.5): +def get_deepbooru_tags(pil_image): """ This method is for running only one image at a time for simple use. Used to the img2img interrogate. """ from modules import shared # prevents circular reference - create_deepbooru_process(threshold) + create_deepbooru_process(shared.opts.deepbooru_threshold, shared.opts.deepbooru_sort_alpha) shared.deepbooru_process_return["value"] = -1 shared.deepbooru_process_queue.put(pil_image) while shared.deepbooru_process_return["value"] == -1: time.sleep(0.2) + tags = shared.deepbooru_process_return["value"] release_process() + return tags -def deepbooru_process(queue, deepbooru_process_return, threshold): +def deepbooru_process(queue, deepbooru_process_return, threshold, alpha_sort): model, tags = get_deepbooru_tags_model() while True: # while process is running, keep monitoring queue for new image pil_image = queue.get() if pil_image == "QUIT": break else: - deepbooru_process_return["value"] = get_deepbooru_tags_from_model(model, tags, pil_image, threshold) + deepbooru_process_return["value"] = get_deepbooru_tags_from_model(model, tags, pil_image, threshold, alpha_sort) -def create_deepbooru_process(threshold=0.5): +def create_deepbooru_process(threshold, alpha_sort): """ Creates deepbooru process. A queue is created to send images into the process. This enables multiple images to be processed in a row without reloading the model or creating a new process. To return the data, a shared @@ -40,7 +41,7 @@ def create_deepbooru_process(threshold=0.5): shared.deepbooru_process_queue = shared.deepbooru_process_manager.Queue() shared.deepbooru_process_return = shared.deepbooru_process_manager.dict() shared.deepbooru_process_return["value"] = -1 - shared.deepbooru_process = multiprocessing.Process(target=deepbooru_process, args=(shared.deepbooru_process_queue, shared.deepbooru_process_return, threshold)) + shared.deepbooru_process = multiprocessing.Process(target=deepbooru_process, args=(shared.deepbooru_process_queue, shared.deepbooru_process_return, threshold, alpha_sort)) shared.deepbooru_process.start() @@ -80,7 +81,7 @@ def get_deepbooru_tags_model(): return model, tags -def get_deepbooru_tags_from_model(model, tags, pil_image, threshold=0.5): +def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, alpha_sort): import deepdanbooru as dd import tensorflow as tf import numpy as np @@ -105,15 +106,28 @@ def get_deepbooru_tags_from_model(model, tags, pil_image, threshold=0.5): for i, tag in enumerate(tags): result_dict[tag] = y[i] - result_tags_out = [] + + unsorted_tags_in_theshold = [] result_tags_print = [] for tag in tags: if result_dict[tag] >= threshold: if tag.startswith("rating:"): continue - result_tags_out.append(tag) + unsorted_tags_in_theshold.append((result_dict[tag], tag)) result_tags_print.append(f'{result_dict[tag]} {tag}') + # sort tags + result_tags_out = [] + sort_ndx = 0 + print(alpha_sort) + if alpha_sort: + sort_ndx = 1 + + # sort by reverse by likelihood and normal for alpha + unsorted_tags_in_theshold.sort(key=lambda y: y[sort_ndx], reverse=(not alpha_sort)) + for weight, tag in unsorted_tags_in_theshold: + result_tags_out.append(tag) + print('\n'.join(sorted(result_tags_print, reverse=True))) - return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') \ No newline at end of file + return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') diff --git a/modules/shared.py b/modules/shared.py index 1995a99a7..2e307809b 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -261,6 +261,12 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters" 's_noise': OptionInfo(1.0, "sigma noise", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), })) +if cmd_opts.deepdanbooru: + options_templates.update(options_section(('deepbooru-params', "DeepBooru parameters"), { + "deepbooru_sort_alpha": OptionInfo(True, "Sort Alphabetical", gr.Checkbox), + 'deepbooru_threshold': OptionInfo(0.5, "Threshold", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), + })) + class Options: data = None From 70b50b1dfcb0ce0f87998c994f4855014bc7e26b Mon Sep 17 00:00:00 2001 From: ClashSAN <98228077+ClashSAN@users.noreply.github.com> Date: Mon, 10 Oct 2022 23:23:12 +0000 Subject: [PATCH 295/460] add features, credit for Composable Diffusion to readme https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/2171 --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 561eb03d1..0e9387686 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,12 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - CodeFormer, face restoration tool as an alternative to GFPGAN - RealESRGAN, neural network upscaler - ESRGAN, neural network upscaler with a lot of third party models - - SwinIR, neural network upscaler + - SwinIR and Swin2SR([see here](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/2092)), neural network upscalers - LDSR, Latent diffusion super resolution upscaling - Resizing aspect ratio options - Sampling method selection + - Adjust sampler eta values (noise multiplier) + - More advanced noise setting options - Interrupt processing at any time - 4GB video card support (also reports of 2GB working) - Correct seeds for batches @@ -67,6 +69,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2` - No token limit for prompts (original stable diffusion lets you use up to 75 tokens) - DeepDanbooru integration, creates danbooru style tags for anime prompts (add --deepdanbooru to commandline args) +- [xformers](https://github.com/mv-lab/swin2sr), major speed increase for select cards: (add --xformers to commandline args) ## Installation and Running Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. @@ -116,6 +119,7 @@ The documentation was moved from this README over to the project's [wiki](https: - CodeFormer - https://github.com/sczhou/CodeFormer - ESRGAN - https://github.com/xinntao/ESRGAN - SwinIR - https://github.com/JingyunLiang/SwinIR +- Swin2SR - https://github.com/mv-lab/swin2sr - LDSR - https://github.com/Hafiidz/latent-diffusion - Ideas for optimizations - https://github.com/basujindal/stable-diffusion - Doggettx - Cross Attention layer optimization - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing. @@ -123,6 +127,8 @@ The documentation was moved from this README over to the project's [wiki](https: - Idea for SD upscale - https://github.com/jquesnelle/txt2imghd - Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot - CLIP interrogator idea and borrowing some code - https://github.com/pharmapsychotic/clip-interrogator +- Idea for Composable Diffusion - https://github.com/energy-based-model/Compositional-Visual-Generation-with-Composable-Diffusion-Models-PyTorch +- xformers - https://github.com/facebookresearch/xformers +- DeepDanbooru - interrogator for anime diffusers https://github.com/KichangKim/DeepDanbooru - Initial Gradio script - posted on 4chan by an Anonymous user. Thank you Anonymous user. -- DeepDanbooru - interrogator for anime diffusors https://github.com/KichangKim/DeepDanbooru - (You) From bb932dbf9faf43ba918daa4791873078797b2a48 Mon Sep 17 00:00:00 2001 From: JC_Array Date: Mon, 10 Oct 2022 18:37:52 -0500 Subject: [PATCH 296/460] added alpha sort and threshold variables to create process method in preprocessing --- modules/textual_inversion/preprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index 4a2194da1..c0af729b0 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -29,7 +29,7 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ shared.interrogator.load() if process_caption_deepbooru: - deepbooru.create_deepbooru_process() + deepbooru.create_deepbooru_process(opts.deepbooru_threshold, opts.deepbooru_sort_alpha) def save_pic_with_caption(image, index): if process_caption: From 1add3cff84b7e2436d69b1e97ae689281e4a7c33 Mon Sep 17 00:00:00 2001 From: papuSpartan Date: Mon, 10 Oct 2022 19:57:43 -0500 Subject: [PATCH 297/460] Refresh list of models/ckpts upon hitting restart gradio in the settings pane --- modules/ui.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/ui.py b/modules/ui.py index e8039d76c..06ff118f8 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -39,6 +39,7 @@ import modules.generation_parameters_copypaste from modules import prompt_parser from modules.images import save_image import modules.textual_inversion.ui +from modules.sd_models import list_models # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI mimetypes.init() @@ -1290,6 +1291,9 @@ Requested path was: {f} shared.state.interrupt() settings_interface.gradio_ref.do_restart = True + # refresh models so that new models/.ckpt's show up on reload + list_models() + restart_gradio.click( fn=request_restart, inputs=[], From 7aa8fcac1e45c3ad9c6a40df0e44a346afcd5032 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 04:17:36 +0100 Subject: [PATCH 298/460] use simple lcg in xor --- modules/textual_inversion/textual_inversion.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index ae8072684..13416a085 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -39,9 +39,15 @@ def embeddingFromB64(data): d = base64.b64decode(data) return json.loads(d,cls=EmbeddingDecoder) +def lcg(m=2**32, a=1664525, c=1013904223, seed=0): + while True: + seed = (a * seed + c) % m + yield seed + def xorBlock(block): - return np.bitwise_xor(block.astype(np.uint8), - ((np.random.RandomState(0xDEADBEEF).random(block.shape)*255).astype(np.uint8)) & 0x0F ) + g = lcg() + randblock = np.array([next(g) for _ in range(np.product(block.shape))]).astype(np.uint8).reshape(block.shape) + return np.bitwise_xor(block.astype(np.uint8),randblock & 0x0F) def styleBlock(block,sequence): im = Image.new('RGB',(block.shape[1],block.shape[0])) From 8b7d3f1bef47bbe048f644ed0d8dd3ad46554045 Mon Sep 17 00:00:00 2001 From: Jairo Correa Date: Tue, 11 Oct 2022 02:22:46 -0300 Subject: [PATCH 299/460] Make the ctrl+enter shortcut use the generate button on the current tab --- modules/ui.py | 2 +- script.js | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index e8039d76c..cafda8845 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1331,7 +1331,7 @@ Requested path was: {f} with gr.Tabs() as tabs: for interface, label, ifid in interfaces: - with gr.TabItem(label, id=ifid): + with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid): interface.render() if os.path.exists(os.path.join(script_path, "notification.mp3")): diff --git a/script.js b/script.js index a92c0f77d..9543cbe68 100644 --- a/script.js +++ b/script.js @@ -6,6 +6,10 @@ function get_uiCurrentTab() { return gradioApp().querySelector('.tabs button:not(.border-transparent)') } +function get_uiCurrentTabContent() { + return gradioApp().querySelector('.tabitem[id^=tab_]:not([style*="display: none"])') +} + uiUpdateCallbacks = [] uiTabChangeCallbacks = [] let uiCurrentTab = null @@ -50,8 +54,11 @@ document.addEventListener("DOMContentLoaded", function() { } else if (e.keyCode !== undefined) { if((e.keyCode == 13 && (e.metaKey || e.ctrlKey))) handled = true; } - if (handled) { - gradioApp().querySelector("#txt2img_generate").click(); + if (handled) { + button = get_uiCurrentTabContent().querySelector('button[id$=_generate]'); + if (button) { + button.click(); + } e.preventDefault(); } }) From 8617396c6df71074c7fd3d39419802026874712a Mon Sep 17 00:00:00 2001 From: Kenneth Date: Mon, 10 Oct 2022 17:23:07 -0600 Subject: [PATCH 300/460] Added slider for deepbooru score threshold in settings --- modules/shared.py | 1 + modules/ui.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index ecd15ef5d..e0830e281 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -239,6 +239,7 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"), "interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}), "interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}), "interrogate_clip_dict_limit": OptionInfo(1500, "Interrogate: maximum number of lines in text file (0 = No limit)"), + "interrogate_deepbooru_score_threshold": OptionInfo(0.5, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), })) options_templates.update(options_section(('ui', "User interface"), { diff --git a/modules/ui.py b/modules/ui.py index cafda8845..ca3151c47 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -311,7 +311,7 @@ def interrogate(image): def interrogate_deepbooru(image): - prompt = get_deepbooru_tags(image) + prompt = get_deepbooru_tags(image, opts.interrogate_deepbooru_score_threshold) return gr_show(True) if prompt is None else prompt From 5e2627a1a63e4c9f87e6e604ecc24e9936f149de Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Tue, 11 Oct 2022 07:55:28 +0100 Subject: [PATCH 301/460] Comma backtrack padding (#2192) Comma backtrack padding --- modules/sd_hijack.py | 19 ++++++++++++++++++- modules/shared.py | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 827bf3045..aa4d2cbc0 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -107,6 +107,8 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): self.tokenizer = wrapped.tokenizer self.token_mults = {} + self.comma_token = [v for k, v in self.tokenizer.get_vocab().items() if k == ','][0] + tokens_with_parens = [(k, v) for k, v in self.tokenizer.get_vocab().items() if '(' in k or ')' in k or '[' in k or ']' in k] for text, ident in tokens_with_parens: mult = 1.0 @@ -136,6 +138,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): fixes = [] remade_tokens = [] multipliers = [] + last_comma = -1 for tokens, (text, weight) in zip(tokenized, parsed): i = 0 @@ -144,6 +147,20 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): embedding, embedding_length_in_tokens = self.hijack.embedding_db.find_embedding_at_position(tokens, i) + if token == self.comma_token: + last_comma = len(remade_tokens) + elif opts.comma_padding_backtrack != 0 and max(len(remade_tokens), 1) % 75 == 0 and last_comma != -1 and len(remade_tokens) - last_comma <= opts.comma_padding_backtrack: + last_comma += 1 + reloc_tokens = remade_tokens[last_comma:] + reloc_mults = multipliers[last_comma:] + + remade_tokens = remade_tokens[:last_comma] + length = len(remade_tokens) + + rem = int(math.ceil(length / 75)) * 75 - length + remade_tokens += [id_end] * rem + reloc_tokens + multipliers = multipliers[:last_comma] + [1.0] * rem + reloc_mults + if embedding is None: remade_tokens.append(token) multipliers.append(weight) @@ -284,7 +301,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): while max(map(len, remade_batch_tokens)) != 0: rem_tokens = [x[75:] for x in remade_batch_tokens] rem_multipliers = [x[75:] for x in batch_multipliers] - + self.hijack.fixes = [] for unfiltered in hijack_fixes: fixes = [] diff --git a/modules/shared.py b/modules/shared.py index e0830e281..14b40d70d 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -227,6 +227,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "enable_emphasis": OptionInfo(True, "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention"), "use_old_emphasis_implementation": OptionInfo(False, "Use old emphasis implementation. Can be useful to reproduce old seeds."), "enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image"), + "comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }), "filter_nsfw": OptionInfo(False, "Filter NSFW content"), 'CLIP_stop_at_last_layers': OptionInfo(1, "Stop At last layers of CLIP model", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}), "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), From 948533950c9db5069a874d925fadd50bac00fdb5 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 11:09:51 +0300 Subject: [PATCH 302/460] replace duplicate code with a function --- modules/hypernetwork.py | 23 ++++++++++------ modules/sd_hijack_optimizations.py | 44 ++++++++++-------------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py index 498bc9d8f..7bbc443e5 100644 --- a/modules/hypernetwork.py +++ b/modules/hypernetwork.py @@ -64,21 +64,26 @@ def load_hypernetwork(filename): shared.loaded_hypernetwork = None +def apply_hypernetwork(hypernetwork, context): + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + + if hypernetwork_layers is None: + return context, context + + context_k = hypernetwork_layers[0](context) + context_v = hypernetwork_layers[1](context) + return context_k, context_v + + def attention_CrossAttention_forward(self, x, context=None, mask=None): h = self.heads q = self.to_q(x) context = default(context, x) - hypernetwork = shared.loaded_hypernetwork - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) - - if hypernetwork_layers is not None: - k = self.to_k(hypernetwork_layers[0](context)) - v = self.to_v(hypernetwork_layers[1](context)) - else: - k = self.to_k(context) - v = self.to_v(context) + context_k, context_v = apply_hypernetwork(shared.loaded_hypernetwork, context) + k = self.to_k(context_k) + v = self.to_v(context_v) q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 18408e629..25cb67a4e 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -8,7 +8,8 @@ from torch import einsum from ldm.util import default from einops import rearrange -from modules import shared +from modules import shared, hypernetwork + if shared.cmd_opts.xformers or shared.cmd_opts.force_enable_xformers: try: @@ -26,16 +27,10 @@ def split_cross_attention_forward_v1(self, x, context=None, mask=None): q_in = self.to_q(x) context = default(context, x) - hypernetwork = shared.loaded_hypernetwork - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) - - if hypernetwork_layers is not None: - k_in = self.to_k(hypernetwork_layers[0](context)) - v_in = self.to_v(hypernetwork_layers[1](context)) - else: - k_in = self.to_k(context) - v_in = self.to_v(context) - del context, x + context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + k_in = self.to_k(context_k) + v_in = self.to_v(context_v) + del context, context_k, context_v, x q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q_in, k_in, v_in)) del q_in, k_in, v_in @@ -59,22 +54,16 @@ def split_cross_attention_forward_v1(self, x, context=None, mask=None): return self.to_out(r2) -# taken from https://github.com/Doggettx/stable-diffusion +# taken from https://github.com/Doggettx/stable-diffusion and modified def split_cross_attention_forward(self, x, context=None, mask=None): h = self.heads q_in = self.to_q(x) context = default(context, x) - hypernetwork = shared.loaded_hypernetwork - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) - - if hypernetwork_layers is not None: - k_in = self.to_k(hypernetwork_layers[0](context)) - v_in = self.to_v(hypernetwork_layers[1](context)) - else: - k_in = self.to_k(context) - v_in = self.to_v(context) + context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + k_in = self.to_k(context_k) + v_in = self.to_v(context_v) k_in *= self.scale @@ -130,14 +119,11 @@ def xformers_attention_forward(self, x, context=None, mask=None): h = self.heads q_in = self.to_q(x) context = default(context, x) - hypernetwork = shared.loaded_hypernetwork - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) - if hypernetwork_layers is not None: - k_in = self.to_k(hypernetwork_layers[0](context)) - v_in = self.to_v(hypernetwork_layers[1](context)) - else: - k_in = self.to_k(context) - v_in = self.to_v(context) + + context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + k_in = self.to_k(context_k) + v_in = self.to_v(context_v) + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b n h d', h=h), (q_in, k_in, v_in)) del q_in, k_in, v_in out = xformers.ops.memory_efficient_attention(q, k, v, attn_bias=None) From b2368a3bce663f19a7209d9cb38617e635ca6e3c Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Tue, 11 Oct 2022 17:32:46 +0900 Subject: [PATCH 303/460] Switched to exception handling --- modules/textual_inversion/dataset.py | 10 +++++----- modules/textual_inversion/preprocess.py | 8 +++++--- modules/textual_inversion/textual_inversion.py | 18 ++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index 0dc54fb70..4d0063669 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -22,7 +22,6 @@ class PersonalizedBase(Dataset): self.width = width self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) - self.extns = [".jpg",".jpeg",".png",".webp",".bmp"] self.dataset = [] @@ -33,12 +32,13 @@ class PersonalizedBase(Dataset): assert data_root, 'dataset directory not specified' - self.image_paths = [os.path.join(data_root, file_path) for file_path in os.listdir(data_root) if os.path.splitext(file_path.casefold())[1] in self.extns] + self.image_paths = [os.path.join(data_root, file_path) for file_path in os.listdir(data_root)] print("Preparing dataset...") for path in tqdm.tqdm(self.image_paths): - image = Image.open(path) - image = image.convert('RGB') - image = image.resize((self.width, self.height), PIL.Image.BICUBIC) + try: + image = Image.open(path).convert('RGB').resize((self.width, self.height), PIL.Image.BICUBIC) + except Exception: + continue filename = os.path.basename(path) filename_tokens = os.path.splitext(filename)[0] diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index 8290abe88..1a6727255 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -12,13 +12,12 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ height = process_height src = os.path.abspath(process_src) dst = os.path.abspath(process_dst) - extns = [".jpg",".jpeg",".png",".webp",".bmp"] assert src != dst, 'same directory specified as source and destination' os.makedirs(dst, exist_ok=True) - files = [i for i in os.listdir(src) if os.path.splitext(i.casefold())[1] in extns] + files = os.listdir(src) shared.state.textinfo = "Preprocessing..." shared.state.job_count = len(files) @@ -47,7 +46,10 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ for index, imagefile in enumerate(tqdm.tqdm(files)): subindex = [0] filename = os.path.join(src, imagefile) - img = Image.open(filename).convert("RGB") + try: + img = Image.open(filename).convert("RGB") + except Exception: + continue if shared.state.interrupted: break diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 33c923d16..91cde04b5 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -161,7 +161,6 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.textinfo = "Initializing textual inversion training..." shared.state.job_count = steps - extns = [".jpg",".jpeg",".png",".webp",".bmp"] filename = os.path.join(shared.cmd_opts.embeddings_dir, f'{embedding_name}.pt') @@ -201,10 +200,6 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if ititial_step > steps: return embedding, filename - tr_img_len = len([os.path.join(data_root, file_path) for file_path in os.listdir(data_root) if os.path.splitext(file_path.casefold())[1] in extns]) - - epoch_len = (tr_img_len * num_repeats) + tr_img_len - pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) for i, (x, text) in pbar: embedding.step = i + ititial_step @@ -228,10 +223,10 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini loss.backward() optimizer.step() - epoch_num = embedding.step // epoch_len - epoch_step = embedding.step - (epoch_num * epoch_len) + 1 + epoch_num = embedding.step // len(ds) + epoch_step = embedding.step - (epoch_num * len(ds)) + 1 - pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{epoch_len}]loss: {losses.mean():.7f}") + pbar.set_description(f"[Epoch {epoch_num}: {epoch_step}/{len(ds)}]loss: {losses.mean():.7f}") if embedding.step > 0 and embedding_dir is not None and embedding.step % save_embedding_every == 0: last_saved_file = os.path.join(embedding_dir, f'{embedding_name}-{embedding.step}.pt') @@ -243,9 +238,12 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, prompt=text, - steps=20, - height=training_height, + steps=28, + height=768, width=training_width, + negative_prompt="lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts,signature, watermark, username, blurry, artist name", + cfg_scale=7.0, + sampler_index=0, do_not_save_grid=True, do_not_save_samples=True, ) From 8bacbca0a1ab9aabcb0ad0cbf070e0006991e98a Mon Sep 17 00:00:00 2001 From: alg-wiki Date: Tue, 11 Oct 2022 17:35:09 +0900 Subject: [PATCH 304/460] Removed my local edits to checkpoint image generation --- modules/textual_inversion/textual_inversion.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 91cde04b5..e9ff80c24 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -238,12 +238,9 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, prompt=text, - steps=28, - height=768, + steps=20, + height=training_height, width=training_width, - negative_prompt="lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts,signature, watermark, username, blurry, artist name", - cfg_scale=7.0, - sampler_index=0, do_not_save_grid=True, do_not_save_samples=True, ) From 255be75d30f41e089e499ec1c8462d6bf64dec24 Mon Sep 17 00:00:00 2001 From: aperullo <18688190+aperullo@users.noreply.github.com> Date: Tue, 11 Oct 2022 06:16:57 -0400 Subject: [PATCH 305/460] Error if prompt missing SR token to prevent mis-gens (#2209) --- scripts/xy_grid.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 42e1489c4..10a82dc9f 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -27,9 +27,16 @@ def apply_field(field): def apply_prompt(p, x, xs): + + orig_prompt = p.prompt + orig_negative_prompt = p.negative_prompt + p.prompt = p.prompt.replace(xs[0], x) p.negative_prompt = p.negative_prompt.replace(xs[0], x) + if p.prompt == orig_prompt and p.negative_prompt == orig_negative_prompt: + raise RuntimeError(f"Prompt S/R did not find {xs[0]} in prompt or negative prompt. Did you forget to add the token?") + def apply_order(p, x, xs): token_order = [] From 4b460fcb1a0224772949556fe0469da93245c532 Mon Sep 17 00:00:00 2001 From: Rory Grieve Date: Tue, 11 Oct 2022 11:23:47 +0100 Subject: [PATCH 306/460] Reset init img in loopback at start of each batch (#2214) Before a new batch would use the last image from the previous batch. Now each batch will use the original image for the init image at the start of the batch. --- scripts/loopback.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/loopback.py b/scripts/loopback.py index e90b58d46..d8c68af89 100644 --- a/scripts/loopback.py +++ b/scripts/loopback.py @@ -38,6 +38,7 @@ class Script(scripts.Script): grids = [] all_images = [] + original_init_image = p.init_images state.job_count = loops * batch_count initial_color_corrections = [processing.setup_color_correction(p.init_images[0])] @@ -45,6 +46,9 @@ class Script(scripts.Script): for n in range(batch_count): history = [] + # Reset to original init image at the start of each batch + p.init_images = original_init_image + for i in range(loops): p.n_iter = 1 p.batch_size = 1 From a8490e4019c359ff24824e004059744d7164361b Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 11:42:41 +0100 Subject: [PATCH 307/460] revert sr warning --- scripts/xy_grid.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 10a82dc9f..99b3c4f64 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -35,7 +35,8 @@ def apply_prompt(p, x, xs): p.negative_prompt = p.negative_prompt.replace(xs[0], x) if p.prompt == orig_prompt and p.negative_prompt == orig_negative_prompt: - raise RuntimeError(f"Prompt S/R did not find {xs[0]} in prompt or negative prompt. Did you forget to add the token?") + pass + #raise RuntimeError(f"Prompt S/R did not find {xs[0]} in prompt or negative prompt. Did you forget to add the token?") def apply_order(p, x, xs): From 1a0a6a84c3149e236211d547471f5416cd1129f3 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 11:59:56 +0100 Subject: [PATCH 308/460] add incorrect start word guard to xy_grid (#2259) --- scripts/xy_grid.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 99b3c4f64..9d4d6187e 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -27,17 +27,12 @@ def apply_field(field): def apply_prompt(p, x, xs): - - orig_prompt = p.prompt - orig_negative_prompt = p.negative_prompt + if xs[0] not in p.prompt and xs[0] not in p.negative_prompt: + raise RuntimeError(f"Prompt S/R did not find {xs[0]} in prompt or negative prompt.") p.prompt = p.prompt.replace(xs[0], x) p.negative_prompt = p.negative_prompt.replace(xs[0], x) - if p.prompt == orig_prompt and p.negative_prompt == orig_negative_prompt: - pass - #raise RuntimeError(f"Prompt S/R did not find {xs[0]} in prompt or negative prompt. Did you forget to add the token?") - def apply_order(p, x, xs): token_order = [] From 530103b586109c11fd068eb70ef09503ec6a4caf Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 14:53:02 +0300 Subject: [PATCH 309/460] fixes related to merge --- modules/hypernetwork.py | 103 ------------------ modules/hypernetwork/hypernetwork.py | 82 ++++++++------ modules/hypernetwork/ui.py | 10 +- modules/sd_hijack_optimizations.py | 3 +- modules/shared.py | 13 ++- .../textual_inversion/textual_inversion.py | 12 +- modules/ui.py | 5 +- scripts/xy_grid.py | 3 +- webui.py | 15 +-- 9 files changed, 82 insertions(+), 164 deletions(-) delete mode 100644 modules/hypernetwork.py diff --git a/modules/hypernetwork.py b/modules/hypernetwork.py deleted file mode 100644 index 7bbc443e5..000000000 --- a/modules/hypernetwork.py +++ /dev/null @@ -1,103 +0,0 @@ -import glob -import os -import sys -import traceback - -import torch - -from ldm.util import default -from modules import devices, shared -import torch -from torch import einsum -from einops import rearrange, repeat - - -class HypernetworkModule(torch.nn.Module): - def __init__(self, dim, state_dict): - super().__init__() - - self.linear1 = torch.nn.Linear(dim, dim * 2) - self.linear2 = torch.nn.Linear(dim * 2, dim) - - self.load_state_dict(state_dict, strict=True) - self.to(devices.device) - - def forward(self, x): - return x + (self.linear2(self.linear1(x))) - - -class Hypernetwork: - filename = None - name = None - - def __init__(self, filename): - self.filename = filename - self.name = os.path.splitext(os.path.basename(filename))[0] - self.layers = {} - - state_dict = torch.load(filename, map_location='cpu') - for size, sd in state_dict.items(): - self.layers[size] = (HypernetworkModule(size, sd[0]), HypernetworkModule(size, sd[1])) - - -def list_hypernetworks(path): - res = {} - for filename in glob.iglob(os.path.join(path, '**/*.pt'), recursive=True): - name = os.path.splitext(os.path.basename(filename))[0] - res[name] = filename - return res - - -def load_hypernetwork(filename): - path = shared.hypernetworks.get(filename, None) - if path is not None: - print(f"Loading hypernetwork {filename}") - try: - shared.loaded_hypernetwork = Hypernetwork(path) - except Exception: - print(f"Error loading hypernetwork {path}", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - else: - if shared.loaded_hypernetwork is not None: - print(f"Unloading hypernetwork") - - shared.loaded_hypernetwork = None - - -def apply_hypernetwork(hypernetwork, context): - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) - - if hypernetwork_layers is None: - return context, context - - context_k = hypernetwork_layers[0](context) - context_v = hypernetwork_layers[1](context) - return context_k, context_v - - -def attention_CrossAttention_forward(self, x, context=None, mask=None): - h = self.heads - - q = self.to_q(x) - context = default(context, x) - - context_k, context_v = apply_hypernetwork(shared.loaded_hypernetwork, context) - k = self.to_k(context_k) - v = self.to_v(context_v) - - q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) - - sim = einsum('b i d, b j d -> b i j', q, k) * self.scale - - if mask is not None: - mask = rearrange(mask, 'b ... -> b (...)') - max_neg_value = -torch.finfo(sim.dtype).max - mask = repeat(mask, 'b j -> (b h) () j', h=h) - sim.masked_fill_(~mask, max_neg_value) - - # attention, what we cannot get enough of - attn = sim.softmax(dim=-1) - - out = einsum('b i j, b j d -> b i d', attn, v) - out = rearrange(out, '(b h) n d -> b n (h d)', h=h) - return self.to_out(out) diff --git a/modules/hypernetwork/hypernetwork.py b/modules/hypernetwork/hypernetwork.py index a3d6a47ef..aa701bda5 100644 --- a/modules/hypernetwork/hypernetwork.py +++ b/modules/hypernetwork/hypernetwork.py @@ -26,10 +26,11 @@ class HypernetworkModule(torch.nn.Module): if state_dict is not None: self.load_state_dict(state_dict, strict=True) else: - self.linear1.weight.data.fill_(0.0001) - self.linear1.bias.data.fill_(0.0001) - self.linear2.weight.data.fill_(0.0001) - self.linear2.bias.data.fill_(0.0001) + + self.linear1.weight.data.normal_(mean=0.0, std=0.01) + self.linear1.bias.data.zero_() + self.linear2.weight.data.normal_(mean=0.0, std=0.01) + self.linear2.bias.data.zero_() self.to(devices.device) @@ -92,41 +93,54 @@ class Hypernetwork: self.sd_checkpoint_name = state_dict.get('sd_checkpoint_name', None) -def load_hypernetworks(path): +def list_hypernetworks(path): res = {} - - for filename in glob.iglob(path + '**/*.pt', recursive=True): - try: - hn = Hypernetwork() - hn.load(filename) - res[hn.name] = hn - except Exception: - print(f"Error loading hypernetwork {filename}", file=sys.stderr) - print(traceback.format_exc(), file=sys.stderr) - + for filename in glob.iglob(os.path.join(path, '**/*.pt'), recursive=True): + name = os.path.splitext(os.path.basename(filename))[0] + res[name] = filename return res +def load_hypernetwork(filename): + path = shared.hypernetworks.get(filename, None) + if path is not None: + print(f"Loading hypernetwork {filename}") + try: + shared.loaded_hypernetwork = Hypernetwork() + shared.loaded_hypernetwork.load(path) + + except Exception: + print(f"Error loading hypernetwork {path}", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + else: + if shared.loaded_hypernetwork is not None: + print(f"Unloading hypernetwork") + + shared.loaded_hypernetwork = None + + +def apply_hypernetwork(hypernetwork, context, layer=None): + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + + if hypernetwork_layers is None: + return context, context + + if layer is not None: + layer.hyper_k = hypernetwork_layers[0] + layer.hyper_v = hypernetwork_layers[1] + + context_k = hypernetwork_layers[0](context) + context_v = hypernetwork_layers[1](context) + return context_k, context_v + + def attention_CrossAttention_forward(self, x, context=None, mask=None): h = self.heads q = self.to_q(x) context = default(context, x) - hypernetwork_layers = (shared.hypernetwork.layers if shared.hypernetwork is not None else {}).get(context.shape[2], None) - - if hypernetwork_layers is not None: - hypernetwork_k, hypernetwork_v = hypernetwork_layers - - self.hypernetwork_k = hypernetwork_k - self.hypernetwork_v = hypernetwork_v - - context_k = hypernetwork_k(context) - context_v = hypernetwork_v(context) - else: - context_k = context - context_v = context - + context_k, context_v = apply_hypernetwork(shared.loaded_hypernetwork, context, self) k = self.to_k(context_k) v = self.to_v(context_v) @@ -151,7 +165,9 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_image_prompt): assert hypernetwork_name, 'embedding not selected' - shared.hypernetwork = shared.hypernetworks[hypernetwork_name] + path = shared.hypernetworks.get(hypernetwork_name, None) + shared.loaded_hypernetwork = Hypernetwork() + shared.loaded_hypernetwork.load(path) shared.state.textinfo = "Initializing hypernetwork training..." shared.state.job_count = steps @@ -176,9 +192,9 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, size=512, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=512, height=512, repeats=1, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file) - hypernetwork = shared.hypernetworks[hypernetwork_name] + hypernetwork = shared.loaded_hypernetwork weights = hypernetwork.weights() for weight in weights: weight.requires_grad = True @@ -194,7 +210,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, if ititial_step > steps: return hypernetwork, filename - pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) + pbar = tqdm.tqdm(enumerate(ds), total=steps - ititial_step) for i, (x, text) in pbar: hypernetwork.step = i + ititial_step diff --git a/modules/hypernetwork/ui.py b/modules/hypernetwork/ui.py index 525f978c5..f6d1d0a35 100644 --- a/modules/hypernetwork/ui.py +++ b/modules/hypernetwork/ui.py @@ -6,24 +6,24 @@ import gradio as gr import modules.textual_inversion.textual_inversion import modules.textual_inversion.preprocess from modules import sd_hijack, shared +from modules.hypernetwork import hypernetwork def create_hypernetwork(name): fn = os.path.join(shared.cmd_opts.hypernetwork_dir, f"{name}.pt") assert not os.path.exists(fn), f"file {fn} already exists" - hypernetwork = modules.hypernetwork.hypernetwork.Hypernetwork(name=name) - hypernetwork.save(fn) + hypernet = modules.hypernetwork.hypernetwork.Hypernetwork(name=name) + hypernet.save(fn) shared.reload_hypernetworks() - shared.hypernetwork = shared.hypernetworks.get(shared.opts.sd_hypernetwork, None) return gr.Dropdown.update(choices=sorted([x for x in shared.hypernetworks.keys()])), f"Created: {fn}", "" def train_hypernetwork(*args): - initial_hypernetwork = shared.hypernetwork + initial_hypernetwork = shared.loaded_hypernetwork try: sd_hijack.undo_optimizations() @@ -38,6 +38,6 @@ Hypernetwork saved to {html.escape(filename)} except Exception: raise finally: - shared.hypernetwork = initial_hypernetwork + shared.loaded_hypernetwork = initial_hypernetwork sd_hijack.apply_optimizations() diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 25cb67a4e..27e571fcd 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -8,7 +8,8 @@ from torch import einsum from ldm.util import default from einops import rearrange -from modules import shared, hypernetwork +from modules import shared +from modules.hypernetwork import hypernetwork if shared.cmd_opts.xformers or shared.cmd_opts.force_enable_xformers: diff --git a/modules/shared.py b/modules/shared.py index 14b40d70d..8753015e5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -13,7 +13,8 @@ import modules.memmon import modules.sd_models import modules.styles import modules.devices as devices -from modules import sd_samplers, hypernetwork +from modules import sd_samplers +from modules.hypernetwork import hypernetwork from modules.paths import models_path, script_path, sd_path sd_model_file = os.path.join(script_path, 'model.ckpt') @@ -29,6 +30,7 @@ parser.add_argument("--no-half-vae", action='store_true', help="do not switch th parser.add_argument("--no-progressbar-hiding", action='store_true', help="do not hide progressbar in gradio UI (we hide it because it slows down ML if you have hardware acceleration in browser)") parser.add_argument("--max-batch-count", type=int, default=16, help="maximum batch count value for the UI") parser.add_argument("--embeddings-dir", type=str, default=os.path.join(script_path, 'embeddings'), help="embeddings directory for textual inversion (default: embeddings)") +parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_path, 'hypernetworks'), help="hypernetwork directory") parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui") parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage") parser.add_argument("--lowvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a lot of speed for very low VRM usage") @@ -82,10 +84,17 @@ parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram xformers_available = False config_filename = cmd_opts.ui_settings_file -hypernetworks = hypernetwork.list_hypernetworks(os.path.join(models_path, 'hypernetworks')) +hypernetworks = hypernetwork.list_hypernetworks(cmd_opts.hypernetwork_dir) loaded_hypernetwork = None +def reload_hypernetworks(): + global hypernetworks + + hypernetworks = hypernetwork.list_hypernetworks(cmd_opts.hypernetwork_dir) + hypernetwork.load_hypernetwork(opts.sd_hypernetwork) + + class State: skipped = False interrupted = False diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 5965c5a06..d69779504 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -156,7 +156,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file, preview_image_prompt): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -238,12 +238,14 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if embedding.step > 0 and images_dir is not None and embedding.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{embedding_name}-{embedding.step}.png') + preview_text = text if preview_image_prompt == "" else preview_image_prompt + p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, - prompt=text, + prompt=preview_text, steps=20, - height=training_height, - width=training_width, + height=training_height, + width=training_width, do_not_save_grid=True, do_not_save_samples=True, ) @@ -254,7 +256,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.current_image = image image.save(last_saved_image) - last_saved_image += f", prompt: {text}" + last_saved_image += f", prompt: {preview_text}" shared.state.job_no = embedding.step diff --git a/modules/ui.py b/modules/ui.py index 10b1ee3a9..df6530590 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1023,7 +1023,7 @@ def create_ui(wrap_gradio_gpu_call): gr.HTML(value="") with gr.Column(): - create_embedding = gr.Button(value="Create", variant='primary') + create_embedding = gr.Button(value="Create embedding", variant='primary') with gr.Group(): gr.HTML(value="

    Create a new hypernetwork

    ") @@ -1035,7 +1035,7 @@ def create_ui(wrap_gradio_gpu_call): gr.HTML(value="") with gr.Column(): - create_hypernetwork = gr.Button(value="Create", variant='primary') + create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary') with gr.Group(): gr.HTML(value="

    Preprocess images

    ") @@ -1147,6 +1147,7 @@ def create_ui(wrap_gradio_gpu_call): create_image_every, save_embedding_every, template_file, + preview_image_prompt, ], outputs=[ ti_output, diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 42e1489c4..0af5993ce 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -10,7 +10,8 @@ import numpy as np import modules.scripts as scripts import gradio as gr -from modules import images, hypernetwork +from modules import images +from modules.hypernetwork import hypernetwork from modules.processing import process_images, Processed, get_correct_sampler from modules.shared import opts, cmd_opts, state import modules.shared as shared diff --git a/webui.py b/webui.py index 7c2005519..ba2156c84 100644 --- a/webui.py +++ b/webui.py @@ -29,6 +29,7 @@ from modules import devices from modules import modelloader from modules.paths import script_path from modules.shared import cmd_opts +import modules.hypernetwork.hypernetwork modelloader.cleanup_models() modules.sd_models.setup_model() @@ -77,22 +78,12 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) -def set_hypernetwork(): - shared.hypernetwork = shared.hypernetworks.get(shared.opts.sd_hypernetwork, None) - - -shared.reload_hypernetworks() -shared.opts.onchange("sd_hypernetwork", set_hypernetwork) -set_hypernetwork() - - modules.scripts.load_scripts(os.path.join(script_path, "scripts")) shared.sd_model = modules.sd_models.load_model() shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) -loaded_hypernetwork = modules.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork) -shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) +shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetwork.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) def webui(): @@ -117,7 +108,7 @@ def webui(): prevent_thread_lock=True ) - app.add_middleware(GZipMiddleware,minimum_size=1000) + app.add_middleware(GZipMiddleware, minimum_size=1000) while 1: time.sleep(0.5) From 7b1db45e1fda8603d4617affd976066be5e5b821 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Tue, 11 Oct 2022 20:17:27 +0800 Subject: [PATCH 310/460] images history improvement --- javascript/images_history.js | 178 ++++++++++++++++--------- javascript/jquery-3.6.0.min.js | 2 - modules/images_history.py | 229 +++++++++++++++++---------------- style.css | 3 + 4 files changed, 242 insertions(+), 170 deletions(-) delete mode 100644 javascript/jquery-3.6.0.min.js diff --git a/javascript/images_history.js b/javascript/images_history.js index 93d2b89ab..9a3e00a00 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -1,66 +1,124 @@ -function init_images_history(){ - if (gradioApp().getElementById('txt2img_images_history_first_page') == null) { - setTimeout(init_images_history, 1000) - } else { - tab_list = ["txt2img", "img2img"] - for (i in tab_list){ - tab = tab_list[i] - gradioApp().getElementById(tab + "_images_history_first_page").click() - $(gradioApp().getElementById(tab + '_images_history')).addClass("images_history_gallery") - item = $(gradioApp().getElementById(tab + '_images_history_set_index')) - item.addClass("images_history_set_index") - item.hide() - } - } - +images_history_tab_list = ["txt2img", "img2img", "extras"] +function images_history_init(){ + if (gradioApp().getElementById('txt2img_images_history_first_page') == null) { + setTimeout(images_history_init, 500) + } else { + for (i in images_history_tab_list ){ + tab = images_history_tab_list[i] + gradioApp().getElementById(tab + '_images_history').classList.add("images_history_gallery") + gradioApp().getElementById(tab + '_images_history_set_index').classList.add("images_history_set_index") + + } + gradioApp().getElementById("txt2img_images_history_first_page").click() + } +} +setTimeout(images_history_init, 500) +var images_history_button_actions = function(){ + if (!this.classList.contains("transform")){ + gallery = this.parentElement + while(!gallery.classList.contains("images_history_gallery")){gallery = gallery.parentElement} + buttons = gallery.querySelectorAll(".gallery-item") + i = 0 + hidden_list = [] + buttons.forEach(function(e){ + if (e.style.display == "none"){ + hidden_list.push(i) + } + i += 1 + }) + if (hidden_list.length > 0){ + setTimeout(images_history_hide_buttons, 10, hidden_list, gallery) + } + + } + images_history_set_image_info(this) + } -setTimeout(init_images_history, 1000) onUiUpdate(function(){ - fullImg_preview = gradioApp().querySelectorAll('#txt2img_images_history img.w-full') - if(fullImg_preview.length > 0){ - fullImg_preview.forEach(set_history_index_from_img); - } - fullImg_preview = gradioApp().querySelectorAll('#img2img_images_history img.w-full') - if(fullImg_preview.length > 0){ - fullImg_preview.forEach(set_history_index_from_img); + for (i in images_history_tab_list ){ + tab = images_history_tab_list[i] + buttons = gradioApp().querySelectorAll('#' + tab + '_images_history .gallery-item') + buttons.forEach(function(bnt){ + bnt.addEventListener('click', images_history_button_actions, true) + }); } }) - -function set_history_gallery_index(item){ - buttons = item.find(".gallery-item") - // alert(item.attr("id") + " " + buttons.length) - index = -1 - i = 0 - buttons.each(function(){ - if($(this).hasClass("!ring-2")){ index = i } - i += 1 - }) - if (index == -1){ - setTimeout(set_history_gallery_index, 10, item) - } else { - item = item.find(".images_history_set_index").first() - item.attr("img_index", index) - item.click() - } -} -function set_history_index_from_img(e){ - if(e && e.parentElement.tagName == 'BUTTON'){ - bnt = $(e).parent() - if (bnt.hasClass("transform")){ - bnt.off("click").on("click",function(){ - set_history_gallery_index($(this).parents(".images_history_gallery").first()) - }) - } else { - bnt.off("mousedown").on("mousedown", function(){ - set_history_gallery_index($(this).parents(".images_history_gallery").first()) - }) - - } - } -} -function images_history_get_current_img(is_image2image, image_path, files){ - head = is_image2image?"img2img":"txt2img" - s = $(gradioApp().getElementById(head + '_images_history_set_index')).attr("img_index") - return [s, image_path, files] +function images_history_hide_buttons(hidden_list, gallery){ + buttons = gallery.querySelectorAll(".gallery-item") + num = 0 + buttons.forEach(function(e){ + if (e.style.display == "none"){ + num += 1 + } + }) + if (num == hidden_list.length){ + setTimeout(images_history_hide_buttons, 10, hidden_list, gallery) + } + for( i in hidden_list){ + buttons[hidden_list[i]].style.display = "none" + } } +function images_history_set_image_info(button){ + item = button.parentElement + while(item.tagName != "DIV"){item = item.parentElement} + buttons = item.querySelectorAll(".gallery-item") + index = -1 + i = 0 + buttons.forEach(function(e){ + if(e==button){index = i} + if(e.style.display != "none"){ + i += 1 + } + }) + gallery = button.parentElement + while(!gallery.classList.contains("images_history_gallery")){gallery = gallery.parentElement} + set_btn = gallery.querySelector(".images_history_set_index") + set_btn.setAttribute("img_index", index) + set_btn.click() +} + +function images_history_get_current_img(tabname, image_path, files){ + s = gradioApp().getElementById(tabname + '_images_history_set_index').getAttribute("img_index") + return [s, image_path, files] +} + +function images_history_delete(tabname, img_path, img_file_name, page_index, filenames, image_index){ + image_index = parseInt(image_index) + tab = gradioApp().getElementById(tabname + '_images_history') + set_btn = tab.querySelector(".images_history_set_index") + buttons = [] + tab.querySelectorAll(".gallery-item").forEach(function(e){ + if (e.style.display != 'none'){ + buttons.push(e) + } + }) + + + img_num = buttons.length / 2 + if (img_num == 1){ + setTimeout(function(tabname){ + gradioApp().getElementById(tabname + '_images_history_renew_page').click() + }, 30, tabname) + } else { + buttons[image_index].style.display = 'none' + buttons[image_index + img_num].style.display = 'none' + if (image_index >= img_num - 1){ + console.log(buttons.length, img_num) + btn = buttons[img_num - 2] + } else { + btn = buttons[image_index + 1] + } + setTimeout(function(btn){btn.click()}, 30, btn) + } + + return [tabname, img_path, img_file_name, page_index, filenames, image_index] +} + +function images_history_turnpage(img_path, page_index, image_index, tabname){ + buttons = gradioApp().getElementById(tabname + '_images_history').querySelectorAll(".gallery-item") + buttons.forEach(function(elem) { + elem.style.display = 'block' + }) + return [img_path, page_index, image_index, tabname] +} diff --git a/javascript/jquery-3.6.0.min.js b/javascript/jquery-3.6.0.min.js deleted file mode 100644 index c4c6022f2..000000000 --- a/javascript/jquery-3.6.0.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 max_page_index else page_index - idx_frm = (page_index - 1) * num - file_list = file_list[idx_frm:idx_frm + num] - print(f"Loading history page {page_index}") - image_index = int(image_index) - if image_index < 0 or image_index > len(file_list) - 1: - current_file = None - hide_image = None - else: - current_file = file_list[int(image_index)] - hide_image = os.path.join(dir_name, current_file) - return [os.path.join(dir_name, file) for file in file_list], page_index, file_list, current_file, hide_image -def first_page_click(dir_name, page_index, image_index): - return get_recent_images(dir_name, 1, 0, image_index) -def end_page_click(dir_name, page_index, image_index): - return get_recent_images(dir_name, -1, 0, image_index) -def prev_page_click(dir_name, page_index, image_index): - return get_recent_images(dir_name, page_index, -1, image_index) -def next_page_click(dir_name, page_index, image_index): - return get_recent_images(dir_name, page_index, 1, image_index) -def page_index_change(dir_name, page_index, image_index): - return get_recent_images(dir_name, page_index, 0, image_index) + #print(image_index) + page_index = int(page_index) + f_list = os.listdir(dir_name) + file_list = [] + for file in f_list: + if file[-4:] == ".txt": + continue + file_list.append(file) + file_list = sorted(file_list, key=lambda file: -os.path.getctime(os.path.join(dir_name, file))) + num = 48 + max_page_index = len(file_list) // num + 1 + page_index = max_page_index if page_index == -1 else page_index + step + page_index = 1 if page_index < 1 else page_index + page_index = max_page_index if page_index > max_page_index else page_index + idx_frm = (page_index - 1) * num + file_list = file_list[idx_frm:idx_frm + num] + #print(f"Loading history page {page_index}") + image_index = int(image_index) + if image_index < 0 or image_index > len(file_list) - 1: + current_file = None + hide_image = None + else: + current_file = file_list[int(image_index)] + hide_image = os.path.join(dir_name, current_file) + return [os.path.join(dir_name, file) for file in file_list], page_index, file_list, current_file, hide_image +def first_page_click(dir_name, page_index, image_index, tabname): + return get_recent_images(dir_name, 1, 0, image_index) +def end_page_click(dir_name, page_index, image_index, tabname): + return get_recent_images(dir_name, -1, 0, image_index) +def prev_page_click(dir_name, page_index, image_index, tabname): + return get_recent_images(dir_name, page_index, -1, image_index) +def next_page_click(dir_name, page_index, image_index, tabname): + return get_recent_images(dir_name, page_index, 1, image_index) +def page_index_change(dir_name, page_index, image_index, tabname): + return get_recent_images(dir_name, page_index, 0, image_index) def show_image_info(num, image_path, filenames): - file = filenames[int(num)] - return file, num, os.path.join(image_path, file) -def delete_image(is_img2img, dir_name, name, page_index, filenames, image_index): - print("filename", name) - path = os.path.join(dir_name, name) - if os.path.exists(path): - print(f"Delete file {path}") - os.remove(path) - images, page_index, file_list, current_file, hide_image = get_recent_images(dir_name, page_index, 0, image_index) - return images, page_index, file_list, current_file, hide_image + #print("set img",num) + file = filenames[int(num)] + return file, num, os.path.join(image_path, file) +def delete_image(tabname, dir_name, name, page_index, filenames, image_index): + #print("filename", name) + path = os.path.join(dir_name, name) + if os.path.exists(path): + print(f"Delete file {path}") + os.remove(path) + new_file_list = [] + for f in filenames: + if f == name: + continue + new_file_list.append(f) + else: + print(f"Not exists file {path}") + new_file_list = filenames + return page_index, new_file_list +def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): + if tabname == "txt2img": + dir_name = opts.outdir_txt2img_samples + elif tabname == "img2img": + dir_name = opts.outdir_img2img_samples + elif tabname == "extras": + dir_name = opts.outdir_extras_samples + with gr.Row(): + renew_page = gr.Button('Renew', elem_id=tabname + "_images_history_renew_page") + first_page = gr.Button('First', elem_id=tabname + "_images_history_first_page") + prev_page = gr.Button('Prev') + page_index = gr.Number(value=1, label="Page Index") + next_page = gr.Button('Next', elem_id=tabname + "_images_history_next_page") + end_page = gr.Button('End') + with gr.Row(elem_id=tabname + "_images_history"): + with gr.Row(): + with gr.Column(): + history_gallery = gr.Gallery(show_label=False).style(grid=6) + with gr.Column(): + with gr.Row(): + delete = gr.Button('Delete') + pnginfo_send_to_txt2img = gr.Button('Send to txt2img') + pnginfo_send_to_img2img = gr.Button('Send to img2img') + with gr.Row(): + with gr.Column(): + img_file_info = gr.Textbox(label="Generate Info") + img_file_name = gr.Textbox(label="File Name") + with gr.Row(): + # hiden items + img_path = gr.Textbox(dir_name, visible=False) + tabname_box = gr.Textbox(tabname, visible=False) + image_index = gr.Textbox(value=-1, visible=False) + set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False) + filenames = gr.State() + hide_image = gr.Image(visible=False, type="pil") + info1 = gr.Textbox(visible=False) + info2 = gr.Textbox(visible=False) -def show_images_history(gr, opts, is_img2img, run_pnginfo, switch_dict): - def id_name(is_img2img, name): - return ("img2img" if is_img2img else "txt2img") + "_" + name - if is_img2img: - dir_name = opts.outdir_img2img_samples - else: - dir_name = opts.outdir_txt2img_samples - with gr.Row(): - first_page = gr.Button('First', elem_id=id_name(is_img2img,"images_history_first_page")) - prev_page = gr.Button('Prev') - page_index = gr.Number(value=1, label="Page Index") - next_page = gr.Button('Next') - end_page = gr.Button('End') - with gr.Row(elem_id=id_name(is_img2img,"images_history")): - with gr.Row(): - with gr.Column(): - history_gallery = gr.Gallery(show_label=False).style(grid=6) - with gr.Column(): - with gr.Row(): - delete = gr.Button('Delete') - pnginfo_send_to_txt2img = gr.Button('Send to txt2img') - pnginfo_send_to_img2img = gr.Button('Send to img2img') - with gr.Row(): - with gr.Column(): - img_file_info = gr.Textbox(dir_name, label="Generate Info") - img_file_name = gr.Textbox(label="File Name") - with gr.Row(): - # hiden items - img_path = gr.Textbox(dir_name, visible=False) - is_img2img_flag = gr.Checkbox(is_img2img, visible=False) - image_index = gr.Textbox(value=-1, visible=False) - set_index = gr.Button('set_index', elem_id=id_name(is_img2img,"images_history_set_index")) - filenames = gr.State() - hide_image = gr.Image(visible=False, type="pil") - info1 = gr.Textbox(visible=False) - info2 = gr.Textbox(visible=False) + + # turn pages + gallery_inputs = [img_path, page_index, image_index, tabname_box] + gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hide_image] - - # turn pages - gallery_inputs = [img_path, page_index, image_index] - gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hide_image] - first_page.click(first_page_click, inputs=gallery_inputs, outputs=gallery_outputs) - next_page.click(next_page_click, inputs=gallery_inputs, outputs=gallery_outputs) - prev_page.click(prev_page_click, inputs=gallery_inputs, outputs=gallery_outputs) - end_page.click(end_page_click, inputs=gallery_inputs, outputs=gallery_outputs) - page_index.submit(page_index_change, inputs=gallery_inputs, outputs=gallery_outputs) - #page_index.change(page_index_change, inputs=[is_img2img_flag, img_path, page_index], outputs=[history_gallery, page_index]) + first_page.click(first_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + next_page.click(next_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + prev_page.click(prev_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + end_page.click(end_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + page_index.submit(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + renew_page.click(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + #page_index.change(page_index_change, inputs=[tabname_box, img_path, page_index], outputs=[history_gallery, page_index]) - #other funcitons - set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[is_img2img_flag, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) - delete.click(delete_image, inputs=[is_img2img_flag, img_path, img_file_name, page_index, filenames, image_index], outputs=gallery_outputs) - hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) - switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') - switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') - - + #other funcitons + set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) + delete.click(delete_image,_js="images_history_delete", inputs=[tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[page_index, filenames]) + hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) + switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') + switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') + + def create_history_tabs(gr, opts, run_pnginfo, switch_dict): - with gr.Blocks(analytics_enabled=False) as images_history: - with gr.Tabs() as tabs: - with gr.Tab("txt2img history", id="images_history_txt2img"): - with gr.Blocks(analytics_enabled=False) as images_history_txt2img: - show_images_history(gr, opts, False, run_pnginfo, switch_dict) - with gr.Tab("img2img history", id="images_history_img2img"): - with gr.Blocks(analytics_enabled=False) as images_history_img2img: - show_images_history(gr, opts, True, run_pnginfo, switch_dict) - return images_history + with gr.Blocks(analytics_enabled=False) as images_history: + with gr.Tabs() as tabs: + with gr.Tab("txt2img history"): + with gr.Blocks(analytics_enabled=False) as images_history_txt2img: + show_images_history(gr, opts, "txt2img", run_pnginfo, switch_dict) + with gr.Tab("img2img history"): + with gr.Blocks(analytics_enabled=False) as images_history_img2img: + show_images_history(gr, opts, "img2img", run_pnginfo, switch_dict) + with gr.Tab("extras history"): + with gr.Blocks(analytics_enabled=False) as images_history_img2img: + show_images_history(gr, opts, "extras", run_pnginfo, switch_dict) + return images_history diff --git a/style.css b/style.css index c0c3f2bb3..ca1cdba1c 100644 --- a/style.css +++ b/style.css @@ -463,3 +463,6 @@ input[type="range"]{ max-width: 32em; padding: 0; } +.images-history-hidden{ + display: none; +} \ No newline at end of file From 45ada1c91025e221df04f911de6377e419f19e3f Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 13:10:11 +0100 Subject: [PATCH 311/460] Correct list style, apply gen forever to both tabs, roll3 on both tabs --- javascript/contextMenus.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index 7852793c1..4e7720658 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -16,7 +16,7 @@ contextMenuInit = function(){ oldMenu.remove() } - let tabButton = gradioApp().querySelector('button') + let tabButton = uiCurrentTab let baseStyle = window.getComputedStyle(tabButton) const contextMenu = document.createElement('nav') @@ -130,9 +130,9 @@ addContextMenuEventListener = initResponse[2] //Start example Context Menu Items -generateOnRepeatId = appendContextMenuOption('#txt2img_generate','Generate forever',function(){ - let genbutton = gradioApp().querySelector('#txt2img_generate'); - let interruptbutton = gradioApp().querySelector('#txt2img_interrupt'); +generateOnRepeat = function(genbuttonid,interruptbuttonid){ + let genbutton = gradioApp().querySelector(genbuttonid); + let interruptbutton = gradioApp().querySelector(interruptbuttonid); if(!interruptbutton.offsetParent){ genbutton.click(); } @@ -142,8 +142,15 @@ generateOnRepeatId = appendContextMenuOption('#txt2img_generate','Generate forev genbutton.click(); } }, - 500)} -) + 500) +} + +generateOnRepeatId = appendContextMenuOption('#txt2img_generate','Generate forever',function(){ + generateOnRepeat('#txt2img_generate','#txt2img_interrupt'); +}) +generateOnRepeatId = appendContextMenuOption('#img2img_generate','Generate forever',function(){ + generateOnRepeat('#img2img_generate','#img2img_interrupt'); +}) cancelGenerateForever = function(){ clearInterval(window.generateOnRepeatInterval) @@ -151,11 +158,12 @@ cancelGenerateForever = function(){ appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever) appendContextMenuOption('#txt2img_generate', 'Cancel generate forever',cancelGenerateForever) - +appendContextMenuOption('#img2img_interrupt','Cancel generate forever',cancelGenerateForever) +appendContextMenuOption('#img2img_generate', 'Cancel generate forever',cancelGenerateForever) appendContextMenuOption('#roll','Roll three', function(){ - let rollbutton = gradioApp().querySelector('#roll'); + let rollbutton = get_uiCurrentTabContent().querySelector('#roll'); setTimeout(function(){rollbutton.click()},100) setTimeout(function(){rollbutton.click()},200) setTimeout(function(){rollbutton.click()},300) From 9b8faefde05464fe6ba51668fe1d361e4fe22339 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 13:19:16 +0100 Subject: [PATCH 312/460] context menus closure --- javascript/contextMenus.js | 83 +++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index 4e7720658..7636c4b33 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -123,52 +123,53 @@ contextMenuInit = function(){ return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener] } -initResponse = contextMenuInit() -appendContextMenuOption = initResponse[0] -removeContextMenuOption = initResponse[1] -addContextMenuEventListener = initResponse[2] +initResponse = contextMenuInit(); +appendContextMenuOption = initResponse[0]; +removeContextMenuOption = initResponse[1]; +addContextMenuEventListener = initResponse[2]; - -//Start example Context Menu Items -generateOnRepeat = function(genbuttonid,interruptbuttonid){ - let genbutton = gradioApp().querySelector(genbuttonid); - let interruptbutton = gradioApp().querySelector(interruptbuttonid); - if(!interruptbutton.offsetParent){ - genbutton.click(); - } - clearInterval(window.generateOnRepeatInterval) - window.generateOnRepeatInterval = setInterval(function(){ +(function(){ + //Start example Context Menu Items + let generateOnRepeat = function(genbuttonid,interruptbuttonid){ + let genbutton = gradioApp().querySelector(genbuttonid); + let interruptbutton = gradioApp().querySelector(interruptbuttonid); if(!interruptbutton.offsetParent){ genbutton.click(); } - }, - 500) -} - -generateOnRepeatId = appendContextMenuOption('#txt2img_generate','Generate forever',function(){ - generateOnRepeat('#txt2img_generate','#txt2img_interrupt'); -}) -generateOnRepeatId = appendContextMenuOption('#img2img_generate','Generate forever',function(){ - generateOnRepeat('#img2img_generate','#img2img_interrupt'); -}) - -cancelGenerateForever = function(){ - clearInterval(window.generateOnRepeatInterval) -} - -appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever) -appendContextMenuOption('#txt2img_generate', 'Cancel generate forever',cancelGenerateForever) -appendContextMenuOption('#img2img_interrupt','Cancel generate forever',cancelGenerateForever) -appendContextMenuOption('#img2img_generate', 'Cancel generate forever',cancelGenerateForever) - -appendContextMenuOption('#roll','Roll three', - function(){ - let rollbutton = get_uiCurrentTabContent().querySelector('#roll'); - setTimeout(function(){rollbutton.click()},100) - setTimeout(function(){rollbutton.click()},200) - setTimeout(function(){rollbutton.click()},300) + clearInterval(window.generateOnRepeatInterval) + window.generateOnRepeatInterval = setInterval(function(){ + if(!interruptbutton.offsetParent){ + genbutton.click(); + } + }, + 500) } -) + + appendContextMenuOption('#txt2img_generate','Generate forever',function(){ + generateOnRepeat('#txt2img_generate','#txt2img_interrupt'); + }) + appendContextMenuOption('#img2img_generate','Generate forever',function(){ + generateOnRepeat('#img2img_generate','#img2img_interrupt'); + }) + + let cancelGenerateForever = function(){ + clearInterval(window.generateOnRepeatInterval) + } + + appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever) + appendContextMenuOption('#txt2img_generate', 'Cancel generate forever',cancelGenerateForever) + appendContextMenuOption('#img2img_interrupt','Cancel generate forever',cancelGenerateForever) + appendContextMenuOption('#img2img_generate', 'Cancel generate forever',cancelGenerateForever) + + appendContextMenuOption('#roll','Roll three', + function(){ + let rollbutton = get_uiCurrentTabContent().querySelector('#roll'); + setTimeout(function(){rollbutton.click()},100) + setTimeout(function(){rollbutton.click()},200) + setTimeout(function(){rollbutton.click()},300) + } + ) +})(); //End example Context Menu Items onUiUpdate(function(){ From 92d7a138857b308c97a8d009848f642aeb93d6c8 Mon Sep 17 00:00:00 2001 From: Martin Cairns Date: Tue, 11 Oct 2022 00:02:44 +0100 Subject: [PATCH 313/460] Handle different parameters for DPM fast & adaptive --- modules/sd_samplers.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index d168b938f..eee52e7d7 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -57,7 +57,7 @@ def set_samplers(): global samplers, samplers_for_img2img hidden = set(opts.hide_samplers) - hidden_img2img = set(opts.hide_samplers + ['PLMS', 'DPM fast', 'DPM adaptive']) + hidden_img2img = set(opts.hide_samplers + ['PLMS']) samplers = [x for x in all_samplers if x.name not in hidden] samplers_for_img2img = [x for x in all_samplers if x.name not in hidden_img2img] @@ -365,16 +365,27 @@ class KDiffusionSampler: else: sigmas = self.model_wrap.get_sigmas(steps) - noise = noise * sigmas[steps - t_enc - 1] - xi = x + noise - - extra_params_kwargs = self.initialize(p) - sigma_sched = sigmas[steps - t_enc - 1:] + print('check values same', sigmas[steps - t_enc - 1] , sigma_sched[0], sigmas[steps - t_enc - 1] - sigma_sched[0]) + xi = x + noise * sigma_sched[0] + + extra_params_kwargs = self.initialize(p) + if 'sigma_min' in inspect.signature(self.func).parameters: + ## last sigma is zero which is allowed by DPM Fast & Adaptive so taking value before last + extra_params_kwargs['sigma_min'] = sigma_sched[-2] + if 'sigma_max' in inspect.signature(self.func).parameters: + extra_params_kwargs['sigma_max'] = sigma_sched[0] + if 'n' in inspect.signature(self.func).parameters: + extra_params_kwargs['n'] = len(sigma_sched) - 1 + if 'sigma_sched' in inspect.signature(self.func).parameters: + extra_params_kwargs['sigma_sched'] = sigma_sched + if 'sigmas' in inspect.signature(self.func).parameters: + extra_params_kwargs['sigmas'] = sigma_sched self.model_wrap_cfg.init_latent = x - return self.func(self.model_wrap_cfg, xi, sigma_sched, extra_args={'cond': conditioning, 'uncond': unconditional_conditioning, 'cond_scale': p.cfg_scale}, disable=False, callback=self.callback_state, **extra_params_kwargs) + return self.func(self.model_wrap_cfg, xi, extra_args={'cond': conditioning, 'uncond': unconditional_conditioning, 'cond_scale': p.cfg_scale}, disable=False, callback=self.callback_state, **extra_params_kwargs) + def sample(self, p, x, conditioning, unconditional_conditioning, steps=None): steps = steps or p.steps From 1eae3076078f00ecc5d0fac3c77fffb85cd2eb77 Mon Sep 17 00:00:00 2001 From: Martin Cairns Date: Tue, 11 Oct 2022 00:04:06 +0100 Subject: [PATCH 314/460] Remove debug code for checking that first sigma value is same after code cleanup --- modules/sd_samplers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index eee52e7d7..32272916f 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -366,7 +366,6 @@ class KDiffusionSampler: sigmas = self.model_wrap.get_sigmas(steps) sigma_sched = sigmas[steps - t_enc - 1:] - print('check values same', sigmas[steps - t_enc - 1] , sigma_sched[0], sigmas[steps - t_enc - 1] - sigma_sched[0]) xi = x + noise * sigma_sched[0] extra_params_kwargs = self.initialize(p) From eacc03b16730bcc5be95cda2d7c966ff1b4a8263 Mon Sep 17 00:00:00 2001 From: Martin Cairns Date: Tue, 11 Oct 2022 00:36:00 +0100 Subject: [PATCH 315/460] Fix typo in comments --- modules/sd_samplers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py index 32272916f..20309e06b 100644 --- a/modules/sd_samplers.py +++ b/modules/sd_samplers.py @@ -370,7 +370,7 @@ class KDiffusionSampler: extra_params_kwargs = self.initialize(p) if 'sigma_min' in inspect.signature(self.func).parameters: - ## last sigma is zero which is allowed by DPM Fast & Adaptive so taking value before last + ## last sigma is zero which isn't allowed by DPM Fast & Adaptive so taking value before last extra_params_kwargs['sigma_min'] = sigma_sched[-2] if 'sigma_max' in inspect.signature(self.func).parameters: extra_params_kwargs['sigma_max'] = sigma_sched[0] From 87d63bbab5c973ac5cec777ef7304d28f1ab3f24 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Tue, 11 Oct 2022 20:37:03 +0800 Subject: [PATCH 316/460] images history improvement --- javascript/images_history.js | 6 ++---- modules/images_history.py | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/javascript/images_history.js b/javascript/images_history.js index 9a3e00a00..d62eb1814 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -93,7 +93,6 @@ function images_history_delete(tabname, img_path, img_file_name, page_index, fil buttons.push(e) } }) - img_num = buttons.length / 2 if (img_num == 1){ @@ -110,15 +109,14 @@ function images_history_delete(tabname, img_path, img_file_name, page_index, fil btn = buttons[image_index + 1] } setTimeout(function(btn){btn.click()}, 30, btn) - } - + } return [tabname, img_path, img_file_name, page_index, filenames, image_index] } function images_history_turnpage(img_path, page_index, image_index, tabname){ buttons = gradioApp().getElementById(tabname + '_images_history').querySelectorAll(".gallery-item") buttons.forEach(function(elem) { - elem.style.display = 'block' + elem.style.display = 'block' }) return [img_path, page_index, image_index, tabname] } diff --git a/modules/images_history.py b/modules/images_history.py index 01d11a01c..23f55b302 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -64,12 +64,12 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): elif tabname == "extras": dir_name = opts.outdir_extras_samples with gr.Row(): - renew_page = gr.Button('Renew', elem_id=tabname + "_images_history_renew_page") - first_page = gr.Button('First', elem_id=tabname + "_images_history_first_page") - prev_page = gr.Button('Prev') - page_index = gr.Number(value=1, label="Page Index") - next_page = gr.Button('Next', elem_id=tabname + "_images_history_next_page") - end_page = gr.Button('End') + renew_page = gr.Button('Renew', elem_id=tabname + "_images_history_renew_page") + first_page = gr.Button('First', elem_id=tabname + "_images_history_first_page") + prev_page = gr.Button('Prev') + page_index = gr.Number(value=1, label="Page Index") + next_page = gr.Button('Next', elem_id=tabname + "_images_history_next_page") + end_page = gr.Button('End') with gr.Row(elem_id=tabname + "_images_history"): with gr.Row(): with gr.Column(): @@ -84,15 +84,15 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): img_file_info = gr.Textbox(label="Generate Info") img_file_name = gr.Textbox(label="File Name") with gr.Row(): - # hiden items - img_path = gr.Textbox(dir_name, visible=False) - tabname_box = gr.Textbox(tabname, visible=False) - image_index = gr.Textbox(value=-1, visible=False) - set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False) - filenames = gr.State() - hide_image = gr.Image(visible=False, type="pil") - info1 = gr.Textbox(visible=False) - info2 = gr.Textbox(visible=False) + # hiden items + img_path = gr.Textbox(dir_name, visible=False) + tabname_box = gr.Textbox(tabname, visible=False) + image_index = gr.Textbox(value=-1, visible=False) + set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False) + filenames = gr.State() + hide_image = gr.Image(visible=False, type="pil") + info1 = gr.Textbox(visible=False) + info2 = gr.Textbox(visible=False) # turn pages From b372f5538bee4feba87080af4f3acf1e437accc6 Mon Sep 17 00:00:00 2001 From: Ben <110583491+TheLastBen@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:34:07 +0100 Subject: [PATCH 317/460] Save some space --- style.css | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/style.css b/style.css index 00a3d07fe..38410ca44 100644 --- a/style.css +++ b/style.css @@ -2,6 +2,18 @@ max-width: 100%; } +#txt2img_token_counter { + height: 0px; +} + +#img2img_token_counter { + height: 0px; +} + +#negative_prompt { + width: 97.9%; +} + .output-html p {margin: 0 0.5em;} .row > *, From 87b77cad5f3017c952a7dfec0e7904a9df5b72fd Mon Sep 17 00:00:00 2001 From: Ben <110583491+TheLastBen@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:37:16 +0100 Subject: [PATCH 318/460] Layout fix --- modules/ui.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index df6530590..de4cd7f23 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -550,15 +550,15 @@ def create_ui(wrap_gradio_gpu_call): button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder' open_txt2img_folder = gr.Button(folder_symbol, elem_id=button_id) - with gr.Row(): - do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) + with gr.Row(): + do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) - with gr.Row(): - download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) + with gr.Row(): + download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) - with gr.Group(): - html_info = gr.HTML() - generation_info = gr.Textbox(visible=False) + with gr.Group(): + html_info = gr.HTML() + generation_info = gr.Textbox(visible=False) connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) @@ -738,15 +738,15 @@ def create_ui(wrap_gradio_gpu_call): button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder' open_img2img_folder = gr.Button(folder_symbol, elem_id=button_id) - with gr.Row(): - do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) + with gr.Row(): + do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False) - with gr.Row(): - download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) + with gr.Row(): + download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) - with gr.Group(): - html_info = gr.HTML() - generation_info = gr.Textbox(visible=False) + with gr.Group(): + html_info = gr.HTML() + generation_info = gr.Textbox(visible=False) connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) From 861297cefe2bb663f4e09dd4778a4cb93ebe8ff1 Mon Sep 17 00:00:00 2001 From: Ben <110583491+TheLastBen@users.noreply.github.com> Date: Tue, 11 Oct 2022 08:08:45 +0100 Subject: [PATCH 319/460] add a space holder --- modules/ui.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index de4cd7f23..fc0f3d3cb 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -429,7 +429,10 @@ def create_toprow(is_img2img): with gr.Row(): with gr.Column(scale=8): - negative_prompt = gr.Textbox(label="Negative prompt", elem_id="negative_prompt", show_label=False, placeholder="Negative prompt", lines=2) + with gr.Row(): + negative_prompt = gr.Textbox(label="Negative prompt", elem_id="negative_prompt", show_label=False, placeholder="Negative prompt", lines=2) + with gr.Column(scale=1, elem_id="roll_col"): + sh = gr.Button(elem_id="sh", visible=True) with gr.Column(scale=1, elem_id="style_neg_col"): prompt_style2 = gr.Dropdown(label="Style 2", elem_id=f"{id_part}_style2_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())), visible=len(shared.prompt_styles.styles) > 1) From 031dc8cd7fa6bc74b44114715b28e0737342de37 Mon Sep 17 00:00:00 2001 From: Ben <110583491+TheLastBen@users.noreply.github.com> Date: Tue, 11 Oct 2022 08:08:47 +0100 Subject: [PATCH 320/460] space holder --- style.css | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/style.css b/style.css index 38410ca44..d1c866fcb 100644 --- a/style.css +++ b/style.css @@ -10,8 +10,16 @@ height: 0px; } -#negative_prompt { - width: 97.9%; +#sh{ + min-width: 2em; + min-height: 2em; + max-width: 2em; + max-height: 2em; + flex-grow: 0; + padding-left: 0.25em; + padding-right: 0.25em; + margin: 0.1em 0; + opacity: 0%; } .output-html p {margin: 0 0.5em;} From 54c519943a24881ea61af5a73dedbab92f9431ce Mon Sep 17 00:00:00 2001 From: Ben <110583491+TheLastBen@users.noreply.github.com> Date: Tue, 11 Oct 2022 10:16:53 +0100 Subject: [PATCH 321/460] Update style.css --- style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/style.css b/style.css index d1c866fcb..ecb51bb02 100644 --- a/style.css +++ b/style.css @@ -20,6 +20,7 @@ padding-right: 0.25em; margin: 0.1em 0; opacity: 0%; + cursor: default; } .output-html p {margin: 0 0.5em;} From 210fd72babb8314b280a7b5ef8603c62024a22db Mon Sep 17 00:00:00 2001 From: parsec501 <105080989+parsec501@users.noreply.github.com> Date: Tue, 11 Oct 2022 14:37:01 +0200 Subject: [PATCH 322/460] Added 'suggestion' flair to suggestion template --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d6..eda42fa7d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: '' -labels: '' +labels: 'suggestion' assignees: '' --- From 4e485b79238666ace2b270045f73a12e5ccc7af9 Mon Sep 17 00:00:00 2001 From: JamnedZ Date: Tue, 11 Oct 2022 16:38:03 +0700 Subject: [PATCH 323/460] Added installation of pyngrok if needed --- launch.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launch.py b/launch.py index e1000f559..16627a032 100644 --- a/launch.py +++ b/launch.py @@ -104,6 +104,7 @@ def prepare_enviroment(): args, skip_torch_cuda_test = extract_arg(args, '--skip-torch-cuda-test') xformers = '--xformers' in args deepdanbooru = '--deepdanbooru' in args + ngrok = '--ngrok' in args try: commit = run(f"{git} rev-parse HEAD").strip() @@ -134,6 +135,9 @@ def prepare_enviroment(): if not is_installed("deepdanbooru") and deepdanbooru: run_pip("install git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] tensorflow==2.10.0 tensorflow-io==0.27.0", "deepdanbooru") + if not is_installed("pyngrok") and ngrok: + run_pip("install pyngrok", "ngrok") + os.makedirs(dir_repos, exist_ok=True) git_clone("https://github.com/CompVis/stable-diffusion.git", repo_dir('stable-diffusion'), "Stable Diffusion", stable_diffusion_commit_hash) From 59925644480b6fd84f6bb84b4df7d4fbc6a0cce8 Mon Sep 17 00:00:00 2001 From: JamnedZ Date: Tue, 11 Oct 2022 16:40:27 +0700 Subject: [PATCH 324/460] Cleaned ngrok integration --- modules/ngrok.py | 15 +++++++++++++++ modules/shared.py | 1 + modules/ui.py | 5 +++++ 3 files changed, 21 insertions(+) create mode 100644 modules/ngrok.py diff --git a/modules/ngrok.py b/modules/ngrok.py new file mode 100644 index 000000000..17e6976f7 --- /dev/null +++ b/modules/ngrok.py @@ -0,0 +1,15 @@ +from pyngrok import ngrok, conf, exception + + +def connect(token, port): + if token == None: + token = 'None' + conf.get_default().auth_token = token + try: + public_url = ngrok.connect(port).public_url + except exception.PyngrokNgrokError: + print(f'Invalid ngrok authtoken, ngrok connection aborted.\n' + f'Your token: {token}, get the right one on https://dashboard.ngrok.com/get-started/your-authtoken') + else: + print(f'ngrok connected to localhost:{port}! URL: {public_url}\n' + 'You can use this link after the launch is complete.') \ No newline at end of file diff --git a/modules/shared.py b/modules/shared.py index 8753015e5..375e3afb6 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -38,6 +38,7 @@ parser.add_argument("--always-batch-cond-uncond", action='store_true', help="dis parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.") parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast") parser.add_argument("--share", action='store_true', help="use share=True for gradio and make the UI accessible through their site (doesn't work for me but you might have better luck)") +parser.add_argument("--ngrok", type=str, help="ngrok authtoken, alternative to gradio --share", default=None) parser.add_argument("--codeformer-models-path", type=str, help="Path to directory with codeformer model file(s).", default=os.path.join(models_path, 'Codeformer')) parser.add_argument("--gfpgan-models-path", type=str, help="Path to directory with GFPGAN model file(s).", default=os.path.join(models_path, 'GFPGAN')) parser.add_argument("--esrgan-models-path", type=str, help="Path to directory with ESRGAN model file(s).", default=os.path.join(models_path, 'ESRGAN')) diff --git a/modules/ui.py b/modules/ui.py index fc0f3d3cb..f57f32db7 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -51,6 +51,11 @@ if not cmd_opts.share and not cmd_opts.listen: gradio.utils.version_check = lambda: None gradio.utils.get_local_ip_address = lambda: '127.0.0.1' +if cmd_opts.ngrok != None: + import modules.ngrok as ngrok + print('ngrok authtoken detected, trying to connect...') + ngrok.connect(cmd_opts.ngrok, cmd_opts.port if cmd_opts.port != None else 7860) + def gr_show(visible=True): return {"visible": visible, "__type__": "update"} From a004d1a855311b0d7ff2976a4e31b0247ad9d1f6 Mon Sep 17 00:00:00 2001 From: JamnedZ Date: Tue, 11 Oct 2022 16:48:27 +0700 Subject: [PATCH 325/460] Added new line at the end of ngrok.py --- modules/ngrok.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ngrok.py b/modules/ngrok.py index 17e6976f7..7d03a6df5 100644 --- a/modules/ngrok.py +++ b/modules/ngrok.py @@ -12,4 +12,4 @@ def connect(token, port): f'Your token: {token}, get the right one on https://dashboard.ngrok.com/get-started/your-authtoken') else: print(f'ngrok connected to localhost:{port}! URL: {public_url}\n' - 'You can use this link after the launch is complete.') \ No newline at end of file + 'You can use this link after the launch is complete.') From 873efeed49bb5197a42da18272115b326c5d68f3 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 15:51:22 +0300 Subject: [PATCH 326/460] rename hypernetwork dir to hypernetworks to prevent clash with an old filename that people who use zip instead of git clone will have --- modules/{hypernetwork => hypernetworks}/hypernetwork.py | 0 modules/{hypernetwork => hypernetworks}/ui.py | 2 +- modules/sd_hijack.py | 2 +- modules/sd_hijack_optimizations.py | 2 +- modules/shared.py | 2 +- modules/ui.py | 2 +- scripts/xy_grid.py | 2 +- webui.py | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename modules/{hypernetwork => hypernetworks}/hypernetwork.py (100%) rename modules/{hypernetwork => hypernetworks}/ui.py (92%) diff --git a/modules/hypernetwork/hypernetwork.py b/modules/hypernetworks/hypernetwork.py similarity index 100% rename from modules/hypernetwork/hypernetwork.py rename to modules/hypernetworks/hypernetwork.py diff --git a/modules/hypernetwork/ui.py b/modules/hypernetworks/ui.py similarity index 92% rename from modules/hypernetwork/ui.py rename to modules/hypernetworks/ui.py index f6d1d0a35..811bc31eb 100644 --- a/modules/hypernetwork/ui.py +++ b/modules/hypernetworks/ui.py @@ -6,7 +6,7 @@ import gradio as gr import modules.textual_inversion.textual_inversion import modules.textual_inversion.preprocess from modules import sd_hijack, shared -from modules.hypernetwork import hypernetwork +from modules.hypernetworks import hypernetwork def create_hypernetwork(name): diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index f873049a9..f07ec0416 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -37,7 +37,7 @@ def apply_optimizations(): def undo_optimizations(): - from modules.hypernetwork import hypernetwork + from modules.hypernetworks import hypernetwork ldm.modules.attention.CrossAttention.forward = hypernetwork.attention_CrossAttention_forward ldm.modules.diffusionmodules.model.nonlinearity = diffusionmodules_model_nonlinearity diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 27e571fcd..3349b9c3c 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -9,7 +9,7 @@ from ldm.util import default from einops import rearrange from modules import shared -from modules.hypernetwork import hypernetwork +from modules.hypernetworks import hypernetwork if shared.cmd_opts.xformers or shared.cmd_opts.force_enable_xformers: diff --git a/modules/shared.py b/modules/shared.py index 375e3afb6..1dc2ccf20 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -14,7 +14,7 @@ import modules.sd_models import modules.styles import modules.devices as devices from modules import sd_samplers -from modules.hypernetwork import hypernetwork +from modules.hypernetworks import hypernetwork from modules.paths import models_path, script_path, sd_path sd_model_file = os.path.join(script_path, 'model.ckpt') diff --git a/modules/ui.py b/modules/ui.py index f57f32db7..42e5d8663 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -39,7 +39,7 @@ import modules.generation_parameters_copypaste from modules import prompt_parser from modules.images import save_image import modules.textual_inversion.ui -import modules.hypernetwork.ui +import modules.hypernetworks.ui # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI mimetypes.init() diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 16918c99c..cddb192a7 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -11,7 +11,7 @@ import modules.scripts as scripts import gradio as gr from modules import images -from modules.hypernetwork import hypernetwork +from modules.hypernetworks import hypernetwork from modules.processing import process_images, Processed, get_correct_sampler from modules.shared import opts, cmd_opts, state import modules.shared as shared diff --git a/webui.py b/webui.py index ba2156c84..faa38a0df 100644 --- a/webui.py +++ b/webui.py @@ -29,7 +29,7 @@ from modules import devices from modules import modelloader from modules.paths import script_path from modules.shared import cmd_opts -import modules.hypernetwork.hypernetwork +import modules.hypernetworks.hypernetwork modelloader.cleanup_models() modules.sd_models.setup_model() From b0583be0884cd17dafb408fd79b52b2a0a972563 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 15:54:34 +0300 Subject: [PATCH 327/460] more renames --- modules/hypernetworks/ui.py | 4 ++-- modules/ui.py | 4 ++-- webui.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index 811bc31eb..e7540f41e 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -13,7 +13,7 @@ def create_hypernetwork(name): fn = os.path.join(shared.cmd_opts.hypernetwork_dir, f"{name}.pt") assert not os.path.exists(fn), f"file {fn} already exists" - hypernet = modules.hypernetwork.hypernetwork.Hypernetwork(name=name) + hypernet = modules.hypernetworks.hypernetwork.Hypernetwork(name=name) hypernet.save(fn) shared.reload_hypernetworks() @@ -28,7 +28,7 @@ def train_hypernetwork(*args): try: sd_hijack.undo_optimizations() - hypernetwork, filename = modules.hypernetwork.hypernetwork.train_hypernetwork(*args) + hypernetwork, filename = modules.hypernetworks.hypernetwork.train_hypernetwork(*args) res = f""" Training {'interrupted' if shared.state.interrupted else 'finished'} at {hypernetwork.step} steps. diff --git a/modules/ui.py b/modules/ui.py index 42e5d8663..ee333c3b4 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1111,7 +1111,7 @@ def create_ui(wrap_gradio_gpu_call): ) create_hypernetwork.click( - fn=modules.hypernetwork.ui.create_hypernetwork, + fn=modules.hypernetworks.ui.create_hypernetwork, inputs=[ new_hypernetwork_name, ], @@ -1164,7 +1164,7 @@ def create_ui(wrap_gradio_gpu_call): ) train_hypernetwork.click( - fn=wrap_gradio_gpu_call(modules.hypernetwork.ui.train_hypernetwork, extra_outputs=[gr.update()]), + fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]), _js="start_training_textual_inversion", inputs=[ train_hypernetwork_name, diff --git a/webui.py b/webui.py index faa38a0df..338f58e13 100644 --- a/webui.py +++ b/webui.py @@ -83,7 +83,7 @@ modules.scripts.load_scripts(os.path.join(script_path, "scripts")) shared.sd_model = modules.sd_models.load_model() shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) -shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetwork.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) +shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetworks.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) def webui(): From 5766ce21abc1986c94d8bd3279b6f4d5205ba984 Mon Sep 17 00:00:00 2001 From: ClashSAN <98228077+ClashSAN@users.noreply.github.com> Date: Tue, 11 Oct 2022 13:20:03 +0000 Subject: [PATCH 328/460] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e9387686..a10faa01a 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web - also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2` - No token limit for prompts (original stable diffusion lets you use up to 75 tokens) - DeepDanbooru integration, creates danbooru style tags for anime prompts (add --deepdanbooru to commandline args) -- [xformers](https://github.com/mv-lab/swin2sr), major speed increase for select cards: (add --xformers to commandline args) +- [xformers](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers), major speed increase for select cards: (add --xformers to commandline args) ## Installation and Running Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs. From d01a2d01560b31937df1f3433d210c18f97d32fa Mon Sep 17 00:00:00 2001 From: papuSpartan Date: Tue, 11 Oct 2022 08:03:31 -0500 Subject: [PATCH 329/460] move list refresh to webui.py and add stdout indicating it's doing so --- modules/ui.py | 3 --- webui.py | 2 ++ 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 06ff118f8..ae9317a36 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -39,7 +39,6 @@ import modules.generation_parameters_copypaste from modules import prompt_parser from modules.images import save_image import modules.textual_inversion.ui -from modules.sd_models import list_models # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI mimetypes.init() @@ -1291,8 +1290,6 @@ Requested path was: {f} shared.state.interrupt() settings_interface.gradio_ref.do_restart = True - # refresh models so that new models/.ckpt's show up on reload - list_models() restart_gradio.click( fn=request_restart, diff --git a/webui.py b/webui.py index 270584f77..94098c4cd 100644 --- a/webui.py +++ b/webui.py @@ -124,6 +124,8 @@ def webui(): modules.scripts.reload_scripts(os.path.join(script_path, "scripts")) print('Reloading modules: modules.ui') importlib.reload(modules.ui) + print('Refreshing Model List') + modules.sd_models.list_models() print('Restarting Gradio') From 66b7d7584f0b44ce1316425808c27ca7df38293c Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 17:03:00 +0300 Subject: [PATCH 330/460] become even stricter with pickles no pickle shall pass thank you again, RyotaK --- modules/safe.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/modules/safe.py b/modules/safe.py index 059174632..20be16a50 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -10,6 +10,7 @@ import torch import numpy import _codecs import zipfile +import re # PyTorch 1.13 and later have _TypedStorage renamed to TypedStorage @@ -54,11 +55,27 @@ class RestrictedUnpickler(pickle.Unpickler): raise pickle.UnpicklingError(f"global '{module}/{name}' is forbidden") +allowed_zip_names = ["archive/data.pkl", "archive/version"] +allowed_zip_names_re = re.compile(r"^archive/data/\d+$") + + +def check_zip_filenames(filename, names): + for name in names: + if name in allowed_zip_names: + continue + if allowed_zip_names_re.match(name): + continue + + raise Exception(f"bad file inside {filename}: {name}") + + def check_pt(filename): try: # new pytorch format is a zip file with zipfile.ZipFile(filename) as z: + check_zip_filenames(filename, z.namelist()) + with z.open('archive/data.pkl') as file: unpickler = RestrictedUnpickler(file) unpickler.load() From e0ee5bf703996b33e6d97aa36e0973ceedc88503 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 17:08:03 +0300 Subject: [PATCH 331/460] add codeowners file so stop the great guys who are collaborating on the project from merging in PRs. --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..935fedcf2 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @AUTOMATIC1111 From c0484f1b986ce7acb0e3596f6089a191279f5442 Mon Sep 17 00:00:00 2001 From: brkirch Date: Mon, 10 Oct 2022 22:48:54 -0400 Subject: [PATCH 332/460] Add cross-attention optimization from InvokeAI * Add cross-attention optimization from InvokeAI (~30% speed improvement on MPS) * Add command line option for it * Make it default when CUDA is unavailable --- modules/sd_hijack.py | 5 +- modules/sd_hijack_optimizations.py | 79 ++++++++++++++++++++++++++++++ modules/shared.py | 5 +- 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index f07ec0416..5a1b167fa 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -30,8 +30,11 @@ def apply_optimizations(): elif cmd_opts.opt_split_attention_v1: print("Applying v1 cross attention optimization.") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 + elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention_invokeai or not torch.cuda.is_available()): + print("Applying cross attention optimization (InvokeAI).") + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_invokeAI elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): - print("Applying cross attention optimization.") + print("Applying cross attention optimization (Doggettx).") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 3349b9c3c..870226c50 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -1,6 +1,7 @@ import math import sys import traceback +import psutil import torch from torch import einsum @@ -116,6 +117,84 @@ def split_cross_attention_forward(self, x, context=None, mask=None): return self.to_out(r2) +# -- From https://github.com/invoke-ai/InvokeAI/blob/main/ldm/modules/attention.py (with hypernetworks support added) -- + +mem_total_gb = psutil.virtual_memory().total // (1 << 30) + +def einsum_op_compvis(q, k, v): + s = einsum('b i d, b j d -> b i j', q, k) + s = s.softmax(dim=-1, dtype=s.dtype) + return einsum('b i j, b j d -> b i d', s, v) + +def einsum_op_slice_0(q, k, v, slice_size): + r = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device, dtype=q.dtype) + for i in range(0, q.shape[0], slice_size): + end = i + slice_size + r[i:end] = einsum_op_compvis(q[i:end], k[i:end], v[i:end]) + return r + +def einsum_op_slice_1(q, k, v, slice_size): + r = torch.zeros(q.shape[0], q.shape[1], v.shape[2], device=q.device, dtype=q.dtype) + for i in range(0, q.shape[1], slice_size): + end = i + slice_size + r[:, i:end] = einsum_op_compvis(q[:, i:end], k, v) + return r + +def einsum_op_mps_v1(q, k, v): + if q.shape[1] <= 4096: # (512x512) max q.shape[1]: 4096 + return einsum_op_compvis(q, k, v) + else: + slice_size = math.floor(2**30 / (q.shape[0] * q.shape[1])) + return einsum_op_slice_1(q, k, v, slice_size) + +def einsum_op_mps_v2(q, k, v): + if mem_total_gb > 8 and q.shape[1] <= 4096: + return einsum_op_compvis(q, k, v) + else: + return einsum_op_slice_0(q, k, v, 1) + +def einsum_op_tensor_mem(q, k, v, max_tensor_mb): + size_mb = q.shape[0] * q.shape[1] * k.shape[1] * q.element_size() // (1 << 20) + if size_mb <= max_tensor_mb: + return einsum_op_compvis(q, k, v) + div = 1 << int((size_mb - 1) / max_tensor_mb).bit_length() + if div <= q.shape[0]: + return einsum_op_slice_0(q, k, v, q.shape[0] // div) + return einsum_op_slice_1(q, k, v, max(q.shape[1] // div, 1)) + +def einsum_op(q, k, v): + if q.device.type == 'mps': + if mem_total_gb >= 32: + return einsum_op_mps_v1(q, k, v) + return einsum_op_mps_v2(q, k, v) + + # Smaller slices are faster due to L2/L3/SLC caches. + # Tested on i7 with 8MB L3 cache. + return einsum_op_tensor_mem(q, k, v, 32) + +def split_cross_attention_forward_invokeAI(self, x, context=None, mask=None): + h = self.heads + + q = self.to_q(x) + context = default(context, x) + + hypernetwork = shared.loaded_hypernetwork + hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) + + if hypernetwork_layers is not None: + k = self.to_k(hypernetwork_layers[0](context)) * self.scale + v = self.to_v(hypernetwork_layers[1](context)) + else: + k = self.to_k(context) * self.scale + v = self.to_v(context) + del context, x + + q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) + r = einsum_op(q, k, v) + return self.to_out(rearrange(r, '(b h) n d -> b n (h d)', h=h)) + +# -- End of code from https://github.com/invoke-ai/InvokeAI/blob/main/ldm/modules/attention.py -- + def xformers_attention_forward(self, x, context=None, mask=None): h = self.heads q_in = self.to_q(x) diff --git a/modules/shared.py b/modules/shared.py index 1dc2ccf20..20b45f231 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -50,9 +50,10 @@ parser.add_argument("--ldsr-models-path", type=str, help="Path to directory with parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers") parser.add_argument("--force-enable-xformers", action='store_true', help="enable xformers for cross attention layers regardless of whether the checking code thinks you can run it; do not make bug reports if this fails to work") parser.add_argument("--deepdanbooru", action='store_true', help="enable deepdanbooru interrogator") -parser.add_argument("--opt-split-attention", action='store_true', help="force-enables cross-attention layer optimization. By default, it's on for torch.cuda and off for other torch devices.") -parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") +parser.add_argument("--opt-split-attention", action='store_true', help="force-enables Doggettx's cross-attention layer optimization. By default, it's on for torch cuda.") +parser.add_argument("--opt-split-attention-invokeai", action='store_true', help="force-enables InvokeAI's cross-attention layer optimization. By default, it's on when cuda is unavailable.") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") +parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") parser.add_argument("--use-cpu", nargs='+',choices=['SD', 'GFPGAN', 'BSRGAN', 'ESRGAN', 'SCUNet', 'CodeFormer'], help="use CPU as torch device for specified modules", default=[]) parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests") parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None) From 98fd5cde72d5bda1620ab78416c7828fdc3dc10b Mon Sep 17 00:00:00 2001 From: brkirch Date: Mon, 10 Oct 2022 23:55:48 -0400 Subject: [PATCH 333/460] Add check for psutil --- modules/sd_hijack.py | 10 ++++++++-- modules/sd_hijack_optimizations.py | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 5a1b167fa..ac70f8767 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -10,6 +10,7 @@ from torch.nn.functional import silu import modules.textual_inversion.textual_inversion from modules import prompt_parser, devices, sd_hijack_optimizations, shared from modules.shared import opts, device, cmd_opts +from modules.sd_hijack_optimizations import invokeAI_mps_available import ldm.modules.attention import ldm.modules.diffusionmodules.model @@ -31,8 +32,13 @@ def apply_optimizations(): print("Applying v1 cross attention optimization.") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention_invokeai or not torch.cuda.is_available()): - print("Applying cross attention optimization (InvokeAI).") - ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_invokeAI + if not invokeAI_mps_available and shared.device.type == 'mps': + print("The InvokeAI cross attention optimization for MPS requires the psutil package which is not installed.") + print("Applying v1 cross attention optimization.") + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1 + else: + print("Applying cross attention optimization (InvokeAI).") + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_invokeAI elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()): print("Applying cross attention optimization (Doggettx).") ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 870226c50..2a4ac7e00 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -1,7 +1,7 @@ import math import sys import traceback -import psutil +import importlib import torch from torch import einsum @@ -117,9 +117,20 @@ def split_cross_attention_forward(self, x, context=None, mask=None): return self.to_out(r2) -# -- From https://github.com/invoke-ai/InvokeAI/blob/main/ldm/modules/attention.py (with hypernetworks support added) -- -mem_total_gb = psutil.virtual_memory().total // (1 << 30) +def check_for_psutil(): + try: + spec = importlib.util.find_spec('psutil') + return spec is not None + except ModuleNotFoundError: + return False + +invokeAI_mps_available = check_for_psutil() + +# -- Taken from https://github.com/invoke-ai/InvokeAI -- +if invokeAI_mps_available: + import psutil + mem_total_gb = psutil.virtual_memory().total // (1 << 30) def einsum_op_compvis(q, k, v): s = einsum('b i d, b j d -> b i j', q, k) @@ -193,7 +204,7 @@ def split_cross_attention_forward_invokeAI(self, x, context=None, mask=None): r = einsum_op(q, k, v) return self.to_out(rearrange(r, '(b h) n d -> b n (h d)', h=h)) -# -- End of code from https://github.com/invoke-ai/InvokeAI/blob/main/ldm/modules/attention.py -- +# -- End of code from https://github.com/invoke-ai/InvokeAI -- def xformers_attention_forward(self, x, context=None, mask=None): h = self.heads From 574c8e554a5371eca2cbf344764cb241c6ec4efc Mon Sep 17 00:00:00 2001 From: brkirch Date: Tue, 11 Oct 2022 03:32:11 -0400 Subject: [PATCH 334/460] Add InvokeAI and lstein to credits, add back CUDA support --- README.md | 1 + modules/sd_hijack_optimizations.py | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index a10faa01a..859a91b6f 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ The documentation was moved from this README over to the project's [wiki](https: - LDSR - https://github.com/Hafiidz/latent-diffusion - Ideas for optimizations - https://github.com/basujindal/stable-diffusion - Doggettx - Cross Attention layer optimization - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing. +- InvokeAI, lstein - Cross Attention layer optimization - https://github.com/invoke-ai/InvokeAI (originally http://github.com/lstein/stable-diffusion) - Rinon Gal - Textual Inversion - https://github.com/rinongal/textual_inversion (we're not using his code, but we are using his ideas). - Idea for SD upscale - https://github.com/jquesnelle/txt2imghd - Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index 2a4ac7e00..f006427f8 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -173,7 +173,20 @@ def einsum_op_tensor_mem(q, k, v, max_tensor_mb): return einsum_op_slice_0(q, k, v, q.shape[0] // div) return einsum_op_slice_1(q, k, v, max(q.shape[1] // div, 1)) +def einsum_op_cuda(q, k, v): + stats = torch.cuda.memory_stats(q.device) + mem_active = stats['active_bytes.all.current'] + mem_reserved = stats['reserved_bytes.all.current'] + mem_free_cuda, _ = torch.cuda.mem_get_info(q.device) + mem_free_torch = mem_reserved - mem_active + mem_free_total = mem_free_cuda + mem_free_torch + # Divide factor of safety as there's copying and fragmentation + return self.einsum_op_tensor_mem(q, k, v, mem_free_total / 3.3 / (1 << 20)) + def einsum_op(q, k, v): + if q.device.type == 'cuda': + return einsum_op_cuda(q, k, v) + if q.device.type == 'mps': if mem_total_gb >= 32: return einsum_op_mps_v1(q, k, v) From 861db783c7acfcb93cf0b5191db3d50f9a9bc531 Mon Sep 17 00:00:00 2001 From: brkirch Date: Tue, 11 Oct 2022 05:13:17 -0400 Subject: [PATCH 335/460] Use apply_hypernetwork function --- modules/sd_hijack_optimizations.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py index f006427f8..79405525e 100644 --- a/modules/sd_hijack_optimizations.py +++ b/modules/sd_hijack_optimizations.py @@ -202,16 +202,10 @@ def split_cross_attention_forward_invokeAI(self, x, context=None, mask=None): q = self.to_q(x) context = default(context, x) - hypernetwork = shared.loaded_hypernetwork - hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) - - if hypernetwork_layers is not None: - k = self.to_k(hypernetwork_layers[0](context)) * self.scale - v = self.to_v(hypernetwork_layers[1](context)) - else: - k = self.to_k(context) * self.scale - v = self.to_v(context) - del context, x + context_k, context_v = hypernetwork.apply_hypernetwork(shared.loaded_hypernetwork, context) + k = self.to_k(context_k) * self.scale + v = self.to_v(context_v) + del context, context_k, context_v, x q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v)) r = einsum_op(q, k, v) From 5ba23cb41f28f5856a7f64cb0d95e1e94dce90af Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 17:28:17 +0300 Subject: [PATCH 336/460] change default for XY plot's Y to Nothing. --- scripts/xy_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index cddb192a7..ef4311054 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -197,7 +197,7 @@ class Script(scripts.Script): x_values = gr.Textbox(label="X values", visible=False, lines=1) with gr.Row(): - y_type = gr.Dropdown(label="Y type", choices=[x.label for x in current_axis_options], value=current_axis_options[4].label, visible=False, type="index", elem_id="y_type") + y_type = gr.Dropdown(label="Y type", choices=[x.label for x in current_axis_options], value=current_axis_options[0].label, visible=False, type="index", elem_id="y_type") y_values = gr.Textbox(label="Y values", visible=False, lines=1) draw_legend = gr.Checkbox(label='Draw legend', value=True) From d682444ecc99319fbd2b142a12727501e2884ba7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 18:04:47 +0300 Subject: [PATCH 337/460] add option to select hypernetwork modules when creating --- modules/hypernetworks/hypernetwork.py | 4 ++-- modules/hypernetworks/ui.py | 4 ++-- modules/ui.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index aa701bda5..b081f14e9 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -42,7 +42,7 @@ class Hypernetwork: filename = None name = None - def __init__(self, name=None): + def __init__(self, name=None, enable_sizes=None): self.filename = None self.name = name self.layers = {} @@ -50,7 +50,7 @@ class Hypernetwork: self.sd_checkpoint = None self.sd_checkpoint_name = None - for size in [320, 640, 768, 1280]: + for size in enable_sizes or [320, 640, 768, 1280]: self.layers[size] = (HypernetworkModule(size), HypernetworkModule(size)) def weights(self): diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index e7540f41e..cdddcce1a 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -9,11 +9,11 @@ from modules import sd_hijack, shared from modules.hypernetworks import hypernetwork -def create_hypernetwork(name): +def create_hypernetwork(name, enable_sizes): fn = os.path.join(shared.cmd_opts.hypernetwork_dir, f"{name}.pt") assert not os.path.exists(fn), f"file {fn} already exists" - hypernet = modules.hypernetworks.hypernetwork.Hypernetwork(name=name) + hypernet = modules.hypernetworks.hypernetwork.Hypernetwork(name=name, enable_sizes=[int(x) for x in enable_sizes]) hypernet.save(fn) shared.reload_hypernetworks() diff --git a/modules/ui.py b/modules/ui.py index f2d16b120..14b87b927 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1037,6 +1037,7 @@ def create_ui(wrap_gradio_gpu_call): gr.HTML(value="

    Create a new hypernetwork

    ") new_hypernetwork_name = gr.Textbox(label="Name") + new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "320", "640", "1280"]) with gr.Row(): with gr.Column(scale=3): @@ -1114,6 +1115,7 @@ def create_ui(wrap_gradio_gpu_call): fn=modules.hypernetworks.ui.create_hypernetwork, inputs=[ new_hypernetwork_name, + new_hypernetwork_sizes, ], outputs=[ train_hypernetwork_name, From ff4ef13dd591ec52f196f344f47537695df95364 Mon Sep 17 00:00:00 2001 From: JC_Array Date: Tue, 11 Oct 2022 10:24:27 -0500 Subject: [PATCH 338/460] removed unneeded print --- modules/deepbooru.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index e31e92c09..89dcac3cf 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -119,7 +119,6 @@ def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, alpha_sort) # sort tags result_tags_out = [] sort_ndx = 0 - print(alpha_sort) if alpha_sort: sort_ndx = 1 From 6d09b8d1df3a96e1380bb1650f5961781630af96 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 18:33:57 +0300 Subject: [PATCH 339/460] produce error when training with medvram/lowvram enabled --- modules/hypernetworks/ui.py | 2 ++ modules/textual_inversion/ui.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index cdddcce1a..3541a388b 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -25,6 +25,8 @@ def train_hypernetwork(*args): initial_hypernetwork = shared.loaded_hypernetwork + assert not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram, 'Training models with lowvram or medvram is not possible' + try: sd_hijack.undo_optimizations() diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py index c57de1f94..70f47343e 100644 --- a/modules/textual_inversion/ui.py +++ b/modules/textual_inversion/ui.py @@ -22,6 +22,9 @@ def preprocess(*args): def train_embedding(*args): + + assert not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram, 'Training models with lowvram or medvram is not possible' + try: sd_hijack.undo_optimizations() From d4ea5f4d8631f778d11efcde397e4a5b8801d43b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 19:03:08 +0300 Subject: [PATCH 340/460] add an option to unload models during hypernetwork training to save VRAM --- modules/hypernetworks/hypernetwork.py | 25 +++++++++++----- modules/hypernetworks/ui.py | 4 ++- modules/shared.py | 4 +++ modules/textual_inversion/dataset.py | 29 +++++++++++++------ .../textual_inversion/textual_inversion.py | 2 +- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index b081f14e9..4700e1ec1 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -175,6 +175,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork_name}.pt') log_directory = os.path.join(log_directory, datetime.datetime.now().strftime("%Y-%m-%d"), hypernetwork_name) + unload = shared.opts.unload_models_when_training if save_hypernetwork_every > 0: hypernetwork_dir = os.path.join(log_directory, "hypernetworks") @@ -188,11 +189,13 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, else: images_dir = None - cond_model = shared.sd_model.cond_stage_model - shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=512, height=512, repeats=1, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=512, height=512, repeats=1, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True) + + if unload: + shared.sd_model.cond_stage_model.to(devices.cpu) + shared.sd_model.first_stage_model.to(devices.cpu) hypernetwork = shared.loaded_hypernetwork weights = hypernetwork.weights() @@ -211,7 +214,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, return hypernetwork, filename pbar = tqdm.tqdm(enumerate(ds), total=steps - ititial_step) - for i, (x, text) in pbar: + for i, (x, text, cond) in pbar: hypernetwork.step = i + ititial_step if hypernetwork.step > steps: @@ -221,11 +224,11 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, break with torch.autocast("cuda"): - c = cond_model([text]) - + cond = cond.to(devices.device) x = x.to(devices.device) - loss = shared.sd_model(x.unsqueeze(0), c)[0] + loss = shared.sd_model(x.unsqueeze(0), cond)[0] del x + del cond losses[hypernetwork.step % losses.shape[0]] = loss.item() @@ -244,6 +247,10 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, preview_text = text if preview_image_prompt == "" else preview_image_prompt + optimizer.zero_grad() + shared.sd_model.cond_stage_model.to(devices.device) + shared.sd_model.first_stage_model.to(devices.device) + p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, prompt=preview_text, @@ -255,6 +262,10 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, processed = processing.process_images(p) image = processed.images[0] + if unload: + shared.sd_model.cond_stage_model.to(devices.cpu) + shared.sd_model.first_stage_model.to(devices.cpu) + shared.state.current_image = image image.save(last_saved_image) diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index 3541a388b..c67facbb7 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -5,7 +5,7 @@ import gradio as gr import modules.textual_inversion.textual_inversion import modules.textual_inversion.preprocess -from modules import sd_hijack, shared +from modules import sd_hijack, shared, devices from modules.hypernetworks import hypernetwork @@ -41,5 +41,7 @@ Hypernetwork saved to {html.escape(filename)} raise finally: shared.loaded_hypernetwork = initial_hypernetwork + shared.sd_model.cond_stage_model.to(devices.device) + shared.sd_model.first_stage_model.to(devices.device) sd_hijack.apply_optimizations() diff --git a/modules/shared.py b/modules/shared.py index 20b45f231..c1092ff79 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -228,6 +228,10 @@ options_templates.update(options_section(('system', "System"), { "multiple_tqdm": OptionInfo(True, "Add a second progress bar to the console that shows progress for an entire job."), })) +options_templates.update(options_section(('training', "Training"), { + "unload_models_when_training": OptionInfo(False, "Unload VAE and CLIP form VRAM when training"), +})) + options_templates.update(options_section(('sd', "Stable Diffusion"), { "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, show_on_main_page=True), "sd_hypernetwork": OptionInfo("None", "Stable Diffusion finetune hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}), diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index 4d0063669..f61f40d30 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -8,14 +8,14 @@ from torchvision import transforms import random import tqdm -from modules import devices +from modules import devices, shared import re re_tag = re.compile(r"[a-zA-Z][_\w\d()]+") class PersonalizedBase(Dataset): - def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None): + def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None, include_cond=False): self.placeholder_token = placeholder_token @@ -32,6 +32,8 @@ class PersonalizedBase(Dataset): assert data_root, 'dataset directory not specified' + cond_model = shared.sd_model.cond_stage_model + self.image_paths = [os.path.join(data_root, file_path) for file_path in os.listdir(data_root)] print("Preparing dataset...") for path in tqdm.tqdm(self.image_paths): @@ -53,7 +55,13 @@ class PersonalizedBase(Dataset): init_latent = model.get_first_stage_encoding(model.encode_first_stage(torchdata.unsqueeze(dim=0))).squeeze() init_latent = init_latent.to(devices.cpu) - self.dataset.append((init_latent, filename_tokens)) + if include_cond: + text = self.create_text(filename_tokens) + cond = cond_model([text]).to(devices.cpu) + else: + cond = None + + self.dataset.append((init_latent, filename_tokens, cond)) self.length = len(self.dataset) * repeats @@ -64,6 +72,12 @@ class PersonalizedBase(Dataset): def shuffle(self): self.indexes = self.initial_indexes[torch.randperm(self.initial_indexes.shape[0])] + def create_text(self, filename_tokens): + text = random.choice(self.lines) + text = text.replace("[name]", self.placeholder_token) + text = text.replace("[filewords]", ' '.join(filename_tokens)) + return text + def __len__(self): return self.length @@ -72,10 +86,7 @@ class PersonalizedBase(Dataset): self.shuffle() index = self.indexes[i % len(self.indexes)] - x, filename_tokens = self.dataset[index] + x, filename_tokens, cond = self.dataset[index] - text = random.choice(self.lines) - text = text.replace("[name]", self.placeholder_token) - text = text.replace("[filewords]", ' '.join(filename_tokens)) - - return x, text + text = self.create_text(filename_tokens) + return x, text, cond diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index bb05cdc65..35f4bd9e0 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -201,7 +201,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini return embedding, filename pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) - for i, (x, text) in pbar: + for i, (x, text, _) in pbar: embedding.step = i + ititial_step if embedding.step > steps: From 6a9ea5b41cf92cd9e980349bb5034439f4e7a58b Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 19:22:30 +0300 Subject: [PATCH 341/460] prevent extra modules from being saved/loaded with hypernet --- modules/hypernetworks/hypernetwork.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 4700e1ec1..5608e7995 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -50,7 +50,7 @@ class Hypernetwork: self.sd_checkpoint = None self.sd_checkpoint_name = None - for size in enable_sizes or [320, 640, 768, 1280]: + for size in enable_sizes or []: self.layers[size] = (HypernetworkModule(size), HypernetworkModule(size)) def weights(self): From d7474a5185df2af84a93a12bc7e140d24e0fc516 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 21:10:55 +0300 Subject: [PATCH 342/460] bump gradio to 3.4.1 --- requirements.txt | 2 +- requirements_versions.txt | 2 +- style.css | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 631fe616a..a0d985ce7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ fairscale==0.4.4 fonts font-roboto gfpgan -gradio==3.4b3 +gradio==3.4.1 invisible-watermark numpy omegaconf diff --git a/requirements_versions.txt b/requirements_versions.txt index fdff26878..2bbea40b4 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -2,7 +2,7 @@ transformers==4.19.2 diffusers==0.3.0 basicsr==1.4.2 gfpgan==1.3.8 -gradio==3.4b3 +gradio==3.4.1 numpy==1.23.3 Pillow==9.2.0 realesrgan==0.3.0 diff --git a/style.css b/style.css index ecb51bb02..e6fa10b4f 100644 --- a/style.css +++ b/style.css @@ -240,6 +240,7 @@ fieldset span.text-gray-500, .gr-block.gr-box span.text-gray-500, label.block s #settings fieldset span.text-gray-500, #settings .gr-block.gr-box span.text-gray-500, #settings label.block span{ position: relative; border: none; + margin-right: 8em; } .gr-panel div.flex-col div.justify-between label span{ @@ -495,3 +496,13 @@ canvas[key="mask"] { mix-blend-mode: multiply; pointer-events: none; } + + +/* gradio 3.4.1 stuff for editable scrollbar values */ +.gr-box > div > div > input.gr-text-input{ + position: absolute; + right: 0.5em; + top: -0.6em; + z-index: 200; + width: 8em; +} From 9e5f6b558072f6cdfa0f7010fa819662952fcaf1 Mon Sep 17 00:00:00 2001 From: nai-degen <92774204+nai-degen@users.noreply.github.com> Date: Sun, 9 Oct 2022 19:37:35 -0500 Subject: [PATCH 343/460] triggers 'input' event when using arrow keys to edit attention --- javascript/edit-attention.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js index 0280c603f..79566a2e2 100644 --- a/javascript/edit-attention.js +++ b/javascript/edit-attention.js @@ -38,4 +38,7 @@ addEventListener('keydown', (event) => { target.selectionStart = selectionStart; target.selectionEnd = selectionEnd; } + // Since we've modified a Gradio Textbox component manually, we need to simulate an `input` DOM event to ensure its + // internal Svelte data binding remains in sync. + target.dispatchEvent(new Event("input", { bubbles: true })); }); From c080f52ceae73b893155eff7de577aaf1a982a2f Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 19:37:58 +0100 Subject: [PATCH 344/460] move embedding logic to separate file --- modules/textual_inversion/image_embedding.py | 234 +++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 modules/textual_inversion/image_embedding.py diff --git a/modules/textual_inversion/image_embedding.py b/modules/textual_inversion/image_embedding.py new file mode 100644 index 000000000..6ad396021 --- /dev/null +++ b/modules/textual_inversion/image_embedding.py @@ -0,0 +1,234 @@ +import base64 +import json +import numpy as np +import zlib +from PIL import Image,PngImagePlugin,ImageDraw,ImageFont +from fonts.ttf import Roboto +import torch + +class EmbeddingEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, torch.Tensor): + return {'TORCHTENSOR':obj.cpu().detach().numpy().tolist()} + return json.JSONEncoder.default(self, obj) + +class EmbeddingDecoder(json.JSONDecoder): + def __init__(self, *args, **kwargs): + json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) + def object_hook(self, d): + if 'TORCHTENSOR' in d: + return torch.from_numpy(np.array(d['TORCHTENSOR'])) + return d + +def embedding_to_b64(data): + d = json.dumps(data,cls=EmbeddingEncoder) + return base64.b64encode(d.encode()) + +def embedding_from_b64(data): + d = base64.b64decode(data) + return json.loads(d,cls=EmbeddingDecoder) + +def lcg(m=2**32, a=1664525, c=1013904223, seed=0): + while True: + seed = (a * seed + c) % m + yield seed%255 + +def xor_block(block): + g = lcg() + randblock = np.array([next(g) for _ in range(np.product(block.shape))]).astype(np.uint8).reshape(block.shape) + return np.bitwise_xor(block.astype(np.uint8),randblock & 0x0F) + +def style_block(block,sequence): + im = Image.new('RGB',(block.shape[1],block.shape[0])) + draw = ImageDraw.Draw(im) + i=0 + for x in range(-6,im.size[0],8): + for yi,y in enumerate(range(-6,im.size[1],8)): + offset=0 + if yi%2==0: + offset=4 + shade = sequence[i%len(sequence)] + i+=1 + draw.ellipse((x+offset, y, x+6+offset, y+6), fill =(shade,shade,shade) ) + + fg = np.array(im).astype(np.uint8) & 0xF0 + + return block ^ fg + +def insert_image_data_embed(image,data): + d = 3 + data_compressed = zlib.compress( json.dumps(data,cls=EmbeddingEncoder).encode(),level=9) + data_np_ = np.frombuffer(data_compressed,np.uint8).copy() + data_np_high = data_np_ >> 4 + data_np_low = data_np_ & 0x0F + + h = image.size[1] + next_size = data_np_low.shape[0] + (h-(data_np_low.shape[0]%h)) + next_size = next_size + ((h*d)-(next_size%(h*d))) + + data_np_low.resize(next_size) + data_np_low = data_np_low.reshape((h,-1,d)) + + data_np_high.resize(next_size) + data_np_high = data_np_high.reshape((h,-1,d)) + + edge_style = list(data['string_to_param'].values())[0].cpu().detach().numpy().tolist()[0][:1024] + edge_style = (np.abs(edge_style)/np.max(np.abs(edge_style))*255).astype(np.uint8) + + data_np_low = style_block(data_np_low,sequence=edge_style) + data_np_low = xor_block(data_np_low) + data_np_high = style_block(data_np_high,sequence=edge_style[::-1]) + data_np_high = xor_block(data_np_high) + + im_low = Image.fromarray(data_np_low,mode='RGB') + im_high = Image.fromarray(data_np_high,mode='RGB') + + background = Image.new('RGB',(image.size[0]+im_low.size[0]+im_high.size[0]+2,image.size[1]),(0,0,0)) + background.paste(im_low,(0,0)) + background.paste(image,(im_low.size[0]+1,0)) + background.paste(im_high,(im_low.size[0]+1+image.size[0]+1,0)) + + return background + +def crop_black(img,tol=0): + mask = (img>tol).all(2) + mask0,mask1 = mask.any(0),mask.any(1) + col_start,col_end = mask0.argmax(),mask.shape[1]-mask0[::-1].argmax() + row_start,row_end = mask1.argmax(),mask.shape[0]-mask1[::-1].argmax() + return img[row_start:row_end,col_start:col_end] + +def extract_image_data_embed(image): + d=3 + outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) & 0x0F + black_cols = np.where( np.sum(outarr, axis=(0,2))==0) + if black_cols[0].shape[0] < 2: + print('No Image data blocks found.') + return None + + data_block_lower = outarr[:,:black_cols[0].min(),:].astype(np.uint8) + data_block_upper = outarr[:,black_cols[0].max()+1:,:].astype(np.uint8) + + data_block_lower = xor_block(data_block_lower) + data_block_upper = xor_block(data_block_upper) + + data_block = (data_block_upper << 4) | (data_block_lower) + data_block = data_block.flatten().tobytes() + + data = zlib.decompress(data_block) + return json.loads(data,cls=EmbeddingDecoder) + +def addCaptionLines(lines,image,initialx,textfont): + draw = ImageDraw.Draw(image) + hstart =initialx + for fill,line in lines: + fontsize = 32 + font = ImageFont.truetype(textfont, fontsize) + _,_,w, h = draw.textbbox((0,0),line,font=font) + fontsize = min( int(fontsize * ((image.size[0]-35)/w) ), 28) + font = ImageFont.truetype(textfont, fontsize) + _,_,w,h = draw.textbbox((0,0),line,font=font) + draw.text(((image.size[0]-w)/2,hstart), line, font=font, fill=fill) + hstart += h + return hstart + +def caption_image(image,prelines,postlines,background=(51, 51, 51),font=None): + if font is None: + try: + font = ImageFont.truetype(opts.font or Roboto, fontsize) + font = opts.font or Roboto + except Exception: + font = Roboto + + sample_image = image + background = Image.new("RGBA", (sample_image.size[0],sample_image.size[1]+1024), background) + hoffset = addCaptionLines(prelines,background,5,font)+16 + background.paste(sample_image,(0,hoffset)) + hoffset = hoffset+sample_image.size[1]+8 + hoffset = addCaptionLines(postlines,background,hoffset,font) + background = background.crop((0,0,sample_image.size[0],hoffset+8)) + return background + +def caption_image_overlay(srcimage,title,footerLeft,footerMid,footerRight,textfont=None): + from math import cos + + image = srcimage.copy() + + if textfont is None: + try: + textfont = ImageFont.truetype(opts.font or Roboto, fontsize) + textfont = opts.font or Roboto + except Exception: + textfont = Roboto + + factor = 1.5 + gradient = Image.new('RGBA', (1,image.size[1]), color=(0,0,0,0)) + for y in range(image.size[1]): + mag = 1-cos(y/image.size[1]*factor) + mag = max(mag,1-cos((image.size[1]-y)/image.size[1]*factor*1.1)) + gradient.putpixel((0, y), (0,0,0,int(mag*255))) + image = Image.alpha_composite(image.convert('RGBA'), gradient.resize(image.size)) + + draw = ImageDraw.Draw(image) + fontsize = 32 + font = ImageFont.truetype(textfont, fontsize) + padding = 10 + + _,_,w, h = draw.textbbox((0,0),title,font=font) + fontsize = min( int(fontsize * (((image.size[0]*0.75)-(padding*4))/w) ), 72) + font = ImageFont.truetype(textfont, fontsize) + _,_,w,h = draw.textbbox((0,0),title,font=font) + draw.text((padding,padding), title, anchor='lt', font=font, fill=(255,255,255,230)) + + _,_,w, h = draw.textbbox((0,0),footerLeft,font=font) + fontsize_left = min( int(fontsize * (((image.size[0]/3)-(padding))/w) ), 72) + _,_,w, h = draw.textbbox((0,0),footerMid,font=font) + fontsize_mid = min( int(fontsize * (((image.size[0]/3)-(padding))/w) ), 72) + _,_,w, h = draw.textbbox((0,0),footerRight,font=font) + fontsize_right = min( int(fontsize * (((image.size[0]/3)-(padding))/w) ), 72) + + font = ImageFont.truetype(textfont, min(fontsize_left,fontsize_mid,fontsize_right)) + + draw.text((padding,image.size[1]-padding), footerLeft, anchor='ls', font=font, fill=(255,255,255,230)) + draw.text((image.size[0]/2,image.size[1]-padding), footerMid, anchor='ms', font=font, fill=(255,255,255,230)) + draw.text((image.size[0]-padding,image.size[1]-padding), footerRight, anchor='rs', font=font, fill=(255,255,255,230)) + + return image + +if __name__ == '__main__': + + image = Image.new('RGBA',(512,512),(255,255,200,255)) + caption_image(image,[((255,255,255),'line a'),((255,255,255),'line b')], + [((255,255,255),'line c'),((255,255,255),'line d')]) + + image = Image.new('RGBA',(512,512),(255,255,200,255)) + cap_image = caption_image_overlay(image, 'title', 'footerLeft', 'footerMid', 'footerRight') + + test_embed = {'string_to_param':{'*':torch.from_numpy(np.random.random((2, 4096)))}} + + embedded_image = insert_image_data_embed(cap_image, test_embed) + + retrived_embed = extract_image_data_embed(embedded_image) + + assert str(retrived_embed) == str(test_embed) + + embedded_image2 = insert_image_data_embed(cap_image, retrived_embed) + + assert embedded_image == embedded_image2 + + g = lcg() + shared_random = np.array([next(g) for _ in range(100)]).astype(np.uint8).tolist() + + reference_random = [253, 242, 127, 44, 157, 27, 239, 133, 38, 79, 167, 4, 177, + 95, 130, 79, 78, 14, 52, 215, 220, 194, 126, 28, 240, 179, + 160, 153, 149, 50, 105, 14, 21, 218, 199, 18, 54, 198, 193, + 38, 128, 19, 53, 195, 124, 75, 205, 12, 6, 145, 0, 28, + 30, 148, 8, 45, 218, 171, 55, 249, 97, 166, 12, 35, 0, + 41, 221, 122, 215, 170, 31, 113, 186, 97, 119, 31, 23, 185, + 66, 140, 30, 41, 37, 63, 137, 109, 216, 55, 159, 145, 82, + 204, 86, 73, 222, 44, 198, 118, 240, 97] + + assert shared_random == reference_random + + hunna_kay_random_sum = sum(np.array([next(g) for _ in range(100000)]).astype(np.uint8).tolist()) + + assert 12731374 == hunna_kay_random_sum \ No newline at end of file From e5fbf5c755b7c306696546405385d5d2314e555b Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 19:46:33 +0100 Subject: [PATCH 345/460] remove embedding related image functions from images --- modules/images.py | 77 ----------------------------------------------- 1 file changed, 77 deletions(-) diff --git a/modules/images.py b/modules/images.py index e62eec8ef..c0a906762 100644 --- a/modules/images.py +++ b/modules/images.py @@ -463,80 +463,3 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i txt_fullfn = None return fullfn, txt_fullfn - -def addCaptionLines(lines,image,initialx,textfont): - draw = ImageDraw.Draw(image) - hstart =initialx - for fill,line in lines: - fontSize = 32 - font = ImageFont.truetype(textfont, fontSize) - _,_,w, h = draw.textbbox((0,0),line,font=font) - fontSize = min( int(fontSize * ((image.size[0]-35)/w) ), 28) - font = ImageFont.truetype(textfont, fontSize) - _,_,w,h = draw.textbbox((0,0),line,font=font) - draw.text(((image.size[0]-w)/2,hstart), line, font=font, fill=fill) - hstart += h - return hstart - -def captionImge(image,prelines,postlines,background=(51, 51, 51),font=None): - if font is None: - try: - font = ImageFont.truetype(opts.font or Roboto, fontsize) - font = opts.font or Roboto - except Exception: - font = Roboto - - sampleImage = image - background = Image.new("RGBA", (sampleImage.size[0],sampleImage.size[1]+1024), background) - hoffset = addCaptionLines(prelines,background,5,font)+16 - background.paste(sampleImage,(0,hoffset)) - hoffset = hoffset+sampleImage.size[1]+8 - hoffset = addCaptionLines(postlines,background,hoffset,font) - background = background.crop((0,0,sampleImage.size[0],hoffset+8)) - return background - -def captionImageOverlay(srcimage,title,footerLeft,footerMid,footerRight,textfont=None): - from math import cos - - image = srcimage.copy() - - if textfont is None: - try: - textfont = ImageFont.truetype(opts.font or Roboto, fontsize) - textfont = opts.font or Roboto - except Exception: - textfont = Roboto - - factor = 1.5 - gradient = Image.new('RGBA', (1,image.size[1]), color=(0,0,0,0)) - for y in range(image.size[1]): - mag = 1-cos(y/image.size[1]*factor) - mag = max(mag,1-cos((image.size[1]-y)/image.size[1]*factor*1.1)) - gradient.putpixel((0, y), (0,0,0,int(mag*255))) - image = Image.alpha_composite(image.convert('RGBA'), gradient.resize(image.size)) - - draw = ImageDraw.Draw(image) - fontSize = 32 - font = ImageFont.truetype(textfont, fontSize) - padding = 10 - - _,_,w, h = draw.textbbox((0,0),title,font=font) - fontSize = min( int(fontSize * (((image.size[0]*0.75)-(padding*4))/w) ), 72) - font = ImageFont.truetype(textfont, fontSize) - _,_,w,h = draw.textbbox((0,0),title,font=font) - draw.text((padding,padding), title, anchor='lt', font=font, fill=(255,255,255,230)) - - _,_,w, h = draw.textbbox((0,0),footerLeft,font=font) - fontSizeleft = min( int(fontSize * (((image.size[0]/3)-(padding))/w) ), 72) - _,_,w, h = draw.textbbox((0,0),footerMid,font=font) - fontSizemid = min( int(fontSize * (((image.size[0]/3)-(padding))/w) ), 72) - _,_,w, h = draw.textbbox((0,0),footerRight,font=font) - fontSizeright = min( int(fontSize * (((image.size[0]/3)-(padding))/w) ), 72) - - font = ImageFont.truetype(textfont, min(fontSizeleft,fontSizemid,fontSizeright)) - - draw.text((padding,image.size[1]-padding), footerLeft, anchor='ls', font=font, fill=(255,255,255,230)) - draw.text((image.size[0]/2,image.size[1]-padding), footerMid, anchor='ms', font=font, fill=(255,255,255,230)) - draw.text((image.size[0]-padding,image.size[1]-padding), footerRight, anchor='rs', font=font, fill=(255,255,255,230)) - - return image From 61788c0538415fa9ca1dd1b306519c116b18bd2c Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 19:50:50 +0100 Subject: [PATCH 346/460] shift embedding logic out of textual_inversion --- .../textual_inversion/textual_inversion.py | 125 +----------------- 1 file changed, 6 insertions(+), 119 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 8c66aeb5b..22b4ae7f2 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -7,124 +7,11 @@ import tqdm import html import datetime -from PIL import Image,PngImagePlugin,ImageDraw -from ..images import captionImageOverlay -import numpy as np -import base64 -import json -import zlib +from PIL import Image,PngImagePlugin from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset -class EmbeddingEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, torch.Tensor): - return {'TORCHTENSOR':obj.cpu().detach().numpy().tolist()} - return json.JSONEncoder.default(self, obj) - -class EmbeddingDecoder(json.JSONDecoder): - def __init__(self, *args, **kwargs): - json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) - def object_hook(self, d): - if 'TORCHTENSOR' in d: - return torch.from_numpy(np.array(d['TORCHTENSOR'])) - return d - -def embeddingToB64(data): - d = json.dumps(data,cls=EmbeddingEncoder) - return base64.b64encode(d.encode()) - -def embeddingFromB64(data): - d = base64.b64decode(data) - return json.loads(d,cls=EmbeddingDecoder) - -def lcg(m=2**32, a=1664525, c=1013904223, seed=0): - while True: - seed = (a * seed + c) % m - yield seed - -def xorBlock(block): - g = lcg() - randblock = np.array([next(g) for _ in range(np.product(block.shape))]).astype(np.uint8).reshape(block.shape) - return np.bitwise_xor(block.astype(np.uint8),randblock & 0x0F) - -def styleBlock(block,sequence): - im = Image.new('RGB',(block.shape[1],block.shape[0])) - draw = ImageDraw.Draw(im) - i=0 - for x in range(-6,im.size[0],8): - for yi,y in enumerate(range(-6,im.size[1],8)): - offset=0 - if yi%2==0: - offset=4 - shade = sequence[i%len(sequence)] - i+=1 - draw.ellipse((x+offset, y, x+6+offset, y+6), fill =(shade,shade,shade) ) - - fg = np.array(im).astype(np.uint8) & 0xF0 - return block ^ fg - -def insertImageDataEmbed(image,data): - d = 3 - data_compressed = zlib.compress( json.dumps(data,cls=EmbeddingEncoder).encode(),level=9) - dnp = np.frombuffer(data_compressed,np.uint8).copy() - dnphigh = dnp >> 4 - dnplow = dnp & 0x0F - - h = image.size[1] - next_size = dnplow.shape[0] + (h-(dnplow.shape[0]%h)) - next_size = next_size + ((h*d)-(next_size%(h*d))) - - dnplow.resize(next_size) - dnplow = dnplow.reshape((h,-1,d)) - - dnphigh.resize(next_size) - dnphigh = dnphigh.reshape((h,-1,d)) - - edgeStyleWeights = list(data['string_to_param'].values())[0].cpu().detach().numpy().tolist()[0][:1024] - edgeStyleWeights = (np.abs(edgeStyleWeights)/np.max(np.abs(edgeStyleWeights))*255).astype(np.uint8) - - dnplow = styleBlock(dnplow,sequence=edgeStyleWeights) - dnplow = xorBlock(dnplow) - dnphigh = styleBlock(dnphigh,sequence=edgeStyleWeights[::-1]) - dnphigh = xorBlock(dnphigh) - - imlow = Image.fromarray(dnplow,mode='RGB') - imhigh = Image.fromarray(dnphigh,mode='RGB') - - background = Image.new('RGB',(image.size[0]+imlow.size[0]+imhigh.size[0]+2,image.size[1]),(0,0,0)) - background.paste(imlow,(0,0)) - background.paste(image,(imlow.size[0]+1,0)) - background.paste(imhigh,(imlow.size[0]+1+image.size[0]+1,0)) - - return background - -def crop_black(img,tol=0): - mask = (img>tol).all(2) - mask0,mask1 = mask.any(0),mask.any(1) - col_start,col_end = mask0.argmax(),mask.shape[1]-mask0[::-1].argmax() - row_start,row_end = mask1.argmax(),mask.shape[0]-mask1[::-1].argmax() - return img[row_start:row_end,col_start:col_end] - -def extractImageDataEmbed(image): - d=3 - outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) & 0x0F - blackCols = np.where( np.sum(outarr, axis=(0,2))==0) - if blackCols[0].shape[0] < 2: - print('No Image data blocks found.') - return None - - dataBlocklower = outarr[:,:blackCols[0].min(),:].astype(np.uint8) - dataBlockupper = outarr[:,blackCols[0].max()+1:,:].astype(np.uint8) - - dataBlocklower = xorBlock(dataBlocklower) - dataBlockupper = xorBlock(dataBlockupper) - - dataBlock = (dataBlockupper << 4) | (dataBlocklower) - dataBlock = dataBlock.flatten().tobytes() - data = zlib.decompress(dataBlock) - return json.loads(data,cls=EmbeddingDecoder) class Embedding: def __init__(self, vec, name, step=None): @@ -199,10 +86,10 @@ class EmbeddingDatabase: if filename.upper().endswith('.PNG'): embed_image = Image.open(path) if 'sd-ti-embedding' in embed_image.text: - data = embeddingFromB64(embed_image.text['sd-ti-embedding']) + data = embedding_from_b64(embed_image.text['sd-ti-embedding']) name = data.get('name',name) else: - data = extractImageDataEmbed(embed_image) + data = extract_image_data_embed(embed_image) name = data.get('name',name) else: data = torch.load(path, map_location="cpu") @@ -393,7 +280,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini info = PngImagePlugin.PngInfo() data = torch.load(last_saved_file) - info.add_text("sd-ti-embedding", embeddingToB64(data)) + info.add_text("sd-ti-embedding", embedding_to_b64(data)) title = "<{}>".format(data.get('name','???')) checkpoint = sd_models.select_checkpoint() @@ -401,8 +288,8 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini footer_mid = '[{}]'.format(checkpoint.hash) footer_right = '{}'.format(embedding.step) - captioned_image = captionImageOverlay(image,title,footer_left,footer_mid,footer_right) - captioned_image = insertImageDataEmbed(captioned_image,data) + captioned_image = caption_image_overlay(image,title,footer_left,footer_mid,footer_right) + captioned_image = insert_image_data_embed(captioned_image,data) captioned_image.save(last_saved_image_chunks, "PNG", pnginfo=info) From db71290d2659d3b58ff9b57a82e4721a9eab9229 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 19:55:54 +0100 Subject: [PATCH 347/460] remove old caption method --- modules/textual_inversion/image_embedding.py | 39 +------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/modules/textual_inversion/image_embedding.py b/modules/textual_inversion/image_embedding.py index 6ad396021..c67028a50 100644 --- a/modules/textual_inversion/image_embedding.py +++ b/modules/textual_inversion/image_embedding.py @@ -117,37 +117,6 @@ def extract_image_data_embed(image): data = zlib.decompress(data_block) return json.loads(data,cls=EmbeddingDecoder) -def addCaptionLines(lines,image,initialx,textfont): - draw = ImageDraw.Draw(image) - hstart =initialx - for fill,line in lines: - fontsize = 32 - font = ImageFont.truetype(textfont, fontsize) - _,_,w, h = draw.textbbox((0,0),line,font=font) - fontsize = min( int(fontsize * ((image.size[0]-35)/w) ), 28) - font = ImageFont.truetype(textfont, fontsize) - _,_,w,h = draw.textbbox((0,0),line,font=font) - draw.text(((image.size[0]-w)/2,hstart), line, font=font, fill=fill) - hstart += h - return hstart - -def caption_image(image,prelines,postlines,background=(51, 51, 51),font=None): - if font is None: - try: - font = ImageFont.truetype(opts.font or Roboto, fontsize) - font = opts.font or Roboto - except Exception: - font = Roboto - - sample_image = image - background = Image.new("RGBA", (sample_image.size[0],sample_image.size[1]+1024), background) - hoffset = addCaptionLines(prelines,background,5,font)+16 - background.paste(sample_image,(0,hoffset)) - hoffset = hoffset+sample_image.size[1]+8 - hoffset = addCaptionLines(postlines,background,hoffset,font) - background = background.crop((0,0,sample_image.size[0],hoffset+8)) - return background - def caption_image_overlay(srcimage,title,footerLeft,footerMid,footerRight,textfont=None): from math import cos @@ -195,11 +164,7 @@ def caption_image_overlay(srcimage,title,footerLeft,footerMid,footerRight,textfo return image if __name__ == '__main__': - - image = Image.new('RGBA',(512,512),(255,255,200,255)) - caption_image(image,[((255,255,255),'line a'),((255,255,255),'line b')], - [((255,255,255),'line c'),((255,255,255),'line d')]) - + image = Image.new('RGBA',(512,512),(255,255,200,255)) cap_image = caption_image_overlay(image, 'title', 'footerLeft', 'footerMid', 'footerRight') @@ -231,4 +196,4 @@ if __name__ == '__main__': hunna_kay_random_sum = sum(np.array([next(g) for _ in range(100000)]).astype(np.uint8).tolist()) - assert 12731374 == hunna_kay_random_sum \ No newline at end of file + assert 12731374 == hunna_kay_random_sum From d6fcc6b87bc00fcdecea276fe5b7c7945f7a8b14 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 22:03:05 +0300 Subject: [PATCH 348/460] apply lr schedule to hypernets --- modules/hypernetworks/hypernetwork.py | 19 ++++++-- modules/textual_inversion/learn_schedule.py | 34 ++++++++++++++ .../textual_inversion/textual_inversion.py | 44 ++----------------- modules/ui.py | 2 +- 4 files changed, 54 insertions(+), 45 deletions(-) create mode 100644 modules/textual_inversion/learn_schedule.py diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 5608e7995..470659dfe 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -14,6 +14,7 @@ import torch from torch import einsum from einops import rearrange, repeat import modules.textual_inversion.dataset +from modules.textual_inversion.learn_schedule import LearnSchedule class HypernetworkModule(torch.nn.Module): @@ -202,8 +203,6 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, for weight in weights: weight.requires_grad = True - optimizer = torch.optim.AdamW(weights, lr=learn_rate) - losses = torch.zeros((32,)) last_saved_file = "" @@ -213,12 +212,24 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, if ititial_step > steps: return hypernetwork, filename + schedules = iter(LearnSchedule(learn_rate, steps, ititial_step)) + (learn_rate, end_step) = next(schedules) + print(f'Training at rate of {learn_rate} until step {end_step}') + + optimizer = torch.optim.AdamW(weights, lr=learn_rate) + pbar = tqdm.tqdm(enumerate(ds), total=steps - ititial_step) for i, (x, text, cond) in pbar: hypernetwork.step = i + ititial_step - if hypernetwork.step > steps: - break + if hypernetwork.step > end_step: + try: + (learn_rate, end_step) = next(schedules) + except Exception: + break + tqdm.tqdm.write(f'Training at rate of {learn_rate} until step {end_step}') + for pg in optimizer.param_groups: + pg['lr'] = learn_rate if shared.state.interrupted: break diff --git a/modules/textual_inversion/learn_schedule.py b/modules/textual_inversion/learn_schedule.py new file mode 100644 index 000000000..db7202712 --- /dev/null +++ b/modules/textual_inversion/learn_schedule.py @@ -0,0 +1,34 @@ + +class LearnSchedule: + def __init__(self, learn_rate, max_steps, cur_step=0): + pairs = learn_rate.split(',') + self.rates = [] + self.it = 0 + self.maxit = 0 + for i, pair in enumerate(pairs): + tmp = pair.split(':') + if len(tmp) == 2: + step = int(tmp[1]) + if step > cur_step: + self.rates.append((float(tmp[0]), min(step, max_steps))) + self.maxit += 1 + if step > max_steps: + return + elif step == -1: + self.rates.append((float(tmp[0]), max_steps)) + self.maxit += 1 + return + else: + self.rates.append((float(tmp[0]), max_steps)) + self.maxit += 1 + return + + def __iter__(self): + return self + + def __next__(self): + if self.it < self.maxit: + self.it += 1 + return self.rates[self.it - 1] + else: + raise StopIteration diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 47a27faf2..7717837da 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -10,6 +10,7 @@ import datetime from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset +from modules.textual_inversion.learn_schedule import LearnSchedule class Embedding: @@ -198,11 +199,8 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if ititial_step > steps: return embedding, filename - tr_img_len = len([os.path.join(data_root, file_path) for file_path in os.listdir(data_root)]) - epoch_len = (tr_img_len * num_repeats) + tr_img_len - - scheduleIter = iter(LearnSchedule(learn_rate, steps, ititial_step)) - (learn_rate, end_step) = next(scheduleIter) + schedules = iter(LearnSchedule(learn_rate, steps, ititial_step)) + (learn_rate, end_step) = next(schedules) print(f'Training at rate of {learn_rate} until step {end_step}') optimizer = torch.optim.AdamW([embedding.vec], lr=learn_rate) @@ -213,7 +211,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if embedding.step > end_step: try: - (learn_rate, end_step) = next(scheduleIter) + (learn_rate, end_step) = next(schedules) except: break tqdm.tqdm.write(f'Training at rate of {learn_rate} until step {end_step}') @@ -288,37 +286,3 @@ Last saved image: {html.escape(last_saved_image)}
    embedding.save(filename) return embedding, filename - -class LearnSchedule: - def __init__(self, learn_rate, max_steps, cur_step=0): - pairs = learn_rate.split(',') - self.rates = [] - self.it = 0 - self.maxit = 0 - for i, pair in enumerate(pairs): - tmp = pair.split(':') - if len(tmp) == 2: - step = int(tmp[1]) - if step > cur_step: - self.rates.append((float(tmp[0]), min(step, max_steps))) - self.maxit += 1 - if step > max_steps: - return - elif step == -1: - self.rates.append((float(tmp[0]), max_steps)) - self.maxit += 1 - return - else: - self.rates.append((float(tmp[0]), max_steps)) - self.maxit += 1 - return - - def __iter__(self): - return self - - def __next__(self): - if self.it < self.maxit: - self.it += 1 - return self.rates[self.it - 1] - else: - raise StopIteration diff --git a/modules/ui.py b/modules/ui.py index 2b688e325..1204eef7b 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1070,7 +1070,7 @@ def create_ui(wrap_gradio_gpu_call): gr.HTML(value="

    Train an embedding; must specify a directory with a set of 1:1 ratio images

    ") train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', choices=[x for x in shared.hypernetworks.keys()]) - learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value = "5.0e-03") + learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value="0.005") dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) From aa75d5cfe8c84768b0f5d16f977ddba298677379 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 20:06:13 +0100 Subject: [PATCH 349/460] correct conflict resolution typo --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 22b4ae7f2..789383ce7 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -169,7 +169,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_image_prompt) +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_image_prompt): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." From 91d7ee0d097a7ea203d261b570cd2b834837d9e2 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 20:09:10 +0100 Subject: [PATCH 350/460] update imports --- modules/textual_inversion/textual_inversion.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 789383ce7..ff0a62b33 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -12,6 +12,9 @@ from PIL import Image,PngImagePlugin from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset +from modules.textual_inversion.image_embedding import( embedding_to_b64,embedding_from_b64, + insert_image_data_embed,extract_image_data_embed, + caption_image_overlay ) class Embedding: def __init__(self, vec, name, step=None): From 5f3317376bb7952bc5145f05f16c1bbd466efc85 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 20:09:49 +0100 Subject: [PATCH 351/460] spacing --- modules/textual_inversion/textual_inversion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index ff0a62b33..485ef46cf 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -12,7 +12,7 @@ from PIL import Image,PngImagePlugin from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset -from modules.textual_inversion.image_embedding import( embedding_to_b64,embedding_from_b64, +from modules.textual_inversion.image_embedding import (embedding_to_b64,embedding_from_b64, insert_image_data_embed,extract_image_data_embed, caption_image_overlay ) From 7e6a6e00ad6f3b7ef43c8120db9ecac6e8d6bea5 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 20:20:46 +0100 Subject: [PATCH 352/460] Add files via upload --- modules/textual_inversion/test_embedding.png | Bin 0 -> 489220 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 modules/textual_inversion/test_embedding.png diff --git a/modules/textual_inversion/test_embedding.png b/modules/textual_inversion/test_embedding.png new file mode 100644 index 0000000000000000000000000000000000000000..07e2d9afaeaff3751b68a7c0f49d8b3466474282 GIT binary patch literal 489220 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

    _gXT+oL1!p{=j_4x0aQkU_NRi{$KZQx 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 z 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 N;OXk;vd$@?2>{a42J!#^ literal 0 HcmV?d00001 From 66ec505975aaa305a217fc27281ce368cbaef281 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Tue, 11 Oct 2022 20:21:30 +0100 Subject: [PATCH 353/460] add file based test --- modules/textual_inversion/image_embedding.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/textual_inversion/image_embedding.py b/modules/textual_inversion/image_embedding.py index c67028a50..1224fb422 100644 --- a/modules/textual_inversion/image_embedding.py +++ b/modules/textual_inversion/image_embedding.py @@ -164,6 +164,14 @@ def caption_image_overlay(srcimage,title,footerLeft,footerMid,footerRight,textfo return image if __name__ == '__main__': + + testEmbed = Image.open('test_embedding.png') + + data = extract_image_data_embed(testEmbed) + assert data is not None + + data = embedding_from_b64(testEmbed.text['sd-ti-embedding']) + assert data is not None image = Image.new('RGBA',(512,512),(255,255,200,255)) cap_image = caption_image_overlay(image, 'title', 'footerLeft', 'footerMid', 'footerRight') From 6be32b31d181e42c639dad3451229aa7b9cfd1cf Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Tue, 11 Oct 2022 23:07:09 +0300 Subject: [PATCH 354/460] reports that training with medvram is possible. --- modules/hypernetworks/ui.py | 2 +- modules/textual_inversion/ui.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py index c67facbb7..dfa599afa 100644 --- a/modules/hypernetworks/ui.py +++ b/modules/hypernetworks/ui.py @@ -25,7 +25,7 @@ def train_hypernetwork(*args): initial_hypernetwork = shared.loaded_hypernetwork - assert not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram, 'Training models with lowvram or medvram is not possible' + assert not shared.cmd_opts.lowvram, 'Training models with lowvram is not possible' try: sd_hijack.undo_optimizations() diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py index 70f47343e..36881e7ad 100644 --- a/modules/textual_inversion/ui.py +++ b/modules/textual_inversion/ui.py @@ -23,7 +23,7 @@ def preprocess(*args): def train_embedding(*args): - assert not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram, 'Training models with lowvram or medvram is not possible' + assert not shared.cmd_opts.lowvram, 'Training models with lowvram not possible' try: sd_hijack.undo_optimizations() From f53f703aebc801c4204182d52bb1e0bef9808e1f Mon Sep 17 00:00:00 2001 From: JC_Array Date: Tue, 11 Oct 2022 18:12:12 -0500 Subject: [PATCH 355/460] resolved conflicts, moved settings under interrogate section, settings only show if deepbooru flag is enabled --- modules/deepbooru.py | 2 +- modules/shared.py | 19 +++++++++---------- modules/textual_inversion/preprocess.py | 2 +- modules/ui.py | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 89dcac3cf..295299490 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -8,7 +8,7 @@ def get_deepbooru_tags(pil_image): This method is for running only one image at a time for simple use. Used to the img2img interrogate. """ from modules import shared # prevents circular reference - create_deepbooru_process(shared.opts.deepbooru_threshold, shared.opts.deepbooru_sort_alpha) + create_deepbooru_process(shared.opts.interrogate_deepbooru_score_threshold, shared.opts.deepbooru_sort_alpha) shared.deepbooru_process_return["value"] = -1 shared.deepbooru_process_queue.put(pil_image) while shared.deepbooru_process_return["value"] == -1: diff --git a/modules/shared.py b/modules/shared.py index 817203f80..5456c4778 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -248,15 +248,20 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), })) -options_templates.update(options_section(('interrogate', "Interrogate Options"), { +interrogate_option_dictionary = { "interrogate_keep_models_in_memory": OptionInfo(False, "Interrogate: keep models in VRAM"), "interrogate_use_builtin_artists": OptionInfo(True, "Interrogate: use artists from artists.csv"), "interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}), "interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}), "interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}), - "interrogate_clip_dict_limit": OptionInfo(1500, "Interrogate: maximum number of lines in text file (0 = No limit)"), - "interrogate_deepbooru_score_threshold": OptionInfo(0.5, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), -})) + "interrogate_clip_dict_limit": OptionInfo(1500, "Interrogate: maximum number of lines in text file (0 = No limit)") +} + +if cmd_opts.deepdanbooru: + interrogate_option_dictionary["interrogate_deepbooru_score_threshold"] = OptionInfo(0.5, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}) + interrogate_option_dictionary["deepbooru_sort_alpha"] = OptionInfo(True, "Interrogate: deepbooru sort alphabetically", gr.Checkbox) + +options_templates.update(options_section(('interrogate', "Interrogate Options"), interrogate_option_dictionary)) options_templates.update(options_section(('ui', "User interface"), { "show_progressbar": OptionInfo(True, "Show progressbar"), @@ -282,12 +287,6 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters" 'eta_noise_seed_delta': OptionInfo(0, "Eta noise seed delta", gr.Number, {"precision": 0}), })) -if cmd_opts.deepdanbooru: - options_templates.update(options_section(('deepbooru-params', "DeepBooru parameters"), { - "deepbooru_sort_alpha": OptionInfo(True, "Sort Alphabetical", gr.Checkbox), - 'deepbooru_threshold': OptionInfo(0.5, "Threshold", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}), - })) - class Options: data = None diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index a96388d6d..113cecf1d 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -29,7 +29,7 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ shared.interrogator.load() if process_caption_deepbooru: - deepbooru.create_deepbooru_process(opts.deepbooru_threshold, opts.deepbooru_sort_alpha) + deepbooru.create_deepbooru_process(opts.interrogate_deepbooru_score_threshold, opts.deepbooru_sort_alpha) def save_pic_with_caption(image, index): if process_caption: diff --git a/modules/ui.py b/modules/ui.py index 2891fc8c7..fa45edca7 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -317,7 +317,7 @@ def interrogate(image): def interrogate_deepbooru(image): - prompt = get_deepbooru_tags(image, opts.interrogate_deepbooru_score_threshold) + prompt = get_deepbooru_tags(image) return gr_show(True) if prompt is None else prompt From 6d408c06c634cc96480f055941754dcc43f781d9 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Wed, 12 Oct 2022 00:19:28 +0100 Subject: [PATCH 356/460] Prevent nans from failed float parsing from overwriting weights --- javascript/edit-attention.js | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js index 79566a2e2..3f1d2fbbd 100644 --- a/javascript/edit-attention.js +++ b/javascript/edit-attention.js @@ -25,6 +25,7 @@ addEventListener('keydown', (event) => { } else { end = target.value.slice(selectionEnd + 1).indexOf(")") + 1; weight = parseFloat(target.value.slice(selectionEnd + 1, selectionEnd + 1 + end)); + if (isNaN(weight)) return; if (event.key == minus) weight -= 0.1; if (event.key == plus) weight += 0.1; From 65b973ac4e547a325f30a05f852b161421af2041 Mon Sep 17 00:00:00 2001 From: supersteve3d <39339941+supersteve3d@users.noreply.github.com> Date: Wed, 12 Oct 2022 08:21:52 +0800 Subject: [PATCH 357/460] Update shared.py Correct typo to "Unload VAE and CLIP from VRAM when training" in settings tab. --- modules/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/shared.py b/modules/shared.py index c1092ff79..46bc740c5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -229,7 +229,7 @@ options_templates.update(options_section(('system', "System"), { })) options_templates.update(options_section(('training', "Training"), { - "unload_models_when_training": OptionInfo(False, "Unload VAE and CLIP form VRAM when training"), + "unload_models_when_training": OptionInfo(False, "Unload VAE and CLIP from VRAM when training"), })) options_templates.update(options_section(('sd', "Stable Diffusion"), { From d717eb079cd6b7fa7a4f97c0a10d400bdec753fb Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Tue, 11 Oct 2022 18:02:41 -0700 Subject: [PATCH 358/460] Interrogate: add option to include ranks in output Since the UI also allows users to specify ranks, it can be useful to show people what ranks are being returned by interrogate This can also give much better results when feeding the interrogate results back into either img2img or txt2img, especially when trying to generate a specific character or scene for which you have a similar concept image Testing Steps: Launch Webui with command line arg: --deepdanbooru Navigate to img2img tab, use interrogate DeepBooru, verify tags appears as before. Use "Interrogate CLIP", verify prompt appears as before Navigate to Settings tab, enable new option, click "apply settings" Navigate to img2img, Interrogate DeepBooru again, verify that weights appear and are properly formatted. Note that "Interrogate CLIP" prompt is still unchanged In my testing, this change has no effect to "Interrogate CLIP", as it seems to generate a sentence-structured caption, and not a set of tags. (reproduce changes from https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/2149/commits/6ed4faac46c45ca7353f228aca9b436bbaba7bc7) --- modules/deepbooru.py | 14 +++++++++----- modules/interrogate.py | 7 +++++-- modules/shared.py | 1 + modules/ui.py | 5 ++--- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 7e3c06182..32d741e20 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -3,7 +3,7 @@ from concurrent.futures import ProcessPoolExecutor from multiprocessing import get_context -def _load_tf_and_return_tags(pil_image, threshold): +def _load_tf_and_return_tags(pil_image, threshold, include_ranks): import deepdanbooru as dd import tensorflow as tf import numpy as np @@ -52,12 +52,16 @@ def _load_tf_and_return_tags(pil_image, threshold): if result_dict[tag] >= threshold: if tag.startswith("rating:"): continue - result_tags_out.append(tag) + tag_formatted = tag.replace('_', ' ').replace(':', ' ') + if include_ranks: + result_tags_out.append(f'({tag_formatted}:{result_dict[tag]})') + else: + result_tags_out.append(tag_formatted) result_tags_print.append(f'{result_dict[tag]} {tag}') print('\n'.join(sorted(result_tags_print, reverse=True))) - return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') + return ', '.join(result_tags_out) def subprocess_init_no_cuda(): @@ -65,9 +69,9 @@ def subprocess_init_no_cuda(): os.environ["CUDA_VISIBLE_DEVICES"] = "-1" -def get_deepbooru_tags(pil_image, threshold=0.5): +def get_deepbooru_tags(pil_image, threshold=0.5, include_ranks=False): context = get_context('spawn') with ProcessPoolExecutor(initializer=subprocess_init_no_cuda, mp_context=context) as executor: - f = executor.submit(_load_tf_and_return_tags, pil_image, threshold, ) + f = executor.submit(_load_tf_and_return_tags, pil_image, threshold, include_ranks) ret = f.result() # will rethrow any exceptions return ret \ No newline at end of file diff --git a/modules/interrogate.py b/modules/interrogate.py index 635e266e7..af858cc09 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -123,7 +123,7 @@ class InterrogateModels: return caption[0] - def interrogate(self, pil_image): + def interrogate(self, pil_image, include_ranks=False): res = None try: @@ -156,7 +156,10 @@ class InterrogateModels: for name, topn, items in self.categories: matches = self.rank(image_features, items, top_count=topn) for match, score in matches: - res += ", " + match + if include_ranks: + res += ", " + match + else: + res += f", ({match}:{score})" except Exception: print(f"Error interrogating", file=sys.stderr) diff --git a/modules/shared.py b/modules/shared.py index c1092ff79..3e0bfd726 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -251,6 +251,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { options_templates.update(options_section(('interrogate', "Interrogate Options"), { "interrogate_keep_models_in_memory": OptionInfo(False, "Interrogate: keep models in VRAM"), "interrogate_use_builtin_artists": OptionInfo(True, "Interrogate: use artists from artists.csv"), + "interrogate_return_ranks": OptionInfo(False, "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators)."), "interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}), "interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}), "interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}), diff --git a/modules/ui.py b/modules/ui.py index 1204eef7b..f4dbe2472 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -311,13 +311,12 @@ def apply_styles(prompt, prompt_neg, style1_name, style2_name): def interrogate(image): - prompt = shared.interrogator.interrogate(image) - + prompt = shared.interrogator.interrogate(image, include_ranks=opts.interrogate_return_ranks) return gr_show(True) if prompt is None else prompt def interrogate_deepbooru(image): - prompt = get_deepbooru_tags(image, opts.interrogate_deepbooru_score_threshold) + prompt = get_deepbooru_tags(image, opts.interrogate_deepbooru_score_threshold, opts.interrogate_return_ranks) return gr_show(True) if prompt is None else prompt From 6ac2ec2b78bc5fabd09cb866dd9a71061d669269 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 07:01:20 +0300 Subject: [PATCH 359/460] create dir for hypernetworks --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index c1092ff79..e65e77f81 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -86,6 +86,7 @@ parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram xformers_available = False config_filename = cmd_opts.ui_settings_file +os.makedirs(cmd_opts.hypernetwork_dir, exist_ok=True) hypernetworks = hypernetwork.list_hypernetworks(cmd_opts.hypernetwork_dir) loaded_hypernetwork = None From fec2221eeaafb50afd26ba3e109bf6f928011e69 Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Tue, 11 Oct 2022 19:29:38 -0700 Subject: [PATCH 360/460] Truncate error text to fix service lockup / stall What: * Update wrap_gradio_call to add a limit to the maximum amount of text output Why: * wrap_gradio_call currently prints out a list of the arguments provided to the failing function. * if that function is save_image, this causes the entire image to be printed to stderr * If the image is large, this can cause the service to lock up while attempting to print all the text * It is easy to generate large images using the x/y plot script * it is easy to encounter image save exceptions, including if the output directory does not exist / cannot be written to, or if the file is too big * The huge amount of log spam is confusing and not particularly helpful --- modules/ui.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index 1204eef7b..33a49d3bf 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -181,8 +181,15 @@ def wrap_gradio_call(func, extra_outputs=None): try: res = list(func(*args, **kwargs)) except Exception as e: + # When printing out our debug argument list, do not print out more than a MB of text + max_debug_str_len = 131072 # (1024*1024)/8 + print("Error completing request", file=sys.stderr) - print("Arguments:", args, kwargs, file=sys.stderr) + argStr = f"Arguments: {str(args)} {str(kwargs)}" + print(argStr[:max_debug_str_len], file=sys.stderr) + if len(argStr) > max_debug_str_len: + print(f"(Argument list truncated at {max_debug_str_len}/{len(argStr)} characters)", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) shared.state.job = "" From 336bd8703c7b4d71f2f096f303599925a30b8167 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 09:00:07 +0300 Subject: [PATCH 361/460] just add the deepdanbooru settings unconditionally --- modules/shared.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index f150e0243..42e997416 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -249,20 +249,15 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), })) -interrogate_option_dictionary = { +options_templates.update(options_section(('interrogate', "Interrogate Options"), { "interrogate_keep_models_in_memory": OptionInfo(False, "Interrogate: keep models in VRAM"), "interrogate_use_builtin_artists": OptionInfo(True, "Interrogate: use artists from artists.csv"), "interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}), "interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}), "interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}), - "interrogate_clip_dict_limit": OptionInfo(1500, "Interrogate: maximum number of lines in text file (0 = No limit)") -} - -if cmd_opts.deepdanbooru: - interrogate_option_dictionary["interrogate_deepbooru_score_threshold"] = OptionInfo(0.5, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}) - interrogate_option_dictionary["deepbooru_sort_alpha"] = OptionInfo(True, "Interrogate: deepbooru sort alphabetically", gr.Checkbox) - -options_templates.update(options_section(('interrogate', "Interrogate Options"), interrogate_option_dictionary)) + "interrogate_deepbooru_score_threshold": OptionInfo(0.5, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), + "deepbooru_sort_alpha": OptionInfo(True, "Interrogate: deepbooru sort alphabetically"), +})) options_templates.update(options_section(('ui', "User interface"), { "show_progressbar": OptionInfo(True, "Show progressbar"), From fd07b103aeb70a80e3641068e483475e32c9750c Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 09:00:39 +0300 Subject: [PATCH 362/460] prevent SD model from loading when running in deepdanbooru process --- webui.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/webui.py b/webui.py index ca278e940..32bcdb065 100644 --- a/webui.py +++ b/webui.py @@ -31,12 +31,7 @@ from modules.paths import script_path from modules.shared import cmd_opts import modules.hypernetworks.hypernetwork -modelloader.cleanup_models() -modules.sd_models.setup_model() -codeformer.setup_model(cmd_opts.codeformer_models_path) -gfpgan.setup_model(cmd_opts.gfpgan_models_path) -shared.face_restorers.append(modules.face_restoration.FaceRestoration()) -modelloader.load_upscalers() + queue_lock = threading.Lock() @@ -78,12 +73,19 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) -modules.scripts.load_scripts(os.path.join(script_path, "scripts")) +def initialize(): + modelloader.cleanup_models() + modules.sd_models.setup_model() + codeformer.setup_model(cmd_opts.codeformer_models_path) + gfpgan.setup_model(cmd_opts.gfpgan_models_path) + shared.face_restorers.append(modules.face_restoration.FaceRestoration()) + modelloader.load_upscalers() -shared.sd_model = modules.sd_models.load_model() -shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) + modules.scripts.load_scripts(os.path.join(script_path, "scripts")) -shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetworks.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) + shared.sd_model = modules.sd_models.load_model() + shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) + shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetworks.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) def webui(): @@ -98,7 +100,7 @@ def webui(): demo = modules.ui.create_ui(wrap_gradio_gpu_call=wrap_gradio_gpu_call) - app,local_url,share_url = demo.launch( + app, local_url, share_url = demo.launch( share=cmd_opts.share, server_name="0.0.0.0" if cmd_opts.listen else None, server_port=cmd_opts.port, @@ -129,6 +131,6 @@ def webui(): print('Restarting Gradio') - if __name__ == "__main__": + initialize() webui() From 7edd58d90dd08f68fab5ff84d26dedd0eb85cae3 Mon Sep 17 00:00:00 2001 From: James Noeckel Date: Tue, 11 Oct 2022 17:48:24 -0700 Subject: [PATCH 363/460] update environment-wsl2.yaml --- environment-wsl2.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/environment-wsl2.yaml b/environment-wsl2.yaml index c9ce11df3..f88727507 100644 --- a/environment-wsl2.yaml +++ b/environment-wsl2.yaml @@ -3,9 +3,9 @@ channels: - pytorch - defaults dependencies: - - python=3.8.5 - - pip=20.3 + - python=3.10 + - pip=22.2.2 - cudatoolkit=11.3 - - pytorch=1.11.0 - - torchvision=0.12.0 - - numpy=1.19.2 + - pytorch=1.12.1 + - torchvision=0.13.1 + - numpy=1.23.1 \ No newline at end of file From 8aead63f1ac9fec0e5198bd626ec2c5bcbeff4d8 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 09:32:14 +0300 Subject: [PATCH 364/460] emergency fix --- webui.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webui.py b/webui.py index 32bcdb065..33ba79054 100644 --- a/webui.py +++ b/webui.py @@ -89,6 +89,8 @@ def initialize(): def webui(): + initialize() + # make the program just exit at ctrl+c without waiting for anything def sigint_handler(sig, frame): print(f'Interrupted with signal {sig} in {frame}') @@ -132,5 +134,4 @@ def webui(): if __name__ == "__main__": - initialize() webui() From 57e03cdd244eee4e33ccab7554b3594563a3d0cd Mon Sep 17 00:00:00 2001 From: brkirch Date: Wed, 12 Oct 2022 00:54:24 -0400 Subject: [PATCH 365/460] Ensure the directory exists before saving to it The directory for the images saved with the Save button may still not exist, so it needs to be created prior to opening the log.csv file. --- modules/ui.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ui.py b/modules/ui.py index 00bf09ae3..cd67b84b3 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -131,6 +131,8 @@ def save_files(js_data, images, do_make_zip, index): images = [images[index]] start_index = index + os.makedirs(opts.outdir_save, exist_ok=True) + with open(os.path.join(opts.outdir_save, "log.csv"), "a", encoding="utf8", newline='') as file: at_start = file.tell() == 0 writer = csv.writer(file) From f421f2af2df41a86af1aea1e82b4c32a2d143385 Mon Sep 17 00:00:00 2001 From: aoirusann Date: Wed, 12 Oct 2022 13:02:28 +0800 Subject: [PATCH 366/460] [img2imgalt] Fix seed & Allow batch. --- scripts/img2imgalt.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/img2imgalt.py b/scripts/img2imgalt.py index f9894cb01..313a55d21 100644 --- a/scripts/img2imgalt.py +++ b/scripts/img2imgalt.py @@ -129,8 +129,6 @@ class Script(scripts.Script): return [original_prompt, original_negative_prompt, cfg, st, randomness, sigma_adjustment] def run(self, p, original_prompt, original_negative_prompt, cfg, st, randomness, sigma_adjustment): - p.batch_size = 1 - p.batch_count = 1 def sample_extra(conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength): @@ -154,7 +152,7 @@ class Script(scripts.Script): rec_noise = find_noise_for_image(p, cond, uncond, cfg, st) self.cache = Cached(rec_noise, cfg, st, lat, original_prompt, original_negative_prompt, sigma_adjustment) - rand_noise = processing.create_random_tensors(p.init_latent.shape[1:], [p.seed + x + 1 for x in range(p.init_latent.shape[0])]) + rand_noise = processing.create_random_tensors(p.init_latent.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=p.subseed_strength, seed_resize_from_h=p.seed_resize_from_h, seed_resize_from_w=p.seed_resize_from_w, p=p) combined_noise = ((1 - randomness) * rec_noise + randomness * rand_noise) / ((randomness**2 + (1-randomness)**2) ** 0.5) From ca5efc316b9431746ff886d259275310f63f95fb Mon Sep 17 00:00:00 2001 From: LunixWasTaken Date: Tue, 11 Oct 2022 22:04:56 +0200 Subject: [PATCH 367/460] Typo fix in watermark hint. --- javascript/hints.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/hints.js b/javascript/hints.js index 045f2d3c1..b81c181b9 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -80,7 +80,7 @@ titles = { "Scale latent": "Uscale the image in latent space. Alternative is to produce the full image from latent representation, upscale that, and then move it back to latent space.", "Eta noise seed delta": "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing.", - "Do not add watermark to images": "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be bevaing in an unethical manner.", + "Do not add watermark to images": "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be behaving in an unethical manner.", } From 2d006ce16cd95d587533656c3ac4991495e96f23 Mon Sep 17 00:00:00 2001 From: Milly Date: Mon, 10 Oct 2022 00:56:36 +0900 Subject: [PATCH 368/460] xy_grid: Find hypernetwork by closest name --- modules/hypernetworks/hypernetwork.py | 11 +++++++++++ scripts/xy_grid.py | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 470659dfe..8f2192e2f 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -120,6 +120,17 @@ def load_hypernetwork(filename): shared.loaded_hypernetwork = None +def find_closest_hypernetwork_name(search: str): + if not search: + return None + search = search.lower() + applicable = [name for name in shared.hypernetworks if search in name.lower()] + if not applicable: + return None + applicable = sorted(applicable, key=lambda name: len(name)) + return applicable[0] + + def apply_hypernetwork(hypernetwork, context, layer=None): hypernetwork_layers = (hypernetwork.layers if hypernetwork is not None else {}).get(context.shape[2], None) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index ef4311054..6f4217ec6 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -84,7 +84,11 @@ def apply_checkpoint(p, x, xs): def apply_hypernetwork(p, x, xs): - hypernetwork.load_hypernetwork(x) + if x.lower() in ["", "none"]: + name = None + else: + name = hypernetwork.find_closest_hypernetwork_name(x) + hypernetwork.load_hypernetwork(name) def apply_clip_skip(p, x, xs): From 7dba1c07cb337114507d9c256f9b843162c187d6 Mon Sep 17 00:00:00 2001 From: Milly Date: Mon, 10 Oct 2022 01:37:09 +0900 Subject: [PATCH 369/460] xy_grid: Confirm that hypernetwork options are valid before starting --- scripts/xy_grid.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 6f4217ec6..b2239d0a3 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -88,9 +88,19 @@ def apply_hypernetwork(p, x, xs): name = None else: name = hypernetwork.find_closest_hypernetwork_name(x) + if not name: + raise RuntimeError(f"Unknown hypernetwork: {x}") hypernetwork.load_hypernetwork(name) +def confirm_hypernetworks(xs): + for x in xs: + if x.lower() in ["", "none"]: + continue + if not hypernetwork.find_closest_hypernetwork_name(x): + raise RuntimeError(f"Unknown hypernetwork: {x}") + + def apply_clip_skip(p, x, xs): opts.data["CLIP_stop_at_last_layers"] = x @@ -284,6 +294,8 @@ class Script(scripts.Script): for ckpt_val in valslist: if modules.sd_models.get_closet_checkpoint_match(ckpt_val) is None: raise RuntimeError(f"Checkpoint for {ckpt_val} not found") + elif opt.label == "Hypernetwork": + confirm_hypernetworks(valslist) return valslist From 2fffd4bddce12b2c98a5bae5a2cc6d64450d65a0 Mon Sep 17 00:00:00 2001 From: Milly Date: Mon, 10 Oct 2022 02:20:35 +0900 Subject: [PATCH 370/460] xy_grid: Refactor confirm functions --- scripts/xy_grid.py | 73 +++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index b2239d0a3..3bb080bf3 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -77,12 +77,26 @@ def apply_sampler(p, x, xs): p.sampler_index = sampler_index +def confirm_samplers(p, xs): + samplers_dict = build_samplers_dict(p) + for x in xs: + if x.lower() not in samplers_dict.keys(): + raise RuntimeError(f"Unknown sampler: {x}") + + def apply_checkpoint(p, x, xs): info = modules.sd_models.get_closet_checkpoint_match(x) - assert info is not None, f'Checkpoint for {x} not found' + if info is None: + raise RuntimeError(f"Unknown checkpoint: {x}") modules.sd_models.reload_model_weights(shared.sd_model, info) +def confirm_checkpoints(p, xs): + for x in xs: + if modules.sd_models.get_closet_checkpoint_match(x) is None: + raise RuntimeError(f"Unknown checkpoint: {x}") + + def apply_hypernetwork(p, x, xs): if x.lower() in ["", "none"]: name = None @@ -93,7 +107,7 @@ def apply_hypernetwork(p, x, xs): hypernetwork.load_hypernetwork(name) -def confirm_hypernetworks(xs): +def confirm_hypernetworks(p, xs): for x in xs: if x.lower() in ["", "none"]: continue @@ -135,29 +149,29 @@ def str_permutations(x): return x -AxisOption = namedtuple("AxisOption", ["label", "type", "apply", "format_value"]) -AxisOptionImg2Img = namedtuple("AxisOptionImg2Img", ["label", "type", "apply", "format_value"]) +AxisOption = namedtuple("AxisOption", ["label", "type", "apply", "format_value", "confirm"]) +AxisOptionImg2Img = namedtuple("AxisOptionImg2Img", ["label", "type", "apply", "format_value", "confirm"]) axis_options = [ - AxisOption("Nothing", str, do_nothing, format_nothing), - AxisOption("Seed", int, apply_field("seed"), format_value_add_label), - AxisOption("Var. seed", int, apply_field("subseed"), format_value_add_label), - AxisOption("Var. strength", float, apply_field("subseed_strength"), format_value_add_label), - AxisOption("Steps", int, apply_field("steps"), format_value_add_label), - AxisOption("CFG Scale", float, apply_field("cfg_scale"), format_value_add_label), - AxisOption("Prompt S/R", str, apply_prompt, format_value), - AxisOption("Prompt order", str_permutations, apply_order, format_value_join_list), - AxisOption("Sampler", str, apply_sampler, format_value), - AxisOption("Checkpoint name", str, apply_checkpoint, format_value), - AxisOption("Hypernetwork", str, apply_hypernetwork, format_value), - AxisOption("Sigma Churn", float, apply_field("s_churn"), format_value_add_label), - AxisOption("Sigma min", float, apply_field("s_tmin"), format_value_add_label), - AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label), - AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label), - AxisOption("Eta", float, apply_field("eta"), format_value_add_label), - AxisOption("Clip skip", int, apply_clip_skip, format_value_add_label), - AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label), # as it is now all AxisOptionImg2Img items must go after AxisOption ones + AxisOption("Nothing", str, do_nothing, format_nothing, None), + AxisOption("Seed", int, apply_field("seed"), format_value_add_label, None), + AxisOption("Var. seed", int, apply_field("subseed"), format_value_add_label, None), + AxisOption("Var. strength", float, apply_field("subseed_strength"), format_value_add_label, None), + AxisOption("Steps", int, apply_field("steps"), format_value_add_label, None), + AxisOption("CFG Scale", float, apply_field("cfg_scale"), format_value_add_label, None), + AxisOption("Prompt S/R", str, apply_prompt, format_value, None), + AxisOption("Prompt order", str_permutations, apply_order, format_value_join_list, None), + AxisOption("Sampler", str, apply_sampler, format_value, confirm_samplers), + AxisOption("Checkpoint name", str, apply_checkpoint, format_value, confirm_checkpoints), + AxisOption("Hypernetwork", str, apply_hypernetwork, format_value, confirm_hypernetworks), + AxisOption("Sigma Churn", float, apply_field("s_churn"), format_value_add_label, None), + AxisOption("Sigma min", float, apply_field("s_tmin"), format_value_add_label, None), + AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label, None), + AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label, None), + AxisOption("Eta", float, apply_field("eta"), format_value_add_label, None), + AxisOption("Clip skip", int, apply_clip_skip, format_value_add_label, None), + AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label, None), # as it is now all AxisOptionImg2Img items must go after AxisOption ones ] @@ -283,19 +297,10 @@ class Script(scripts.Script): valslist = list(permutations(valslist)) valslist = [opt.type(x) for x in valslist] - + # Confirm options are valid before starting - if opt.label == "Sampler": - samplers_dict = build_samplers_dict(p) - for sampler_val in valslist: - if sampler_val.lower() not in samplers_dict.keys(): - raise RuntimeError(f"Unknown sampler: {sampler_val}") - elif opt.label == "Checkpoint name": - for ckpt_val in valslist: - if modules.sd_models.get_closet_checkpoint_match(ckpt_val) is None: - raise RuntimeError(f"Checkpoint for {ckpt_val} not found") - elif opt.label == "Hypernetwork": - confirm_hypernetworks(valslist) + if opt.confirm: + opt.confirm(p, valslist) return valslist From ee015a1af66a94a75c914659fa0d321e702a0a87 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 11:05:57 +0300 Subject: [PATCH 371/460] change textual inversion tab to train remake train interface to use tabs --- modules/hypernetworks/hypernetwork.py | 2 +- modules/ui.py | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 8f2192e2f..8314450ae 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -175,7 +175,7 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_image_prompt): - assert hypernetwork_name, 'embedding not selected' + assert hypernetwork_name, 'hypernetwork not selected' path = shared.hypernetworks.get(hypernetwork_name, None) shared.loaded_hypernetwork = Hypernetwork() diff --git a/modules/ui.py b/modules/ui.py index 4bfdd2752..86a2da6c3 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1035,14 +1035,14 @@ def create_ui(wrap_gradio_gpu_call): sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() - with gr.Blocks() as textual_inversion_interface: + with gr.Blocks() as train_interface: with gr.Row().style(equal_height=False): - with gr.Column(): - with gr.Group(): - gr.HTML(value="

    See wiki for detailed explanation.

    ") + gr.HTML(value="

    See wiki for detailed explanation.

    ") - gr.HTML(value="

    Create a new embedding

    ") + with gr.Row().style(equal_height=False): + with gr.Tabs(elem_id="train_tabs"): + with gr.Tab(label="Create embedding"): new_embedding_name = gr.Textbox(label="Name") initialization_text = gr.Textbox(label="Initialization text", value="*") nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1) @@ -1054,9 +1054,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Column(): create_embedding = gr.Button(value="Create embedding", variant='primary') - with gr.Group(): - gr.HTML(value="

    Create a new hypernetwork

    ") - + with gr.Tab(label="Create hypernetwork"): new_hypernetwork_name = gr.Textbox(label="Name") new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "320", "640", "1280"]) @@ -1067,9 +1065,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Column(): create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary') - with gr.Group(): - gr.HTML(value="

    Preprocess images

    ") - + with gr.Tab(label="Preprocess images"): process_src = gr.Textbox(label='Source directory') process_dst = gr.Textbox(label='Destination directory') process_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512) @@ -1091,7 +1087,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Column(): run_preprocess = gr.Button(value="Preprocess", variant='primary') - with gr.Group(): + with gr.Tab(label="Train"): gr.HTML(value="

    Train an embedding; must specify a directory with a set of 1:1 ratio images

    ") train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', choices=[x for x in shared.hypernetworks.keys()]) @@ -1388,7 +1384,7 @@ Requested path was: {f} (extras_interface, "Extras", "extras"), (pnginfo_interface, "PNG Info", "pnginfo"), (modelmerger_interface, "Checkpoint Merger", "modelmerger"), - (textual_inversion_interface, "Textual inversion", "ti"), + (train_interface, "Train", "ti"), (settings_interface, "Settings", "settings"), ] From 80f3cf2bb2ce3f00d801cae2c3a8c20a8d4167d8 Mon Sep 17 00:00:00 2001 From: hentailord85ez <112723046+hentailord85ez@users.noreply.github.com> Date: Tue, 11 Oct 2022 19:48:53 +0100 Subject: [PATCH 372/460] Account when lines are mismatched --- modules/sd_hijack.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index ac70f8767..2753d4fa8 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -321,7 +321,17 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): fixes.append(fix[1]) self.hijack.fixes.append(fixes) - z1 = self.process_tokens([x[:75] for x in remade_batch_tokens], [x[:75] for x in batch_multipliers]) + tokens = [] + multipliers = [] + for i in range(len(remade_batch_tokens)): + if len(remade_batch_tokens[i]) > 0: + tokens.append(remade_batch_tokens[i][:75]) + multipliers.append(batch_multipliers[i][:75]) + else: + tokens.append([self.wrapped.tokenizer.eos_token_id] * 75) + multipliers.append([1.0] * 75) + + z1 = self.process_tokens(tokens, multipliers) z = z1 if z is None else torch.cat((z, z1), axis=-2) remade_batch_tokens = rem_tokens From 8561d5762b98bf7cfb764128ebf11633d8bb4405 Mon Sep 17 00:00:00 2001 From: Kalle Date: Wed, 12 Oct 2022 12:43:11 +0300 Subject: [PATCH 373/460] Remove duplicate artist from file --- artists.csv | 1 - 1 file changed, 1 deletion(-) diff --git a/artists.csv b/artists.csv index 14ba2022a..99cdbdc60 100644 --- a/artists.csv +++ b/artists.csv @@ -1045,7 +1045,6 @@ Bakemono Zukushi,0.67051035,anime Lucy Madox Brown,0.67032814,fineart Paul Wonner,0.6700563,scribbles Guido Borelli Da Caluso,0.66966087,digipa-high-impact -Guido Borelli da Caluso,0.66966087,digipa-high-impact Emil Alzamora,0.5844039,nudity Heinrich Brocksieper,0.64469147,fineart Dan Smith,0.669563,digipa-high-impact From 429442f4a6aab7301efb89d27bef524fe827e81a Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 13:38:03 +0300 Subject: [PATCH 374/460] fix iterator bug for #2295 --- modules/sd_hijack.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index 2753d4fa8..c81722a0a 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -323,10 +323,10 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module): tokens = [] multipliers = [] - for i in range(len(remade_batch_tokens)): - if len(remade_batch_tokens[i]) > 0: - tokens.append(remade_batch_tokens[i][:75]) - multipliers.append(batch_multipliers[i][:75]) + for j in range(len(remade_batch_tokens)): + if len(remade_batch_tokens[j]) > 0: + tokens.append(remade_batch_tokens[j][:75]) + multipliers.append(batch_multipliers[j][:75]) else: tokens.append([self.wrapped.tokenizer.eos_token_id] * 75) multipliers.append([1.0] * 75) From 50be33e953be93c40814262c6dbce36e66004528 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Wed, 12 Oct 2022 13:13:25 +0100 Subject: [PATCH 375/460] formatting --- modules/textual_inversion/image_embedding.py | 170 ++++++++++--------- 1 file changed, 91 insertions(+), 79 deletions(-) diff --git a/modules/textual_inversion/image_embedding.py b/modules/textual_inversion/image_embedding.py index 1224fb422..898ce3b3b 100644 --- a/modules/textual_inversion/image_embedding.py +++ b/modules/textual_inversion/image_embedding.py @@ -2,122 +2,134 @@ import base64 import json import numpy as np import zlib -from PIL import Image,PngImagePlugin,ImageDraw,ImageFont +from PIL import Image, PngImagePlugin, ImageDraw, ImageFont from fonts.ttf import Roboto import torch + class EmbeddingEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, torch.Tensor): - return {'TORCHTENSOR':obj.cpu().detach().numpy().tolist()} + return {'TORCHTENSOR': obj.cpu().detach().numpy().tolist()} return json.JSONEncoder.default(self, obj) + class EmbeddingDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): json.JSONDecoder.__init__(self, object_hook=self.object_hook, *args, **kwargs) + def object_hook(self, d): if 'TORCHTENSOR' in d: return torch.from_numpy(np.array(d['TORCHTENSOR'])) return d + def embedding_to_b64(data): - d = json.dumps(data,cls=EmbeddingEncoder) + d = json.dumps(data, cls=EmbeddingEncoder) return base64.b64encode(d.encode()) + def embedding_from_b64(data): d = base64.b64decode(data) - return json.loads(d,cls=EmbeddingDecoder) + return json.loads(d, cls=EmbeddingDecoder) + def lcg(m=2**32, a=1664525, c=1013904223, seed=0): while True: seed = (a * seed + c) % m - yield seed%255 + yield seed % 255 + def xor_block(block): g = lcg() randblock = np.array([next(g) for _ in range(np.product(block.shape))]).astype(np.uint8).reshape(block.shape) - return np.bitwise_xor(block.astype(np.uint8),randblock & 0x0F) + return np.bitwise_xor(block.astype(np.uint8), randblock & 0x0F) -def style_block(block,sequence): - im = Image.new('RGB',(block.shape[1],block.shape[0])) + +def style_block(block, sequence): + im = Image.new('RGB', (block.shape[1], block.shape[0])) draw = ImageDraw.Draw(im) - i=0 - for x in range(-6,im.size[0],8): - for yi,y in enumerate(range(-6,im.size[1],8)): - offset=0 - if yi%2==0: - offset=4 - shade = sequence[i%len(sequence)] - i+=1 - draw.ellipse((x+offset, y, x+6+offset, y+6), fill =(shade,shade,shade) ) + i = 0 + for x in range(-6, im.size[0], 8): + for yi, y in enumerate(range(-6, im.size[1], 8)): + offset = 0 + if yi % 2 == 0: + offset = 4 + shade = sequence[i % len(sequence)] + i += 1 + draw.ellipse((x+offset, y, x+6+offset, y+6), fill=(shade, shade, shade)) fg = np.array(im).astype(np.uint8) & 0xF0 return block ^ fg -def insert_image_data_embed(image,data): + +def insert_image_data_embed(image, data): d = 3 - data_compressed = zlib.compress( json.dumps(data,cls=EmbeddingEncoder).encode(),level=9) - data_np_ = np.frombuffer(data_compressed,np.uint8).copy() + data_compressed = zlib.compress(json.dumps(data, cls=EmbeddingEncoder).encode(), level=9) + data_np_ = np.frombuffer(data_compressed, np.uint8).copy() data_np_high = data_np_ >> 4 - data_np_low = data_np_ & 0x0F - + data_np_low = data_np_ & 0x0F + h = image.size[1] - next_size = data_np_low.shape[0] + (h-(data_np_low.shape[0]%h)) - next_size = next_size + ((h*d)-(next_size%(h*d))) + next_size = data_np_low.shape[0] + (h-(data_np_low.shape[0] % h)) + next_size = next_size + ((h*d)-(next_size % (h*d))) data_np_low.resize(next_size) - data_np_low = data_np_low.reshape((h,-1,d)) + data_np_low = data_np_low.reshape((h, -1, d)) data_np_high.resize(next_size) - data_np_high = data_np_high.reshape((h,-1,d)) + data_np_high = data_np_high.reshape((h, -1, d)) edge_style = list(data['string_to_param'].values())[0].cpu().detach().numpy().tolist()[0][:1024] edge_style = (np.abs(edge_style)/np.max(np.abs(edge_style))*255).astype(np.uint8) - data_np_low = style_block(data_np_low,sequence=edge_style) - data_np_low = xor_block(data_np_low) - data_np_high = style_block(data_np_high,sequence=edge_style[::-1]) - data_np_high = xor_block(data_np_high) + data_np_low = style_block(data_np_low, sequence=edge_style) + data_np_low = xor_block(data_np_low) + data_np_high = style_block(data_np_high, sequence=edge_style[::-1]) + data_np_high = xor_block(data_np_high) - im_low = Image.fromarray(data_np_low,mode='RGB') - im_high = Image.fromarray(data_np_high,mode='RGB') + im_low = Image.fromarray(data_np_low, mode='RGB') + im_high = Image.fromarray(data_np_high, mode='RGB') - background = Image.new('RGB',(image.size[0]+im_low.size[0]+im_high.size[0]+2,image.size[1]),(0,0,0)) - background.paste(im_low,(0,0)) - background.paste(image,(im_low.size[0]+1,0)) - background.paste(im_high,(im_low.size[0]+1+image.size[0]+1,0)) + background = Image.new('RGB', (image.size[0]+im_low.size[0]+im_high.size[0]+2, image.size[1]), (0, 0, 0)) + background.paste(im_low, (0, 0)) + background.paste(image, (im_low.size[0]+1, 0)) + background.paste(im_high, (im_low.size[0]+1+image.size[0]+1, 0)) return background -def crop_black(img,tol=0): - mask = (img>tol).all(2) - mask0,mask1 = mask.any(0),mask.any(1) - col_start,col_end = mask0.argmax(),mask.shape[1]-mask0[::-1].argmax() - row_start,row_end = mask1.argmax(),mask.shape[0]-mask1[::-1].argmax() - return img[row_start:row_end,col_start:col_end] + +def crop_black(img, tol=0): + mask = (img > tol).all(2) + mask0, mask1 = mask.any(0), mask.any(1) + col_start, col_end = mask0.argmax(), mask.shape[1]-mask0[::-1].argmax() + row_start, row_end = mask1.argmax(), mask.shape[0]-mask1[::-1].argmax() + return img[row_start:row_end, col_start:col_end] + def extract_image_data_embed(image): - d=3 - outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1],image.size[0],d ).astype(np.uint8) ) & 0x0F - black_cols = np.where( np.sum(outarr, axis=(0,2))==0) + d = 3 + outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1], image.size[0], d).astype(np.uint8)) & 0x0F + black_cols = np.where(np.sum(outarr, axis=(0, 2)) == 0) if black_cols[0].shape[0] < 2: print('No Image data blocks found.') return None - data_block_lower = outarr[:,:black_cols[0].min(),:].astype(np.uint8) - data_block_upper = outarr[:,black_cols[0].max()+1:,:].astype(np.uint8) + data_block_lower = outarr[:, :black_cols[0].min(), :].astype(np.uint8) + data_block_upper = outarr[:, black_cols[0].max()+1:, :].astype(np.uint8) data_block_lower = xor_block(data_block_lower) data_block_upper = xor_block(data_block_upper) - + data_block = (data_block_upper << 4) | (data_block_lower) data_block = data_block.flatten().tobytes() data = zlib.decompress(data_block) - return json.loads(data,cls=EmbeddingDecoder) + return json.loads(data, cls=EmbeddingDecoder) -def caption_image_overlay(srcimage,title,footerLeft,footerMid,footerRight,textfont=None): + +def caption_image_overlay(srcimage, title, footerLeft, footerMid, footerRight, textfont=None): from math import cos image = srcimage.copy() @@ -130,11 +142,11 @@ def caption_image_overlay(srcimage,title,footerLeft,footerMid,footerRight,textfo textfont = Roboto factor = 1.5 - gradient = Image.new('RGBA', (1,image.size[1]), color=(0,0,0,0)) + gradient = Image.new('RGBA', (1, image.size[1]), color=(0, 0, 0, 0)) for y in range(image.size[1]): mag = 1-cos(y/image.size[1]*factor) - mag = max(mag,1-cos((image.size[1]-y)/image.size[1]*factor*1.1)) - gradient.putpixel((0, y), (0,0,0,int(mag*255))) + mag = max(mag, 1-cos((image.size[1]-y)/image.size[1]*factor*1.1)) + gradient.putpixel((0, y), (0, 0, 0, int(mag*255))) image = Image.alpha_composite(image.convert('RGBA'), gradient.resize(image.size)) draw = ImageDraw.Draw(image) @@ -142,41 +154,41 @@ def caption_image_overlay(srcimage,title,footerLeft,footerMid,footerRight,textfo font = ImageFont.truetype(textfont, fontsize) padding = 10 - _,_,w, h = draw.textbbox((0,0),title,font=font) - fontsize = min( int(fontsize * (((image.size[0]*0.75)-(padding*4))/w) ), 72) + _, _, w, h = draw.textbbox((0, 0), title, font=font) + fontsize = min(int(fontsize * (((image.size[0]*0.75)-(padding*4))/w)), 72) font = ImageFont.truetype(textfont, fontsize) - _,_,w,h = draw.textbbox((0,0),title,font=font) - draw.text((padding,padding), title, anchor='lt', font=font, fill=(255,255,255,230)) + _, _, w, h = draw.textbbox((0, 0), title, font=font) + draw.text((padding, padding), title, anchor='lt', font=font, fill=(255, 255, 255, 230)) - _,_,w, h = draw.textbbox((0,0),footerLeft,font=font) - fontsize_left = min( int(fontsize * (((image.size[0]/3)-(padding))/w) ), 72) - _,_,w, h = draw.textbbox((0,0),footerMid,font=font) - fontsize_mid = min( int(fontsize * (((image.size[0]/3)-(padding))/w) ), 72) - _,_,w, h = draw.textbbox((0,0),footerRight,font=font) - fontsize_right = min( int(fontsize * (((image.size[0]/3)-(padding))/w) ), 72) + _, _, w, h = draw.textbbox((0, 0), footerLeft, font=font) + fontsize_left = min(int(fontsize * (((image.size[0]/3)-(padding))/w)), 72) + _, _, w, h = draw.textbbox((0, 0), footerMid, font=font) + fontsize_mid = min(int(fontsize * (((image.size[0]/3)-(padding))/w)), 72) + _, _, w, h = draw.textbbox((0, 0), footerRight, font=font) + fontsize_right = min(int(fontsize * (((image.size[0]/3)-(padding))/w)), 72) - font = ImageFont.truetype(textfont, min(fontsize_left,fontsize_mid,fontsize_right)) + font = ImageFont.truetype(textfont, min(fontsize_left, fontsize_mid, fontsize_right)) - draw.text((padding,image.size[1]-padding), footerLeft, anchor='ls', font=font, fill=(255,255,255,230)) - draw.text((image.size[0]/2,image.size[1]-padding), footerMid, anchor='ms', font=font, fill=(255,255,255,230)) - draw.text((image.size[0]-padding,image.size[1]-padding), footerRight, anchor='rs', font=font, fill=(255,255,255,230)) + draw.text((padding, image.size[1]-padding), footerLeft, anchor='ls', font=font, fill=(255, 255, 255, 230)) + draw.text((image.size[0]/2, image.size[1]-padding), footerMid, anchor='ms', font=font, fill=(255, 255, 255, 230)) + draw.text((image.size[0]-padding, image.size[1]-padding), footerRight, anchor='rs', font=font, fill=(255, 255, 255, 230)) return image + if __name__ == '__main__': testEmbed = Image.open('test_embedding.png') - data = extract_image_data_embed(testEmbed) assert data is not None data = embedding_from_b64(testEmbed.text['sd-ti-embedding']) assert data is not None - - image = Image.new('RGBA',(512,512),(255,255,200,255)) + + image = Image.new('RGBA', (512, 512), (255, 255, 200, 255)) cap_image = caption_image_overlay(image, 'title', 'footerLeft', 'footerMid', 'footerRight') - test_embed = {'string_to_param':{'*':torch.from_numpy(np.random.random((2, 4096)))}} + test_embed = {'string_to_param': {'*': torch.from_numpy(np.random.random((2, 4096)))}} embedded_image = insert_image_data_embed(cap_image, test_embed) @@ -191,16 +203,16 @@ if __name__ == '__main__': g = lcg() shared_random = np.array([next(g) for _ in range(100)]).astype(np.uint8).tolist() - reference_random = [253, 242, 127, 44, 157, 27, 239, 133, 38, 79, 167, 4, 177, - 95, 130, 79, 78, 14, 52, 215, 220, 194, 126, 28, 240, 179, - 160, 153, 149, 50, 105, 14, 21, 218, 199, 18, 54, 198, 193, - 38, 128, 19, 53, 195, 124, 75, 205, 12, 6, 145, 0, 28, - 30, 148, 8, 45, 218, 171, 55, 249, 97, 166, 12, 35, 0, - 41, 221, 122, 215, 170, 31, 113, 186, 97, 119, 31, 23, 185, - 66, 140, 30, 41, 37, 63, 137, 109, 216, 55, 159, 145, 82, + reference_random = [253, 242, 127, 44, 157, 27, 239, 133, 38, 79, 167, 4, 177, + 95, 130, 79, 78, 14, 52, 215, 220, 194, 126, 28, 240, 179, + 160, 153, 149, 50, 105, 14, 21, 218, 199, 18, 54, 198, 193, + 38, 128, 19, 53, 195, 124, 75, 205, 12, 6, 145, 0, 28, + 30, 148, 8, 45, 218, 171, 55, 249, 97, 166, 12, 35, 0, + 41, 221, 122, 215, 170, 31, 113, 186, 97, 119, 31, 23, 185, + 66, 140, 30, 41, 37, 63, 137, 109, 216, 55, 159, 145, 82, 204, 86, 73, 222, 44, 198, 118, 240, 97] - assert shared_random == reference_random + assert shared_random == reference_random hunna_kay_random_sum = sum(np.array([next(g) for _ in range(100000)]).astype(np.uint8).tolist()) From 10a2de644f8ea4cfade88e85d768da3480f4c9f0 Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Wed, 12 Oct 2022 13:15:35 +0100 Subject: [PATCH 376/460] formatting --- .../textual_inversion/textual_inversion.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 485ef46cf..b072d7455 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -7,14 +7,14 @@ import tqdm import html import datetime -from PIL import Image,PngImagePlugin +from PIL import Image, PngImagePlugin from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset -from modules.textual_inversion.image_embedding import (embedding_to_b64,embedding_from_b64, - insert_image_data_embed,extract_image_data_embed, - caption_image_overlay ) +from modules.textual_inversion.image_embedding import (embedding_to_b64, embedding_from_b64, + insert_image_data_embed, extract_image_data_embed, + caption_image_overlay) class Embedding: def __init__(self, vec, name, step=None): @@ -90,10 +90,10 @@ class EmbeddingDatabase: embed_image = Image.open(path) if 'sd-ti-embedding' in embed_image.text: data = embedding_from_b64(embed_image.text['sd-ti-embedding']) - name = data.get('name',name) + name = data.get('name', name) else: data = extract_image_data_embed(embed_image) - name = data.get('name',name) + name = data.get('name', name) else: data = torch.load(path, map_location="cpu") @@ -278,24 +278,24 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.current_image = image if save_image_with_stored_embedding and os.path.exists(last_saved_file): - + last_saved_image_chunks = os.path.join(images_embeds_dir, f'{embedding_name}-{embedding.step}.png') info = PngImagePlugin.PngInfo() data = torch.load(last_saved_file) info.add_text("sd-ti-embedding", embedding_to_b64(data)) - title = "<{}>".format(data.get('name','???')) + title = "<{}>".format(data.get('name', '???')) checkpoint = sd_models.select_checkpoint() footer_left = checkpoint.model_name footer_mid = '[{}]'.format(checkpoint.hash) footer_right = '{}'.format(embedding.step) - captioned_image = caption_image_overlay(image,title,footer_left,footer_mid,footer_right) - captioned_image = insert_image_data_embed(captioned_image,data) + captioned_image = caption_image_overlay(image, title, footer_left, footer_mid, footer_right) + captioned_image = insert_image_data_embed(captioned_image, data) captioned_image.save(last_saved_image_chunks, "PNG", pnginfo=info) - + image.save(last_saved_image) last_saved_image += f", prompt: {preview_text}" From e05573e1adc1cde1e3bd7eb651a1ab27c446b3d5 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Wed, 12 Oct 2022 20:47:55 +0800 Subject: [PATCH 377/460] images history improvement --- .gitignore | 1 + javascript/images_history.js | 224 +++++++++++++++++++++++------------ modules/images_history.py | 67 +++++++---- 3 files changed, 191 insertions(+), 101 deletions(-) diff --git a/.gitignore b/.gitignore index 7afc93953..434e23ce1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ __pycache__ notification.mp3 /SwinIR /textual_inversion +/images_history_testui.py diff --git a/javascript/images_history.js b/javascript/images_history.js index d62eb1814..c9a631664 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -1,122 +1,192 @@ -images_history_tab_list = ["txt2img", "img2img", "extras"] -function images_history_init(){ - if (gradioApp().getElementById('txt2img_images_history_first_page') == null) { - setTimeout(images_history_init, 500) - } else { - for (i in images_history_tab_list ){ - tab = images_history_tab_list[i] - gradioApp().getElementById(tab + '_images_history').classList.add("images_history_gallery") - gradioApp().getElementById(tab + '_images_history_set_index').classList.add("images_history_set_index") - - } - gradioApp().getElementById("txt2img_images_history_first_page").click() - } -} -setTimeout(images_history_init, 500) -var images_history_button_actions = function(){ +var images_history_click_image = function(){ if (!this.classList.contains("transform")){ - gallery = this.parentElement - while(!gallery.classList.contains("images_history_gallery")){gallery = gallery.parentElement} - buttons = gallery.querySelectorAll(".gallery-item") - i = 0 - hidden_list = [] + var gallery = images_history_get_parent_by_class(this, "images_history_cantainor"); + var buttons = gallery.querySelectorAll(".gallery-item"); + var i = 0; + var hidden_list = []; buttons.forEach(function(e){ if (e.style.display == "none"){ - hidden_list.push(i) + hidden_list.push(i); } - i += 1 + i += 1; }) if (hidden_list.length > 0){ - setTimeout(images_history_hide_buttons, 10, hidden_list, gallery) - } - + setTimeout(images_history_hide_buttons, 10, hidden_list, gallery); + } } - images_history_set_image_info(this) - + images_history_set_image_info(this); } -onUiUpdate(function(){ - for (i in images_history_tab_list ){ - tab = images_history_tab_list[i] - buttons = gradioApp().querySelectorAll('#' + tab + '_images_history .gallery-item') - buttons.forEach(function(bnt){ - bnt.addEventListener('click', images_history_button_actions, true) - }); + +var images_history_click_tab = function(){ + var tabs_box = gradioApp().getElementById("images_history_tab"); + if (!tabs_box.classList.contains(this.getAttribute("tabname"))) { + gradioApp().getElementById(this.getAttribute("tabname") + "_images_history_renew_page").click(); + tabs_box.classList.add(this.getAttribute("tabname")) + } +} + +var images_history_close_full_view = function(){ + var box = images_history_get_parent_by_class(this, "images_history_cantainor"); + box.querySelector(".images_history_del_button").setAttribute("disabled", "disabled"); +} + +function images_history_get_parent_by_class(item, class_name){ + var parent = item.parentElement; + while(!parent.classList.contains(class_name)){ + parent = parent.parentElement; } -}) + return parent; +} + +function images_history_get_parent_by_tagname(item, tagname){ + var parent = item.parentElement; + tagname = tagname.toUpperCase() + while(parent.tagName != tagname){ + console.log(parent.tagName, tagname) + parent = parent.parentElement; + } + return parent; +} function images_history_hide_buttons(hidden_list, gallery){ - buttons = gallery.querySelectorAll(".gallery-item") - num = 0 + var buttons = gallery.querySelectorAll(".gallery-item"); + var num = 0; buttons.forEach(function(e){ if (e.style.display == "none"){ - num += 1 + num += 1; } }) if (num == hidden_list.length){ - setTimeout(images_history_hide_buttons, 10, hidden_list, gallery) + setTimeout(images_history_hide_buttons, 10, hidden_list, gallery); } for( i in hidden_list){ - buttons[hidden_list[i]].style.display = "none" + buttons[hidden_list[i]].style.display = "none"; } } function images_history_set_image_info(button){ - item = button.parentElement - while(item.tagName != "DIV"){item = item.parentElement} - buttons = item.querySelectorAll(".gallery-item") - index = -1 - i = 0 + var buttons = images_history_get_parent_by_tagname(button, "DIV").querySelectorAll(".gallery-item"); + var index = -1; + var i = 0; buttons.forEach(function(e){ - if(e==button){index = i} + if(e == button){ + index = i; + } if(e.style.display != "none"){ - i += 1 + i += 1; } }) - gallery = button.parentElement - while(!gallery.classList.contains("images_history_gallery")){gallery = gallery.parentElement} - set_btn = gallery.querySelector(".images_history_set_index") - set_btn.setAttribute("img_index", index) - set_btn.click() + var gallery = images_history_get_parent_by_class(button, "images_history_cantainor"); + var set_btn = gallery.querySelector(".images_history_set_index"); + set_btn.setAttribute("img_index", index); + set_btn.click(); + gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){ + btn.setAttribute('disabled','disabled'); + }) + } function images_history_get_current_img(tabname, image_path, files){ - s = gradioApp().getElementById(tabname + '_images_history_set_index').getAttribute("img_index") - return [s, image_path, files] + return [ + gradioApp().getElementById(tabname + '_images_history_set_index').getAttribute("img_index"), + image_path, + files + ]; } function images_history_delete(tabname, img_path, img_file_name, page_index, filenames, image_index){ - image_index = parseInt(image_index) - tab = gradioApp().getElementById(tabname + '_images_history') - set_btn = tab.querySelector(".images_history_set_index") - buttons = [] + image_index = parseInt(image_index); + var tab = gradioApp().getElementById(tabname + '_images_history'); + var set_btn = tab.querySelector(".images_history_set_index"); + var buttons = []; tab.querySelectorAll(".gallery-item").forEach(function(e){ if (e.style.display != 'none'){ - buttons.push(e) + buttons.push(e); } - }) + }); - img_num = buttons.length / 2 - if (img_num == 1){ - setTimeout(function(tabname){ - gradioApp().getElementById(tabname + '_images_history_renew_page').click() - }, 30, tabname) + var img_num = buttons.length / 2; + if (img_num === 1){ + setTimeout(function(tabname){ + gradioApp().getElementById(tabname + '_images_history_renew_page').click(); + }, 30, tabname); } else { - buttons[image_index].style.display = 'none' - buttons[image_index + img_num].style.display = 'none' - if (image_index >= img_num - 1){ - console.log(buttons.length, img_num) - btn = buttons[img_num - 2] + buttons[image_index].style.display = 'none'; + buttons[image_index + img_num].style.display = 'none'; + var bnt; + if (image_index >= img_num - 1){ + btn = buttons[img_num - 2]; } else { - btn = buttons[image_index + 1] + btn = buttons[image_index + 1] ; } - setTimeout(function(btn){btn.click()}, 30, btn) + setTimeout(function(btn){btn.click()}, 30, btn); } - return [tabname, img_path, img_file_name, page_index, filenames, image_index] + return [tabname, img_path, img_file_name, page_index, filenames, image_index]; } function images_history_turnpage(img_path, page_index, image_index, tabname){ - buttons = gradioApp().getElementById(tabname + '_images_history').querySelectorAll(".gallery-item") + var buttons = gradioApp().getElementById(tabname + '_images_history').querySelectorAll(".gallery-item"); buttons.forEach(function(elem) { - elem.style.display = 'block' + elem.style.display = 'block'; }) - return [img_path, page_index, image_index, tabname] + return [img_path, page_index, image_index, tabname]; } + +function images_history_enable_del_buttons(){ + gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){ + btn.removeAttribute('disabled'); + }) +} + +function images_history_init(){ + if (gradioApp().getElementById('txt2img_images_history_renew_page') == null) { + setTimeout(images_history_init, 500); + } else { + for (var i in images_history_tab_list ){ + tab = images_history_tab_list[i]; + gradioApp().getElementById(tab + '_images_history').classList.add("images_history_cantainor"); + gradioApp().getElementById(tab + '_images_history_set_index').classList.add("images_history_set_index"); + gradioApp().getElementById(tab + '_images_history_del_button').classList.add("images_history_del_button"); + gradioApp().getElementById(tab + '_images_history_gallery').classList.add("images_history_gallery"); + + + } + var tabs_box = gradioApp().getElementById("tab_images_history").querySelector("div").querySelector("div").querySelector("div"); + tabs_box.setAttribute("id", "images_history_tab"); + tabs_box.classList.add(images_history_tab_list[0]); + gradioApp().getElementById("txt2img_images_history_renew_page").click(); + } +} + +var images_history_tab_list = ["txt2img", "img2img", "extras"]; +var images_history_start_flag = false; + +onUiUpdate(function(){ + var tab = gradioApp().getElementById("images_history_tab"); + if (tab) { + if (!images_history_start_flag){ + images_history_init(); + images_history_start_flag = true; + } + var tab_btns = gradioApp().getElementById("images_history_tab").querySelectorAll("button"); + for (var i in images_history_tab_list ){ + var buttons = gradioApp().querySelectorAll('#' + images_history_tab_list[i] + '_images_history .gallery-item'); + buttons.forEach(function(bnt){ + bnt.addEventListener('click', images_history_click_image, true); + }); + var tabname = images_history_tab_list[i] + tab_btns[i].setAttribute("tabname", tabname); + tab_btns[i].addEventListener('click', images_history_click_tab, true); + // var cls_btn = gradioApp().getElementById(tabname + '_images_history_gallery').querySelector("svg"); + // if (cls_btn){ + // cls_btn.addEventListener('click', images_history_close_full_view, false); + // } + // console.log(cls_btn, cls_btn.parentElement.parentElement) + // if (cls_btn) { + // cls_btn = images_history_get_parent_by_tagname(cls_btn, "BUTTON"); + // cls_btn.addEventListener('click', images_history_close_full_view, true); + // } + } + + } +}); + diff --git a/modules/images_history.py b/modules/images_history.py index 23f55b302..77f692fe5 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -1,15 +1,29 @@ import os -def get_recent_images(dir_name, page_index, step, image_index): - #print(image_index) +import shutil +def get_recent_images(dir_name, page_index, step, image_index, tabname): + print(f"renew page {page_index}") page_index = int(page_index) f_list = os.listdir(dir_name) file_list = [] for file in f_list: if file[-4:] == ".txt": continue - file_list.append(file) + #subdirectories + if file[-10:].rfind(".") < 0: + sub_dir = os.path.join(dir_name, file) + if os.path.isfile(sub_dir): + continue + sub_file_list = os.listdir(sub_dir) + for sub_file in sub_file_list: + if sub_file[-4:] == ".txt": + continue + if os.path.isfile(os.path.join(sub_dir, sub_file) ): + file_list.append(os.path.join(file, sub_file)) + continue + file_list.append(file) + file_list = sorted(file_list, key=lambda file: -os.path.getctime(os.path.join(dir_name, file))) - num = 48 + num = 48 if tabname != "extras" else 12 max_page_index = len(file_list) // num + 1 page_index = max_page_index if page_index == -1 else page_index + step page_index = 1 if page_index < 1 else page_index @@ -26,26 +40,28 @@ def get_recent_images(dir_name, page_index, step, image_index): hide_image = os.path.join(dir_name, current_file) return [os.path.join(dir_name, file) for file in file_list], page_index, file_list, current_file, hide_image def first_page_click(dir_name, page_index, image_index, tabname): - return get_recent_images(dir_name, 1, 0, image_index) + return get_recent_images(dir_name, 1, 0, image_index, tabname) def end_page_click(dir_name, page_index, image_index, tabname): - return get_recent_images(dir_name, -1, 0, image_index) + return get_recent_images(dir_name, -1, 0, image_index, tabname) def prev_page_click(dir_name, page_index, image_index, tabname): - return get_recent_images(dir_name, page_index, -1, image_index) + return get_recent_images(dir_name, page_index, -1, image_index, tabname) def next_page_click(dir_name, page_index, image_index, tabname): - return get_recent_images(dir_name, page_index, 1, image_index) + return get_recent_images(dir_name, page_index, 1, image_index, tabname) def page_index_change(dir_name, page_index, image_index, tabname): - return get_recent_images(dir_name, page_index, 0, image_index) + return get_recent_images(dir_name, page_index, 0, image_index, tabname) def show_image_info(num, image_path, filenames): - #print("set img",num) + print(f"select image {num}") file = filenames[int(num)] return file, num, os.path.join(image_path, file) def delete_image(tabname, dir_name, name, page_index, filenames, image_index): - #print("filename", name) path = os.path.join(dir_name, name) - if os.path.exists(path): + if os.path.exists(path): print(f"Delete file {path}") - os.remove(path) + os.remove(path) + txt_file = os.path.splitext(path)[0] + ".txt" + if os.path.exists(txt_file): + os.remove(txt_file) new_file_list = [] for f in filenames: if f == name: @@ -64,25 +80,26 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): elif tabname == "extras": dir_name = opts.outdir_extras_samples with gr.Row(): - renew_page = gr.Button('Renew', elem_id=tabname + "_images_history_renew_page") - first_page = gr.Button('First', elem_id=tabname + "_images_history_first_page") - prev_page = gr.Button('Prev') + renew_page = gr.Button('Renew Page', elem_id=tabname + "_images_history_renew_page") + first_page = gr.Button('First Page') + prev_page = gr.Button('Prev Page') page_index = gr.Number(value=1, label="Page Index") - next_page = gr.Button('Next', elem_id=tabname + "_images_history_next_page") - end_page = gr.Button('End') + next_page = gr.Button('Next Page') + end_page = gr.Button('End Page') with gr.Row(elem_id=tabname + "_images_history"): with gr.Row(): - with gr.Column(): - history_gallery = gr.Gallery(show_label=False).style(grid=6) + with gr.Column(scale=2): + history_gallery = gr.Gallery(show_label=False, elem_id=tabname + "_images_history_gallery").style(grid=6) + delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") with gr.Column(): with gr.Row(): - delete = gr.Button('Delete') + #pnginfo = gr.Button('PNG info') pnginfo_send_to_txt2img = gr.Button('Send to txt2img') pnginfo_send_to_img2img = gr.Button('Send to img2img') with gr.Row(): with gr.Column(): - img_file_info = gr.Textbox(label="Generate Info") - img_file_name = gr.Textbox(label="File Name") + img_file_info = gr.Textbox(label="Generate Info", interactive=False) + img_file_name = gr.Textbox(label="File Name", interactive=False) with gr.Row(): # hiden items img_path = gr.Textbox(dir_name, visible=False) @@ -90,7 +107,7 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): image_index = gr.Textbox(value=-1, visible=False) set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False) filenames = gr.State() - hide_image = gr.Image(visible=False, type="pil") + hide_image = gr.Image(type="pil", visible=False) info1 = gr.Textbox(visible=False) info2 = gr.Textbox(visible=False) @@ -111,6 +128,8 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) delete.click(delete_image,_js="images_history_delete", inputs=[tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[page_index, filenames]) hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) + hide_image.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) + #pnginfo.click(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') From a1a94b8b5f342f467aecc53b21b80ed0227ee76a Mon Sep 17 00:00:00 2001 From: yfszzx Date: Thu, 13 Oct 2022 00:19:34 +0800 Subject: [PATCH 378/460] images history improvement --- javascript/images_history.js | 125 ++++++++++++++++++----------------- modules/images_history.py | 7 +- modules/ui.py | 40 ++++++----- 3 files changed, 88 insertions(+), 84 deletions(-) diff --git a/javascript/images_history.js b/javascript/images_history.js index c9a631664..620f242c3 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -18,20 +18,26 @@ var images_history_click_image = function(){ } var images_history_click_tab = function(){ - var tabs_box = gradioApp().getElementById("images_history_tab"); - if (!tabs_box.classList.contains(this.getAttribute("tabname"))) { - gradioApp().getElementById(this.getAttribute("tabname") + "_images_history_renew_page").click(); - tabs_box.classList.add(this.getAttribute("tabname")) - } + var tabs_box = gradioApp().getElementById("images_history_tab"); + if (!tabs_box.classList.contains(this.getAttribute("tabname"))) { + gradioApp().getElementById(this.getAttribute("tabname") + "_images_history_renew_page").click(); + tabs_box.classList.add(this.getAttribute("tabname")) + } } var images_history_close_full_view = function(){ - var box = images_history_get_parent_by_class(this, "images_history_cantainor"); - box.querySelector(".images_history_del_button").setAttribute("disabled", "disabled"); + var box = images_history_get_parent_by_class(this, "images_history_cantainor"); + box.querySelector(".images_history_del_button").setAttribute("disabled", "disabled"); +} + +function images_history_disabled_del(){ + gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){ + btn.setAttribute('disabled','disabled'); + }); } function images_history_get_parent_by_class(item, class_name){ - var parent = item.parentElement; + var parent = item.parentElement; while(!parent.classList.contains(class_name)){ parent = parent.parentElement; } @@ -39,14 +45,15 @@ function images_history_get_parent_by_class(item, class_name){ } function images_history_get_parent_by_tagname(item, tagname){ - var parent = item.parentElement; - tagname = tagname.toUpperCase() + var parent = item.parentElement; + tagname = tagname.toUpperCase() while(parent.tagName != tagname){ - console.log(parent.tagName, tagname) + console.log(parent.tagName, tagname) parent = parent.parentElement; } return parent; } + function images_history_hide_buttons(hidden_list, gallery){ var buttons = gallery.querySelectorAll(".gallery-item"); var num = 0; @@ -54,7 +61,7 @@ function images_history_hide_buttons(hidden_list, gallery){ if (e.style.display == "none"){ num += 1; } - }) + }); if (num == hidden_list.length){ setTimeout(images_history_hide_buttons, 10, hidden_list, gallery); } @@ -74,14 +81,15 @@ function images_history_set_image_info(button){ if(e.style.display != "none"){ i += 1; } - }) + }); var gallery = images_history_get_parent_by_class(button, "images_history_cantainor"); var set_btn = gallery.querySelector(".images_history_set_index"); - set_btn.setAttribute("img_index", index); + var curr_idx = set_btn.getAttribute("img_index", index); + if (curr_idx != index) { + set_btn.setAttribute("img_index", index); + images_history_disabled_del(); + } set_btn.click(); - gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){ - btn.setAttribute('disabled','disabled'); - }) } @@ -102,24 +110,24 @@ function images_history_delete(tabname, img_path, img_file_name, page_index, fil if (e.style.display != 'none'){ buttons.push(e); } - }); - + }); var img_num = buttons.length / 2; if (img_num === 1){ setTimeout(function(tabname){ gradioApp().getElementById(tabname + '_images_history_renew_page').click(); }, 30, tabname); - } else { + } else { buttons[image_index].style.display = 'none'; buttons[image_index + img_num].style.display = 'none'; var bnt; if (image_index >= img_num - 1){ btn = buttons[img_num - 2]; - } else { + } else { btn = buttons[image_index + 1] ; - } + } setTimeout(function(btn){btn.click()}, 30, btn); - } + } + images_history_disabled_del(); return [tabname, img_path, img_file_name, page_index, filenames, image_index]; } @@ -132,61 +140,58 @@ function images_history_turnpage(img_path, page_index, image_index, tabname){ } function images_history_enable_del_buttons(){ - gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){ - btn.removeAttribute('disabled'); + gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){ + btn.removeAttribute('disabled'); }) } function images_history_init(){ - if (gradioApp().getElementById('txt2img_images_history_renew_page') == null) { - setTimeout(images_history_init, 500); - } else { + var load_txt2img_button = gradioApp().getElementById('txt2img_images_history_renew_page') + if (load_txt2img_button){ for (var i in images_history_tab_list ){ tab = images_history_tab_list[i]; gradioApp().getElementById(tab + '_images_history').classList.add("images_history_cantainor"); gradioApp().getElementById(tab + '_images_history_set_index').classList.add("images_history_set_index"); gradioApp().getElementById(tab + '_images_history_del_button').classList.add("images_history_del_button"); - gradioApp().getElementById(tab + '_images_history_gallery').classList.add("images_history_gallery"); - - + gradioApp().getElementById(tab + '_images_history_gallery').classList.add("images_history_gallery"); + } var tabs_box = gradioApp().getElementById("tab_images_history").querySelector("div").querySelector("div").querySelector("div"); - tabs_box.setAttribute("id", "images_history_tab"); - tabs_box.classList.add(images_history_tab_list[0]); - gradioApp().getElementById("txt2img_images_history_renew_page").click(); - } + tabs_box.setAttribute("id", "images_history_tab"); + var tab_btns = tabs_box.querySelectorAll("button"); + for (var i in images_history_tab_list){ + var tabname = images_history_tab_list[i] + tab_btns[i].setAttribute("tabname", tabname); + tab_btns[i].addEventListener('click', images_history_click_tab); + } + tabs_box.classList.add(images_history_tab_list[0]); + load_txt2img_button.click(); + } else { + setTimeout(images_history_init, 500); + } } var images_history_tab_list = ["txt2img", "img2img", "extras"]; -var images_history_start_flag = false; - -onUiUpdate(function(){ - var tab = gradioApp().getElementById("images_history_tab"); - if (tab) { - if (!images_history_start_flag){ - images_history_init(); - images_history_start_flag = true; - } - var tab_btns = gradioApp().getElementById("images_history_tab").querySelectorAll("button"); - for (var i in images_history_tab_list ){ - var buttons = gradioApp().querySelectorAll('#' + images_history_tab_list[i] + '_images_history .gallery-item'); - buttons.forEach(function(bnt){ - bnt.addEventListener('click', images_history_click_image, true); - }); - var tabname = images_history_tab_list[i] - tab_btns[i].setAttribute("tabname", tabname); - tab_btns[i].addEventListener('click', images_history_click_tab, true); +setTimeout(images_history_init, 500) +document.addEventListener("DOMContentLoaded", function() { + var mutationObserver = new MutationObserver(function(m){ + for (var i in images_history_tab_list ){ + var buttons = gradioApp().querySelectorAll('#' + images_history_tab_list[i] + '_images_history .gallery-item'); + buttons.forEach(function(bnt){ + bnt.addEventListener('click', images_history_click_image, true); + }); // var cls_btn = gradioApp().getElementById(tabname + '_images_history_gallery').querySelector("svg"); // if (cls_btn){ - // cls_btn.addEventListener('click', images_history_close_full_view, false); + // cls_btn.addEventListener('click', images_history_close_full_view, false); // } // console.log(cls_btn, cls_btn.parentElement.parentElement) // if (cls_btn) { - // cls_btn = images_history_get_parent_by_tagname(cls_btn, "BUTTON"); - // cls_btn.addEventListener('click', images_history_close_full_view, true); - // } - } + // cls_btn = images_history_get_parent_by_tagname(cls_btn, "BUTTON"); + // cls_btn.addEventListener('click', images_history_close_full_view, true); + } + }); + mutationObserver.observe( gradioApp(), { childList:true, subtree:true }); + +}); - } -}); diff --git a/modules/images_history.py b/modules/images_history.py index 2bc4b7eee..1bca0ad92 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -61,7 +61,7 @@ def delete_image(tabname, dir_name, name, page_index, filenames, image_index): os.remove(path) txt_file = os.path.splitext(path)[0] + ".txt" if os.path.exists(txt_file): - os.remove(txt_file) + os.remove(txt_file) new_file_list = [] for f in filenames: if f == name: @@ -88,7 +88,7 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): end_page = gr.Button('End Page') with gr.Row(elem_id=tabname + "_images_history"): with gr.Row(): - with gr.Column(scale=2): + with gr.Column(scale=2): history_gallery = gr.Gallery(show_label=False, elem_id=tabname + "_images_history_gallery").style(grid=6) delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") with gr.Column(): @@ -126,9 +126,10 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): #other funcitons set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) + img_file_name.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) delete.click(delete_image,_js="images_history_delete", inputs=[tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[page_index, filenames]) hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) - hide_image.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) + #pnginfo.click(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') diff --git a/modules/ui.py b/modules/ui.py index 94297ba65..8cd12b518 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -39,7 +39,7 @@ import modules.generation_parameters_copypaste from modules import prompt_parser from modules.images import save_image import modules.textual_inversion.ui -import modules.hypernetwork.ui +import modules.hypernetworks.ui import modules.images_history as img_his # this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI @@ -554,6 +554,7 @@ def create_ui(wrap_gradio_gpu_call): custom_inputs = modules.scripts.scripts_txt2img.setup_ui(is_img2img=False) with gr.Column(variant='panel'): + with gr.Group(): txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False) txt2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='txt2img_gallery').style(grid=4) @@ -573,9 +574,9 @@ def create_ui(wrap_gradio_gpu_call): with gr.Row(): download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) - with gr.Group(): - html_info = gr.HTML() - generation_info = gr.Textbox(visible=False) + with gr.Group(): + html_info = gr.HTML() + generation_info = gr.Textbox(visible=False) connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) @@ -669,7 +670,6 @@ def create_ui(wrap_gradio_gpu_call): ] modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt) token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) - with gr.Blocks(analytics_enabled=False) as img2img_interface: img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) @@ -762,10 +762,10 @@ def create_ui(wrap_gradio_gpu_call): with gr.Row(): download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False) - with gr.Group(): - html_info = gr.HTML() - generation_info = gr.Textbox(visible=False) - + with gr.Group(): + html_info = gr.HTML() + generation_info = gr.Textbox(visible=False) + connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) @@ -1016,6 +1016,13 @@ def create_ui(wrap_gradio_gpu_call): inputs=[image], outputs=[html, generation_info, html2], ) + #images history + images_history_switch_dict = { + "fn":modules.generation_parameters_copypaste.connect_paste, + "t2i":txt2img_paste_fields, + "i2i":img2img_paste_fields + } + images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict) with gr.Blocks() as modelmerger_interface: with gr.Row().style(equal_height=False): @@ -1285,16 +1292,7 @@ Requested path was: {f} opts.save(shared.config_filename) - return f'{changed} settings changed.', opts.dumpjson() - - #images history - images_history_switch_dict = { - "fn":modules.generation_parameters_copypaste.connect_paste, - "t2i":txt2img_paste_fields, - "i2i":img2img_paste_fields - } - images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict) - + return f'{changed} settings changed.', opts.dumpjson() def run_settings_single(value, key): if not opts.same_type(value, opts.data_labels[key].default): @@ -1393,11 +1391,10 @@ Requested path was: {f} (img2img_interface, "img2img", "img2img"), (extras_interface, "Extras", "extras"), (pnginfo_interface, "PNG Info", "pnginfo"), - (modelmerger_interface, "Checkpoint Merger", "modelmerger"), (images_history, "History", "images_history"), + (modelmerger_interface, "Checkpoint Merger", "modelmerger"), (train_interface, "Train", "ti"), (settings_interface, "Settings", "settings"), - ] with open(os.path.join(script_path, "style.css"), "r", encoding="utf8") as file: @@ -1616,3 +1613,4 @@ if 'gradio_routes_templates_response' not in globals(): gradio_routes_templates_response = gradio.routes.templates.TemplateResponse gradio.routes.templates.TemplateResponse = template_response + From a2aa2a68bc7868320b502a78765be597e507ce45 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Thu, 13 Oct 2022 00:21:16 +0800 Subject: [PATCH 379/460] images history improvement --- modules/images_history.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/images_history.py b/modules/images_history.py index 1bca0ad92..6408973c6 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -1,7 +1,7 @@ import os import shutil def get_recent_images(dir_name, page_index, step, image_index, tabname): - print(f"renew page {page_index}") + #print(f"renew page {page_index}") page_index = int(page_index) f_list = os.listdir(dir_name) file_list = [] @@ -51,7 +51,7 @@ def page_index_change(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, page_index, 0, image_index, tabname) def show_image_info(num, image_path, filenames): - print(f"select image {num}") + #print(f"select image {num}") file = filenames[int(num)] return file, num, os.path.join(image_path, file) def delete_image(tabname, dir_name, name, page_index, filenames, image_index): From 717ba4c71c86cb2d49d731caeed82ce8bec0c057 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Thu, 13 Oct 2022 00:27:45 +0800 Subject: [PATCH 380/460] images history improvement --- javascript/images_history.js | 2 +- style.css | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/images_history.js b/javascript/images_history.js index 620f242c3..c5c2886ef 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -172,7 +172,7 @@ function images_history_init(){ } var images_history_tab_list = ["txt2img", "img2img", "extras"]; -setTimeout(images_history_init, 500) +setTimeout(images_history_init, 500); document.addEventListener("DOMContentLoaded", function() { var mutationObserver = new MutationObserver(function(m){ for (var i in images_history_tab_list ){ diff --git a/style.css b/style.css index 7704e7bd1..c75dce4c6 100644 --- a/style.css +++ b/style.css @@ -20,7 +20,7 @@ padding-right: 0.25em; margin: 0.1em 0; opacity: 0%; - cursor: default; + cursor: default; } .output-html p {margin: 0 0.5em;} @@ -442,7 +442,7 @@ input[type="range"]{ } .red { - color: red; + color: red; } .gallery-item { From c3c8eef9fd5a0c8b26319e32ca4a19b56204e6df Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 20:49:47 +0300 Subject: [PATCH 381/460] train: change filename processing to be more simple and configurable train: make it possible to make text files with prompts train: rework scheduler so that there's less repeating code in textual inversion and hypernets train: move epochs setting to options --- javascript/hints.js | 3 ++ modules/hypernetworks/hypernetwork.py | 40 ++++++--------- modules/shared.py | 3 ++ modules/textual_inversion/dataset.py | 49 +++++++++++++------ modules/textual_inversion/learn_schedule.py | 37 +++++++++++++- .../textual_inversion/textual_inversion.py | 35 +++++-------- modules/ui.py | 2 - 7 files changed, 106 insertions(+), 63 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index b81c181b9..d51ee14c1 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -81,6 +81,9 @@ titles = { "Eta noise seed delta": "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing.", "Do not add watermark to images": "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be behaving in an unethical manner.", + + "Filename word regex": "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is.", + "Filename join string": "This string will be used to hoin split words into a single line if the option above is enabled.", } diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 8314450ae..b6c06d49e 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -14,7 +14,7 @@ import torch from torch import einsum from einops import rearrange, repeat import modules.textual_inversion.dataset -from modules.textual_inversion.learn_schedule import LearnSchedule +from modules.textual_inversion.learn_schedule import LearnRateScheduler class HypernetworkModule(torch.nn.Module): @@ -223,31 +223,23 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, if ititial_step > steps: return hypernetwork, filename - schedules = iter(LearnSchedule(learn_rate, steps, ititial_step)) - (learn_rate, end_step) = next(schedules) - print(f'Training at rate of {learn_rate} until step {end_step}') - - optimizer = torch.optim.AdamW(weights, lr=learn_rate) + scheduler = LearnRateScheduler(learn_rate, steps, ititial_step) + optimizer = torch.optim.AdamW(weights, lr=scheduler.learn_rate) pbar = tqdm.tqdm(enumerate(ds), total=steps - ititial_step) - for i, (x, text, cond) in pbar: + for i, entry in pbar: hypernetwork.step = i + ititial_step - if hypernetwork.step > end_step: - try: - (learn_rate, end_step) = next(schedules) - except Exception: - break - tqdm.tqdm.write(f'Training at rate of {learn_rate} until step {end_step}') - for pg in optimizer.param_groups: - pg['lr'] = learn_rate + scheduler.apply(optimizer, hypernetwork.step) + if scheduler.finished: + break if shared.state.interrupted: break with torch.autocast("cuda"): - cond = cond.to(devices.device) - x = x.to(devices.device) + cond = entry.cond.to(devices.device) + x = entry.latent.to(devices.device) loss = shared.sd_model(x.unsqueeze(0), cond)[0] del x del cond @@ -267,7 +259,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, if hypernetwork.step > 0 and images_dir is not None and hypernetwork.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{hypernetwork_name}-{hypernetwork.step}.png') - preview_text = text if preview_image_prompt == "" else preview_image_prompt + preview_text = entry.cond_text if preview_image_prompt == "" else preview_image_prompt optimizer.zero_grad() shared.sd_model.cond_stage_model.to(devices.device) @@ -282,16 +274,16 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, ) processed = processing.process_images(p) - image = processed.images[0] + image = processed.images[0] if len(processed.images)>0 else None if unload: shared.sd_model.cond_stage_model.to(devices.cpu) shared.sd_model.first_stage_model.to(devices.cpu) - shared.state.current_image = image - image.save(last_saved_image) - - last_saved_image += f", prompt: {preview_text}" + if image is not None: + shared.state.current_image = image + image.save(last_saved_image) + last_saved_image += f", prompt: {preview_text}" shared.state.job_no = hypernetwork.step @@ -299,7 +291,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory,

    Loss: {losses.mean():.7f}
    Step: {hypernetwork.step}
    -Last prompt: {html.escape(text)}
    +Last prompt: {html.escape(entry.cond_text)}
    Last saved embedding: {html.escape(last_saved_file)}
    Last saved image: {html.escape(last_saved_image)}

    diff --git a/modules/shared.py b/modules/shared.py index 42e997416..e64e69fcb 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -231,6 +231,9 @@ options_templates.update(options_section(('system', "System"), { options_templates.update(options_section(('training', "Training"), { "unload_models_when_training": OptionInfo(False, "Unload VAE and CLIP from VRAM when training"), + "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), + "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), + "training_image_repeats_per_epoch": OptionInfo(100, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), })) options_templates.update(options_section(('sd', "Stable Diffusion"), { diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index f61f40d30..67e90afeb 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -11,11 +11,21 @@ import tqdm from modules import devices, shared import re -re_tag = re.compile(r"[a-zA-Z][_\w\d()]+") +re_numbers_at_start = re.compile(r"^[-\d]+\s*") + + +class DatasetEntry: + def __init__(self, filename=None, latent=None, filename_text=None): + self.filename = filename + self.latent = latent + self.filename_text = filename_text + self.cond = None + self.cond_text = None class PersonalizedBase(Dataset): def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None, include_cond=False): + re_word = re.compile(shared.opts.dataset_filename_word_regex) if len(shared.opts.dataset_filename_word_regex)>0 else None self.placeholder_token = placeholder_token @@ -42,9 +52,18 @@ class PersonalizedBase(Dataset): except Exception: continue + text_filename = os.path.splitext(path)[0] + ".txt" filename = os.path.basename(path) - filename_tokens = os.path.splitext(filename)[0] - filename_tokens = re_tag.findall(filename_tokens) + + if os.path.exists(text_filename): + with open(text_filename, "r", encoding="utf8") as file: + filename_text = file.read() + else: + filename_text = os.path.splitext(filename)[0] + filename_text = re.sub(re_numbers_at_start, '', filename_text) + if re_word: + tokens = re_word.findall(filename_text) + filename_text = (shared.opts.dataset_filename_join_string or "").join(tokens) npimage = np.array(image).astype(np.uint8) npimage = (npimage / 127.5 - 1.0).astype(np.float32) @@ -55,13 +74,13 @@ class PersonalizedBase(Dataset): init_latent = model.get_first_stage_encoding(model.encode_first_stage(torchdata.unsqueeze(dim=0))).squeeze() init_latent = init_latent.to(devices.cpu) - if include_cond: - text = self.create_text(filename_tokens) - cond = cond_model([text]).to(devices.cpu) - else: - cond = None + entry = DatasetEntry(filename=path, filename_text=filename_text, latent=init_latent) - self.dataset.append((init_latent, filename_tokens, cond)) + if include_cond: + entry.cond_text = self.create_text(filename_text) + entry.cond = cond_model([entry.cond_text]).to(devices.cpu) + + self.dataset.append(entry) self.length = len(self.dataset) * repeats @@ -72,10 +91,10 @@ class PersonalizedBase(Dataset): def shuffle(self): self.indexes = self.initial_indexes[torch.randperm(self.initial_indexes.shape[0])] - def create_text(self, filename_tokens): + def create_text(self, filename_text): text = random.choice(self.lines) text = text.replace("[name]", self.placeholder_token) - text = text.replace("[filewords]", ' '.join(filename_tokens)) + text = text.replace("[filewords]", filename_text) return text def __len__(self): @@ -86,7 +105,9 @@ class PersonalizedBase(Dataset): self.shuffle() index = self.indexes[i % len(self.indexes)] - x, filename_tokens, cond = self.dataset[index] + entry = self.dataset[index] - text = self.create_text(filename_tokens) - return x, text, cond + if entry.cond is None: + entry.cond_text = self.create_text(entry.filename_text) + + return entry diff --git a/modules/textual_inversion/learn_schedule.py b/modules/textual_inversion/learn_schedule.py index db7202712..2062726ad 100644 --- a/modules/textual_inversion/learn_schedule.py +++ b/modules/textual_inversion/learn_schedule.py @@ -1,6 +1,12 @@ +import tqdm -class LearnSchedule: + +class LearnScheduleIterator: def __init__(self, learn_rate, max_steps, cur_step=0): + """ + specify learn_rate as "0.001:100, 0.00001:1000, 1e-5:10000" to have lr of 0.001 until step 100, 0.00001 until 1000, 1e-5:10000 until 10000 + """ + pairs = learn_rate.split(',') self.rates = [] self.it = 0 @@ -32,3 +38,32 @@ class LearnSchedule: return self.rates[self.it - 1] else: raise StopIteration + + +class LearnRateScheduler: + def __init__(self, learn_rate, max_steps, cur_step=0, verbose=True): + self.schedules = LearnScheduleIterator(learn_rate, max_steps, cur_step) + (self.learn_rate, self.end_step) = next(self.schedules) + self.verbose = verbose + + if self.verbose: + print(f'Training at rate of {self.learn_rate} until step {self.end_step}') + + self.finished = False + + def apply(self, optimizer, step_number): + if step_number <= self.end_step: + return + + try: + (self.learn_rate, self.end_step) = next(self.schedules) + except Exception: + self.finished = True + return + + if self.verbose: + tqdm.tqdm.write(f'Training at rate of {self.learn_rate} until step {self.end_step}') + + for pg in optimizer.param_groups: + pg['lr'] = self.learn_rate + diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index c5153e4aa..fa0e33a2a 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -11,7 +11,7 @@ from PIL import Image, PngImagePlugin from modules import shared, devices, sd_hijack, processing, sd_models import modules.textual_inversion.dataset -from modules.textual_inversion.learn_schedule import LearnSchedule +from modules.textual_inversion.learn_schedule import LearnRateScheduler from modules.textual_inversion.image_embedding import (embedding_to_b64, embedding_from_b64, insert_image_data_embed, extract_image_data_embed, @@ -172,8 +172,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn - -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, num_repeats, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_image_prompt): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_image_prompt): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -205,7 +204,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=num_repeats, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) hijack = sd_hijack.model_hijack @@ -221,32 +220,24 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if ititial_step > steps: return embedding, filename - schedules = iter(LearnSchedule(learn_rate, steps, ititial_step)) - (learn_rate, end_step) = next(schedules) - print(f'Training at rate of {learn_rate} until step {end_step}') - - optimizer = torch.optim.AdamW([embedding.vec], lr=learn_rate) + scheduler = LearnRateScheduler(learn_rate, steps, ititial_step) + optimizer = torch.optim.AdamW([embedding.vec], lr=scheduler.learn_rate) pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) - for i, (x, text, _) in pbar: + for i, entry in pbar: embedding.step = i + ititial_step - if embedding.step > end_step: - try: - (learn_rate, end_step) = next(schedules) - except: - break - tqdm.tqdm.write(f'Training at rate of {learn_rate} until step {end_step}') - for pg in optimizer.param_groups: - pg['lr'] = learn_rate + scheduler.apply(optimizer, embedding.step) + if scheduler.finished: + break if shared.state.interrupted: break with torch.autocast("cuda"): - c = cond_model([text]) + c = cond_model([entry.cond_text]) - x = x.to(devices.device) + x = entry.latent.to(devices.device) loss = shared.sd_model(x.unsqueeze(0), c)[0] del x @@ -268,7 +259,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if embedding.step > 0 and images_dir is not None and embedding.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{embedding_name}-{embedding.step}.png') - preview_text = text if preview_image_prompt == "" else preview_image_prompt + preview_text = entry.cond_text if preview_image_prompt == "" else preview_image_prompt p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, @@ -314,7 +305,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini

    Loss: {losses.mean():.7f}
    Step: {embedding.step}
    -Last prompt: {html.escape(text)}
    +Last prompt: {html.escape(entry.cond_text)}
    Last saved embedding: {html.escape(last_saved_file)}
    Last saved image: {html.escape(last_saved_image)}

    diff --git a/modules/ui.py b/modules/ui.py index 2b332267f..c42535c84 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1098,7 +1098,6 @@ def create_ui(wrap_gradio_gpu_call): training_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512) training_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512) steps = gr.Number(label='Max steps', value=100000, precision=0) - num_repeats = gr.Number(label='Number of repeats for a single input image per epoch', value=100, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True) @@ -1176,7 +1175,6 @@ def create_ui(wrap_gradio_gpu_call): training_width, training_height, steps, - num_repeats, create_image_every, save_embedding_every, template_file, From 698d303b04e293635bfb49c525409f3bcf671dce Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Wed, 12 Oct 2022 21:55:43 +0300 Subject: [PATCH 382/460] deepbooru: added option to use spaces or underscores deepbooru: added option to quote (\) in tags deepbooru/BLIP: write caption to file instead of image filename deepbooru/BLIP: now possible to use both for captions deepbooru: process is stopped even if an exception occurs --- modules/deepbooru.py | 65 +++++++++++++---- modules/shared.py | 2 + modules/textual_inversion/preprocess.py | 94 +++++++++++-------------- modules/ui.py | 7 +- 4 files changed, 96 insertions(+), 72 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 295299490..419e6a9cd 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -2,33 +2,44 @@ import os.path from concurrent.futures import ProcessPoolExecutor import multiprocessing import time +import re + +re_special = re.compile(r'([\\()])') def get_deepbooru_tags(pil_image): """ This method is for running only one image at a time for simple use. Used to the img2img interrogate. """ from modules import shared # prevents circular reference - create_deepbooru_process(shared.opts.interrogate_deepbooru_score_threshold, shared.opts.deepbooru_sort_alpha) - shared.deepbooru_process_return["value"] = -1 - shared.deepbooru_process_queue.put(pil_image) - while shared.deepbooru_process_return["value"] == -1: - time.sleep(0.2) - tags = shared.deepbooru_process_return["value"] - release_process() - return tags + + try: + create_deepbooru_process(shared.opts.interrogate_deepbooru_score_threshold, create_deepbooru_opts()) + return get_tags_from_process(pil_image) + finally: + release_process() -def deepbooru_process(queue, deepbooru_process_return, threshold, alpha_sort): +def create_deepbooru_opts(): + from modules import shared + + return { + "use_spaces": shared.opts.deepbooru_use_spaces, + "use_escape": shared.opts.deepbooru_escape, + "alpha_sort": shared.opts.deepbooru_sort_alpha, + } + + +def deepbooru_process(queue, deepbooru_process_return, threshold, deepbooru_opts): model, tags = get_deepbooru_tags_model() while True: # while process is running, keep monitoring queue for new image pil_image = queue.get() if pil_image == "QUIT": break else: - deepbooru_process_return["value"] = get_deepbooru_tags_from_model(model, tags, pil_image, threshold, alpha_sort) + deepbooru_process_return["value"] = get_deepbooru_tags_from_model(model, tags, pil_image, threshold, deepbooru_opts) -def create_deepbooru_process(threshold, alpha_sort): +def create_deepbooru_process(threshold, deepbooru_opts): """ Creates deepbooru process. A queue is created to send images into the process. This enables multiple images to be processed in a row without reloading the model or creating a new process. To return the data, a shared @@ -41,10 +52,23 @@ def create_deepbooru_process(threshold, alpha_sort): shared.deepbooru_process_queue = shared.deepbooru_process_manager.Queue() shared.deepbooru_process_return = shared.deepbooru_process_manager.dict() shared.deepbooru_process_return["value"] = -1 - shared.deepbooru_process = multiprocessing.Process(target=deepbooru_process, args=(shared.deepbooru_process_queue, shared.deepbooru_process_return, threshold, alpha_sort)) + shared.deepbooru_process = multiprocessing.Process(target=deepbooru_process, args=(shared.deepbooru_process_queue, shared.deepbooru_process_return, threshold, deepbooru_opts)) shared.deepbooru_process.start() +def get_tags_from_process(image): + from modules import shared + + shared.deepbooru_process_return["value"] = -1 + shared.deepbooru_process_queue.put(image) + while shared.deepbooru_process_return["value"] == -1: + time.sleep(0.2) + caption = shared.deepbooru_process_return["value"] + shared.deepbooru_process_return["value"] = -1 + + return caption + + def release_process(): """ Stops the deepbooru process to return used memory @@ -81,10 +105,15 @@ def get_deepbooru_tags_model(): return model, tags -def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, alpha_sort): +def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, deepbooru_opts): import deepdanbooru as dd import tensorflow as tf import numpy as np + + alpha_sort = deepbooru_opts['alpha_sort'] + use_spaces = deepbooru_opts['use_spaces'] + use_escape = deepbooru_opts['use_escape'] + width = model.input_shape[2] height = model.input_shape[1] image = np.array(pil_image) @@ -129,4 +158,12 @@ def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, alpha_sort) print('\n'.join(sorted(result_tags_print, reverse=True))) - return ', '.join(result_tags_out).replace('_', ' ').replace(':', ' ') + tags_text = ', '.join(result_tags_out) + + if use_spaces: + tags_text = tags_text.replace('_', ' ') + + if use_escape: + tags_text = re.sub(re_special, r'\\\1', tags_text) + + return tags_text.replace(':', ' ') diff --git a/modules/shared.py b/modules/shared.py index e64e69fcb..78b73aae5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -260,6 +260,8 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"), "interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}), "interrogate_deepbooru_score_threshold": OptionInfo(0.5, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), "deepbooru_sort_alpha": OptionInfo(True, "Interrogate: deepbooru sort alphabetically"), + "deepbooru_use_spaces": OptionInfo(False, "use spaces for tags in deepbooru"), + "deepbooru_escape": OptionInfo(True, "escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)"), })) options_templates.update(options_section(('ui', "User interface"), { diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index 113cecf1d..3047bedea 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -10,7 +10,28 @@ from modules.shared import opts, cmd_opts if cmd_opts.deepdanbooru: import modules.deepbooru as deepbooru + def preprocess(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption, process_caption_deepbooru=False): + try: + if process_caption: + shared.interrogator.load() + + if process_caption_deepbooru: + deepbooru.create_deepbooru_process(opts.interrogate_deepbooru_score_threshold, deepbooru.create_deepbooru_opts()) + + preprocess_work(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption, process_caption_deepbooru) + + finally: + + if process_caption: + shared.interrogator.send_blip_to_ram() + + if process_caption_deepbooru: + deepbooru.release_process() + + + +def preprocess_work(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption, process_caption_deepbooru=False): width = process_width height = process_height src = os.path.abspath(process_src) @@ -25,30 +46,28 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ shared.state.textinfo = "Preprocessing..." shared.state.job_count = len(files) - if process_caption: - shared.interrogator.load() - - if process_caption_deepbooru: - deepbooru.create_deepbooru_process(opts.interrogate_deepbooru_score_threshold, opts.deepbooru_sort_alpha) - def save_pic_with_caption(image, index): - if process_caption: - caption = "-" + shared.interrogator.generate_caption(image) - caption = sanitize_caption(os.path.join(dst, f"{index:05}-{subindex[0]}"), caption, ".png") - elif process_caption_deepbooru: - shared.deepbooru_process_return["value"] = -1 - shared.deepbooru_process_queue.put(image) - while shared.deepbooru_process_return["value"] == -1: - time.sleep(0.2) - caption = "-" + shared.deepbooru_process_return["value"] - caption = sanitize_caption(os.path.join(dst, f"{index:05}-{subindex[0]}"), caption, ".png") - shared.deepbooru_process_return["value"] = -1 - else: - caption = filename - caption = os.path.splitext(caption)[0] - caption = os.path.basename(caption) + caption = "" + + if process_caption: + caption += shared.interrogator.generate_caption(image) + + if process_caption_deepbooru: + if len(caption) > 0: + caption += ", " + caption += deepbooru.get_tags_from_process(image) + + filename_part = filename + filename_part = os.path.splitext(filename_part)[0] + filename_part = os.path.basename(filename_part) + + basename = f"{index:05}-{subindex[0]}-{filename_part}" + image.save(os.path.join(dst, f"{basename}.png")) + + if len(caption) > 0: + with open(os.path.join(dst, f"{basename}.txt"), "w", encoding="utf8") as file: + file.write(caption) - image.save(os.path.join(dst, f"{index:05}-{subindex[0]}{caption}.png")) subindex[0] += 1 def save_pic(image, index): @@ -93,34 +112,3 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ save_pic(img, index) shared.state.nextjob() - - if process_caption: - shared.interrogator.send_blip_to_ram() - - if process_caption_deepbooru: - deepbooru.release_process() - - -def sanitize_caption(base_path, original_caption, suffix): - operating_system = platform.system().lower() - if (operating_system == "windows"): - invalid_path_characters = "\\/:*?\"<>|" - max_path_length = 259 - else: - invalid_path_characters = "/" #linux/macos - max_path_length = 1023 - caption = original_caption - for invalid_character in invalid_path_characters: - caption = caption.replace(invalid_character, "") - fixed_path_length = len(base_path) + len(suffix) - if fixed_path_length + len(caption) <= max_path_length: - return caption - caption_tokens = caption.split() - new_caption = "" - for token in caption_tokens: - last_caption = new_caption - new_caption = new_caption + token + " " - if (len(new_caption) + fixed_path_length - 1 > max_path_length): - break - print(f"\nPath will be too long. Truncated caption: {original_caption}\nto: {last_caption}", file=sys.stderr) - return last_caption.strip() diff --git a/modules/ui.py b/modules/ui.py index c42535c84..e07ee0e1d 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1074,11 +1074,8 @@ def create_ui(wrap_gradio_gpu_call): with gr.Row(): process_flip = gr.Checkbox(label='Create flipped copies') process_split = gr.Checkbox(label='Split oversized images into two') - process_caption = gr.Checkbox(label='Use BLIP caption as filename') - if cmd_opts.deepdanbooru: - process_caption_deepbooru = gr.Checkbox(label='Use deepbooru caption as filename') - else: - process_caption_deepbooru = gr.Checkbox(label='Use deepbooru caption as filename', visible=False) + process_caption = gr.Checkbox(label='Use BLIP for caption') + process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True if cmd_opts.deepdanbooru else False) with gr.Row(): with gr.Column(scale=3): From efefa4862c6c75115d3da9f768348630cc32bdea Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Wed, 12 Oct 2022 13:03:00 -0700 Subject: [PATCH 383/460] [1/?] [wip] Reintroduce opts.interrogate_return_ranks looks functionally correct, needs testing Needs particular testing care around whether the colon usage (:) will break anything in whatever new use cases were introduced by https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/2143 --- modules/deepbooru.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 419e6a9cd..2cbf2cab6 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -26,6 +26,7 @@ def create_deepbooru_opts(): "use_spaces": shared.opts.deepbooru_use_spaces, "use_escape": shared.opts.deepbooru_escape, "alpha_sort": shared.opts.deepbooru_sort_alpha, + "include_ranks": shared.opts.interrogate_return_ranks, } @@ -113,6 +114,7 @@ def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, deepbooru_o alpha_sort = deepbooru_opts['alpha_sort'] use_spaces = deepbooru_opts['use_spaces'] use_escape = deepbooru_opts['use_escape'] + include_ranks = deepbooru_opts['include_ranks'] width = model.input_shape[2] height = model.input_shape[1] @@ -151,19 +153,20 @@ def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, deepbooru_o if alpha_sort: sort_ndx = 1 - # sort by reverse by likelihood and normal for alpha + # sort by reverse by likelihood and normal for alpha, and format tag text as requested unsorted_tags_in_theshold.sort(key=lambda y: y[sort_ndx], reverse=(not alpha_sort)) for weight, tag in unsorted_tags_in_theshold: - result_tags_out.append(tag) + # note: tag_outformat will still have a colon if include_ranks is True + tag_outformat = tag.replace(':', ' ') + if use_spaces: + tag_outformat = tag_outformat.replace('_', ' ') + if use_escape: + tag_outformat = re.sub(re_special, r'\\\1', tag_outformat) + if include_ranks: + use_escape += f":{weight:.3f}" + + result_tags_out.append(tag_outformat) print('\n'.join(sorted(result_tags_print, reverse=True))) - tags_text = ', '.join(result_tags_out) - - if use_spaces: - tags_text = tags_text.replace('_', ' ') - - if use_escape: - tags_text = re.sub(re_special, r'\\\1', tags_text) - - return tags_text.replace(':', ' ') + return ', '.join(result_tags_out) From f776254b12361b5bae16f6629bcdcb47b450c48d Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Wed, 12 Oct 2022 13:08:06 -0700 Subject: [PATCH 384/460] [2/?] [wip] ignore OPT_INCLUDE_RANKS for training filenames --- modules/deepbooru.py | 3 ++- modules/textual_inversion/preprocess.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 2cbf2cab6..fcc05819b 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -19,6 +19,7 @@ def get_deepbooru_tags(pil_image): release_process() +OPT_INCLUDE_RANKS = "include_ranks" def create_deepbooru_opts(): from modules import shared @@ -26,7 +27,7 @@ def create_deepbooru_opts(): "use_spaces": shared.opts.deepbooru_use_spaces, "use_escape": shared.opts.deepbooru_escape, "alpha_sort": shared.opts.deepbooru_sort_alpha, - "include_ranks": shared.opts.interrogate_return_ranks, + OPT_INCLUDE_RANKS: shared.opts.interrogate_return_ranks, } diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py index 3047bedea..886cf0c3b 100644 --- a/modules/textual_inversion/preprocess.py +++ b/modules/textual_inversion/preprocess.py @@ -17,7 +17,9 @@ def preprocess(process_src, process_dst, process_width, process_height, process_ shared.interrogator.load() if process_caption_deepbooru: - deepbooru.create_deepbooru_process(opts.interrogate_deepbooru_score_threshold, deepbooru.create_deepbooru_opts()) + db_opts = deepbooru.create_deepbooru_opts() + db_opts[deepbooru.OPT_INCLUDE_RANKS] = False + deepbooru.create_deepbooru_process(opts.interrogate_deepbooru_score_threshold, db_opts) preprocess_work(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption, process_caption_deepbooru) From 514456101b142b47acf87f6de95bad1a23d73be7 Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Wed, 12 Oct 2022 13:14:13 -0700 Subject: [PATCH 385/460] [3/?] [wip] fix incorrect variable reference still needs testing --- modules/deepbooru.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index fcc05819b..c20046968 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -164,7 +164,7 @@ def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, deepbooru_o if use_escape: tag_outformat = re.sub(re_special, r'\\\1', tag_outformat) if include_ranks: - use_escape += f":{weight:.3f}" + tag_outformat += f":{weight:.3f}" result_tags_out.append(tag_outformat) From 1cfc2a18981ee56bdb69a2de7b463a11ad05e329 Mon Sep 17 00:00:00 2001 From: Melan Date: Wed, 12 Oct 2022 23:36:29 +0200 Subject: [PATCH 386/460] Save a csv containing the loss while training --- modules/hypernetworks/hypernetwork.py | 17 ++++++++++++++++- modules/textual_inversion/textual_inversion.py | 17 ++++++++++++++++- modules/ui.py | 3 +++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index b6c06d49e..6522078f7 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -5,6 +5,7 @@ import os import sys import traceback import tqdm +import csv import torch @@ -174,7 +175,7 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): return self.to_out(out) -def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_image_prompt): +def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, write_csv_every, template_file, preview_image_prompt): assert hypernetwork_name, 'hypernetwork not selected' path = shared.hypernetworks.get(hypernetwork_name, None) @@ -256,6 +257,20 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name}-{hypernetwork.step}.pt') hypernetwork.save(last_saved_file) + print(f"{write_csv_every} > {hypernetwork.step % write_csv_every == 0}, {write_csv_every}") + if write_csv_every > 0 and hypernetwork_dir is not None and hypernetwork.step % write_csv_every == 0: + write_csv_header = False if os.path.exists(os.path.join(hypernetwork_dir, "hypernetwork_loss.csv")) else True + + with open(os.path.join(hypernetwork_dir, "hypernetwork_loss.csv"), "a+") as fout: + + csv_writer = csv.DictWriter(fout, fieldnames=["step", "loss"]) + + if write_csv_header: + csv_writer.writeheader() + + csv_writer.writerow({"step": hypernetwork.step, + "loss": f"{losses.mean():.7f}"}) + if hypernetwork.step > 0 and images_dir is not None and hypernetwork.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{hypernetwork_name}-{hypernetwork.step}.png') diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index fa0e33a2a..25038a890 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -6,6 +6,7 @@ import torch import tqdm import html import datetime +import csv from PIL import Image, PngImagePlugin @@ -172,7 +173,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_image_prompt): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, write_csv_every, template_file, save_image_with_stored_embedding, preview_image_prompt): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -256,6 +257,20 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini last_saved_file = os.path.join(embedding_dir, f'{embedding_name}-{embedding.step}.pt') embedding.save(last_saved_file) + if write_csv_every > 0 and log_directory is not None and embedding.step % write_csv_every == 0: + write_csv_header = False if os.path.exists(os.path.join(log_directory, "textual_inversion_loss.csv")) else True + + with open(os.path.join(log_directory, "textual_inversion_loss.csv"), "a+") as fout: + + csv_writer = csv.DictWriter(fout, fieldnames=["epoch", "epoch_step", "loss"]) + + if write_csv_header: + csv_writer.writeheader() + + csv_writer.writerow({"epoch": epoch_num + 1, + "epoch_step": epoch_step - 1, + "loss": f"{losses.mean():.7f}"}) + if embedding.step > 0 and images_dir is not None and embedding.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{embedding_name}-{embedding.step}.png') diff --git a/modules/ui.py b/modules/ui.py index e07ee0e1d..1195c2f12 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1096,6 +1096,7 @@ def create_ui(wrap_gradio_gpu_call): training_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512) steps = gr.Number(label='Max steps', value=100000, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) + write_csv_every = gr.Number(label='Save an csv containing the loss to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True) preview_image_prompt = gr.Textbox(label='Preview prompt', value="") @@ -1174,6 +1175,7 @@ def create_ui(wrap_gradio_gpu_call): steps, create_image_every, save_embedding_every, + write_csv_every, template_file, save_image_with_stored_embedding, preview_image_prompt, @@ -1195,6 +1197,7 @@ def create_ui(wrap_gradio_gpu_call): steps, create_image_every, save_embedding_every, + write_csv_every, template_file, preview_image_prompt, ], From 54e0051bdd7dea7348825c09600ec61ea0771cb8 Mon Sep 17 00:00:00 2001 From: d8ahazard Date: Wed, 12 Oct 2022 18:17:26 -0500 Subject: [PATCH 387/460] Add drag/drop param loading. Drop an image or generational text onto the prompt bar, it loads the info for parsing. --- javascript/dragdrop.js | 3 +++ javascript/imageParams.js | 22 ++++++++++++++++++++++ modules/images.py | 20 ++++++++++++++++++++ modules/ui.py | 30 +++++++++++++++++++++++++++++- 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 javascript/imageParams.js diff --git a/javascript/dragdrop.js b/javascript/dragdrop.js index 5aac57f77..cf900f501 100644 --- a/javascript/dragdrop.js +++ b/javascript/dragdrop.js @@ -53,6 +53,9 @@ window.document.addEventListener('dragover', e => { window.document.addEventListener('drop', e => { const target = e.composedPath()[0]; + if (target.placeholder === "Prompt") { + return; + } const imgWrap = target.closest('[data-testid="image"]'); if ( !imgWrap ) { return; diff --git a/javascript/imageParams.js b/javascript/imageParams.js new file mode 100644 index 000000000..f9d0c0aa8 --- /dev/null +++ b/javascript/imageParams.js @@ -0,0 +1,22 @@ +window.onload = (function(){ + window.addEventListener('drop', e => { + const target = e.composedPath()[0]; + const idx = selected_gallery_index(); + let prompt_target = "txt2img_prompt_image"; + if (idx === 1) { + prompt_target = "img2img_prompt_image"; + } + if (target.placeholder === "Prompt") { + e.stopPropagation(); + e.preventDefault(); + const imgParent = gradioApp().getElementById(prompt_target); + const files = e.dataTransfer.files; + const fileInput = imgParent.querySelector('input[type="file"]'); + if ( fileInput ) { + fileInput.files = files; + fileInput.dispatchEvent(new Event('change')); + } + } + }); + +}); \ No newline at end of file diff --git a/modules/images.py b/modules/images.py index c0a906762..f1155b7f4 100644 --- a/modules/images.py +++ b/modules/images.py @@ -463,3 +463,23 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i txt_fullfn = None return fullfn, txt_fullfn + + +def image_data(image_path): + file, ext = os.path.splitext(image_path.name) + data = {} + if "png" in ext: + image = Image.open(image_path.name, "r") + print(f"Image data requested for {image_path.name} {image.format} of {type(image)}") + try: + data = image.text["parameters"] + except Exception as e: + print(f"Exception: {e}") + pass + print(f"Image data: {data}") + if "txt" in ext: + myfile = open(image_path.name, 'r') + data = myfile.read() + myfile.close() + + return data, None diff --git a/modules/ui.py b/modules/ui.py index 2b332267f..dd793c391 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -431,7 +431,6 @@ def create_toprow(is_img2img): with gr.Column(scale=80): with gr.Row(): prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, placeholder="Prompt", lines=2) - with gr.Column(scale=1, elem_id="roll_col"): roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0) paste = gr.Button(value=paste_symbol, elem_id="paste") @@ -513,6 +512,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Blocks(analytics_enabled=False) as txt2img_interface: txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) + txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="file", visible=False) with gr.Row(elem_id='txt2img_progress_row'): with gr.Column(scale=1): @@ -614,6 +614,18 @@ def create_ui(wrap_gradio_gpu_call): txt2img_prompt.submit(**txt2img_args) submit.click(**txt2img_args) + txt_prompt_img.change( + fn=modules.images.image_data, + # _js = "get_extras_tab_index", + inputs=[ + txt_prompt_img + ], + outputs=[ + txt2img_prompt, + txt_prompt_img + ] + ) + enable_hr.change( fn=lambda x: gr_show(x), inputs=[enable_hr], @@ -674,6 +686,9 @@ def create_ui(wrap_gradio_gpu_call): img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) with gr.Row(elem_id='img2img_progress_row'): + img2img_prompt_img = gr.File(label="", elem_id="txt_prompt_image", file_count="single", type="file", + visible=False) + with gr.Column(scale=1): pass @@ -768,6 +783,18 @@ def create_ui(wrap_gradio_gpu_call): connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False) connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True) + img2img_prompt_img.change( + fn=modules.images.image_data, + # _js = "get_extras_tab_index", + inputs=[ + txt_prompt_img + ], + outputs=[ + img2img_prompt, + img2img_prompt_img + ] + ) + mask_mode.change( lambda mode, img: { init_img_with_mask: gr_show(mode == 0), @@ -956,6 +983,7 @@ def create_ui(wrap_gradio_gpu_call): button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else '' open_extras_folder = gr.Button('Open output directory', elem_id=button_id) + submit.click( fn=wrap_gradio_gpu_call(modules.extras.run_extras), _js="get_extras_tab_index", From 716a9e034f1aff434083363b218bd6043a774fc2 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Thu, 13 Oct 2022 12:19:50 +0800 Subject: [PATCH 388/460] images history delete a number of images consecutively next --- javascript/images_history.js | 24 ++++++++++++-------- modules/images_history.py | 44 ++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/javascript/images_history.js b/javascript/images_history.js index c5c2886ef..8fa4a15e3 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -101,7 +101,7 @@ function images_history_get_current_img(tabname, image_path, files){ ]; } -function images_history_delete(tabname, img_path, img_file_name, page_index, filenames, image_index){ +function images_history_delete(del_num, tabname, img_path, img_file_name, page_index, filenames, image_index){ image_index = parseInt(image_index); var tab = gradioApp().getElementById(tabname + '_images_history'); var set_btn = tab.querySelector(".images_history_set_index"); @@ -112,23 +112,29 @@ function images_history_delete(tabname, img_path, img_file_name, page_index, fil } }); var img_num = buttons.length / 2; - if (img_num === 1){ + if (img_num <= del_num){ setTimeout(function(tabname){ gradioApp().getElementById(tabname + '_images_history_renew_page').click(); }, 30, tabname); - } else { - buttons[image_index].style.display = 'none'; - buttons[image_index + img_num].style.display = 'none'; + } else { + var next_img + for (var i = 0; i < del_num; i++){ + if (image_index + i < image_index + img_num){ + buttons[image_index + i].style.display = 'none'; + buttons[image_index + img_num + 1].style.display = 'none'; + next_img = image_index + i + 1 + } + } var bnt; - if (image_index >= img_num - 1){ - btn = buttons[img_num - 2]; + if (next_img >= img_num){ + btn = buttons[image_index - del_num]; } else { - btn = buttons[image_index + 1] ; + btn = buttons[next_img]; } setTimeout(function(btn){btn.click()}, 30, btn); } images_history_disabled_del(); - return [tabname, img_path, img_file_name, page_index, filenames, image_index]; + return [del_num, tabname, img_path, img_file_name, page_index, filenames, image_index]; } function images_history_turnpage(img_path, page_index, image_index, tabname){ diff --git a/modules/images_history.py b/modules/images_history.py index 6408973c6..f812ea4e9 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -54,23 +54,26 @@ def show_image_info(num, image_path, filenames): #print(f"select image {num}") file = filenames[int(num)] return file, num, os.path.join(image_path, file) -def delete_image(tabname, dir_name, name, page_index, filenames, image_index): - path = os.path.join(dir_name, name) - if os.path.exists(path): - print(f"Delete file {path}") - os.remove(path) - txt_file = os.path.splitext(path)[0] + ".txt" - if os.path.exists(txt_file): - os.remove(txt_file) - new_file_list = [] - for f in filenames: - if f == name: - continue - new_file_list.append(f) - else: - print(f"Not exists file {path}") - new_file_list = filenames - return page_index, new_file_list +def delete_image(delete_num, tabname, dir_name, name, page_index, filenames, image_index): + delete_num = int(delete_num) + index = list(filenames).index(name) + i = 0 + new_file_list = [] + for name in filenames: + if i >= index and i < index + delete_num: + path = os.path.join(dir_name, name) + if os.path.exists(path): + print(f"Delete file {path}") + os.remove(path) + txt_file = os.path.splitext(path)[0] + ".txt" + if os.path.exists(txt_file): + os.remove(txt_file) + else: + print(f"Not exists file {path}") + else: + new_file_list.append(name) + i += 1 + return page_index, new_file_list, 1 def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): if tabname == "txt2img": @@ -90,10 +93,11 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): with gr.Row(): with gr.Column(scale=2): history_gallery = gr.Gallery(show_label=False, elem_id=tabname + "_images_history_gallery").style(grid=6) - delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") + with gr.Row(): + delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") + delete_num = gr.Number(value=1, interactive=True, label="number of images to delete consecutively next") with gr.Column(): with gr.Row(): - #pnginfo = gr.Button('PNG info') pnginfo_send_to_txt2img = gr.Button('Send to txt2img') pnginfo_send_to_img2img = gr.Button('Send to img2img') with gr.Row(): @@ -127,7 +131,7 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): #other funcitons set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) img_file_name.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) - delete.click(delete_image,_js="images_history_delete", inputs=[tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[page_index, filenames]) + delete.click(delete_image,_js="images_history_delete", inputs=[delete_num, tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[page_index, filenames, delete_num]) hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) #pnginfo.click(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) From 78592d404acba7db3baf8d78bdc19266906e684a Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 13 Oct 2022 07:40:03 +0300 Subject: [PATCH 389/460] remove interrogate option I accidentally deleted --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index 78b73aae5..9bda45c19 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -258,6 +258,7 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"), "interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}), "interrogate_clip_min_length": OptionInfo(24, "Interrogate: minimum description length (excluding artists, etc..)", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}), "interrogate_clip_max_length": OptionInfo(48, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}), + "interrogate_clip_dict_limit": OptionInfo(1500, "CLIP: maximum number of lines in text file (0 = No limit)"), "interrogate_deepbooru_score_threshold": OptionInfo(0.5, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}), "deepbooru_sort_alpha": OptionInfo(True, "Interrogate: deepbooru sort alphabetically"), "deepbooru_use_spaces": OptionInfo(False, "use spaces for tags in deepbooru"), From 490494320ec8b5e1049c4ff35c3416258b75807b Mon Sep 17 00:00:00 2001 From: DepFA <35278260+dfaker@users.noreply.github.com> Date: Thu, 13 Oct 2022 04:10:38 +0100 Subject: [PATCH 390/460] add missing id property --- javascript/contextMenus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index 7636c4b33..fe67c42e1 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -94,7 +94,7 @@ contextMenuInit = function(){ } gradioApp().addEventListener("click", function(e) { let source = e.composedPath()[0] - if(source.id && source.indexOf('check_progress')>-1){ + if(source.id && source.id.indexOf('check_progress')>-1){ return } From 04c0e643f2eec68d93a76db171b4d70595808702 Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Wed, 12 Oct 2022 22:13:53 -0700 Subject: [PATCH 391/460] Merge branch 'master' of https://github.com/HunterVacui/stable-diffusion-webui --- modules/deepbooru.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index c20046968..f34f37882 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -164,7 +164,7 @@ def get_deepbooru_tags_from_model(model, tags, pil_image, threshold, deepbooru_o if use_escape: tag_outformat = re.sub(re_special, r'\\\1', tag_outformat) if include_ranks: - tag_outformat += f":{weight:.3f}" + tag_outformat = f"({tag_outformat}:{weight:.3f})" result_tags_out.append(tag_outformat) From e72adc999b3531370eafb9d316924ac497feb445 Mon Sep 17 00:00:00 2001 From: Trung Ngo Date: Sat, 8 Oct 2022 22:57:19 -0500 Subject: [PATCH 392/460] Restore last generation params --- .gitignore | 1 + javascript/hints.js | 2 +- modules/generation_parameters_copypaste.py | 8 ++++++++ modules/processing.py | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7afc93953..69785b3e2 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ __pycache__ /webui.settings.bat /embeddings /styles.csv +/params.txt /styles.csv.bak /webui-user.bat /webui-user.sh diff --git a/javascript/hints.js b/javascript/hints.js index d51ee14c1..32f10fdeb 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -14,7 +14,7 @@ titles = { "\u{1f3b2}\ufe0f": "Set seed to -1, which will cause a new random number to be used every time", "\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomed", "\u{1f3a8}": "Add a random artist to the prompt.", - "\u2199\ufe0f": "Read generation parameters from prompt into user interface.", + "\u2199\ufe0f": "Read generation parameters from prompt or last generation if prompt is empty into user interface.", "\u{1f4c2}": "Open images output directory", "Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt", diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index ac1ba7f40..3e75aecca 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -1,5 +1,7 @@ +import os import re import gradio as gr +from modules.shared import script_path re_param_code = r"\s*([\w ]+):\s*([^,]+)(?:,|$)" re_param = re.compile(re_param_code) @@ -61,6 +63,12 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model def connect_paste(button, paste_fields, input_comp, js=None): def paste_func(prompt): + if not prompt: + filename = os.path.join(script_path, "params.txt") + if os.path.exists(filename): + with open(filename, "r", encoding="utf8") as file: + prompt = file.read() + params = parse_generation_parameters(prompt) res = [] diff --git a/modules/processing.py b/modules/processing.py index 698b3069e..d5172f008 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -324,6 +324,10 @@ def process_images(p: StableDiffusionProcessing) -> Processed: else: assert p.prompt is not None + with open(os.path.join(shared.script_path, "params.txt"), "w", encoding="utf8") as file: + processed = Processed(p, [], p.seed, "") + file.write(processed.infotext(p, 0)) + devices.torch_gc() seed = get_fixed_seed(p.seed) From fde7fefa2ea23747f1107e3e46bf60c08a1134f1 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 13 Oct 2022 12:26:34 +0300 Subject: [PATCH 393/460] update #2336 to prevent reading params.txt when --hide-ui-dir-config option is enabled (for servers, since this will let some users access others' params) --- modules/generation_parameters_copypaste.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 3e75aecca..c27826b6b 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -2,6 +2,7 @@ import os import re import gradio as gr from modules.shared import script_path +from modules import shared re_param_code = r"\s*([\w ]+):\s*([^,]+)(?:,|$)" re_param = re.compile(re_param_code) @@ -63,7 +64,7 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model def connect_paste(button, paste_fields, input_comp, js=None): def paste_func(prompt): - if not prompt: + if not prompt and not shared.cmd_opts.hide_ui_dir_config: filename = os.path.join(script_path, "params.txt") if os.path.exists(filename): with open(filename, "r", encoding="utf8") as file: From 94c01aa35656130b56f401830ad443ce3d97c364 Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Tue, 11 Oct 2022 17:05:20 -0700 Subject: [PATCH 394/460] draw_xy_grid provides the option to also return lone images --- scripts/xy_grid.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 3bb080bf3..14edacc18 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -175,8 +175,9 @@ axis_options = [ ] -def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend): +def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend, include_lone_images): res = [] + successful_images = [] ver_texts = [[images.GridAnnotation(y)] for y in y_labels] hor_texts = [[images.GridAnnotation(x)] for x in x_labels] @@ -194,7 +195,9 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend): first_processed = processed try: - res.append(processed.images[0]) + processed_image = processed.images[0] + res.append(processed_image) + successful_images.append(processed_image) except: res.append(Image.new(res[0].mode, res[0].size)) @@ -203,6 +206,8 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend): grid = images.draw_grid_annotations(grid, res[0].width, res[0].height, hor_texts, ver_texts) first_processed.images = [grid] + if include_lone_images: + first_processed.images += successful_images return first_processed @@ -229,11 +234,12 @@ class Script(scripts.Script): y_values = gr.Textbox(label="Y values", visible=False, lines=1) draw_legend = gr.Checkbox(label='Draw legend', value=True) + include_lone_images = gr.Checkbox(label='Include Separate Images', value=True) no_fixed_seeds = gr.Checkbox(label='Keep -1 for seeds', value=False) - return [x_type, x_values, y_type, y_values, draw_legend, no_fixed_seeds] + return [x_type, x_values, y_type, y_values, draw_legend, include_lone_images, no_fixed_seeds] - def run(self, p, x_type, x_values, y_type, y_values, draw_legend, no_fixed_seeds): + def run(self, p, x_type, x_values, y_type, y_values, draw_legend, include_lone_images, no_fixed_seeds): if not no_fixed_seeds: modules.processing.fix_seed(p) @@ -344,7 +350,8 @@ class Script(scripts.Script): x_labels=[x_opt.format_value(p, x_opt, x) for x in xs], y_labels=[y_opt.format_value(p, y_opt, y) for y in ys], cell=cell, - draw_legend=draw_legend + draw_legend=draw_legend, + include_lone_images=include_lone_images ) if opts.grid_save: From aeacbac218c47f61f1d0d3f3b429c9038b8faf0f Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Tue, 11 Oct 2022 19:46:33 -0700 Subject: [PATCH 395/460] Fix save error --- modules/ui.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/ui.py b/modules/ui.py index e07ee0e1d..4fa405a9e 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -148,7 +148,10 @@ def save_files(js_data, images, do_make_zip, index): is_grid = image_index < p.index_of_first_image i = 0 if is_grid else (image_index - p.index_of_first_image) - fullfn, txt_fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) + seed = p.all_seeds[i] if len(p.all_seeds) > 1 else p.seed + prompt = p.all_prompts[i] if len(p.all_prompts) > 1 else p.prompt + info = p.infotexts[image_index] if len(p.infotexts) > 1 else p.infotexts[0] + fullfn, txt_fullfn = save_image(image, path, "", seed=seed, prompt=prompt, extension=extension, info=info, grid=is_grid, p=p, save_to_dirs=save_to_dirs) filename = os.path.relpath(fullfn, path) filenames.append(filename) From 8711c2fe0135d5c160a57db41cb79ed1942ce7fa Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Wed, 12 Oct 2022 16:12:12 -0700 Subject: [PATCH 396/460] Fix metadata contents --- modules/ui.py | 5 +---- scripts/xy_grid.py | 52 ++++++++++++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 4fa405a9e..e07ee0e1d 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -148,10 +148,7 @@ def save_files(js_data, images, do_make_zip, index): is_grid = image_index < p.index_of_first_image i = 0 if is_grid else (image_index - p.index_of_first_image) - seed = p.all_seeds[i] if len(p.all_seeds) > 1 else p.seed - prompt = p.all_prompts[i] if len(p.all_prompts) > 1 else p.prompt - info = p.infotexts[image_index] if len(p.infotexts) > 1 else p.infotexts[0] - fullfn, txt_fullfn = save_image(image, path, "", seed=seed, prompt=prompt, extension=extension, info=info, grid=is_grid, p=p, save_to_dirs=save_to_dirs) + fullfn, txt_fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) filename = os.path.relpath(fullfn, path) filenames.append(filename) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 14edacc18..02931ae62 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -176,13 +176,16 @@ axis_options = [ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend, include_lone_images): - res = [] - successful_images = [] - ver_texts = [[images.GridAnnotation(y)] for y in y_labels] hor_texts = [[images.GridAnnotation(x)] for x in x_labels] - first_processed = None + # Temporary list of all the images that are generated to be populated into the grid. + # Will be filled with empty images for any individual step that fails to process properly + image_cache = [] + + processed_result = None + cell_mode = "P" + cell_size = (1,1) state.job_count = len(xs) * len(ys) * p.n_iter @@ -190,26 +193,39 @@ def draw_xy_grid(p, xs, ys, x_labels, y_labels, cell, draw_legend, include_lone_ for ix, x in enumerate(xs): state.job = f"{ix + iy * len(xs) + 1} out of {len(xs) * len(ys)}" - processed = cell(x, y) - if first_processed is None: - first_processed = processed - + processed:Processed = cell(x, y) try: - processed_image = processed.images[0] - res.append(processed_image) - successful_images.append(processed_image) + # this dereference will throw an exception if the image was not processed + # (this happens in cases such as if the user stops the process from the UI) + processed_image = processed.images[0] + + if processed_result is None: + # Use our first valid processed result as a template container to hold our full results + processed_result = copy(processed) + cell_mode = processed_image.mode + cell_size = processed_image.size + processed_result.images = [Image.new(cell_mode, cell_size)] + + image_cache.append(processed_image) + if include_lone_images: + processed_result.images.append(processed_image) + processed_result.all_prompts.append(processed.prompt) + processed_result.all_seeds.append(processed.seed) + processed_result.infotexts.append(processed.infotexts[0]) except: - res.append(Image.new(res[0].mode, res[0].size)) + image_cache.append(Image.new(cell_mode, cell_size)) - grid = images.image_grid(res, rows=len(ys)) + if not processed_result: + print("Unexpected error: draw_xy_grid failed to return even a single processed image") + return Processed() + + grid = images.image_grid(image_cache, rows=len(ys)) if draw_legend: - grid = images.draw_grid_annotations(grid, res[0].width, res[0].height, hor_texts, ver_texts) + grid = images.draw_grid_annotations(grid, cell_size[0], cell_size[1], hor_texts, ver_texts) - first_processed.images = [grid] - if include_lone_images: - first_processed.images += successful_images + processed_result.images[0] = grid - return first_processed + return processed_result re_range = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\(([+-]\d+)\s*\))?\s*") From a3f02e4690844715a510b7bc857a0971dd05c4d8 Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Wed, 12 Oct 2022 16:48:53 -0700 Subject: [PATCH 397/460] fix prompt in log.csv --- modules/ui.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index e07ee0e1d..edb4dab1a 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -139,6 +139,8 @@ def save_files(js_data, images, do_make_zip, index): if at_start: writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"]) + log_prompt=data["prompt"] + log_seed=data["seed"] for image_index, filedata in enumerate(images, start_index): if filedata.startswith("data:image/png;base64,"): filedata = filedata[len("data:image/png;base64,"):] @@ -148,7 +150,9 @@ def save_files(js_data, images, do_make_zip, index): is_grid = image_index < p.index_of_first_image i = 0 if is_grid else (image_index - p.index_of_first_image) - fullfn, txt_fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) + log_seed=p.all_seeds[i] + log_prompt=p.all_prompts[i] + fullfn, txt_fullfn = save_image(image, path, "", seed=log_seed, prompt=log_prompt, extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) filename = os.path.relpath(fullfn, path) filenames.append(filename) @@ -157,7 +161,7 @@ def save_files(js_data, images, do_make_zip, index): filenames.append(os.path.basename(txt_fullfn)) fullfns.append(txt_fullfn) - writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]]) + writer.writerow([log_prompt, log_seed, data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]]) # Make Zip if do_make_zip: From fed7f0e281a42ea962bbe422e018468bafa6f1e6 Mon Sep 17 00:00:00 2001 From: Greg Fuller Date: Wed, 12 Oct 2022 23:09:30 -0700 Subject: [PATCH 398/460] Revert "fix prompt in log.csv" This reverts commit e4b5d1696429ab78dae9779420ce6ec4cd9c5f67. --- modules/ui.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index edb4dab1a..e07ee0e1d 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -139,8 +139,6 @@ def save_files(js_data, images, do_make_zip, index): if at_start: writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"]) - log_prompt=data["prompt"] - log_seed=data["seed"] for image_index, filedata in enumerate(images, start_index): if filedata.startswith("data:image/png;base64,"): filedata = filedata[len("data:image/png;base64,"):] @@ -150,9 +148,7 @@ def save_files(js_data, images, do_make_zip, index): is_grid = image_index < p.index_of_first_image i = 0 if is_grid else (image_index - p.index_of_first_image) - log_seed=p.all_seeds[i] - log_prompt=p.all_prompts[i] - fullfn, txt_fullfn = save_image(image, path, "", seed=log_seed, prompt=log_prompt, extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) + fullfn, txt_fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs) filename = os.path.relpath(fullfn, path) filenames.append(filename) @@ -161,7 +157,7 @@ def save_files(js_data, images, do_make_zip, index): filenames.append(os.path.basename(txt_fullfn)) fullfns.append(txt_fullfn) - writer.writerow([log_prompt, log_seed, data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]]) + writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]]) # Make Zip if do_make_zip: From 8636b50aea83f9c743f005722d9f3f8ee9303e00 Mon Sep 17 00:00:00 2001 From: Melan Date: Thu, 13 Oct 2022 12:37:58 +0200 Subject: [PATCH 399/460] Add learn_rate to csv and removed a left-over debug statement --- modules/hypernetworks/hypernetwork.py | 6 +++--- modules/textual_inversion/textual_inversion.py | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 6522078f7..2751a8c8d 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -257,19 +257,19 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name}-{hypernetwork.step}.pt') hypernetwork.save(last_saved_file) - print(f"{write_csv_every} > {hypernetwork.step % write_csv_every == 0}, {write_csv_every}") if write_csv_every > 0 and hypernetwork_dir is not None and hypernetwork.step % write_csv_every == 0: write_csv_header = False if os.path.exists(os.path.join(hypernetwork_dir, "hypernetwork_loss.csv")) else True with open(os.path.join(hypernetwork_dir, "hypernetwork_loss.csv"), "a+") as fout: - csv_writer = csv.DictWriter(fout, fieldnames=["step", "loss"]) + csv_writer = csv.DictWriter(fout, fieldnames=["step", "loss", "learn_rate"]) if write_csv_header: csv_writer.writeheader() csv_writer.writerow({"step": hypernetwork.step, - "loss": f"{losses.mean():.7f}"}) + "loss": f"{losses.mean():.7f}", + "learn_rate": scheduler.learn_rate}) if hypernetwork.step > 0 and images_dir is not None and hypernetwork.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{hypernetwork_name}-{hypernetwork.step}.png') diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 25038a890..b83df079d 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -262,14 +262,15 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini with open(os.path.join(log_directory, "textual_inversion_loss.csv"), "a+") as fout: - csv_writer = csv.DictWriter(fout, fieldnames=["epoch", "epoch_step", "loss"]) + csv_writer = csv.DictWriter(fout, fieldnames=["epoch", "epoch_step", "loss", "learn_rate"]) if write_csv_header: csv_writer.writeheader() csv_writer.writerow({"epoch": epoch_num + 1, "epoch_step": epoch_step - 1, - "loss": f"{losses.mean():.7f}"}) + "loss": f"{losses.mean():.7f}", + "learn_rate": scheduler.learn_rate}) if embedding.step > 0 and images_dir is not None and embedding.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{embedding_name}-{embedding.step}.png') From bb7baf6b9cb6b4b9fa09b6f07ef997db32fe6e58 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 13 Oct 2022 16:07:18 +0300 Subject: [PATCH 400/460] add option to change what's shown in quicksettings bar --- javascript/hints.js | 2 ++ modules/shared.py | 4 ++-- modules/ui.py | 16 +++++++++------- style.css | 1 + 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index 32f10fdeb..06bbd9e23 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -84,6 +84,8 @@ titles = { "Filename word regex": "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is.", "Filename join string": "This string will be used to hoin split words into a single line if the option above is enabled.", + + "Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual stetting tab. See modules/shared.py for setting names. Requires restart to apply." } diff --git a/modules/shared.py b/modules/shared.py index 5f6101a41..4d3ed6259 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -152,7 +152,6 @@ class OptionInfo: self.component_args = component_args self.onchange = onchange self.section = None - self.show_on_main_page = show_on_main_page def options_section(section_identifier, options_dict): @@ -237,7 +236,7 @@ options_templates.update(options_section(('training', "Training"), { })) options_templates.update(options_section(('sd', "Stable Diffusion"), { - "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, show_on_main_page=True), + "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}), "sd_hypernetwork": OptionInfo("None", "Stable Diffusion finetune hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), "save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"), @@ -250,6 +249,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), { "filter_nsfw": OptionInfo(False, "Filter NSFW content"), 'CLIP_stop_at_last_layers': OptionInfo(1, "Stop At last layers of CLIP model", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1}), "random_artist_categories": OptionInfo([], "Allowed categories for random artists selection when using the Roll button", gr.CheckboxGroup, {"choices": artist_db.categories()}), + 'quicksettings': OptionInfo("sd_model_checkpoint", "Quicksettings list"), })) options_templates.update(options_section(('interrogate', "Interrogate Options"), { diff --git a/modules/ui.py b/modules/ui.py index e07ee0e1d..a05298604 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1305,6 +1305,9 @@ Requested path was: {f} settings_cols = 3 items_per_col = int(len(opts.data_labels) * 0.9 / settings_cols) + quicksettings_names = [x.strip() for x in opts.quicksettings.split(",")] + quicksettings_names = set(x for x in quicksettings_names if x != 'quicksettings') + quicksettings_list = [] cols_displayed = 0 @@ -1329,7 +1332,7 @@ Requested path was: {f} gr.HTML(elem_id="settings_header_text_{}".format(item.section[0]), value='

    {}

    '.format(item.section[1])) - if item.show_on_main_page: + if k in quicksettings_names: quicksettings_list.append((i, k, item)) components.append(dummy_component) else: @@ -1338,7 +1341,11 @@ Requested path was: {f} components.append(component) items_displayed += 1 - request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications") + with gr.Row(): + request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications") + reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary') + restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') + request_notifications.click( fn=lambda: None, inputs=[], @@ -1346,10 +1353,6 @@ Requested path was: {f} _js='function(){}' ) - with gr.Row(): - reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary') - restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary') - def reload_scripts(): modules.scripts.reload_script_body_only() @@ -1364,7 +1367,6 @@ Requested path was: {f} shared.state.interrupt() settings_interface.gradio_ref.do_restart = True - restart_gradio.click( fn=request_restart, inputs=[], diff --git a/style.css b/style.css index e6fa10b4f..55c41971e 100644 --- a/style.css +++ b/style.css @@ -488,6 +488,7 @@ input[type="range"]{ #quicksettings > div > div{ max-width: 32em; padding: 0; + margin-right: 0.75em; } canvas[key="mask"] { From cf1e8fcb303a21ab626fc1e8b3bc95bb780e8758 Mon Sep 17 00:00:00 2001 From: Kalle Date: Thu, 13 Oct 2022 00:12:20 +0300 Subject: [PATCH 401/460] Correct img gen count in notification Display correct count of images generated in browser notification regardless of "Show grid in results for web" setting. --- javascript/notification.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/notification.js b/javascript/notification.js index bdf614ada..f96de313b 100644 --- a/javascript/notification.js +++ b/javascript/notification.js @@ -36,7 +36,7 @@ onUiUpdate(function(){ const notification = new Notification( 'Stable Diffusion', { - body: `Generated ${imgs.size > 1 ? imgs.size - 1 : 1} image${imgs.size > 1 ? 's' : ''}`, + body: `Generated ${imgs.size > 1 ? imgs.size - opts.return_grid : 1} image${imgs.size > 1 ? 's' : ''}`, icon: headImg, image: headImg, } From a4170875b00e5362cd252277c9830024dcea0c51 Mon Sep 17 00:00:00 2001 From: aoirusann Date: Wed, 12 Oct 2022 20:09:42 +0800 Subject: [PATCH 402/460] [img2imgalt] Add `override` in UI for convenience. Some params in img2imgalt are fixed, such as `Sampling method` and `Denosing Strength`. And some params should be matched with those in decode, such as `steps`. --- scripts/img2imgalt.py | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/scripts/img2imgalt.py b/scripts/img2imgalt.py index 313a55d21..1e52f69b6 100644 --- a/scripts/img2imgalt.py +++ b/scripts/img2imgalt.py @@ -120,15 +120,44 @@ class Script(scripts.Script): return is_img2img def ui(self, is_img2img): + info = gr.Markdown(''' + * `Sampling method` is overriden as Euler, as this script is built on it. + * `CFG Scale` should be 2 or lower. + ''') + + override_prompt = gr.Checkbox(label="Override `prompt` to the same value as `original prompt`?(and `negative prompt`)", value=True) original_prompt = gr.Textbox(label="Original prompt", lines=1) original_negative_prompt = gr.Textbox(label="Original negative prompt", lines=1) - cfg = gr.Slider(label="Decode CFG scale", minimum=0.0, maximum=15.0, step=0.1, value=1.0) + + override_steps = gr.Checkbox(label="Override `Sampling Steps` to the same value as `Decode steps`?", value=True) st = gr.Slider(label="Decode steps", minimum=1, maximum=150, step=1, value=50) + + override_strength = gr.Checkbox(label="Override `Denoising strength` to 1?", value=True) + + cfg = gr.Slider(label="Decode CFG scale", minimum=0.0, maximum=15.0, step=0.1, value=1.0) randomness = gr.Slider(label="Randomness", minimum=0.0, maximum=1.0, step=0.01, value=0.0) sigma_adjustment = gr.Checkbox(label="Sigma adjustment for finding noise for image", value=False) - return [original_prompt, original_negative_prompt, cfg, st, randomness, sigma_adjustment] - def run(self, p, original_prompt, original_negative_prompt, cfg, st, randomness, sigma_adjustment): + return [ + info, + override_prompt, original_prompt, original_negative_prompt, + override_steps, st, + override_strength, + cfg, randomness, sigma_adjustment, + ] + + def run(self, p, _, override_prompt, original_prompt, original_negative_prompt, override_steps, st, override_strength, cfg, randomness, sigma_adjustment): + # MUST Override + p.sampler_index = [sampler.name for sampler in sd_samplers.samplers].index("Euler") + + # OPTIONAL Override + if override_prompt: + p.prompt = original_prompt + p.negative_prompt = original_negative_prompt + if override_steps: + p.steps = st + if override_strength: + p.denoising_strength = 1.0 def sample_extra(conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength): From e548fc4aca19e58fa97da5404a2116915eb85531 Mon Sep 17 00:00:00 2001 From: aoirusann Date: Thu, 13 Oct 2022 07:39:33 +0800 Subject: [PATCH 403/460] [img2imgalt] Make sampler's override be optional --- scripts/img2imgalt.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/img2imgalt.py b/scripts/img2imgalt.py index 1e52f69b6..d438175ce 100644 --- a/scripts/img2imgalt.py +++ b/scripts/img2imgalt.py @@ -121,10 +121,11 @@ class Script(scripts.Script): def ui(self, is_img2img): info = gr.Markdown(''' - * `Sampling method` is overriden as Euler, as this script is built on it. * `CFG Scale` should be 2 or lower. ''') + override_sampler = gr.Checkbox(label="Override `Sampling method` to Euler?(this method is built for it)", value=True) + override_prompt = gr.Checkbox(label="Override `prompt` to the same value as `original prompt`?(and `negative prompt`)", value=True) original_prompt = gr.Textbox(label="Original prompt", lines=1) original_negative_prompt = gr.Textbox(label="Original negative prompt", lines=1) @@ -140,17 +141,17 @@ class Script(scripts.Script): return [ info, + override_sampler, override_prompt, original_prompt, original_negative_prompt, override_steps, st, override_strength, cfg, randomness, sigma_adjustment, ] - def run(self, p, _, override_prompt, original_prompt, original_negative_prompt, override_steps, st, override_strength, cfg, randomness, sigma_adjustment): - # MUST Override - p.sampler_index = [sampler.name for sampler in sd_samplers.samplers].index("Euler") - - # OPTIONAL Override + def run(self, p, _, override_sampler, override_prompt, original_prompt, original_negative_prompt, override_steps, st, override_strength, cfg, randomness, sigma_adjustment): + # Override + if override_sampler: + p.sampler_index = [sampler.name for sampler in sd_samplers.samplers].index("Euler") if override_prompt: p.prompt = original_prompt p.negative_prompt = original_negative_prompt From dccc181b55100b09182c1679c8dd75011aad7335 Mon Sep 17 00:00:00 2001 From: Taithrah Date: Thu, 13 Oct 2022 10:43:57 -0400 Subject: [PATCH 404/460] Update hints.js typo --- javascript/hints.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/hints.js b/javascript/hints.js index 06bbd9e23..f65e7b882 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -85,7 +85,7 @@ titles = { "Filename word regex": "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is.", "Filename join string": "This string will be used to hoin split words into a single line if the option above is enabled.", - "Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual stetting tab. See modules/shared.py for setting names. Requires restart to apply." + "Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply." } From a10b0e11fc22cc67b6a3664f2ddd17425d8433a8 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 13 Oct 2022 19:22:41 +0300 Subject: [PATCH 405/460] options to refresh list of models and hypernetworks --- modules/shared.py | 9 +++++---- modules/ui.py | 33 +++++++++++++++++++++++++++++---- style.css | 21 ++++++++++++++++++++- 3 files changed, 54 insertions(+), 9 deletions(-) diff --git a/modules/shared.py b/modules/shared.py index 4d3ed6259..d8e3a2863 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -13,7 +13,7 @@ import modules.memmon import modules.sd_models import modules.styles import modules.devices as devices -from modules import sd_samplers +from modules import sd_samplers, sd_models from modules.hypernetworks import hypernetwork from modules.paths import models_path, script_path, sd_path @@ -145,13 +145,14 @@ def realesrgan_models_names(): class OptionInfo: - def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, show_on_main_page=False): + def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, show_on_main_page=False, refresh=None): self.default = default self.label = label self.component = component self.component_args = component_args self.onchange = onchange self.section = None + self.refresh = refresh def options_section(section_identifier, options_dict): @@ -236,8 +237,8 @@ options_templates.update(options_section(('training', "Training"), { })) options_templates.update(options_section(('sd', "Stable Diffusion"), { - "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}), - "sd_hypernetwork": OptionInfo("None", "Stable Diffusion finetune hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}), + "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, refresh=sd_models.list_models), + "sd_hypernetwork": OptionInfo("None", "Stable Diffusion finetune hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), "save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"), "img2img_fix_steps": OptionInfo(False, "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising)."), diff --git a/modules/ui.py b/modules/ui.py index a05298604..0a58f6bed 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -78,6 +78,8 @@ reuse_symbol = '\u267b\ufe0f' # ♻️ art_symbol = '\U0001f3a8' # 🎨 paste_symbol = '\u2199\ufe0f' # ↙ folder_symbol = '\U0001f4c2' # 📂 +refresh_symbol = '\U0001f504' # 🔄 + def plaintext_to_html(text): text = "

    " + "
    \n".join([f"{html.escape(x)}" for x in text.split('\n')]) + "

    " @@ -1210,8 +1212,7 @@ def create_ui(wrap_gradio_gpu_call): outputs=[], ) - - def create_setting_component(key): + def create_setting_component(key, is_quicksettings=False): def fun(): return opts.data[key] if key in opts.data else opts.data_labels[key].default @@ -1231,7 +1232,31 @@ def create_ui(wrap_gradio_gpu_call): else: raise Exception(f'bad options item type: {str(t)} for key {key}') - return comp(label=info.label, value=fun, **(args or {})) + if info.refresh is not None: + if is_quicksettings: + res = comp(label=info.label, value=fun, **(args or {})) + refresh_button = gr.Button(value=refresh_symbol, elem_id="refresh_"+key) + else: + with gr.Row(variant="compact"): + res = comp(label=info.label, value=fun, **(args or {})) + refresh_button = gr.Button(value=refresh_symbol, elem_id="refresh_" + key) + + def refresh(): + info.refresh() + refreshed_args = info.component_args() if callable(info.component_args) else info.component_args + res.choices = refreshed_args["choices"] + return gr.update(**(refreshed_args or {})) + + refresh_button.click( + fn=refresh, + inputs=[], + outputs=[res], + ) + else: + res = comp(label=info.label, value=fun, **(args or {})) + + + return res components = [] component_dict = {} @@ -1401,7 +1426,7 @@ Requested path was: {f} with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo: with gr.Row(elem_id="quicksettings"): for i, k, item in quicksettings_list: - component = create_setting_component(k) + component = create_setting_component(k, is_quicksettings=True) component_dict[k] = component settings_interface.gradio_ref = demo diff --git a/style.css b/style.css index 55c41971e..ad2a52cc9 100644 --- a/style.css +++ b/style.css @@ -228,6 +228,8 @@ fieldset span.text-gray-500, .gr-block.gr-box span.text-gray-500, label.block s border-top: 1px solid #eee; border-left: 1px solid #eee; border-right: 1px solid #eee; + + z-index: 300; } .dark fieldset span.text-gray-500, .dark .gr-block.gr-box span.text-gray-500, .dark label.block span{ @@ -480,17 +482,30 @@ input[type="range"]{ background: #a55000; } +#quicksettings { + gap: 0.4em; +} + #quicksettings > div{ border: none; background: none; + flex: unset; + gap: 0.5em; } #quicksettings > div > div{ max-width: 32em; + min-width: 24em; padding: 0; - margin-right: 0.75em; } +#refresh_sd_model_checkpoint, #refresh_sd_hypernetwork{ + max-width: 2.5em; + min-width: 2.5em; + height: 2.4em; +} + + canvas[key="mask"] { z-index: 12 !important; filter: invert(); @@ -507,3 +522,7 @@ canvas[key="mask"] { z-index: 200; width: 8em; } + +.row.gr-compact{ + overflow: visible; +} From 354ef0da3b1f0fa5c113d04b6c79e3908c848d23 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 13 Oct 2022 20:12:37 +0300 Subject: [PATCH 406/460] add hypernetwork multipliers --- modules/hypernetworks/hypernetwork.py | 8 +++++++- modules/shared.py | 5 ++++- modules/ui.py | 5 ++++- scripts/xy_grid.py | 9 ++++++++- style.css | 3 +++ webui.py | 2 +- 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index b6c06d49e..f1248bb7b 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -18,6 +18,8 @@ from modules.textual_inversion.learn_schedule import LearnRateScheduler class HypernetworkModule(torch.nn.Module): + multiplier = 1.0 + def __init__(self, dim, state_dict=None): super().__init__() @@ -36,7 +38,11 @@ class HypernetworkModule(torch.nn.Module): self.to(devices.device) def forward(self, x): - return x + (self.linear2(self.linear1(x))) + return x + (self.linear2(self.linear1(x))) * self.multiplier + + +def apply_strength(value=None): + HypernetworkModule.multiplier = value if value is not None else shared.opts.sd_hypernetwork_strength class Hypernetwork: diff --git a/modules/shared.py b/modules/shared.py index d8e3a2863..5901e6056 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -238,7 +238,8 @@ options_templates.update(options_section(('training', "Training"), { options_templates.update(options_section(('sd', "Stable Diffusion"), { "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, refresh=sd_models.list_models), - "sd_hypernetwork": OptionInfo("None", "Stable Diffusion finetune hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), + "sd_hypernetwork": OptionInfo("None", "Hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), + "sd_hypernetwork_strength": OptionInfo(1.0, "Hypernetwork strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.001}), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), "save_images_before_color_correction": OptionInfo(False, "Save a copy of image before applying color correction to img2img results"), "img2img_fix_steps": OptionInfo(False, "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising)."), @@ -348,6 +349,8 @@ class Options: item = self.data_labels.get(key) item.onchange = func + func() + def dumpjson(self): d = {k: self.data.get(k, self.data_labels.get(k).default) for k in self.data_labels.keys()} return json.dumps(d) diff --git a/modules/ui.py b/modules/ui.py index 0a58f6bed..673014f26 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1244,7 +1244,10 @@ def create_ui(wrap_gradio_gpu_call): def refresh(): info.refresh() refreshed_args = info.component_args() if callable(info.component_args) else info.component_args - res.choices = refreshed_args["choices"] + + for k, v in refreshed_args.items(): + setattr(res, k, v) + return gr.update(**(refreshed_args or {})) refresh_button.click( diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 02931ae62..efb63af54 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -107,6 +107,10 @@ def apply_hypernetwork(p, x, xs): hypernetwork.load_hypernetwork(name) +def apply_hypernetwork_strength(p, x, xs): + hypernetwork.apply_strength(x) + + def confirm_hypernetworks(p, xs): for x in xs: if x.lower() in ["", "none"]: @@ -165,6 +169,7 @@ axis_options = [ AxisOption("Sampler", str, apply_sampler, format_value, confirm_samplers), AxisOption("Checkpoint name", str, apply_checkpoint, format_value, confirm_checkpoints), AxisOption("Hypernetwork", str, apply_hypernetwork, format_value, confirm_hypernetworks), + AxisOption("Hypernet str.", float, apply_hypernetwork_strength, format_value_add_label, None), AxisOption("Sigma Churn", float, apply_field("s_churn"), format_value_add_label, None), AxisOption("Sigma min", float, apply_field("s_tmin"), format_value_add_label, None), AxisOption("Sigma max", float, apply_field("s_tmax"), format_value_add_label, None), @@ -250,7 +255,7 @@ class Script(scripts.Script): y_values = gr.Textbox(label="Y values", visible=False, lines=1) draw_legend = gr.Checkbox(label='Draw legend', value=True) - include_lone_images = gr.Checkbox(label='Include Separate Images', value=True) + include_lone_images = gr.Checkbox(label='Include Separate Images', value=False) no_fixed_seeds = gr.Checkbox(label='Keep -1 for seeds', value=False) return [x_type, x_values, y_type, y_values, draw_legend, include_lone_images, no_fixed_seeds] @@ -377,6 +382,8 @@ class Script(scripts.Script): modules.sd_models.reload_model_weights(shared.sd_model) hypernetwork.load_hypernetwork(opts.sd_hypernetwork) + hypernetwork.apply_strength() + opts.data["CLIP_stop_at_last_layers"] = CLIP_stop_at_last_layers diff --git a/style.css b/style.css index ad2a52cc9..aa3d379c1 100644 --- a/style.css +++ b/style.css @@ -522,6 +522,9 @@ canvas[key="mask"] { z-index: 200; width: 8em; } +#quicksettings .gr-box > div > div > input.gr-text-input { + top: -1.12em; +} .row.gr-compact{ overflow: visible; diff --git a/webui.py b/webui.py index 33ba79054..fe0ce321f 100644 --- a/webui.py +++ b/webui.py @@ -72,7 +72,6 @@ def wrap_gradio_gpu_call(func, extra_outputs=None): return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs) - def initialize(): modelloader.cleanup_models() modules.sd_models.setup_model() @@ -86,6 +85,7 @@ def initialize(): shared.sd_model = modules.sd_models.load_model() shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model))) shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetworks.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork))) + shared.opts.onchange("sd_hypernetwork_strength", modules.hypernetworks.hypernetwork.apply_strength) def webui(): From 08b3f7aef15f74f4d2254b1274dd66fcc7940348 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Thu, 13 Oct 2022 20:42:27 +0300 Subject: [PATCH 407/460] emergency fix for broken send to buttons --- javascript/ui.js | 8 ++++---- modules/ui.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ui.js b/javascript/ui.js index 4100944e6..0f8fe68ef 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -33,27 +33,27 @@ function args_to_array(args){ } function switch_to_txt2img(){ - gradioApp().querySelectorAll('button')[0].click(); + gradioApp().querySelector('#tabs').querySelectorAll('button')[0].click(); return args_to_array(arguments); } function switch_to_img2img_img2img(){ - gradioApp().querySelectorAll('button')[1].click(); + gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click(); gradioApp().getElementById('mode_img2img').querySelectorAll('button')[0].click(); return args_to_array(arguments); } function switch_to_img2img_inpaint(){ - gradioApp().querySelectorAll('button')[1].click(); + gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click(); gradioApp().getElementById('mode_img2img').querySelectorAll('button')[1].click(); return args_to_array(arguments); } function switch_to_extras(){ - gradioApp().querySelectorAll('button')[2].click(); + gradioApp().querySelector('#tabs').querySelectorAll('button')[2].click(); return args_to_array(arguments); } diff --git a/modules/ui.py b/modules/ui.py index 673014f26..7446439d0 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1434,7 +1434,7 @@ Requested path was: {f} settings_interface.gradio_ref = demo - with gr.Tabs() as tabs: + with gr.Tabs(elem_id="tabs") as tabs: for interface, label, ifid in interfaces: with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid): interface.render() From a1489f94283c07824a7a58353c03dc89541bbe49 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Fri, 14 Oct 2022 07:13:38 +0800 Subject: [PATCH 408/460] images history fix all known bug --- .gitignore | 1 + javascript/images_history.js | 23 +++++++--------- modules/images_history.py | 51 +++++++++++++++++++----------------- repositorieslatent-diffusion | 1 - style.css | 6 ++--- 5 files changed, 40 insertions(+), 42 deletions(-) delete mode 160000 repositorieslatent-diffusion diff --git a/.gitignore b/.gitignore index 434e23ce1..b9e23112e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ notification.mp3 /SwinIR /textual_inversion /images_history_testui.py +/repositorieslatent-diffusion diff --git a/javascript/images_history.js b/javascript/images_history.js index 8fa4a15e3..3a20056b9 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -25,11 +25,6 @@ var images_history_click_tab = function(){ } } -var images_history_close_full_view = function(){ - var box = images_history_get_parent_by_class(this, "images_history_cantainor"); - box.querySelector(".images_history_del_button").setAttribute("disabled", "disabled"); -} - function images_history_disabled_del(){ gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){ btn.setAttribute('disabled','disabled'); @@ -182,18 +177,18 @@ setTimeout(images_history_init, 500); document.addEventListener("DOMContentLoaded", function() { var mutationObserver = new MutationObserver(function(m){ for (var i in images_history_tab_list ){ - var buttons = gradioApp().querySelectorAll('#' + images_history_tab_list[i] + '_images_history .gallery-item'); + let tabname = images_history_tab_list[i] + var buttons = gradioApp().querySelectorAll('#' + tabname + '_images_history .gallery-item'); buttons.forEach(function(bnt){ bnt.addEventListener('click', images_history_click_image, true); }); - // var cls_btn = gradioApp().getElementById(tabname + '_images_history_gallery').querySelector("svg"); - // if (cls_btn){ - // cls_btn.addEventListener('click', images_history_close_full_view, false); - // } - // console.log(cls_btn, cls_btn.parentElement.parentElement) - // if (cls_btn) { - // cls_btn = images_history_get_parent_by_tagname(cls_btn, "BUTTON"); - // cls_btn.addEventListener('click', images_history_close_full_view, true); + var cls_btn = gradioApp().getElementById(tabname + '_images_history_gallery').querySelector("svg"); + if (cls_btn){ + cls_btn.addEventListener('click', function(){ + gradioApp().getElementById(tabname + '_images_history_renew_page').click(); + }, false); + } + } }); mutationObserver.observe( gradioApp(), { childList:true, subtree:true }); diff --git a/modules/images_history.py b/modules/images_history.py index f812ea4e9..cdfcffed6 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -38,7 +38,7 @@ def get_recent_images(dir_name, page_index, step, image_index, tabname): else: current_file = file_list[int(image_index)] hide_image = os.path.join(dir_name, current_file) - return [os.path.join(dir_name, file) for file in file_list], page_index, file_list, current_file, hide_image + return [os.path.join(dir_name, file) for file in file_list], page_index, file_list, current_file, hide_image, "" def first_page_click(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, 1, 0, image_index, tabname) def end_page_click(dir_name, page_index, image_index, tabname): @@ -55,25 +55,28 @@ def show_image_info(num, image_path, filenames): file = filenames[int(num)] return file, num, os.path.join(image_path, file) def delete_image(delete_num, tabname, dir_name, name, page_index, filenames, image_index): - delete_num = int(delete_num) - index = list(filenames).index(name) - i = 0 - new_file_list = [] - for name in filenames: - if i >= index and i < index + delete_num: - path = os.path.join(dir_name, name) - if os.path.exists(path): - print(f"Delete file {path}") - os.remove(path) - txt_file = os.path.splitext(path)[0] + ".txt" - if os.path.exists(txt_file): - os.remove(txt_file) + if name == "": + return filenames, delete_num + else: + delete_num = int(delete_num) + index = list(filenames).index(name) + i = 0 + new_file_list = [] + for name in filenames: + if i >= index and i < index + delete_num: + path = os.path.join(dir_name, name) + if os.path.exists(path): + print(f"Delete file {path}") + os.remove(path) + txt_file = os.path.splitext(path)[0] + ".txt" + if os.path.exists(txt_file): + os.remove(txt_file) + else: + print(f"Not exists file {path}") else: - print(f"Not exists file {path}") - else: - new_file_list.append(name) - i += 1 - return page_index, new_file_list, 1 + new_file_list.append(name) + i += 1 + return new_file_list, 1 def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): if tabname == "txt2img": @@ -93,9 +96,9 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): with gr.Row(): with gr.Column(scale=2): history_gallery = gr.Gallery(show_label=False, elem_id=tabname + "_images_history_gallery").style(grid=6) - with gr.Row(): - delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") - delete_num = gr.Number(value=1, interactive=True, label="number of images to delete consecutively next") + with gr.Row(): + delete_num = gr.Number(value=1, interactive=True, label="number of images to delete consecutively next") + delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") with gr.Column(): with gr.Row(): pnginfo_send_to_txt2img = gr.Button('Send to txt2img') @@ -118,7 +121,7 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): # turn pages gallery_inputs = [img_path, page_index, image_index, tabname_box] - gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hide_image] + gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hide_image, img_file_name] first_page.click(first_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) next_page.click(next_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) @@ -131,7 +134,7 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): #other funcitons set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) img_file_name.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) - delete.click(delete_image,_js="images_history_delete", inputs=[delete_num, tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[page_index, filenames, delete_num]) + delete.click(delete_image,_js="images_history_delete", inputs=[delete_num, tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[filenames, delete_num]) hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) #pnginfo.click(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) diff --git a/repositorieslatent-diffusion b/repositorieslatent-diffusion deleted file mode 160000 index abf33e700..000000000 --- a/repositorieslatent-diffusion +++ /dev/null @@ -1 +0,0 @@ -Subproject commit abf33e7002d59d9085081bce93ec798dcabd49af diff --git a/style.css b/style.css index c75dce4c6..e6fa10b4f 100644 --- a/style.css +++ b/style.css @@ -20,7 +20,7 @@ padding-right: 0.25em; margin: 0.1em 0; opacity: 0%; - cursor: default; + cursor: default; } .output-html p {margin: 0 0.5em;} @@ -442,7 +442,7 @@ input[type="range"]{ } .red { - color: red; + color: red; } .gallery-item { @@ -505,4 +505,4 @@ canvas[key="mask"] { top: -0.6em; z-index: 200; width: 8em; -} \ No newline at end of file +} From 4a37c7eedeab579efec03e8dae3f3f9fd4a37b02 Mon Sep 17 00:00:00 2001 From: yfszzx Date: Fri, 14 Oct 2022 11:48:28 +0800 Subject: [PATCH 409/460] fix deep nesting directories problem --- modules/images_history.py | 76 +++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/modules/images_history.py b/modules/images_history.py index cdfcffed6..723f5301c 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -1,44 +1,47 @@ import os import shutil +def traverse_all_files(output_dir, image_list, curr_dir=None): + curr_path = output_dir if curr_dir is None else os.path.join(output_dir, curr_dir) + try: + f_list = os.listdir(curr_path) + except: + if curr_dir[-10:].rfind(".") > 0 and curr_dir[-4:] != ".txt": + image_list.append(curr_dir) + return image_list + for file in f_list: + file = file if curr_dir is None else os.path.join(curr_dir, file) + file_path = os.path.join(curr_path, file) + if file[-4:] == ".txt": + pass + elif os.path.isfile(file_path) and file[-10:].rfind(".") > 0: + image_list.append(file) + else: + image_list = traverse_all_files(output_dir, image_list, file) + return image_list + + def get_recent_images(dir_name, page_index, step, image_index, tabname): - #print(f"renew page {page_index}") page_index = int(page_index) f_list = os.listdir(dir_name) - file_list = [] - for file in f_list: - if file[-4:] == ".txt": - continue - #subdirectories - if file[-10:].rfind(".") < 0: - sub_dir = os.path.join(dir_name, file) - if os.path.isfile(sub_dir): - continue - sub_file_list = os.listdir(sub_dir) - for sub_file in sub_file_list: - if sub_file[-4:] == ".txt": - continue - if os.path.isfile(os.path.join(sub_dir, sub_file) ): - file_list.append(os.path.join(file, sub_file)) - continue - file_list.append(file) - - file_list = sorted(file_list, key=lambda file: -os.path.getctime(os.path.join(dir_name, file))) + image_list = [] + image_list = traverse_all_files(dir_name, image_list) + image_list = sorted(image_list, key=lambda file: -os.path.getctime(os.path.join(dir_name, file))) num = 48 if tabname != "extras" else 12 - max_page_index = len(file_list) // num + 1 + max_page_index = len(image_list) // num + 1 page_index = max_page_index if page_index == -1 else page_index + step page_index = 1 if page_index < 1 else page_index page_index = max_page_index if page_index > max_page_index else page_index idx_frm = (page_index - 1) * num - file_list = file_list[idx_frm:idx_frm + num] - #print(f"Loading history page {page_index}") + image_list = image_list[idx_frm:idx_frm + num] image_index = int(image_index) - if image_index < 0 or image_index > len(file_list) - 1: + if image_index < 0 or image_index > len(image_list) - 1: current_file = None - hide_image = None + hidden = None else: - current_file = file_list[int(image_index)] - hide_image = os.path.join(dir_name, current_file) - return [os.path.join(dir_name, file) for file in file_list], page_index, file_list, current_file, hide_image, "" + current_file = image_list[int(image_index)] + hidden = os.path.join(dir_name, current_file) + return [os.path.join(dir_name, file) for file in image_list], page_index, image_list, current_file, hidden, "" + def first_page_click(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, 1, 0, image_index, tabname) def end_page_click(dir_name, page_index, image_index, tabname): @@ -85,6 +88,10 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): dir_name = opts.outdir_img2img_samples elif tabname == "extras": dir_name = opts.outdir_extras_samples + d = dir_name.split("/") + dir_name = d[0] + for p in d[1:]: + dir_name = os.path.join(dir_name, p) with gr.Row(): renew_page = gr.Button('Renew Page', elem_id=tabname + "_images_history_renew_page") first_page = gr.Button('First Page') @@ -109,19 +116,20 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): img_file_name = gr.Textbox(label="File Name", interactive=False) with gr.Row(): # hiden items - img_path = gr.Textbox(dir_name, visible=False) + + img_path = gr.Textbox(dir_name.rstrip("/") , visible=False) tabname_box = gr.Textbox(tabname, visible=False) image_index = gr.Textbox(value=-1, visible=False) set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False) filenames = gr.State() - hide_image = gr.Image(type="pil", visible=False) + hidden = gr.Image(type="pil", visible=False) info1 = gr.Textbox(visible=False) info2 = gr.Textbox(visible=False) # turn pages gallery_inputs = [img_path, page_index, image_index, tabname_box] - gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hide_image, img_file_name] + gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hidden, img_file_name] first_page.click(first_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) next_page.click(next_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) @@ -132,12 +140,12 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): #page_index.change(page_index_change, inputs=[tabname_box, img_path, page_index], outputs=[history_gallery, page_index]) #other funcitons - set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hide_image]) + set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hidden]) img_file_name.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) delete.click(delete_image,_js="images_history_delete", inputs=[delete_num, tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[filenames, delete_num]) - hide_image.change(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) + hidden.change(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2]) - #pnginfo.click(fn=run_pnginfo, inputs=[hide_image], outputs=[info1, img_file_info, info2]) + #pnginfo.click(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2]) switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') From 494afccbc1d7b0aca4ffeb3d8354b09c414d95f4 Mon Sep 17 00:00:00 2001 From: crackfoo Date: Thu, 13 Oct 2022 20:26:54 -0700 Subject: [PATCH 410/460] Update hints.js typo --- javascript/hints.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/hints.js b/javascript/hints.js index f65e7b882..94438c5cd 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -83,7 +83,7 @@ titles = { "Do not add watermark to images": "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be behaving in an unethical manner.", "Filename word regex": "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is.", - "Filename join string": "This string will be used to hoin split words into a single line if the option above is enabled.", + "Filename join string": "This string will be used to join split words into a single line if the option above is enabled.", "Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply." } From fdecb636855748e03efc40c846a0043800aadfcc Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 09:05:06 +0300 Subject: [PATCH 411/460] add an ability to merge three checkpoints --- javascript/hints.js | 5 ++++- modules/extras.py | 29 +++++++++++++++++++++-------- modules/ui.py | 11 +++++++---- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index 94438c5cd..af010a59d 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -85,7 +85,10 @@ titles = { "Filename word regex": "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is.", "Filename join string": "This string will be used to join split words into a single line if the option above is enabled.", - "Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply." + "Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply.", + + "Weighted Sum": "Result = A * (1 - M) + B * M", + "Add difference": "Result = A + (B - C) * (1 - M)", } diff --git a/modules/extras.py b/modules/extras.py index b24d7de3f..532d869f5 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -159,48 +159,61 @@ def run_pnginfo(image): return '', geninfo, info -def run_modelmerger(primary_model_name, secondary_model_name, interp_method, interp_amount, save_as_half, custom_name): +def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_name, interp_method, interp_amount, save_as_half, custom_name): # Linear interpolation (https://en.wikipedia.org/wiki/Linear_interpolation) - def weighted_sum(theta0, theta1, alpha): + def weighted_sum(theta0, theta1, theta2, alpha): return ((1 - alpha) * theta0) + (alpha * theta1) # Smoothstep (https://en.wikipedia.org/wiki/Smoothstep) - def sigmoid(theta0, theta1, alpha): + def sigmoid(theta0, theta1, theta2, alpha): alpha = alpha * alpha * (3 - (2 * alpha)) return theta0 + ((theta1 - theta0) * alpha) # Inverse Smoothstep (https://en.wikipedia.org/wiki/Smoothstep) - def inv_sigmoid(theta0, theta1, alpha): + def inv_sigmoid(theta0, theta1, theta2, alpha): import math alpha = 0.5 - math.sin(math.asin(1.0 - 2.0 * alpha) / 3.0) return theta0 + ((theta1 - theta0) * alpha) + def add_difference(theta0, theta1, theta2, alpha): + return theta0 + (theta1 - theta2) * (1.0 - alpha) + primary_model_info = sd_models.checkpoints_list[primary_model_name] secondary_model_info = sd_models.checkpoints_list[secondary_model_name] + teritary_model_info = sd_models.checkpoints_list.get(teritary_model_name, None) print(f"Loading {primary_model_info.filename}...") primary_model = torch.load(primary_model_info.filename, map_location='cpu') + theta_0 = sd_models.get_state_dict_from_checkpoint(primary_model) print(f"Loading {secondary_model_info.filename}...") secondary_model = torch.load(secondary_model_info.filename, map_location='cpu') - - theta_0 = sd_models.get_state_dict_from_checkpoint(primary_model) theta_1 = sd_models.get_state_dict_from_checkpoint(secondary_model) + if teritary_model_info is not None: + print(f"Loading {teritary_model_info.filename}...") + teritary_model = torch.load(teritary_model_info.filename, map_location='cpu') + theta_2 = sd_models.get_state_dict_from_checkpoint(teritary_model) + else: + theta_2 = None + theta_funcs = { "Weighted Sum": weighted_sum, "Sigmoid": sigmoid, "Inverse Sigmoid": inv_sigmoid, + "Add difference": add_difference, } theta_func = theta_funcs[interp_method] print(f"Merging...") + for key in tqdm.tqdm(theta_0.keys()): if 'model' in key and key in theta_1: - theta_0[key] = theta_func(theta_0[key], theta_1[key], (float(1.0) - interp_amount)) # Need to reverse the interp_amount to match the desired mix ration in the merged checkpoint + theta_0[key] = theta_func(theta_0[key], theta_1[key], theta_2[key] if theta_2 else None, (float(1.0) - interp_amount)) # Need to reverse the interp_amount to match the desired mix ration in the merged checkpoint if save_as_half: theta_0[key] = theta_0[key].half() + # I believe this part should be discarded, but I'll leave it for now until I am sure for key in theta_1.keys(): if 'model' in key and key not in theta_0: theta_0[key] = theta_1[key] @@ -219,4 +232,4 @@ def run_modelmerger(primary_model_name, secondary_model_name, interp_method, int sd_models.list_models() print(f"Checkpoint saved.") - return ["Checkpoint saved to " + output_modelname] + [gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(3)] + return ["Checkpoint saved to " + output_modelname] + [gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)] diff --git a/modules/ui.py b/modules/ui.py index 7446439d0..220fb80b5 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1024,11 +1024,12 @@ def create_ui(wrap_gradio_gpu_call): gr.HTML(value="

    A merger of the two checkpoints will be generated in your checkpoint directory.

    ") with gr.Row(): - primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary Model Name") - secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary Model Name") + primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary model (A)") + secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary model (B)") + tertiary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model (C)") custom_name = gr.Textbox(label="Custom Name (Optional)") - interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation Amount', value=0.3) - interp_method = gr.Radio(choices=["Weighted Sum", "Sigmoid", "Inverse Sigmoid"], value="Weighted Sum", label="Interpolation Method") + interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation amount (1 - M)', value=0.3) + interp_method = gr.Radio(choices=["Weighted Sum", "Sigmoid", "Inverse Sigmoid", "Add difference"], value="Weighted Sum", label="Interpolation Method") save_as_half = gr.Checkbox(value=False, label="Save as float16") modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary') @@ -1473,6 +1474,7 @@ Requested path was: {f} inputs=[ primary_model_name, secondary_model_name, + tertiary_model_name, interp_method, interp_amount, save_as_half, @@ -1482,6 +1484,7 @@ Requested path was: {f} submit_result, primary_model_name, secondary_model_name, + tertiary_model_name, component_dict['sd_model_checkpoint'], ] ) From fdef8253a43ca5135923092ca9b85e878d980869 Mon Sep 17 00:00:00 2001 From: brkirch Date: Fri, 14 Oct 2022 04:42:53 -0400 Subject: [PATCH 412/460] Add 'interrogate' and 'all' choices to --use-cpu * Add 'interrogate' and 'all' choices to --use-cpu * Change type for --use-cpu argument to str.lower, so that choices are case insensitive --- modules/devices.py | 2 +- modules/interrogate.py | 14 +++++++------- modules/shared.py | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/devices.py b/modules/devices.py index 03ef58f19..eb4225834 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -34,7 +34,7 @@ def enable_tf32(): errors.run(enable_tf32, "Enabling TF32") -device = device_gfpgan = device_bsrgan = device_esrgan = device_scunet = device_codeformer = get_optimal_device() +device = device_interrogate = device_gfpgan = device_bsrgan = device_esrgan = device_scunet = device_codeformer = get_optimal_device() dtype = torch.float16 dtype_vae = torch.float16 diff --git a/modules/interrogate.py b/modules/interrogate.py index af858cc09..9263d65a6 100644 --- a/modules/interrogate.py +++ b/modules/interrogate.py @@ -55,7 +55,7 @@ class InterrogateModels: model, preprocess = clip.load(clip_model_name) model.eval() - model = model.to(shared.device) + model = model.to(devices.device_interrogate) return model, preprocess @@ -65,14 +65,14 @@ class InterrogateModels: if not shared.cmd_opts.no_half: self.blip_model = self.blip_model.half() - self.blip_model = self.blip_model.to(shared.device) + self.blip_model = self.blip_model.to(devices.device_interrogate) if self.clip_model is None: self.clip_model, self.clip_preprocess = self.load_clip_model() if not shared.cmd_opts.no_half: self.clip_model = self.clip_model.half() - self.clip_model = self.clip_model.to(shared.device) + self.clip_model = self.clip_model.to(devices.device_interrogate) self.dtype = next(self.clip_model.parameters()).dtype @@ -99,11 +99,11 @@ class InterrogateModels: text_array = text_array[0:int(shared.opts.interrogate_clip_dict_limit)] top_count = min(top_count, len(text_array)) - text_tokens = clip.tokenize([text for text in text_array], truncate=True).to(shared.device) + text_tokens = clip.tokenize([text for text in text_array], truncate=True).to(devices.device_interrogate) text_features = self.clip_model.encode_text(text_tokens).type(self.dtype) text_features /= text_features.norm(dim=-1, keepdim=True) - similarity = torch.zeros((1, len(text_array))).to(shared.device) + similarity = torch.zeros((1, len(text_array))).to(devices.device_interrogate) for i in range(image_features.shape[0]): similarity += (100.0 * image_features[i].unsqueeze(0) @ text_features.T).softmax(dim=-1) similarity /= image_features.shape[0] @@ -116,7 +116,7 @@ class InterrogateModels: transforms.Resize((blip_image_eval_size, blip_image_eval_size), interpolation=InterpolationMode.BICUBIC), transforms.ToTensor(), transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)) - ])(pil_image).unsqueeze(0).type(self.dtype).to(shared.device) + ])(pil_image).unsqueeze(0).type(self.dtype).to(devices.device_interrogate) with torch.no_grad(): caption = self.blip_model.generate(gpu_image, sample=False, num_beams=shared.opts.interrogate_clip_num_beams, min_length=shared.opts.interrogate_clip_min_length, max_length=shared.opts.interrogate_clip_max_length) @@ -140,7 +140,7 @@ class InterrogateModels: res = caption - clip_image = self.clip_preprocess(pil_image).unsqueeze(0).type(self.dtype).to(shared.device) + clip_image = self.clip_preprocess(pil_image).unsqueeze(0).type(self.dtype).to(devices.device_interrogate) precision_scope = torch.autocast if shared.cmd_opts.precision == "autocast" else contextlib.nullcontext with torch.no_grad(), precision_scope("cuda"): diff --git a/modules/shared.py b/modules/shared.py index 5901e6056..b6a5c1a8c 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -54,7 +54,7 @@ parser.add_argument("--opt-split-attention", action='store_true', help="force-en parser.add_argument("--opt-split-attention-invokeai", action='store_true', help="force-enables InvokeAI's cross-attention layer optimization. By default, it's on when cuda is unavailable.") parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find") parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization") -parser.add_argument("--use-cpu", nargs='+',choices=['SD', 'GFPGAN', 'BSRGAN', 'ESRGAN', 'SCUNet', 'CodeFormer'], help="use CPU as torch device for specified modules", default=[]) +parser.add_argument("--use-cpu", nargs='+',choices=['all', 'sd', 'interrogate', 'gfpgan', 'bsrgan', 'esrgan', 'scunet', 'codeformer'], help="use CPU as torch device for specified modules", default=[], type=str.lower) parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests") parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None) parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False) @@ -76,8 +76,8 @@ parser.add_argument("--disable-safe-unpickle", action='store_true', help="disabl cmd_opts = parser.parse_args() -devices.device, devices.device_gfpgan, devices.device_bsrgan, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \ -(devices.cpu if x in cmd_opts.use_cpu else devices.get_optimal_device() for x in ['SD', 'GFPGAN', 'BSRGAN', 'ESRGAN', 'SCUNet', 'CodeFormer']) +devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_bsrgan, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \ +(devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'bsrgan', 'esrgan', 'scunet', 'codeformer']) device = devices.device From 9e5ca5077f43bb3ec1a0ec41b47964cb38d544a6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 16:37:32 +0300 Subject: [PATCH 413/460] extra message for unpicking fails --- modules/safe.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/safe.py b/modules/safe.py index 20be16a50..399165a19 100644 --- a/modules/safe.py +++ b/modules/safe.py @@ -96,11 +96,18 @@ def load(filename, *args, **kwargs): if not shared.cmd_opts.disable_safe_unpickle: check_pt(filename) + except pickle.UnpicklingError: + print(f"Error verifying pickled file from {filename}:", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + print(f"-----> !!!! The file is most likely corrupted !!!! <-----", file=sys.stderr) + print(f"You can skip this check with --disable-safe-unpickle commandline argument, but that is not going to help you.\n\n", file=sys.stderr) + return None + except Exception: print(f"Error verifying pickled file from {filename}:", file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) print(f"\nThe file may be malicious, so the program is not going to read it.", file=sys.stderr) - print(f"You can skip this check with --disable-safe-unpickle commandline argument.", file=sys.stderr) + print(f"You can skip this check with --disable-safe-unpickle commandline argument.\n\n", file=sys.stderr) return None return unsafe_torch_load(filename, *args, **kwargs) From b2261b53ae4ad01b3713bc73ff62ab7b6f479e26 Mon Sep 17 00:00:00 2001 From: Buckzor Date: Thu, 13 Oct 2022 17:07:06 +0100 Subject: [PATCH 414/460] Added first_pass_width and height as adjustable inputs to "High Res Fix" --- modules/processing.py | 6 ++++-- modules/txt2img.py | 5 ++++- modules/ui.py | 6 ++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index d5172f008..abbfdf98d 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -506,11 +506,13 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): firstphase_width_truncated = 0 firstphase_height_truncated = 0 - def __init__(self, enable_hr=False, scale_latent=True, denoising_strength=0.75, **kwargs): + def __init__(self, enable_hr=False, scale_latent=True, denoising_strength=0.75, first_pass_width=512, first_pass_height=512, **kwargs): super().__init__(**kwargs) self.enable_hr = enable_hr self.scale_latent = scale_latent self.denoising_strength = denoising_strength + self.first_pass_width = first_pass_width + self.first_pass_height = first_pass_height def init(self, all_prompts, all_seeds, all_subseeds): if self.enable_hr: @@ -519,7 +521,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): else: state.job_count = state.job_count * 2 - desired_pixel_count = 512 * 512 + desired_pixel_count = self.first_pass_width * self.first_pass_height actual_pixel_count = self.width * self.height scale = math.sqrt(desired_pixel_count / actual_pixel_count) diff --git a/modules/txt2img.py b/modules/txt2img.py index e985242b3..85cbece4d 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -6,7 +6,7 @@ import modules.processing as processing from modules.ui import plaintext_to_html -def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, scale_latent: bool, denoising_strength: float, *args): +def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, scale_latent: bool, denoising_strength: float, first_pass_width: int, first_pass_height: int, *args): p = StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples, @@ -32,6 +32,9 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: enable_hr=enable_hr, scale_latent=scale_latent if enable_hr else None, denoising_strength=denoising_strength if enable_hr else None, + first_pass_width=first_pass_width if enable_hr else None, + first_pass_height=first_pass_height if enable_hr else None, + ) if cmd_opts.enable_console_prompts: diff --git a/modules/ui.py b/modules/ui.py index 220fb80b5..544419b25 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -540,6 +540,8 @@ def create_ui(wrap_gradio_gpu_call): enable_hr = gr.Checkbox(label='Highres. fix', value=False) with gr.Row(visible=False) as hr_options: + first_pass_width = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass width", value=512) + first_pass_height = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass height", value=512) scale_latent = gr.Checkbox(label='Scale latent', value=False) denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) @@ -604,6 +606,8 @@ def create_ui(wrap_gradio_gpu_call): enable_hr, scale_latent, denoising_strength, + first_pass_width, + first_pass_height, ] + custom_inputs, outputs=[ txt2img_gallery, @@ -668,6 +672,8 @@ def create_ui(wrap_gradio_gpu_call): (denoising_strength, "Denoising strength"), (enable_hr, lambda d: "Denoising strength" in d), (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)), + (first_pass_width, "First pass width"), + (first_pass_height, "First pass height"), ] modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt) token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) From 40d1c6e423b4dc52b3bdae43d9e2442960760ced Mon Sep 17 00:00:00 2001 From: Buckzor Date: Thu, 13 Oct 2022 20:04:22 +0100 Subject: [PATCH 415/460] Option between stretch and crop for Highres. fix --- modules/processing.py | 34 ++++++++++++++++++++++------------ modules/txt2img.py | 7 ++++--- modules/ui.py | 25 ++++++++++++++++--------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index abbfdf98d..0246f5dd6 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -506,13 +506,14 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): firstphase_width_truncated = 0 firstphase_height_truncated = 0 - def __init__(self, enable_hr=False, scale_latent=True, denoising_strength=0.75, first_pass_width=512, first_pass_height=512, **kwargs): + def __init__(self, enable_hr=False, scale_latent=True, denoising_strength=0.75, firstphase_width=512, firstphase_height=512, crop_scale=False, **kwargs): super().__init__(**kwargs) self.enable_hr = enable_hr self.scale_latent = scale_latent self.denoising_strength = denoising_strength - self.first_pass_width = first_pass_width - self.first_pass_height = first_pass_height + self.firstphase_width = firstphase_width + self.firstphase_height = firstphase_height + self.crop_scale = crop_scale def init(self, all_prompts, all_seeds, all_subseeds): if self.enable_hr: @@ -521,14 +522,14 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): else: state.job_count = state.job_count * 2 - desired_pixel_count = self.first_pass_width * self.first_pass_height - actual_pixel_count = self.width * self.height - scale = math.sqrt(desired_pixel_count / actual_pixel_count) + #desired_pixel_count = self.firstphase_width * self.firstphase_height + #actual_pixel_count = self.width * self.height + #scale = math.sqrt(desired_pixel_count / actual_pixel_count) - self.firstphase_width = math.ceil(scale * self.width / 64) * 64 - self.firstphase_height = math.ceil(scale * self.height / 64) * 64 - self.firstphase_width_truncated = int(scale * self.width) - self.firstphase_height_truncated = int(scale * self.height) + #self.firstphase_width = math.ceil(scale * self.width / 64) * 64 + #self.firstphase_height = math.ceil(scale * self.height / 64) * 64 + #self.firstphase_width_truncated = int(scale * self.width) + #self.firstphase_height_truncated = int(scale * self.height) def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength): self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model) @@ -541,8 +542,17 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): x = create_random_tensors([opt_C, self.firstphase_height // opt_f, self.firstphase_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) - truncate_x = (self.firstphase_width - self.firstphase_width_truncated) // opt_f - truncate_y = (self.firstphase_height - self.firstphase_height_truncated) // opt_f + truncate_x = 0 + truncate_y = 0 + + if self.crop_scale: + if self.width/self.firstphase_width > self.height/self.firstphase_height: + #Crop to landscape + truncate_y = (self.width - self.firstphase_width)//2 // opt_f + + elif self.width/self.firstphase_width < self.height/self.firstphase_height: + #Crop to portrait + truncate_x = (self.height - self.firstphase_height)//2 // opt_f samples = samples[:, :, truncate_y//2:samples.shape[2]-truncate_y//2, truncate_x//2:samples.shape[3]-truncate_x//2] diff --git a/modules/txt2img.py b/modules/txt2img.py index 85cbece4d..447ec3d3f 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -6,7 +6,7 @@ import modules.processing as processing from modules.ui import plaintext_to_html -def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, scale_latent: bool, denoising_strength: float, first_pass_width: int, first_pass_height: int, *args): +def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, scale_latent: bool, denoising_strength: float, firstphase_width: int, firstphase_height: int, crop_scale: bool, *args): p = StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples, @@ -32,8 +32,9 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: enable_hr=enable_hr, scale_latent=scale_latent if enable_hr else None, denoising_strength=denoising_strength if enable_hr else None, - first_pass_width=first_pass_width if enable_hr else None, - first_pass_height=first_pass_height if enable_hr else None, + firstphase_width=firstphase_width if enable_hr else None, + firstphase_height=firstphase_height if enable_hr else None, + crop_scale=crop_scale if enable_hr else None, ) diff --git a/modules/ui.py b/modules/ui.py index 544419b25..f2d81f687 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -540,12 +540,18 @@ def create_ui(wrap_gradio_gpu_call): enable_hr = gr.Checkbox(label='Highres. fix', value=False) with gr.Row(visible=False) as hr_options: - first_pass_width = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass width", value=512) - first_pass_height = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass height", value=512) - scale_latent = gr.Checkbox(label='Scale latent', value=False) - denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) + with gr.Column(scale=1.0): + firstphase_width = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass width", value=512) + firstphase_height = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass height", value=512) + + with gr.Column(scale=1.0): + with gr.Row(): + crop_scale = gr.Checkbox(label='Crop when scaling', value=False) + scale_latent = gr.Checkbox(label='Scale latent', value=False) + with gr.Row(): + denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) - with gr.Row(): + with gr.Row(equal_height=True): batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1) batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1) @@ -606,8 +612,9 @@ def create_ui(wrap_gradio_gpu_call): enable_hr, scale_latent, denoising_strength, - first_pass_width, - first_pass_height, + firstphase_width, + firstphase_height, + crop_scale, ] + custom_inputs, outputs=[ txt2img_gallery, @@ -672,8 +679,8 @@ def create_ui(wrap_gradio_gpu_call): (denoising_strength, "Denoising strength"), (enable_hr, lambda d: "Denoising strength" in d), (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)), - (first_pass_width, "First pass width"), - (first_pass_height, "First pass height"), + (firstphase_width, "First pass width"), + (firstphase_height, "First pass height"), ] modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt) token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) From b382de2d77c653c565840ce92d27aa668a1934d7 Mon Sep 17 00:00:00 2001 From: Buckzor Date: Thu, 13 Oct 2022 22:23:22 +0100 Subject: [PATCH 416/460] Fixed Scale ratio problem --- modules/processing.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 0246f5dd6..d9b0e0e72 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -522,15 +522,6 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): else: state.job_count = state.job_count * 2 - #desired_pixel_count = self.firstphase_width * self.firstphase_height - #actual_pixel_count = self.width * self.height - #scale = math.sqrt(desired_pixel_count / actual_pixel_count) - - #self.firstphase_width = math.ceil(scale * self.width / 64) * 64 - #self.firstphase_height = math.ceil(scale * self.height / 64) * 64 - #self.firstphase_width_truncated = int(scale * self.width) - #self.firstphase_height_truncated = int(scale * self.height) - def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength): self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model) @@ -544,17 +535,23 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): truncate_x = 0 truncate_y = 0 + width_ratio = self.width/self.firstphase_width + height_ratio = self.height/self.firstphase_height if self.crop_scale: - if self.width/self.firstphase_width > self.height/self.firstphase_height: + if width_ratio > height_ratio: #Crop to landscape - truncate_y = (self.width - self.firstphase_width)//2 // opt_f + truncate_y = int((self.width - self.firstphase_width) / width_ratio / height_ratio / opt_f) - elif self.width/self.firstphase_width < self.height/self.firstphase_height: + elif width_ratio < height_ratio: #Crop to portrait - truncate_x = (self.height - self.firstphase_height)//2 // opt_f + truncate_x = int((self.height - self.firstphase_height) / width_ratio / height_ratio / opt_f) + + samples = samples[:, :, truncate_y//2:samples.shape[2]-truncate_y//2, truncate_x//2:samples.shape[3]-truncate_x//2] - samples = samples[:, :, truncate_y//2:samples.shape[2]-truncate_y//2, truncate_x//2:samples.shape[3]-truncate_x//2] + + + if self.scale_latent: samples = torch.nn.functional.interpolate(samples, size=(self.height // opt_f, self.width // opt_f), mode="bilinear") From e644b5a80beb54b6df4caa63fb19d889dd4ceff6 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 17:03:03 +0300 Subject: [PATCH 417/460] remove scale latent and no-crop options from hires fix support copy-pasting new parameters for hires fix --- modules/processing.py | 60 ++++++++++++++++++------------------------- modules/txt2img.py | 9 +++---- modules/ui.py | 19 ++++---------- 3 files changed, 33 insertions(+), 55 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index d9b0e0e72..100a259f8 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -506,14 +506,12 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): firstphase_width_truncated = 0 firstphase_height_truncated = 0 - def __init__(self, enable_hr=False, scale_latent=True, denoising_strength=0.75, firstphase_width=512, firstphase_height=512, crop_scale=False, **kwargs): + def __init__(self, enable_hr=False, denoising_strength=0.75, firstphase_width=512, firstphase_height=512, **kwargs): super().__init__(**kwargs) self.enable_hr = enable_hr - self.scale_latent = scale_latent self.denoising_strength = denoising_strength self.firstphase_width = firstphase_width self.firstphase_height = firstphase_height - self.crop_scale = crop_scale def init(self, all_prompts, all_seeds, all_subseeds): if self.enable_hr: @@ -530,6 +528,8 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning) return samples + self.extra_generation_params["First pass size"] = f"{self.firstphase_width}x{self.firstphase_height}" + x = create_random_tensors([opt_C, self.firstphase_height // opt_f, self.firstphase_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) @@ -538,46 +538,36 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): width_ratio = self.width/self.firstphase_width height_ratio = self.height/self.firstphase_height - if self.crop_scale: - if width_ratio > height_ratio: - #Crop to landscape - truncate_y = int((self.width - self.firstphase_width) / width_ratio / height_ratio / opt_f) + if width_ratio > height_ratio: + truncate_y = int((self.width - self.firstphase_width) / width_ratio / height_ratio / opt_f) - elif width_ratio < height_ratio: - #Crop to portrait - truncate_x = int((self.height - self.firstphase_height) / width_ratio / height_ratio / opt_f) + elif width_ratio < height_ratio: + truncate_x = int((self.height - self.firstphase_height) / width_ratio / height_ratio / opt_f) - samples = samples[:, :, truncate_y//2:samples.shape[2]-truncate_y//2, truncate_x//2:samples.shape[3]-truncate_x//2] + samples = samples[:, :, truncate_y//2:samples.shape[2]-truncate_y//2, truncate_x//2:samples.shape[3]-truncate_x//2] - + decoded_samples = decode_first_stage(self.sd_model, samples) - - - if self.scale_latent: - samples = torch.nn.functional.interpolate(samples, size=(self.height // opt_f, self.width // opt_f), mode="bilinear") + if opts.upscaler_for_img2img is None or opts.upscaler_for_img2img == "None": + decoded_samples = torch.nn.functional.interpolate(decoded_samples, size=(self.height, self.width), mode="bilinear") else: - decoded_samples = decode_first_stage(self.sd_model, samples) + lowres_samples = torch.clamp((decoded_samples + 1.0) / 2.0, min=0.0, max=1.0) - if opts.upscaler_for_img2img is None or opts.upscaler_for_img2img == "None": - decoded_samples = torch.nn.functional.interpolate(decoded_samples, size=(self.height, self.width), mode="bilinear") - else: - lowres_samples = torch.clamp((decoded_samples + 1.0) / 2.0, min=0.0, max=1.0) + batch_images = [] + for i, x_sample in enumerate(lowres_samples): + x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2) + x_sample = x_sample.astype(np.uint8) + image = Image.fromarray(x_sample) + image = images.resize_image(0, image, self.width, self.height) + image = np.array(image).astype(np.float32) / 255.0 + image = np.moveaxis(image, 2, 0) + batch_images.append(image) - batch_images = [] - for i, x_sample in enumerate(lowres_samples): - x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2) - x_sample = x_sample.astype(np.uint8) - image = Image.fromarray(x_sample) - image = images.resize_image(0, image, self.width, self.height) - image = np.array(image).astype(np.float32) / 255.0 - image = np.moveaxis(image, 2, 0) - batch_images.append(image) + decoded_samples = torch.from_numpy(np.array(batch_images)) + decoded_samples = decoded_samples.to(shared.device) + decoded_samples = 2. * decoded_samples - 1. - decoded_samples = torch.from_numpy(np.array(batch_images)) - decoded_samples = decoded_samples.to(shared.device) - decoded_samples = 2. * decoded_samples - 1. - - samples = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(decoded_samples)) + samples = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(decoded_samples)) shared.state.nextjob() diff --git a/modules/txt2img.py b/modules/txt2img.py index 447ec3d3f..2381347f9 100644 --- a/modules/txt2img.py +++ b/modules/txt2img.py @@ -6,7 +6,7 @@ import modules.processing as processing from modules.ui import plaintext_to_html -def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, scale_latent: bool, denoising_strength: float, firstphase_width: int, firstphase_height: int, crop_scale: bool, *args): +def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: str, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, denoising_strength: float, firstphase_width: int, firstphase_height: int, *args): p = StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples, @@ -30,12 +30,9 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2: restore_faces=restore_faces, tiling=tiling, enable_hr=enable_hr, - scale_latent=scale_latent if enable_hr else None, denoising_strength=denoising_strength if enable_hr else None, - firstphase_width=firstphase_width if enable_hr else None, - firstphase_height=firstphase_height if enable_hr else None, - crop_scale=crop_scale if enable_hr else None, - + firstphase_width=firstphase_width if enable_hr else None, + firstphase_height=firstphase_height if enable_hr else None, ) if cmd_opts.enable_console_prompts: diff --git a/modules/ui.py b/modules/ui.py index f2d81f687..d66ddc142 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -540,16 +540,9 @@ def create_ui(wrap_gradio_gpu_call): enable_hr = gr.Checkbox(label='Highres. fix', value=False) with gr.Row(visible=False) as hr_options: - with gr.Column(scale=1.0): - firstphase_width = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass width", value=512) - firstphase_height = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass height", value=512) - - with gr.Column(scale=1.0): - with gr.Row(): - crop_scale = gr.Checkbox(label='Crop when scaling', value=False) - scale_latent = gr.Checkbox(label='Scale latent', value=False) - with gr.Row(): - denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) + firstphase_width = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass width", value=512) + firstphase_height = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass height", value=512) + denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) with gr.Row(equal_height=True): batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1) @@ -610,11 +603,9 @@ def create_ui(wrap_gradio_gpu_call): height, width, enable_hr, - scale_latent, denoising_strength, firstphase_width, firstphase_height, - crop_scale, ] + custom_inputs, outputs=[ txt2img_gallery, @@ -679,8 +670,8 @@ def create_ui(wrap_gradio_gpu_call): (denoising_strength, "Denoising strength"), (enable_hr, lambda d: "Denoising strength" in d), (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)), - (firstphase_width, "First pass width"), - (firstphase_height, "First pass height"), + (firstphase_width, "First pass size-1"), + (firstphase_height, "First pass size-2"), ] modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt) token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) From 33ae6be55eaedabd49c8c888ec0b37c612618fdf Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 17:53:34 +0300 Subject: [PATCH 418/460] fix paste not working in firefox fix paste always going into txt2img field --- javascript/dragdrop.js | 2 +- javascript/imageParams.js | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/javascript/dragdrop.js b/javascript/dragdrop.js index cf900f501..fe0185a50 100644 --- a/javascript/dragdrop.js +++ b/javascript/dragdrop.js @@ -43,7 +43,7 @@ function dropReplaceImage( imgWrap, files ) { window.document.addEventListener('dragover', e => { const target = e.composedPath()[0]; const imgWrap = target.closest('[data-testid="image"]'); - if ( !imgWrap ) { + if ( !imgWrap && target.placeholder != "Prompt") { return; } e.stopPropagation(); diff --git a/javascript/imageParams.js b/javascript/imageParams.js index f9d0c0aa8..4a7b0900a 100644 --- a/javascript/imageParams.js +++ b/javascript/imageParams.js @@ -2,21 +2,18 @@ window.onload = (function(){ window.addEventListener('drop', e => { const target = e.composedPath()[0]; const idx = selected_gallery_index(); - let prompt_target = "txt2img_prompt_image"; - if (idx === 1) { - prompt_target = "img2img_prompt_image"; - } - if (target.placeholder === "Prompt") { - e.stopPropagation(); - e.preventDefault(); - const imgParent = gradioApp().getElementById(prompt_target); - const files = e.dataTransfer.files; - const fileInput = imgParent.querySelector('input[type="file"]'); - if ( fileInput ) { - fileInput.files = files; - fileInput.dispatchEvent(new Event('change')); - } + if (target.placeholder != "Prompt") return; + + let prompt_target = get_tab_index('tabs') == 1 ? "img2img_prompt_image" : "txt2img_prompt_image"; + + e.stopPropagation(); + e.preventDefault(); + const imgParent = gradioApp().getElementById(prompt_target); + const files = e.dataTransfer.files; + const fileInput = imgParent.querySelector('input[type="file"]'); + if ( fileInput ) { + fileInput.files = files; + fileInput.dispatchEvent(new Event('change')); } }); - -}); \ No newline at end of file +}); From 0aec19d7837d8564355fdb286541db7165852e41 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 18:15:03 +0300 Subject: [PATCH 419/460] make pasting into img2img prompt work make image params request not use temp files --- modules/images.py | 34 +++++++++++++++++----------------- modules/ui.py | 9 +++------ 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/modules/images.py b/modules/images.py index f1155b7f4..68cdbc932 100644 --- a/modules/images.py +++ b/modules/images.py @@ -1,4 +1,5 @@ import datetime +import io import math import os from collections import namedtuple @@ -465,21 +466,20 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i return fullfn, txt_fullfn -def image_data(image_path): - file, ext = os.path.splitext(image_path.name) - data = {} - if "png" in ext: - image = Image.open(image_path.name, "r") - print(f"Image data requested for {image_path.name} {image.format} of {type(image)}") - try: - data = image.text["parameters"] - except Exception as e: - print(f"Exception: {e}") - pass - print(f"Image data: {data}") - if "txt" in ext: - myfile = open(image_path.name, 'r') - data = myfile.read() - myfile.close() +def image_data(data): + try: + image = Image.open(io.BytesIO(data)) + textinfo = image.text["parameters"] + return textinfo, None + except Exception: + pass - return data, None + try: + text = data.decode('utf8') + assert len(text) < 10000 + return text, None + + except Exception: + pass + + return '', None diff --git a/modules/ui.py b/modules/ui.py index 0a3ee887f..6266db492 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -514,7 +514,7 @@ def create_ui(wrap_gradio_gpu_call): with gr.Blocks(analytics_enabled=False) as txt2img_interface: txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) - txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="file", visible=False) + txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="bytes", visible=False) with gr.Row(elem_id='txt2img_progress_row'): with gr.Column(scale=1): @@ -620,7 +620,6 @@ def create_ui(wrap_gradio_gpu_call): txt_prompt_img.change( fn=modules.images.image_data, - # _js = "get_extras_tab_index", inputs=[ txt_prompt_img ], @@ -692,8 +691,7 @@ def create_ui(wrap_gradio_gpu_call): img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) with gr.Row(elem_id='img2img_progress_row'): - img2img_prompt_img = gr.File(label="", elem_id="txt_prompt_image", file_count="single", type="file", - visible=False) + img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="bytes", visible=False) with gr.Column(scale=1): pass @@ -791,9 +789,8 @@ def create_ui(wrap_gradio_gpu_call): img2img_prompt_img.change( fn=modules.images.image_data, - # _js = "get_extras_tab_index", inputs=[ - txt_prompt_img + img2img_prompt_img ], outputs=[ img2img_prompt, From 67f447ddcc8a17d11939c3801dca635dc22944c7 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 19:30:28 +0300 Subject: [PATCH 420/460] possibility to load checkpoint, clip skip, and hypernet from infotext --- modules/ui.py | 52 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index 6266db492..a37a4e179 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -22,7 +22,7 @@ import gradio as gr import gradio.utils import gradio.routes -from modules import sd_hijack +from modules import sd_hijack, sd_models from modules.paths import script_path from modules.shared import opts, cmd_opts if cmd_opts.deepdanbooru: @@ -507,12 +507,38 @@ def setup_progressbar(progressbar, preview, id_part, textinfo=None): ) +def apply_setting(key, value): + if value is None: + return gr.update() + + if key == "sd_model_checkpoint": + ckpt_info = sd_models.get_closet_checkpoint_match(value) + + if ckpt_info is not None: + value = ckpt_info.title + else: + return gr.update() + + comp_args = opts.data_labels[key].component_args + if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False: + return + + valtype = type(opts.data_labels[key].default) + oldval = opts.data[key] + opts.data[key] = valtype(value) if valtype != type(None) else value + if oldval != value and opts.data_labels[key].onchange is not None: + opts.data_labels[key].onchange() + + opts.save(shared.config_filename) + return value + + def create_ui(wrap_gradio_gpu_call): import modules.img2img import modules.txt2img with gr.Blocks(analytics_enabled=False) as txt2img_interface: - txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=False) + txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button = create_toprow(is_img2img=False) dummy_component = gr.Label(visible=False) txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="bytes", visible=False) @@ -684,11 +710,10 @@ def create_ui(wrap_gradio_gpu_call): (firstphase_width, "First pass size-1"), (firstphase_height, "First pass size-2"), ] - modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt) token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) with gr.Blocks(analytics_enabled=False) as img2img_interface: - img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True) + img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, token_counter, token_button = create_toprow(is_img2img=True) with gr.Row(elem_id='img2img_progress_row'): img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="bytes", visible=False) @@ -938,7 +963,6 @@ def create_ui(wrap_gradio_gpu_call): (seed_resize_from_h, "Seed resize from-2"), (denoising_strength, "Denoising strength"), ] - modules.generation_parameters_copypaste.connect_paste(paste, img2img_paste_fields, img2img_prompt) token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter]) with gr.Blocks(analytics_enabled=False) as extras_interface: @@ -1580,8 +1604,22 @@ Requested path was: {f} outputs=[extras_image], ) - modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_txt2img, txt2img_paste_fields, generation_info, 'switch_to_txt2img') - modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_img2img, img2img_paste_fields, generation_info, 'switch_to_img2img_img2img') + settings_map = { + 'sd_hypernetwork': 'Hypernet', + 'CLIP_stop_at_last_layers': 'Clip skip', + 'sd_model_checkpoint': 'Model hash', + } + + settings_paste_fields = [ + (component_dict[k], lambda d, k=k, v=v: apply_setting(k, d.get(v, None))) + for k, v in settings_map.items() + ] + + modules.generation_parameters_copypaste.connect_paste(txt2img_paste, txt2img_paste_fields + settings_paste_fields, txt2img_prompt) + modules.generation_parameters_copypaste.connect_paste(img2img_paste, img2img_paste_fields + settings_paste_fields, img2img_prompt) + + modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_txt2img, txt2img_paste_fields + settings_paste_fields, generation_info, 'switch_to_txt2img') + modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_img2img, img2img_paste_fields + settings_paste_fields, generation_info, 'switch_to_img2img_img2img') ui_config_file = cmd_opts.ui_config_file ui_settings = {} From 6c6427946087d761d548d97164594d914fdd9b78 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 19:33:49 +0300 Subject: [PATCH 421/460] remove user's liners from .gitigbore - those go into .git/info/exclude --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index a6f274956..69785b3e2 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,3 @@ __pycache__ notification.mp3 /SwinIR /textual_inversion -/images_history_testui.py -/repositorieslatent-diffusion From 2fb9891af3bb4c36a6de6b44937e927bda43c10d Mon Sep 17 00:00:00 2001 From: Gugubo <29143981+Gugubo@users.noreply.github.com> Date: Fri, 14 Oct 2022 14:19:39 +0200 Subject: [PATCH 422/460] Change grid row count autodetect to prevent empty spots Instead of just rounding (sometimes resulting in grids with "empty" spots), find a divisor. For example: 8 images will now result in a 4x2 grid instead of a 3x3 with one empty spot. --- modules/images.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/images.py b/modules/images.py index 68cdbc932..90eca37a5 100644 --- a/modules/images.py +++ b/modules/images.py @@ -25,8 +25,9 @@ def image_grid(imgs, batch_size=1, rows=None): elif opts.n_rows == 0: rows = batch_size else: - rows = math.sqrt(len(imgs)) - rows = round(rows) + rows = math.floor(math.sqrt(len(imgs))) + while len(imgs) % rows != 0: + rows -= 1 cols = math.ceil(len(imgs) / rows) From 43f926aad1b77a4bb642c1d173adfae1f56cf42d Mon Sep 17 00:00:00 2001 From: Gugubo <29143981+Gugubo@users.noreply.github.com> Date: Fri, 14 Oct 2022 17:06:51 +0200 Subject: [PATCH 423/460] Add option to prevent empty spots in grid (1/2) --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index b6a5c1a8c..159f504f1 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -175,6 +175,7 @@ options_templates.update(options_section(('saving-images', "Saving images/grids" "grid_format": OptionInfo('png', 'File format for grids'), "grid_extended_filename": OptionInfo(False, "Add extended info (seed, prompt) to filename when saving grid"), "grid_only_if_multiple": OptionInfo(True, "Do not save grids consisting of one picture"), + "grid_prevent_empty_spots": OptionInfo(False, "Prevent empty spots in grid (when set to autodetect)"), "n_rows": OptionInfo(-1, "Grid row count; use -1 for autodetect and 0 for it to be same as batch size", gr.Slider, {"minimum": -1, "maximum": 16, "step": 1}), "enable_pnginfo": OptionInfo(True, "Save text information about generation parameters as chunks to png files"), From 5f87dd1ee0960963e3f756c4ebe47652ff57f715 Mon Sep 17 00:00:00 2001 From: Gugubo <29143981+Gugubo@users.noreply.github.com> Date: Fri, 14 Oct 2022 17:07:24 +0200 Subject: [PATCH 424/460] Add option to prevent empty spots in grid (2/2) --- modules/images.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/images.py b/modules/images.py index 90eca37a5..b9589563a 100644 --- a/modules/images.py +++ b/modules/images.py @@ -24,10 +24,13 @@ def image_grid(imgs, batch_size=1, rows=None): rows = opts.n_rows elif opts.n_rows == 0: rows = batch_size - else: + elif opts.grid_prevent_empty_spots: rows = math.floor(math.sqrt(len(imgs))) while len(imgs) % rows != 0: rows -= 1 + else: + rows = math.sqrt(len(imgs)) + rows = round(rows) cols = math.ceil(len(imgs) / rows) From a8eeb2b7ad0c43ad60ac2ba8bd299b9cb265fdd3 Mon Sep 17 00:00:00 2001 From: Ljzd-PRO <63289359+Ljzd-PRO@users.noreply.github.com> Date: Thu, 13 Oct 2022 02:03:08 +0800 Subject: [PATCH 425/460] add `--lowram` parameter load models to VRM instead of RAM (for machines which have bigger VRM than RAM such as free Google Colab server) --- modules/shared.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/shared.py b/modules/shared.py index 159f504f1..cd4a4714a 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -34,6 +34,7 @@ parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_ parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui") parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage") parser.add_argument("--lowvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a lot of speed for very low VRM usage") +parser.add_argument("--lowram", action='store_true', help="load models to VRM instead of RAM (for machines which have bigger VRM than RAM such as free Google Colab server)") parser.add_argument("--always-batch-cond-uncond", action='store_true', help="disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram") parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.") parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast") From 4a216ded433ded315106e2989c5ff7dec1c49304 Mon Sep 17 00:00:00 2001 From: Ljzd-PRO <63289359+Ljzd-PRO@users.noreply.github.com> Date: Thu, 13 Oct 2022 02:07:49 +0800 Subject: [PATCH 426/460] load models to VRAM when using `--lowram` param load models to VRM instead of RAM (for machines which have bigger VRM than RAM such as free Google Colab server) --- modules/sd_models.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 0a55b4c32..78a198b9c 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -134,7 +134,12 @@ def load_model_weights(model, checkpoint_info): print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}") - pl_sd = torch.load(checkpoint_file, map_location="cpu") + if shared.cmd_opts.lowram: + print("Load to VRAM if GPU is available (low RAM)") + pl_sd = torch.load(checkpoint_file) + else: + pl_sd = torch.load(checkpoint_file, map_location="cpu") + if "global_step" in pl_sd: print(f"Global Step: {pl_sd['global_step']}") @@ -158,7 +163,13 @@ def load_model_weights(model, checkpoint_info): if os.path.exists(vae_file): print(f"Loading VAE weights from: {vae_file}") - vae_ckpt = torch.load(vae_file, map_location="cpu") + + if shared.cmd_opts.lowram: + print("Load to VRAM if GPU is available (low RAM)") + vae_ckpt = torch.load(vae_file) + else: + vae_ckpt = torch.load(vae_file, map_location="cpu") + vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} model.first_stage_model.load_state_dict(vae_dict) From bb295f54785ac36dc6aa6f7103a3431464440fc3 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 20:03:41 +0300 Subject: [PATCH 427/460] rework the code for lowram a bit --- modules/sd_models.py | 12 ++---------- modules/shared.py | 3 ++- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 78a198b9c..3a01c93d0 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -134,11 +134,7 @@ def load_model_weights(model, checkpoint_info): print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}") - if shared.cmd_opts.lowram: - print("Load to VRAM if GPU is available (low RAM)") - pl_sd = torch.load(checkpoint_file) - else: - pl_sd = torch.load(checkpoint_file, map_location="cpu") + pl_sd = torch.load(checkpoint_file, map_location=shared.weight_load_location) if "global_step" in pl_sd: print(f"Global Step: {pl_sd['global_step']}") @@ -164,11 +160,7 @@ def load_model_weights(model, checkpoint_info): if os.path.exists(vae_file): print(f"Loading VAE weights from: {vae_file}") - if shared.cmd_opts.lowram: - print("Load to VRAM if GPU is available (low RAM)") - vae_ckpt = torch.load(vae_file) - else: - vae_ckpt = torch.load(vae_file, map_location="cpu") + vae_ckpt = torch.load(vae_file, map_location=shared.weight_load_location) vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} diff --git a/modules/shared.py b/modules/shared.py index cd4a4714a..695d29b66 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -34,7 +34,7 @@ parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_ parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui") parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage") parser.add_argument("--lowvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a lot of speed for very low VRM usage") -parser.add_argument("--lowram", action='store_true', help="load models to VRM instead of RAM (for machines which have bigger VRM than RAM such as free Google Colab server)") +parser.add_argument("--lowram", action='store_true', help="load stable diffusion checkpoint weights to VRAM instead of RAM") parser.add_argument("--always-batch-cond-uncond", action='store_true', help="disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram") parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.") parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast") @@ -81,6 +81,7 @@ devices.device, devices.device_interrogate, devices.device_gfpgan, devices.devic (devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'bsrgan', 'esrgan', 'scunet', 'codeformer']) device = devices.device +weight_load_location = None if cmd_opts.lowram else "cpu" batch_cond_uncond = cmd_opts.always_batch_cond_uncond or not (cmd_opts.lowvram or cmd_opts.medvram) parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram From c344ba3b325459abbf9b0df2c1b18f7bf99805b2 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 20:31:49 +0300 Subject: [PATCH 428/460] add option to read generation params for learning previews from txt2img --- modules/hypernetworks/hypernetwork.py | 21 ++++++++++++---- .../textual_inversion/textual_inversion.py | 25 +++++++++++++------ modules/ui.py | 20 ++++++++++++--- 3 files changed, 51 insertions(+), 15 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index f1248bb7b..e5cb1817f 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -180,7 +180,7 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): return self.to_out(out) -def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_image_prompt): +def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): assert hypernetwork_name, 'hypernetwork not selected' path = shared.hypernetworks.get(hypernetwork_name, None) @@ -265,20 +265,31 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, if hypernetwork.step > 0 and images_dir is not None and hypernetwork.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{hypernetwork_name}-{hypernetwork.step}.png') - preview_text = entry.cond_text if preview_image_prompt == "" else preview_image_prompt - optimizer.zero_grad() shared.sd_model.cond_stage_model.to(devices.device) shared.sd_model.first_stage_model.to(devices.device) p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, - prompt=preview_text, - steps=20, do_not_save_grid=True, do_not_save_samples=True, ) + if preview_from_txt2img: + p.prompt = preview_prompt + p.negative_prompt = preview_negative_prompt + p.steps = preview_steps + p.sampler_index = preview_sampler_index + p.cfg_scale = preview_cfg_scale + p.seed = preview_seed + p.width = preview_width + p.height = preview_height + else: + p.prompt = entry.cond_text + p.steps = 20 + + preview_text = p.prompt + processed = processing.process_images(p) image = processed.images[0] if len(processed.images)>0 else None diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index fa0e33a2a..3d8353585 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -172,7 +172,7 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_image_prompt): +def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -259,18 +259,29 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini if embedding.step > 0 and images_dir is not None and embedding.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{embedding_name}-{embedding.step}.png') - preview_text = entry.cond_text if preview_image_prompt == "" else preview_image_prompt - p = processing.StableDiffusionProcessingTxt2Img( sd_model=shared.sd_model, - prompt=preview_text, - steps=20, - height=training_height, - width=training_width, do_not_save_grid=True, do_not_save_samples=True, ) + if preview_from_txt2img: + p.prompt = preview_prompt + p.negative_prompt = preview_negative_prompt + p.steps = preview_steps + p.sampler_index = preview_sampler_index + p.cfg_scale = preview_cfg_scale + p.seed = preview_seed + p.width = preview_width + p.height = preview_height + else: + p.prompt = entry.cond_text + p.steps = 20 + p.width = training_width + p.height = training_height + + preview_text = p.prompt + processed = processing.process_images(p) image = processed.images[0] diff --git a/modules/ui.py b/modules/ui.py index 828bfeea9..4a04c2cce 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -711,6 +711,18 @@ def create_ui(wrap_gradio_gpu_call): (firstphase_width, "First pass size-1"), (firstphase_height, "First pass size-2"), ] + + txt2img_preview_params = [ + txt2img_prompt, + txt2img_negative_prompt, + steps, + sampler_index, + cfg_scale, + seed, + width, + height, + ] + token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter]) with gr.Blocks(analytics_enabled=False) as img2img_interface: @@ -1162,7 +1174,7 @@ def create_ui(wrap_gradio_gpu_call): create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True) - preview_image_prompt = gr.Textbox(label='Preview prompt', value="") + preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False) with gr.Row(): interrupt_training = gr.Button(value="Interrupt") @@ -1240,7 +1252,8 @@ def create_ui(wrap_gradio_gpu_call): save_embedding_every, template_file, save_image_with_stored_embedding, - preview_image_prompt, + preview_from_txt2img, + *txt2img_preview_params, ], outputs=[ ti_output, @@ -1260,7 +1273,8 @@ def create_ui(wrap_gradio_gpu_call): create_image_every, save_embedding_every, template_file, - preview_image_prompt, + preview_from_txt2img, + *txt2img_preview_params, ], outputs=[ ti_output, From 6cdf55627cb4eb156fb7d8c010d396f93011c04e Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 21:12:52 +0300 Subject: [PATCH 429/460] restore borders for prompts --- style.css | 8 -------- 1 file changed, 8 deletions(-) diff --git a/style.css b/style.css index aa3d379c1..2306c0024 100644 --- a/style.css +++ b/style.css @@ -167,14 +167,6 @@ button{ align-self: stretch !important; } -#prompt, #negative_prompt{ - border: none !important; -} -#prompt textarea, #negative_prompt textarea{ - border: none !important; -} - - #img2maskimg .h-60{ height: 30rem; } From 2f0e089c7c8e1ad7d2ad658971c6fdec9622e3ab Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 21:20:28 +0300 Subject: [PATCH 430/460] should fix the issue with missing layers in chechpoint merger --- modules/extras.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/extras.py b/modules/extras.py index 532d869f5..2e7b37516 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -209,7 +209,12 @@ def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_nam for key in tqdm.tqdm(theta_0.keys()): if 'model' in key and key in theta_1: - theta_0[key] = theta_func(theta_0[key], theta_1[key], theta_2[key] if theta_2 else None, (float(1.0) - interp_amount)) # Need to reverse the interp_amount to match the desired mix ration in the merged checkpoint + t2 = (theta_2 or {}).get(key) + if t2 is None: + t2 = torch.zeros_like(theta_0[key]) + + theta_0[key] = theta_func(theta_0[key], theta_1[key], t2, (float(1.0) - interp_amount)) # Need to reverse the interp_amount to match the desired mix ration in the merged checkpoint + if save_as_half: theta_0[key] = theta_0[key].half() From 9b75ab144f5fa3669166374dacd5ffc340984078 Mon Sep 17 00:00:00 2001 From: ChucklesTheBeard Date: Thu, 13 Oct 2022 16:45:02 -0400 Subject: [PATCH 431/460] fix typo --- launch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.py b/launch.py index 16627a032..a7c5807b3 100644 --- a/launch.py +++ b/launch.py @@ -76,7 +76,7 @@ def git_clone(url, dir, name, commithash=None): return run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}") - run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commint for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}") + run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commit for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}") return run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}") From 02382f7ce462a360e8aea9ee3178da48b564f70a Mon Sep 17 00:00:00 2001 From: RnDMonkey Date: Wed, 12 Oct 2022 16:35:36 -0700 Subject: [PATCH 432/460] regression in xy_grid Var. seed fixing --- scripts/xy_grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index efb63af54..5700b0070 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -338,7 +338,7 @@ class Script(scripts.Script): ys = process_axis(y_opt, y_values) def fix_axis_seeds(axis_opt, axis_list): - if axis_opt.label == 'Seed': + if axis_opt.label in ['Seed','Var. seed']: return [int(random.randrange(4294967294)) if val is None or val == '' or val == -1 else val for val in axis_list] else: return axis_list From c250cb289c97fe303cef69064bf45899406f6a40 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 22:01:49 +0300 Subject: [PATCH 433/460] change checkpoint merger to work in a more obvious way remove sigmoid and inverse sigmoid because they just did the same thing as weighed sum only with changed multiplier --- javascript/hints.js | 4 ++-- modules/extras.py | 24 +++++------------------- modules/ui.py | 4 ++-- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/javascript/hints.js b/javascript/hints.js index af010a59d..8fec907d0 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -87,8 +87,8 @@ titles = { "Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply.", - "Weighted Sum": "Result = A * (1 - M) + B * M", - "Add difference": "Result = A + (B - C) * (1 - M)", + "Weighted sum": "Result = A * (1 - M) + B * M", + "Add difference": "Result = A + (B - C) * M", } diff --git a/modules/extras.py b/modules/extras.py index 2e7b37516..f2f5a7b04 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -159,24 +159,12 @@ def run_pnginfo(image): return '', geninfo, info -def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_name, interp_method, interp_amount, save_as_half, custom_name): - # Linear interpolation (https://en.wikipedia.org/wiki/Linear_interpolation) +def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_name, interp_method, multiplier, save_as_half, custom_name): def weighted_sum(theta0, theta1, theta2, alpha): return ((1 - alpha) * theta0) + (alpha * theta1) - # Smoothstep (https://en.wikipedia.org/wiki/Smoothstep) - def sigmoid(theta0, theta1, theta2, alpha): - alpha = alpha * alpha * (3 - (2 * alpha)) - return theta0 + ((theta1 - theta0) * alpha) - - # Inverse Smoothstep (https://en.wikipedia.org/wiki/Smoothstep) - def inv_sigmoid(theta0, theta1, theta2, alpha): - import math - alpha = 0.5 - math.sin(math.asin(1.0 - 2.0 * alpha) / 3.0) - return theta0 + ((theta1 - theta0) * alpha) - def add_difference(theta0, theta1, theta2, alpha): - return theta0 + (theta1 - theta2) * (1.0 - alpha) + return theta0 + (theta1 - theta2) * alpha primary_model_info = sd_models.checkpoints_list[primary_model_name] secondary_model_info = sd_models.checkpoints_list[secondary_model_name] @@ -198,9 +186,7 @@ def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_nam theta_2 = None theta_funcs = { - "Weighted Sum": weighted_sum, - "Sigmoid": sigmoid, - "Inverse Sigmoid": inv_sigmoid, + "Weighted sum": weighted_sum, "Add difference": add_difference, } theta_func = theta_funcs[interp_method] @@ -213,7 +199,7 @@ def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_nam if t2 is None: t2 = torch.zeros_like(theta_0[key]) - theta_0[key] = theta_func(theta_0[key], theta_1[key], t2, (float(1.0) - interp_amount)) # Need to reverse the interp_amount to match the desired mix ration in the merged checkpoint + theta_0[key] = theta_func(theta_0[key], theta_1[key], t2, multiplier) if save_as_half: theta_0[key] = theta_0[key].half() @@ -227,7 +213,7 @@ def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_nam ckpt_dir = shared.cmd_opts.ckpt_dir or sd_models.model_path - filename = primary_model_info.model_name + '_' + str(round(interp_amount, 2)) + '-' + secondary_model_info.model_name + '_' + str(round((float(1.0) - interp_amount), 2)) + '-' + interp_method.replace(" ", "_") + '-merged.ckpt' + filename = primary_model_info.model_name + '_' + str(round(1-multiplier, 2)) + '-' + secondary_model_info.model_name + '_' + str(round(multiplier, 2)) + '-' + interp_method.replace(" ", "_") + '-merged.ckpt' filename = filename if custom_name == '' else (custom_name + '.ckpt') output_modelname = os.path.join(ckpt_dir, filename) diff --git a/modules/ui.py b/modules/ui.py index 4a04c2cce..a08ffc9b5 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1101,8 +1101,8 @@ def create_ui(wrap_gradio_gpu_call): secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary model (B)") tertiary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model (C)") custom_name = gr.Textbox(label="Custom Name (Optional)") - interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation amount (1 - M)', value=0.3) - interp_method = gr.Radio(choices=["Weighted Sum", "Sigmoid", "Inverse Sigmoid", "Add difference"], value="Weighted Sum", label="Interpolation Method") + interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Multiplier (M) - set to 0 to get model A', value=0.3) + interp_method = gr.Radio(choices=["Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method") save_as_half = gr.Checkbox(value=False, label="Save as float16") modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary') From 4cc37e4cdf2ce5f5b753786b55ae1d4abd530c01 Mon Sep 17 00:00:00 2001 From: Naeaeaeaeae Date: Thu, 13 Oct 2022 18:49:58 +0200 Subject: [PATCH 434/460] [xy_grid.py] add option denoising_strength --- scripts/xy_grid.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 5700b0070..fda2b71d0 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -176,6 +176,7 @@ axis_options = [ AxisOption("Sigma noise", float, apply_field("s_noise"), format_value_add_label, None), AxisOption("Eta", float, apply_field("eta"), format_value_add_label, None), AxisOption("Clip skip", int, apply_clip_skip, format_value_add_label, None), + AxisOption("Denoising", float, apply_field("denoising_strength"), format_value_add_label, None), AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label, None), # as it is now all AxisOptionImg2Img items must go after AxisOption ones ] From 989a552de3d1fcd1f178fe873713b884e192dd61 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 22:04:08 +0300 Subject: [PATCH 435/460] remove the other Denoising --- scripts/xy_grid.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index fda2b71d0..8c7da6bb3 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -177,7 +177,6 @@ axis_options = [ AxisOption("Eta", float, apply_field("eta"), format_value_add_label, None), AxisOption("Clip skip", int, apply_clip_skip, format_value_add_label, None), AxisOption("Denoising", float, apply_field("denoising_strength"), format_value_add_label, None), - AxisOptionImg2Img("Denoising", float, apply_field("denoising_strength"), format_value_add_label, None), # as it is now all AxisOptionImg2Img items must go after AxisOption ones ] From 03d62538aebeff51713619fe808c953bdb70193d Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 22:43:55 +0300 Subject: [PATCH 436/460] remove duplicate code for log loss, add step, make it read from options rather than gradio input --- modules/hypernetworks/hypernetwork.py | 20 +++------ modules/shared.py | 3 +- .../textual_inversion/textual_inversion.py | 44 +++++++++++++------ modules/ui.py | 3 -- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index edb8cba12..59c7ac6ee 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -15,6 +15,7 @@ import torch from torch import einsum from einops import rearrange, repeat import modules.textual_inversion.dataset +from modules.textual_inversion import textual_inversion from modules.textual_inversion.learn_schedule import LearnRateScheduler @@ -210,7 +211,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=512, height=512, repeats=1, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=512, height=512, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True) if unload: shared.sd_model.cond_stage_model.to(devices.cpu) @@ -263,19 +264,10 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name}-{hypernetwork.step}.pt') hypernetwork.save(last_saved_file) - if write_csv_every > 0 and hypernetwork_dir is not None and hypernetwork.step % write_csv_every == 0: - write_csv_header = False if os.path.exists(os.path.join(hypernetwork_dir, "hypernetwork_loss.csv")) else True - - with open(os.path.join(hypernetwork_dir, "hypernetwork_loss.csv"), "a+") as fout: - - csv_writer = csv.DictWriter(fout, fieldnames=["step", "loss", "learn_rate"]) - - if write_csv_header: - csv_writer.writeheader() - - csv_writer.writerow({"step": hypernetwork.step, - "loss": f"{losses.mean():.7f}", - "learn_rate": scheduler.learn_rate}) + textual_inversion.write_loss(log_directory, "hypernetwork_loss.csv", hypernetwork.step, len(ds), { + "loss": f"{losses.mean():.7f}", + "learn_rate": scheduler.learn_rate + }) if hypernetwork.step > 0 and images_dir is not None and hypernetwork.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{hypernetwork_name}-{hypernetwork.step}.png') diff --git a/modules/shared.py b/modules/shared.py index 695d29b66..d41a7ab3a 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -236,7 +236,8 @@ options_templates.update(options_section(('training', "Training"), { "unload_models_when_training": OptionInfo(False, "Unload VAE and CLIP from VRAM when training"), "dataset_filename_word_regex": OptionInfo("", "Filename word regex"), "dataset_filename_join_string": OptionInfo(" ", "Filename join string"), - "training_image_repeats_per_epoch": OptionInfo(100, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), + "training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}), + "training_write_csv_every": OptionInfo(500, "Save an csv containing the loss to log directory every N steps, 0 to disable"), })) options_templates.update(options_section(('sd', "Stable Diffusion"), { diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index 1f5ace6f7..da0d77a0e 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -173,6 +173,32 @@ def create_embedding(name, num_vectors_per_token, init_text='*'): return fn +def write_loss(log_directory, filename, step, epoch_len, values): + if shared.opts.training_write_csv_every == 0: + return + + if step % shared.opts.training_write_csv_every != 0: + return + + write_csv_header = False if os.path.exists(os.path.join(log_directory, filename)) else True + + with open(os.path.join(log_directory, filename), "a+", newline='') as fout: + csv_writer = csv.DictWriter(fout, fieldnames=["step", "epoch", "epoch_step", *(values.keys())]) + + if write_csv_header: + csv_writer.writeheader() + + epoch = step // epoch_len + epoch_step = step - epoch * epoch_len + + csv_writer.writerow({ + "step": step + 1, + "epoch": epoch + 1, + "epoch_step": epoch_step + 1, + **values, + }) + + def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): assert embedding_name, 'embedding not selected' @@ -257,20 +283,10 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini last_saved_file = os.path.join(embedding_dir, f'{embedding_name}-{embedding.step}.pt') embedding.save(last_saved_file) - if write_csv_every > 0 and log_directory is not None and embedding.step % write_csv_every == 0: - write_csv_header = False if os.path.exists(os.path.join(log_directory, "textual_inversion_loss.csv")) else True - - with open(os.path.join(log_directory, "textual_inversion_loss.csv"), "a+") as fout: - - csv_writer = csv.DictWriter(fout, fieldnames=["epoch", "epoch_step", "loss", "learn_rate"]) - - if write_csv_header: - csv_writer.writeheader() - - csv_writer.writerow({"epoch": epoch_num + 1, - "epoch_step": epoch_step - 1, - "loss": f"{losses.mean():.7f}", - "learn_rate": scheduler.learn_rate}) + write_loss(log_directory, "textual_inversion_loss.csv", embedding.step, len(ds), { + "loss": f"{losses.mean():.7f}", + "learn_rate": scheduler.learn_rate + }) if embedding.step > 0 and images_dir is not None and embedding.step % create_image_every == 0: last_saved_image = os.path.join(images_dir, f'{embedding_name}-{embedding.step}.png') diff --git a/modules/ui.py b/modules/ui.py index be4a43a7e..a08ffc9b5 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1172,7 +1172,6 @@ def create_ui(wrap_gradio_gpu_call): training_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512) steps = gr.Number(label='Max steps', value=100000, precision=0) create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0) - write_csv_every = gr.Number(label='Save an csv containing the loss to log directory every N steps, 0 to disable', value=500, precision=0) save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0) save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True) preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False) @@ -1251,7 +1250,6 @@ def create_ui(wrap_gradio_gpu_call): steps, create_image_every, save_embedding_every, - write_csv_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, @@ -1274,7 +1272,6 @@ def create_ui(wrap_gradio_gpu_call): steps, create_image_every, save_embedding_every, - write_csv_every, template_file, preview_from_txt2img, *txt2img_preview_params, From e21f01f64504bc651da6e85216474bbd35ee010d Mon Sep 17 00:00:00 2001 From: Rae Fu Date: Thu, 13 Oct 2022 23:00:38 -0600 Subject: [PATCH 437/460] add checkpoint cache option to UI for faster model switching switching time reduced from ~1500ms to ~280ms --- modules/sd_models.py | 54 ++++++++++++++++++++++++++------------------ modules/shared.py | 1 + 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 0a55b4c32..f3660d8df 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -1,4 +1,4 @@ -import glob +import collections import os.path import sys from collections import namedtuple @@ -15,6 +15,7 @@ model_path = os.path.abspath(os.path.join(models_path, model_dir)) CheckpointInfo = namedtuple("CheckpointInfo", ['filename', 'title', 'hash', 'model_name', 'config']) checkpoints_list = {} +checkpoints_loaded = collections.OrderedDict() try: # this silences the annoying "Some weights of the model checkpoint were not used when initializing..." message at start. @@ -132,38 +133,46 @@ def load_model_weights(model, checkpoint_info): checkpoint_file = checkpoint_info.filename sd_model_hash = checkpoint_info.hash - print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}") + if checkpoint_info not in checkpoints_loaded: + print(f"Loading weights [{sd_model_hash}] from {checkpoint_file}") - pl_sd = torch.load(checkpoint_file, map_location="cpu") - if "global_step" in pl_sd: - print(f"Global Step: {pl_sd['global_step']}") + pl_sd = torch.load(checkpoint_file, map_location="cpu") + if "global_step" in pl_sd: + print(f"Global Step: {pl_sd['global_step']}") - sd = get_state_dict_from_checkpoint(pl_sd) + sd = get_state_dict_from_checkpoint(pl_sd) + model.load_state_dict(sd, strict=False) - model.load_state_dict(sd, strict=False) + if shared.cmd_opts.opt_channelslast: + model.to(memory_format=torch.channels_last) - if shared.cmd_opts.opt_channelslast: - model.to(memory_format=torch.channels_last) + if not shared.cmd_opts.no_half: + model.half() - if not shared.cmd_opts.no_half: - model.half() + devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16 + devices.dtype_vae = torch.float32 if shared.cmd_opts.no_half or shared.cmd_opts.no_half_vae else torch.float16 - devices.dtype = torch.float32 if shared.cmd_opts.no_half else torch.float16 - devices.dtype_vae = torch.float32 if shared.cmd_opts.no_half or shared.cmd_opts.no_half_vae else torch.float16 + vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt" - vae_file = os.path.splitext(checkpoint_file)[0] + ".vae.pt" + if not os.path.exists(vae_file) and shared.cmd_opts.vae_path is not None: + vae_file = shared.cmd_opts.vae_path - if not os.path.exists(vae_file) and shared.cmd_opts.vae_path is not None: - vae_file = shared.cmd_opts.vae_path + if os.path.exists(vae_file): + print(f"Loading VAE weights from: {vae_file}") + vae_ckpt = torch.load(vae_file, map_location="cpu") + vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} - if os.path.exists(vae_file): - print(f"Loading VAE weights from: {vae_file}") - vae_ckpt = torch.load(vae_file, map_location="cpu") - vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"} + model.first_stage_model.load_state_dict(vae_dict) - model.first_stage_model.load_state_dict(vae_dict) + model.first_stage_model.to(devices.dtype_vae) - model.first_stage_model.to(devices.dtype_vae) + checkpoints_loaded[checkpoint_info] = model.state_dict().copy() + while len(checkpoints_loaded) > shared.opts.sd_checkpoint_cache: + checkpoints_loaded.popitem(last=False) # LRU + else: + print(f"Loading weights [{sd_model_hash}] from cache") + checkpoints_loaded.move_to_end(checkpoint_info) + model.load_state_dict(checkpoints_loaded[checkpoint_info]) model.sd_model_hash = sd_model_hash model.sd_model_checkpoint = checkpoint_file @@ -202,6 +211,7 @@ def reload_model_weights(sd_model, info=None): return if sd_model.sd_checkpoint_info.config != checkpoint_info.config: + checkpoints_loaded.clear() shared.sd_model = load_model() return shared.sd_model diff --git a/modules/shared.py b/modules/shared.py index 5901e6056..b2090da17 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -238,6 +238,7 @@ options_templates.update(options_section(('training', "Training"), { options_templates.update(options_section(('sd', "Stable Diffusion"), { "sd_model_checkpoint": OptionInfo(None, "Stable Diffusion checkpoint", gr.Dropdown, lambda: {"choices": modules.sd_models.checkpoint_tiles()}, refresh=sd_models.list_models), + "sd_checkpoint_cache": OptionInfo(0, "Checkpoints to cache in RAM", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}), "sd_hypernetwork": OptionInfo("None", "Hypernetwork", gr.Dropdown, lambda: {"choices": ["None"] + [x for x in hypernetworks.keys()]}, refresh=reload_hypernetworks), "sd_hypernetwork_strength": OptionInfo(1.0, "Hypernetwork strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.001}), "img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."), From cd58e44051f658f2efb544203a92837f43786372 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 23:17:28 +0300 Subject: [PATCH 438/460] disabling history - i knew it was slow as fuck but i didn't realize it would also show galleries on launch --- modules/ui.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index a08ffc9b5..6d1939557 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1089,7 +1089,8 @@ def create_ui(wrap_gradio_gpu_call): "t2i":txt2img_paste_fields, "i2i":img2img_paste_fields } - images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict) + + #images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict) with gr.Blocks() as modelmerger_interface: with gr.Row().style(equal_height=False): @@ -1486,7 +1487,7 @@ Requested path was: {f} (img2img_interface, "img2img", "img2img"), (extras_interface, "Extras", "extras"), (pnginfo_interface, "PNG Info", "pnginfo"), - (images_history, "History", "images_history"), + #(images_history, "History", "images_history"), (modelmerger_interface, "Checkpoint Merger", "modelmerger"), (train_interface, "Train", "ti"), (settings_interface, "Settings", "settings"), From 368f4cc4c73509c1968cd9defe068d8bf4ff7c4f Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Fri, 14 Oct 2022 23:19:05 +0300 Subject: [PATCH 439/460] set firstpass w/h to 0 by default and rever to old behavior when any are 0 --- modules/processing.py | 49 ++++++++++++++++++++++++++----------------- modules/ui.py | 4 ++-- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/modules/processing.py b/modules/processing.py index 100a259f8..a75b9f847 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -501,17 +501,15 @@ def process_images(p: StableDiffusionProcessing) -> Processed: class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): sampler = None - firstphase_width = 0 - firstphase_height = 0 - firstphase_width_truncated = 0 - firstphase_height_truncated = 0 - def __init__(self, enable_hr=False, denoising_strength=0.75, firstphase_width=512, firstphase_height=512, **kwargs): + def __init__(self, enable_hr=False, denoising_strength=0.75, firstphase_width=0, firstphase_height=0, **kwargs): super().__init__(**kwargs) self.enable_hr = enable_hr self.denoising_strength = denoising_strength self.firstphase_width = firstphase_width self.firstphase_height = firstphase_height + self.truncate_x = 0 + self.truncate_y = 0 def init(self, all_prompts, all_seeds, all_subseeds): if self.enable_hr: @@ -520,6 +518,32 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): else: state.job_count = state.job_count * 2 + if self.firstphase_width == 0 or self.firstphase_height == 0: + desired_pixel_count = 512 * 512 + actual_pixel_count = self.width * self.height + scale = math.sqrt(desired_pixel_count / actual_pixel_count) + self.firstphase_width = math.ceil(scale * self.width / 64) * 64 + self.firstphase_height = math.ceil(scale * self.height / 64) * 64 + firstphase_width_truncated = int(scale * self.width) + firstphase_height_truncated = int(scale * self.height) + + else: + self.extra_generation_params["First pass size"] = f"{self.firstphase_width}x{self.firstphase_height}" + + width_ratio = self.width / self.firstphase_width + height_ratio = self.height / self.firstphase_height + + if width_ratio > height_ratio: + firstphase_width_truncated = self.firstphase_width + firstphase_height_truncated = self.firstphase_width * self.height / self.width + else: + firstphase_width_truncated = self.firstphase_height * self.width / self.height + firstphase_height_truncated = self.firstphase_height + + self.truncate_x = int(self.firstphase_width - firstphase_width_truncated) // opt_f + self.truncate_y = int(self.firstphase_height - firstphase_height_truncated) // opt_f + + def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength): self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model) @@ -528,23 +552,10 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning) return samples - self.extra_generation_params["First pass size"] = f"{self.firstphase_width}x{self.firstphase_height}" - x = create_random_tensors([opt_C, self.firstphase_height // opt_f, self.firstphase_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) - truncate_x = 0 - truncate_y = 0 - width_ratio = self.width/self.firstphase_width - height_ratio = self.height/self.firstphase_height - - if width_ratio > height_ratio: - truncate_y = int((self.width - self.firstphase_width) / width_ratio / height_ratio / opt_f) - - elif width_ratio < height_ratio: - truncate_x = int((self.height - self.firstphase_height) / width_ratio / height_ratio / opt_f) - - samples = samples[:, :, truncate_y//2:samples.shape[2]-truncate_y//2, truncate_x//2:samples.shape[3]-truncate_x//2] + samples = samples[:, :, self.truncate_y//2:samples.shape[2]-self.truncate_y//2, self.truncate_x//2:samples.shape[3]-self.truncate_x//2] decoded_samples = decode_first_stage(self.sd_model, samples) diff --git a/modules/ui.py b/modules/ui.py index 6d1939557..a1d18be91 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -567,8 +567,8 @@ def create_ui(wrap_gradio_gpu_call): enable_hr = gr.Checkbox(label='Highres. fix', value=False) with gr.Row(visible=False) as hr_options: - firstphase_width = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass width", value=512) - firstphase_height = gr.Slider(minimum=64, maximum=1024, step=64, label="First pass height", value=512) + firstphase_width = gr.Slider(minimum=0, maximum=1024, step=64, label="First pass width", value=0) + firstphase_height = gr.Slider(minimum=0, maximum=1024, step=64, label="First pass height", value=0) denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) with gr.Row(equal_height=True): From 4d19f3b7d461fe0f63e7ccff936909b0ce0c6126 Mon Sep 17 00:00:00 2001 From: Melan Date: Fri, 14 Oct 2022 22:45:26 +0200 Subject: [PATCH 440/460] Raise an assertion error if no training images have been found. --- modules/textual_inversion/dataset.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index 67e90afeb..12e2f43b0 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -81,7 +81,8 @@ class PersonalizedBase(Dataset): entry.cond = cond_model([entry.cond_text]).to(devices.cpu) self.dataset.append(entry) - + + assert len(self.dataset) > 1, "No images have been found in the dataset." self.length = len(self.dataset) * repeats self.initial_indexes = np.arange(self.length) % len(self.dataset) From 4dc426509918e90bf4557ecfd1f84031362360c0 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 15 Oct 2022 00:21:48 +0300 Subject: [PATCH 441/460] rename firstpass w/h to discard old user settings --- modules/ui.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ui.py b/modules/ui.py index a1d18be91..c5d295eaa 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -567,8 +567,8 @@ def create_ui(wrap_gradio_gpu_call): enable_hr = gr.Checkbox(label='Highres. fix', value=False) with gr.Row(visible=False) as hr_options: - firstphase_width = gr.Slider(minimum=0, maximum=1024, step=64, label="First pass width", value=0) - firstphase_height = gr.Slider(minimum=0, maximum=1024, step=64, label="First pass height", value=0) + firstphase_width = gr.Slider(minimum=0, maximum=1024, step=64, label="Firstpass width", value=0) + firstphase_height = gr.Slider(minimum=0, maximum=1024, step=64, label="Firstpass height", value=0) denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7) with gr.Row(equal_height=True): From 4bbe5d62e042e78cfe1dc83492c2398a39a2455c Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 15 Oct 2022 00:25:09 +0300 Subject: [PATCH 442/460] reformat lines in images_history.py --- modules/images_history.py | 174 ++++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 80 deletions(-) diff --git a/modules/images_history.py b/modules/images_history.py index 723f5301c..f5ef44fe0 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -1,5 +1,7 @@ import os import shutil + + def traverse_all_files(output_dir, image_list, curr_dir=None): curr_path = output_dir if curr_dir is None else os.path.join(output_dir, curr_dir) try: @@ -16,10 +18,10 @@ def traverse_all_files(output_dir, image_list, curr_dir=None): elif os.path.isfile(file_path) and file[-10:].rfind(".") > 0: image_list.append(file) else: - image_list = traverse_all_files(output_dir, image_list, file) + image_list = traverse_all_files(output_dir, image_list, file) return image_list - + def get_recent_images(dir_name, page_index, step, image_index, tabname): page_index = int(page_index) f_list = os.listdir(dir_name) @@ -27,36 +29,48 @@ def get_recent_images(dir_name, page_index, step, image_index, tabname): image_list = traverse_all_files(dir_name, image_list) image_list = sorted(image_list, key=lambda file: -os.path.getctime(os.path.join(dir_name, file))) num = 48 if tabname != "extras" else 12 - max_page_index = len(image_list) // num + 1 + max_page_index = len(image_list) // num + 1 page_index = max_page_index if page_index == -1 else page_index + step - page_index = 1 if page_index < 1 else page_index + page_index = 1 if page_index < 1 else page_index page_index = max_page_index if page_index > max_page_index else page_index idx_frm = (page_index - 1) * num image_list = image_list[idx_frm:idx_frm + num] image_index = int(image_index) - if image_index < 0 or image_index > len(image_list) - 1: - current_file = None + if image_index < 0 or image_index > len(image_list) - 1: + current_file = None hidden = None else: - current_file = image_list[int(image_index)] + current_file = image_list[int(image_index)] hidden = os.path.join(dir_name, current_file) return [os.path.join(dir_name, file) for file in image_list], page_index, image_list, current_file, hidden, "" + def first_page_click(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, 1, 0, image_index, tabname) + + def end_page_click(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, -1, 0, image_index, tabname) + + def prev_page_click(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, page_index, -1, image_index, tabname) -def next_page_click(dir_name, page_index, image_index, tabname): + + +def next_page_click(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, page_index, 1, image_index, tabname) -def page_index_change(dir_name, page_index, image_index, tabname): + + +def page_index_change(dir_name, page_index, image_index, tabname): return get_recent_images(dir_name, page_index, 0, image_index, tabname) + def show_image_info(num, image_path, filenames): - #print(f"select image {num}") + # print(f"select image {num}") file = filenames[int(num)] return file, num, os.path.join(image_path, file) + + def delete_image(delete_num, tabname, dir_name, name, page_index, filenames, image_index): if name == "": return filenames, delete_num @@ -66,14 +80,14 @@ def delete_image(delete_num, tabname, dir_name, name, page_index, filenames, ima i = 0 new_file_list = [] for name in filenames: - if i >= index and i < index + delete_num: + if i >= index and i < index + delete_num: path = os.path.join(dir_name, name) - if os.path.exists(path): + if os.path.exists(path): print(f"Delete file {path}") os.remove(path) - txt_file = os.path.splitext(path)[0] + ".txt" + txt_file = os.path.splitext(path)[0] + ".txt" if os.path.exists(txt_file): - os.remove(txt_file) + os.remove(txt_file) else: print(f"Not exists file {path}") else: @@ -81,81 +95,81 @@ def delete_image(delete_num, tabname, dir_name, name, page_index, filenames, ima i += 1 return new_file_list, 1 + def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): - if tabname == "txt2img": - dir_name = opts.outdir_txt2img_samples - elif tabname == "img2img": - dir_name = opts.outdir_img2img_samples - elif tabname == "extras": - dir_name = opts.outdir_extras_samples - d = dir_name.split("/") - dir_name = d[0] - for p in d[1:]: - dir_name = os.path.join(dir_name, p) - with gr.Row(): - renew_page = gr.Button('Renew Page', elem_id=tabname + "_images_history_renew_page") - first_page = gr.Button('First Page') - prev_page = gr.Button('Prev Page') - page_index = gr.Number(value=1, label="Page Index") - next_page = gr.Button('Next Page') - end_page = gr.Button('End Page') - with gr.Row(elem_id=tabname + "_images_history"): - with gr.Row(): - with gr.Column(scale=2): - history_gallery = gr.Gallery(show_label=False, elem_id=tabname + "_images_history_gallery").style(grid=6) - with gr.Row(): - delete_num = gr.Number(value=1, interactive=True, label="number of images to delete consecutively next") - delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") - with gr.Column(): - with gr.Row(): - pnginfo_send_to_txt2img = gr.Button('Send to txt2img') - pnginfo_send_to_img2img = gr.Button('Send to img2img') - with gr.Row(): - with gr.Column(): - img_file_info = gr.Textbox(label="Generate Info", interactive=False) - img_file_name = gr.Textbox(label="File Name", interactive=False) - with gr.Row(): - # hiden items + if tabname == "txt2img": + dir_name = opts.outdir_txt2img_samples + elif tabname == "img2img": + dir_name = opts.outdir_img2img_samples + elif tabname == "extras": + dir_name = opts.outdir_extras_samples + d = dir_name.split("/") + dir_name = d[0] + for p in d[1:]: + dir_name = os.path.join(dir_name, p) + with gr.Row(): + renew_page = gr.Button('Renew Page', elem_id=tabname + "_images_history_renew_page") + first_page = gr.Button('First Page') + prev_page = gr.Button('Prev Page') + page_index = gr.Number(value=1, label="Page Index") + next_page = gr.Button('Next Page') + end_page = gr.Button('End Page') + with gr.Row(elem_id=tabname + "_images_history"): + with gr.Row(): + with gr.Column(scale=2): + history_gallery = gr.Gallery(show_label=False, elem_id=tabname + "_images_history_gallery").style(grid=6) + with gr.Row(): + delete_num = gr.Number(value=1, interactive=True, label="number of images to delete consecutively next") + delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button") + with gr.Column(): + with gr.Row(): + pnginfo_send_to_txt2img = gr.Button('Send to txt2img') + pnginfo_send_to_img2img = gr.Button('Send to img2img') + with gr.Row(): + with gr.Column(): + img_file_info = gr.Textbox(label="Generate Info", interactive=False) + img_file_name = gr.Textbox(label="File Name", interactive=False) + with gr.Row(): + # hiden items - img_path = gr.Textbox(dir_name.rstrip("/") , visible=False) - tabname_box = gr.Textbox(tabname, visible=False) - image_index = gr.Textbox(value=-1, visible=False) - set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False) - filenames = gr.State() - hidden = gr.Image(type="pil", visible=False) - info1 = gr.Textbox(visible=False) - info2 = gr.Textbox(visible=False) + img_path = gr.Textbox(dir_name.rstrip("/"), visible=False) + tabname_box = gr.Textbox(tabname, visible=False) + image_index = gr.Textbox(value=-1, visible=False) + set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False) + filenames = gr.State() + hidden = gr.Image(type="pil", visible=False) + info1 = gr.Textbox(visible=False) + info2 = gr.Textbox(visible=False) - - # turn pages - gallery_inputs = [img_path, page_index, image_index, tabname_box] - gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hidden, img_file_name] + # turn pages + gallery_inputs = [img_path, page_index, image_index, tabname_box] + gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hidden, img_file_name] + + first_page.click(first_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + next_page.click(next_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + prev_page.click(prev_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + end_page.click(end_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + page_index.submit(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + renew_page.click(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) + # page_index.change(page_index_change, inputs=[tabname_box, img_path, page_index], outputs=[history_gallery, page_index]) + + # other funcitons + set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hidden]) + img_file_name.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) + delete.click(delete_image, _js="images_history_delete", inputs=[delete_num, tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[filenames, delete_num]) + hidden.change(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2]) + + # pnginfo.click(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2]) + switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') + switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') - first_page.click(first_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) - next_page.click(next_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) - prev_page.click(prev_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) - end_page.click(end_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) - page_index.submit(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) - renew_page.click(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs) - #page_index.change(page_index_change, inputs=[tabname_box, img_path, page_index], outputs=[history_gallery, page_index]) - #other funcitons - set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hidden]) - img_file_name.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None) - delete.click(delete_image,_js="images_history_delete", inputs=[delete_num, tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[filenames, delete_num]) - hidden.change(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2]) - - #pnginfo.click(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2]) - switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img') - switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img') - - def create_history_tabs(gr, opts, run_pnginfo, switch_dict): with gr.Blocks(analytics_enabled=False) as images_history: with gr.Tabs() as tabs: with gr.Tab("txt2img history"): - with gr.Blocks(analytics_enabled=False) as images_history_txt2img: - show_images_history(gr, opts, "txt2img", run_pnginfo, switch_dict) + with gr.Blocks(analytics_enabled=False) as images_history_txt2img: + show_images_history(gr, opts, "txt2img", run_pnginfo, switch_dict) with gr.Tab("img2img history"): with gr.Blocks(analytics_enabled=False) as images_history_img2img: show_images_history(gr, opts, "img2img", run_pnginfo, switch_dict) From a8f7722e4e7460122b44589c3718eee0c597009d Mon Sep 17 00:00:00 2001 From: space-nuko <24979496+space-nuko@users.noreply.github.com> Date: Fri, 14 Oct 2022 14:26:38 -0700 Subject: [PATCH 443/460] Fix XY-plot steps if highres fix is enabled --- scripts/xy_grid.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py index 8c7da6bb3..88ad3bf78 100644 --- a/scripts/xy_grid.py +++ b/scripts/xy_grid.py @@ -12,7 +12,7 @@ import gradio as gr from modules import images from modules.hypernetworks import hypernetwork -from modules.processing import process_images, Processed, get_correct_sampler +from modules.processing import process_images, Processed, get_correct_sampler, StableDiffusionProcessingTxt2Img from modules.shared import opts, cmd_opts, state import modules.shared as shared import modules.sd_samplers @@ -354,6 +354,9 @@ class Script(scripts.Script): else: total_steps = p.steps * len(xs) * len(ys) + if isinstance(p, StableDiffusionProcessingTxt2Img) and p.enable_hr: + total_steps *= 2 + print(f"X/Y plot will create {len(xs) * len(ys) * p.n_iter} images on a {len(xs)}x{len(ys)} grid. (Total steps to process: {total_steps * p.n_iter})") shared.total_tqdm.updateTotal(total_steps * p.n_iter) From acedbe67d2b8a3af99ca3b9a2f809e7a2db285d1 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 15 Oct 2022 00:43:15 +0300 Subject: [PATCH 444/460] bring history tab back, make it behave; it's still slow but won't fuck anything up until you use it --- javascript/images_history.js | 16 ++++++++++++---- modules/ui.py | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/javascript/images_history.js b/javascript/images_history.js index 3a20056b9..f7d052c3d 100644 --- a/javascript/images_history.js +++ b/javascript/images_history.js @@ -163,10 +163,15 @@ function images_history_init(){ for (var i in images_history_tab_list){ var tabname = images_history_tab_list[i] tab_btns[i].setAttribute("tabname", tabname); - tab_btns[i].addEventListener('click', images_history_click_tab); + + // this refreshes history upon tab switch + // until the history is known to work well, which is not the case now, we do not do this at startup + //tab_btns[i].addEventListener('click', images_history_click_tab); } - tabs_box.classList.add(images_history_tab_list[0]); - load_txt2img_button.click(); + tabs_box.classList.add(images_history_tab_list[0]); + + // same as above, at page load + //load_txt2img_button.click(); } else { setTimeout(images_history_init, 500); } @@ -182,12 +187,15 @@ document.addEventListener("DOMContentLoaded", function() { buttons.forEach(function(bnt){ bnt.addEventListener('click', images_history_click_image, true); }); + + // same as load_txt2img_button.click() above + /* var cls_btn = gradioApp().getElementById(tabname + '_images_history_gallery').querySelector("svg"); if (cls_btn){ cls_btn.addEventListener('click', function(){ gradioApp().getElementById(tabname + '_images_history_renew_page').click(); }, false); - } + }*/ } }); diff --git a/modules/ui.py b/modules/ui.py index c5d295eaa..1bc919c7e 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1090,7 +1090,7 @@ def create_ui(wrap_gradio_gpu_call): "i2i":img2img_paste_fields } - #images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict) + images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict) with gr.Blocks() as modelmerger_interface: with gr.Row().style(equal_height=False): @@ -1487,7 +1487,7 @@ Requested path was: {f} (img2img_interface, "img2img", "img2img"), (extras_interface, "Extras", "extras"), (pnginfo_interface, "PNG Info", "pnginfo"), - #(images_history, "History", "images_history"), + (images_history, "History", "images_history"), (modelmerger_interface, "Checkpoint Merger", "modelmerger"), (train_interface, "Train", "ti"), (settings_interface, "Settings", "settings"), From c7a86f7fe9c0b8967a87e8d709f507d2f44400d8 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 15 Oct 2022 09:24:59 +0300 Subject: [PATCH 445/460] add option to use batch size for training --- modules/hypernetworks/hypernetwork.py | 33 ++++++++++++++----- modules/textual_inversion/dataset.py | 31 ++++++++++------- .../textual_inversion/textual_inversion.py | 17 +++++----- modules/ui.py | 3 ++ 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 59c7ac6ee..a2b3bc0af 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -182,7 +182,21 @@ def attention_CrossAttention_forward(self, x, context=None, mask=None): return self.to_out(out) -def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def stack_conds(conds): + if len(conds) == 1: + return torch.stack(conds) + + # same as in reconstruct_multicond_batch + token_count = max([x.shape[0] for x in conds]) + for i in range(len(conds)): + if conds[i].shape[0] != token_count: + last_vector = conds[i][-1:] + last_vector_repeated = last_vector.repeat([token_count - conds[i].shape[0], 1]) + conds[i] = torch.vstack([conds[i], last_vector_repeated]) + + return torch.stack(conds) + +def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): assert hypernetwork_name, 'hypernetwork not selected' path = shared.hypernetworks.get(hypernetwork_name, None) @@ -211,7 +225,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=512, height=512, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=512, height=512, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size) if unload: shared.sd_model.cond_stage_model.to(devices.cpu) @@ -235,7 +249,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, optimizer = torch.optim.AdamW(weights, lr=scheduler.learn_rate) pbar = tqdm.tqdm(enumerate(ds), total=steps - ititial_step) - for i, entry in pbar: + for i, entries in pbar: hypernetwork.step = i + ititial_step scheduler.apply(optimizer, hypernetwork.step) @@ -246,11 +260,12 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, break with torch.autocast("cuda"): - cond = entry.cond.to(devices.device) - x = entry.latent.to(devices.device) - loss = shared.sd_model(x.unsqueeze(0), cond)[0] + c = stack_conds([entry.cond for entry in entries]).to(devices.device) +# c = torch.vstack([entry.cond for entry in entries]).to(devices.device) + x = torch.stack([entry.latent for entry in entries]).to(devices.device) + loss = shared.sd_model(x, c)[0] del x - del cond + del c losses[hypernetwork.step % losses.shape[0]] = loss.item() @@ -292,7 +307,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory, p.width = preview_width p.height = preview_height else: - p.prompt = entry.cond_text + p.prompt = entries[0].cond_text p.steps = 20 preview_text = p.prompt @@ -315,7 +330,7 @@ def train_hypernetwork(hypernetwork_name, learn_rate, data_root, log_directory,

    Loss: {losses.mean():.7f}
    Step: {hypernetwork.step}
    -Last prompt: {html.escape(entry.cond_text)}
    +Last prompt: {html.escape(entries[0].cond_text)}
    Last saved embedding: {html.escape(last_saved_file)}
    Last saved image: {html.escape(last_saved_image)}

    diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py index 67e90afeb..bd99c0cb2 100644 --- a/modules/textual_inversion/dataset.py +++ b/modules/textual_inversion/dataset.py @@ -24,11 +24,12 @@ class DatasetEntry: class PersonalizedBase(Dataset): - def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None, include_cond=False): - re_word = re.compile(shared.opts.dataset_filename_word_regex) if len(shared.opts.dataset_filename_word_regex)>0 else None + def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, device=None, template_file=None, include_cond=False, batch_size=1): + re_word = re.compile(shared.opts.dataset_filename_word_regex) if len(shared.opts.dataset_filename_word_regex) > 0 else None self.placeholder_token = placeholder_token + self.batch_size = batch_size self.width = width self.height = height self.flip = transforms.RandomHorizontalFlip(p=flip_p) @@ -78,13 +79,13 @@ class PersonalizedBase(Dataset): if include_cond: entry.cond_text = self.create_text(filename_text) - entry.cond = cond_model([entry.cond_text]).to(devices.cpu) + entry.cond = cond_model([entry.cond_text]).to(devices.cpu).squeeze(0) self.dataset.append(entry) - self.length = len(self.dataset) * repeats + self.length = len(self.dataset) * repeats // batch_size - self.initial_indexes = np.arange(self.length) % len(self.dataset) + self.initial_indexes = np.arange(len(self.dataset)) self.indexes = None self.shuffle() @@ -101,13 +102,19 @@ class PersonalizedBase(Dataset): return self.length def __getitem__(self, i): - if i % len(self.dataset) == 0: - self.shuffle() + res = [] - index = self.indexes[i % len(self.indexes)] - entry = self.dataset[index] + for j in range(self.batch_size): + position = i * self.batch_size + j + if position % len(self.indexes) == 0: + self.shuffle() - if entry.cond is None: - entry.cond_text = self.create_text(entry.filename_text) + index = self.indexes[position % len(self.indexes)] + entry = self.dataset[index] - return entry + if entry.cond is None: + entry.cond_text = self.create_text(entry.filename_text) + + res.append(entry) + + return res diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index da0d77a0e..e754747ea 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -199,7 +199,7 @@ def write_loss(log_directory, filename, step, epoch_len, values): }) -def train_embedding(embedding_name, learn_rate, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): +def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_embedding_every, template_file, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): assert embedding_name, 'embedding not selected' shared.state.textinfo = "Initializing textual inversion training..." @@ -231,7 +231,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." with torch.autocast("cuda"): - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file) + ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, model=shared.sd_model, device=devices.device, template_file=template_file, batch_size=batch_size) hijack = sd_hijack.model_hijack @@ -251,7 +251,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini optimizer = torch.optim.AdamW([embedding.vec], lr=scheduler.learn_rate) pbar = tqdm.tqdm(enumerate(ds), total=steps-ititial_step) - for i, entry in pbar: + for i, entries in pbar: embedding.step = i + ititial_step scheduler.apply(optimizer, embedding.step) @@ -262,10 +262,9 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini break with torch.autocast("cuda"): - c = cond_model([entry.cond_text]) - - x = entry.latent.to(devices.device) - loss = shared.sd_model(x.unsqueeze(0), c)[0] + c = cond_model([entry.cond_text for entry in entries]) + x = torch.stack([entry.latent for entry in entries]).to(devices.device) + loss = shared.sd_model(x, c)[0] del x losses[embedding.step % losses.shape[0]] = loss.item() @@ -307,7 +306,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini p.width = preview_width p.height = preview_height else: - p.prompt = entry.cond_text + p.prompt = entries[0].cond_text p.steps = 20 p.width = training_width p.height = training_height @@ -348,7 +347,7 @@ def train_embedding(embedding_name, learn_rate, data_root, log_directory, traini

    Loss: {losses.mean():.7f}
    Step: {embedding.step}
    -Last prompt: {html.escape(entry.cond_text)}
    +Last prompt: {html.escape(entries[0].cond_text)}
    Last saved embedding: {html.escape(last_saved_file)}
    Last saved image: {html.escape(last_saved_image)}

    diff --git a/modules/ui.py b/modules/ui.py index 1bc919c7e..45550ea86 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1166,6 +1166,7 @@ def create_ui(wrap_gradio_gpu_call): train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())) train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', choices=[x for x in shared.hypernetworks.keys()]) learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value="0.005") + batch_size = gr.Number(label='Batch size', value=1, precision=0) dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion") template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt")) @@ -1244,6 +1245,7 @@ def create_ui(wrap_gradio_gpu_call): inputs=[ train_embedding_name, learn_rate, + batch_size, dataset_directory, log_directory, training_width, @@ -1268,6 +1270,7 @@ def create_ui(wrap_gradio_gpu_call): inputs=[ train_hypernetwork_name, learn_rate, + batch_size, dataset_directory, log_directory, steps, From 3bd40bb77ff274f2a09efa07b759eebf6dc40b58 Mon Sep 17 00:00:00 2001 From: ruocaled Date: Fri, 14 Oct 2022 11:05:14 -0700 Subject: [PATCH 446/460] auto re-open selected image after re-generation attach an observer of gallery when generation in progress, if there was a image selected in gallery and gallery has only 1 image, auto re-select/open that image. This matches behavior of prior to Gradio 3.4.1 version bump, is a quality of life feature many people enjoyed. --- javascript/progressbar.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 4395a2159..4994b4768 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -1,5 +1,7 @@ // code related to showing and updating progressbar shown as the image is being made global_progressbars = {} +galleries = {} +galleryObservers = {} function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip, id_interrupt, id_preview, id_gallery){ var progressbar = gradioApp().getElementById(id_progressbar) @@ -31,6 +33,9 @@ function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip preview.style.width = gallery.clientWidth + "px" preview.style.height = gallery.clientHeight + "px" + //only watch gallery if there is a generation process going on + check_gallery(id_gallery); + var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0; if(!progressDiv){ if (skip) { @@ -38,6 +43,12 @@ function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip } interrupt.style.display = "none" } + + //disconnect observer once generation finished, so user can close selected image if they want + if (galleryObservers[id_gallery]) { + galleryObservers[id_gallery].disconnect(); + galleries[id_gallery] = null; + } } window.setTimeout(function() { requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt) }, 500) @@ -46,6 +57,27 @@ function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip } } +function check_gallery(id_gallery){ + let gallery = gradioApp().getElementById(id_gallery) + // if gallery has no change, no need to setting up observer again. + if (gallery && galleries[id_gallery] !== gallery){ + galleries[id_gallery] = gallery; + if(galleryObservers[id_gallery]){ + galleryObservers[id_gallery].disconnect(); + } + galleryObservers[id_gallery] = new MutationObserver(function (){ + let galleryButtons = gradioApp().querySelectorAll('#'+id_gallery+' .gallery-item') + let galleryBtnSelected = gradioApp().querySelector('#'+id_gallery+' .gallery-item.\\!ring-2') + if (galleryButtons.length === 1 && !galleryBtnSelected) { + //automatically open when there is only 1 gallery btn, and was previously selected + galleryButtons[0].click(); + console.log('clicked'); + } + }) + galleryObservers[id_gallery].observe( gallery, { childList:true, subtree:false }) + } +} + onUiUpdate(function(){ check_progressbar('txt2img', 'txt2img_progressbar', 'txt2img_progress_span', 'txt2img_skip', 'txt2img_interrupt', 'txt2img_preview', 'txt2img_gallery') check_progressbar('img2img', 'img2img_progressbar', 'img2img_progress_span', 'img2img_skip', 'img2img_interrupt', 'img2img_preview', 'img2img_gallery') From 6b5c54c187796900bf677c8c14b62a166eb53b24 Mon Sep 17 00:00:00 2001 From: ruocaled Date: Fri, 14 Oct 2022 11:06:38 -0700 Subject: [PATCH 447/460] remove console.log --- javascript/progressbar.js | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 4994b4768..b4925e996 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -71,7 +71,6 @@ function check_gallery(id_gallery){ if (galleryButtons.length === 1 && !galleryBtnSelected) { //automatically open when there is only 1 gallery btn, and was previously selected galleryButtons[0].click(); - console.log('clicked'); } }) galleryObservers[id_gallery].observe( gallery, { childList:true, subtree:false }) From c84eef8195b2bae4f4b4d1785159ae9efd937abe Mon Sep 17 00:00:00 2001 From: ruocaled Date: Fri, 14 Oct 2022 11:10:26 -0700 Subject: [PATCH 448/460] fix observer disconnect logic --- javascript/progressbar.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index b4925e996..196fe5070 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -42,13 +42,15 @@ function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip skip.style.display = "none" } interrupt.style.display = "none" + + //disconnect observer once generation finished, so user can close selected image if they want + if (galleryObservers[id_gallery]) { + galleryObservers[id_gallery].disconnect(); + galleries[id_gallery] = null; + } } - //disconnect observer once generation finished, so user can close selected image if they want - if (galleryObservers[id_gallery]) { - galleryObservers[id_gallery].disconnect(); - galleries[id_gallery] = null; - } + } window.setTimeout(function() { requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt) }, 500) From b26efff8c496309329cd1982aee55e81bf81a655 Mon Sep 17 00:00:00 2001 From: ruocaled Date: Fri, 14 Oct 2022 17:14:59 -0700 Subject: [PATCH 449/460] allow re-open for multiple images gallery --- javascript/progressbar.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 196fe5070..574fd549b 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -67,12 +67,13 @@ function check_gallery(id_gallery){ if(galleryObservers[id_gallery]){ galleryObservers[id_gallery].disconnect(); } + let prevSelectedIndex = selected_gallery_index(); galleryObservers[id_gallery] = new MutationObserver(function (){ let galleryButtons = gradioApp().querySelectorAll('#'+id_gallery+' .gallery-item') let galleryBtnSelected = gradioApp().querySelector('#'+id_gallery+' .gallery-item.\\!ring-2') - if (galleryButtons.length === 1 && !galleryBtnSelected) { - //automatically open when there is only 1 gallery btn, and was previously selected - galleryButtons[0].click(); + if (prevSelectedIndex !== -1 && galleryButtons.length>prevSelectedIndex && !galleryBtnSelected) { + //automatically re-open previously selected index (if exists) + galleryButtons[prevSelectedIndex].click(); } }) galleryObservers[id_gallery].observe( gallery, { childList:true, subtree:false }) From c7cd2fda5a6c9c97d5c238e0f2e1146d346e0e93 Mon Sep 17 00:00:00 2001 From: ruocaled Date: Fri, 14 Oct 2022 19:05:41 -0700 Subject: [PATCH 450/460] re-attach full screen zoom listeners --- javascript/progressbar.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 574fd549b..35f20b15b 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -74,6 +74,9 @@ function check_gallery(id_gallery){ if (prevSelectedIndex !== -1 && galleryButtons.length>prevSelectedIndex && !galleryBtnSelected) { //automatically re-open previously selected index (if exists) galleryButtons[prevSelectedIndex].click(); + setTimeout(function (){ + showGalleryImage() + },100) } }) galleryObservers[id_gallery].observe( gallery, { childList:true, subtree:false }) From 661a61985c7bee34a67390a05761e25830a6b918 Mon Sep 17 00:00:00 2001 From: ruocaled Date: Fri, 14 Oct 2022 19:25:30 -0700 Subject: [PATCH 451/460] remove extra 100ms timeout --- javascript/progressbar.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 35f20b15b..076f0a973 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -74,9 +74,7 @@ function check_gallery(id_gallery){ if (prevSelectedIndex !== -1 && galleryButtons.length>prevSelectedIndex && !galleryBtnSelected) { //automatically re-open previously selected index (if exists) galleryButtons[prevSelectedIndex].click(); - setTimeout(function (){ - showGalleryImage() - },100) + showGalleryImage(); } }) galleryObservers[id_gallery].observe( gallery, { childList:true, subtree:false }) From db27b987a97fc8b7894a9dd34bd7641536f9c424 Mon Sep 17 00:00:00 2001 From: aoirusann Date: Sat, 15 Oct 2022 11:48:13 +0800 Subject: [PATCH 452/460] Add hint for `ctrl/alt enter` And duplicate implementations are removed --- javascript/ui.js | 10 ---------- modules/ui.py | 10 ++++++++-- script.js | 4 ++-- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/javascript/ui.js b/javascript/ui.js index 0f8fe68ef..56f4216f4 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -187,12 +187,10 @@ onUiUpdate(function(){ if (!txt2img_textarea) { txt2img_textarea = gradioApp().querySelector("#txt2img_prompt > label > textarea"); txt2img_textarea?.addEventListener("input", () => update_token_counter("txt2img_token_button")); - txt2img_textarea?.addEventListener("keyup", (event) => submit_prompt(event, "txt2img_generate")); } if (!img2img_textarea) { img2img_textarea = gradioApp().querySelector("#img2img_prompt > label > textarea"); img2img_textarea?.addEventListener("input", () => update_token_counter("img2img_token_button")); - img2img_textarea?.addEventListener("keyup", (event) => submit_prompt(event, "img2img_generate")); } }) @@ -220,14 +218,6 @@ function update_token_counter(button_id) { token_timeout = setTimeout(() => gradioApp().getElementById(button_id)?.click(), wait_time); } -function submit_prompt(event, generate_button_id) { - if (event.altKey && event.keyCode === 13) { - event.preventDefault(); - gradioApp().getElementById(generate_button_id).click(); - return; - } -} - function restart_reload(){ document.body.innerHTML='

    Reloading...

    '; setTimeout(function(){location.reload()},2000) diff --git a/modules/ui.py b/modules/ui.py index 45550ea86..baf4c3977 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -433,7 +433,10 @@ def create_toprow(is_img2img): with gr.Row(): with gr.Column(scale=80): with gr.Row(): - prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, placeholder="Prompt", lines=2) + prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=2, + placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)" + ) + with gr.Column(scale=1, elem_id="roll_col"): roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0) paste = gr.Button(value=paste_symbol, elem_id="paste") @@ -446,7 +449,10 @@ def create_toprow(is_img2img): with gr.Row(): with gr.Column(scale=8): with gr.Row(): - negative_prompt = gr.Textbox(label="Negative prompt", elem_id="negative_prompt", show_label=False, placeholder="Negative prompt", lines=2) + negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2, + placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)" + ) + with gr.Column(scale=1, elem_id="roll_col"): sh = gr.Button(elem_id="sh", visible=True) diff --git a/script.js b/script.js index 9543cbe68..88f2c839d 100644 --- a/script.js +++ b/script.js @@ -50,9 +50,9 @@ document.addEventListener("DOMContentLoaded", function() { document.addEventListener('keydown', function(e) { var handled = false; if (e.key !== undefined) { - if((e.key == "Enter" && (e.metaKey || e.ctrlKey))) handled = true; + if((e.key == "Enter" && (e.metaKey || e.ctrlKey || e.altKey))) handled = true; } else if (e.keyCode !== undefined) { - if((e.keyCode == 13 && (e.metaKey || e.ctrlKey))) handled = true; + if((e.keyCode == 13 && (e.metaKey || e.ctrlKey || e.altKey))) handled = true; } if (handled) { button = get_uiCurrentTabContent().querySelector('button[id$=_generate]'); From cd28465bf87d911965790513c37e6881e4231523 Mon Sep 17 00:00:00 2001 From: ddPn08 Date: Sat, 15 Oct 2022 10:56:02 +0900 Subject: [PATCH 453/460] do not force relative paths in image history --- modules/images_history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images_history.py b/modules/images_history.py index f5ef44fe0..09c749feb 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -104,7 +104,7 @@ def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): elif tabname == "extras": dir_name = opts.outdir_extras_samples d = dir_name.split("/") - dir_name = d[0] + dir_name = "/" if dir_name.startswith("/") else d[0] for p in d[1:]: dir_name = os.path.join(dir_name, p) with gr.Row(): From 0da6c1809996f0f696d4047faf4b9c9939e26daa Mon Sep 17 00:00:00 2001 From: ddPn08 Date: Sat, 15 Oct 2022 11:22:05 +0900 Subject: [PATCH 454/460] use "outdir_samples" if specified --- modules/images_history.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/images_history.py b/modules/images_history.py index 09c749feb..9260df8a8 100644 --- a/modules/images_history.py +++ b/modules/images_history.py @@ -97,7 +97,9 @@ def delete_image(delete_num, tabname, dir_name, name, page_index, filenames, ima def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict): - if tabname == "txt2img": + if opts.outdir_samples != "": + dir_name = opts.outdir_samples + elif tabname == "txt2img": dir_name = opts.outdir_txt2img_samples elif tabname == "img2img": dir_name = opts.outdir_img2img_samples From 77bf3525f894e89e8f3d812319e822e44419f5ea Mon Sep 17 00:00:00 2001 From: Cassy-Lee <104408348+Cassy-Lee@users.noreply.github.com> Date: Fri, 14 Oct 2022 17:31:39 +0800 Subject: [PATCH 455/460] Update launch.py Allow change set --index-url for pip. --- launch.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/launch.py b/launch.py index a7c5807b3..b753efc13 100644 --- a/launch.py +++ b/launch.py @@ -89,6 +89,7 @@ def prepare_enviroment(): torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113") requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") commandline_args = os.environ.get('COMMANDLINE_ARGS', "") + index_url = os.environ.get('INDEX_URL',"") gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379") clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1") @@ -121,22 +122,22 @@ def prepare_enviroment(): run_python("import torch; assert torch.cuda.is_available(), 'Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'") if not is_installed("gfpgan"): - run_pip(f"install {gfpgan_package}", "gfpgan") + run_pip(f"install {gfpgan_package}{f' --index-url {index_url}' if index_url!='' else ''}", "gfpgan") if not is_installed("clip"): - run_pip(f"install {clip_package}", "clip") + run_pip(f"install {clip_package}{f' --index-url {index_url}' if index_url!='' else ''}", "clip") if not is_installed("xformers") and xformers and platform.python_version().startswith("3.10"): if platform.system() == "Windows": run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/c/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") elif platform.system() == "Linux": - run_pip("install xformers", "xformers") + run_pip("install xformers{f' --index-url {index_url}' if index_url!='' else ''}", "xformers") if not is_installed("deepdanbooru") and deepdanbooru: run_pip("install git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] tensorflow==2.10.0 tensorflow-io==0.27.0", "deepdanbooru") if not is_installed("pyngrok") and ngrok: - run_pip("install pyngrok", "ngrok") + run_pip("install pyngrok{f' --index-url {index_url}' if index_url!='' else ''}", "ngrok") os.makedirs(dir_repos, exist_ok=True) @@ -147,9 +148,9 @@ def prepare_enviroment(): git_clone("https://github.com/salesforce/BLIP.git", repo_dir('BLIP'), "BLIP", blip_commit_hash) if not is_installed("lpips"): - run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}", "requirements for CodeFormer") + run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}{f' --index-url {index_url}' if index_url!='' else ''}", "requirements for CodeFormer") - run_pip(f"install -r {requirements_file}", "requirements for Web UI") + run_pip(f"install -r {requirements_file}{f' --index-url {index_url}' if index_url!='' else ''}", "requirements for Web UI") sys.argv += args From 7855993bef0a16c235649027527b0f3ad7cca757 Mon Sep 17 00:00:00 2001 From: Cassy-Lee <104408348+Cassy-Lee@users.noreply.github.com> Date: Sat, 15 Oct 2022 10:02:18 +0800 Subject: [PATCH 456/460] Move index_url args into run_pip. --- launch.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/launch.py b/launch.py index b753efc13..42072f33f 100644 --- a/launch.py +++ b/launch.py @@ -9,6 +9,7 @@ import platform dir_repos = "repositories" python = sys.executable git = os.environ.get('GIT', "git") +index_url = os.environ.get('INDEX_URL',"") def extract_arg(args, name): @@ -57,7 +58,7 @@ def run_python(code, desc=None, errdesc=None): def run_pip(args, desc=None): - return run(f'"{python}" -m pip {args} --prefer-binary', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") + return run(f'"{python}" -m pip {args} --prefer-binary{f' --index-url {index_url}' if index_url!='' else ''}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") def check_run_python(code): @@ -89,7 +90,6 @@ def prepare_enviroment(): torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113") requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt") commandline_args = os.environ.get('COMMANDLINE_ARGS', "") - index_url = os.environ.get('INDEX_URL',"") gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379") clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1") @@ -122,22 +122,22 @@ def prepare_enviroment(): run_python("import torch; assert torch.cuda.is_available(), 'Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'") if not is_installed("gfpgan"): - run_pip(f"install {gfpgan_package}{f' --index-url {index_url}' if index_url!='' else ''}", "gfpgan") + run_pip(f"install {gfpgan_package}", "gfpgan") if not is_installed("clip"): - run_pip(f"install {clip_package}{f' --index-url {index_url}' if index_url!='' else ''}", "clip") + run_pip(f"install {clip_package}", "clip") if not is_installed("xformers") and xformers and platform.python_version().startswith("3.10"): if platform.system() == "Windows": run_pip("install https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/c/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl", "xformers") elif platform.system() == "Linux": - run_pip("install xformers{f' --index-url {index_url}' if index_url!='' else ''}", "xformers") + run_pip("install xformers", "xformers") if not is_installed("deepdanbooru") and deepdanbooru: run_pip("install git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26#egg=deepdanbooru[tensorflow] tensorflow==2.10.0 tensorflow-io==0.27.0", "deepdanbooru") if not is_installed("pyngrok") and ngrok: - run_pip("install pyngrok{f' --index-url {index_url}' if index_url!='' else ''}", "ngrok") + run_pip("install pyngrok", "ngrok") os.makedirs(dir_repos, exist_ok=True) @@ -148,9 +148,9 @@ def prepare_enviroment(): git_clone("https://github.com/salesforce/BLIP.git", repo_dir('BLIP'), "BLIP", blip_commit_hash) if not is_installed("lpips"): - run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}{f' --index-url {index_url}' if index_url!='' else ''}", "requirements for CodeFormer") + run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}", "requirements for CodeFormer") - run_pip(f"install -r {requirements_file}{f' --index-url {index_url}' if index_url!='' else ''}", "requirements for Web UI") + run_pip(f"install -r {requirements_file}", "requirements for Web UI") sys.argv += args From a13af34b902bebc5df9509228380206a01f1245b Mon Sep 17 00:00:00 2001 From: githublsx Date: Thu, 13 Oct 2022 20:05:07 -0700 Subject: [PATCH 457/460] Set to -1 when seed input is none --- modules/processing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/processing.py b/modules/processing.py index a75b9f847..7e2a416d7 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -140,7 +140,7 @@ class Processed: self.sampler_noise_scheduler_override = p.sampler_noise_scheduler_override self.prompt = self.prompt if type(self.prompt) != list else self.prompt[0] self.negative_prompt = self.negative_prompt if type(self.negative_prompt) != list else self.negative_prompt[0] - self.seed = int(self.seed if type(self.seed) != list else self.seed[0]) + self.seed = int(self.seed if type(self.seed) != list else self.seed[0]) if self.seed is not None else -1 self.subseed = int(self.subseed if type(self.subseed) != list else self.subseed[0]) if self.subseed is not None else -1 self.all_prompts = all_prompts or [self.prompt] From c24df4b486a48c60f48276f7760a9acb4a13e22d Mon Sep 17 00:00:00 2001 From: CookieHCl Date: Sat, 15 Oct 2022 03:26:36 +0900 Subject: [PATCH 458/460] Disable compiling deepbooru model This is only necessary when you have to train, and compiling model produces warning. --- modules/deepbooru.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/deepbooru.py b/modules/deepbooru.py index f34f37882..4ad334a12 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -102,7 +102,7 @@ def get_deepbooru_tags_model(): tags = dd.project.load_tags_from_project(model_path) model = dd.project.load_model_from_project( - model_path, compile_model=True + model_path, compile_model=False ) return model, tags From f756bc540a849039d88c19378419838fe87f15b0 Mon Sep 17 00:00:00 2001 From: AUTOMATIC <16777216c@gmail.com> Date: Sat, 15 Oct 2022 10:28:20 +0300 Subject: [PATCH 459/460] fix #2588 breaking launch.py (. . .) --- launch.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/launch.py b/launch.py index 42072f33f..537670a39 100644 --- a/launch.py +++ b/launch.py @@ -9,7 +9,7 @@ import platform dir_repos = "repositories" python = sys.executable git = os.environ.get('GIT', "git") -index_url = os.environ.get('INDEX_URL',"") +index_url = os.environ.get('INDEX_URL', "") def extract_arg(args, name): @@ -58,7 +58,8 @@ def run_python(code, desc=None, errdesc=None): def run_pip(args, desc=None): - return run(f'"{python}" -m pip {args} --prefer-binary{f' --index-url {index_url}' if index_url!='' else ''}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") + index_url_line = f' --index-url {index_url}' if index_url != '' else '' + return run(f'"{python}" -m pip {args} --prefer-binary{index_url_line}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}") def check_run_python(code): From 6a4e84671016d38c10a55fedcdf09321dba737ae Mon Sep 17 00:00:00 2001 From: Daniel M Date: Fri, 14 Oct 2022 20:50:21 +0200 Subject: [PATCH 460/460] Fix prerequisites check in webui.sh - Check the actually used `$python_cmd` and `$GIT` executables instead of the hardcoded ones - Fix typo in comment --- webui.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webui.sh b/webui.sh index 05ca497d2..980c0aaf3 100755 --- a/webui.sh +++ b/webui.sh @@ -82,8 +82,8 @@ then clone_dir="${PWD##*/}" fi -# Check prequisites -for preq in git python3 +# Check prerequisites +for preq in "${GIT}" "${python_cmd}" do if ! hash "${preq}" &>/dev/null then
  • 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