Merge branch 'master' of https://github.com/vladmandic/automatic into settings-improvements

This commit is contained in:
Alex Heller
2023-06-08 19:52:14 +02:00
67 changed files with 1313 additions and 516 deletions
+3 -2
View File
@@ -51,13 +51,14 @@
"globals": {
//script.js
"gradioApp": "readonly",
"executeCallbacks": "readonly",
"onAfterUiUpdate": "readonly",
"onOptionsChanged": "readonly",
"onUiLoaded": "readonly",
"onUiUpdate": "readonly",
"onOptionsChanged": "readonly",
"uiCurrentTab": "writable",
"uiElementIsVisible": "readonly",
"uiElementInSight": "readonly",
"executeCallbacks": "readonly",
//ui.js
"opts": "writable",
"all_gallery_buttons": "readonly",
+1 -1
View File
@@ -28,7 +28,7 @@ body:
- type: markdown
attributes:
value: |
If issue is setup, installation or startup related, please check `webui.log` before reporting
If issue is setup, installation or startup related, please check `sdnext.log` before reporting
And when posting console logs, please use code blocks ( \`\`\` ) to format them insead of uploading screenshots
- type: markdown
attributes:
+7 -1
View File
@@ -22,6 +22,12 @@ body:
label: URL link of the extension
description: URL link of the extension
value:
- type: textarea
id: url
attributes:
label: URL link of the issue reported in the extension repository
description: Any extension related issue must also be reported to extension repository as well
value:
- type: markdown
attributes:
value: |
@@ -29,5 +35,5 @@ body:
- type: markdown
attributes:
value: |
If issue is extension installation or startup related, please check `webui.log` before reporting
If issue is extension installation or startup related, please check `sdnext.log` before reporting
And when posting console logs, please use code blocks ( \`\`\` ) to format them insead of uploading screenshots
+28 -5
View File
@@ -1,11 +1,34 @@
# Change Log for SD.Next
## Update for 06/03/2023
## Update for 06/07/2023
- reworked **installer** sequence
as some extensions are loading packages directly from their preload sequence
which was preventing some optimizations to take effect
i hope this does not cause regressions, but if it does, please report
- experimental `sd_model_dict` setting which allows you to load model dictionary
from one model and apply weights from another model specified in `sd_model_checkpoint`
results? who am i to judge :)
## Update for 06/05/2023
Few new features and extra handling for broken extensions
that caused my phone to go crazy with notifications over the weekend...
- added extra networks to **xyz grid** options
now you can have more fun with all your embeddings and loras :)
- new **vae decode** method to help with larger batch sizes, thanks @bigdog
- new setting -> lora -> **use lycoris to handle all lora types**
this is still experimental, but the goal is to obsolete old built-in lora module
as it doesn't understand many new loras and built-in lyco module can handle it all
- somewhat optimize browser page loading
still slower than i'd want, but gradio is pretty bad at this
- profiling of scripts/extensions callbacks
you can now see how much or pre/post processing is done, not just how long generate takes
- additional exception handling so bad exception does not crash main app
- additional background removal models
- some work on bfloat16 which nobody really should be using, but why not 🙂
- new vae decode method to help with larger batch sizes, thanks @bigdog
- profiling of scripts/extensions callbacks
- additional exception handling so bad exception does not crash main app
- additional background removal models
## Update for 06/02/2023
+2 -2
View File
@@ -31,13 +31,13 @@ Individual features are not listed here, instead check [Changelog](CHANGELOG.md)
3. Run launcher
`webui.bat` or `webui.sh`:
- Platform specific wrapper scripts For Windows, Linux and OSX
- Starts `launch.py` in a Python virtual environment (`venv`)
- Starts `sdnext.py` in a Python virtual environment (`venv`)
- Uses `install.py` to handle all actual requirements and dependencies
- *Note*: Server can run without virtual environment, but it is recommended to use it to avoid library version conflicts with other applications
*Note*: **nVidia/CUDA** and **AMD/ROCm** are auto-detected is present and available, but for any other use case specify required parameter explicitly or wrong packages may be installed as installer will assume CPU-only environment
Full startup sequence is logged in `webui.log`, so if you encounter any issues, please check it first
Full startup sequence is logged in `sdnext.log`, so if you encounter any issues, please check it first
Below is partial list of all available parameters, run `webui --help` for the full list:
+3
View File
@@ -42,6 +42,7 @@ Tech that can be integrated as part of the core workflow...
- [Custom diffusion](https://github.com/guaneec/custom-diffusion-webui), [Custom diffusion](https://www.cs.cmu.edu/~custom-diffusion/)
- [Dream artist](https://github.com/7eu7d7/DreamArtist-sd-webui-extension)
- [QuickEmbedding](https://github.com/ethansmith2000/QuickEmbedding)
- [DataComp CLiP](https://github.com/mlfoundations/open_clip/blob/main/docs/datacomp_models.md)
- `TensorRT`
## Random
@@ -56,3 +57,5 @@ Tech that can be integrated as part of the core workflow...
- docker
- port `p.all_hr_prompts`
- test `lyco_patch_lora`
- fix `lyco` logging
- git diff index
+2
View File
@@ -1,3 +1,5 @@
#!/usr/bin/env python
import sys
import huggingface_hub as hf
from rich import print # pylint: disable=redefined-builtin
+106
View File
@@ -0,0 +1,106 @@
#!/bin/env python
import os
import io
import re
import sys
import json
from PIL import Image, ExifTags, TiffImagePlugin, PngImagePlugin
from rich import print # pylint: disable=redefined-builtin
# warnings.filterwarnings("ignore", category=UserWarning)
class Exif: # pylint: disable=single-string-used-for-slots
__slots__ = ('__dict__') # pylint: disable=superfluous-parens
def __init__(self, image = None):
super(Exif, self).__setattr__('exif', Image.Exif())
self.pnginfo = PngImagePlugin.PngInfo()
self.tags = {**dict(((k, v) for k, v in ExifTags.TAGS.items())), **dict(((k, v) for k, v in ExifTags.GPSTAGS.items()))}
self.ids = {**dict(((v, k) for k, v in ExifTags.TAGS.items())), **dict(((v, k) for k, v in ExifTags.GPSTAGS.items()))}
if image is not None:
self.load(image)
def __getattr__(self, attr):
if attr in self.__dict__:
return self.__dict__[attr]
return self.exif.get(attr, None)
def load(self, img: Image):
img.load() # exif may not be ready
exif_dict = {}
try:
exif_dict = dict(img._getexif().items()) # pylint: disable=protected-access
except:
exif_dict = dict(img.info.items())
for key, val in exif_dict.items():
if isinstance(val, bytes): # decode bytestring
val = self.decode(val)
if val is not None:
if isinstance(key, str):
self.exif[key] = val
self.pnginfo.add_text(key, str(val), zip=False)
elif isinstance(key, int) and key in ExifTags.TAGS: # add known tags
if self.tags[key] in ['ExifOffset']:
continue
self.exif[self.tags[key]] = val
self.pnginfo.add_text(self.tags[key], str(val), zip=False)
# if self.tags[key] == 'UserComment': # add geninfo from UserComment
# self.geninfo = val
else:
print('metadata unknown tag:', key, val)
for key, val in self.exif.items():
if isinstance(val, bytes): # decode bytestring
self.exif[key] = self.decode(val)
def decode(self, s: bytes):
remove_prefix = lambda text, prefix: text[len(prefix):] if text.startswith(prefix) else text # pylint: disable=unnecessary-lambda-assignment
for encoding in ['utf-8', 'utf-16', 'ascii', 'latin_1', 'cp1252', 'cp437']: # try different encodings
try:
s = remove_prefix(s, b'UNICODE')
s = remove_prefix(s, b'ASCII')
s = remove_prefix(s, b'\x00')
val = s.decode(encoding, errors="strict")
val = re.sub(r'[\x00-\x09]', '', val).strip() # remove remaining special characters
if len(val) == 0: # remove empty strings
val = None
return val
except:
pass
return None
def get_bytes(self):
ifd = TiffImagePlugin.ImageFileDirectory_v2()
exif_stream = io.BytesIO()
for key, val in self.exif.items():
if key in self.ids:
ifd[self.ids[key]] = val
else:
print('metadata unknown exif tag:', key, val)
ifd.save(exif_stream)
raw = b'Exif\x00\x00' + exif_stream.getvalue()
return raw
def read_exif(filename: str):
try:
img = Image.open(filename)
exif = Exif(img)
print('image:', filename, 'format:', img.format, 'metadata:', json.dumps(vars(exif.exif)['_data'], indent=2))
except Exception as e:
print('metadata error reading:', filename, e)
# exif.exif['Software'] = 'This is a Test'
# img.save('input-scored.jpg', exif=exif.bytes())
if __name__ == '__main__':
sys.argv.pop(0)
if len(sys.argv) == 0:
print('metadata:', 'no files specified')
for fn in sys.argv:
if os.path.isfile(fn):
read_exif(fn)
elif os.path.isdir(fn):
for root, dirs, files in os.walk(fn):
for file in files:
read_exif(os.path.join(root, file))
+11 -6
View File
@@ -87,6 +87,10 @@ def parse_args():
global args # pylint: disable=global-statement
parser = argparse.ArgumentParser(description = 'SD.Next Train')
group_server = parser.add_argument_group('Server')
group_server.add_argument('--server', type=str, default='http://127.0.0.1:7860', required=False, help='server url, default: %(default)s')
group_main = parser.add_argument_group('Main')
group_main.add_argument('--type', type=str, choices=['embedding', 'ti', 'lora', 'lyco', 'dreambooth', 'hypernetwork'], default=None, required=True, help='training type')
group_main.add_argument('--model', type=str, default='', required=False, help='base model to use for training, default: current loaded model')
@@ -95,7 +99,7 @@ def parse_args():
group_data = parser.add_argument_group('Dataset')
group_data.add_argument('--input', type=str, default=None, required=True, help='input folder with training images')
group_data.add_argument('--output', type=str, default='', required=False, help='where to store processed images, default is system temp/train')
group_data.add_argument('--interim', type=str, default='', required=False, help='where to store processed images, default is system temp/train')
group_data.add_argument('--process', type=str, default='original,interrogate,resize,square', required=False, help=f'list of possible processing steps: {valid_steps}, default: %(default)s')
group_train = parser.add_argument_group('Train')
@@ -164,9 +168,9 @@ def verify_args():
if not os.path.isfile(args.model):
log.error(f'cannot find loaded model: {args.model}')
exit(1)
if not os.path.exists(args.ckpt_dir) or not os.path.isdir(args.ckpt_dir):
log.error(f'cannot find models folder: {args.ckpt_dir}')
exit(1)
# if not os.path.exists(args.ckpt_dir) or not os.path.isdir(args.ckpt_dir):
# log.error(f'cannot find models folder: {args.ckpt_dir}')
# exit(1)
if not os.path.exists(args.input) or not os.path.isdir(args.input):
log.error(f'cannot find training folder: {args.input}')
exit(1)
@@ -176,8 +180,8 @@ def verify_args():
if not os.path.exists(args.lyco_dir) or not os.path.isdir(args.lyco_dir):
log.error(f'cannot find lyco folder: {args.lyco_dir}')
exit(1)
if args.output != '':
args.process_dir = args.output
if args.interim != '':
args.process_dir = args.interim
else:
args.process_dir = os.path.join(tempfile.gettempdir(), 'train', args.name)
log.debug(f'args: {vars(args)}')
@@ -376,6 +380,7 @@ def process_inputs():
if __name__ == '__main__':
log.info('SD.Next train script')
parse_args()
sdapi.sd_url = args.server
setup_logging()
prepare_server()
verify_args()
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python
import sys
import json
from rich import print # pylint: disable=redefined-builtin
if __name__ == "__main__":
sys.argv.pop(0)
fn = sys.argv[0] if len(sys.argv) > 0 else 'locale_en.json'
with open(fn, 'r') as f:
data = json.load(f)
keys = []
t_names = 0
t_hints = 0
for k in data.keys():
print(f'Section: {k}')
names = len(data[k])
t_names += names
print(f' Names: {names}')
hints = len([k for k in data[k] if k["hint"] != ""])
t_hints += hints
print(f' Hints: {hints}')
print(f' Missing: {names - hints}')
for v in data[k]:
if v['text'] in keys:
print(f' Duplicate: {k}.{v["text"]}')
else:
keys.append(v['text'])
print(f'Total entries: {t_names}')
print(f'Total hints: {t_hints}')
print(f'Total missing: {t_names - t_hints}')
@@ -14,21 +14,22 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage):
def list_items(self):
for name, lora_on_disk in lora.available_loras.items():
path, ext = os.path.splitext(lora_on_disk.filename)
path, _ext = os.path.splitext(lora_on_disk.filename)
alias = lora_on_disk.get_alias()
yield {
"name": name,
"filename": path,
"preview": self.find_preview(path),
"description": self.find_description(path),
"search_term": self.search_terms_from_path(lora_on_disk.filename),
"prompt": json.dumps(f"<lora:{alias}:") + " + opts.extra_networks_default_multiplier + " + json.dumps(">"),
"prompt": (
json.dumps(f"<lora:{alias}")
+ " + " + json.dumps(f':{shared.opts.extra_networks_default_multiplier}')
+ " + " + json.dumps(">")
),
"local_preview": f"{path}.{shared.opts.samples_format}",
"metadata": json.dumps(lora_on_disk.metadata, indent=4) if lora_on_disk.metadata else None,
}
def allowed_directories_for_previews(self):
return [shared.cmd_opts.lora_dir]
@@ -1,15 +1,13 @@
import os
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, devices, script_callbacks, shared
from modules.shared import opts, state
from tqdm.rich import tqdm
from swinir_model_arch import SwinIR as net
from swinir_model_arch_v2 import Swin2SR as net2
from modules import modelloader, devices, script_callbacks, shared
from modules.shared import opts, state
from modules.upscaler import Upscaler, UpscalerData
@@ -36,8 +34,8 @@ class UpscalerSwinIR(Upscaler):
scalers.append(model_data)
self.scalers = scalers
def do_upscale(self, img, model_file):
model = self.load_model(model_file)
def do_upscale(self, img, selected_model):
model = self.load_model(selected_model)
if model is None:
return img
model = model.to(device_swinir, dtype=devices.dtype)
@@ -56,8 +54,7 @@ class UpscalerSwinIR(Upscaler):
filename = path
if filename is None or not os.path.exists(filename):
return None
if filename.endswith(".v2.pth"):
model = net2(
model_v2 = net2(
upscale=scale,
in_chans=3,
img_size=64,
@@ -69,29 +66,33 @@ class UpscalerSwinIR(Upscaler):
mlp_ratio=2,
upsampler="nearest+conv",
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"
)
model_v1 = 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",
)
pretrained_model = torch.load(filename)
if params is not None:
model.load_state_dict(pretrained_model[params], strict=True)
else:
model.load_state_dict(pretrained_model, strict=True)
for model in [model_v1, model_v2]:
for param in ["params_ema", "params", None]:
try:
if param is not None:
model.load_state_dict(pretrained_model[param], strict=True)
else:
model.load_state_dict(pretrained_model, strict=True)
shared.log.info(f'Loaded SwinIR model: {filename} param={param}')
return model
except Exception:
pass
shared.log.error(f'Could not determine SwinIR model parameters: {filename}')
return model
@@ -142,7 +143,7 @@ def inference(img, model, tile, tile_overlap, window_size, scale):
E = torch.zeros(b, c, h * sf, w * sf, dtype=devices.dtype, device=device_swinir).type_as(img)
W = torch.zeros_like(E, dtype=devices.dtype, device=device_swinir)
with tqdm(total=len(h_idx_list) * len(w_idx_list), desc="SwinIR tiles") as pbar:
with tqdm(total=len(h_idx_list) * len(w_idx_list), desc="Upscaling SwinIR") as pbar:
for h_idx in h_idx_list:
if state.interrupted or state.skipped:
break
+565
View File
@@ -0,0 +1,565 @@
{ "icons": [
{"id":"","label":"📘","localized":"","hint":"Read generation parameters from prompt or last generation if prompt is empty into user interface"},
{"id":"","label":"🚮","localized":"","hint":"Clear prompt"},
{"id":"","label":"🌐","localized":"","hint":"Show/hide extra networks"},
{"id":"","label":"🧳","localized":"","hint":"Apply selected styles to current prompt"},
{"id":"","label":"🛅","localized":"","hint":"Save style"},
{"id":"","label":"🔄","localized":"","hint":"Refresh"},
{"id":"","label":"❌","localized":"","hint":"Close"},
{"id":"","label":"📒","localized":"","hint":"Fill"},
{"id":"","label":"🎲️","localized":"","hint":"Use random seed"},
{"id":"","label":"♻️","localized":"","hint":"Reuse previous seed"},
{"id":"","label":"⇅","localized":"","hint":"Switch values"}
],
"prompts": [
{"id":"","label":"Prompt","localized":"","hint":"Prompt"},
{"id":"","label":"Negative prompt","localized":"","hint":"Negative Prompt"}
],
"tabs": [
{"id":"","label":"From Text ","localized":"txt2img","hint":"Create image from text"},
{"id":"","label":"From Image ","localized":"","hint":"Create image from image"},
{"id":"","label":"Process Image ","localized":"","hint":"Process existing image"},
{"id":"","label":"Train ","localized":"","hint":"Run training or model merging"},
{"id":"","label":"Settings ","localized":"","hint":"Application settings"},
{"id":"","label":"Extensions ","localized":"","hint":"Application extensions"}
],
"action panel": [
{"id":"","label":"Generate","localized":"","hint":"Start processing"},
{"id":"","label":"Stop","localized":"","hint":"Stop processing"},
{"id":"","label":"Skip","localized":"","hint":"Stop processing current job and continue processing"},
{"id":"","label":"Pause","localized":"","hint":"Pause processing"},
{"id":"","label":"Interrogate\nCLIP","localized":"","hint":"Run interrogate using CLIP model"},
{"id":"","label":"Interrogate\nDeepBooru","localized":"","hint":"Run interrogate using DeepBooru model"}
],
"extra networks": [
{"id":"","label":"Save preview","localized":"","hint":"Save current image as extra network preview"},
{"id":"","label":"Save description","localized":"","hint":"Save current text as extra network description"},
{"id":"","label":"Read description","localized":"","hint":"Read stored extra network description"}
],
"gallery buttons": [
{"id":"","label":"show","localized":"","hint":"Show image location"},
{"id":"","label":"save","localized":"","hint":"Save image"},
{"id":"","label":"zip","localized":"","hint":"Create zip archive from images"},
{"id":"","label":"delete","localized":"","hint":"Delete image"},
{"id":"","label":"➠ text","localized":"","hint":"Transfer image to text interface"},
{"id":"","label":"➠ image","localized":"","hint":"Transfer image to image interface"},
{"id":"","label":"➠ inpaint","localized":"","hint":"Transfer image to inpaint interface"},
{"id":"","label":"➠ sketch","localized":"","hint":"Transfer image to sketch interface"},
{"id":"","label":"➠ inpaint sketch","localized":"","hint":"Transfer image to inpaint sketch interface"},
{"id":"","label":"➠ process","localized":"","hint":"Transfer image to process interface"}
],
"extensions": [
{"id":"","label":"Install","localized":"","hint":""},
{"id":"","label":"Search","localized":"","hint":""},
{"id":"","label":"Sort by","localized":"","hint":""},
{"id":"","label":"Manage Extensions ","localized":"","hint":""},
{"id":"","label":"Manual install ","localized":"","hint":""},
{"id":"","label":"Extension GIT repository URL","localized":"","hint":""},
{"id":"","label":"Specific branch name","localized":"","hint":""},
{"id":"","label":"Local directory name","localized":"","hint":""},
{"id":"","label":"Refresh extension list","localized":"","hint":""},
{"id":"","label":"Update installed extensions","localized":"","hint":""},
{"id":"","label":"Apply changes & restart server","localized":"","hint":""}
],
"txt2img tab": [
{"id":"","label":"Sampling method","localized":"","hint":"Which algorithm to use to produce the image"},
{"id":"","label":"Sampling steps","localized":"","hint":"How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results"},
{"id":"","label":"Restore faces","localized":"","hint":""},
{"id":"","label":"Tiling","localized":"","hint":"Produce an image that can be tiled"},
{"id":"","label":"Hires fix","localized":"","hint":""},
{"id":"","label":"Denoising strength","localized":"","hint":"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"},
{"id":"","label":"Hires steps","localized":"","hint":"Number of sampling steps for upscaled picture. If 0, uses same as for original"},
{"id":"","label":"Upscaler","localized":"","hint":""},
{"id":"","label":"Upscale by","localized":"","hint":"Adjusts the size of the image by multiplying the original width and height by the selected value. Ignored if either Resize width to or Resize height to are non-zero"},
{"id":"","label":"Resize width to","localized":"","hint":"Resizes image to this width. If 0, width is inferred from either of two nearby sliders"},
{"id":"","label":"Resize height to","localized":"","hint":"Resizes image to this height. If 0, height is inferred from either of two nearby sliders"},
{"id":"","label":"Width","localized":"","hint":""},
{"id":"","label":"Height","localized":"","hint":""},
{"id":"","label":"Batch count","localized":"","hint":"How many batches of images to create (has no impact on generation performance or VRAM usage)"},
{"id":"","label":"Batch size","localized":"","hint":"How many image to create in a single batch (increases generation performance at cost of higher VRAM usage)"},
{"id":"","label":"CFG Scale","localized":"","hint":"Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results"},
{"id":"","label":"CLIP skip","localized":"","hint":""},
{"id":"","label":"Seed","localized":"","hint":"A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result"},
{"id":"","label":"Extra","localized":"","hint":""},
{"id":"","label":"Variation seed","localized":"","hint":"Seed of a different picture to be mixed into the generation"},
{"id":"","label":"Variation strength","localized":"","hint":"How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something)"},
{"id":"","label":"Resize seed from width","localized":"","hint":"Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution"},
{"id":"","label":"Resize seed from height","localized":"","hint":"Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution"},
{"id":"","label":"Override settings","localized":"","hint":""}
],
"process tab": [
{"id":"","label":"Single Image ","localized":"","hint":""},
{"id":"","label":"Process Batch ","localized":"","hint":""},
{"id":"","label":"Process Folder ","localized":"","hint":""},
{"id":"","label":"Scale by ","localized":"","hint":""},
{"id":"","label":"Scale to ","localized":"","hint":""},
{"id":"","label":"Input directory","localized":"","hint":""},
{"id":"","label":"Output directory","localized":"","hint":""},
{"id":"","label":"Show result images","localized":"","hint":""},
{"id":"","label":"Resize","localized":"","hint":""},
{"id":"","label":"Crop to fit","localized":"","hint":""},
{"id":"","label":"Secondary Upscaler","localized":"","hint":""},
{"id":"","label":"Upscaler 2 visibility","localized":"","hint":""},
{"id":"","label":"GFPGAN visibility","localized":"","hint":""},
{"id":"","label":"CodeFormer visibility","localized":"","hint":""},
{"id":"","label":"CodeFormer weight (0 = max, 1 = min)","localized":"","hint":""}
],
"settings menu": [
{"id":"settings_submit","label":"Apply settings","localized":"","hint":""},
{"id":"restart_submit","label":"Restart server","localized":"","hint":""},
{"id":"shutdown_submit","label":"Shutdown server","localized":"","hint":""},
{"id":"settings_preview_theme","label":"Preview theme","localized":"","hint":""},
{"id":"defaults_submit","label":"Restore defaults","localized":"","hint":""},
{"id":"sett_unload_sd_model","label":"Unload checkpoint","localized":"","hint":""},
{"id":"sett_reload_sd_model","label":"Reload checkpoint","localized":"","hint":""}
],
"settings sections": [
{"id":"","label":"Stable Diffusion ","localized":"","hint":""},
{"id":"","label":"Compute Settings ","localized":"","hint":""},
{"id":"","label":"System Paths ","localized":"","hint":""},
{"id":"","label":"Image Options ","localized":"","hint":""},
{"id":"","label":"Image Processing ","localized":"","hint":""},
{"id":"","label":"Output Paths ","localized":"","hint":""},
{"id":"","label":"User interface ","localized":"","hint":""},
{"id":"","label":"Live previews ","localized":"","hint":""},
{"id":"","label":"Sampler Settings ","localized":"","hint":""},
{"id":"","label":"Postprocessing ","localized":"","hint":""},
{"id":"","label":"Training ","localized":"","hint":""},
{"id":"","label":"Interrogate ","localized":"","hint":""},
{"id":"","label":"Upscaling ","localized":"","hint":""},
{"id":"","label":"Lora ","localized":"","hint":""},
{"id":"","label":"Face restoration ","localized":"","hint":""},
{"id":"","label":"Extra Networks ","localized":"","hint":""},
{"id":"","label":"Token Merging ","localized":"","hint":""},
{"id":"","label":"Licenses ","localized":"","hint":""},
{"id":"","label":"Show all pages","localized":"","hint":""},
{"id":"","label":"Request browser notifications","localized":"","hint":""}
],
"img2img tabs": [
{"id":"","label":"Image ","localized":"","hint":""},
{"id":"","label":"Sketch ","localized":"","hint":""},
{"id":"","label":"Inpaint ","localized":"","hint":""},
{"id":"","label":"Inpaint sketch ","localized":"","hint":""},
{"id":"","label":"Inpaint upload ","localized":"","hint":""},
{"id":"","label":"Batch ","localized":"","hint":""}
],
"img2img tab": [
{"id":"","label":"Inpaint Batch input directory","localized":"","hint":""},
{"id":"","label":"Inpaint Batch output directory","localized":"","hint":""},
{"id":"","label":"Inpaint batch mask directory","localized":"","hint":""},
{"id":"","label":"Resize fixed","localized":"","hint":"Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio"},
{"id":"","label":"Crop and resize","localized":"","hint":"Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out"},
{"id":"","label":"Resize and fill","localized":"","hint":"Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors"},
{"id":"","label":"Resize using Latent upscale","localized":"","hint":""},
{"id":"","label":"Mask blur","localized":"","hint":"How much to blur the mask before processing, in pixels"},
{"id":"","label":"Mask transparency","localized":"","hint":""},
{"id":"","label":"Inpaint masked","localized":"","hint":""},
{"id":"","label":"Inpaint not masked","localized":"","hint":""},
{"id":"","label":"fill","localized":"","hint":"fill it with colors of the image"},
{"id":"","label":"original","localized":"","hint":"keep whatever was there originally"},
{"id":"","label":"latent noise","localized":"","hint":"fill it with latent space noise"},
{"id":"","label":"latent nothing","localized":"","hint":"fill it with latent space zeroes"},
{"id":"","label":"Whole picture","localized":"","hint":""},
{"id":"","label":"Only masked","localized":"","hint":""},
{"id":"","label":"Only masked padding, pixels","localized":"","hint":""},
{"id":"","label":"Scale","localized":"","hint":""},
{"id":"","label":"Unused","localized":"","hint":""},
{"id":"","label":"Image CFG Scale","localized":"","hint":""}
],
"train tabs": [
{"id":"","label":"Merge models ","localized":"","hint":""},
{"id":"","label":"Create embedding ","localized":"","hint":""},
{"id":"","label":"Create hypernetwork ","localized":"","hint":""},
{"id":"","label":"Preprocess images ","localized":"","hint":""},
{"id":"","label":"Merge","localized":"","hint":""},
{"id":"","label":"Calculate hash for all models (may take a long time)","localized":"","hint":""},
{"id":"","label":"Create embedding","localized":"","hint":""},
{"id":"","label":"Create hypernetwork","localized":"","hint":""},
{"id":"","label":"Preprocess","localized":"","hint":""},
{"id":"","label":"Train Embedding","localized":"","hint":""},
{"id":"","label":"Train Hypernetwork","localized":"","hint":""}
],
"train tab": [
{"id":"","label":"Primary model","localized":"","hint":""},
{"id":"","label":"Secondary model","localized":"","hint":""},
{"id":"","label":"Tertiary model","localized":"","hint":""},
{"id":"","label":"New model name","localized":"","hint":""},
{"id":"","label":"No interpolation","localized":"","hint":"Result = A"},
{"id":"","label":"Weighted sum","localized":"","hint":"Result = A * (1 - M) + B * M"},
{"id":"","label":"Add difference","localized":"","hint":"Result = A + (B - C) * M"},
{"id":"","label":"Interpolation ratio from Primary to Secondary","localized":"","hint":""},
{"id":"","label":"ckpt","localized":"","hint":""},
{"id":"","label":"safetensors","localized":"","hint":""},
{"id":"","label":"Use FP16","localized":"","hint":""},
{"id":"","label":"Save metadata","localized":"","hint":""},
{"id":"","label":"Primary","localized":"","hint":""},
{"id":"","label":"Secondary","localized":"","hint":""},
{"id":"","label":"Tertiary","localized":"","hint":""},
{"id":"","label":"Bake in VAE","localized":"","hint":""},
{"id":"","label":"Discard weights with matching name","localized":"","hint":"Regular expression; if weights's name matches it, the weights is not written to the resulting checkpoint. Use ^model_ema to discard EMA weights"},
{"id":"","label":"Name","localized":"","hint":""},
{"id":"","label":"Initialization text","localized":"","hint":"If the number of tokens is more than the number of vectors, some may be skipped.\nLeave the textbox empty to start with zeroed out vectors"},
{"id":"","label":"Number of vectors per token","localized":"","hint":""},
{"id":"","label":"Overwrite Old Embedding","localized":"","hint":""},
{"id":"","label":"Enter hypernetwork layer structure","localized":"","hint":""},
{"id":"","label":"Select activation function of hypernetwork. Recommended : Swish / Linear(none)","localized":"","hint":""},
{"id":"","label":"Select Layer weights initialization. Recommended: Kaiming for relu-like, Xavier for sigmoid-like, Normal otherwise","localized":"","hint":""},
{"id":"","label":"Add layer normalization","localized":"","hint":""},
{"id":"","label":"Use dropout","localized":"","hint":""},
{"id":"","label":"Enter hypernetwork Dropout structure (or empty). Recommended : 0~0.35 incrementing sequence: 0, 0.05, 0.15","localized":"","hint":""},
{"id":"","label":"Overwrite Old Hypernetwork","localized":"","hint":""},
{"id":"","label":"Source directory","localized":"","hint":""},
{"id":"","label":"Destination directory","localized":"","hint":""},
{"id":"","label":"Existing Caption txt Action","localized":"","hint":""},
{"id":"","label":"Keep original size","localized":"","hint":""},
{"id":"","label":"Keep original image channels","localized":"","hint":""},
{"id":"","label":"Create flipped copies","localized":"","hint":""},
{"id":"","label":"Split oversized images","localized":"","hint":""},
{"id":"","label":"Auto focal point crop","localized":"","hint":""},
{"id":"","label":"Auto-sized crop","localized":"","hint":""},
{"id":"","label":"Create captions only","localized":"","hint":""},
{"id":"","label":"Create BLIP captions","localized":"","hint":""},
{"id":"","label":"Create Deepbooru captions","localized":"","hint":""},
{"id":"","label":"Split image threshold","localized":"","hint":""},
{"id":"","label":"Split image overlap ratio","localized":"","hint":""},
{"id":"","label":"Focal point face weight","localized":"","hint":""},
{"id":"","label":"Focal point entropy weight","localized":"","hint":""},
{"id":"","label":"Focal point edges weight","localized":"","hint":""},
{"id":"","label":"Create debug image","localized":"","hint":""},
{"id":"","label":"Dimension lower bound","localized":"","hint":""},
{"id":"","label":"Dimension upper bound","localized":"","hint":""},
{"id":"","label":"Area lower bound","localized":"","hint":""},
{"id":"","label":"Area upper bound","localized":"","hint":""},
{"id":"","label":"Maximize area","localized":"","hint":""},
{"id":"","label":"Minimize error","localized":"","hint":""},
{"id":"","label":"Error threshold","localized":"","hint":""},
{"id":"","label":"Embedding","localized":"","hint":""},
{"id":"","label":"Hypernetwork","localized":"","hint":""},
{"id":"","label":"Embedding Learning rate","localized":"","hint":""},
{"id":"","label":"Hypernetwork Learning rate","localized":"","hint":""},
{"id":"","label":"Gradient Clipping","localized":"","hint":""},
{"id":"","label":"Gradient accumulation steps","localized":"","hint":""},
{"id":"","label":"Dataset directory","localized":"","hint":""},
{"id":"","label":"Log directory","localized":"","hint":""},
{"id":"","label":"Prompt template","localized":"","hint":""},
{"id":"","label":"Do not resize images","localized":"","hint":""},
{"id":"","label":"Max steps","localized":"","hint":""},
{"id":"","label":"Save an image to log directory every N steps, 0 to disable","localized":"","hint":""},
{"id":"","label":"Save a copy of embedding to log directory every N steps, 0 to disable","localized":"","hint":""},
{"id":"","label":"Use PNG alpha channel as loss weight","localized":"","hint":""},
{"id":"","label":"Save images with embedding in PNG chunks","localized":"","hint":""},
{"id":"","label":"Read parameters (prompt, etc...) from txt2img tab when making previews","localized":"","hint":""},
{"id":"","label":"Shuffle tags by ',' when creating prompts","localized":"","hint":""},
{"id":"","label":"Drop out tags when creating prompts","localized":"","hint":""},
{"id":"","label":"once","localized":"","hint":""},
{"id":"","label":"deterministic","localized":"","hint":""},
{"id":"","label":"random","localized":"","hint":""}
],
"settings": [
{"id":"","label":"Stable Diffusion checkpoint","localized":"","hint":"Select model checkpoint to use"},
{"id":"","label":"Stable Diffusion checkpoint dict","localized":"","hint":"Select model from which to extract dictionary only"},
{"id":"","label":"Number of cached model checkpoints","localized":"","hint":""},
{"id":"","label":"Number of cached VAE checkpoints","localized":"","hint":""},
{"id":"","label":"Select VAE","localized":"","hint":"Select variable auto-encoder to work with model when rendering images"},
{"id":"","label":"Enable splitting of hires batch processing","localized":"","hint":""},
{"id":"","label":"When loading models attempt stream loading optimized for slow or network storage","localized":"","hint":""},
{"id":"","label":"When loading models attempt to reuse previous model dictionary","localized":"","hint":""},
{"id":"","label":"Disable cross-attention layer optimization","localized":"","hint":""},
{"id":"","label":"xFormers","localized":"","hint":""},
{"id":"","label":"Scaled-Dot-Product","localized":"","hint":""},
{"id":"","label":"Doggettx's","localized":"","hint":""},
{"id":"","label":"InvokeAI's","localized":"","hint":""},
{"id":"","label":"Sub-quadratic","localized":"","hint":""},
{"id":"","label":"Split attention","localized":"","hint":""},
{"id":"","label":"xFormers enable flash Attention","localized":"","hint":""},
{"id":"","label":"SDP disable memory attention","localized":"","hint":""},
{"id":"","label":"Sub-quadratic cross-attention query chunk size","localized":"","hint":""},
{"id":"","label":"Sub-quadratic cross-attention kv chunk size","localized":"","hint":""},
{"id":"","label":"Sub-quadratic cross-attention chunking threshold","localized":"","hint":""},
{"id":"","label":"Full parser","localized":"","hint":""},
{"id":"","label":"Compel parser","localized":"","hint":""},
{"id":"","label":"A1111 parser","localized":"","hint":""},
{"id":"","label":"Fixed attention","localized":"","hint":""},
{"id":"","label":"Prompt attention mean normalization","localized":"","hint":""},
{"id":"","label":"Disable conditional batching enabled on low memory systems","localized":"","hint":""},
{"id":"","label":"Enable samplers quantization for sharper and cleaner results","localized":"","hint":""},
{"id":"","label":"Increase coherency by padding from the last comma within n tokens when using more than 75 tokens","localized":"","hint":""},
{"id":"","label":"Original","localized":"","hint":""},
{"id":"","label":"Diffusers","localized":"","hint":""},
{"id":"","label":"VRAM usage polls per second during generation","localized":"","hint":""},
{"id":"","label":"Autocast","localized":"","hint":""},
{"id":"","label":"Full","localized":"","hint":""},
{"id":"","label":"FP32","localized":"","hint":""},
{"id":"","label":"FP16","localized":"","hint":""},
{"id":"","label":"BF16","localized":"","hint":""},
{"id":"","label":"Use full precision for model (--no-half)","localized":"","hint":""},
{"id":"","label":"Use full precision for VAE (--no-half-vae)","localized":"","hint":""},
{"id":"","label":"Enable upcast sampling","localized":"","hint":""},
{"id":"","label":"Enable upcast cross attention layer","localized":"","hint":""},
{"id":"","label":"Disable NaN check in produced images/latent spaces","localized":"","hint":""},
{"id":"","label":"Attempt to roll back VAE when produced NaN values, requires NaN check (experimental)","localized":"","hint":""},
{"id":"","label":"Use channels last as torch memory format ","localized":"","hint":""},
{"id":"","label":"Enable full-depth cuDNN benchmark feature","localized":"","hint":""},
{"id":"","label":"Allow TF32 math ops","localized":"","hint":""},
{"id":"","label":"Allow TF16 reduced precision math ops","localized":"","hint":""},
{"id":"","label":"Enable model compile (experimental)","localized":"","hint":""},
{"id":"","label":"inductor","localized":"","hint":""},
{"id":"","label":"cudagraphs","localized":"","hint":""},
{"id":"","label":"aot_ts_nvfuser","localized":"","hint":""},
{"id":"","label":"hidet","localized":"","hint":""},
{"id":"","label":"ipex","localized":"","hint":""},
{"id":"","label":"Model compile verbose mode","localized":"","hint":""},
{"id":"","label":"Model compile suppress errors","localized":"","hint":""},
{"id":"","label":"Disable Torch memory garbage collection (experimental)","localized":"","hint":""},
{"id":"","label":"Directory for temporary images; leave empty for default","localized":"","hint":""},
{"id":"","label":"Cleanup non-default temporary directory when starting webui","localized":"","hint":""},
{"id":"","label":"Path to directory with stable diffusion checkpoints","localized":"","hint":""},
{"id":"","label":"Path to directory with stable diffusion diffusers","localized":"","hint":""},
{"id":"","label":"Path to directory with VAE files","localized":"","hint":""},
{"id":"","label":"Embeddings directory for textual inversion","localized":"","hint":""},
{"id":"","label":"Hypernetwork directory","localized":"","hint":""},
{"id":"","label":"Path to directory with codeformer model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with GFPGAN model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with ESRGAN model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with BSRGAN model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with RealESRGAN model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with ScuNET model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with SwinIR model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with LDSR model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with CLIP model file(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with Lora network(s)","localized":"","hint":""},
{"id":"","label":"Path to directory with LyCORIS network(s)","localized":"","hint":""},
{"id":"","label":"Path to user-defined styles file","localized":"","hint":""},
{"id":"","label":"Always save all generated images","localized":"","hint":""},
{"id":"","label":"File format for generated images","localized":"","hint":""},
{"id":"","label":"Images filename pattern","localized":"","hint":"Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default"},
{"id":"","label":"Add number to filename when saving","localized":"","hint":""},
{"id":"","label":"Always save all generated image grids","localized":"","hint":""},
{"id":"","label":"File format for grids","localized":"","hint":""},
{"id":"","label":"Add extended info (seed, prompt) to filename when saving grid","localized":"","hint":""},
{"id":"","label":"Do not save grids consisting of one picture","localized":"","hint":""},
{"id":"","label":"Prevent empty spots in grid (when set to autodetect)","localized":"","hint":""},
{"id":"","label":"Grid row count; use -1 for autodetect and 0 for it to be same as batch size","localized":"","hint":""},
{"id":"","label":"Create a text file next to every image with generation parameters","localized":"","hint":""},
{"id":"","label":"Create a JSON log file with image information for each saved image","localized":"","hint":""},
{"id":"","label":"Save a copy of image before doing face restoration","localized":"","hint":""},
{"id":"","label":"Save a copy of image before applying highres fix","localized":"","hint":""},
{"id":"","label":"Save a copy of image before applying color correction to img2img results","localized":"","hint":""},
{"id":"","label":"Save a copy of the inpainting greyscale mask","localized":"","hint":""},
{"id":"","label":"Save a copy of inpainting masked composite","localized":"","hint":""},
{"id":"","label":"Save a copy of processing init images","localized":"","hint":""},
{"id":"","label":"Quality for saved jpeg images","localized":"","hint":""},
{"id":"","label":"Use lossless compression for webp images","localized":"","hint":""},
{"id":"","label":"Maximum allowed image size in megapixels","localized":"","hint":""},
{"id":"","label":"Use original name for output filename during batch process in extras tab","localized":"","hint":""},
{"id":"","label":"Use upscaler name as filename suffix in the extras tab","localized":"","hint":""},
{"id":"","label":"When using 'Save' button, only save a single selected image","localized":"","hint":""},
{"id":"","label":"Save images to a subdirectory","localized":"","hint":""},
{"id":"","label":"Save grids to a subdirectory","localized":"","hint":""},
{"id":"","label":"Save images to a subdirectory when using Save button","localized":"","hint":""},
{"id":"","label":"Directory name pattern","localized":"","hint":"Use following tags to define how subdirectories for images and grids are chosen: [steps], [cfg],[prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default"},
{"id":"","label":"Max prompt words for [prompt_words] pattern","localized":"","hint":""},
{"id":"","label":"Apply color correction to match original colors","localized":"","hint":""},
{"id":"","label":"For image processing do exact number of steps as specified","localized":"","hint":""},
{"id":"","label":"Image transparent color fill","localized":"","hint":""},
{"id":"","label":"Inpainting conditioning mask strength","localized":"","hint":"Determines how strongly to mask off the original image for inpainting and img2img. 1.0 means fully masked (default). 0.0 means a fully unmasked conditioning. Lower values will help preserve the overall composition of the image, but will struggle with large changes"},
{"id":"","label":"Noise multiplier for image processing","localized":"","hint":""},
{"id":"","label":"Clip skip","localized":"","hint":"Early stopping parameter for CLIP model; 1 is stop at last layer as usual, 2 is stop at penultimate layer, etc"},
{"id":"","label":"Output directory for images; if empty, defaults to three directories below","localized":"","hint":""},
{"id":"","label":"Output directory for txt2img images","localized":"","hint":""},
{"id":"","label":"Output directory for img2img images","localized":"","hint":""},
{"id":"","label":"Output directory for images from extras tab","localized":"","hint":""},
{"id":"","label":"Output directory for grids; if empty, defaults to two directories below","localized":"","hint":""},
{"id":"","label":"Output directory for txt2img grids","localized":"","hint":""},
{"id":"","label":"Output directory for img2img grids","localized":"","hint":""},
{"id":"","label":"Directory for saving images using the Save button","localized":"","hint":""},
{"id":"","label":"Directory for saving init images when using img2img","localized":"","hint":""},
{"id":"","label":"UI theme","localized":"","hint":""},
{"id":"","label":"Auto","localized":"","hint":""},
{"id":"","label":"Dark","localized":"","hint":""},
{"id":"","label":"Light","localized":"","hint":""},
{"id":"","label":"Show grid in results for web","localized":"","hint":""},
{"id":"","label":"For inpainting, include the greyscale mask in results for web","localized":"","hint":""},
{"id":"","label":"For inpainting, include masked composite in results for web","localized":"","hint":""},
{"id":"","label":"Do not change the selected model when reading generation parameters","localized":"","hint":""},
{"id":"","label":"Send seed when sending prompt or image to other interface","localized":"","hint":""},
{"id":"","label":"Send size when sending prompt or image to another interface","localized":"","hint":""},
{"id":"","label":"Font for image grids that have text","localized":"","hint":""},
{"id":"","label":"Ctrl+up/down precision when editing (attention:1.1)","localized":"","hint":""},
{"id":"","label":"Ctrl+up/down precision when editing <extra networks:0.9>","localized":"","hint":""},
{"id":"","label":"Ctrl+up/down word delimiters","localized":"","hint":""},
{"id":"","label":"Quicksettings list","localized":"","hint":"List of setting names, separated by commas, for settings that should go to the quick access bar at the top instead the setting tab"},
{"id":"","label":"Hidden UI tabs","localized":"","hint":""},
{"id":"","label":"UI tabs order","localized":"","hint":""},
{"id":"","label":"UI scripts order","localized":"","hint":""},
{"id":"","label":"txt2img/img2img UI item order","localized":"","hint":""},
{"id":"","label":"Extra networks tab order","localized":"","hint":"Comma-separated list of tab names; tabs listed here will appear in the extra networks UI first and in order lsited"},
{"id":"","label":"Show progressbar","localized":"","hint":""},
{"id":"","label":"Show live previews of the created image","localized":"","hint":""},
{"id":"","label":"Show previews of all images generated in a batch as a grid","localized":"","hint":""},
{"id":"","label":"Play a sound when images are finished generating","localized":"","hint":""},
{"id":"","label":"Path to notification sound","localized":"","hint":""},
{"id":"","label":"Live preview display period","localized":"","hint":""},
{"id":"","label":"Full VAE","localized":"","hint":""},
{"id":"","label":"Approximate NN","localized":"","hint":"Cheap neural network approximation. Very fast compared to VAE, but produces pictures with 4 times smaller horizontal/vertical resolution and lower quality"},
{"id":"","label":"Approximate simple","localized":"","hint":"Very cheap approximation. Very fast compared to VAE, but produces pictures with 8 times smaller horizontal/vertical resolution and extremely low quality"},
{"id":"","label":"TAESD","localized":"","hint":""},
{"id":"","label":"Combined","localized":"","hint":""},
{"id":"","label":"Progressbar/preview update period, in milliseconds","localized":"","hint":""},
{"id":"","label":"Euler a","localized":"","hint":"Euler Ancestral - very creative, each can get a completely different picture depending on step count, setting steps higher than 30-40 does not help"},
{"id":"","label":"Euler","localized":"","hint":""},
{"id":"","label":"LMS","localized":"","hint":""},
{"id":"","label":"Heun","localized":"","hint":""},
{"id":"","label":"DPM2","localized":"","hint":""},
{"id":"","label":"DPM2 a","localized":"","hint":""},
{"id":"","label":"DPM++ 2S a","localized":"","hint":""},
{"id":"","label":"DPM++ 2M","localized":"","hint":""},
{"id":"","label":"DPM++ SDE","localized":"","hint":""},
{"id":"","label":"DPM++ 2M SDE","localized":"","hint":""},
{"id":"","label":"DPM fast","localized":"","hint":""},
{"id":"","label":"DPM adaptive","localized":"","hint":"Ignores step count - uses a number of steps determined by the CFG and resolution"},
{"id":"","label":"LMS Karras","localized":"","hint":""},
{"id":"","label":"DPM2 Karras","localized":"","hint":""},
{"id":"","label":"DPM2 a Karras","localized":"","hint":""},
{"id":"","label":"DPM++ 2S a Karras","localized":"","hint":""},
{"id":"","label":"DPM++ 2M Karras","localized":"","hint":""},
{"id":"","label":"DPM++ SDE Karras","localized":"","hint":""},
{"id":"","label":"DPM++ 2M SDE Karras","localized":"","hint":""},
{"id":"","label":"DDIM","localized":"","hint":"Denoising Diffusion Implicit Models - best at inpainting"},
{"id":"","label":"UniPC","localized":"","hint":"Unified Predictor-Corrector Framework for Fast Sampling of Diffusion Models"},
{"id":"","label":"Secondary sampler","localized":"","hint":""},
{"id":"","label":"Force latent upscaler sampler","localized":"","hint":""},
{"id":"","label":"Noise multiplier for ancestral samplers (eta)","localized":"","hint":""},
{"id":"","label":"Noise multiplier for DDIM (eta)","localized":"","hint":""},
{"id":"","label":"uniform","localized":"","hint":""},
{"id":"","label":"quad","localized":"","hint":""},
{"id":"","label":"sigma churn","localized":"","hint":""},
{"id":"","label":"Negative Guidance minimum sigma","localized":"","hint":""},
{"id":"","label":"sigma tmin","localized":"","hint":""},
{"id":"","label":"sigma noise","localized":"","hint":""},
{"id":"","label":"Noise seed delta (eta)","localized":"","hint":""},
{"id":"","label":"Always discard next-to-last sigma","localized":"","hint":""},
{"id":"","label":"bh1","localized":"","hint":""},
{"id":"","label":"bh2","localized":"","hint":""},
{"id":"","label":"vary_coeff","localized":"","hint":""},
{"id":"","label":"time_uniform","localized":"","hint":""},
{"id":"","label":"time_quadratic","localized":"","hint":""},
{"id":"","label":"logSNR","localized":"","hint":""},
{"id":"","label":"UniPC order (must be < sampling steps)","localized":"","hint":""},
{"id":"","label":"UniPC lower order final","localized":"","hint":""},
{"id":"","label":"Enable addtional postprocessing operations","localized":"","hint":""},
{"id":"","label":"Postprocessing operation order","localized":"","hint":""},
{"id":"","label":"Maximum number of images in upscaling cache","localized":"","hint":""},
{"id":"","label":"Move VAE and CLIP to RAM when training if possible","localized":"","hint":""},
{"id":"","label":"Pin training dataset to memory","localized":"","hint":""},
{"id":"","label":"Saves resumable optimizer state when training embedding or hypernetwork","localized":"","hint":""},
{"id":"","label":"Save textual inversion and hypernet settings to a text file whenever training starts","localized":"","hint":""},
{"id":"","label":"Filename word regex","localized":"","hint":"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"},
{"id":"","label":"Filename join string","localized":"","hint":"This string will be used to join split words into a single line if the option above is enabled"},
{"id":"","label":"Embeddings train templates directory","localized":"","hint":""},
{"id":"","label":"Number of repeats for a single input image per epoch; used only for displaying epoch number","localized":"","hint":""},
{"id":"","label":"Save an csv containing the loss to log directory every N steps, 0 to disable","localized":"","hint":""},
{"id":"","label":"Enable tensorboard logging","localized":"","hint":""},
{"id":"","label":"Save generated images within tensorboard","localized":"","hint":""},
{"id":"","label":"How often, in seconds, to flush the pending tensorboard events and summaries to disk","localized":"","hint":""},
{"id":"","label":"Interrogate: keep models in VRAM","localized":"","hint":""},
{"id":"","label":"Interrogate: include ranks of model tags matches in results","localized":"","hint":""},
{"id":"","label":"Interrogate: num_beams for BLIP","localized":"","hint":""},
{"id":"","label":"Interrogate: minimum description length (excluding artists, etc..)","localized":"","hint":""},
{"id":"","label":"Interrogate: maximum description length","localized":"","hint":""},
{"id":"","label":"CLIP: maximum number of lines in text file (0 = No limit)","localized":"","hint":""},
{"id":"","label":"flavors","localized":"","hint":""},
{"id":"","label":"artists","localized":"","hint":""},
{"id":"","label":"mediums","localized":"","hint":""},
{"id":"","label":"movements","localized":"","hint":""},
{"id":"","label":"Interrogate: deepbooru score threshold","localized":"","hint":""},
{"id":"","label":"Interrogate: deepbooru sort alphabetically","localized":"","hint":""},
{"id":"","label":"use spaces for tags in deepbooru","localized":"","hint":""},
{"id":"","label":"escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)","localized":"","hint":""},
{"id":"","label":"filter out those tags from deepbooru output (separated by comma)","localized":"","hint":""},
{"id":"","label":"Default upscaler for image resize operations","localized":"","hint":""},
{"id":"","label":"Tile size for ESRGAN upscalers (0 = no tiling)","localized":"","hint":""},
{"id":"","label":"Tile overlap in pixels for ESRGAN upscalers","localized":"","hint":""},
{"id":"","label":"Tile size for SCUNET upscalers. 0 = no tiling","localized":"","hint":""},
{"id":"","label":"Tile overlap, in pixels for SCUNET upscalers. Low values = visible seam","localized":"","hint":""},
{"id":"","label":"Hires fix uses width & height to set final resolution rather than first pass","localized":"","hint":""},
{"id":"","label":"Do not fix prompt schedule for second order samplers","localized":"","hint":""},
{"id":"","label":"Use LyCoris handler for all Lora types","localized":"","hint":""},
{"id":"","label":"Use Kohya method for handling multiple Loras","localized":"","hint":""},
{"id":"","label":"CodeFormer","localized":"","hint":""},
{"id":"","label":"GFPGAN","localized":"","hint":"Restore low quality faces using GFPGAN neural network"},
{"id":"","label":"CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect","localized":"","hint":""},
{"id":"","label":"Move face restoration model from VRAM into RAM after processing","localized":"","hint":""},
{"id":"","label":"Default view for Extra Networks","localized":"","hint":""},
{"id":"","label":"Multiplier for extra networks","localized":"","hint":"When adding extra network such as Hypernetwork or Lora to prompt, use this multiplier for it"},
{"id":"","label":"Card width for Extra Networks (px)","localized":"","hint":""},
{"id":"","label":"Card height for Extra Networks (px)","localized":"","hint":""},
{"id":"","label":"Extra text to add before <...> when adding extra network to prompt","localized":"","hint":""},
{"id":"","label":"Add hypernetwork to prompt","localized":"","hint":""},
{"id":"","label":"Enable redundant token merging via tomesd for speed and memory improvements","localized":"","hint":""},
{"id":"","label":"Token merging Ratio. Higher merging ratio = faster generation, smaller VRAM usage, lower quality","localized":"","hint":""},
{"id":"","label":"Apply only to high-res fix pass. Disabling can yield a ~20-35% speedup on contemporary resolutions","localized":"","hint":""},
{"id":"","label":"Merging Ratio (high-res pass) - If 'Apply only to high-res' is enabled, this will always be the ratio used","localized":"","hint":""},
{"id":"","label":"Use random perturbations - Can improve outputs for certain samplers. For others, it may cause visual artifacting","localized":"","hint":""},
{"id":"","label":"Merge attention (Recommend on)","localized":"","hint":""},
{"id":"","label":"Merge cross attention (Recommend off)","localized":"","hint":""},
{"id":"","label":"Merge mlp (Strongly recommend off)","localized":"","hint":""},
{"id":"","label":"Stride - X","localized":"","hint":""},
{"id":"","label":"Stride - Y","localized":"","hint":""}
],
"scripts": [
{"id":"","label":"Script","localized":"","hint":""},
{"id":"","label":"Swap X/Y axes","localized":"","hint":""},
{"id":"","label":"Swap Y/Z axes","localized":"","hint":""},
{"id":"","label":"Swap X/Z axes","localized":"","hint":""},
{"id":"","label":"Resize to ","localized":"","hint":""},
{"id":"","label":"Resize by ","localized":"","hint":""},
{"id":"","label":"Use via API ","localized":"","hint":""},
{"id":"","label":"Styles","localized":"","hint":""},
{"id":"","label":"Put variable parts at start of prompt","localized":"","hint":""},
{"id":"","label":"Use different seed for each picture","localized":"","hint":""},
{"id":"","label":"positive","localized":"","hint":""},
{"id":"","label":"negative","localized":"","hint":""},
{"id":"","label":"comma","localized":"","hint":""},
{"id":"","label":"space","localized":"","hint":""},
{"id":"","label":"Iterate seed every line","localized":"","hint":""},
{"id":"","label":"Use same random seed for all lines","localized":"","hint":""},
{"id":"","label":"List of prompt inputs","localized":"","hint":""},
{"id":"","label":"X type","localized":"","hint":""},
{"id":"","label":"X values","localized":"","hint":"Separate values for X axis using commas"},
{"id":"","label":"Y type","localized":"","hint":""},
{"id":"","label":"Y values","localized":"","hint":"Separate values for Y axis using commas"},
{"id":"","label":"Z type","localized":"","hint":""},
{"id":"","label":"Z values","localized":"","hint":""},
{"id":"","label":"Draw legend","localized":"","hint":""},
{"id":"","label":"Keep random for seeds","localized":"","hint":""},
{"id":"","label":"Do not create grid","localized":"","hint":""},
{"id":"","label":"Include Sub Images","localized":"","hint":""},
{"id":"","label":"Include Sub Grids","localized":"","hint":""},
{"id":"","label":"Override `Sampling method` to Euler?(this method is built for it)","localized":"","hint":""},
{"id":"","label":"Override `prompt` to the same value as `original prompt`?(and `negative prompt`)","localized":"","hint":""},
{"id":"","label":"Original prompt","localized":"","hint":""},
{"id":"","label":"Original negative prompt","localized":"","hint":""},
{"id":"","label":"Override `Sampling Steps` to the same value as `Decode steps`?","localized":"","hint":""},
{"id":"","label":"Decode steps","localized":"","hint":""},
{"id":"","label":"Override `Denoising strength` to 1?","localized":"","hint":""},
{"id":"","label":"Decode CFG scale","localized":"","hint":""},
{"id":"","label":"Randomness","localized":"","hint":""},
{"id":"","label":"Sigma adjustment for finding noise for image","localized":"","hint":""},
{"id":"","label":"Loops","localized":"","hint":"How many times to process an image. Each output is used as the input of the next loop. If set to 1, behavior will be as if this script were not used"},
{"id":"","label":"Final denoising strength","localized":"","hint":"The denoising strength for the final loop of each image in the batch"},
{"id":"","label":"Denoising strength curve","localized":"","hint":"The denoising curve controls the rate of denoising strength change each loop. Aggressive: Most of the change will happen towards the start of the loops. Linear: Change will be constant through all loops. Lazy: Most of the change will happen towards the end of the loops"},
{"id":"","label":"Append interrogated prompt at each iteration","localized":"","hint":""},
{"id":"","label":"Pixels to expand","localized":"","hint":""},
{"id":"","label":"left","localized":"","hint":""},
{"id":"","label":"right","localized":"","hint":""},
{"id":"","label":"up","localized":"","hint":""},
{"id":"","label":"down","localized":"","hint":""},
{"id":"","label":"Fall-off exponent (lower=higher detail)","localized":"","hint":""},
{"id":"","label":"Color variation","localized":"","hint":""},
{"id":"","label":"Tile overlap","localized":"","hint":"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"},
{"id":"","label":"Scale Factor","localized":"","hint":""},
{"id":"","label":"None","localized":"","hint":"Do not do anything special"},
{"id":"","label":"Grid margins","localized":"","hint":""}
]
}
+61 -89
View File
@@ -9,13 +9,9 @@ import subprocess
import io
import pstats
import cProfile
import argparse
import pkg_resources
try:
from modules.cmd_args import parser
except:
import argparse
parser = argparse.ArgumentParser(description="SD.Next", conflict_handler='resolve', formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=55, indent_increment=2, width=200))
class Dot(dict): # dot notation access to dictionary attributes
__getattr__ = dict.get
@@ -24,7 +20,7 @@ class Dot(dict): # dot notation access to dictionary attributes
log = logging.getLogger("sd")
log_file = os.path.join(os.path.dirname(__file__), 'webui.log')
log_file = os.path.join(os.path.dirname(__file__), 'sdnext.log')
quick_allowed = True
errors = 0
opts = {}
@@ -69,8 +65,6 @@ def setup_logging(clean=False):
"traceback.border.syntax_error": "black",
"inspect.value.border": "black",
}))
# logging.getLogger("urllib3").setLevel(logging.ERROR)
# logging.getLogger("httpx").setLevel(logging.ERROR)
level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(level=logging.ERROR, format='%(asctime)s | %(name)s | %(levelname)s | %(module)s | %(message)s', filename=log_file, filemode='a', encoding='utf-8', force=True)
log.setLevel(logging.DEBUG) # log to file is always at level debug for facility `sd`
@@ -81,6 +75,9 @@ def setup_logging(clean=False):
while log.hasHandlers() and len(log.handlers) > 0:
log.removeHandler(log.handlers[0])
log.addHandler(rh)
logging.getLogger("urllib3").setLevel(logging.ERROR)
logging.getLogger("httpx").setLevel(logging.ERROR)
logging.getLogger("ControlNet").handlers = log.handlers
def print_profile(profile: cProfile.Profile, msg: str):
@@ -120,7 +117,7 @@ def installed(package, friendly: str = None):
ok = ok and spec is not None
if ok:
version = pkg_resources.get_distribution(p[0]).version
log.debug(f"Package version found: {p[0]} {version}")
# log.debug(f"Package version found: {p[0]} {version}")
if len(p) > 1:
ok = ok and version == p[1]
if not ok:
@@ -346,12 +343,24 @@ def check_torch():
print_profile(pr, 'Torch')
# check modified files
def check_modified_files():
if args.skip_git:
return
try:
res = git('status --porcelain')
files = [x[2:].strip() for x in res.split('\n')]
log.warning(f'Modified files: {files}')
except:
pass
# install required packages
def install_packages():
if args.profile:
pr = cProfile.Profile()
pr.enable()
log.info('Installing packages')
log.info('Verifying packages')
# gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379")
# openclip_package = os.environ.get('OPENCLIP_PACKAGE', "git+https://github.com/mlfoundations/open_clip.git@bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b")
# install(gfpgan_package, 'gfpgan')
@@ -418,15 +427,21 @@ def run_extension_installer(folder):
log.error(f'Exception running extension installer: {e}')
# get list of all enabled extensions
def list_extensions(folder):
disabled_extensions = opts.get('disable_all_extensions', 'none')
if disabled_extensions != 'none':
log.debug(f'Disabled extensions: {disabled_extensions}')
def list_extensions(folder, quiet=False):
name = os.path.basename(folder)
disabled_extensions_all = opts.get('disable_all_extensions', 'none')
if disabled_extensions_all != 'none':
if not quiet:
log.info(f'Disabled {name}: {disabled_extensions_all}')
return []
disabled_extensions = set(opts.get('disabled_extensions', []))
disabled_extensions = opts.get('disabled_extensions', [])
if len(disabled_extensions) > 0:
log.debug(f'Disabled extensions: {disabled_extensions}')
return [x for x in os.listdir(folder) if x not in disabled_extensions and not x.startswith('.')]
if not quiet:
log.info(f'Disabled {name}: {disabled_extensions}')
enabled_extensions = [x for x in os.listdir(folder) if x not in disabled_extensions and not x.startswith('.')]
if not quiet:
log.info(f'Enabled {name}: {enabled_extensions}')
return enabled_extensions
# run installer for each installed and enabled extension and optionally update them
@@ -441,10 +456,12 @@ def install_extensions():
extensions_duplicates = []
extensions_enabled = []
extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir]
if args.base:
extension_folders = []
for folder in extension_folders:
if not os.path.isdir(folder):
continue
extensions = list_extensions(folder)
extensions = list_extensions(folder, quiet=True)
log.debug(f'Extensions all: {extensions}')
for ext in extensions:
if ext in extensions_enabled:
@@ -552,6 +569,8 @@ def check_extensions():
newest_all = os.path.getmtime('requirements.txt')
from modules.paths_internal import extensions_builtin_dir, extensions_dir
extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir]
if args.base:
extension_folders = []
for folder in extension_folders:
if not os.path.isdir(folder):
continue
@@ -568,7 +587,7 @@ def check_extensions():
ts = os.path.getmtime(os.path.join(extension_dir, f))
newest = max(newest, ts)
newest_all = max(newest_all, newest)
log.debug(f'Extension version: {time.ctime(newest)} {folder}{os.pathsep}{ext}')
# log.debug(f'Extension version: {time.ctime(newest)} {folder}{os.pathsep}{ext}')
return round(newest_all)
@@ -578,14 +597,12 @@ def check_version(offline=False, reset=True): # pylint: disable=unused-argument
log.error('Not a git repository')
if not args.ignore:
sys.exit(1)
# status = git('status')
# if 'branch' not in status:
# log.error('Cannot get git repository status')
# sys.exit(1)
ver = git('log -1 --pretty=format:"%h %ad"')
log.info(f'Version: {ver}')
if args.version:
return
if args.skip_git:
return
commit = git('rev-parse HEAD')
global git_commit # pylint: disable=global-statement
git_commit = commit[:7]
@@ -666,7 +683,7 @@ def check_timestamp():
return ok
def add_args():
def add_args(parser):
group = parser.add_argument_group('Setup options')
group.add_argument('--debug', default = False, action='store_true', help = "Run installer with debug logging, default: %(default)s")
group.add_argument('--reset', default = False, action='store_true', help = "Reset main repository to latest version, default: %(default)s")
@@ -686,44 +703,39 @@ def add_args():
group.add_argument('--version', default = False, action='store_true', help = "Print version information")
group.add_argument('--ignore', default = False, action='store_true', help = "Ignore any errors and attempt to continue")
group.add_argument('--safe', default = False, action='store_true', help = "Run in safe mode with no user extensions")
group.add_argument('--base', default = False, action='store_true', help = argparse.SUPPRESS)
def parse_args():
def parse_args(parser):
# command line args
global args # pylint: disable=global-statement
args = parser.parse_args()
return args
def extensions_preload(force = False):
def extensions_preload(parser):
if args.profile:
pr = cProfile.Profile()
pr.enable()
setup_time = 0
if not force:
if os.path.isfile(log_file):
with open(log_file, 'r', encoding='utf8') as f:
lines = f.readlines()
for line in lines:
if 'Setup complete without errors' in line:
setup_time = int(line.split(' ')[-1])
if setup_time > 0 or force:
log.info('Running extension preloading')
if args.safe:
log.info('Running in safe mode without user extensions')
try:
from modules.script_loading import preload_extensions
from modules.paths_internal import extensions_builtin_dir, extensions_dir
extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir]
for ext_dir in extension_folders:
t0 = time.time()
preload_extensions(ext_dir, parser)
t1 = time.time()
log.debug(f'Extension preload: {round(t1 - t0, 1)}s {ext_dir}')
except:
log.error('Error running extension preloading')
if args.safe:
log.info('Running in safe mode without user extensions')
try:
from modules.script_loading import preload_extensions
from modules.paths_internal import extensions_builtin_dir, extensions_dir
extension_folders = [extensions_builtin_dir] if args.safe else [extensions_builtin_dir, extensions_dir]
if args.base:
extension_folders = []
for ext_dir in extension_folders:
t0 = time.time()
preload_extensions(ext_dir, parser)
t1 = time.time()
log.info(f'Extension preload: {round(t1 - t0, 1)}s {ext_dir}')
except:
log.error('Error running extension preloading')
if args.profile:
print_profile(pr, 'Preload')
def git_reset():
log.warning('Running GIT reset')
global quick_allowed # pylint: disable=global-statement
@@ -740,43 +752,3 @@ def read_options():
if os.path.isfile(args.config):
with open(args.config, "r", encoding="utf8") as file:
opts = json.load(file)
# entry method when used as module
def run_setup():
# setup_logging(args.upgrade)
log.info('Starting SD.Next')
read_options()
check_python()
if args.reset:
git_reset()
if args.skip_git:
log.info('Skipping GIT operations')
check_version()
set_environment()
if args.reinstall:
log.info('Forcing reinstall of all packages')
check_torch()
install_requirements()
install_packages()
if check_timestamp():
log.info('No changes detected: Quick launch active')
return
log.info("Running setup")
log.debug(f"Args: {vars(args)}")
install_repositories()
install_submodules()
install_extensions()
update_wiki()
if errors == 0:
log.debug(f'Setup complete without errors: {round(time.time())}')
else:
log.warning(f'Setup complete with errors: {errors}')
log.warning(f'See log file for more details: {log_file}')
if __name__ == "__main__":
add_args()
ensure_base_requirements()
parse_args()
run_setup()
+1 -3
View File
@@ -1,5 +1,3 @@
/* global gradioApp, onUiUpdate, get_tab_index */
let currentWidth = null;
let currentHeight = null;
let arFrameTimeout = setTimeout(() => {}, 0);
@@ -52,7 +50,7 @@ function dimensionChange(e, is_width, is_height) {
}
}
onUiUpdate(() => {
onAfterUiUpdate(() => {
const arPreviewRect = gradioApp().querySelector('#imageARPreview');
if (arPreviewRect) arPreviewRect.style.display = 'none';
const tabImg2img = gradioApp().querySelector('#tab_img2img');
+1 -3
View File
@@ -1,5 +1,3 @@
/* global gradioApp, uiCurrentTab, onUiUpdate, get_uiCurrentTabContent */
const contextMenuInit = () => {
let eventListenerApplied = false;
const menuSpecs = new Map();
@@ -137,4 +135,4 @@ const addContextMenuEventListener = initResponse[2];
}());
// End example Context Menu Items
onUiUpdate(() => addContextMenuEventListener());
onAfterUiUpdate(() => addContextMenuEventListener());
+1
View File
@@ -72,6 +72,7 @@ function cardClicked(tabname, textToAdd, allowNegativePrompt) {
}
function saveCardPreview(event, tabname, filename) {
console.log('saveCardPreview', event, tabname, filename)
const textarea = gradioApp().querySelector(`#${tabname}_preview_filename > label > textarea`);
const button = gradioApp().getElementById(`${tabname}_save_preview`);
textarea.value = filename;
+1 -2
View File
@@ -1,4 +1,3 @@
/* global gradioApp, onUiUpdate */
// attaches listeners to the txt2img and img2img galleries to update displayed generation param text when the image changes
function attachGalleryListeners(tab_name) {
@@ -22,7 +21,7 @@ let txt2img_gallery;
let img2img_gallery;
let modal;
onUiUpdate(() => {
onAfterUiUpdate(() => {
if (!txt2img_gallery) txt2img_gallery = attachGalleryListeners('txt2img');
if (!img2img_gallery) img2img_gallery = attachGalleryListeners('img2img');
if (!modal) {
-97
View File
@@ -1,97 +0,0 @@
// HTML tooltips for various UI elements
titles = {
// unicode icons
'\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',
'\u2199\ufe0f': 'Read generation parameters from prompt or last generation if prompt is empty into user interface.',
'\u{1f4c2}': 'Open images output directory',
'\u{1f4be}': 'Save style',
'\u{1f5d1}\ufe0f': 'Clear prompt',
'\u{1f4cb}': 'Apply selected styles to current prompt',
'\u{1f4d2}': 'Paste available values into the field',
'\u{1f3b4}': 'Show/hide extra networks',
'\u{1F4D8}': 'Read generation parameters from prompt or last generation if prompt is empty into user interface.',
'\u{1F6C5}': 'Save style',
'\u{1F9F3}': 'Apply selected styles to current prompt',
'\u{1F6AE}': 'Clear prompt',
'\u{1F310}': 'Show/hide extra networks',
// strings
'Sampling steps': 'How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results',
'Sampling method': 'Which algorithm to use to produce the image',
'GFPGAN': 'Restore low quality faces using GFPGAN neural network',
'Euler a': 'Euler Ancestral - very creative, each can get a completely different picture depending on step count, setting steps higher than 30-40 does not help',
'DDIM': 'Denoising Diffusion Implicit Models - best at inpainting',
'UniPC': 'Unified Predictor-Corrector Framework for Fast Sampling of Diffusion Models',
'DPM adaptive': 'Ignores step count - uses a number of steps determined by the CFG and resolution',
'Batch count': 'How many batches of images to create (has no impact on generation performance or VRAM usage)',
'Batch size': 'How many image to create in a single batch (increases generation performance at cost of higher VRAM usage)',
'CFG Scale': 'Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results',
'Seed': "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result",
'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',
'Just resize': 'Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.',
'Crop and resize': 'Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.',
'Resize and fill': "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.",
'Mask blur': 'How much to blur the mask before processing, in pixels.',
'Masked content': 'What to put inside the masked area before processing it with Stable Diffusion.',
'fill': 'fill it with colors of the image',
'original': 'keep whatever was there originally',
'latent noise': 'fill it with latent space noise',
'latent nothing': 'fill it with latent space zeroes',
'Inpaint at full resolution': 'Upscale masked region to target resolution, do inpainting, downscale back and paste into original image',
'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.",
'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.',
'X values': 'Separate values for X axis using commas.',
'Y values': 'Separate values for Y axis using commas.',
'None': 'Do not do anything special',
'Prompt matrix': 'Separate prompts into parts using vertical pipe character (|) and the script will create a picture for every combination of them (except for the first part, which will be present in all combinations)',
'X/Y/Z plot': 'Create grid(s) where images will have different parameters. Use inputs below to specify which parameters will be shared by columns and rows',
'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.',
'Variation seed': 'Seed of a different picture to be mixed into the generation.',
'Variation strength': 'How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something).',
'Resize seed from height': 'Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution',
'Resize seed from width': 'Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution',
'Interrogate': 'Reconstruct prompt from existing image and put it into the prompt field.',
'Images filename pattern': 'Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.',
'Directory name pattern': 'Use following tags to define how subdirectories for images and grids are chosen: [steps], [cfg],[prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.',
'Max prompt words': 'Set the maximum number of words to be used in the [prompt_words] option; ATTENTION: If the words are too long, they may exceed the maximum length of the file path that the system can handle',
'Loopback': 'Performs img2img processing multiple times. Output images are used as input for the next loop.',
'Loops': 'How many times to process an image. Each output is used as the input of the next loop. If set to 1, behavior will be as if this script were not used.',
'Final denoising strength': 'The denoising strength for the final loop of each image in the batch.',
'Denoising strength curve': 'The denoising curve controls the rate of denoising strength change each loop. Aggressive: Most of the change will happen towards the start of the loops. Linear: Change will be constant through all loops. Lazy: Most of the change will happen towards the end of the loops.',
'Style 1': 'Style to apply; styles have components for both positive and negative prompts and apply to both',
'Style 2': 'Style to apply; styles have components for both positive and negative prompts and apply to both',
'Apply style': 'Insert selected styles into prompt fields',
'Create style': 'Save current prompts as a style. If you add the token {prompt} to the text, the style uses that as a placeholder for your prompt when you use the style in the future.',
'Checkpoint name': 'Loads weights from checkpoint before making images. You can either use hash or a part of filename (as seen in settings) for checkpoint name. Recommended to use with Y axis for less switching.',
'Inpainting conditioning mask strength': 'Only applies to inpainting models. Determines how strongly to mask off the original image for inpainting and img2img. 1.0 means fully masked, which is the default behaviour. 0.0 means a fully unmasked conditioning. Lower values will help preserve the overall composition of the image, but will struggle with large changes.',
'vram': 'Torch active: Peak amount of VRAM used by Torch during generation, excluding cached data.\nTorch reserved: Peak amount of VRAM allocated by Torch, including all active and cached data.\nSys VRAM: Peak amount of VRAM allocation across all applications / total GPU VRAM (peak utilization%).',
'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 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.',
'Weighted sum': 'Result = A * (1 - M) + B * M',
'Add difference': 'Result = A + (B - C) * M',
'No interpolation': 'Result = A',
'Initialization text': 'If the number of tokens is more than the number of vectors, some may be skipped.\nLeave the textbox empty to start with zeroed out vectors',
'Learning rate': 'How fast should training go. Low values will take longer to train, high values may fail to converge (not generate accurate results) and/or may break the embedding (This has happened if you see Loss: nan in the training info textbox. If this happens, you need to manually restore your embedding from an older not-broken backup).\n\nYou can set a single numeric value, or multiple learning rates using the syntax:\n\n rate_1:max_steps_1, rate_2:max_steps_2, ...\n\nEG: 0.005:100, 1e-3:1000, 1e-5\n\nWill train with rate of 0.005 for first 100 steps, then 1e-3 until 1000 steps, then 1e-5 for all remaining steps.',
'Clip skip': 'Early stopping parameter for CLIP model; 1 is stop at last layer as usual, 2 is stop at penultimate layer, etc.',
'Approx NN': 'Cheap neural network approximation. Very fast compared to VAE, but produces pictures with 4 times smaller horizontal/vertical resolution and lower quality.',
'Approx cheap': 'Very cheap approximation. Very fast compared to VAE, but produces pictures with 8 times smaller horizontal/vertical resolution and extremely low quality.',
'Hires. fix': 'Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition',
'Hires steps': 'Number of sampling steps for upscaled picture. If 0, uses same as for original.',
'Upscale by': 'Adjusts the size of the image by multiplying the original width and height by the selected value. Ignored if either Resize width to or Resize height to are non-zero.',
'Resize width to': 'Resizes image to this width. If 0, width is inferred from either of two nearby sliders.',
'Resize height to': 'Resizes image to this height. If 0, height is inferred from either of two nearby sliders.',
'Multiplier for extra networks': 'When adding extra network such as Hypernetwork or Lora to prompt, use this multiplier for it.',
'Discard weights with matching name': "Regular expression; if weights's name matches it, the weights is not written to the resulting checkpoint. Use ^model_ema to discard EMA weights.",
'Extra networks tab order': 'Comma-separated list of tab names; tabs listed here will appear in the extra networks UI first and in order lsited.',
};
-1
View File
@@ -1,4 +1,3 @@
/* global gradioApp, opts */
function onCalcResolutionHires(enable_hr, width, height, hr_scale, hr_resize_x, hr_resize_y) {
function setInactive(elem, inactive) {
elem.classList.toggle('inactive', !!inactive);
+1 -2
View File
@@ -1,4 +1,3 @@
/* global gradioApp, onUiUpdate */
/**
* temporary fix for https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/668
* @see https://github.com/gradio-app/gradio/issues/1721
@@ -41,5 +40,5 @@ function imageMaskResize() {
});
}
onUiUpdate(imageMaskResize);
onAfterUiUpdate(imageMaskResize);
window.addEventListener('resize', imageMaskResize);
-1
View File
@@ -1,4 +1,3 @@
/* global gradioApp, get_tab_index */
window.onload = (function () {
window.addEventListener('drop', (e) => {
const target = e.composedPath()[0];
+1 -2
View File
@@ -1,4 +1,3 @@
/* global gradioApp, onUiUpdate */
// A full size 'lightbox' preview modal shown when left clicking on gallery previews
function closeModal() {
gradioApp().getElementById('lightboxModal').style.display = 'none';
@@ -143,7 +142,7 @@ function galleryImageHandler(e) {
e.onclick = showGalleryImage;
}
onUiUpdate(() => {
onAfterUiUpdate(() => {
fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img');
if (fullImg_preview != null) fullImg_preview.forEach(setupImageForLightbox);
updateOnBackgroundChange();
+1 -1
View File
@@ -3,7 +3,7 @@
let lastHeadImg = null;
let notificationButton = null;
onUiUpdate(function () {
onAfterUiUpdate(function () {
if (!notificationButton) {
notificationButton = gradioApp().getElementById('request_notifications');
if (notificationButton) notificationButton.addEventListener('click', (evt) => Notification.requestPermission(), true);
-1
View File
@@ -1,4 +1,3 @@
/* global opts */
let lastState = {};
function rememberGallerySelection(id_gallery) {}
+1 -1
View File
@@ -34,7 +34,7 @@ function setupBracketChecking(id_prompt, id_counter) {
}
}
onUiLoaded(function() {
onAfterUiUpdate(function() {
setupBracketChecking('txt2img_prompt', 'txt2img_token_counter');
setupBracketChecking('txt2img_neg_prompt', 'txt2img_negative_token_counter');
setupBracketChecking('img2img_prompt', 'img2img_token_counter');
+26 -10
View File
@@ -13,33 +13,48 @@ function get_uiCurrentTabContent() {
return gradioApp().querySelector('.tabitem[id^=tab_]:not([style*="display: none"])');
}
uiUpdateCallbacks = [];
uiLoadedCallbacks = [];
uiTabChangeCallbacks = [];
optionsChangedCallbacks = [];
const uiAfterUpdateCallbacks = [];
const uiUpdateCallbacks = [];
const uiLoadedCallbacks = [];
const uiTabChangeCallbacks = [];
const optionsChangedCallbacks = [];
let uiCurrentTab = null;
let uiAfterUpdateTimeout = null;
function onAfterUiUpdate(callback) {
uiAfterUpdateCallbacks.push(callback);
}
function onUiUpdate(callback) {
uiUpdateCallbacks.push(callback);
}
function onUiLoaded(callback) {
uiLoadedCallbacks.push(callback);
}
function onUiTabChange(callback) {
uiTabChangeCallbacks.push(callback);
}
function onOptionsChanged(callback) {
optionsChangedCallbacks.push(callback);
}
function runCallback(x, m) {
try {
x(m);
} catch (e) { (console.error || console.log).call(console, e.message, e); }
function executeCallbacks(queue, arg) {
// if (!uiLoaded) return
for (const callback of queue) {
try {
callback(arg);
} catch (e) {
console.error("error running callback", callback, ":", e);
}
}
}
function executeCallbacks(queue, m) {
queue.forEach((x) => { runCallback(x, m); });
function scheduleAfterUiUpdateCallbacks() {
clearTimeout(uiAfterUpdateTimeout);
uiAfterUpdateTimeout = setTimeout(() => executeCallbacks(uiAfterUpdateCallbacks, 500));
}
let executedOnLoaded = false;
@@ -51,6 +66,7 @@ document.addEventListener('DOMContentLoaded', () => {
executeCallbacks(uiLoadedCallbacks);
}
executeCallbacks(uiUpdateCallbacks, m);
scheduleAfterUiUpdateCallbacks();
const newTab = get_uiCurrentTab();
if (newTab && (newTab !== uiCurrentTab)) {
uiCurrentTab = newTab;
+28 -18
View File
@@ -1,20 +1,30 @@
onUiUpdate(() => {
gradioApp().querySelectorAll('span, button, select, p').forEach((span) => {
tooltip = titles[span.textContent];
if (!tooltip) tooltip = titles[span.value];
if (!tooltip) {
for (const c of span.classList) {
if (c in titles) {
tooltip = titles[c];
break;
}
}
}
if (tooltip) span.title = tooltip;
});
let locale = {
data: [],
timeout: null,
finished: false,
}
gradioApp().querySelectorAll('select').forEach((select) => {
if (select.onchange != null) return;
select.onchange = () => select.title = titles[select.value] || '';
});
async function setLocale() {
if (locale.finished) return;
console.log('setLocale');
if (locale.data.length === 0) {
const res = await fetch('/file=html/locale_en.json');
const json = await res.json();
locale.data = Object.values(json).flat();
}
const elements = [
...Array.from(gradioApp().querySelectorAll('button')),
...Array.from(gradioApp().querySelectorAll('label > span')),
];
for (el of elements) {
const found = locale.data.find(l => l.label === el.textContent);
if (found?.localized?.length > 0) el.textContent = found.localized;
if (found?.hint?.length > 0) el.title = found.hint;
}
locale.finished = true;
}
onAfterUiUpdate(async () => {
if (locale.timeout) clearTimeout(locale.timeout);
locale.timeout = setTimeout(setLocale, 250)
});
+2 -1
View File
@@ -93,7 +93,7 @@ footer { display: none !important; }
}
.performance { font-size: 0.85em; color: #444; }
.performance p { display: inline-block; color: var(--primary-100) !important }
.performance p { display: inline-block; color: var(--body-text-color-subdued) !important }
.performance .time { margin-right: 0; }
@media screen and (min-width: 2500px) {
@@ -639,3 +639,4 @@ div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; gri
#scripts_alwayson_txt2img, #scripts_alwayson_img2img { display: grid }
#extras_generate, #extras_interrupt, #extras_skip { display: block !important; position: relative; height: 36px; }
#extras_upscale { margin-top: 10px }
#refresh_tac_refreshTempFiles { display: none; }
+4 -3
View File
@@ -1,5 +1,3 @@
/* global gradioApp, onUiUpdate, opts */
window.opts = {};
window.localization = {};
let tabSelected = '';
@@ -227,7 +225,7 @@ function showAllSettings() {
});
}
onUiUpdate(() => {
onAfterUiUpdate(() => {
sort_ui_elements();
if (Object.keys(opts).length !== 0) return;
const json_elem = gradioApp().getElementById('settings_json');
@@ -512,6 +510,8 @@ function preview_theme() {
}
}
let uiLoaded = false;
function reconnect_ui() {
const api_logo = Array.from(gradioApp().querySelectorAll('img')).filter((el) => el?.src?.endsWith('api-logo.svg'));
if (api_logo.length > 0) api_logo[0].remove();
@@ -525,6 +525,7 @@ function reconnect_ui() {
rememberGallerySelection('txt2img_gallery');
requestProgress(task_id, null, gallery, null, null, true);
}
uiLoaded = true;
const sd_model = gradioApp().getElementById('setting_sd_model_checkpoint');
let loadingStarted = 0;
+55 -23
View File
@@ -4,22 +4,15 @@ import time
import shlex
import logging
import subprocess
import installer
commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
sys.argv += shlex.split(commandline_args)
import installer
installer.ensure_base_requirements()
installer.add_args()
installer.parse_args()
installer.setup_logging(False)
installer.extensions_preload(force=False)
import modules.cmd_args
args, _ = modules.cmd_args.parser.parse_known_args()
import modules.paths_internal
script_path = modules.paths_internal.script_path
extensions_dir = modules.paths_internal.extensions_dir
args = None
parser = None
script_path = None
extensions_dir = None
git = os.environ.get('GIT', "git")
index_url = os.environ.get('INDEX_URL', "")
stored_commit_hash = None
@@ -28,6 +21,17 @@ python = sys.executable # used by some extensions to run python
skip_install = False # parsed by some extensions
def init_modules():
global parser, args, script_path, extensions_dir # pylint: disable=global-statement
import modules.cmd_args
parser = modules.cmd_args.parser
installer.add_args(parser)
args, _ = parser.parse_known_args()
import modules.paths_internal
script_path = modules.paths_internal.script_path
extensions_dir = modules.paths_internal.extensions_dir
def commit_hash(): # compatbility function
global stored_commit_hash # pylint: disable=global-statement
if stored_commit_hash is not None:
@@ -133,19 +137,47 @@ def start_server(immediate=True, server=None):
if __name__ == "__main__":
if args.version:
installer.add_args()
installer.log.info('SD.Next version information')
installer.check_python()
installer.check_version()
installer.check_torch()
exit(0)
installer.run_setup()
installer.extensions_preload(force=True)
installer.ensure_base_requirements()
init_modules() # setup argparser and default folders
installer.args = args
installer.setup_logging(False)
installer.log.info('Starting SD.Next')
installer.read_options()
installer.check_python()
if args.reset:
installer.git_reset()
if args.skip_git:
installer.log.info('Skipping GIT operations')
installer.check_version()
installer.set_environment()
installer.check_torch()
installer.check_modified_files()
if args.reinstall:
installer.log.info('Forcing reinstall of all packages')
installer.quick_allowed = False
if installer.check_timestamp():
installer.log.info('No changes detected: Quick launch active')
installer.check_extensions()
else:
installer.install_requirements()
installer.install_packages()
installer.install_repositories()
installer.install_submodules()
installer.install_extensions()
installer.update_wiki()
if installer.errors == 0:
installer.log.debug(f'Setup complete without errors: {round(time.time())}')
else:
installer.log.warning(f'Setup complete with errors: {installer.errors}')
installer.log.warning(f'See log file for more details: {installer.log_file}')
installer.extensions_preload(parser) # adds additional args from extensions
args = installer.parse_args(parser)
# installer.run_setup()
installer.log.debug(f"Args: {vars(args)}")
installer.log.info(f"Server arguments: {sys.argv[1:]}")
installer.log.debug('Starting WebUI')
logging.disable(logging.NOTSET if args.debug else logging.DEBUG)
instance = start_server(immediate=True, server=None)
while True:
try:
-1
View File
@@ -89,7 +89,6 @@ def save_image(image, fn, ext):
def encode_pil_to_base64(image):
# TODO jpeg
with io.BytesIO() as output_bytes:
save_image(image, output_bytes, shared.opts.samples_format)
bytes_data = output_bytes.getvalue()
+2
View File
@@ -25,6 +25,7 @@ group.add_argument("--freeze", action='store_true', help="Disable editing settin
group.add_argument("--auth", type=str, help='Set access authentication like "user:pwd,user:pwd""', default=None)
group.add_argument("--auth-file", type=str, help='Set access authentication using file, default: %(default)s', default=None)
group.add_argument("--autolaunch", action='store_true', help="Open the UI URL in the system's default browser upon launch", default=False)
group.add_argument('--docs', default = False, action='store_true', help = "Mount Gradio docs at /docs, default: %(default)s")
group.add_argument('--api-only', default = False, action='store_true', help = "Run in API only mode without starting UI")
group.add_argument("--api-log", default=False, action='store_true', help="Enable logging of all API requests, default: %(default)s")
group.add_argument("--device-id", type=str, help="Select the default CUDA device to use, default: %(default)s", default=None)
@@ -91,6 +92,7 @@ def compatibility_args(opts, args):
group.add_argument("--lora-dir", help=argparse.SUPPRESS, default=opts.lora_dir)
group.add_argument("--lyco-dir", help=argparse.SUPPRESS, default=opts.lyco_dir)
group.add_argument("--lyco-patch-lora", help=argparse.SUPPRESS, default=opts.lyco_patch_lora)
group.add_argument("--lyco-debug", help=argparse.SUPPRESS, action='store_true', default=False)
group.add_argument("--enable-console-prompts", help=argparse.SUPPRESS, action='store_true', default=False)
group.add_argument("--safe", help=argparse.SUPPRESS, action='store_true', default=False)
+35 -13
View File
@@ -98,6 +98,18 @@ def test_fp16():
shared.opts.no_half_vae = True
return False
def test_bf16():
if shared.cmd_opts.experimental:
return True
try:
import torch.nn.functional as F
image = torch.randn(1, 4, 32, 32).to(device=device, dtype=torch.bfloat16)
_out = F.interpolate(image, size=(64, 64), mode="nearest")
return True
except:
shared.log.warning('Torch BF16 test failed: Fallback to FP16 operations')
return False
def set_cuda_params():
shared.log.debug('Verifying Torch settings')
@@ -117,25 +129,32 @@ def set_cuda_params():
except:
pass
global dtype, dtype_vae, dtype_unet, unet_needs_upcast # pylint: disable=global-statement
ok = test_fp16()
if shared.cmd_opts.use_directml and not shared.cmd_opts.experimental: # TODO DirectML does not have full autocast capabilities
shared.opts.no_half = True
shared.opts.no_half_vae = True
if ok and shared.opts.cuda_dtype == 'FP32':
shared.log.info('CUDA FP16 test passed but desired mode is set to FP32')
if shared.opts.cuda_dtype == 'FP16' and ok:
dtype = torch.float16
dtype_vae = torch.float16
dtype_unet = torch.float16
if shared.opts.cuda_dtype == 'BF16' and ok:
dtype = torch.bfloat16
dtype_vae = torch.bfloat16
dtype_unet = torch.bfloat16
if shared.opts.cuda_dtype == 'FP32' or shared.opts.no_half or not ok:
if shared.opts.cuda_dtype == 'FP32':
dtype = torch.float32
dtype_vae = torch.float32
dtype_unet = torch.float32
if shared.opts.cuda_dtype == 'BF16' or dtype == torch.bfloat16:
bf16_ok = test_bf16()
dtype = torch.bfloat16 if bf16_ok else torch.float16
dtype_vae = torch.bfloat16 if bf16_ok else torch.float16
dtype_unet = torch.bfloat16 if bf16_ok else torch.float16
if shared.opts.cuda_dtype == 'FP16' or dtype == torch.float16:
fp16_ok = test_fp16()
dtype = torch.float16 if fp16_ok else torch.float32
dtype_vae = torch.float16 if fp16_ok else torch.float32
dtype_unet = torch.float16 if fp16_ok else torch.float32
else:
pass
if shared.opts.no_half:
shared.log.info('Torch override dtype: no-half set')
dtype = torch.float32
dtype_vae = torch.float32
dtype_unet = torch.float32
if shared.opts.no_half_vae: # set dtype again as no-half-vae options take priority
shared.log.info('Torch override VAE dtype: no-half set')
dtype_vae = torch.float32
unet_needs_upcast = shared.opts.upcast_sampling
shared.log.debug(f'Desired Torch parameters: dtype={shared.opts.cuda_dtype} no-half={shared.opts.no_half} no-half-vae={shared.opts.no_half_vae} upscast={shared.opts.upcast_sampling}')
@@ -150,7 +169,10 @@ if args.use_ipex:
CondFunc('torch.nn.modules.GroupNorm.forward',
lambda orig_func, *args, **kwargs: orig_func(args[0], args[1].to(args[0].weight.data.dtype)),
lambda *args, **kwargs: args[2].dtype != args[1].weight.data.dtype)
CondFunc('torch.nn.modules.Linear.forward',
lambda orig_func, *args, **kwargs: orig_func(args[0], args[1].to(args[0].weight.data.dtype)),
lambda *args, **kwargs: args[2].dtype != args[1].weight.data.dtype)
#Use XPU instead of CPU. %20 Perf improvement on weak CPUs.
if args.device_id is not None:
cpu = torch.device(f"xpu:{args.device_id}")
+2
View File
@@ -126,6 +126,8 @@ def list_extensions():
extension_paths = []
extension_names = []
extension_folders = [extensions_builtin_dir] if shared.cmd_opts.safe else [extensions_builtin_dir, extensions_dir]
if shared.cmd_opts.base:
extension_folders = []
for dirname in extension_folders:
if not os.path.isdir(dirname):
return
+1 -1
View File
@@ -352,7 +352,6 @@ def create_override_settings_dict(text_pairs):
def connect_paste(button, local_paste_fields, input_comp, override_settings_component, tabname):
def paste_func(prompt):
shared.log.debug(f'paste prompt: {prompt}')
if prompt is not None and 'Negative prompt' not in prompt and 'Steps' not in prompt:
prompt = None
if not prompt and not shared.cmd_opts.hide_ui_dir_config:
@@ -362,6 +361,7 @@ def connect_paste(button, local_paste_fields, input_comp, override_settings_comp
prompt = file.read()
else:
prompt = ''
shared.log.debug(f'paste prompt: {prompt}')
params = parse_generation_parameters(prompt)
script_callbacks.infotext_pasted_callback(prompt, params)
res = []
+4 -6
View File
@@ -594,12 +594,10 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi
print(e)
if shared.cmd_opts.use_ipex:
scaler = ipex.cpu.autocast._grad_scaler.GradScaler()
#Remove these after Intel adds support for float16 training:
if shared.opts.cuda_dtype == 'BF16':
shared.sd_model = shared.sd_model.bfloat16()
elif shared.opts.cuda_dtype == 'FP32':
shared.sd_model = shared.sd_model.float32()
scaler = ipex.cpu.autocast._grad_scaler.GradScaler() #scaler.step(optimizer): PI_ERROR_INVALID_ARG_VALUE
shared.sd_model = shared.sd_model.to(dtype=torch.float32)
shared.sd_model.train()
shared.sd_model, optimizer = ipex.optimize(shared.sd_model, optimizer=optimizer, dtype=devices.dtype)
else:
scaler = torch.cuda.amp.GradScaler()
+2 -2
View File
@@ -403,8 +403,8 @@ class FilenameGenerator:
elif replacement is not None:
res += text + str(replacement)
continue
res += f'{text}[{pattern}]'
res = res.split('?')[0]
res += f'{text}'
res = res.split('?')[0].strip()
return res
+4
View File
@@ -19,6 +19,8 @@ def memory_stats():
s = torch.cuda.mem_get_info()
gpu = { 'used': gb(s[1] - s[0]), 'total': gb(s[1]) }
s = dict(torch.cuda.memory_stats())
if s['num_ooms'] > 0:
shared.state.oom = True
mem.update({
'gpu': gpu,
'retries': s['num_alloc_retries'],
@@ -35,6 +37,8 @@ def memory_stats():
'retries': s['num_alloc_retries'],
'oom': s['num_ooms']
})
if s['num_ooms'] > 0:
shared.state.oom = True
return mem
except:
pass
+8 -1
View File
@@ -9,9 +9,16 @@ from modules.paths import script_path, models_path
diffuser_repos = []
def load_diffusers(model_path: str, command_path: str = None):
def load_diffusers(model_path: str, hub_url: str = None, command_path: str = None):
import huggingface_hub as hf
from diffusers import DiffusionPipeline
places = []
# download repo
if hub_url is not None:
DiffusionPipeline.download(hub_url, cache_dir=model_path)
places.append(model_path)
if command_path is not None and command_path != model_path and os.path.isdir(command_path):
places.append(command_path)
+13 -2
View File
@@ -3,6 +3,7 @@ import torch.nn.functional as F
import math
import time
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn
from modules import shared
class NoiseScheduleVP:
@@ -684,7 +685,12 @@ class UniPC:
if order == 2:
rhos_p = torch.tensor([0.5], device=b.device)
else:
rhos_p = torch.linalg.solve(R[:-1, :-1], b[:-1])
if shared.cmd_opts.use_ipex:
#Running torch.linalg.solve on XPU crashes the GPU.
rhos_p = torch.linalg.solve(R[:-1, :-1].to("cpu"), b[:-1].to("cpu"))
rhos_p = rhos_p.to(b.device)
else:
rhos_p = torch.linalg.solve(R[:-1, :-1], b[:-1])
else:
D1s = None
@@ -694,7 +700,12 @@ class UniPC:
if order == 1:
rhos_c = torch.tensor([0.5], device=b.device)
else:
rhos_c = torch.linalg.solve(R, b)
if shared.cmd_opts.use_ipex:
#Running torch.linalg.solve on XPU crashes the GPU.
rhos_c = torch.linalg.solve(R.to("cpu"), b.to("cpu"))
rhos_c = rhos_c.to(b.device)
else:
rhos_c = torch.linalg.solve(R, b)
model_t = None
if self.predict_x0:
+1
View File
@@ -2,6 +2,7 @@ import os
import sys
import modules.paths_internal
data_path = modules.paths_internal.data_path
script_path = modules.paths_internal.script_path
models_path = modules.paths_internal.models_path
+3 -2
View File
@@ -62,7 +62,8 @@ def run_postprocessing(extras_mode, image, image_folder: List[tempfile.NamedTemp
basename = os.path.splitext(os.path.basename(name))[0]
else:
basename = ''
_geninfo, items = images.read_info_from_image(image)
geninfo, items = images.read_info_from_image(image)
params = generation_parameters_copypaste.parse_generation_parameters(geninfo)
for k, v in items.items():
pp.image.info[k] = v
if 'parameters' in items:
@@ -75,7 +76,7 @@ def run_postprocessing(extras_mode, image, image_folder: List[tempfile.NamedTemp
outputs.append(pp.image)
devices.torch_gc()
return outputs, ui_common.infotext_to_html(infotext), pp.image.info
return outputs, ui_common.infotext_to_html(infotext), params
def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_dir, show_extras_results, 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, upscale_first: bool, save_output: bool = True): #pylint: disable=unused-argument
+3 -3
View File
@@ -609,7 +609,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
with torch.no_grad(), ema_scope_context():
with devices.autocast():
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
if shared.opts.live_previews_enable and opts.show_progress_type == "Approx NN" and backend == Backend.ORIGINAL:
if shared.opts.live_previews_enable and opts.show_progress_type == "Approximate NN" and backend == Backend.ORIGINAL:
sd_vae_approx.model()
if state.job_count == -1:
state.job_count = p.n_iter
@@ -933,7 +933,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
image_conditioning = self.img2img_image_conditioning(decoded_samples, samples)
shared.state.nextjob()
img2img_sampler_name = self.sampler_name
force_latent_upscaler = shared.opts.data.get('xyz_fallback_sampler')
force_latent_upscaler = shared.opts.data.get('force_latent_sampler')
if force_latent_upscaler != 'None' and force_latent_upscaler != 'PLMS':
img2img_sampler_name = force_latent_upscaler
if img2img_sampler_name == 'PLMS':
@@ -981,7 +981,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
self.image_conditioning = None
def init(self, all_prompts, all_seeds, all_subseeds):
force_latent_upscaler = shared.opts.data.get('xyz_fallback_sampler')
force_latent_upscaler = shared.opts.data.get('force_latent_sampler')
if self.sampler_name in ['PLMS']:
self.sampler_name = force_latent_upscaler if force_latent_upscaler != 'None' else shared.opts.fallback_sampler # PLMS does not support img2img, use fallback instead
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
+2
View File
@@ -21,6 +21,8 @@ def preload_extensions(extensions_dir, parser):
if not os.path.isdir(extensions_dir):
return
for dirname in sorted(os.listdir(extensions_dir)):
# if dirname in opts.get('disabled_extensions', []): # TODO: preload happens before opts are parsed
# continue
if dirname in preloaded:
continue
preloaded.append(dirname)
+15 -12
View File
@@ -282,18 +282,21 @@ class ScriptRunner:
auto_processing_scripts = scripts_auto_postprocessing.create_auto_preprocessing_script_data()
for script_class, path, _basedir, _script_module in auto_processing_scripts + scripts_data:
script = script_class()
script.filename = path
script.is_txt2img = not is_img2img
script.is_img2img = is_img2img
visibility = script.show(script.is_img2img)
if visibility == AlwaysVisible:
self.scripts.append(script)
self.alwayson_scripts.append(script)
script.alwayson = True
elif visibility:
self.scripts.append(script)
self.selectable_scripts.append(script)
try:
script = script_class()
script.filename = path
script.is_txt2img = not is_img2img
script.is_img2img = is_img2img
visibility = script.show(script.is_img2img)
if visibility == AlwaysVisible:
self.scripts.append(script)
self.alwayson_scripts.append(script)
script.alwayson = True
elif visibility:
self.scripts.append(script)
self.selectable_scripts.append(script)
except Exception as e:
log.error(f'Script initialize: {path} {e}')
def setup_ui(self):
self.titles = [wrap_call(script.title, script.filename, "title") or f"{script.filename} [error]" for script in self.selectable_scripts]
+1 -1
View File
@@ -511,7 +511,7 @@ def sdp_attnblock_forward(self, x):
q, k, v = map(lambda t: rearrange(t, 'b c h w -> b (h w) c'), (q, k, v))
dtype = q.dtype
if shared.opts.upcast_attn:
q, k = q.float(), k.float()
q, k, v = q.float(), k.float(), v.float()
q = q.contiguous()
k = k.contiguous()
v = v.contiguous()
+36 -15
View File
@@ -108,7 +108,9 @@ def list_models():
if shared.backend == shared.Backend.ORIGINAL:
model_list = modelloader.load_models(model_path=os.path.join(models_path, 'Stable-diffusion'), model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=[".ckpt", ".safetensors"], download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
else:
model_list = modelloader.load_diffusers(model_path=os.path.join(models_path, 'Diffusers'), command_path=shared.opts.diffusers_dir)
global model_path # pylint: disable=global-statement
model_path = os.path.join(models_path, 'Diffusers')
model_list = modelloader.load_diffusers(model_path=model_path, command_path=shared.opts.diffusers_dir)
for filename in sorted(model_list, key=str.lower):
checkpoint_info = CheckpointInfo(filename)
if checkpoint_info.name is not None:
@@ -125,16 +127,23 @@ def list_models():
elif shared.cmd_opts.ckpt != shared.default_sd_model_file and shared.cmd_opts.ckpt is not None:
shared.log.warning(f"Checkpoint not found: {shared.cmd_opts.ckpt}")
shared.log.info(f'Available models: {shared.opts.ckpt_dir} {len(checkpoints_list)}')
if len(checkpoints_list) == 0:
if not shared.cmd_opts.no_download:
key = input('Download the default model? (y/N) ')
if key.lower().startswith('y'):
model_url = "https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors"
shared.opts.data['sd_model_checkpoint'] = "v1-5-pruned-emaonly.safetensors"
model_list = modelloader.load_models(model_path=model_path, model_url=model_url, command_path=shared.opts.ckpt_dir, ext_filter=[".ckpt", ".safetensors"], download_name="v1-5-pruned-emaonly.safetensors", ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
if shared.backend == shared.Backend.ORIGINAL:
model_url = "https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors"
shared.opts.data['sd_model_checkpoint'] = "v1-5-pruned-emaonly.safetensors"
model_list = modelloader.load_models(model_path=model_path, model_url=model_url, command_path=shared.opts.ckpt_dir, ext_filter=[".ckpt", ".safetensors"], download_name="v1-5-pruned-emaonly.safetensors", ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
else:
hub_url = "runwayml/stable-diffusion-v1-5"
model_list = modelloader.load_diffusers(model_path=model_path, hub_url=hub_url, command_path=shared.opts.diffusers_dir)
for filename in sorted(model_list, key=str.lower):
checkpoint_info = CheckpointInfo(filename)
checkpoint_info.register()
if checkpoint_info.name is not None:
checkpoint_info.register()
def update_model_hashes():
@@ -181,8 +190,8 @@ def model_hash(filename):
return 'NOHASH'
def select_checkpoint():
model_checkpoint = shared.opts.sd_model_checkpoint
def select_checkpoint(model=True):
model_checkpoint = shared.opts.sd_model_checkpoint if model else shared.opts.sd_model_dict
checkpoint_info = checkpoint_aliases.get(model_checkpoint, None)
if checkpoint_info is not None:
shared.log.debug(f'Select checkpoint: {checkpoint_info.title if checkpoint_info is not None else None}')
@@ -291,7 +300,8 @@ def load_model_weights(model: torch.nn.Module, checkpoint_info: CheckpointInfo,
shared.log.debug(f'Model weights loading: {memory_stats()}')
sd_model_hash = checkpoint_info.calculate_shorthash()
timer.record("hash")
shared.opts.data["sd_model_checkpoint"] = checkpoint_info.title
if model_data.sd_dict == 'None':
shared.opts.data["sd_model_checkpoint"] = checkpoint_info.title
if state_dict is None:
state_dict = get_checkpoint_state_dict(checkpoint_info, timer)
model.load_state_dict(state_dict, strict=False)
@@ -389,6 +399,7 @@ sd2_clip_weight = 'cond_stage_model.model.transformer.resblocks.0.attn.in_proj_w
class SdModelData:
def __init__(self):
self.sd_model = None
self.sd_dict = 'None'
self.initial = True
self.lock = threading.Lock()
@@ -397,7 +408,7 @@ class SdModelData:
with self.lock:
try:
if shared.backend == shared.Backend.ORIGINAL:
load_model()
reload_model_weights()
elif shared.backend == shared.Backend.DIFFUSERS:
load_diffuser()
else:
@@ -543,15 +554,21 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None)
shared.log.info(f'Model load finished: {memory_stats()}')
def reload_model_weights(sd_model=None, info=None):
def reload_model_weights(sd_model=None, info=None, reuse_dict=False):
load_dict = shared.opts.sd_model_dict != model_data.sd_dict
global skip_next_load # pylint: disable=global-statement
if skip_next_load:
shared.log.debug('Reload model weights skip')
skip_next_load = False
return
shared.log.debug(f'Reload model weights: {sd_model is not None} {info}')
from modules import lowvram, sd_hijack
checkpoint_info = info or select_checkpoint()
checkpoint_info = info or select_checkpoint(model=not load_dict) # are we selecting model or dictionary
next_checkpoint_info = info or select_checkpoint(model=load_dict) if load_dict else None
if load_dict:
shared.log.debug(f'Model dict: existing={sd_model is not None} target={checkpoint_info.filename} info={info}')
else:
model_data.sd_dict = 'None'
shared.log.debug(f'Reload model weights: existing={sd_model is not None} target={checkpoint_info.filename} info={info}')
if not sd_model:
sd_model = model_data.sd_model
if sd_model is None: # previous model load failed
@@ -564,7 +581,7 @@ def reload_model_weights(sd_model=None, info=None):
lowvram.send_everything_to_cpu()
else:
sd_model.to(devices.cpu)
if shared.opts.model_reuse_dict and sd_model is not None:
if reuse_dict or (shared.opts.model_reuse_dict and sd_model is not None):
shared.log.info('Reusing previous model dictionary')
sd_hijack.model_hijack.undo_hijack(sd_model)
else:
@@ -581,6 +598,10 @@ def reload_model_weights(sd_model=None, info=None):
load_model(checkpoint_info, already_loaded_state_dict=state_dict, timer=timer)
else:
load_diffuser(checkpoint_info, already_loaded_state_dict=state_dict, timer=timer)
if load_dict and next_checkpoint_info is not None:
model_data.sd_dict = shared.opts.sd_model_dict
shared.opts.data["sd_model_checkpoint"] = next_checkpoint_info.title
reload_model_weights(reuse_dict=True) # ok we loaded dict now lets redo and load model on top of it
return model_data.sd_model
try:
load_model_weights(sd_model, checkpoint_info, state_dict, timer)
@@ -606,8 +627,8 @@ def unload_model_weights(sd_model=None, _info=None):
sd_hijack.model_hijack.undo_hijack(model_data.sd_model)
model_data.sd_model = None
sd_model = None
devices.torch_gc(force=True)
shared.log.debug(f'Model weights unloaded: {memory_stats()}')
devices.torch_gc(force=True)
shared.log.debug(f'Model weights unloaded: {memory_stats()}')
return sd_model
+1 -1
View File
@@ -22,7 +22,7 @@ def setup_img2img_steps(p, steps=None):
return steps, t_enc
approximation_indexes = {"Full": 0, "Approx NN": 1, "Approx cheap": 2, "TAESD": 3}
approximation_indexes = {"Full VAE": 0, "Approximate NN": 1, "Approximate simple": 2, "TAESD": 3}
def single_sample_to_image(sample, approximation=None):
+26 -15
View File
@@ -102,6 +102,7 @@ class State:
time_start = None
need_restart = False
server_start = None
oom = False
def skip(self):
log.debug('Requested skip')
@@ -250,6 +251,14 @@ def list_themes():
return themes
def lora_disable():
if opts.lora_disable:
if 'Lora' not in opts.disabled_extensions:
opts.data['disabled_extensions'].append('Lora')
else:
opts.data['disabled_extensions'] = [x for x in opts.disabled_extensions if x != 'Lora']
def refresh_themes():
try:
req = requests.get('https://huggingface.co/datasets/freddyaboulton/gradio-theme-subdomains/resolve/main/subdomains.json', timeout=5)
@@ -282,6 +291,7 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
"sd_checkpoint_cache": OptionInfo(0, "Number of cached model checkpoints", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
"sd_vae_checkpoint_cache": OptionInfo(0, "Number of cached VAE checkpoints", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
"sd_vae": OptionInfo("Automatic", "Select VAE", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list),
"sd_model_dict": OptionInfo('None', "Stable Diffusion checkpoint dict", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_tiles()}, refresh=refresh_checkpoints),
"sd_vae_sliced_encode": OptionInfo(False, "Enable splitting of hires batch processing"),
"stream_load": OptionInfo(False, "When loading models attempt stream loading optimized for slow or network storage"),
"model_reuse_dict": OptionInfo(False, "When loading models attempt to reuse previous model dictionary"),
@@ -325,6 +335,9 @@ options_templates.update(options_section(('system-paths', "System Paths"), {
"ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Path to directory with stable diffusion checkpoints"),
"diffusers_dir": OptionInfo(os.path.join(paths.models_path, 'Diffusers'), "Path to directory with stable diffusion diffusers"),
"vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Path to directory with VAE files"),
"lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Path to directory with Lora network(s)"),
"lyco_dir": OptionInfo(os.path.join(paths.models_path, 'LyCORIS'), "Path to directory with LyCORIS network(s)"),
"styles_dir": OptionInfo(os.path.join(paths.data_path, 'styles.csv'), "Path to user-defined styles file"),
"embeddings_dir": OptionInfo(os.path.join(paths.models_path, 'embeddings'), "Embeddings directory for textual inversion"),
"hypernetwork_dir": OptionInfo(os.path.join(paths.models_path, 'hypernetworks'), "Hypernetwork directory"),
"codeformer_models_path": OptionInfo(os.path.join(paths.models_path, 'Codeformer'), "Path to directory with codeformer model file(s)"),
@@ -336,9 +349,6 @@ options_templates.update(options_section(('system-paths', "System Paths"), {
"swinir_models_path": OptionInfo(os.path.join(paths.models_path, 'SwinIR'), "Path to directory with SwinIR model file(s)"),
"ldsr_models_path": OptionInfo(os.path.join(paths.models_path, 'LDSR'), "Path to directory with LDSR model file(s)"),
"clip_models_path": OptionInfo(os.path.join(paths.models_path, 'CLIP'), "Path to directory with CLIP model file(s)"),
"lora_dir": OptionInfo(os.path.join(paths.models_path, 'Lora'), "Path to directory with Lora network(s)"),
"lyco_dir": OptionInfo(os.path.join(paths.models_path, 'LyCORIS'), "Path to directory with LyCORIS network(s)"),
"styles_dir": OptionInfo(os.path.join(paths.data_path, 'styles.csv'), "Path to user-defined styles file"),
}))
options_templates.update(options_section(('saving-images', "Image Options"), {
@@ -423,7 +433,7 @@ options_templates.update(options_section(('live-preview', "Live previews"), {
"notification_audio_enable": OptionInfo(False, "Play a sound when images are finished generating"),
"notification_audio_path": OptionInfo("html/notification.mp3","Path to notification sound", component_args=hide_dirs),
"show_progress_every_n_steps": OptionInfo(1, "Live preview display period", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}),
"show_progress_type": OptionInfo("TAESD", "Live preview method", gr.Radio, {"choices": ["Full", "Approx NN", "Approx cheap", "TAESD"]}),
"show_progress_type": OptionInfo("TAESD", "Live preview method", gr.Radio, {"choices": ["Full VAE", "Approximate NN", "Approximate simple", "TAESD"]}),
"live_preview_content": OptionInfo("Combined", "Live preview subject", gr.Radio, {"choices": ["Combined", "Prompt", "Negative prompt"]}),
"live_preview_refresh_period": OptionInfo(250, "Progressbar/preview update period, in milliseconds")
}))
@@ -431,7 +441,7 @@ options_templates.update(options_section(('live-preview', "Live previews"), {
options_templates.update(options_section(('sampler-params', "Sampler Settings"), {
"show_samplers": OptionInfo(["Euler a", "UniPC", "DDIM", "DPM++ 2M SDE", "DPM++ 2M SDE Karras", "DPM2 Karras", "DPM++ 2M Karras"], "Show samplers in user interface", gr.CheckboxGroup, lambda: {"choices": [x.name for x in list_samplers() if x.name != "PLMS"]}),
"fallback_sampler": OptionInfo("Euler a", "Secondary sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
"xyz_fallback_sampler": OptionInfo("None", "Force latent upscaler sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
"force_latent_sampler": OptionInfo("None", "Force latent upscaler sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
"eta_ancestral": OptionInfo(1.0, "Noise multiplier for ancestral samplers (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
"eta_ddim": OptionInfo(0.0, "Noise multiplier for DDIM (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
"ddim_discretize": OptionInfo('uniform', "DDIM discretize img2img", gr.Radio, {"choices": ['uniform', 'quad']}),
@@ -488,16 +498,17 @@ options_templates.update(options_section(('upscaling', "Upscaling"), {
"realesrgan_enabled_models": OptionInfo(["R-ESRGAN 4x+", "R-ESRGAN 4x+ Anime6B"], "Real-ESRGAN available models", gr.CheckboxGroup, lambda: {"choices": shared_items.realesrgan_models_names()}),
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers (0 = no tiling)", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
"ESRGAN_tile_overlap": OptionInfo(8, "Tile overlap in pixels for ESRGAN upscalers", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
"SCUNET_tile": OptionInfo(256, "Tile size for SCUNET upscalers. 0 = no tiling.", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
"SCUNET_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for SCUNET upscalers. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}),
"SCUNET_tile": OptionInfo(256, "Tile size for SCUNET upscalers (0 = no tiling)", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
"SCUNET_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for SCUNET upscalers (low values = visible seam)", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}),
"use_old_hires_fix_width_height": OptionInfo(False, "Hires fix uses width & height to set final resolution rather than first pass"),
"dont_fix_second_order_samplers_schedule": OptionInfo(False, "Do not fix prompt schedule for second order samplers"),
"lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all Lora types", gr.Checkbox, { "visible": False }), # TODO: lyco-patch-lora
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox, { "visible": False }),
}))
# options_templates.update(options_section(('lora', "Lora"), {
# }))
options_templates.update(options_section(('lora', "Lora"), {
"lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all Lora types", gr.Checkbox, { "visible": True }),
"lora_disable": OptionInfo(False, "Disable built-in Lora handler", gr.Checkbox, { "visible": True }, onchange=lora_disable),
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox, { "visible": True }),
}))
options_templates.update(options_section(('face-restoration', "Face restoration"), {
"face_restoration_model": OptionInfo("CodeFormer", "Face restoration model", gr.Radio, lambda: {"choices": [x.name() for x in face_restorers]}),
@@ -516,10 +527,10 @@ options_templates.update(options_section(('extra_networks', "Extra Networks"), {
options_templates.update(options_section(('token_merging', 'Token Merging'), {
"token_merging": OptionInfo(False, "Enable redundant token merging via tomesd for speed and memory improvements", gr.Checkbox),
"token_merging_ratio": OptionInfo(0.5, "Token merging Ratio. Higher merging ratio = faster generation, smaller VRAM usage, lower quality.", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
"token_merging_hr_only": OptionInfo(True, "Apply only to high-res fix pass. Disabling can yield a ~20-35% speedup on contemporary resolutions.", gr.Checkbox),
"token_merging_ratio_hr": OptionInfo(0.5, "Merging Ratio (high-res pass) - If 'Apply only to high-res' is enabled, this will always be the ratio used.", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
"token_merging_random": OptionInfo(False, "Use random perturbations - Can improve outputs for certain samplers. For others, it may cause visual artifacting.", gr.Checkbox),
"token_merging_ratio": OptionInfo(0.5, "Token merging Ratio. Higher merging ratio = faster generation, smaller VRAM usage, lower quality", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
"token_merging_hr_only": OptionInfo(True, "Apply only to high-res fix pass. Disabling can yield a ~20-35% speedup on contemporary resolutions", gr.Checkbox),
"token_merging_ratio_hr": OptionInfo(0.5, "Merging Ratio for high-res pass", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
"token_merging_random": OptionInfo(False, "Use random perturbations - Can improve outputs for certain samplers. For others, it may cause visual artifacting", gr.Checkbox),
"token_merging_merge_attention": OptionInfo(True, "Merge attention (Recommend on)", gr.Checkbox),
"token_merging_merge_cross_attention": OptionInfo(False, "Merge cross attention (Recommend off)", gr.Checkbox),
"token_merging_merge_mlp": OptionInfo(False, "Merge mlp (Strongly recommend off)", gr.Checkbox),
@@ -3,6 +3,10 @@ import html
import csv
from collections import namedtuple
import torch
try:
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
except:
pass
from tqdm import tqdm
import safetensors.torch
import numpy as np
@@ -239,7 +243,7 @@ class EmbeddingDatabase:
self.previously_displayed_embeddings = displayed_embeddings
shared.log.info(f"Embeddings loaded: {len(self.word_embeddings)} {[k for k in self.word_embeddings.keys()]}")
if len(self.skipped_embeddings) > 0:
shared.log.info(f"Textual inversion embeddings skipped({len(self.skipped_embeddings)}): {', '.join(self.skipped_embeddings.keys())}")
shared.log.info(f"Embeddings skipped: {len(self.skipped_embeddings)} {[k for k in self.skipped_embeddings.keys()]}")
def find_embedding_at_position(self, tokens, offset):
token = tokens[offset]
@@ -433,7 +437,10 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
shared.log.info("No saved optimizer exists in checkpoint")
if shared.cmd_opts.use_ipex:
scaler = torch.xpu.amp.GradScaler()
scaler = ipex.cpu.autocast._grad_scaler.GradScaler() #scaler.step(optimizer): PI_ERROR_INVALID_ARG_VALUE
shared.sd_model = shared.sd_model.to(dtype=torch.float32)
shared.sd_model.train()
shared.sd_model, optimizer = ipex.optimize(shared.sd_model, optimizer=optimizer, dtype=devices.dtype)
else:
scaler = torch.cuda.amp.GradScaler()
+9 -11
View File
@@ -545,9 +545,7 @@ def create_ui():
def add_copy_image_controls(tab_name, elem):
with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"):
gr.HTML("Copy image to: ", elem_id=f"img2img_label_copy_to_{tab_name}")
for title, name in zip(['img2img', 'sketch', 'inpaint', 'inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
for title, name in zip(['➠ image', '➠ sketch', '➠ inpaint', '➠ inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
if name == tab_name:
gr.Button(title, interactive=False)
copy_image_destinations[name] = elem
@@ -558,7 +556,7 @@ def create_ui():
with gr.Tabs(elem_id="mode_img2img"):
img2img_selected_tab = gr.State(0) # pylint: disable=abstract-class-instantiated
with gr.TabItem('img2img', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img:
with gr.TabItem('Image', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img:
init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool="editor", image_mode="RGBA").style(height=480)
add_copy_image_controls('img2img', init_img)
@@ -596,9 +594,9 @@ def create_ui():
"<br>Add inpaint batch mask directory to enable inpaint batch processing."
f"{hidden}</p>"
)
img2img_batch_input_dir = gr.Textbox(label="Input directory", **modules.shared.hide_dirs, elem_id="img2img_batch_input_dir")
img2img_batch_output_dir = gr.Textbox(label="Output directory", **modules.shared.hide_dirs, elem_id="img2img_batch_output_dir")
img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory (required for inpaint batch processing only)", **modules.shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir")
img2img_batch_input_dir = gr.Textbox(label="Inpaint batch input directory", **modules.shared.hide_dirs, elem_id="img2img_batch_input_dir")
img2img_batch_output_dir = gr.Textbox(label="Inpaint batch output directory", **modules.shared.hide_dirs, elem_id="img2img_batch_output_dir")
img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory", **modules.shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir")
img2img_tabs = [tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch]
img2img_image_inputs = [init_img, sketch, init_img_with_mask, inpaint_color_sketch] # pylint: disable=unused-variable
@@ -626,7 +624,7 @@ def create_ui():
)
with FormRow():
resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", choices=["Just resize", "Crop and resize", "Resize and fill", "Just resize (latent upscale)"], type="index", value="Just resize")
resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", choices=["Resize fixed", "Crop and resize", "Resize and fill", "Resize using Latent upscale"], type="index", value="Resize and fill")
for category in ordered_ui_categories():
if category == "sampler":
@@ -1462,7 +1460,7 @@ def create_ui():
for _interface, label, _ifid in interfaces:
modules.shared.tab_names.append(label)
with gr.Blocks(theme=modules.shared.gradio_theme, analytics_enabled=False, title="SD.Next") as demo:
with gr.Blocks(theme=modules.shared.gradio_theme, analytics_enabled=False, title="SD.Next", allowed_paths=[cmd_opts.data_dir]) as demo:
with gr.Row(elem_id="quicksettings", variant="compact"):
for i, k, item in sorted(quicksettings_list, key=lambda x: quicksettings_names.get(x[1], x[0])):
component = create_setting_component(k, is_quicksettings=True)
@@ -1679,7 +1677,7 @@ def html_head():
head += f'<script type="module" src="{webpath(script.path)}"></script>\n'
added.append(script.path)
added = [a.replace(script_path, '').replace('\\', '/') for a in added]
modules.shared.log.debug(f'Adding JS scripts: {added}')
# modules.shared.log.debug(f'Adding JS scripts: {added}')
return head
@@ -1712,7 +1710,7 @@ def html_css():
if os.path.exists(os.path.join(data_path, "user.css")):
head += stylesheet(os.path.join(data_path, "user.css"))
added = [a.replace(script_path, '').replace('\\', '/') for a in added]
modules.shared.log.debug(f'Adding CSS stylesheets: {added}')
# modules.shared.log.debug(f'Adding CSS stylesheets: {added}')
return head
+33 -23
View File
@@ -17,12 +17,13 @@ def update_generation_info(generation_info, html_info, img_index):
try:
generation_info = json.loads(generation_info)
if img_index < 0 or img_index >= len(generation_info["infotexts"]):
return html_info, gr.update()
html_text = infotext_to_html(generation_info["infotexts"][img_index])
return html_text, gr.update()
return html_info, generation_info
infotext = generation_info["infotexts"][img_index]
html_text = infotext_to_html(infotext)
return html_text, infotext
except Exception:
pass
return html_info, gr.update()
return html_info, generation_info
def plaintext_to_html(text):
@@ -39,7 +40,7 @@ def infotext_to_html(text):
return res
def delete_files(js_data, images, _do_make_zip, index):
def delete_files(js_data, images, _html_info, _do_make_zip, index):
try:
data = json.loads(js_data)
except Exception:
@@ -65,22 +66,28 @@ def delete_files(js_data, images, _do_make_zip, index):
return images, plaintext_to_html(f"Deleted: {filenames[0] if len(filenames) > 0 else 'none'}")
def save_files(js_data, images, do_make_zip, index):
def save_files(js_data, images, html_info, do_make_zip, index):
os.makedirs(shared.opts.outdir_save, exist_ok=True)
class MyObject: #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it
class PObject: #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it
def __init__(self, d=None):
if d is not None:
for key, value in d.items():
setattr(self, key, value)
self.seed = getattr(self, 'seed', None) or getattr(self, 'Seed', None)
self.prompt = getattr(self, 'prompt', None) or getattr(self, 'Prompt', None)
self.all_seeds = getattr(self, 'all_seeds', [self.seed])
self.all_prompts = getattr(self, 'all_prompts', [self.prompt])
self.infotext = html_info
self.infotexts = getattr(self, 'infotexts', [html_info])
self.index_of_first_image = getattr(self, 'index_of_first_image', 0)
try:
data = json.loads(js_data)
except Exception:
data = { 'index_of_first_image': 0 }
p = MyObject(data)
data = {}
p = PObject(data)
start_index = 0
if index > -1 and shared.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 # pylint: disable=no-member
if index > -1 and shared.opts.save_selected_only and (index >= p.index_of_first_image): # ensures we are looking at a specific non-grid picture, and we have save_selected_only # pylint: disable=no-member
images = [images[index]]
start_index = index
filenames = []
@@ -88,10 +95,12 @@ def save_files(js_data, images, do_make_zip, index):
for image_index, filedata in enumerate(images, start_index):
is_grid = image_index < p.index_of_first_image # pylint: disable=no-member
i = 0 if is_grid else (image_index - p.index_of_first_image) # pylint: disable=no-member
if len(p.all_seeds) <= i: # pylint: disable=no-member
p.all_seeds.append(p.seed) # pylint: disable=no-member
if len(p.all_prompts) <= i: # pylint: disable=no-member
p.all_prompts.append(p.prompt) # pylint: disable=no-member
while len(p.all_seeds) <= i:
p.all_seeds.append(p.seed)
while len(p.all_prompts) <= i:
p.all_prompts.append(p.prompt)
while len(p.infotexts) <= i:
p.infotexts.append(p.infotext)
if 'name' in filedata and ('tmp' not in filedata['name']) and os.path.isfile(filedata['name']):
fullfn = filedata['name']
filenames.append(os.path.basename(fullfn))
@@ -106,7 +115,7 @@ def save_files(js_data, images, do_make_zip, index):
shared.log.info(f"Copying image: {fullfn} -> {destination}")
else:
image = image_from_url_text(filedata)
fullfn, txt_fullfn = modules.images.save_image(image, shared.opts.outdir_save, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=shared.opts.samples_format, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=shared.opts.use_save_to_dirs_for_ui) # pylint: disable=no-member
fullfn, txt_fullfn = modules.images.save_image(image, shared.opts.outdir_save, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], info=p.infotexts[i], extension=shared.opts.samples_format, grid=is_grid, p=p, save_to_dirs=shared.opts.use_save_to_dirs_for_ui)
if fullfn is None:
continue
filename = os.path.relpath(fullfn, shared.opts.outdir_save)
@@ -164,23 +173,24 @@ def create_output_panel(tabname, outdir):
download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False, elem_id=f'download_files_{tabname}')
with gr.Group():
html_info = gr.HTML(elem_id=f'html_info_{tabname}', elem_classes="infotext")
html_info_raw = gr.Text(elem_id=f'html_info_raw_{tabname}', visible=False)
html_log = gr.HTML(elem_id=f'html_log_{tabname}')
generation_info = gr.Textbox(visible=False, elem_id=f'generation_info_{tabname}')
generation_info_button = gr.Button(visible=False, elem_id=f"{tabname}_generation_info_button")
generation_info_button.click(fn=update_generation_info, _js="(x, y, z) => [x, y, selected_gallery_index()]", show_progress=False,
inputs=[generation_info, html_info, html_info],
outputs=[html_info, html_info],
outputs=[html_info, html_info_raw],
)
save.click(fn=call_queue.wrap_gradio_call(save_files), _js="(x, y, z, w) => [x, y, false, selected_gallery_index()]", show_progress=False,
inputs=[generation_info, result_gallery, html_info, html_info],
save.click(fn=call_queue.wrap_gradio_call(save_files), _js="(x, y, z, q1, q2) => [x, y, z, false, selected_gallery_index()]", show_progress=False,
inputs=[generation_info, result_gallery, html_info, html_info, html_info],
outputs=[download_files, html_log],
)
save_zip.click(fn=call_queue.wrap_gradio_call(save_files), _js="(x, y, z, w) => [x, y, true, selected_gallery_index()]",
inputs=[generation_info, result_gallery, html_info, html_info],
save_zip.click(fn=call_queue.wrap_gradio_call(save_files), _js="(x, y, z, q1, q2) => [x, y, z, true, selected_gallery_index()]",
inputs=[generation_info, result_gallery, html_info, html_info, html_info],
outputs=[download_files, html_log],
)
delete.click(fn=call_queue.wrap_gradio_call(delete_files), _js="(x, y, z, w) => [x, y, true, selected_gallery_index()]",
inputs=[generation_info, result_gallery, html_info, html_info],
delete.click(fn=call_queue.wrap_gradio_call(delete_files), _js="(x, y, z, q1, q2) => [x, y, z, true, selected_gallery_index()]",
inputs=[generation_info, result_gallery, html_info, html_info, html_info],
outputs=[result_gallery, html_log],
)
+3 -3
View File
@@ -112,7 +112,7 @@ def check_updates(_id_task, disable_list, search_text, sort_column):
except FileNotFoundError as e:
if 'FETCH_HEAD' not in str(e):
raise
except Exception:
except Exception as e:
errors.display(e, f'extensions check update: {ext.name}')
shared.state.nextjob()
return refresh_extensions_list_from_data(search_text, sort_column), "Extension update complete | Restart required"
@@ -261,7 +261,7 @@ def search_extensions(search_text, sort_column):
def refresh_extensions_list_from_data(search_text, sort_column):
shared.log.debug(f'Extensions manager: refresh list search="{search_text}" sort="{sort_column}"')
# shared.log.debug(f'Extensions manager: refresh list search="{search_text}" sort="{sort_column}"')
code = """
<table id="extensions">
<colgroup>
@@ -432,7 +432,7 @@ def create_ui():
outputs=[extensions_table, info],
)
with gr.TabItem("Manual install", id="install_from_url"):
install_url = gr.Text(label="URL for extension's git repository")
install_url = gr.Text(label="Extension GIT repository URL")
install_branch = gr.Text(label="Specific branch name", placeholder="Leave empty for default main branch")
install_dirname = gr.Text(label="Local directory name", placeholder="Leave empty for auto")
install_button = gr.Button(value="Install", variant="primary")
+39 -21
View File
@@ -4,7 +4,7 @@ import os.path
import urllib.parse
from pathlib import Path
import gradio as gr
from modules import shared
from modules import shared, scripts
from modules.generation_parameters_copypaste import image_from_url_text
from modules.ui_components import ToolButton
@@ -54,10 +54,27 @@ class ExtraNetworksPage:
self.card_short = shared.html("extra-networks-card-short.html")
self.allow_negative_prompt = False
self.metadata = {}
self.items = []
def refresh(self):
pass
def create_xyz_grid(self):
xyz_grid = [x for x in scripts.scripts_data if x.script_class.__module__ == "xyz_grid.py"][0].module
def add_prompt(p, opt, x):
for item in [x for x in self.items if x["name"] == opt]:
try:
p.prompt = f'{p.prompt} {eval(item["prompt"])}' # pylint: disable=eval-used
except Exception as e:
shared.log.error(f'Cannot evaluate extra network prompt: {item["prompt"]} {e}')
if not any(self.title in x.label for x in xyz_grid.axis_options):
if self.title == 'Checkpoints':
return
opt = xyz_grid.AxisOption(f"[Network] {self.title}", str, add_prompt, choices=lambda: [x["name"] for x in self.items])
xyz_grid.axis_options.append(opt)
def link_preview(self, filename):
quoted_filename = urllib.parse.quote(filename.replace('\\', '/'))
mtime = os.path.getmtime(filename)
@@ -93,12 +110,13 @@ class ExtraNetworksPage:
if subdirs:
subdirs = {"": 1, **subdirs}
subdirs_html = "".join([f"""
<button class='lg secondary gradio-button custom-button{" search-all" if subdir=="" else ""}' onclick='extraNetworksSearchButton("{tabname}_extra_tabs", event)'>
{html.escape(subdir if subdir!="" else "all")}
</button>
""" for subdir in subdirs])
<button class='lg secondary gradio-button custom-button{" search-all" if subdir=="" else ""}' onclick='extraNetworksSearchButton("{tabname}_extra_tabs", event)'>
{html.escape(subdir if subdir!="" else "all")}
</button>""" for subdir in subdirs])
try:
for item in self.list_items():
self.items = list(self.list_items())
self.create_xyz_grid()
for item in self.items:
metadata = item.get("metadata")
if metadata:
self.metadata[item["name"]] = metadata
@@ -213,20 +231,20 @@ def create_ui(container, button, tabname):
ui.stored_extra_pages = pages_in_preferred_order(extra_pages.copy())
ui.tabname = tabname
with gr.Tabs(elem_id=tabname+"_extra_tabs"):
ui.search = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", visible=True)
ui.description_input = gr.TextArea('', show_label=False, elem_id=tabname+"_description_input", placeholder="Save/Replace Extra Network Description...", lines=2)
button_refresh = ToolButton(refresh_symbol, elem_id=tabname+"_extra_refresh")
button_close = ToolButton(close_symbol, elem_id=tabname+"_extra_close")
ui.button_save_preview = gr.Button('Save preview', elem_id=tabname+"_save_preview", visible=False)
ui.preview_target_filename = gr.Textbox('Preview save filename', elem_id=tabname+"_preview_filename", visible=False)
ui.button_save_description = gr.Button('Save description', elem_id=tabname+"_save_description", visible=False)
ui.button_read_description = gr.Button('Read description', elem_id=tabname+"_read_description", visible=False)
ui.description_target_filename = gr.Textbox('Description save filename', elem_id=tabname+"_description_filename", visible=False)
for page in ui.stored_extra_pages:
with gr.Tab(page.title, id=page.title.lower().replace(" ", "_")):
page_elem = gr.HTML(page.create_html(ui.tabname))
page_elem.change(fn=lambda: None, _js=f'() => refreshExtraNetworks("{tabname}")', inputs=[], outputs=[])
ui.pages.append(page_elem)
ui.search = gr.Textbox('', show_label=False, elem_id=tabname+"_extra_search", placeholder="Search...", visible=False)
ui.description_input = gr.TextArea('', show_label=False, elem_id=tabname+"_description_input", placeholder="Save/Replace Extra Network Description...", lines=2)
button_refresh = ToolButton(refresh_symbol, elem_id=tabname+"_extra_refresh")
button_close = ToolButton(close_symbol, elem_id=tabname+"_extra_close")
ui.button_save_preview = gr.Button('Save preview', elem_id=tabname+"_save_preview", visible=False)
ui.preview_target_filename = gr.Textbox('Preview save filename', elem_id=tabname+"_preview_filename", visible=False)
ui.button_save_description = gr.Button('Save description', elem_id=tabname+"_save_description", visible=False)
ui.button_read_description = gr.Button('Read description', elem_id=tabname+"_read_description", visible=False)
ui.description_target_filename = gr.Textbox('Description save filename', elem_id=tabname+"_description_filename", visible=False)
def toggle_visibility(is_visible):
is_visible = not is_visible
@@ -271,6 +289,7 @@ def setup_ui(ui, gallery):
break
assert is_allowed, f'writing to {filename} is not allowed'
image.save(filename)
shared.log.info(f'Extra network save preview: {filename}')
return [page.create_html(ui.tabname) for page in ui.stored_extra_pages]
ui.button_save_preview.click(
@@ -286,12 +305,11 @@ def setup_ui(ui, gallery):
filename = filename[0:lastDotIndex]+".description.txt"
if descrip != "":
try:
f = open(filename,'w', encoding='utf-8')
except OSError:
print ("Could not open file to write: " + filename)
with f:
f.write(descrip)
f.close()
with open(filename,'w', encoding='utf-8') as f:
f.write(descrip)
shared.log.info(f'Extra network save description: {filename}')
except Exception as e:
shared.log.error(f'Extra network save preview: {filename} {e}')
return [page.create_html(ui.tabname) for page in ui.stored_extra_pages]
ui.button_save_description.click(
+3 -2
View File
@@ -1,3 +1,4 @@
import json
import gradio as gr
from modules import scripts_postprocessing, scripts, shared, gfpgan_model, codeformer_model, ui_common, postprocessing, call_queue # pylint: disable=unused-import
import modules.generation_parameters_copypaste as parameters_copypaste
@@ -13,8 +14,8 @@ def wrap_pnginfo(image):
def submit_click(tab_index, extras_image, image_batch, extras_batch_input_dir, extras_batch_output_dir, show_extras_results, *script_inputs):
result_images, geninfo, _js_info = postprocessing.run_postprocessing(tab_index, extras_image, image_batch, extras_batch_input_dir, extras_batch_output_dir, show_extras_results, *script_inputs)
return result_images, geninfo, '{}', ''
result_images, geninfo, js_info = postprocessing.run_postprocessing(tab_index, extras_image, image_batch, extras_batch_input_dir, extras_batch_output_dir, show_extras_results, *script_inputs)
return result_images, geninfo, json.dumps(js_info), ''
def create_ui():
+12 -17
View File
@@ -4,7 +4,8 @@ from abc import abstractmethod
import PIL
from PIL import Image
from modules import modelloader, shared
import modules.shared
from modules import modelloader
LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS)
NEAREST = (Image.Resampling.NEAREST if hasattr(Image, 'Resampling') else Image.NEAREST)
@@ -24,25 +25,26 @@ class Upscaler:
def __init__(self, create_dirs=False):
self.mod_pad_h = None
self.tile_size = shared.opts.ESRGAN_tile
self.tile_pad = shared.opts.ESRGAN_tile_overlap
self.device = shared.device
self.tile_size = modules.shared.opts.ESRGAN_tile
self.tile_pad = modules.shared.opts.ESRGAN_tile_overlap
self.device = modules.shared.device
self.img = None
self.output = None
self.scale = 1
self.half = not shared.opts.no_half
self.half = not modules.shared.cmd_opts.no_half
self.pre_pad = 0
self.mod_scale = None
self.model_download_path = None
if self.model_path is None and self.name:
self.model_path = os.path.join(shared.models_path, self.name)
self.model_path = os.path.join(modules.shared.models_path, self.name)
if self.model_path and create_dirs:
os.makedirs(self.model_path, exist_ok=True)
try:
import cv2 # pylint: disable=unused-import
import cv2 # pylint: disable=unused-import
self.can_tile = True
except:
except Exception:
pass
@abstractmethod
@@ -50,25 +52,18 @@ class Upscaler:
return img
def upscale(self, img: PIL.Image, scale, selected_model: str = None):
shared.log.debug(f'upscale: {img}|{scale}|{selected_model}')
self.scale = scale
dest_w = int(img.width * scale)
dest_h = int(img.height * scale)
for _i in range(3):
for _ in range(3):
shape = (img.width, img.height)
img = self.do_upscale(img, selected_model)
if shape == (img.width, img.height):
break
if img.width >= dest_w and img.height >= dest_h:
break
if img.width != dest_w or img.height != dest_h:
img = img.resize((int(dest_w), int(dest_h)), resample=LANCZOS)
return img
@abstractmethod
@@ -79,7 +74,7 @@ class Upscaler:
return modelloader.load_models(model_path=self.model_path, model_url=self.model_url, command_path=self.user_path)
def update_status(self, prompt):
print(f"\nextras: {prompt}")
print(f"\nextras: {prompt}", file=modules.shared.progress_print_out)
class UpscalerData:
+1 -1
View File
@@ -12,7 +12,7 @@ class ScriptPostprocessingCodeFormer(scripts_postprocessing.ScriptPostprocessing
def ui(self):
with FormRow():
codeformer_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="CodeFormer visibility", value=0.0, elem_id="extras_codeformer_visibility")
codeformer_weight = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="CodeFormer weight (0 = max), 1 = min)", value=0.2, elem_id="extras_codeformer_weight")
codeformer_weight = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label="CodeFormer weight (0 = max, 1 = min)", value=0.2, elem_id="extras_codeformer_weight")
return {
"codeformer_visibility": codeformer_visibility,
+1 -1
View File
@@ -51,7 +51,7 @@ class Script(scripts.Script):
prompt_type = gr.Radio(["positive", "negative"], label="Select prompt", elem_id=self.elem_id("prompt_type"), value="positive")
variations_delimiter = gr.Radio(["comma", "space"], label="Select joining char", elem_id=self.elem_id("variations_delimiter"), value="comma")
with gr.Column():
margin_size = gr.Slider(label="Grid margins (px)", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
margin_size = gr.Slider(label="Grid margins", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
return [put_at_start, different_seeds, prompt_type, variations_delimiter, margin_size]
+28 -26
View File
@@ -121,7 +121,7 @@ def apply_fallback(p, x, xs):
if sampler_name is None:
shared.log.warning(f"XYZ grid: unknown sampler: {x}")
else:
shared.opts.data["xyz_fallback_sampler"] = sampler_name
shared.opts.data["force_latent_sampler"] = sampler_name
def apply_uni_pc_order(p, x, xs):
@@ -207,35 +207,35 @@ class AxisOptionTxt2Img(AxisOption):
axis_options = [
AxisOption("Nothing", str, do_nothing, fmt=format_nothing),
AxisOption("Seed", int, apply_field("seed")),
AxisOption("Var. seed", int, apply_field("subseed")),
AxisOption("Var. strength", float, apply_field("subseed_strength")),
AxisOption("Steps", int, apply_field("steps")),
AxisOptionTxt2Img("Hires steps", int, apply_field("hr_second_pass_steps")),
AxisOption("CFG Scale", float, apply_field("cfg_scale")),
AxisOptionImg2Img("Image CFG Scale", float, apply_field("image_cfg_scale")),
AxisOption("Checkpoint name", str, apply_checkpoint, fmt=format_value, confirm=confirm_checkpoints, cost=1.0, choices=lambda: list(sd_models.checkpoints_list)),
AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: ['None'] + list(sd_vae.vae_dict)),
AxisOption("Dict name", str, apply_checkpoint, fmt=format_value, confirm=confirm_checkpoints, cost=1.0, choices=lambda: ['None'] + list(sd_models.checkpoints_list)),
AxisOption("Prompt S/R", str, apply_prompt, fmt=format_value),
AxisOption("Prompt order", str_permutations, apply_order, fmt=format_value_join_list),
AxisOption("Styles", str, apply_styles, choices=lambda: list(shared.prompt_styles.styles)),
AxisOptionTxt2Img("Sampler", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
AxisOptionImg2Img("Sampler", str, apply_sampler, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers_for_img2img]),
AxisOption("Checkpoint name", str, apply_checkpoint, fmt=format_value, confirm=confirm_checkpoints, cost=1.0, choices=lambda: list(sd_models.checkpoints_list)),
AxisOption("Sigma Churn", float, apply_field("s_churn")),
AxisOption("Sigma min", float, apply_field("s_tmin")),
AxisOption("Sigma max", float, apply_field("s_tmax")),
AxisOption("Sigma noise", float, apply_field("s_noise")),
AxisOption("Eta", float, apply_field("eta")),
AxisOption("Seed", int, apply_field("seed")),
AxisOption("Steps", int, apply_field("steps")),
AxisOption("CFG Scale", float, apply_field("cfg_scale")),
AxisOption("Var. seed", int, apply_field("subseed")),
AxisOption("Var. strength", float, apply_field("subseed_strength")),
AxisOption("Clip skip", int, apply_clip_skip),
AxisOption("Denoising", float, apply_field("denoising_strength")),
AxisOptionTxt2Img("Hires steps", int, apply_field("hr_second_pass_steps")),
AxisOptionImg2Img("Image CFG Scale", float, apply_field("image_cfg_scale")),
AxisOption("Prompt order", str_permutations, apply_order, fmt=format_value_join_list),
AxisOption("Sampler Sigma Churn", float, apply_field("s_churn")),
AxisOption("Sampler Sigma min", float, apply_field("s_tmin")),
AxisOption("Sampler Sigma max", float, apply_field("s_tmax")),
AxisOption("Sampler Sigma noise", float, apply_field("s_noise")),
AxisOption("Sampler Eta", float, apply_field("eta")),
AxisOptionTxt2Img("Hires upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]),
AxisOptionTxt2Img("Fallback latent upscaler sampler", str, apply_fallback, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
AxisOptionImg2Img("Cond. Image Mask Weight", float, apply_field("inpainting_mask_weight")),
AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: ['None'] + list(sd_vae.vae_dict)),
AxisOption("Styles", str, apply_styles, choices=lambda: list(shared.prompt_styles.styles)),
AxisOptionImg2Img("Image Mask Weight", float, apply_field("inpainting_mask_weight")),
AxisOption("UniPC Order", int, apply_uni_pc_order, cost=0.5),
AxisOption("Face restore", str, apply_face_restore, fmt=format_value),
AxisOption("ToMe ratio",float,apply_token_merging_ratio),
AxisOption("ToMe ratio for Hires fix",float,apply_token_merging_ratio_hr),
AxisOption("ToMe random pertubations",str,apply_token_merging_random, choices = lambda: ["Yes","No"])
AxisOption("ToMe ratio",float, apply_token_merging_ratio),
AxisOption("ToMe ratio for Hires fix",float, apply_token_merging_ratio_hr),
AxisOption("ToMe random pertubations",str, apply_token_merging_random, choices = lambda: ["Yes","No"])
]
@@ -352,8 +352,9 @@ class SharedSettingsStackHelper(object):
self.token_merging_ratio = shared.opts.token_merging_ratio
self.token_merging_random = shared.opts.token_merging_random
self.sd_model_checkpoint = shared.opts.sd_model_checkpoint
self.sd_model_dict = shared.opts.sd_model_dict
self.sd_vae_checkpoint = shared.opts.sd_vae
self.xyz_fallback_sampler = shared.opts.xyz_fallback_sampler
self.force_latent_sampler = shared.opts.force_latent_sampler
def __exit__(self, exc_type, exc_value, tb):
#Restore overriden settings after plot generation.
@@ -362,8 +363,9 @@ class SharedSettingsStackHelper(object):
shared.opts.data["token_merging_ratio_hr"] = self.token_merging_ratio_hr
shared.opts.data["token_merging_ratio"] = self.token_merging_ratio
shared.opts.data["token_merging_random"] = self.token_merging_random
shared.opts.data["xyz_fallback_sampler"] = self.xyz_fallback_sampler
if self.sd_model_checkpoint != shared.opts.sd_model_checkpoint:
shared.opts.data["force_latent_sampler"] = self.force_latent_sampler
if (self.sd_model_checkpoint != shared.opts.sd_model_checkpoint) or (self.sd_model_dict != shared.opts.sd_model_dict):
shared.opts.data["sd_model_dict"] = self.sd_model_dict
shared.opts.data["sd_model_checkpoint"] = self.sd_model_checkpoint
sd_models.reload_model_weights()
if self.sd_vae_checkpoint != shared.opts.sd_vae:
@@ -409,7 +411,7 @@ class Script(scripts.Script):
include_lone_images = gr.Checkbox(label='Include Sub Images', value=False, elem_id=self.elem_id("include_lone_images"))
include_sub_grids = gr.Checkbox(label='Include Sub Grids', value=False, elem_id=self.elem_id("include_sub_grids"))
with gr.Row(variant="compact", elem_id="axis_options"):
margin_size = gr.Slider(label="Grid margins (px)", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
margin_size = gr.Slider(label="Grid margins", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
with gr.Row(variant="compact", elem_id="swap_axes"):
swap_xy_axes_button = gr.Button(value="Swap X/Y axes", elem_id="xy_grid_swap_axes_button")
swap_yz_axes_button = gr.Button(value="Swap Y/Z axes", elem_id="yz_grid_swap_axes_button")
+28 -16
View File
@@ -6,7 +6,7 @@ import asyncio
import logging
import warnings
from threading import Thread
from modules import timer, errors
from modules import timer, errors, paths # pylint: disable=unused-import
startup_timer = timer.Timer()
local_url = None
@@ -85,7 +85,7 @@ def check_rollback_vae():
def initialize():
log.debug('Entering Initialize')
log.debug('Entering initialize')
check_rollback_vae()
modules.sd_vae.refresh_vae_list()
@@ -104,6 +104,7 @@ def initialize():
gfpgan.setup_model(opts.gfpgan_models_path)
startup_timer.record("gfpgan")
log.debug('Loading scripts')
modules.scripts.load_scripts()
startup_timer.record("scripts")
@@ -157,6 +158,7 @@ def load_model():
else:
shared.opts.data["sd_model_checkpoint"] = shared.sd_model.sd_checkpoint_info.title
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()), call=False)
shared.opts.onchange("sd_model_dict", wrap_queued_call(lambda: modules.sd_models.reload_model_weights()), call=False)
shared.state.end()
startup_timer.record("checkpoint")
@@ -222,7 +224,22 @@ def start_ui():
gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()]
import installer
global local_url
global local_url # pylint: disable=global-statement
gradio_kwargs = {
"version": f'0.0.{installer.git_commit}',
"title": "SD.Next",
"description": "SD.Next",
}
if cmd_opts.docs:
gradio_kwargs.update({
"docs_url": "/docs",
"redocs_url": "/redocs",
"swagger_ui_parameters": {
"displayOperationId": True,
"showCommonExtensions": True,
"deepLinking": False,
}
})
app, local_url, share_url = shared.demo.launch(
share=cmd_opts.share,
server_name=server_name,
@@ -237,21 +254,11 @@ def start_ui():
max_threads=64,
show_api=True,
favicon_path='html/logo.ico',
app_kwargs={
"version": f'0.0.{installer.git_commit}',
"title": "SD.Next",
"description": "SD.Next",
"docs_url": "/docs",
"redocs_url": "/redocs",
"swagger_ui_parameters": {
"displayOperationId": True,
"showCommonExtensions": True,
"deepLinking": False,
},
}
app_kwargs=gradio_kwargs,
)
shared.log.info(f'Local URL: {local_url}')
shared.log.info(f'API Docs: {local_url[:-1]}/docs') # {local_url[:-1]}?view=api
if cmd_opts.docs:
shared.log.info(f'API Docs: {local_url[:-1]}/docs') # {local_url[:-1]}?view=api
if share_url is not None:
shared.log.info(f'Share URL: {share_url}')
shared.log.debug(f'Gradio registered functions: {len(shared.demo.fns)}')
@@ -282,6 +289,11 @@ def webui():
start_ui()
load_model()
log.info(f"Startup time: {startup_timer.summary()}")
# override all loggers to use the same handlers as the main logger
for logger in [logging.getLogger(name) for name in logging.root.manager.loggerDict]: # pylint: disable=no-member
logger.handlers = log.handlers
if cmd_opts.autolaunch and local_url is not None:
cmd_opts.autolaunch = False
shared.log.info('Launching browser')
+1 -1
Submodule wiki updated: d420606fc4...801130e4c4