From 148c4567d605e5de263186353c174fe09ba24c83 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 11 Feb 2023 17:34:20 -0500 Subject: [PATCH] lora training --- automatic.sh | 2 +- cli/README.md | 25 +++-- ...iinterrogate.py => interrogate-offline.py} | 0 .../{extract-lora.py => lora-extract.py} | 0 .../{lora_latents.py => lora-latents.py} | 1 - ...dding-preview.py => preview-embeddings.py} | 0 .../{models-preview.py => preview-models.py} | 0 cli/modules/process.py | 90 +++++++++++----- cli/modules/sdapi.py | 13 ++- cli/{modules => }/train-lora.py | 86 ++++++++------- cli/{train.py => train-ti.py} | 100 ++++++++++++++---- cli/train.json | 76 ------------- config.json | 6 +- extensions-builtin/sd-dynamic-thresholding | 2 +- .../stable-diffusion-webui-images-browser | 2 +- modules/api/api.py | 12 +++ modules/localization.py | 1 + modules/lora | 2 +- requirements.txt | 1 + requirements_versions.txt | 2 + ui-config.json | 8 +- 21 files changed, 248 insertions(+), 181 deletions(-) rename cli/modules/{multiinterrogate.py => interrogate-offline.py} (100%) rename cli/modules/{extract-lora.py => lora-extract.py} (100%) rename cli/modules/{lora_latents.py => lora-latents.py} (99%) rename cli/modules/{embedding-preview.py => preview-embeddings.py} (100%) rename cli/modules/{models-preview.py => preview-models.py} (100%) rename cli/{modules => }/train-lora.py (73%) rename cli/{train.py => train-ti.py} (91%) delete mode 100644 cli/train.json diff --git a/automatic.sh b/automatic.sh index 0300d0daa..151fc235a 100755 --- a/automatic.sh +++ b/automatic.sh @@ -8,7 +8,7 @@ PYTORCH_CUDA_ALLOC_CONF=garbage_collection_threshold:0.9,max_split_size_mb:512 CUDA_LAUNCH_BLOCKING=0 CUDA_CACHE_DISABLE=0 CUDA_AUTO_BOOST=1 -CUDA_DEVICE_DEFAULT_PERSISTING_L2_CACHE_PERCENTAGE_LIMIT=50 +CUDA_DEVICE_DEFAULT_PERSISTING_L2_CACHE_PERCENTAGE_LIMIT=0 if [ "$PYTHON" == "" ]; then PYTHON=`which python` diff --git a/cli/README.md b/cli/README.md index e4c612e92..3e6ce931a 100644 --- a/cli/README.md +++ b/cli/README.md @@ -24,8 +24,8 @@ Parameters that are not specified will be randomized: ### Train -End-to-end embedding training -> python train.py +Textual inversion embedding training +> python train-ti.py Combined pipeline: 1. Creates embedding @@ -33,6 +33,18 @@ Combined pipeline: 3. Preprocesses images 4. Runs training +LoRA training +> python train-lora.py + +Combined pipeline: +1. Creates embedding +2. Extracts images if input is movie +3. Preprocesses images +4. Runs training + +LoRA extract from model +> python moidules/lora-extract.py +
## Auxiliary Scripts @@ -49,7 +61,7 @@ Note: Requires SD API Create previews of embeddings using preview templates Note: Requires SD API -> python modules/embedding-preview.py +> python modules/preview-embeddings.py ## Grid @@ -72,19 +84,19 @@ Note: Requires SD API > python modules/interrogate.py -### Multi-Interrogate +### Interrogate-Offline Standalone implementation of GiT, CLiP and ViT image interrogation Note: Offline tool -> python modules/interrogate.py +> python modules/interrogate-offline.py ### Models Previews Create previews of models using built-in templates Note: Requires SD API -> python modules/models-preview.py +> python modules/preview-models.py ### Palette Extract @@ -146,3 +158,4 @@ Note: Requires SD API Can be used to manually execute specific commands: > python sdapi.py progress > python sdapi.py interrupt +> python sdapi.py shutdown diff --git a/cli/modules/multiinterrogate.py b/cli/modules/interrogate-offline.py similarity index 100% rename from cli/modules/multiinterrogate.py rename to cli/modules/interrogate-offline.py diff --git a/cli/modules/extract-lora.py b/cli/modules/lora-extract.py similarity index 100% rename from cli/modules/extract-lora.py rename to cli/modules/lora-extract.py diff --git a/cli/modules/lora_latents.py b/cli/modules/lora-latents.py similarity index 99% rename from cli/modules/lora_latents.py rename to cli/modules/lora-latents.py index a48b83dbf..95b933ac6 100755 --- a/cli/modules/lora_latents.py +++ b/cli/modules/lora-latents.py @@ -18,7 +18,6 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'modules', ' import library.model_util as model_util import library.train_util as train_util - warnings.filterwarnings('ignore') device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') options = Map({ diff --git a/cli/modules/embedding-preview.py b/cli/modules/preview-embeddings.py similarity index 100% rename from cli/modules/embedding-preview.py rename to cli/modules/preview-embeddings.py diff --git a/cli/modules/models-preview.py b/cli/modules/preview-models.py similarity index 100% rename from cli/modules/models-preview.py rename to cli/modules/preview-models.py diff --git a/cli/modules/process.py b/cli/modules/process.py index 60f59bbb3..7ea370628 100755 --- a/cli/modules/process.py +++ b/cli/modules/process.py @@ -20,6 +20,7 @@ process people images """ import os +import sys import io import math import base64 @@ -32,6 +33,8 @@ import mediapipe as mp from PIL import Image, ImageOps from skimage.metrics import structural_similarity as ssim from scipy.stats import beta +sys.path.append(os.path.join(os.path.dirname(__file__))) + from util import log, Map from sdapi import postsync @@ -50,21 +53,24 @@ params = Map({ 'face_pad': 0.2, # pad face image percentage 'face_model': 1, # which face model to use 0/close-up 1/standard 'face_blur_score': 1.5, # max score for face blur detection - 'face_range_score': 0.2, # min score for face dynamic range detection + 'face_range_score': 0.15, # min score for face dynamic range detection 'body_score': 0.9, # min body detection score 'body_visibility': 0.5, # min visibility score for each detected body part 'body_parts': 15, # min number of detected body parts with sufficient visibility 'body_pad': 0.2, # pad body image percentage 'body_model': 2, # body model to use 0/low 1/medium 2/high 'body_blur_score': 1.8, # max score for body blur detection - 'body_range_score': 0.2, # min score for body dynamic range detection + 'body_range_score': 0.15, # min score for body dynamic range detection 'segmentation_face': False, # segmentation enabled 'segmentation_body': False, # segmentation enabled 'segmentation_model': 0, # segmentation model 0/general 1/landscape 'segmentation_background': (192, 192, 192), # segmentation background color - 'similarity_score': 0.6, # maximum similarity score before image is discarded + 'similarity_score': 0.8, # maximum similarity score before image is discarded 'similarity_size': 64, # base similarity detection on reduced images - 'interrogate_model': 'clip' # interrogate model + 'interrogate_model': ['clip', 'deepdanbooru'], # interrogate model + 'tag_limit': 5, # number of tags to extract + 'face_restore': True, # attempt to restore face quality + 'face_upscale': True, # attempt to scale small faces }) face_model = None body_model = None @@ -161,6 +167,26 @@ def extract_face(img): square = [scale * (cx - l), scale * (cy - l), scale * (cx + l), scale * (cy + l)] square = [max(square[0], 0), max(square[1], 0), min(square[2], img.width), min(square[3], img.height)] cropped = img.crop(tuple(square)) + + upscale = 1 + if params.face_restore or params.face_upscale: + if (cropped.size[0] < params.target_size or cropped.size[1] < params.target_size) and params.face_upscale: + upscale = 2 + kwargs = Map({ + 'image': encode(cropped), + 'upscaler_1': 'SwinIR_4x' if params.face_upscale else None, + 'codeformer_visibility': 1.0 if params.face_restore else 0.0, + 'codeformer_weight': 0.15 if params.face_restore else 0.0, + 'upscaling_resize': upscale, + }) + original = [cropped.size[0], cropped.size[1]] + res = postsync('/sdapi/v1/extra-single-image', kwargs) + cropped = Image.open(io.BytesIO(base64.b64decode(res['image']))) + kwargs.image = [cropped.size[0], cropped.size[1]] + upscaled = [cropped.size[0], cropped.size[1]] + upscale = False if upscale == 1 else { 'original': original, 'upscaled': upscaled } + log.info({ 'process face restore': params.face_restore, 'upscale': upscale }) + if cropped.size[0] < params.target_size and cropped.size[1] < params.target_size: log.info({ 'process face skip': 'low resolution', 'size': [cropped.size[0], cropped.size[1]] }) return None, True @@ -253,37 +279,51 @@ def extract_body(img): similarity = detect_simmilar(squared) if similarity > params.similarity_score: - log.info({ 'process body skip': 'similarity check fail', 'score': similarity }) + log.info({ 'process body skip': 'similarity check fail', 'score': round(similarity, 2) }) return None, True return squared, True -def interrogate(img, fn): - def encode(f): - with io.BytesIO() as stream: - img.save(stream, 'JPEG') - values = stream.getvalue() - encoded = base64.b64encode(values).decode() - return encoded +def encode(img): + with io.BytesIO() as stream: + img.save(stream, 'JPEG') + values = stream.getvalue() + encoded = base64.b64encode(values).decode() + return encoded - if params.interrogate_model is None or params.interrogate_model == '': + +def interrogate(img, fn, txt): + if len(params.interrogate_model) == 0: return - json = Map({ 'image': encode(img), 'model': params.interrogate_model }) - res = postsync('/sdapi/v1/interrogate', json) - caption = res.caption if 'caption' in res else '' - log.info({ 'interrogate': caption }) - file = fn.replace(params.format, '.txt') - f = open(file, 'w') - f.write(caption) - f.close() - return caption + caption = '' + tags = [] + for model in params.interrogate_model: + json = Map({ 'image': encode(img), 'model': model }) + res = postsync('/sdapi/v1/interrogate', json) + if model == 'clip': + caption = res.caption if 'caption' in res else '' + caption = caption.split(',')[0].replace('a ', '') + if model == 'deepdanbooru': + tag = res.caption if 'caption' in res else '' + tags = tag.split(',') + tags = [t.replace('(', '').replace(')', '').split(':')[0].strip() for t in tags] + if txt: + file = fn.replace(params.format, '.txt') + f = open(file, 'w') + f.write(caption) + f.close() + tags.insert(0, caption.split(' ')[0]) + if len(tags) > params.tag_limit: + tags = tags[:params.tag_limit] + log.info({ 'interrogate': caption, 'tags': tags }) + return caption, tags i = {} metadata = Map({}) -def process_file(f: str, dst: str = None, preview: bool = False, offline: bool = False): +def process_file(f: str, dst: str = None, preview: bool = False, offline: bool = False, txt: bool = True): def save(img, f, what): i[what] = i.get(what, 0) + 1 @@ -298,8 +338,8 @@ def process_file(f: str, dst: str = None, preview: bool = False, offline: bool = if not preview: img.save(fn) if not offline: - caption = interrogate(img, fn) - metadata[fn] = { 'caption': caption, 'tags': [] } + caption, tags = interrogate(img, fn, txt) + metadata[fn] = { 'caption': caption, 'tags': tags } return fn log.info({ 'processing': f }) diff --git a/cli/modules/sdapi.py b/cli/modules/sdapi.py index 0fd15ff34..b03373637 100755 --- a/cli/modules/sdapi.py +++ b/cli/modules/sdapi.py @@ -34,7 +34,7 @@ async def result(req): res = {} else: res = Map(json) - log.debug({ 'request': req.status, 'url': req.url, 'reason': req.reason, 'result': res }) + log.debug({ 'request': req.status, 'url': req.url, 'reason': req.reason }) return res @@ -51,7 +51,7 @@ def resultsync(req: requests.Response): res = {} else: res = Map(json) - log.debug({ 'request': req.status_code, 'url': req.url, 'reason': req.reason, 'result': res }) + log.debug({ 'request': req.status_code, 'url': req.url, 'reason': req.reason }) return res @@ -128,6 +128,13 @@ async def progress(): return res +def shutdown(): + try: + postsync('/sdapi/v1/shutdown') + except Exception as e: + log.info({ 'shutdown': e }) + + async def session(): global sess # pylint: disable=global-statement time = aiohttp.ClientTimeout(total = None, sock_connect = 10, sock_read = None) # default value is 5 minutes, we need longer for training @@ -161,4 +168,6 @@ if __name__ == "__main__": asyncio.run(interrupt()) if 'progress' in sys.argv: asyncio.run(progress()) + if 'shutdown' in sys.argv: + shutdown() asyncio.run(close()) diff --git a/cli/modules/train-lora.py b/cli/train-lora.py similarity index 73% rename from cli/modules/train-lora.py rename to cli/train-lora.py index 8709c0e94..2e8049e8e 100755 --- a/cli/modules/train-lora.py +++ b/cli/train-lora.py @@ -17,15 +17,19 @@ import os import gc import sys import json +import time import argparse import tempfile import torch +import logging +import importlib import transformers from pathlib import Path -from util import log, Map, get_memory -import process -import multiinterrogate -import lora_latents +from modules.util import log, Map, get_memory +import modules.process +import modules.sdapi + +latents = importlib.import_module('modules.lora-latents') sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'modules', 'lora')) from train_network import train @@ -122,19 +126,27 @@ if __name__ == '__main__': parser = argparse.ArgumentParser(description = 'train lora') parser.add_argument('--model', type=str, default=None, required=True, help='original model to use a base for training') parser.add_argument('--input', type=str, default=None, required=True, help='input folder with training images') + parser.add_argument('--output', type=str, default=None, required=True, help='lora name') + parser.add_argument('--tag', type=str, default=None, required=False, help='primary tag') parser.add_argument('--dir', type=str, default=None, required=True, help='folder containing lora checkpoints') - parser.add_argument('--name', type=str, default=None, required=True, help='lora name') parser.add_argument('--interim', type=int, default=0, help = 'save interim checkpoints after n epoch') parser.add_argument('--noprocess', default = False, action='store_true', help = 'skip processing and use existing input data') + parser.add_argument('--notrain', default = False, action='store_true', help = 'just run processing and skip training') parser.add_argument('--nocaptions', default = False, action='store_true', help = 'skip creating captions and tags') parser.add_argument('--nolatents', default = False, action='store_true', help = 'skip generating vae latents') + parser.add_argument('--offline', default = False, action='store_true', help = 'do not use webui server for processing') parser.add_argument('--gradient', type=int, default=1, required=False, help='gradient accumulation steps, default: %(default)s') parser.add_argument('--steps', type=int, default=5000, required=False, help='training steps, default: %(default)s') parser.add_argument('--dim', type=int, default=128, required=False, help='network dimension, default: %(default)s') + parser.add_argument('--batch', type=int, default=1, required=False, help='batch size, default: %(default)s') parser.add_argument('--lr', type=float, default=1e-04, required=False, help='model learning rate, default: %(default)s') parser.add_argument('--unetlr', type=float, default=1e-04, required=False, help='unet learning rate, default: %(default)s') parser.add_argument('--textlr', type=float, default=5e-05, required=False, help='text encoder learning rate, default: %(default)s') + parser.add_argument('--debug', default=False, action='store_true', help = "enable debug logging") args = parser.parse_args() + if args.debug: + log.setLevel(logging.DEBUG) + log.debug({ 'debug': True }) if not os.path.exists(args.model) or not os.path.isfile(args.model): log.error({ 'lora cannot find model': args.model }) exit(1) @@ -146,7 +158,7 @@ if __name__ == '__main__': log.error({ 'lora cannot find training dir': args.dir }) exit(1) options.output_dir = args.dir - options.output_name = args.name + options.output_name = args.output options.max_train_steps = args.steps options.network_dim = args.dim options.gradient_accumulation_steps = args.gradient @@ -154,46 +166,44 @@ if __name__ == '__main__': options.learning_rate = args.lr options.unet_lr = args.unetlr options.text_encoder_lr = args.textlr + options.train_batch_size = args.batch log.info({ 'train lora args': vars(options) }) transformers.logging.set_verbosity_error() mem_stats() - if args.noprocess: - dir = args.input - options.train_data_dir = dir - options.in_json = None - else: - dir = os.path.join(tempfile.gettempdir(), args.name, '10_processed') - Path(dir).mkdir(parents=True, exist_ok=True) + dir = os.path.join(tempfile.gettempdir(), args.output, '10_processed') + Path(dir).mkdir(parents=True, exist_ok=True) + json_file = os.path.join(dir, args.output + '.json') + options.train_data_dir = os.path.join(tempfile.gettempdir(), args.output) + options.in_json = json_file + for root, _sub_dirs, folder in os.walk(args.input): + files = [os.path.join(root, f) for f in folder] + if not args.noprocess: # preprocess - for root, _sub_dirs, folder in os.walk(args.input): - files = [os.path.join(root, f) for f in folder] for f in files: - res, metadata = process.process_file(f = f, dst = dir, preview = False, offline = True) - process.unload_models() - options.train_data_dir = os.path.join(tempfile.gettempdir(), args.name) + res, metadata = modules.process.process_file(f = f, dst = dir, preview = False, offline = args.offline, txt = False) + modules.process.unload_models() mem_stats() - - if not args.nocaptions: - # interrogate - for root, _sub_dirs, folder in os.walk(dir): - files = [os.path.join(root, f) for f in folder] - metadata = multiinterrogate.interrogate_files(Map({ 'input': dir, 'json': '', 'tag': args.name }), files) - json_file = os.path.join(dir, args.name + '.json') + if args.tag is not None: + for name, item in metadata.items(): + item['tags'].insert(0, args.tag) with open(json_file, "w") as outfile: outfile.write(json.dumps(metadata, indent=2)) - multiinterrogate.unload_model() + log.info({ 'processed': res, 'inputs': len(files), 'metadata': json_file, 'path': dir }) + else: + log.info({ 'skip processing': len(files), 'metadata': json_file, 'path': dir }) + + if not args.notrain: + log.info({ 'server shutdown required': True }) + modules.sdapi.shutdown() + time.sleep(1) + + if not args.nolatents and json_file is not None: + # create latents + latents.create_vae_latents(Map({ 'input': dir, 'json': json_file })) + latents.unload_vae() + mem_stats() + + train(options) mem_stats() - options.in_json = json_file - - log.info({ 'processed': res, 'inputs': len(files), 'metadata': json_file }) - - if not args.nolatents: - # create latents - lora_latents.create_vae_latents(Map({ 'input': dir, 'json': json_file })) - lora_latents.unload_vae() - mem_stats() - - train(options) - mem_stats() diff --git a/cli/train.py b/cli/train-ti.py similarity index 91% rename from cli/train.py rename to cli/train-ti.py index 7bfb1ec02..61db0bb34 100755 --- a/cli/train.py +++ b/cli/train-ti.py @@ -29,7 +29,7 @@ from modules.util import Map, log, set_logfile from modules.sdapi import close, get, interrupt, post, progress, session from modules.process import process_images from modules.grid import grid -create_preview = importlib.import_module('modules.embedding-preview').create_preview +create_preview = importlib.import_module('modules.preview-embeddings').create_preview plot = importlib.import_module('modules.train-losschart').plot extract = importlib.import_module('modules.video-extract').extract gen_loss_rate_str = importlib.import_module('modules.train-lossrate').gen_loss_rate_str @@ -38,6 +38,82 @@ images = [] args = {} options = None cmdflags = None +args = Map({ + "training_model": "sd-v15-runwayml.ckpt", + "extract_video": { + "rate": 0, + "fps": 5, + "vstart": 0, + "vend": 0 + }, + "create_embedding": { + "name": "test", + "num_vectors_per_token": 1, + "overwrite_old": False, + "init_text": "*" + }, + "preprocess": { + "id_task": 0, + "process_src": "", + "process_dst": "", + "process_width": 512, + "process_height": 512, + "process_flip": False, + "process_split": False, + "process_caption": True, + "process_caption_deepbooru": False, + "preprocess_txt_action": "ignore", + "process_focal_crop": True, + "process_focal_crop_face_weight": 0.9, + "process_focal_crop_entropy_weight": 0.3, + "process_focal_crop_edges_weight": 0.5, + "process_focal_crop_debug": False, + "split_threshold": 0.5, + "overlap_ratio": 0.2, + "process_multicrop": None, + "process_multicrop_mindim": None, + "process_multicrop_maxdim": None, + "process_multicrop_minarea": None, + "process_multicrop_maxarea": None, + "process_multicrop_objective": None, + "process_multicrop_threshold": None, + }, + "train_embedding": { + "id_task": 0, + "embedding_name": "", + "learn_rate": -1, + "batch_size": 1, + "steps": 500, + "data_root": "", + "log_directory": "train/log", + "template_filename": "subject_filewords.txt", + "gradient_step": 20, + "training_width": 512, + "training_height": 512, + "shuffle_tags": False, + "tag_drop_out": 0, + "clip_grad_mode": "disabled", + "clip_grad_value": "0.1", + "latent_sampling_method": "deterministic", + "create_image_every": -1, + "save_embedding_every": -1, + "save_image_with_stored_embedding": False, + "preview_from_txt2img": False, + "preview_prompt": "", + "preview_negative_prompt": "blurry, duplicate, ugly, deformed, low res, watermark, text", + "preview_steps": 20, + "preview_sampler_index": 0, + "preview_cfg_scale": 6, + "preview_seed": -1, + "preview_width": 512, + "preview_height": 512, + "varsize": False, + }, + "create_hypernetwork": { + }, + "train_hypernetwork": { + } +}) async def plotloss(params): @@ -427,7 +503,6 @@ async def monitor(params): async def main(): parser = argparse.ArgumentParser(description="sd train pipeline") - parser.add_argument("--config", type = str, default = 'train.json', required = False, help = "configuration file, default: %(default)s") parser.add_argument("--name", type = str, required = True, help = "embedding name, set to auto to use src folder name") parser.add_argument("--src", type = str, required = True, help = "source image folder or movie file") parser.add_argument("--init", type = str, default = "person", required = False, help = "initialization class, default: %(default)s") @@ -458,27 +533,6 @@ async def main(): log.debug({ 'args': params.__dict__ }) home = Path(sys.argv[0]).parent global args # pylint: disable=global-statement - if os.path.isfile(params.config): - try: - with open(params.config, 'r', encoding='utf-8') as f: - data = json.load(f) - args = Map(data) # pylint: disable=redefined-outer-name - log.debug({ 'config': args }) - except Exception as e: - log.error({ 'config error': params.config, 'exception': e }) - exit() - elif os.path.isfile(os.path.join(home, params.config)): - try: - with open(os.path.join(home, params.config), 'r', encoding='utf-8') as f: - data = json.load(f) - args = Map(data) # pylint: disable=redefined-outer-name - log.debug({ 'config': args }) - except Exception as e: - log.error({ 'config error': params.config, 'exception': e }) - exit() - else: - log.error({ 'config file not found': params.config}) - exit() if params.vstart > 0: args.extract_video.vstart = params.vstart if params.vend > 0: diff --git a/cli/train.json b/cli/train.json deleted file mode 100644 index 5db0dd189..000000000 --- a/cli/train.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "training_model": "sd-v15-runwayml.ckpt", - "extract_video": { - "rate": 0, - "fps": 5, - "vstart": 0, - "vend": 0 - }, - "create_embedding": { - "name": "test", - "num_vectors_per_token": 1, - "overwrite_old": false, - "init_text": "*" - }, - "preprocess": { - "id_task": 0, - "process_src": "", - "process_dst": "", - "process_width": 512, - "process_height": 512, - "process_flip": false, - "process_split": false, - "process_caption": true, - "process_caption_deepbooru": false, - "preprocess_txt_action": "ignore", - "process_focal_crop": true, - "process_focal_crop_face_weight": 0.9, - "process_focal_crop_entropy_weight": 0.3, - "process_focal_crop_edges_weight": 0.5, - "process_focal_crop_debug": false, - "split_threshold": 0.5, - "overlap_ratio": 0.2, - "process_multicrop": null, - "process_multicrop_mindim": null, - "process_multicrop_maxdim": null, - "process_multicrop_minarea": null, - "process_multicrop_maxarea": null, - "process_multicrop_objective": null, - "process_multicrop_threshold": null - }, - "train_embedding": { - "id_task": 0, - "embedding_name": "", - "learn_rate": -1, - "batch_size": 1, - "steps": 500, - "data_root": "", - "log_directory": "train/log", - "template_filename": "subject_filewords.txt", - "gradient_step": 20, - "training_width": 512, - "training_height": 512, - "shuffle_tags": false, - "tag_drop_out": 0, - "clip_grad_mode": "disabled", - "clip_grad_value": "0.1", - "latent_sampling_method": "deterministic", - "create_image_every": -1, - "save_embedding_every": -1, - "save_image_with_stored_embedding": false, - "preview_from_txt2img": false, - "preview_prompt": "", - "preview_negative_prompt": "blurry, duplicate, ugly, deformed, low res, watermark, text", - "preview_steps": 20, - "preview_sampler_index": 0, - "preview_cfg_scale": 6, - "preview_seed": -1, - "preview_width": 512, - "preview_height": 512, - "varsize": false - }, - "create_hypernetwork": { - }, - "train_hypernetwork": { - } -} diff --git a/config.json b/config.json index fc4a8fb8d..e444c4f4d 100644 --- a/config.json +++ b/config.json @@ -64,7 +64,7 @@ "flavors" ], "interrogate_deepbooru_score_threshold": 0.65, - "interrogate_keep_models_in_memory": false, + "interrogate_keep_models_in_memory": true, "interrogate_return_ranks": true, "interrogate_use_builtin_artists": false, "jpeg_quality": 80, @@ -188,5 +188,7 @@ "image_browser_scan_exif": false, "image_browser_page_columns": 6.0, "image_browser_page_rows": 20.0, - "image_browser_pages_perload": 20.0 + "image_browser_pages_perload": 20.0, + "image_browser_mod_shift": false, + "image_browser_mod_ctrl_shift": false } \ No newline at end of file diff --git a/extensions-builtin/sd-dynamic-thresholding b/extensions-builtin/sd-dynamic-thresholding index 61260cad8..681a5ffe7 160000 --- a/extensions-builtin/sd-dynamic-thresholding +++ b/extensions-builtin/sd-dynamic-thresholding @@ -1 +1 @@ -Subproject commit 61260cad8f14842aad463938a74fb9d30b6b3bb5 +Subproject commit 681a5ffe7bcc4cd00890339a32a7e903f9cf6e7c diff --git a/extensions-builtin/stable-diffusion-webui-images-browser b/extensions-builtin/stable-diffusion-webui-images-browser index 7a7c97b76..0416810ad 160000 --- a/extensions-builtin/stable-diffusion-webui-images-browser +++ b/extensions-builtin/stable-diffusion-webui-images-browser @@ -1 +1 @@ -Subproject commit 7a7c97b76aa531f26ebbd95f04a3926faf8e46b8 +Subproject commit 0416810adf4827aa36a032dc7beed94ba6dcb954 diff --git a/modules/api/api.py b/modules/api/api.py index eb7b1da54..f5226f34b 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -150,6 +150,7 @@ class Api: self.add_api_route("/sdapi/v1/train/embedding", self.train_embedding, methods=["POST"], response_model=TrainResponse) self.add_api_route("/sdapi/v1/train/hypernetwork", self.train_hypernetwork, methods=["POST"], response_model=TrainResponse) self.add_api_route("/sdapi/v1/memory", self.get_memory, methods=["GET"], response_model=MemoryResponse) + self.add_api_route("/sdapi/v1/shutdown", self.shutdown, methods=["POST"]) def add_api_route(self, path: str, endpoint, **kwargs): if shared.cmd_opts.api_auth: @@ -175,6 +176,17 @@ class Api: script = script_runner.selectable_scripts[script_idx] return script, script_idx + def shutdown(self): + print('shutdown request received') + # from modules.shared import demo + # demo.close() + # time.sleep(0.5) + # import sys + # sys.exit(0) + import os + os._exit(0) + + def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI): script, script_idx = self.get_script(txt2imgreq.script_name, scripts.scripts_txt2img) diff --git a/modules/localization.py b/modules/localization.py index f6a6f2fbd..353a6baa1 100644 --- a/modules/localization.py +++ b/modules/localization.py @@ -9,6 +9,7 @@ localizations = {} def list_localizations(dirname): localizations.clear() + return localizations for file in os.listdir(dirname): fn, ext = os.path.splitext(file) diff --git a/modules/lora b/modules/lora index 53d60543e..b32abdd32 160000 --- a/modules/lora +++ b/modules/lora @@ -1 +1 @@ -Subproject commit 53d60543e59d6fdf3a6b5d0d15019487d2e415db +Subproject commit b32abdd327f314fabc76fbbb627218090afb7b69 diff --git a/requirements.txt b/requirements.txt index 16698c0c6..4efe59c90 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ blendmodes bitsandbytes clean-fid colormap +diffusers easydev einops extcolors diff --git a/requirements_versions.txt b/requirements_versions.txt index 112d8bfe1..d602b680f 100644 --- a/requirements_versions.txt +++ b/requirements_versions.txt @@ -2,7 +2,9 @@ accelerate==0.16.0 basicsr==1.4.2 blendmodes==2022 clean-fid==0.1.35 +diffusers==0.12.1 einops==0.4.1 +fastapi==0.90.1 gfpgan==1.3.8 GitPython==3.1.27 gradio==3.16.2 diff --git a/ui-config.json b/ui-config.json index e48226aad..fd75e30ce 100644 --- a/ui-config.json +++ b/ui-config.json @@ -756,17 +756,17 @@ "customscript/postprocessing_codeformer.py/extras/CodeFormer visibility/maximum": 1.0, "customscript/postprocessing_codeformer.py/extras/CodeFormer visibility/minimum": 0.0, "customscript/postprocessing_codeformer.py/extras/CodeFormer visibility/step": 0.001, - "customscript/postprocessing_codeformer.py/extras/CodeFormer visibility/value": 0, + "customscript/postprocessing_codeformer.py/extras/CodeFormer visibility/value": 1.0, "customscript/postprocessing_codeformer.py/extras/CodeFormer visibility/visible": true, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = max), 1 = min)/maximum": 1.0, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = max), 1 = min)/minimum": 0.0, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = max), 1 = min)/step": 0.001, - "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = max), 1 = min)/value": 0, + "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = max), 1 = min)/value": 0.15, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = max), 1 = min)/visible": true, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = maximum effect, 1 = minimum effect)/maximum": 1.0, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = maximum effect, 1 = minimum effect)/minimum": 0.0, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = maximum effect, 1 = minimum effect)/step": 0.001, - "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = maximum effect, 1 = minimum effect)/value": 0, + "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = maximum effect, 1 = minimum effect)/value": 0.15, "customscript/postprocessing_codeformer.py/extras/CodeFormer weight (0 = maximum effect, 1 = minimum effect)/visible": true, "customscript/postprocessing_gfpgan.py/extras/GFPGAN visibility/maximum": 1.0, "customscript/postprocessing_gfpgan.py/extras/GFPGAN visibility/minimum": 0.0, @@ -782,7 +782,7 @@ "customscript/postprocessing_upscale.py/extras/Resize/step": 0.05, "customscript/postprocessing_upscale.py/extras/Resize/value": 4, "customscript/postprocessing_upscale.py/extras/Resize/visible": true, - "customscript/postprocessing_upscale.py/extras/Upscaler 1/value": "None", + "customscript/postprocessing_upscale.py/extras/Upscaler 1/value": "SwinIR_4x", "customscript/postprocessing_upscale.py/extras/Upscaler 1/visible": true, "customscript/postprocessing_upscale.py/extras/Upscaler 2 visibility/maximum": 1.0, "customscript/postprocessing_upscale.py/extras/Upscaler 2 visibility/minimum": 0.0,