new training and models interface

This commit is contained in:
Vladimir Mandic
2023-06-22 07:46:48 -04:00
parent c02ccc4f00
commit 9740b9d217
25 changed files with 844 additions and 549 deletions
+5 -4
View File
@@ -1,14 +1,15 @@
# Change Log for SD.Next
## Update for 06/19/2023
## Update for 06/20/2023
This one is less relevant for standard users, but pretty major if you're running an actual server
But even if not, it still includes bunch of cumulative fixes since last release...
But even if not, it still includes bunch of cumulative fixes since last release - and going by number of new issues, this is probably the most stable release so far...
(next one is not going to be as stable, but it will be fun :) )
- minor improvements to extra networks ui
- more hints/tooltips integrated into ui
- decidated api server
- still in developent, but highly promising for high throughput server
- new decidated api server
- but highly promising for high throughput server
- improve server logging and monitoring with
- server log file rotation
- ring buffer with api endpoint `/sdapi/v1/log`
+1 -1
View File
@@ -111,7 +111,7 @@ def watermark(params, file):
if __name__ == '__main__':
parser = argparse.ArgumentParser(description = 'image watermarking')
parser.add_argument('command', choices = ['read', 'write'])
parser.add_argument('--wm', type=str, required=False, default='mm', help='watermark string')
parser.add_argument('--wm', type=str, required=False, default='sdnext', help='watermark string')
parser.add_argument('--strip', default=False, action='store_true', help = "strip existing exif data")
parser.add_argument('--verify', default=False, action='store_true', help = "verify watermark during write")
parser.add_argument('--length', type=int, default=16, help="watermark length in bits")
+1 -1
View File
@@ -99,7 +99,7 @@ lora = Map({
"text_encoder_lr": 5e-05,
"train_batch_size": 1,
"train_data_dir": "",
"training_comment": "mood-magic",
"training_comment": "",
"unet_lr": 1e-04,
"use_8bit_adam": False,
"v_parameterization": False,
@@ -142,8 +142,8 @@ def on_ui_settings():
import gradio as gr
from modules import shared
shared.opts.add_option("SCUNET_tile", shared.OptionInfo(256, "Tile size for SCUNET upscalers.", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}, section=('upscaling', "Upscaling")).info("0 = no tiling"))
shared.opts.add_option("SCUNET_tile_overlap", shared.OptionInfo(8, "Tile overlap for SCUNET upscalers.", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}, section=('upscaling', "Upscaling")).info("Low values = visible seam"))
shared.opts.add_option("SCUNET_tile", shared.OptionInfo(256, "Tile size for SCUNET upscalers", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}, section=('upscaling', "Upscaling")).info("0 = no tiling"))
shared.opts.add_option("SCUNET_tile_overlap", shared.OptionInfo(8, "Tile overlap for SCUNET upscalers", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}, section=('upscaling', "Upscaling")).info("Low values = visible seam"))
script_callbacks.on_ui_settings(on_ui_settings)
@@ -173,8 +173,8 @@ def inference(img, model, tile, tile_overlap, window_size, scale):
def on_ui_settings():
import gradio as gr
shared.opts.add_option("SWIN_tile", shared.OptionInfo(192, "Tile size for all SwinIR.", gr.Slider, {"minimum": 16, "maximum": 512, "step": 16}, section=('upscaling', "Upscaling")))
shared.opts.add_option("SWIN_tile_overlap", shared.OptionInfo(8, "Tile overlap, in pixels for SwinIR. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}, section=('upscaling', "Upscaling")))
shared.opts.add_option("SWIN_tile", shared.OptionInfo(192, "Tile size for all SwinIR", gr.Slider, {"minimum": 16, "maximum": 512, "step": 16}, section=('upscaling', "Upscaling")))
shared.opts.add_option("SWIN_tile_overlap", shared.OptionInfo(8, "Tile overlap, in pixels for SwinIR. Low values = visible seam", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}, section=('upscaling', "Upscaling")))
script_callbacks.on_ui_settings(on_ui_settings)
+90 -68
View File
@@ -1,30 +1,45 @@
{ "icons": [
{"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":"Save current prompt as style template"},
{"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"}
{"id":"","label":"⇅","localized":"","hint":"Swap image height and width values"}
],
"prompts": [
{"id":"","label":"Prompt","localized":"","hint":"Type what you want to see in the image"},
{"id":"","label":"Negative prompt","localized":"","hint":"Type what you DON'T want to see in the image"}
],
"common keywords": [
{"id":"","label":"fp16","localized":"","hint":"Number representation in 16-bit floating point format"},
{"id":"","label":"fp32","localized":"","hint":"Number representation in 32-bit floating point format"},
{"id":"","label":"bf16","localized":"","hint":"Number representation in alternative 16-bit floating point format"},
{"id":"","label":"Run","localized":"","hint":""},
{"id":"","label":"all","localized":"","hint":""},
{"id":"","label":"none","localized":"","hint":""},
{"id":"","label":"disabled","localized":"","hint":""}
],
"tabs": [
{"id":"","label":"From Text ","localized":"","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"}
{"id":"","label":"From Text","localized":"","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":"Models","localized":"","hint":"Convert or merge your models"},
{"id":"","label":"Interrogator","localized":"","hint":"Run interrogate to get description of your image"},
{"id":"","label":"System Info","localized":"","hint":"System information and benchmarking"},
{"id":"","label":"Agent Scheduler","localized":"","hint":"Enqueue your generate requests and run them in the background"},
{"id":"","label":"Image Browser","localized":"","hint":"Browse through your generated image database"},
{"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":"Enqueue","localized":"","hint":"Add task to background queueu in Agent Scheduler"},
{"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"},
@@ -32,6 +47,11 @@
{"id":"","label":"Interrogate\nDeepBooru","localized":"","hint":"Run interrogate using DeepBooru model"}
],
"extra networks": [
{"id":"","label":"Checkpoints","localized":"","hint":""},
{"id":"","label":"Lora","localized":"","hint":""},
{"id":"","label":"LyCORIS","localized":"","hint":""},
{"id":"","label":"Textual Inversion","localized":"","hint":""},
{"id":"","label":"Hypernetworks","localized":"","hint":""},
{"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"}
@@ -52,14 +72,20 @@
{"id":"","label":"Install","localized":"","hint":"Install"},
{"id":"","label":"Search","localized":"","hint":"Search"},
{"id":"","label":"Sort by","localized":"","hint":"Sort by"},
{"id":"","label":"Manage Extensions ","localized":"","hint":"Manage extensions"},
{"id":"","label":"Manual install ","localized":"","hint":"Manually install extension"},
{"id":"","label":"Manage extensions","localized":"","hint":"Manage extensions"},
{"id":"","label":"Manual install","localized":"","hint":"Manually install extension"},
{"id":"","label":"Extension GIT repository URL","localized":"","hint":"Specify extension repository URL on GitHub"},
{"id":"","label":"Specific branch name","localized":"","hint":"Specify extension branch namem, leave blank for default"},
{"id":"","label":"Local directory name","localized":"","hint":"Directory where to install extension, leave blank for default"},
{"id":"","label":"Refresh extension list","localized":"","hint":"Refresh list of available extensions"},
{"id":"","label":"Update installed extensions","localized":"","hint":"Update installed extensions to their latest available version"},
{"id":"","label":"Apply changes & restart server","localized":"","hint":"Apply all changes and restart server"}
{"id":"","label":"Apply changes & restart server","localized":"","hint":"Apply all changes and restart server"},
{"id":"","label":"install","localized":"","hint":"install this extension"},
{"id":"","label":"uninstall","localized":"","hint":"uninstall this extension"},
{"id":"","label":"User interface defaults","localized":"","hint":"Review and set current values as default values for the user interface"},
{"id":"","label":"View changes","localized":"","hint":"Review changes between default user interface values and and current values"},
{"id":"","label":"Set new defaults","localized":"","hint":"Set current values as default values for the user interface"},
{"id":"","label":"Restore system defaults","localized":"","hint":"Restore default user interface values"}
],
"txt2img tab": [
{"id":"","label":"Sampling method","localized":"","hint":"Which algorithm to use to produce the image"},
@@ -88,11 +114,11 @@
{"id":"","label":"Override settings","localized":"","hint":"If you read in generation parameters through 'Process Image tab' and individual generation parameters should deviate from your system settings, this box will be populated with those settings to override your system configuration for this workflow"}
],
"process tab": [
{"id":"","label":"Single Image ","localized":"","hint":"Process single image"},
{"id":"","label":"Process Batch ","localized":"","hint":"Process batch of images"},
{"id":"","label":"Process Folder ","localized":"","hint":"Process all images in a folder"},
{"id":"","label":"Scale by ","localized":"","hint":"Use this tab to resize the source image(s) by a chosen factor"},
{"id":"","label":"Scale to ","localized":"","hint":"Use this tab to resize the source image(s) to a chosen target size"},
{"id":"","label":"Single Image","localized":"","hint":"Process single image"},
{"id":"","label":"Process Batch","localized":"","hint":"Process batch of images"},
{"id":"","label":"Process Folder","localized":"","hint":"Process all images in a folder"},
{"id":"","label":"Scale by","localized":"","hint":"Use this tab to resize the source image(s) by a chosen factor"},
{"id":"","label":"Scale to","localized":"","hint":"Use this tab to resize the source image(s) to a chosen target size"},
{"id":"","label":"Input directory","localized":"","hint":"Folder where the images are that you want to process"},
{"id":"","label":"Output directory","localized":"","hint":"Folder where the processed images should be saved to"},
{"id":"","label":"Show result images","localized":"","hint":"Enable to show the processed images in the image pane"},
@@ -114,38 +140,36 @@
{"id":"sett_reload_sd_model","label":"Reload checkpoint","localized":"","hint":"Reload currently selected model checkpoint"}
],
"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":"Stable Diffusion","localized":"","hint":""},
{"id":"","label":"Optimizations","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":"Extra Networks","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":""}
{"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 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"},
@@ -166,31 +190,32 @@
{"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":""},
"models tabs": [
{"id":"","label":"Convert","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":"Validate","localized":"","hint":""},
{"id":"","label":"List model details","localized":"","hint":""},
{"id":"","label":"Calculate hash for all models (may take a long time)","localized":"","hint":""}
],
"train tabs": [
{"id":"","label":"Preprocess","localized":"","hint":""},
{"id":"","label":"Train Embedding","localized":"","hint":""},
{"id":"","label":"Train Hypernetwork","localized":"","hint":""}
{"id":"","label":"Preprocess images","localized":"","hint":""},
{"id":"","label":"Train embedding","localized":"","hint":""},
{"id":"","label":"Train hypernetwork","localized":"","hint":""},
{"id":"","label":"Create embedding","localized":"","hint":""},
{"id":"","label":"Create 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":"No interpolation","localized":"","hint":"Requires one model. No interpolation will be used, allows for format conversion and VAE baking"},
{"id":"","label":"Weighted sum","localized":"","hint":"Requires two models. Weighted sum will be used for interpolation, result is calculated as A * (1 - M) + B * M"},
{"id":"","label":"Add difference","localized":"","hint":"Requires three models. Difference between the last two models will be added to the first, result is calculated as 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":""},
@@ -210,7 +235,7 @@
{"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":"Existing caption text 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":""},
@@ -233,7 +258,6 @@
{"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":""},
@@ -249,7 +273,7 @@
{"id":"","label":"Use PNG alpha channel as loss weight","localized":"","hint":""},
{"id":"","label":"Save images with embedding in PNG chunks","localized":"","hint":""},
{"id":"","label":"Use current settings for previews","localized":"","hint":"Read parameters (prompt, etc...) from txt2img tab when making previews"},
{"id":"","label":"Shuffle tags by ',' when creating prompts","localized":"","hint":""},
{"id":"","label":"Shuffle tags","localized":"","hint":"Shuffle tags by ',' when creating prompts"},
{"id":"","label":"Drop out tags when creating prompts","localized":"","hint":""},
{"id":"","label":"once","localized":"","hint":""},
{"id":"","label":"deterministic","localized":"","hint":""},
@@ -296,7 +320,7 @@
{"id":"","label":"Enable upcast cross attention layer","localized":"","hint":""},
{"id":"","label":"Disable NaN check in produced images/latent spaces","localized":"","hint":""},
{"id":"","label":"Attempt VAE roll back when produced NaN values (experimental)","localized":"","hint":"Requires Torch 2.1 and NaN check enabled"},
{"id":"","label":"Use channels last as torch memory format ","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":""},
@@ -480,7 +504,7 @@
{"id":"","label":"Tile size for ESRGAN upscalers","localized":"","hint":"0 = no tiling"},
{"id":"","label":"Tile overlap in pixels for ESRGAN upscalers","localized":"","hint":"Low values = visible seam"},
{"id":"","label":"Tile size for SCUNET upscalers","localized":"","hint":"0 = no tiling"},
{"id":"","label":"Tile overlap, in pixels for SCUNET upscalers","localized":"","hint":" Low values = visible seam"},
{"id":"","label":"Tile overlap for SCUNET upscalers","localized":"","hint":" Low values = visible seam"},
{"id":"","label":"Hires fix uses width & height to set final resolution","localized":"","hint":"Hires fix uses width & height to set final resolution rather than first pass"},
{"id":"","label":"Do not fix prompt schedule for second order samplers","localized":"","hint":""},
{"id":"","label":"Use LyCoris handler for all Lora types","localized":"","hint":""},
@@ -496,18 +520,16 @@
{"id":"","label":"Add hypernetwork to prompt","localized":"","hint":""},
{"id":"","label":"Token merging ratio","localized":"","hint":"Enable redundant token merging via tomesd for speed and memory improvements, 0=disabled"},
{"id":"","label":"Token merging ratio for img2img","localized":"","hint":"Enable redundant token merging for img2img via tomesd for speed and memory improvements, 0=disabled"},
{"id":"","label":"Token merging ratio for hires pass","localized":"","hint":"Enable redundant token merging for hires pass via tomesd for speed and memory improvements, 0=disabled"},
{"id":"","label":"Stride - X","localized":"","hint":""},
{"id":"","label":"Stride - Y","localized":"","hint":""}
{"id":"","label":"Token merging ratio for hires pass","localized":"","hint":"Enable redundant token merging for hires pass via tomesd for speed and memory improvements, 0=disabled"}
],
"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":"Resize to","localized":"","hint":""},
{"id":"","label":"Resize by","localized":"","hint":""},
{"id":"","label":"Use via API","localized":"","hint":""},
{"id":"","label":"Stable Diffusion checkpoint","localized":"","hint":""},
{"id":"","label":"Styles","localized":"","hint":""},
{"id":"","label":"Put variable parts at start of prompt","localized":"","hint":""},
+4 -13
View File
@@ -81,10 +81,7 @@ def setup_logging():
"traceback.border.syntax_error": "black",
"inspect.value.border": "black",
}))
try:
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)
except Exception:
logging.basicConfig(level=logging.ERROR, format='%(asctime)s | %(name)s | %(levelname)s | %(module)s | %(message)s') # to be able to report unsupported python version
logging.basicConfig(level=logging.ERROR, format='%(asctime)s | %(name)s | %(levelname)s | %(module)s | %(message)s', handlers=[logging.NullHandler()]) # redirect default logger to null
pretty_install(console=console)
traceback_install(console=console, extra_lines=1, width=console.width, word_wrap=False, indent_guides=False, suppress=[])
while log.hasHandlers() and len(log.handlers) > 0:
@@ -109,6 +106,7 @@ def setup_logging():
logging.getLogger("urllib3").setLevel(logging.ERROR)
logging.getLogger("httpx").setLevel(logging.ERROR)
logging.getLogger("ControlNet").handlers = log.handlers
logging.getLogger("lycoris").handlers = log.handlers
def print_profile(profile: cProfile.Profile, msg: str):
@@ -387,7 +385,7 @@ def check_modified_files():
try:
res = git('status --porcelain')
files = [x[2:].strip() for x in res.split('\n')]
files = [x for x in files if len(x) > 0 and not x.startswith('extensions') and not x.startswith('wiki') and not x.endswith('.json')]
files = [x for x in files if len(x) > 0 and (not x.startswith('extensions')) and (not x.startswith('wiki')) and (not x.endswith('.json')) and (not '.log' in x)]
if len(files) > 0:
log.warning(f'Modified files: {files}')
except Exception:
@@ -406,7 +404,7 @@ def install_packages():
# install(openclip_package, 'open-clip-torch')
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git")
install(clip_package, 'clip')
install('onnxruntime==1.14.0', 'onnxruntime', ignore=True)
install('onnxruntime==1.15.1', 'onnxruntime', ignore=True)
if args.profile:
print_profile(pr, 'Packages')
@@ -495,8 +493,6 @@ 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
@@ -610,8 +606,6 @@ 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
@@ -745,7 +739,6 @@ def add_args(parser):
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(parser):
@@ -765,8 +758,6 @@ def extensions_preload(parser):
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)
+19 -1
View File
@@ -28,6 +28,23 @@ async function tooltipHide(e) {
locale.el.classList.remove('tooltip-show');
}
async function validateHints(elements, data) {
let original = elements.map(e => e.textContent.trim()).sort((a, b) => a > b)
original = [...new Set(original)];
console.log('hints-differences', { elements: original.length, hints: data.length });
const current = data.map(e => e.label).sort((a, b) => a > b)
let missing = [];
for (let i = 0; i < original.length; i++) {
if (!current.includes(original[i])) missing.push(original[i]);
}
console.log('missing in locale:', missing)
missing = [];
for (let i = 0; i < current.length; i++) {
if (!original.includes(current[i])) missing.push(current[i]);
}
console.log('in locale but not ui:', missing)
}
async function setHints() {
if (locale.finished) return;
if (locale.data.length === 0) {
@@ -46,7 +63,7 @@ async function setHints() {
let hints = 0;
locale.finished = true;
for (el of elements) {
const found = locale.data.find(l => l.label === el.textContent);
const found = locale.data.find(l => l.label === el.textContent.trim());
if (found?.localized?.length > 0) {
localized++;
el.textContent = found.localized;
@@ -65,6 +82,7 @@ async function setHints() {
}
}
console.log('set-hints', { type: locale.type, elements: elements.length, localized, hints, data: locale.data.length });
// validateHints(elements, locale.data)
}
onAfterUiUpdate(async () => {
+2
View File
@@ -666,3 +666,5 @@ div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; gri
#extras_generate, #extras_interrupt, #extras_skip { display: block !important; position: relative; height: 36px; }
#extras_upscale { margin-top: 10px }
#refresh_tac_refreshTempFiles { display: none; }
#train_tab { flex-flow: row-reverse; }
#models_tab { flex-flow: row-reverse; }
+4 -4
View File
@@ -1,8 +1,8 @@
function start_training_textual_inversion() {
gradioApp().querySelector('#ti_error').innerHTML=''
function start_train_monitoring() {
gradioApp().querySelector('#train_error').innerHTML=''
var id = randomId()
const onProgress = (progress) => gradioApp().getElementById('ti_progress').innerHTML = progress.textinfo;
requestProgress(id, gradioApp().getElementById('ti_gallery'), null, onProgress, false)
const onProgress = (progress) => gradioApp().getElementById('train_progress').innerHTML = progress.textinfo;
requestProgress(id, gradioApp().getElementById('train_gallery'), null, onProgress, false)
var res = Array.from(arguments);
res[0] = id
return res
+152 -6
View File
@@ -57,6 +57,8 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_
shared.state.begin()
shared.state.job = 'model-merge'
save_as_half = save_as_half == 0
def fail(message):
shared.state.textinfo = message
shared.state.end()
@@ -108,13 +110,13 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_
result_is_instruct_pix2pix_model = False
if theta_func2:
shared.state.textinfo = "Loading B"
shared.log.info(f"Loading {secondary_model_info.filename}...")
shared.log.info(f"Model merge loading secondary model: {secondary_model_info.filename}")
theta_1 = sd_models.read_state_dict(secondary_model_info.filename)
else:
theta_1 = None
if theta_func1:
shared.state.textinfo = "Loading C"
shared.log.info(f"Loading {tertiary_model_info.filename}...")
shared.log.info(f"Model merge loading tertiary model: {tertiary_model_info.filename}")
theta_2 = sd_models.read_state_dict(tertiary_model_info.filename)
shared.state.textinfo = 'Merging B and C'
shared.state.sampling_steps = len(theta_1.keys())
@@ -131,9 +133,9 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_
del theta_2
shared.state.nextjob()
shared.state.textinfo = f"Loading {primary_model_info.filename}..."
shared.log.info(f"Loading {primary_model_info.filename}...")
shared.log.info(f"Model merge loading primary model: {primary_model_info.filename}")
theta_0 = sd_models.read_state_dict(primary_model_info.filename)
shared.log.info("Merging...")
shared.log.info("Model merge: running")
shared.state.textinfo = 'Merging A and B'
shared.state.sampling_steps = len(theta_0.keys())
for key in tqdm.tqdm(theta_0.keys()):
@@ -164,7 +166,7 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_
del theta_1
bake_in_vae_filename = sd_vae.vae_dict.get(bake_in_vae, None)
if bake_in_vae_filename is not None:
shared.log.info(f"Baking in VAE from {bake_in_vae_filename}")
shared.log.info(f"Model merge: baking in VAE: {bake_in_vae_filename}")
shared.state.textinfo = 'Baking in VAE'
vae_dict = sd_vae.load_vae_dict(bake_in_vae_filename)
for key in vae_dict.keys():
@@ -234,7 +236,151 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_
if created_model:
created_model.calculate_shorthash()
create_config(output_modelname, config_source, primary_model_info, secondary_model_info, tertiary_model_info)
shared.log.info(f"Checkpoint saved to {output_modelname}.")
shared.log.info(f"Model merge saved: {output_modelname}.")
shared.state.textinfo = "Checkpoint saved"
shared.state.end()
return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], "Checkpoint saved to " + output_modelname]
def run_modelconvert(model, checkpoint_formats, precision, conv_type, custom_name, unet_conv, text_encoder_conv, vae_conv, others_conv, fix_clip):
# position_ids in clip is int64. model_ema.num_updates is int32
dtypes_to_fp16 = {torch.float32, torch.float64, torch.bfloat16}
dtypes_to_bf16 = {torch.float32, torch.float64, torch.float16}
def conv_fp16(t: torch.Tensor):
return t.half() if t.dtype in dtypes_to_fp16 else t
def conv_bf16(t: torch.Tensor):
return t.bfloat16() if t.dtype in dtypes_to_bf16 else t
def conv_full(t):
return t
_g_precision_func = {
"full": conv_full,
"fp32": conv_full,
"fp16": conv_fp16,
"bf16": conv_bf16,
}
def check_weight_type(k: str) -> str:
if k.startswith("model.diffusion_model"):
return "unet"
elif k.startswith("first_stage_model"):
return "vae"
elif k.startswith("cond_stage_model"):
return "clip"
return "other"
def load_model(path):
if path.endswith(".safetensors"):
m = safetensors.torch.load_file(path, device="cpu")
else:
m = torch.load(path, map_location="cpu")
state_dict = m["state_dict"] if "state_dict" in m else m
return state_dict
def fix_model(model, fix_clip=False):
# code from model-toolkit
nai_keys = {
'cond_stage_model.transformer.embeddings.': 'cond_stage_model.transformer.text_model.embeddings.',
'cond_stage_model.transformer.encoder.': 'cond_stage_model.transformer.text_model.encoder.',
'cond_stage_model.transformer.final_layer_norm.': 'cond_stage_model.transformer.text_model.final_layer_norm.'
}
for k in list(model.keys()):
for r in nai_keys:
if type(k) == str and k.startswith(r):
new_key = k.replace(r, nai_keys[r])
model[new_key] = model[k]
del model[k]
shared.log.warning(f"Model convert: fixed NovelAI error key: {k}")
break
if fix_clip:
i = "cond_stage_model.transformer.text_model.embeddings.position_ids"
if i in model:
correct = torch.Tensor([list(range(77))]).to(torch.int64)
now = model[i].to(torch.int64)
broken = correct.ne(now)
broken = [i for i in range(77) if broken[0][i]]
model[i] = correct
if len(broken) != 0:
shared.log.warning(f"Model convert: fixed broken CLiP: {broken}")
return model
if model == "":
return "Error: you must choose a model"
if len(checkpoint_formats) == 0:
return "Error: at least choose one model save format"
extra_opt = {
"unet": unet_conv,
"clip": text_encoder_conv,
"vae": vae_conv,
"other": others_conv
}
shared.state.begin()
shared.state.job = 'model-convert'
model_info = sd_models.checkpoints_list[model]
shared.state.textinfo = f"Loading {model_info.filename}..."
shared.log.info(f"Model convert loading: {model_info.filename}")
state_dict = load_model(model_info.filename)
ok = {} # {"state_dict": {}}
conv_func = _g_precision_func[precision]
def _hf(wk: str, t: torch.Tensor):
if not isinstance(t, torch.Tensor):
return
w_t = check_weight_type(wk)
conv_t = extra_opt[w_t]
if conv_t == "convert":
ok[wk] = conv_func(t)
elif conv_t == "copy":
ok[wk] = t
elif conv_t == "delete":
return
shared.log.info("Model convert: running")
if conv_type == "ema-only":
for k in tqdm.tqdm(state_dict):
ema_k = "___"
try:
ema_k = "model_ema." + k[6:].replace(".", "")
except:
pass
if ema_k in state_dict:
_hf(k, state_dict[ema_k])
elif not k.startswith("model_ema.") or k in ["model_ema.num_updates", "model_ema.decay"]:
_hf(k, state_dict[k])
elif conv_type == "no-ema":
for k, v in tqdm.tqdm(state_dict.items()):
if "model_ema." not in k:
_hf(k, v)
else:
for k, v in tqdm.tqdm(state_dict.items()):
_hf(k, v)
ok = fix_model(ok, fix_clip=fix_clip)
output = ""
ckpt_dir = shared.cmd_opts.ckpt_dir or sd_models.model_path
save_name = f"{model_info.model_name}-{precision}"
if conv_type != "disabled":
save_name += f"-{conv_type}"
if custom_name != "":
save_name = custom_name
for fmt in checkpoint_formats:
ext = ".safetensors" if fmt == "safetensors" else ".ckpt"
_save_name = save_name + ext
save_path = os.path.join(ckpt_dir, _save_name)
shared.log.info(f"Model convert saving: {save_path}")
if fmt == "safetensors":
safetensors.torch.save_file(ok, save_path)
else:
torch.save({"state_dict": ok}, save_path)
output += f"Checkpoint saved to {save_path}<br>"
shared.state.end()
return output
+3 -3
View File
@@ -488,8 +488,8 @@ def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None,
dropout_structure=dropout_structure
)
hypernet.save(fn)
shared.reload_hypernetworks()
return name
def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, use_weight, create_image_every, save_hypernetwork_every, template_filename, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height):
@@ -609,7 +609,7 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi
# previous_mean_loss = 0
# print("Mean loss of {} elements".format(size))
steps_without_grad = 0
_steps_without_grad = 0
last_saved_file = "<none>"
last_saved_image = "<none>"
@@ -756,7 +756,7 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi
textual_inversion.tensorboard_add_image(tensorboard_writer,
f"Validation at epoch {epoch_num}", image,
hypernetwork.step)
last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename, save_to_dirs=False)
last_saved_image, _last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename, save_to_dirs=False)
last_saved_image += f", prompt: {preview_text}"
shared.state.job_no = hypernetwork.step
-3
View File
@@ -1,7 +1,4 @@
import html
import os
import re
import gradio as gr
import modules.hypernetworks.hypernetwork
from modules import devices, sd_hijack, shared
+4 -4
View File
@@ -411,7 +411,7 @@ options_templates.update(options_section(('saving-paths', "Output Paths"), {
"outdir_init_images": OptionInfo("outputs/init-images", "Directory for saving init images when using img2img", component_args=hide_dirs),
}))
options_templates.update(options_section(('ui', "User interface"), {
options_templates.update(options_section(('ui', "User Interface"), {
"gradio_theme": OptionInfo("black-orange", "UI theme", gr.Dropdown, lambda: {"choices": list_themes()}, refresh=refresh_themes),
"theme_style": OptionInfo("Auto", "Theme mode", gr.Radio, {"choices": ["Auto", "Dark", "Light"]}),
"tooltips": OptionInfo("UI Tooltips", "UI tooltips", gr.Radio, {"choices": ["None", "Browser default", "UI tooltips"]}),
@@ -433,14 +433,14 @@ options_templates.update(options_section(('ui', "User interface"), {
"ui_extra_networks_tab_reorder": OptionInfo("Checkpoints, Lora, LyCORIS, Textual Inversion, Hypernetworks", "Extra networks tab order"),
}))
options_templates.update(options_section(('live-preview', "Live previews"), {
options_templates.update(options_section(('live-preview', "Live Previews"), {
"show_progressbar": OptionInfo(True, "Show progressbar"),
"live_previews_enable": OptionInfo(True, "Show live previews of the created image"),
"show_progress_grid": OptionInfo(True, "Show previews of all images generated in a batch as a grid"),
"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 VAE", "Approximate NN", "Approximate simple", "TAESD"]}),
"show_progress_type": OptionInfo("Approximate NN", "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")
}))
@@ -511,7 +511,7 @@ options_templates.update(options_section(('upscaling', "Upscaling"), {
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers", 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", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
"SCUNET_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for SCUNET upscalers", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}),
"SCUNET_tile_overlap": OptionInfo(8, "Tile overlap for SCUNET upscalers", 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"),
"dont_fix_second_order_samplers_schedule": OptionInfo(False, "Do not fix prompt schedule for second order samplers"),
}))
+7 -430
View File
@@ -10,7 +10,7 @@ import numpy as np
from PIL import Image
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, ui_loadsave
from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, extra_networks, ui_common, ui_postprocessing, ui_loadsave, ui_train, ui_models
from modules.ui_components import FormRow, FormColumn, FormGroup, ToolButton, FormHTML # pylint: disable=unused-import
from modules.paths import script_path, data_path
from modules.shared import opts, cmd_opts, backend, Backend
@@ -26,7 +26,6 @@ import modules.styles
import modules.extras
import modules.textual_inversion.ui
import modules.sd_samplers
from modules.textual_inversion import textual_inversion
modules.errors.install()
@@ -286,16 +285,7 @@ def apply_setting(key, value):
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
def refresh():
refresh_method()
args = refreshed_args() if callable(refreshed_args) else refreshed_args
for k, v in args.items():
setattr(refresh_component, k, v)
return gr.update(**(args or {}))
refresh_button = ToolButton(value=refresh_symbol, elem_id=elem_id)
refresh_button.click(fn=refresh, inputs=[], outputs=[refresh_component])
return refresh_button
return ui_common.create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id)
def create_sampler_and_steps_selection(choices, tabname):
@@ -497,17 +487,6 @@ def create_ui():
parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields, override_settings)
parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(paste_button=txt2img_paste, tabname="txt2img", source_text_component=txt2img_prompt, source_image_component=None))
txt2img_preview_params = [
txt2img_prompt,
txt2img_negative_prompt,
steps,
sampler_index,
cfg_scale,
seed,
width,
height,
]
token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_prompt, steps], outputs=[token_counter])
negative_token_button.click(fn=wrap_queued_call(update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[negative_token_counter])
@@ -875,373 +854,11 @@ def create_ui():
with gr.Blocks(analytics_enabled=False) as extras_interface:
ui_postprocessing.create_ui()
def update_interp_description(value):
interp_description_css = "<p style='margin-bottom: 2.5em'>{}</p>"
interp_descriptions = {
"No interpolation": interp_description_css.format("No interpolation will be used. Requires one model; A. Allows for format conversion and VAE baking."),
"Weighted sum": interp_description_css.format("A weighted sum will be used for interpolation. Requires two models; A and B. The result is calculated as A * (1 - M) + B * M"),
"Add difference": interp_description_css.format("The difference between the last two models will be added to the first. Requires three models; A, B and C. The result is calculated as A + (B - C) * M")
}
return interp_descriptions[value]
with gr.Blocks(analytics_enabled=False) as train_interface:
with gr.Column(elem_id='ti_train_container'):
with gr.Tabs(elem_id="train_tabs"):
with gr.Tab(label="Merge models"):
with gr.Row().style(equal_height=False):
with gr.Column(variant='compact'):
with FormRow(elem_id="modelmerger_models"):
def sd_model_choices():
return ['None'] + modules.sd_models.checkpoint_tiles()
primary_model_name = gr.Dropdown(sd_model_choices(), elem_id="modelmerger_primary_model_name", label="Primary model", value="None")
create_refresh_button(primary_model_name, modules.sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A")
secondary_model_name = gr.Dropdown(sd_model_choices(), elem_id="modelmerger_secondary_model_name", label="Secondary model", value="None")
create_refresh_button(secondary_model_name, modules.sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B")
tertiary_model_name = gr.Dropdown(sd_model_choices(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model", value="None")
create_refresh_button(tertiary_model_name, modules.sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C")
custom_name = gr.Textbox(label="New model name", elem_id="modelmerger_custom_name")
with FormRow():
interp_description = gr.HTML(value=update_interp_description("Weighted sum"), elem_id="modelmerger_interp_description")
with FormRow():
interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method", elem_id="modelmerger_interp_method")
interp_method.change(fn=update_interp_description, inputs=[interp_method], outputs=[interp_description])
interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation ratio from Primary to Secondary', value=0.5, elem_id="modelmerger_interp_amount")
with FormRow():
checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", label="Checkpoint format", elem_id="modelmerger_checkpoint_format")
with gr.Box():
save_as_half = gr.Checkbox(value=True, label="Use FP16", elem_id="modelmerger_save_as_half")
save_metadata = gr.Checkbox(value=True, label="Save metadata", elem_id="modelmerger_save_metadata")
with FormRow():
with gr.Column():
config_source = gr.Radio(choices=["Primary", "Secondary", "Tertiary", "None"], value="Primary", label="Model configuration", type="index", elem_id="modelmerger_config_method")
with gr.Column():
with FormRow():
bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE", elem_id="modelmerger_bake_in_vae")
create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae")
with FormRow():
discard_weights = gr.Textbox(value="", label="Discard weights with matching name", elem_id="modelmerger_discard_weights")
with gr.Row():
modelmerger_merge = gr.Button(elem_id="modelmerger_merge", value="Merge", variant='primary')
model_checkhash = gr.Button(elem_id="modelmerger_hash", value="Calculate hash for all models (may take a long time)", variant='primary')
ui_train.create_ui(txt2img_preview_params = [txt2img_prompt, txt2img_negative_prompt, steps, sampler_index, cfg_scale, seed, width, height])
with gr.Column(variant='compact', elem_id="modelmerger_results_container"):
with gr.Group(elem_id="modelmerger_results_panel"):
modelmerger_result = gr.HTML(elem_id="modelmerger_result", show_label=False)
with gr.Tab(label="Create embedding", id="create_embedding"):
new_embedding_name = gr.Textbox(label="Name", elem_id="train_new_embedding_name")
initialization_text = gr.Textbox(label="Initialization text", value="*", elem_id="train_initialization_text")
nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1, elem_id="train_nvpt")
overwrite_old_embedding = gr.Checkbox(value=False, label="Overwrite Old Embedding", elem_id="train_overwrite_old_embedding")
with gr.Row():
with gr.Column(scale=3):
gr.HTML(value="")
with gr.Column():
create_embedding = gr.Button(value="Create embedding", variant='primary', elem_id="train_create_embedding")
with gr.Tab(label="Create hypernetwork", id="create_hypernetwork"):
new_hypernetwork_name = gr.Textbox(label="Name", elem_id="train_new_hypernetwork_name")
new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "1024", "320", "640", "1280"], elem_id="train_new_hypernetwork_sizes")
new_hypernetwork_layer_structure = gr.Textbox("1, 2, 1", label="Enter hypernetwork layer structure", placeholder="1st and last digit must be 1. ex:'1, 2, 1'", elem_id="train_new_hypernetwork_layer_structure")
new_hypernetwork_activation_func = gr.Dropdown(value="linear", label="Select activation function of hypernetwork", choices=modules.hypernetworks.ui.keys, elem_id="train_new_hypernetwork_activation_func")
new_hypernetwork_initialization_option = gr.Dropdown(value = "Normal", label="Select Layer weights initialization", choices=["Normal", "KaimingUniform", "KaimingNormal", "XavierUniform", "XavierNormal"], elem_id="train_new_hypernetwork_initialization_option")
new_hypernetwork_add_layer_norm = gr.Checkbox(label="Add layer normalization", elem_id="train_new_hypernetwork_add_layer_norm")
new_hypernetwork_use_dropout = gr.Checkbox(label="Use dropout", elem_id="train_new_hypernetwork_use_dropout")
new_hypernetwork_dropout_structure = gr.Textbox("0, 0, 0", label="Enter hypernetwork Dropout structure", placeholder="1st and last digit must be 0 and values should be between 0 and 1. ex:'0, 0.01, 0'")
overwrite_old_hypernetwork = gr.Checkbox(value=False, label="Overwrite Old Hypernetwork", elem_id="train_overwrite_old_hypernetwork")
with gr.Row():
with gr.Column(scale=3):
gr.HTML(value="")
with gr.Column():
create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary', elem_id="train_create_hypernetwork")
with gr.Tab(label="Preprocess images", id="preprocess_images"):
process_src = gr.Textbox(label='Source directory', elem_id="train_process_src")
process_dst = gr.Textbox(label='Destination directory', elem_id="train_process_dst")
process_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_process_width")
process_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_process_height")
preprocess_txt_action = gr.Dropdown(label='Existing Caption txt Action', value="ignore", choices=["ignore", "copy", "prepend", "append"], elem_id="train_preprocess_txt_action")
with gr.Row():
process_keep_original_size = gr.Checkbox(label='Keep original size', elem_id="train_process_keep_original_size")
process_keep_channels = gr.Checkbox(label='Keep original image channels', elem_id="train_process_keep_channels")
process_flip = gr.Checkbox(label='Create flipped copies', elem_id="train_process_flip")
process_split = gr.Checkbox(label='Split oversized images', elem_id="train_process_split")
process_focal_crop = gr.Checkbox(label='Auto focal point crop', elem_id="train_process_focal_crop")
process_multicrop = gr.Checkbox(label='Auto-sized crop', elem_id="train_process_multicrop")
process_caption_only = gr.Checkbox(label='Create captions only', elem_id="train_process_multicrop")
process_caption = gr.Checkbox(label='Create BLIP captions', elem_id="train_process_caption")
process_caption_deepbooru = gr.Checkbox(label='Create Deepbooru captions', visible=True, elem_id="train_process_caption_deepbooru")
with gr.Row(visible=False) as process_split_extra_row:
process_split_threshold = gr.Slider(label='Split image threshold', value=0.5, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_split_threshold")
process_overlap_ratio = gr.Slider(label='Split image overlap ratio', value=0.2, minimum=0.0, maximum=0.9, step=0.05, elem_id="train_process_overlap_ratio")
with gr.Row(visible=False) as process_focal_crop_row:
process_focal_crop_face_weight = gr.Slider(label='Focal point face weight', value=0.9, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_face_weight")
process_focal_crop_entropy_weight = gr.Slider(label='Focal point entropy weight', value=0.15, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_entropy_weight")
process_focal_crop_edges_weight = gr.Slider(label='Focal point edges weight', value=0.5, minimum=0.0, maximum=1.0, step=0.05, elem_id="train_process_focal_crop_edges_weight")
process_focal_crop_debug = gr.Checkbox(label='Create debug image', elem_id="train_process_focal_crop_debug")
with gr.Column(visible=False) as process_multicrop_col:
gr.Markdown('Each image is center-cropped with an automatically chosen width and height.')
with gr.Row():
process_multicrop_mindim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension lower bound", value=384, elem_id="train_process_multicrop_mindim")
process_multicrop_maxdim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension upper bound", value=768, elem_id="train_process_multicrop_maxdim")
with gr.Row():
process_multicrop_minarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area lower bound", value=64*64, elem_id="train_process_multicrop_minarea")
process_multicrop_maxarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area upper bound", value=640*640, elem_id="train_process_multicrop_maxarea")
with gr.Row():
process_multicrop_objective = gr.Radio(["Maximize area", "Minimize error"], value="Maximize area", label="Resizing objective", elem_id="train_process_multicrop_objective")
process_multicrop_threshold = gr.Slider(minimum=0, maximum=1, step=0.01, label="Error threshold", value=0.1, elem_id="train_process_multicrop_threshold")
with gr.Row():
with gr.Column(scale=3):
gr.HTML(value="")
with gr.Column():
with gr.Row():
interrupt_preprocessing = gr.Button("Stop", elem_id="train_interrupt_preprocessing")
run_preprocess = gr.Button(value="Preprocess", variant='primary', elem_id="train_run_preprocess")
process_split.change(
fn=lambda show: gr_show(show),
inputs=[process_split],
outputs=[process_split_extra_row],
)
process_focal_crop.change(
fn=lambda show: gr_show(show),
inputs=[process_focal_crop],
outputs=[process_focal_crop_row],
)
process_multicrop.change(
fn=lambda show: gr_show(show),
inputs=[process_multicrop],
outputs=[process_multicrop_col],
)
def get_textual_inversion_template_names():
return sorted(textual_inversion.textual_inversion_templates)
with gr.Tab(label="Train", id="train"):
gr.HTML(value="<p style='margin-bottom: 0.7em'>Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images</p>")
with FormRow():
train_embedding_name = gr.Dropdown(label='Embedding', elem_id="train_embedding", choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
create_refresh_button(train_embedding_name, sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings, lambda: {"choices": sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())}, "refresh_train_embedding_name")
train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', elem_id="train_hypernetwork", choices=sorted(modules.shared.hypernetworks))
create_refresh_button(train_hypernetwork_name, modules.shared.reload_hypernetworks, lambda: {"choices": sorted(modules.shared.hypernetworks)}, "refresh_train_hypernetwork_name")
with FormRow():
embedding_learn_rate = gr.Textbox(label='Embedding Learning rate', placeholder="Embedding Learning rate", value="0.005", elem_id="train_embedding_learn_rate")
hypernetwork_learn_rate = gr.Textbox(label='Hypernetwork Learning rate', placeholder="Hypernetwork Learning rate", value="0.00001", elem_id="train_hypernetwork_learn_rate")
with FormRow():
clip_grad_mode = gr.Dropdown(value="disabled", label="Gradient Clipping", choices=["disabled", "value", "norm"])
clip_grad_value = gr.Textbox(placeholder="Gradient clip value", value="0.1", show_label=False)
with FormRow():
batch_size = gr.Number(label='Batch size', value=1, precision=0, elem_id="train_batch_size")
gradient_step = gr.Number(label='Gradient accumulation steps', value=1, precision=0, elem_id="train_gradient_step")
dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images", elem_id="train_dataset_directory")
log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value=f"{os.path.join('cmd_opts.data_dir', 'train/log/embeddings')}", elem_id="train_log_directory")
with FormRow():
template_file = gr.Dropdown(label='Prompt template', value="style_filewords.txt", elem_id="train_template_file", choices=get_textual_inversion_template_names())
create_refresh_button(template_file, textual_inversion.list_textual_inversion_templates, lambda: {"choices": get_textual_inversion_template_names()}, "refrsh_train_template_file")
training_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="train_training_width")
training_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="train_training_height")
varsize = gr.Checkbox(label="Do not resize images", value=False, elem_id="train_varsize")
steps = gr.Number(label='Max steps', value=1000, precision=0, elem_id="train_steps")
with FormRow():
create_image_every = gr.Number(label='Create interim images', value=500, precision=0, elem_id="train_create_image_every")
save_embedding_every = gr.Number(label='Create interim embeddings', value=500, precision=0, elem_id="train_save_embedding_every")
use_weight = gr.Checkbox(label="Use PNG alpha channel as loss weight", value=False, elem_id="use_weight")
save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True, elem_id="train_save_image_with_stored_embedding")
preview_from_txt2img = gr.Checkbox(label='Use current settings for previews', value=False, elem_id="train_preview_from_txt2img")
shuffle_tags = gr.Checkbox(label="Shuffle tags by ',' when creating prompts.", value=False, elem_id="train_shuffle_tags")
tag_drop_out = gr.Slider(minimum=0, maximum=1, step=0.1, label="Drop out tags when creating prompts.", value=0, elem_id="train_tag_drop_out")
latent_sampling_method = gr.Radio(label='Choose latent sampling method', value="once", choices=['once', 'deterministic', 'random'], elem_id="train_latent_sampling_method")
with gr.Row():
train_embedding = gr.Button(value="Train Embedding", variant='primary', elem_id="train_train_embedding")
interrupt_training = gr.Button(value="Stop", elem_id="train_interrupt_training")
train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary', elem_id="train_train_hypernetwork")
params = script_callbacks.UiTrainTabParams(txt2img_preview_params)
script_callbacks.ui_train_tabs_callback(params)
with gr.Column(elem_id='ti_gallery_container'):
ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)
gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(columns=4)
gr.HTML(elem_id="ti_progress", value="")
ti_outcome = gr.HTML(elem_id="ti_error", value="")
create_embedding.click(
fn=modules.textual_inversion.ui.create_embedding,
inputs=[
new_embedding_name,
initialization_text,
nvpt,
overwrite_old_embedding,
],
outputs=[
train_embedding_name,
ti_output,
ti_outcome,
]
)
create_hypernetwork.click(
fn=modules.hypernetworks.ui.create_hypernetwork,
inputs=[
new_hypernetwork_name,
new_hypernetwork_sizes,
overwrite_old_hypernetwork,
new_hypernetwork_layer_structure,
new_hypernetwork_activation_func,
new_hypernetwork_initialization_option,
new_hypernetwork_add_layer_norm,
new_hypernetwork_use_dropout,
new_hypernetwork_dropout_structure
],
outputs=[
train_hypernetwork_name,
ti_output,
ti_outcome,
]
)
run_preprocess.click(
fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]),
_js="start_training_textual_inversion",
inputs=[
dummy_component,
process_src,
process_dst,
process_width,
process_height,
preprocess_txt_action,
process_keep_original_size,
process_keep_channels,
process_flip,
process_split,
process_caption_only,
process_caption,
process_caption_deepbooru,
process_split_threshold,
process_overlap_ratio,
process_focal_crop,
process_focal_crop_face_weight,
process_focal_crop_entropy_weight,
process_focal_crop_edges_weight,
process_focal_crop_debug,
process_multicrop,
process_multicrop_mindim,
process_multicrop_maxdim,
process_multicrop_minarea,
process_multicrop_maxarea,
process_multicrop_objective,
process_multicrop_threshold,
],
outputs=[
ti_output,
ti_outcome,
],
)
train_embedding.click(
fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]),
_js="start_training_textual_inversion",
inputs=[
dummy_component,
train_embedding_name,
embedding_learn_rate,
batch_size,
gradient_step,
dataset_directory,
log_directory,
training_width,
training_height,
varsize,
steps,
clip_grad_mode,
clip_grad_value,
shuffle_tags,
tag_drop_out,
latent_sampling_method,
use_weight,
create_image_every,
save_embedding_every,
template_file,
save_image_with_stored_embedding,
preview_from_txt2img,
*txt2img_preview_params,
],
outputs=[
ti_output,
ti_outcome,
]
)
train_hypernetwork.click(
fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
_js="start_training_textual_inversion",
inputs=[
dummy_component,
train_hypernetwork_name,
hypernetwork_learn_rate,
batch_size,
gradient_step,
dataset_directory,
log_directory,
training_width,
training_height,
varsize,
steps,
clip_grad_mode,
clip_grad_value,
shuffle_tags,
tag_drop_out,
latent_sampling_method,
use_weight,
create_image_every,
save_embedding_every,
template_file,
preview_from_txt2img,
*txt2img_preview_params,
],
outputs=[
ti_output,
ti_outcome,
]
)
interrupt_training.click(
fn=lambda: modules.shared.state.interrupt(),
inputs=[],
outputs=[],
)
interrupt_preprocessing.click(
fn=lambda: modules.shared.state.interrupt(),
inputs=[],
outputs=[],
)
with gr.Blocks(analytics_enabled=False) as models_interface:
ui_models.create_ui()
def create_setting_component(key, is_quicksettings=False):
def fun():
@@ -1436,9 +1053,8 @@ def create_ui():
(txt2img_interface, "From Text", "txt2img"),
(img2img_interface, "From Image", "img2img"),
(extras_interface, "Process Image", "process"),
# (pnginfo_interface, "Image Info", "pnginfo"),
# (modelmerger_interface, "Checkpoint Merger", "modelmerger"),
(train_interface, "Train", "train"),
(models_interface, "Models", "models"),
]
interfaces += script_callbacks.ui_tabs_callback()
interfaces += [(settings_interface, "Settings", "settings")]
@@ -1494,7 +1110,7 @@ def create_ui():
show_progress=info.refresh is not None,
)
# TODO image_cfg_scale_visibility should be on model change, not on ui create
# TODO breaks pix2pix needs better detect if pix2pix and image_cfg_scale_visibility should be on model change, not on ui create
# image_cfg_scale_visibility = (modules.shared.sd_model is not None) and hasattr(modules.shared.sd_model, 'cond_stage_key') and (modules.shared.sd_model.cond_stage_key == "edit") # pix2pix
# text_settings.change(fn=lambda: gr.update(visible=image_cfg_scale_visibility), inputs=[], outputs=[image_cfg_scale])
# demo.load(fn=lambda: gr.update(visible=image_cfg_scale_visibility), inputs=[], outputs=[image_cfg_scale])
@@ -1519,47 +1135,8 @@ def create_ui():
queue=False,
)
def modelmerger(*args):
try:
results = modules.extras.run_modelmerger(*args)
except Exception as e:
modules.errors.display(e, 'model merge')
modules.sd_models.list_models() # to remove the potentially missing models from the list
return [*[gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"]
return results
modelmerger_merge.click(fn=lambda: '', inputs=[], outputs=[modelmerger_result])
modelmerger_merge.click(
fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]),
_js='modelmerger',
inputs=[
dummy_component,
primary_model_name,
secondary_model_name,
tertiary_model_name,
interp_method,
interp_amount,
save_as_half,
custom_name,
checkpoint_format,
config_source,
bake_in_vae,
discard_weights,
save_metadata,
],
outputs=[
primary_model_name,
secondary_model_name,
tertiary_model_name,
component_dict['sd_model_checkpoint'],
modelmerger_result,
]
)
model_checkhash.click(fn=sd_models.update_model_hashes, inputs=[], outputs=[modelmerger_result])
loadsave.dump_defaults()
demo.ui_loadsave = loadsave
interp_description.value = update_interp_description(interp_method.value) # Required as a workaround for change() event not triggering when loading values from ui-config.json
return demo
+16
View File
@@ -207,3 +207,19 @@ def create_output_panel(tabname, outdir):
paste_button=paste_button, tabname=paste_tabname, source_tabname=("txt2img" if tabname == "txt2img" else None), source_image_component=result_gallery, paste_field_names=paste_field_names
))
return result_gallery, generation_info, html_info, html_info_formatted, html_log
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
def refresh():
refresh_method()
args = refreshed_args() if callable(refreshed_args) else refreshed_args
for k, v in args.items():
setattr(refresh_component, k, v)
return gr.update(**(args or {}))
from modules.ui_components import ToolButton
refresh_symbol = '\U0001f504' # 🔄
refresh_button = ToolButton(value=refresh_symbol, elem_id=elem_id)
refresh_button.click(fn=refresh, inputs=[], outputs=[refresh_component])
return refresh_button
+3 -1
View File
@@ -331,6 +331,8 @@ def refresh_extensions_list_from_data(search_text, sort_column):
ext['sort_enabled'] = f"{'0' if ext['enabled'] else '1'}{'1' if ext['is_builtin'] else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00')}"
ext['sort_update'] = f"{'1' if update_available else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00')}"
tags = ext.get("tags", [])
if not isinstance(tags, list):
tags = tags.split(' ')
tags_string = ' '.join(tags)
tags = tags + ["installed"] if installed else tags
if len([x for x in tags if x in hide_tags]) > 0:
@@ -377,7 +379,7 @@ def create_ui():
extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False).style(container=False)
extensions_update_list = gr.Text(elem_id="extensions_update_list", visible=False).style(container=False)
with gr.Tabs(elem_id="tabs_extensions"):
with gr.TabItem("Manage Extensions", id="manage"):
with gr.TabItem("Manage extensions", id="manage"):
with gr.Row(elem_id="extensions_installed_top"):
extension_to_install = gr.Text(elem_id="extension_to_install", visible=False)
install_extension_button = gr.Button(elem_id="install_extension_button", visible=False)
+163
View File
@@ -0,0 +1,163 @@
import os
import json
from datetime import datetime
import gradio as gr
from modules import sd_models, sd_vae, extras
from modules.ui_components import FormRow
from modules.ui_common import create_refresh_button
from modules.call_queue import wrap_gradio_gpu_call
import modules.errors
def create_ui():
dummy_component = gr.Label(visible=False)
with gr.Row(id="models_tab", elem_id="models_tab"):
with gr.Column(elem_id='models_output_container', scale=1):
# models_output = gr.Text(elem_id="models_output", value="", show_label=False)
gr.HTML(elem_id="models_progress", value="")
models_outcome = gr.HTML(elem_id="models_error", value="")
with gr.Column(elem_id='models_input_container', scale=3):
def gr_show(visible=True):
return {"visible": visible, "__type__": "update"}
with gr.Tab(label="Convert"):
with gr.Row():
model_name = gr.Dropdown(sd_models.checkpoint_tiles(), label="Original model")
create_refresh_button(model_name, sd_models.list_models, lambda: {"choices": sd_models.checkpoint_tiles()}, "refresh_checkpoint_Z")
with gr.Row():
custom_name = gr.Textbox(label="New model name")
with gr.Row():
precision = gr.Radio(choices=["fp32", "fp16", "bf16"], value="fp32", label="Model precision")
m_type = gr.Radio(choices=["disabled", "no-ema", "ema-only"], value="disabled", label="Model pruning methods")
with gr.Row():
checkpoint_formats = gr.CheckboxGroup(choices=["ckpt", "safetensors"], value=["safetensors"], label="Model Format")
with gr.Row():
show_extra_options = gr.Checkbox(label="Show extra options", value=False)
fix_clip = gr.Checkbox(label="Fix clip", value=False)
with gr.Row(visible=False) as extra_options:
specific_part_conv = ["copy", "convert", "delete"]
unet_conv = gr.Dropdown(specific_part_conv, value="convert", label="unet")
text_encoder_conv = gr.Dropdown(specific_part_conv, value="convert", label="text encoder")
vae_conv = gr.Dropdown(specific_part_conv, value="convert", label="vae")
others_conv = gr.Dropdown(specific_part_conv, value="convert", label="others")
show_extra_options.change(fn=lambda x: gr_show(x), inputs=[show_extra_options], outputs=[extra_options])
model_converter_convert = gr.Button(label="Convert", variant='primary')
model_converter_convert.click(
fn=extras.run_modelconvert,
inputs=[
model_name,
checkpoint_formats,
precision, m_type, custom_name,
unet_conv,
text_encoder_conv,
vae_conv,
others_conv,
fix_clip
],
outputs=[models_outcome]
)
with gr.Tab(label="Merge"):
with gr.Row().style(equal_height=False):
with gr.Column(variant='compact'):
with FormRow():
custom_name = gr.Textbox(label="New model name")
with FormRow():
def sd_model_choices():
return ['None'] + sd_models.checkpoint_tiles()
primary_model_name = gr.Dropdown(sd_model_choices(), label="Primary model", value="None")
create_refresh_button(primary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_A")
secondary_model_name = gr.Dropdown(sd_model_choices(), label="Secondary model", value="None")
create_refresh_button(secondary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_B")
tertiary_model_name = gr.Dropdown(sd_model_choices(), label="Tertiary model", value="None")
create_refresh_button(tertiary_model_name, sd_models.list_models, lambda: {"choices": sd_model_choices()}, "refresh_checkpoint_C")
with FormRow():
interp_method = gr.Radio(choices=["No interpolation", "Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method")
interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation ratio from Primary to Secondary', value=0.5)
with FormRow():
checkpoint_format = gr.Radio(choices=["ckpt", "safetensors"], value="safetensors", label="Model format")
with gr.Box():
save_as_half = gr.Radio(choices=["fp16", "fp32"], value="fp16", label="Model precision", type="index")
with FormRow():
config_source = gr.Radio(choices=["Primary", "Secondary", "Tertiary", "None"], value="Primary", label="Model configuration", type="index")
with FormRow():
bake_in_vae = gr.Dropdown(choices=["None"] + list(sd_vae.vae_dict), value="None", label="Bake in VAE")
create_refresh_button(bake_in_vae, sd_vae.refresh_vae_list, lambda: {"choices": ["None"] + list(sd_vae.vae_dict)}, "modelmerger_refresh_bake_in_vae")
with FormRow():
discard_weights = gr.Textbox(value="", label="Discard weights with matching name")
with FormRow():
save_metadata = gr.Checkbox(value=True, label="Save metadata")
with gr.Row():
modelmerger_merge = gr.Button(value="Merge", variant='primary')
def modelmerger(*args):
try:
results = extras.run_modelmerger(*args)
except Exception as e:
modules.errors.display(e, 'model merge')
sd_models.list_models() # to remove the potentially missing models from the list
return [*[gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"]
return results
modelmerger_merge.click(
fn=wrap_gradio_gpu_call(modelmerger, extra_outputs=lambda: [gr.update() for _ in range(4)]),
_js='modelmerger',
inputs=[
dummy_component,
primary_model_name,
secondary_model_name,
tertiary_model_name,
interp_method,
interp_amount,
save_as_half,
custom_name,
checkpoint_format,
config_source,
bake_in_vae,
discard_weights,
save_metadata,
],
outputs=[
primary_model_name,
secondary_model_name,
tertiary_model_name,
dummy_component,
models_outcome,
]
)
with gr.Tab(label="Validate"):
model_headers = ['name', 'type', 'filename', 'hash', 'added', 'size', 'metadata']
model_data = []
with gr.Row():
model_list_btn = gr.Button(value="List model details", variant='primary')
model_checkhash_btn = gr.Button(value="Calculate hash for all models (may take a long time)", variant='primary')
model_checkhash_btn.click(fn=sd_models.update_model_hashes, inputs=[], outputs=[models_outcome])
with gr.Row():
model_table = gr.DataFrame(model_data, label = 'Model data', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = model_headers)
def list_models():
total_size = 0
for m in sd_models.checkpoints_list.values():
txt = ''
try:
stat = os.stat(m.filename)
m_name = m.name.replace('.ckpt', '').replace('.safetensors', '')
m_type = 'ckpt' if m.name.endswith('.ckpt') else 'safe'
m_meta = len(json.dumps(m.metadata)) - 2
m_size = round(stat.st_size / 1024 / 1024 / 1024, 3)
m_time = datetime.fromtimestamp(stat.st_mtime)
model_data.append([m_name, m_type, m.filename, m.hash, m_time, m_size, m_meta])
total_size += stat.st_size
except Exception as e:
txt += f"Error: {m.name} {e}<br>"
txt += f"Model list enumerated {len(sd_models.checkpoints_list.keys())} models in {round(total_size / 1024 / 1024 / 1024, 3)} GB<br>"
return model_data, txt
model_list_btn.click(fn=list_models, inputs=[], outputs=[model_table, models_outcome])
+360
View File
@@ -0,0 +1,360 @@
import os
import gradio as gr
from modules import sd_hijack, script_callbacks, shared
from modules.ui_components import FormRow
from modules.ui_common import create_refresh_button
from modules.call_queue import wrap_gradio_gpu_call
from modules.textual_inversion import textual_inversion
import modules.errors
def create_ui(txt2img_preview_params):
dummy_component = gr.Label(visible=False)
with gr.Row(id="train_tab", elem_id="train_tab"):
with gr.Column(elem_id='train_output_container', scale=1):
train_output = gr.Text(elem_id="train_output", value="", show_label=False)
gr.Gallery(label='Output', show_label=False, elem_id='train_gallery').style(columns=1)
gr.HTML(elem_id="train_progress", value="")
train_outcome = gr.HTML(elem_id="train_error", value="")
with gr.Row(visible=True) as action_pp:
process_run = gr.Button(value="Preprocess", variant='primary')
process_stop = gr.Button("Stop")
with gr.Row(visible=False) as action_ti:
ti_train = gr.Button(value="Train embedding", variant='primary')
ti_stop = gr.Button(value="Stop")
with gr.Row(visible=False) as action_hn:
hn_train = gr.Button(value="Train hypernetwork", variant='primary')
hn_stop = gr.Button(value="Stop")
with gr.Column(elem_id='train_input_container', scale=3):
with gr.Tabs(elem_id="train_tabs"):
def gr_show(visible=True):
return {"visible": visible, "__type__": "update"}
def train_tab_change(tab):
if tab == 'ti':
return gr_show(False), gr_show(True), gr_show(False)
elif tab == 'hn':
return gr_show(False), gr_show(False), gr_show(True)
else:
return gr_show(True), gr_show(False), gr_show(False)
### preprocess tab
with gr.Tab(label="Preprocess images", id="preprocess_images") as tab_preprocess:
tab_preprocess.select(fn=lambda x: train_tab_change('pp'), inputs=[], outputs=[action_pp, action_ti, action_hn])
process_src = gr.Textbox(label='Source directory')
process_dst = gr.Textbox(label='Destination directory')
with gr.Row():
process_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512)
process_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512)
preprocess_txt_action = gr.Dropdown(label='Existing caption text action', value="ignore", choices=["ignore", "copy", "prepend", "append"])
with gr.Box():
gr.Markdown('## Preprocessing steps')
process_keep_original_size = gr.Checkbox(label='Keep original size')
process_keep_channels = gr.Checkbox(label='Keep original image channels')
process_flip = gr.Checkbox(label='Create flipped copies')
process_split = gr.Checkbox(label='Split oversized images')
process_focal_crop = gr.Checkbox(label='Auto focal point crop')
process_multicrop = gr.Checkbox(label='Auto-sized crop')
process_caption_only = gr.Checkbox(label='Create captions only')
process_caption = gr.Checkbox(label='Create BLIP captions')
process_caption_deepbooru = gr.Checkbox(label='Create Deepbooru captions')
with gr.Row(visible=False) as process_split_extra_row:
process_split_threshold = gr.Slider(label='Split image threshold', value=0.5, minimum=0.0, maximum=1.0, step=0.05)
process_overlap_ratio = gr.Slider(label='Split image overlap ratio', value=0.2, minimum=0.0, maximum=0.9, step=0.05)
with gr.Row(visible=False) as process_focal_crop_row:
process_focal_crop_face_weight = gr.Slider(label='Focal point face weight', value=0.9, minimum=0.0, maximum=1.0, step=0.05)
process_focal_crop_entropy_weight = gr.Slider(label='Focal point entropy weight', value=0.15, minimum=0.0, maximum=1.0, step=0.05)
process_focal_crop_edges_weight = gr.Slider(label='Focal point edges weight', value=0.5, minimum=0.0, maximum=1.0, step=0.05)
process_focal_crop_debug = gr.Checkbox(label='Create debug image')
with gr.Column(visible=False) as process_multicrop_col:
gr.Markdown('## Each image is center-cropped with an automatically chosen width and height.')
with gr.Row():
process_multicrop_mindim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension lower bound", value=384)
process_multicrop_maxdim = gr.Slider(minimum=64, maximum=2048, step=8, label="Dimension upper bound", value=768)
with gr.Row():
process_multicrop_minarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area lower bound", value=64*64)
process_multicrop_maxarea = gr.Slider(minimum=64*64, maximum=2048*2048, step=1, label="Area upper bound", value=640*640)
with gr.Row():
process_multicrop_objective = gr.Radio(["Maximize area", "Minimize error"], value="Maximize area", label="Resizing objective")
process_multicrop_threshold = gr.Slider(minimum=0, maximum=1, step=0.01, label="Error threshold", value=0.1)
process_split.change(fn=lambda show: gr_show(show), inputs=[process_split], outputs=[process_split_extra_row])
process_focal_crop.change(fn=lambda show: gr_show(show), inputs=[process_focal_crop], outputs=[process_focal_crop_row])
process_multicrop.change(fn=lambda show: gr_show(show), inputs=[process_multicrop], outputs=[process_multicrop_col])
process_stop.click(fn=lambda: shared.state.interrupt(), inputs=[], outputs=[])
process_run.click(
fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]),
_js="start_train_monitoring",
inputs=[
dummy_component,
process_src,
process_dst,
process_width,
process_height,
preprocess_txt_action,
process_keep_original_size,
process_keep_channels,
process_flip,
process_split,
process_caption_only,
process_caption,
process_caption_deepbooru,
process_split_threshold,
process_overlap_ratio,
process_focal_crop,
process_focal_crop_face_weight,
process_focal_crop_entropy_weight,
process_focal_crop_edges_weight,
process_focal_crop_debug,
process_multicrop,
process_multicrop_mindim,
process_multicrop_maxdim,
process_multicrop_minarea,
process_multicrop_maxarea,
process_multicrop_objective,
process_multicrop_threshold,
],
outputs=[
train_output,
train_outcome,
],
)
### train embedding tab
with gr.Tab(label="Train embedding", id="train_embedding_tab") as tab_ti:
tab_ti.select(fn=lambda x: train_tab_change('ti'), inputs=[], outputs=[action_pp, action_ti, action_hn])
def get_textual_inversion_template_names():
return sorted(textual_inversion.textual_inversion_templates)
gr.Markdown('## Select existing embedding to continue training or create a new one')
with FormRow():
with gr.Column():
with gr.Row():
ti_name = gr.Dropdown(label='Select embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
create_refresh_button(ti_name, sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings, lambda: {"choices": sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())}, "refresh_train_embedding_name")
with gr.Column():
ti_new_name = gr.Textbox(label="Create emebedding")
ti_init_text = gr.Textbox(label="Initialization text", value="*")
ti_vectors = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1)
ti_overwrite = gr.Checkbox(value=False, label="Overwrite Old Embedding")
with gr.Row():
ti_create = gr.Button(value="Create embedding", variant='secondary')
with gr.Box():
gr.Markdown('## Training parameters')
ti_learn_rate = gr.Textbox(label='Embedding Learning rate', placeholder="Embedding Learning rate", value="0.005")
with FormRow():
ti_clip_grad_mode = gr.Dropdown(value="disabled", label="Gradient Clipping", choices=["disabled", "value", "norm"])
ti_clip_grad_value = gr.Number(label="Gradient clip value", value=0.1)
ti_batch_size = gr.Number(label='Batch size', value=1, precision=0)
ti_gradient_step = gr.Number(label='Gradient accumulation steps', value=1, precision=0)
ti_steps = gr.Number(label='Max steps', value=1000, precision=0)
with gr.Box():
gr.Markdown('## Training images')
ti_dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images")
with FormRow():
ti_varsize = gr.Checkbox(label="Do not resize images", value=False)
ti_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512)
ti_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512)
ti_use_weight = gr.Checkbox(label="Use PNG alpha channel as loss weight", value=False)
with gr.Box():
gr.Markdown('## Dataset processing')
with FormRow():
ti_template = gr.Dropdown(label='Prompt template', value="style_filewords.txt", choices=get_textual_inversion_template_names())
create_refresh_button(ti_template, textual_inversion.list_textual_inversion_templates, lambda: {"choices": get_textual_inversion_template_names()}, "refrsh_train_template_file")
ti_shuffle = gr.Checkbox(label="Shuffle tags", value=False)
ti_tag_drop_out = gr.Slider(minimum=0, maximum=1, step=0.1, label="Drop out tags when creating prompts", value=0)
ti_latent_sampling_method = gr.Radio(label='Choose latent sampling method', value="once", choices=['once', 'deterministic', 'random'])
with gr.Box():
gr.Markdown('## Training outputs')
with FormRow():
ti_create_every = gr.Number(label='Create interim images', value=500, precision=0)
ti_save_every = gr.Number(label='Create interim embeddings', value=500, precision=0)
ti_save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True)
ti_preview_from_txt2img = gr.Checkbox(label='Use current settings for previews', value=False)
ti_log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value=f"{os.path.join(shared.cmd_opts.data_dir, 'train/log/embeddings')}")
ti_stop.click(fn=lambda: shared.state.interrupt(), inputs=[], outputs=[])
ti_create.click(
fn=modules.textual_inversion.ui.create_embedding,
inputs=[
ti_new_name,
ti_init_text,
ti_vectors,
ti_overwrite,
],
outputs=[
ti_name,
train_output,
train_outcome,
]
)
ti_train.click(
fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]),
_js="start_train_monitoring",
inputs=[
dummy_component,
ti_name,
ti_learn_rate,
ti_batch_size,
ti_gradient_step,
ti_dataset_directory,
ti_log_directory,
ti_width,
ti_height,
ti_varsize,
ti_steps,
ti_clip_grad_mode,
ti_clip_grad_value,
ti_shuffle,
ti_tag_drop_out,
ti_latent_sampling_method,
ti_use_weight,
ti_create_every,
ti_save_every,
ti_template,
ti_save_image_with_stored_embedding,
ti_preview_from_txt2img,
*txt2img_preview_params,
],
outputs=[
train_output,
train_outcome,
]
)
### train hypernetwork tab
with gr.Tab(label="Train hypernetwork", id="train_hypernetwork_tab") as tab_hn:
tab_hn.select(fn=lambda x: train_tab_change('hn'), inputs=[], outputs=[action_pp, action_ti, action_hn])
gr.Markdown('## Select existing embedding to continue training or create a new one')
with FormRow():
with gr.Column():
with FormRow():
hn_name = gr.Dropdown(label='Hypernetwork', choices=sorted(shared.hypernetworks))
create_refresh_button(hn_name, shared.reload_hypernetworks, lambda: {"choices": sorted(shared.hypernetworks)}, "refresh_train_hypernetwork_name")
with gr.Column():
hn_new_name = gr.Textbox(label="Name")
hn_new_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "1024", "320", "640", "1280"])
hn_new_layer_structure = gr.Textbox("1, 2, 1", label="Enter hypernetwork layer structure", placeholder="1st and last digit must be 1. ex:'1, 2, 1'")
with gr.Row():
hn_new_activation_func = gr.Dropdown(value="linear", label="Select activation function of hypernetwork", choices=modules.hypernetworks.ui.keys)
hn_new_initialization_option = gr.Dropdown(value = "Normal", label="Select Layer weights initialization", choices=["Normal", "KaimingUniform", "KaimingNormal", "XavierUniform", "XavierNormal"])
hn_new_add_layer_norm = gr.Checkbox(label="Add layer normalization")
hn_new_use_dropout = gr.Checkbox(label="Use dropout")
hn_new_dropout_structure = gr.Textbox("0, 0, 0", label="Enter hypernetwork Dropout structure", placeholder="1st and last digit must be 0 and values should be between 0 and 1. ex:'0, 0.01, 0'")
hn_overwrite = gr.Checkbox(value=False, label="Overwrite Old Hypernetwork")
with gr.Row():
hn_create = gr.Button(value="Create hypernetwork", variant='secondary')
with gr.Box():
gr.Markdown('## Training parameters')
hn_learn_rate = gr.Textbox(label='Hypernetwork Learning rate', placeholder="Hypernetwork Learning rate", value="0.00001")
with FormRow():
hn_clip_grad_mode = gr.Dropdown(value="disabled", label="Gradient Clipping", choices=["disabled", "value", "norm"])
hn_clip_grad_value = gr.Number(label="Gradient clip value", value=0.1)
hn_batch_size = gr.Number(label='Batch size', value=1, precision=0)
hn_gradient_step = gr.Number(label='Gradient accumulation steps', value=1, precision=0)
hn_steps = gr.Number(label='Max steps', value=1000, precision=0)
with gr.Box():
gr.Markdown('## Training images')
hn_dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images")
with FormRow():
hn_varsize = gr.Checkbox(label="Do not resize images", value=False)
hn_width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512)
hn_height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512)
hn_use_weight = gr.Checkbox(label="Use PNG alpha channel as loss weight", value=False)
with gr.Box():
gr.Markdown('## Dataset processing')
with FormRow():
hn_template = gr.Dropdown(label='Prompt template', value="style_filewords.txt", choices=get_textual_inversion_template_names())
create_refresh_button(hn_template, textual_inversion.list_textual_inversion_templates, lambda: {"choices": get_textual_inversion_template_names()}, "refrsh_train_template_file")
hn_shuffle_tags = gr.Checkbox(label="Shuffle tags by ',' when creating prompts.", value=False)
hn_tag_drop_out = gr.Slider(minimum=0, maximum=1, step=0.1, label="Drop out tags when creating prompts", value=0)
hn_latent_sampling_method = gr.Radio(label='Choose latent sampling method', value="once", choices=['once', 'deterministic', 'random'])
with gr.Box():
gr.Markdown('## Training outputs')
with FormRow():
hn_create_every = gr.Number(label='Create interim images', value=500, precision=0)
hn_save_every = gr.Number(label='Create interim hypernetworks', value=500, precision=0)
hn_preview_from_txt2img = gr.Checkbox(label='Use current settings for previews', value=False)
hn_log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value=f"{os.path.join('cmd_opts.data_dir', 'train/log/embeddings')}")
hn_stop.click(fn=lambda: shared.state.interrupt(), inputs=[], outputs=[])
hn_create.click(
fn=modules.hypernetworks.ui.create_hypernetwork,
inputs=[
hn_new_name,
hn_new_sizes,
hn_overwrite,
hn_new_layer_structure,
hn_new_activation_func,
hn_new_initialization_option,
hn_new_add_layer_norm,
hn_new_use_dropout,
hn_new_dropout_structure
],
outputs=[
hn_name,
train_output,
train_outcome,
]
)
hn_train.click(
fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
_js="start_train_monitoring",
inputs=[
dummy_component,
hn_name,
hn_learn_rate,
hn_batch_size,
hn_gradient_step,
hn_dataset_directory,
hn_log_directory,
hn_width,
hn_height,
hn_varsize,
hn_steps,
hn_clip_grad_mode,
hn_clip_grad_value,
hn_shuffle_tags,
hn_tag_drop_out,
hn_latent_sampling_method,
hn_use_weight,
hn_create_every,
hn_save_every,
hn_template,
hn_preview_from_txt2img,
*txt2img_preview_params,
],
outputs=[
train_output,
train_outcome,
]
)
params = script_callbacks.UiTrainTabParams(txt2img_preview_params)
script_callbacks.ui_train_tabs_callback(params)
+1 -1
Submodule wiki updated: 01aabc1269...f941746c0e