From a02052cd6a739186a6014517ea761487c97973bf Mon Sep 17 00:00:00 2001 From: Seunghoon Lee Date: Fri, 23 Feb 2024 15:14:13 +0900 Subject: [PATCH 01/44] improve zluda installation --- installer.py | 46 +++++++++++++++++++++++++++++++++++++++++---- modules/cmd_args.py | 1 + modules/shared.py | 3 --- modules/zluda.py | 26 ++++++++++++++++++++----- 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/installer.py b/installer.py index 0aae1b9b8..b8c17f632 100644 --- a/installer.py +++ b/installer.py @@ -405,10 +405,14 @@ def check_torch(): log.debug(f'Torch allowed: cuda={allow_cuda} rocm={allow_rocm} ipex={allow_ipex} diml={allow_directml} openvino={allow_openvino}') torch_command = os.environ.get('TORCH_COMMAND', '') xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') + zluda_need_dll_patch = False def is_rocm_available(): if not allow_rocm: return False + if installed('torch-directml'): + log.debug('DirectML installation is detected. Skipping HIP SDK check.') + return False if platform.system() == 'Windows': hip_path = os.environ.get('HIP_PATH', None) return hip_path is not None and os.path.exists(os.path.join(hip_path, 'bin')) @@ -474,7 +478,15 @@ def check_torch(): except Exception as e: log.debug(f'ROCm hipconfig failed: {e}') rocm_ver = None - if not is_windows: # remove after PyTorch built with ROCm for Windows is launched + if args.use_zluda: # ZLUDA is available on both Linux and Windows + torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.2.0 torchvision --index-url https://download.pytorch.org/whl/cu118') + log.warning("Currently, ZLUDA support is experimental and unstable.") + zluda_need_dll_patch = is_windows and not installed('torch') + elif is_windows: # remove this check after PyTorch built with ROCm for Windows is released + log.warning("HIP SDK is detected, but there's no PyTorch release for Windows at this moment. If you are trying ZLUDA, please add '--use-zluda'.") + log.info('Using CPU-only torch') + torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') + else: if rocm_ver in {"5.7"}: torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}') elif rocm_ver in {"5.5", "5.6"}: @@ -484,9 +496,6 @@ def check_torch(): torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/rocm5.5') if rocm_ver is not None: install(os.environ.get('ONNXRUNTIME_PACKAGE', get_onnxruntime_source_for_rocm(arr)), "onnxruntime-training built with ROCm", ignore=True) - else: - log.info('Using CPU-only Torch') - torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') elif allow_ipex and (args.use_ipex or shutil.which('sycl-ls') is not None or shutil.which('sycl-ls.exe') is not None or os.environ.get('ONEAPI_ROOT') is not None or os.path.exists('/opt/intel/oneapi') or os.path.exists("C:/Program Files (x86)/Intel/oneAPI") or os.path.exists("C:/oneAPI")): args.use_ipex = True # pylint: disable=attribute-defined-outside-init @@ -539,11 +548,15 @@ def check_torch(): install(torch_command, 'torch torchvision') install('onnxruntime-directml', 'onnxruntime-directml', ignore=True) else: + if args.use_zluda: + log.warning("Failed to initialize ZLUDA. There's no HIP SDK found in PATH.") log.info('Using CPU-only Torch') torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') if 'torch' in torch_command and not args.version: log.debug(f'Installing torch: {torch_command}') install(torch_command, 'torch torchvision') + if zluda_need_dll_patch: + patch_dlls_for_zluda() else: try: import torch @@ -896,6 +909,31 @@ def get_onnxruntime_source_for_rocm(rocm_ver): return 'onnxruntime-gpu' +def patch_dlls_for_zluda(): + zluda_path = os.environ.get('ZLUDA', None) + if zluda_path is None: + paths = os.environ.get('PATH', '').split(';') + for path in paths: + if os.path.exists(os.path.join(path, 'zluda_redirect.dll')): + zluda_path = path + break + if zluda_path is None: + log.warning('Failed to automatically patch torch with ZLUDA. Could not find ZLUDA from PATH.') + return + venv_path = os.path.dirname(shutil.which('python')) + dlls_to_patch = { + 'cublas.dll': 'cublas64_11.dll', + 'cudnn.dll': 'cudnn64_8.dll', + 'cusparse.dll': 'cusparse64_11.dll', + 'nvrtc.dll': 'nvrtc64_112_0.dll', + } + try: + for k, v in dlls_to_patch.items(): + shutil.copyfile(os.path.join(zluda_path, k), os.path.join(venv_path, 'Lib', 'site-packages', 'torch', 'lib', v)) + except Exception as e: + log.warning(f'Failed to automatically patch torch with ZLUDA: {e}') + + # check version of the main repo and optionally upgrade it def check_version(offline=False, reset=True): # pylint: disable=unused-argument if args.skip_all: diff --git a/modules/cmd_args.py b/modules/cmd_args.py index 49025613c..dcec93c87 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -41,6 +41,7 @@ group.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), act group.add_argument("--disable-queue", default=os.environ.get("SD_DISABLEQUEUE", False), action='store_true', help="Disable queues, default: %(default)s") group.add_argument('--debug', default=os.environ.get("SD_DEBUG", False), action='store_true', help = "Run installer with debug logging, default: %(default)s") group.add_argument('--use-directml', default=os.environ.get("SD_USEDIRECTML", False), action='store_true', help = "Use DirectML if no compatible GPU is detected, default: %(default)s") +group.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s") group.add_argument("--use-openvino", default=os.environ.get("SD_USEOPENVINO", False), action='store_true', help="Use Intel OpenVINO backend, default: %(default)s") group.add_argument("--use-ipex", default=os.environ.get("SD_USEIPX", False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s") group.add_argument("--use-cuda", default=os.environ.get("SD_USECUDA", False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s") diff --git a/modules/shared.py b/modules/shared.py index 526d27731..f07c079b5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -407,9 +407,6 @@ options_templates.update(options_section(('cuda', "Compute Settings"), { "olive_vae_encoder_float32": OptionInfo(False, 'Olive force FP32 for VAE Encoder'), "olive_static_dims": OptionInfo(True, 'Olive use static dimensions'), "olive_cache_optimized": OptionInfo(True, 'Olive cache optimized models'), - - "zluda_sep": OptionInfo("

ZLUDA

(experimental)", "", gr.HTML, {"visible": devices.backend == "cuda"}), - "zluda_enable_cudnn": OptionInfo(False, 'ZLUDA enable cuDNN (restart required)', gr.Checkbox, {"visible": devices.backend == "cuda"}), })) options_templates.update(options_section(('advanced', "Inference Settings"), { diff --git a/modules/zluda.py b/modules/zluda.py index 795ea1f3e..6eb6f06bc 100644 --- a/modules/zluda.py +++ b/modules/zluda.py @@ -3,13 +3,29 @@ import torch from modules import shared, devices +def test(device: torch.device): + try: + ten1 = torch.randn((2, 4,), device=device) + ten2 = torch.randn((4, 8,), device=device) + out = torch.mm(ten1, ten2) + return out.sum().is_nonzero() + except Exception: + return False + + def initialize_zluda(): - if platform.system() == "Windows" and devices.cuda_ok and torch.cuda.get_device_name(devices.get_optimal_device()).endswith("[ZLUDA]"): - shared.log.warning("Detected ZLUDA device. Currently, ZLUDA support is experimental and unstable.") - torch.backends.cudnn.enabled = shared.opts.zluda_enable_cudnn - if torch.backends.cudnn.enabled: - shared.log.warning("cuDNN with ZLUDA won't work at this moment. Please wait for future update.") + device = devices.get_optimal_device() + if platform.system() == "Windows" and devices.cuda_ok and torch.cuda.get_device_name(device).endswith("[ZLUDA]"): + torch.backends.cudnn.enabled = False torch.backends.cuda.enable_flash_sdp(False) torch.backends.cuda.enable_math_sdp(True) torch.backends.cuda.enable_mem_efficient_sdp(False) shared.opts.sdp_options = ['Math attention'] + devices.device_codeformer = devices.cpu + + if not test(device): + shared.log.error(f'ZLUDA device failed to pass basic operation test: index={device.index}, device_name={torch.cuda.get_device_name(device)}') + torch.cuda.is_available = lambda: False + devices.cuda_ok = False + devices.backend = 'cpu' + devices.device = devices.device_esrgan = devices.device_gfpgan = devices.device_interrogate = devices.cpu From 74e67dfeea749d9a30816b2e6723c0ed33560c77 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 23 Feb 2024 10:02:53 -0500 Subject: [PATCH 02/44] cleanup --- installer.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/installer.py b/installer.py index b8c17f632..af97fc898 100644 --- a/installer.py +++ b/installer.py @@ -430,7 +430,7 @@ def check_torch(): xformers_package = os.environ.get('XFORMERS_PACKAGE', '--pre xformers' if opts.get('cross_attention_optimization', '') == 'xFormers' else 'none') install('onnxruntime-gpu', 'onnxruntime-gpu', ignore=True) elif is_rocm_available(): - is_windows = platform.system() == 'Windows' # provides more better logs for ZLUDA users and ROCm for Windows users in future. + is_windows = platform.system() == 'Windows' log.info('AMD ROCm toolkit detected') os.environ.setdefault('PYTORCH_HIP_ALLOC_CONF', 'garbage_collection_threshold:0.8,max_split_size_mb:512') if not is_windows: @@ -478,12 +478,13 @@ def check_torch(): except Exception as e: log.debug(f'ROCm hipconfig failed: {e}') rocm_ver = None - if args.use_zluda: # ZLUDA is available on both Linux and Windows + if args.use_zluda: torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.2.0 torchvision --index-url https://download.pytorch.org/whl/cu118') - log.warning("Currently, ZLUDA support is experimental and unstable.") + log.warning("ZLUDA support: experimental") zluda_need_dll_patch = is_windows and not installed('torch') - elif is_windows: # remove this check after PyTorch built with ROCm for Windows is released - log.warning("HIP SDK is detected, but there's no PyTorch release for Windows at this moment. If you are trying ZLUDA, please add '--use-zluda'.") + elif is_windows: # TODO TBD after ROCm for Windows is released + log.warning("HIP SDK is detected, but no Torch release for Windows available") + log.info("For ZLUDA support specify '--use-zluda'") log.info('Using CPU-only torch') torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') else: @@ -492,8 +493,7 @@ def check_torch(): elif rocm_ver in {"5.5", "5.6"}: torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}') else: - # ROCm 5.5 is oldest for PyTorch 2.1 - torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/rocm5.5') + torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/rocm5.5') # ROCm 5.5 is oldest for PyTorch 2.1 if rocm_ver is not None: install(os.environ.get('ONNXRUNTIME_PACKAGE', get_onnxruntime_source_for_rocm(arr)), "onnxruntime-training built with ROCm", ignore=True) xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none') @@ -549,14 +549,14 @@ def check_torch(): install('onnxruntime-directml', 'onnxruntime-directml', ignore=True) else: if args.use_zluda: - log.warning("Failed to initialize ZLUDA. There's no HIP SDK found in PATH.") + log.warning("ZLUDA failed to initialize: no HIP SDK found") log.info('Using CPU-only Torch') torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') if 'torch' in torch_command and not args.version: log.debug(f'Installing torch: {torch_command}') install(torch_command, 'torch torchvision') if zluda_need_dll_patch: - patch_dlls_for_zluda() + patch_zluda() else: try: import torch @@ -909,7 +909,7 @@ def get_onnxruntime_source_for_rocm(rocm_ver): return 'onnxruntime-gpu' -def patch_dlls_for_zluda(): +def patch_zluda(): zluda_path = os.environ.get('ZLUDA', None) if zluda_path is None: paths = os.environ.get('PATH', '').split(';') @@ -931,7 +931,7 @@ def patch_dlls_for_zluda(): for k, v in dlls_to_patch.items(): shutil.copyfile(os.path.join(zluda_path, k), os.path.join(venv_path, 'Lib', 'site-packages', 'torch', 'lib', v)) except Exception as e: - log.warning(f'Failed to automatically patch torch with ZLUDA: {e}') + log.warning(f'ZLUDA: failed to automatically patch torch: {e}') # check version of the main repo and optionally upgrade it From 3e4fe516fe8f098300ae292a03cc6b6985d64734 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 23 Feb 2024 11:00:02 -0500 Subject: [PATCH 03/44] update default theme and add black-gray --- javascript/black-gray.css | 300 ++++++++++++++++++++++++++++++++++++++ javascript/black-teal.css | 70 +++++---- 2 files changed, 333 insertions(+), 37 deletions(-) create mode 100644 javascript/black-gray.css diff --git a/javascript/black-gray.css b/javascript/black-gray.css new file mode 100644 index 000000000..03e07cb63 --- /dev/null +++ b/javascript/black-gray.css @@ -0,0 +1,300 @@ +/* generic html tags */ +@font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSans'), url('notosans-nerdfont-regular.ttf') } +:root, .light, .dark { + --font: 'NotoSans'; + --font-mono: 'ui-monospace', 'Consolas', monospace; + --font-size: 16px; + --primary-50: #f0f0f0; + --primary-100: #e0e0e0; + --primary-200: #d0d0d0; + --primary-300: #b0b0b0; + --primary-400: #909090; + --primary-500: #707070; + --primary-600: #606060; + --primary-700: #404040; + --primary-800: #303030; + --primary-900: #202020; + --primary-950: #101010; + --highlight-color: var(--primary-200); + --inactive-color: var(--primary--800); + --body-text-color: var(--primary-100); + --body-text-color-subdued: var(--primary-300); + --background-color: var(--primary-950); + --background-fill-primary: var(--primary-700); + --input-padding: 4px; + --input-background-fill: var(--primary-800); + --input-shadow: none; + --button-primary-background-fill: var(--primary-600); + --button-primary-background-fill-hover: var(--primary-800); + --button-secondary-background-fill: var(--neutral-600); + --button-secondary-background-fill-hover: var(--neutral-800); + --block-title-text-color: var(--neutral-300); + --radius-sm: 0; + --radius-lg: 0; + --line-xs: 0.5em; + --line-sm: 1.0em; + --line-md: 1.3em; + --line-lg: 1.5em; +} + +:root { scrollbar-color: var(--highlight-color) var(--primary-800); } +html { font-size: var(--font-size); font-family: var(--font); } +body, button, input, select, textarea { font-family: var(--font); } +button { max-width: 400px; white-space: nowrap; } +img { background-color: var(--background-color); } + +input[type=range] { height: var(--line-xs) !important; appearance: none !important; margin-top: 0 !important; min-width: max(4em, 100%) !important; width: 100% !important; background: transparent !important; } +input[type=range]::-webkit-slider-runnable-track { width: 100% !important; height: var(--line-xs) !important; cursor: pointer !important; background: var(--input-background-fill) !important; border: 0px solid var(--primary-900) !important; } +input[type=range]::-moz-range-track { width: 100% !important; height: var(--line-xs) !important; cursor: pointer !important; background: var(--input-background-fill) !important; border: 0px solid var(--primary-900) !important; } +input[type=range]::-webkit-slider-thumb { border: 0px solid var(--primary-950)0 !important; height: var(--line-sm) !important; width: var(--line-sm) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px; border-radius: 4px; } +input[type=range]::-moz-range-thumb { border: 0px solid var(--primary-950)0 !important; height: var(--line-sm) !important; width: var(--line-sm) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px; border-radius: 4px; } + +::-webkit-scrollbar { width: 12px; height: 12px; } +::-webkit-scrollbar-track { background: var(--primary-800); } +::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-width: 0; } +div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; } + +/* gradio style classes */ +fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; } +.border-2 { border-width: 0; } +.border-b-2 { border-bottom-width: 2px; border-color: var(--highlight-color) !important; padding-bottom: 2px; margin-bottom: 8px; } +.bg-white { color: lightyellow; background-color: var(--inactive-color); } +.gr-box { border-radius: var(--radius-sm) !important; background-color: var(--primary-950) !important; box-shadow: none; border-width: 0; padding: 4px; margin: 12px 0px 12px 0px } +.gr-button { font-weight: normal; box-shadow: none; font-size: 0.8rem; min-width: 32px; min-height: 32px; padding: 3px; margin: 3px; } +.gr-check-radio { background-color: var(--inactive-color); border-width: 0; border-radius: var(--radius-lg); box-shadow: none; } +.gr-check-radio:checked { background-color: var(--highlight-color); } +.gr-compact { background-color: var(--background-color); } +.gr-form { border-width: 0; } +.gr-input { background-color: var(--primary-300) !important; padding: 4px; margin: 4px; } +.gr-input-label { color: lightyellow; border-width: 0; background: transparent; padding: 2px !important; } +.gr-panel { background-color: var(--background-color); } +.eta-bar { display: none !important } +svg.feather.feather-image, .feather .feather-image { display: none } +.gap-2 { padding-top: 8px; } +.gr-box > div > div > input.gr-text-input { right: 0; width: 4em; padding: 0; top: -12px; border: none; max-height: 20px; } +.output-html { line-height: 1.2rem; overflow-x: hidden; } +.output-html > div { margin-bottom: 8px; } +.overflow-hidden .flex .flex-col .relative col .gap-4 { min-width: var(--left-column); max-width: var(--left-column); } /* this is a problematic one */ +.p-2 { padding: 0; } +.px-4 { padding-lefT: 1rem; padding-right: 1rem; } +.py-6 { padding-bottom: 0; } +.tabs { background-color: var(--background-color); } +.block.token-counter span { background-color: var(--input-background-fill) !important; border: none !important; font-size: 0.7rem; } +.tab-nav { zoom: 110%; margin-top: 10px; margin-bottom: 10px; border-bottom: 2px solid var(--highlight-color) !important; padding-bottom: 2px; } +.label-wrap { margin: 8px 0px 4px 0px; } +.gradio-button.tool { border: none; background: none; box-shadow: none; filter: hue-rotate(340deg) saturate(0.5); } +#tab_extensions table td, #tab_extensions table th, #tab_config table td, #tab_config table th { border: none; } +#tab_extensions table tr:hover, #tab_config table tr:hover { background-color: var(--neutral-500) !important; } +#tab_extensions table, #tab_config table { width: 96vw } +#tab_extensions table thead, #tab_config table thead { background-color: var(--neutral-700); } +#tab_extensions table, #tab_config table { background-color: var(--primary-900); } + +/* automatic style classes */ +.progressDiv { border-radius: var(--radius-sm) !important; position: fixed; top: 44px; right: 26px; max-width: 262px; height: 48px; z-index: 99; } +.progressDiv .progress { border-radius: var(--radius-lg) !important; background: var(--highlight-color); line-height: 3rem; height: 48px; } +.gallery-item { box-shadow: none !important; } +.performance { color: #888; } +.extra-networks { border-left: 2px solid var(--highlight-color) !important; padding-left: 4px; } +.image-buttons { gap: 10px !important; justify-content: center; } +.image-buttons > button { max-width: 160px; } +.tooltip { background: var(--primary-300); color: black; border: none; border-radius: var(--radius-lg) } +#system_row > button, #settings_row > button, #config_row > button { max-width: 10em; } + +/* gradio elements overrides */ +#div.gradio-container { overflow-x: hidden; } +#img2img_label_copy_to_img2img { font-weight: normal; } + +#txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt, #control_prompt, #control_neg_prompt { background-color: var(--background-color); box-shadow: none !important; } +#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea, #control_prompt > label > textarea, #control_neg_prompt > label > textarea { font-size: 1.0em; line-height: 1.4em; } +#txt2img_styles, #img2img_styles, #control_styles { padding: 0; } +#txt2img_styles_refresh, #img2img_styles_refresh, #control_styles_refresh { padding: 0; margin-top: 1em; } +#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: var(--primary-950); padding-top: 16px; } +#interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; } +#quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; } +#open_folder_extras, #footer, #style_pos_col, #style_neg_col, #roll_col, #extras_upscaler_2, #extras_upscaler_2_visibility, #txt2img_seed_resize_from_w, #txt2img_seed_resize_from_h { display: none; } +#save-animation { border-radius: var(--radius-sm) !important; margin-bottom: 16px; background-color: var(--primary-950); } +#script_list { padding: 4px; margin-top: 16px; margin-bottom: 8px; } +#settings > div.flex-wrap { width: 15em; } +#settings_search { margin-top: 1em; margin-left: 1em; } +#settings_search textarea { padding: 0.5em; height: 2.2em !important; } +#txt2img_cfg_scale { min-width: 200px; } +#txt2img_checkboxes, #img2img_checkboxes, #control_checkboxes { background-color: transparent; margin-bottom: 0.2em; } +textarea[rows="1"] { height: 33px !important; width: 99% !important; padding: 8px !important; } +#extras_upscale { margin-top: 10px } +#txt2img_progress_row > div { min-width: var(--left-column); max-width: var(--left-column); } +#txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: var(--primary-950); padding-top: 16px; } +#pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) } +#txt2img_styles_row, #img2img_styles_row, #control_styles_row { margin-top: -6px; } + +/* based on gradio built-in dark theme */ +:root, .light, .dark { + --body-background-fill: var(--background-color); + --color-accent-soft: var(--neutral-700); + --background-fill-secondary: none; + --border-color-accent: var(--background-color); + --border-color-primary: var(--background-color); + --link-text-color-active: var(--primary-500); + --link-text-color: var(--secondary-500); + --link-text-color-hover: var(--secondary-400); + --link-text-color-visited: var(--secondary-600); + --shadow-spread: 1px; + --block-background-fill: None; + --block-border-color: var(--border-color-primary); + --block_border_width: None; + --block-info-text-color: var(--body-text-color-subdued); + --block-label-background-fill: var(--background-fill-secondary); + --block-label-border-color: var(--border-color-primary); + --block_label_border_width: None; + --block-label-text-color: var(--neutral-200); + --block_shadow: None; + --block_title_background_fill: None; + --block_title_border_color: None; + --block_title_border_width: None; + --panel-background-fill: var(--background-fill-secondary); + --panel-border-color: var(--border-color-primary); + --panel_border_width: None; + --checkbox-background-color: var(--neutral-500); + --checkbox-background-color-focus: var(--checkbox-background-color); + --checkbox-background-color-hover: var(--checkbox-background-color); + --checkbox-background-color-selected: var(--primary-500); + --checkbox-border-color: transparent; + --checkbox-border-color-focus: var(--secondary-500); + --checkbox-border-color-hover: var(--neutral-600); + --checkbox-border-color-selected: var(--primary-600); + --checkbox-border-width: var(--input-border-width); + --checkbox-label-background-fill: None; + --checkbox-label-background-fill-hover: None; + --checkbox-label-background-fill-selected: var(--checkbox-label-background-fill); + --checkbox-label-border-color: var(--border-color-primary); + --checkbox-label-border-color-hover: var(--checkbox-label-border-color); + --checkbox-label-border-width: var(--input-border-width); + --checkbox-label-text-color: var(--body-text-color); + --checkbox-label-text-color-selected: var(--checkbox-label-text-color); + --error-background-fill: var(--background-fill-primary); + --error-border-color: var(--border-color-primary); + --error_border_width: None; + --error-text-color: #ef4444; + --input-background-fill-focus: var(--secondary-600); + --input-background-fill-hover: var(--input-background-fill); + --input-border-color: var(--border-color-primary); + --input-border-color-focus: var(--neutral-700); + --input-border-color-hover: var(--input-border-color); + --input_border_width: None; + --input-placeholder-color: var(--neutral-500); + --input-shadow-focus: none; + --loader_color: None; + --slider_color: None; + --stat-background-fill: var(--primary-500); + --table-border-color: var(--neutral-700); + --table-even-background-fill: var(--primary-900); + --table-odd-background-fill: #303030; + --table-row-focus: var(--color-accent-soft); + --button-border-width: var(--input-border-width); + --button-cancel-background-fill: #b91c1c; + --button-cancel-background-fill-hover: #dc2626; + --button-cancel-border-color: #dc2626; + --button-cancel-border-color-hover: var(--button-cancel-border-color); + --button-cancel-text-color: var(--primary-100); + --button-cancel-text-color-hover: var(--button-cancel-text-color); + --button-primary-border-color: var(--primary-500); + --button-primary-border-color-hover: var(--button-primary-border-color); + --button-primary-text-color: var(--primary-100); + --button-primary-text-color-hover: var(--button-primary-text-color); + --button-secondary-border-color: var(--neutral-600); + --button-secondary-border-color-hover: var(--button-secondary-border-color); + --button-secondary-text-color-hover: var(--button-secondary-text-color); + --secondary-50: #eff6ff; + --secondary-100: #dbeafe; + --secondary-200: #bfdbfe; + --secondary-300: #93c5fd; + --secondary-400: #60a5fa; + --secondary-500: #3b82f6; + --secondary-600: #2563eb; + --secondary-700: #1d4ed8; + --secondary-800: #1e40af; + --secondary-900: #1e3a8a; + --secondary-950: #1d3660; + --neutral-50: #f0f0f0; + --neutral-100: #e0e0e0; + --neutral-200: #d0d0d0; + --neutral-300: #b0b0b0; + --neutral-400: #909090; + --neutral-500: #707070; + --neutral-600: #606060; + --neutral-700: #404040; + --neutral-800: #303030; + --neutral-900: #111827; + --neutral-950: #0b0f19; + --radius-xxs: 0; + --radius-xs: 0; + --radius-md: 0; + --radius-xl: 0; + --radius-xxl: 0; + --body-text-size: var(--text-md); + --body-text-weight: 400; + --embed-radius: var(--radius-lg); + --color-accent: var(--primary-500); + --shadow-drop: 0; + --shadow-drop-lg: 0; + --shadow-inset: rgba(0,0,0,0.05) 0px 2px 4px 0px inset; + --block-border-width: 1px; + --block-info-text-size: var(--text-sm); + --block-info-text-weight: 400; + --block-label-border-width: 1px; + --block-label-margin: 0; + --block-label-padding: var(--spacing-sm) var(--spacing-lg); + --block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0; + --block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px); + --block-label-text-size: var(--text-sm); + --block-label-text-weight: 400; + --block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px); + --block-radius: var(--radius-lg); + --block-shadow: var(--shadow-drop); + --block-title-background-fill: none; + --block-title-border-color: none; + --block-title-border-width: 0px; + --block-title-padding: 0; + --block-title-radius: none; + --block-title-text-size: var(--text-md); + --block-title-text-weight: 400; + --container-radius: var(--radius-lg); + --form-gap-width: 1px; + --layout-gap: var(--spacing-xxl); + --panel-border-width: 0; + --section-header-text-size: var(--text-md); + --section-header-text-weight: 400; + --checkbox-border-radius: var(--radius-sm); + --checkbox-label-gap: 2px; + --checkbox-label-padding: var(--spacing-md); + --checkbox-label-shadow: var(--shadow-drop); + --checkbox-label-text-size: var(--text-md); + --checkbox-label-text-weight: 400; + --checkbox-check: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); + --radio-circle: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); + --checkbox-shadow: var(--input-shadow); + --error-border-width: 1px; + --input-border-width: 0; + --input-radius: var(--radius-lg); + --input-text-size: var(--text-md); + --input-text-weight: 400; + --loader-color: var(--color-accent); + --prose-text-size: var(--text-md); + --prose-text-weight: 400; + --prose-header-text-weight: 400; + --slider-color: ; + --table-radius: var(--radius-lg); + --button-large-padding: 2px 6px; + --button-large-radius: var(--radius-lg); + --button-large-text-size: var(--text-lg); + --button-large-text-weight: 400; + --button-shadow: none; + --button-shadow-active: none; + --button-shadow-hover: none; + --button-small-padding: var(--spacing-sm) calc(2 * var(--spacing-sm)); + --button-small-radius: var(--radius-lg); + --button-small-text-size: var(--text-md); + --button-small-text-weight: 400; + --button-transition: none; + --size-9: 64px; + --size-14: 64px; +} diff --git a/javascript/black-teal.css b/javascript/black-teal.css index 13c65bc73..d1745666a 100644 --- a/javascript/black-teal.css +++ b/javascript/black-teal.css @@ -15,21 +15,37 @@ --primary-800: #2b5656; --primary-900: #224444; --primary-950: #193232; + --neutral-50: #f0f0f0; + --neutral-100: #e0e0e0; + --neutral-200: #d0d0d0; + --neutral-300: #b0b0b0; + --neutral-400: #909090; + --neutral-500: #707070; + --neutral-600: #606060; + --neutral-700: #404040; + --neutral-800: #303030; + --neutral-900: #202020; + --neutral-950: #101010; --highlight-color: var(--primary-200); --inactive-color: var(--primary--800); --body-text-color: var(--neutral-100); --body-text-color-subdued: var(--neutral-300); - --background-color: #000000; + --background-color: #050505; --background-fill-primary: var(--neutral-700); --input-padding: 4px; --input-background-fill: var(--neutral-800); --input-shadow: none; - --button-secondary-text-color: white; + --button-secondary-text-color: var(--neutral-100); --button-secondary-background-fill: linear-gradient(to bottom right, var(--neutral-400), var(--neutral-700)); --button-secondary-background-fill-hover: linear-gradient(to bottom right, var(--neutral-700), var(--neutral-400)); --block-title-text-color: var(--neutral-300); + --radius-xxs: 0; + --radius-xs: 1; --radius-sm: 2px; + --radius-md: 3; --radius-lg: 4px; + --radius-xl: 5; + --radius-xxl: 6; --line-xs: 1.0em; --line-sm: 1.2em; --line-md: 1.4em; @@ -40,20 +56,15 @@ html { font-size: var(--font-size); font-family: var(--font); } body, button, input, select, textarea { font-family: var(--font); } button { max-width: 400px; white-space: nowrap; } img { background-color: var(--background-color); } -input[type=range] { height: var(--line-xs) !important; appearance: none !important; margin-top: 0 !important; min-width: max(4em, 100%) !important; - background-color: var(--background-color) !important; width: 100% !important; background: transparent !important; } -input[type=range]::-webkit-slider-runnable-track { width: 100% !important; height: var(--line-xs) !important; cursor: pointer !important; box-shadow: 2px 2px 3px #111111 !important; - background: var(--input-background-fill) !important; border-radius: var(--radius-lg) !important; border: 0px solid #222222 !important; } -input[type=range]::-moz-range-track { width: 100% !important; height: var(--line-xs) !important; cursor: pointer !important; box-shadow: 2px 2px 3px #111111 !important; background: - var(--input-background-fill) !important; border-radius: var(--radius-lg) !important; border: 0px solid #222222 !important; } -input[type=range]::-webkit-slider-thumb { box-shadow: 2px 2px 3px #111111 !important; border: 0px solid #000000 !important; height: var(--line-xs) !important; width: var(--line-md) !important; - border-radius: var(--radius-lg) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: 0px !important; } -input[type=range]::-moz-range-thumb { box-shadow: 2px 2px 3px #111111 !important; border: 0px solid #000000 !important; height: var(--line-xs) !important; width: var(--line-md) !important; - border-radius: var(--radius-lg) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: 0px !important; } +input[type=range] { height: var(--line-xs) !important; appearance: none !important; margin-top: 0 !important; min-width: max(4em, 100%) !important; background-color: var(--background-color) !important; width: 100% !important; background: transparent !important; } +input[type=range]::-webkit-slider-runnable-track { width: 100% !important; height: 6px !important; cursor: pointer !important; background: var(--input-background-fill) !important; border-radius: var(--radius-lg) !important; border: 0px solid var(--neutral-900) !important; } +input[type=range]::-moz-range-track { width: 100% !important; height: 6px !important; cursor: pointer !important; background: var(--input-background-fill) !important; border-radius: var(--radius-lg) !important; border: 0px solid var(--neutral-900) !important; } +input[type=range]::-webkit-slider-thumb { border: 0px solid #000000 !important; height: var(--line-xs) !important; width: var(--line-md) !important; border-radius: var(--radius-lg) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px !important; } +input[type=range]::-moz-range-thumb { border: 0px solid #000000 !important; height: var(--line-xs) !important; width: var(--line-md) !important; border-radius: var(--radius-lg) !important; background: var(--highlight-color) !important; cursor: pointer !important; appearance: none !important; margin-top: -4px !important; } :root { scrollbar-color: var(--highlight-color) #303030; } ::-webkit-scrollbar { width: 12px; height: 12px; } ::-webkit-scrollbar-track { background: #303030; } -::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px #111111; } +::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px var(--neutral-950); } div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; } /* gradio style classes */ @@ -61,7 +72,7 @@ fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; } .border-2 { border-width: 0; } .border-b-2 { border-bottom-width: 2px; border-color: var(--highlight-color) !important; padding-bottom: 2px; margin-bottom: 8px; } .bg-white { color: lightyellow; background-color: var(--inactive-color); } -.gr-box { border-radius: var(--radius-sm) !important; background-color: #111111 !important; box-shadow: none; border-width: 0; padding: 4px; margin: 12px 0px 12px 0px } +.gr-box { border-radius: var(--radius-sm) !important; background-color: var(--neutral-950) !important; box-shadow: none; border-width: 0; padding: 4px; margin: 12px 0px 12px 0px } .gr-button { font-weight: normal; box-shadow: none; font-size: 0.8rem; min-width: 32px; min-height: 32px; padding: 3px; margin: 3px; } .gr-check-radio { background-color: var(--inactive-color); border-width: 0; border-radius: var(--radius-lg); box-shadow: none; } .gr-check-radio:checked { background-color: var(--highlight-color); } @@ -71,6 +82,7 @@ fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; } .gr-input-label { color: lightyellow; border-width: 0; background: transparent; padding: 2px !important; } .gr-panel { background-color: var(--background-color); } .eta-bar { display: none !important } +.gradio-slider input[type="number"] { background: var(--neutral-950); } svg.feather.feather-image, .feather .feather-image { display: none } .gap-2 { padding-top: 8px; } .gr-box > div > div > input.gr-text-input { right: 0; width: 4em; padding: 0; top: -12px; border: none; max-height: 20px; } @@ -89,7 +101,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } #tab_extensions table tr:hover, #tab_config table tr:hover { background-color: var(--neutral-500) !important; } #tab_extensions table, #tab_config table { width: 96vw } #tab_extensions table thead, #tab_config table thead { background-color: var(--neutral-700); } -#tab_extensions table, #tab_config table { background-color: #222222; } +#tab_extensions table, #tab_config table { background-color: var(--neutral-900); } /* automatic style classes */ .progressDiv { border-radius: var(--radius-sm) !important; position: fixed; top: 44px; right: 26px; max-width: 262px; height: 48px; z-index: 99; box-shadow: var(--button-shadow); } @@ -110,11 +122,11 @@ svg.feather.feather-image, .feather .feather-image { display: none } #txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea, #control_prompt > label > textarea, #control_neg_prompt > label > textarea { font-size: 1.0em; line-height: 1.4em; } #txt2img_styles, #img2img_styles, #control_styles { padding: 0; } #txt2img_styles_refresh, #img2img_styles_refresh, #control_styles_refresh { padding: 0; margin-top: 1em; } -#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: #111111; padding-top: 16px; } +#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: var(--neutral-950); padding-top: 16px; } #interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; } #quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; } #open_folder_extras, #footer, #style_pos_col, #style_neg_col, #roll_col, #extras_upscaler_2, #extras_upscaler_2_visibility, #txt2img_seed_resize_from_w, #txt2img_seed_resize_from_h { display: none; } -#save-animation { border-radius: var(--radius-sm) !important; margin-bottom: 16px; background-color: #111111; } +#save-animation { border-radius: var(--radius-sm) !important; margin-bottom: 16px; background-color: var(--neutral-950); } #script_list { padding: 4px; margin-top: 16px; margin-bottom: 8px; } #settings > div.flex-wrap { width: 15em; } #settings_search { margin-top: 1em; margin-left: 1em; } @@ -124,7 +136,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } textarea[rows="1"] { height: 33px !important; width: 99% !important; padding: 8px !important; } #extras_upscale { margin-top: 10px } #txt2img_progress_row > div { min-width: var(--left-column); max-width: var(--left-column); } -#txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: #111111; padding-top: 16px; } +#txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: var(--neutral-950); padding-top: 16px; } #pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) } #txt2img_styles_row, #img2img_styles_row, #control_styles_row { margin-top: -6px; } @@ -188,7 +200,7 @@ textarea[rows="1"] { height: 33px !important; width: 99% !important; padding: 8p --slider_color: None; --stat-background-fill: linear-gradient(to right, var(--primary-400), var(--primary-600)); --table-border-color: var(--neutral-700); - --table-even-background-fill: #222222; + --table-even-background-fill: var(--neutral-900); --table-odd-background-fill: #303030; --table-row-focus: var(--color-accent-soft); --button-border-width: var(--input-border-width); @@ -196,13 +208,13 @@ textarea[rows="1"] { height: 33px !important; width: 99% !important; padding: 8p --button-cancel-background-fill-hover: linear-gradient(to bottom right, #dc2626, #dc2626); --button-cancel-border-color: #dc2626; --button-cancel-border-color-hover: var(--button-cancel-border-color); - --button-cancel-text-color: white; + --button-cancel-text-color: var(--neutral-50); --button-cancel-text-color-hover: var(--button-cancel-text-color); --button-primary-background-fill: linear-gradient(to bottom right, var(--primary-500), var(--primary-800)); --button-primary-background-fill-hover: linear-gradient(to bottom right, var(--primary-500), var(--primary-300)); --button-primary-border-color: var(--primary-500); --button-primary-border-color-hover: var(--button-primary-border-color); - --button-primary-text-color: white; + --button-primary-text-color: var(--neutral-50); --button-primary-text-color-hover: var(--button-primary-text-color); --button-secondary-border-color: var(--neutral-600); --button-secondary-border-color-hover: var(--button-secondary-border-color); @@ -218,22 +230,6 @@ textarea[rows="1"] { height: 33px !important; width: 99% !important; padding: 8p --secondary-800: #1e40af; --secondary-900: #1e3a8a; --secondary-950: #1d3660; - --neutral-50: #f0f0f0; - --neutral-100: #e0e0e0; - --neutral-200: #d0d0d0; - --neutral-300: #b0b0b0; - --neutral-400: #909090; - --neutral-500: #707070; - --neutral-600: #606060; - --neutral-700: #404040; - --neutral-800: #303030; - --neutral-900: #111827; - --neutral-950: #0b0f19; - --radius-xxs: 0; - --radius-xs: 0; - --radius-md: 0; - --radius-xl: 0; - --radius-xxl: 0; --body-text-size: var(--text-md); --body-text-weight: 400; --embed-radius: var(--radius-lg); From 809ad267505b707c36d3ba5e185bfc0a2b403a3a Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 23 Feb 2024 12:09:53 -0500 Subject: [PATCH 04/44] minor updates --- javascript/black-teal.css | 18 ++++++++++-------- javascript/setHints.js | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/javascript/black-teal.css b/javascript/black-teal.css index d1745666a..8397453b8 100644 --- a/javascript/black-teal.css +++ b/javascript/black-teal.css @@ -4,7 +4,7 @@ --font: 'NotoSans'; --font-mono: 'ui-monospace', 'Consolas', monospace; --font-size: 16px; - --primary-50: #7dffff; + --primary-50: #7dffff; --primary-100: #72e8e8; --primary-200: #67d2d2; --primary-300: #5dbcbc; @@ -15,7 +15,7 @@ --primary-800: #2b5656; --primary-900: #224444; --primary-950: #193232; - --neutral-50: #f0f0f0; + --neutral-50: #f0f0f0; --neutral-100: #e0e0e0; --neutral-200: #d0d0d0; --neutral-300: #b0b0b0; @@ -30,14 +30,17 @@ --inactive-color: var(--primary--800); --body-text-color: var(--neutral-100); --body-text-color-subdued: var(--neutral-300); - --background-color: #050505; + --background-color: black; --background-fill-primary: var(--neutral-700); --input-padding: 4px; --input-background-fill: var(--neutral-800); --input-shadow: none; + --button-primary-text-color: var(--neutral-100); + --button-primary-background-fill: var(--primary-600); + --button-primary-background-fill-hover: var(--primary-800); --button-secondary-text-color: var(--neutral-100); - --button-secondary-background-fill: linear-gradient(to bottom right, var(--neutral-400), var(--neutral-700)); - --button-secondary-background-fill-hover: linear-gradient(to bottom right, var(--neutral-700), var(--neutral-400)); + --button-secondary-background-fill: var(--neutral-600); + --button-secondary-background-fill-hover: var(--neutral-800); --block-title-text-color: var(--neutral-300); --radius-xxs: 0; --radius-xs: 1; @@ -67,6 +70,8 @@ input[type=range]::-moz-range-thumb { border: 0px solid #000000 !important; ::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px var(--neutral-950); } div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; } +.button-icon { font-size: 1.5em !important; margin: 0 !important; padding: 0 !important; height: 1.7em !important; min-height: unset !important; } + /* gradio style classes */ fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; } .border-2 { border-width: 0; } @@ -210,11 +215,8 @@ textarea[rows="1"] { height: 33px !important; width: 99% !important; padding: 8p --button-cancel-border-color-hover: var(--button-cancel-border-color); --button-cancel-text-color: var(--neutral-50); --button-cancel-text-color-hover: var(--button-cancel-text-color); - --button-primary-background-fill: linear-gradient(to bottom right, var(--primary-500), var(--primary-800)); - --button-primary-background-fill-hover: linear-gradient(to bottom right, var(--primary-500), var(--primary-300)); --button-primary-border-color: var(--primary-500); --button-primary-border-color-hover: var(--button-primary-border-color); - --button-primary-text-color: var(--neutral-50); --button-primary-text-color-hover: var(--button-primary-text-color); --button-secondary-border-color: var(--neutral-600); --button-secondary-border-color-hover: var(--button-secondary-border-color); diff --git a/javascript/setHints.js b/javascript/setHints.js index e7bbe0d7b..66720056b 100644 --- a/javascript/setHints.js +++ b/javascript/setHints.js @@ -41,6 +41,25 @@ async function validateHints(elements, data) { log('in locale but not ui:', missingUI); } +async function replaceButtonText(el) { + // https://www.nerdfonts.com/cheat-sheet + // use unicode of icon with format nf-md-_circle + const textIcons = { + Generate: '\uf144', + Enqueue: '\udb81\udc17', + Stop: '\udb81\ude66', + Skip: '\udb81\ude61', + Pause: '\udb80\udfe5', + Restore: '\udb82\udd9b', + Clear: '\udb80\udd59', + Networks: '\uf261', + }; + if (textIcons[el.innerText]) { + el.classList.add('button-icon'); + el.innerText = textIcons[el.innerText]; + } +} + async function setHints() { if (localeData.finished) return; if (localeData.data.length === 0) { @@ -66,6 +85,7 @@ async function setHints() { localized++; el.textContent = found.localized; } + // replaceButtonText(el); if (found?.hint?.length > 0) { hints++; if (localeData.type === 1) { From 1250d488fe14e8596eb3f178b71eb2f9cb814bf9 Mon Sep 17 00:00:00 2001 From: Seunghoon Lee Date: Sat, 24 Feb 2024 13:35:22 +0900 Subject: [PATCH 05/44] fix installer for zluda --- installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/installer.py b/installer.py index af97fc898..1d1c22f18 100644 --- a/installer.py +++ b/installer.py @@ -920,7 +920,7 @@ def patch_zluda(): if zluda_path is None: log.warning('Failed to automatically patch torch with ZLUDA. Could not find ZLUDA from PATH.') return - venv_path = os.path.dirname(shutil.which('python')) + venv_dir = os.environ.get('VENV_DIR', os.path.dirname(shutil.which('python'))) dlls_to_patch = { 'cublas.dll': 'cublas64_11.dll', 'cudnn.dll': 'cudnn64_8.dll', @@ -929,7 +929,7 @@ def patch_zluda(): } try: for k, v in dlls_to_patch.items(): - shutil.copyfile(os.path.join(zluda_path, k), os.path.join(venv_path, 'Lib', 'site-packages', 'torch', 'lib', v)) + shutil.copyfile(os.path.join(zluda_path, k), os.path.join(venv_dir, 'Lib', 'site-packages', 'torch', 'lib', v)) except Exception as e: log.warning(f'ZLUDA: failed to automatically patch torch: {e}') From 1759f69637089ab75d6855672fc403be45721d18 Mon Sep 17 00:00:00 2001 From: Seunghoon Lee Date: Sat, 24 Feb 2024 15:54:08 +0900 Subject: [PATCH 06/44] fix zluda --- installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer.py b/installer.py index 1d1c22f18..1ee471bd3 100644 --- a/installer.py +++ b/installer.py @@ -923,7 +923,7 @@ def patch_zluda(): venv_dir = os.environ.get('VENV_DIR', os.path.dirname(shutil.which('python'))) dlls_to_patch = { 'cublas.dll': 'cublas64_11.dll', - 'cudnn.dll': 'cudnn64_8.dll', + #'cudnn.dll': 'cudnn64_8.dll', 'cusparse.dll': 'cusparse64_11.dll', 'nvrtc.dll': 'nvrtc64_112_0.dll', } From 45b2b3d3483b64a5f2cb419fca411cec64fd34e0 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 07:42:45 -0500 Subject: [PATCH 07/44] fix en refresh --- modules/ui_extra_networks.py | 13 +------------ wiki | 2 +- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 9dabf5565..25f75c9f9 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -251,10 +251,7 @@ class ExtraNetworksPage: htmls.append(self.create_html(item, tabname)) self.html += ''.join(htmls) self.page_time = time.time() - if len(subdirs_html) > 0 or len(self.html) > 0: - self.html = f"
{subdirs_html}
{self.html}
" - else: - return '' + self.html = f"
{subdirs_html}
{self.html}
" shared.log.debug(f"Extra networks: page='{self.name}' items={len(self.items)} subfolders={len(subdirs)} tab={tabname} folders={self.allowed_directories_for_previews()} list={self.list_time:.2f} thumb={self.preview_time:.2f} desc={self.desc_time:.2f} info={self.info_time:.2f} workers={shared.max_workers}") if len(self.missing_thumbs) > 0: threading.Thread(target=self.create_thumb).start() @@ -585,8 +582,6 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): executor.submit(page.create_items, ui.tabname) for page in get_pages(): page.create_page(ui.tabname, skip_indexing) - if len(page.items) == 0: - continue with gr.Tab(page.title, id=page.title.lower().replace(" ", "_"), elem_classes="extra-networks-tab") as tab: page_html = gr.HTML(page.html, elem_id=f'{tabname}{page.name}_extra_page', elem_classes="extra-networks-page") ui.pages.append(page_html) @@ -821,12 +816,6 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): "prompt": prompt, "negative": params.get('Negative prompt', ''), "extra": '', - # "type": 'Style', - # "title": name, - # "filename": fn, - # "search_term": None, - # "preview": None, - # "local_preview": None, } shared.writefile(item, fn, silent=True) if len(prompt) > 0: diff --git a/wiki b/wiki index 9c62124db..ddd8158ac 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 9c62124dbe7521162a22b297481aadfae1deeb01 +Subproject commit ddd8158ac1b86cfaba1b5fa9929bb5214775bb9f From 149c881184cb40c1a979521ce6116aded5210101 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 08:23:08 -0500 Subject: [PATCH 08/44] update changelog --- CHANGELOG.md | 9 +++++++++ javascript/black-teal.css | 4 ++-- javascript/sdnext.css | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5f0a907b..163647ad4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log for SD.Next +## Update for 2024-02-24 + +- **Improvements** + - default theme updates + - additional built-in theme *black-gray* +- **Fixes** + - fix extra networks refresh + - improve ZLUDA installer when using `--use-zluda` cli param, thanks @lshqqytiger + ## Update for 2024-02-22 Only 3 weeks since last release, but here's another feature-packed one! diff --git a/javascript/black-teal.css b/javascript/black-teal.css index 8397453b8..34250a660 100644 --- a/javascript/black-teal.css +++ b/javascript/black-teal.css @@ -87,7 +87,7 @@ fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; } .gr-input-label { color: lightyellow; border-width: 0; background: transparent; padding: 2px !important; } .gr-panel { background-color: var(--background-color); } .eta-bar { display: none !important } -.gradio-slider input[type="number"] { background: var(--neutral-950); } +.gradio-slider input[type="number"] { background: var(--neutral-950); margin-top: 2px; } svg.feather.feather-image, .feather .feather-image { display: none } .gap-2 { padding-top: 8px; } .gr-box > div > div > input.gr-text-input { right: 0; width: 4em; padding: 0; top: -12px; border: none; max-height: 20px; } @@ -125,7 +125,7 @@ svg.feather.feather-image, .feather .feather-image { display: none } #txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt, #control_prompt, #control_neg_prompt { background-color: var(--background-color); box-shadow: none !important; } #txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea, #control_prompt > label > textarea, #control_neg_prompt > label > textarea { font-size: 1.0em; line-height: 1.4em; } -#txt2img_styles, #img2img_styles, #control_styles { padding: 0; } +#txt2img_styles, #img2img_styles, #control_styles { padding: 0; margin-top: 2px; } #txt2img_styles_refresh, #img2img_styles_refresh, #control_styles_refresh { padding: 0; margin-top: 1em; } #img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: var(--neutral-950); padding-top: 16px; } #interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; } diff --git a/javascript/sdnext.css b/javascript/sdnext.css index a2af3a78a..597c6b7cc 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -83,7 +83,7 @@ button.custom-button{ border-radius: var(--button-large-radius); padding: var(-- #txt2img_footer, #img2img_footer, #control_footer { height: fit-content; display: none; } #txt2img_generate_box, #img2img_generate_box, #control_general_box { gap: 0.5em; flex-wrap: wrap-reverse; height: fit-content; } #txt2img_actions_column, #img2img_actions_column, #control_actions_column { gap: 0.3em; height: fit-content; } -#txt2img_generate_box>button, #img2img_generate_box>button, #control_generate_box>button, #txt2img_enqueue, #img2img_enqueue { min-height: 44px; max-height: 44px; line-height: 1em; } +#txt2img_generate_box>button, #img2img_generate_box>button, #control_generate_box>button, #txt2img_enqueue, #img2img_enqueue { min-height: 44px !important; max-height: 44px !important; line-height: 1em; } #txt2img_generate_line2, #img2img_generate_line2, #txt2img_tools, #img2img_tools, #control_generate_line2, #control_tools { display: flex; } #txt2img_generate_line2>button, #img2img_generate_line2>button, #extras_generate_box>button, #control_generate_line2>button, #txt2img_tools>button, #img2img_tools>button, #control_tools>button { height: 2em; line-height: 0; font-size: var(--text-md); min-width: unset; display: block !important; } From 88d513d89e864d0e330f69c36ce05d820cbd2ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enes=20Sad=C4=B1k=20=C3=96zbek?= Date: Fri, 23 Feb 2024 23:01:43 +0300 Subject: [PATCH 09/44] add lora support to faceid --- modules/face/faceid.py | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 7dd2396c7..e9213a126 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -6,7 +6,7 @@ import numpy as np import diffusers import huggingface_hub as hf from PIL import Image -from modules import processing, shared, devices +from modules import processing, shared, devices, extra_networks FACEID_MODELS = { @@ -165,16 +165,33 @@ def face_id( ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder # run generate faceid_model.set_scale(scale) - for i in range(p.n_iter): - ip_model_dict.update({ - "prompt": p.all_prompts[i], - "negative_prompt": p.all_negative_prompts[i], - "seed": int(p.all_seeds[i]), - }) - debug(f"FaceID: {ip_model_dict}") - res = faceid_model.generate(**ip_model_dict) - if isinstance(res, list): - processed_images += res + + with devices.inference_context(): + with devices.autocast(): + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + + extra_network_data = None + + for i in range(p.n_iter): + p.iteration = i + p.prompts = p.all_prompts[i * p.batch_size:(i + 1) * p.batch_size] + p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size] + p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts) + p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size] + + if not p.disable_extra_networks: + with devices.autocast(): + extra_networks.activate(p, extra_network_data) + + ip_model_dict.update({ + "prompt": p.prompts, + "negative_prompt": p.negative_prompts, + "seed": int(p.seeds[0]), + }) + debug(f"FaceID: {ip_model_dict}") + res = faceid_model.generate(**ip_model_dict) + if isinstance(res, list): + processed_images += res faceid_model.set_scale(0) if not cache: From fe2d0589b032b60e2b83e05c8ed60675348bb127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enes=20Sad=C4=B1k=20=C3=96zbek?= Date: Sat, 24 Feb 2024 00:02:12 +0300 Subject: [PATCH 10/44] FaceID: Fix not deactivating extra networks after generation --- modules/face/faceid.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/face/faceid.py b/modules/face/faceid.py index e9213a126..54a84731e 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -192,6 +192,10 @@ def face_id( res = faceid_model.generate(**ip_model_dict) if isinstance(res, list): processed_images += res + + if not p.disable_extra_networks: + extra_networks.deactivate(p, extra_network_data) + faceid_model.set_scale(0) if not cache: From 601317f81b0429bff4d8877c1fd83661014d2d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enes=20Sad=C4=B1k=20=C3=96zbek?= Date: Sat, 24 Feb 2024 01:54:26 +0300 Subject: [PATCH 11/44] Finish FaceID integration with other stuff --- modules/face/faceid.py | 341 ++++++++++++++++++++++++----------------- 1 file changed, 197 insertions(+), 144 deletions(-) diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 54a84731e..9cc2cc765 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -6,8 +6,8 @@ import numpy as np import diffusers import huggingface_hub as hf from PIL import Image -from modules import processing, shared, devices, extra_networks - +from modules import processing, shared, devices, extra_networks, sd_models, sd_hijack_freeu, script_callbacks, ipadapter +from modules.sd_hijack_hypertile import context_hypertile_vae, context_hypertile_unet FACEID_MODELS = { "FaceID Base": "h94/IP-Adapter-FaceID/ip-adapter-faceid_sd15.bin", @@ -18,11 +18,18 @@ FACEID_MODELS = { # "FaceID Portrait v11": "h94/IP-Adapter-FaceID/ip-adapter-faceid-portrait-v11_sd15.bin", # "FaceID XL Plus v2": "h94/IP-Adapter-FaceID/ip-adapter-faceid_sdxl.bin", } -faceid_model = None + +faceid_model_weights = None faceid_model_name = None debug = shared.log.trace if os.environ.get("SD_FACE_DEBUG", None) is not None else lambda *args, **kwargs: None +def hijack_load_ip_adapter(self): + self.image_proj_model.load_state_dict(faceid_model_weights["image_proj"]) + ip_layers = torch.nn.ModuleList(self.pipe.unet.attn_processors.values()) + ip_layers.load_state_dict(faceid_model_weights["ip_adapter"], strict=False) + + def face_id( p: processing.StableDiffusionProcessing, app, @@ -33,7 +40,7 @@ def face_id( scale: float, structure: float, ): - global faceid_model, faceid_model_name # pylint: disable=global-statement + global faceid_model_weights, faceid_model_name # pylint: disable=global-statement if source_images is None or len(source_images) == 0: shared.log.warning('FaceID: no input images') return None @@ -53,155 +60,201 @@ def face_id( shared.log.error(f"FaceID incorrect version of ip_adapter: {e}") return None - ip_ckpt = FACEID_MODELS[model] - folder, filename = os.path.split(ip_ckpt) - basename, _ext = os.path.splitext(filename) - model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.diffusers_dir) - if model_path is None: - shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}") - return None - if override: - shared.sd_model.scheduler = diffusers.DDIMScheduler( - num_train_timesteps=1000, - beta_start=0.00085, - beta_end=0.012, - beta_schedule="scaled_linear", - clip_sample=False, - set_alpha_to_one=False, - steps_offset=1, - ) - shortcut = None - if faceid_model is None or faceid_model_name != model or not cache: - shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}") - if "XL Plus" in model: - image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" - faceid_model = IPAdapterFaceIDPlusXL( - sd_pipe=shared.sd_model, - image_encoder_path=image_encoder_path, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) - elif "XL" in model: - faceid_model = IPAdapterFaceIDXL( - sd_pipe=shared.sd_model, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) - elif "Plus" in model: - image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" - faceid_model = IPAdapterFaceIDPlus( - sd_pipe=shared.sd_model, - image_encoder_path=image_encoder_path, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) - elif "Portrait" in model: - faceid_model = IPAdapterFaceIDPortrait( - sd_pipe=shared.sd_model, - ip_ckpt=model_path, - num_tokens=16, - n_cond=5, - device=devices.device, - torch_dtype=devices.dtype, - ) - else: - faceid_model = IPAdapterFaceID( - sd_pipe=shared.sd_model, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) - shortcut = "v2" in model - faceid_model_name = model - else: - shared.log.debug(f"FaceID cached: model={model} file={ip_ckpt}") - processed_images = [] - face_embeds = [] - face_images = [] - for i, source_image in enumerate(source_images): - np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR) - faces = app.get(np_image) - if len(faces) == 0: - shared.log.error("FaceID: no faces found") - break - face_embeds.append(torch.from_numpy(faces[0].normed_embedding).unsqueeze(0)) - face_images.append(face_align.norm_crop(np_image, landmark=faces[0].kps, image_size=224)) - shared.log.debug(f'FaceID face: i={i+1} score={faces[0].det_score:.2f} gender={"female" if faces[0].gender==0 else "male"} age={faces[0].age} bbox={faces[0].bbox}') - p.extra_generation_params[f"FaceID {i+1}"] = f'{faces[0].det_score:.2f} {"female" if faces[0].gender==0 else "male"} {faces[0].age}y' - if len(face_embeds) == 0: - shared.log.error("FaceID: no faces found") - return None - face_embeds = torch.cat(face_embeds, dim=0) - ip_model_dict = { # main generate dict - "num_samples": p.batch_size, - "width": p.width, - "height": p.height, - "num_inference_steps": p.steps, - "scale": scale, - "guidance_scale": p.cfg_scale, - "faceid_embeds": face_embeds.shape, # placeholder - } - # optional generate dict - if shortcut is not None: - ip_model_dict["shortcut"] = shortcut - if "Plus" in model: - ip_model_dict["s_scale"] = structure - shared.log.debug(f"FaceID args: {ip_model_dict}") - if "Plus" in model: - ip_model_dict["face_image"] = face_images - ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder - # run generate - faceid_model.set_scale(scale) + faceid_model = None + original_load_ip_adapter = None - with devices.inference_context(): - with devices.autocast(): - p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + try: + shared.prompt_styles.apply_styles_to_extra(p) + if not shared.opts.cuda_compile: + sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio()) + sd_hijack_freeu.apply_freeu(p, shared.backend == shared.Backend.ORIGINAL) - extra_network_data = None + script_callbacks.before_process_callback(p) - for i in range(p.n_iter): - p.iteration = i - p.prompts = p.all_prompts[i * p.batch_size:(i + 1) * p.batch_size] - p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size] - p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts) - p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size] + with context_hypertile_vae(p), context_hypertile_unet(p): + with devices.inference_context(): + + with devices.autocast(): + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + + ip_ckpt = FACEID_MODELS[model] + folder, filename = os.path.split(ip_ckpt) + basename, _ext = os.path.splitext(filename) + model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.diffusers_dir) + + if model_path is None: + shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}") + return None + if override: + shared.sd_model.scheduler = diffusers.DDIMScheduler( + num_train_timesteps=1000, + beta_start=0.00085, + beta_end=0.012, + beta_schedule="scaled_linear", + clip_sample=False, + set_alpha_to_one=False, + steps_offset=1, + ) + + if faceid_model_weights is None or faceid_model_name != model or not cache: + shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}") + faceid_model_weights = torch.load(model_path, map_location="cpu") + else: + shared.log.debug(f"FaceID cached: model={model} file={ip_ckpt}") + + if "XL Plus" in model: + image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" + original_load_ip_adapter = IPAdapterFaceIDPlusXL.load_ip_adapter + IPAdapterFaceIDPlusXL.load_ip_adapter = hijack_load_ip_adapter + + faceid_model = IPAdapterFaceIDPlusXL( + sd_pipe=shared.sd_model, + image_encoder_path=image_encoder_path, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) + elif "XL" in model: + original_load_ip_adapter = IPAdapterFaceIDXL.load_ip_adapter + IPAdapterFaceIDXL.load_ip_adapter = hijack_load_ip_adapter + + faceid_model = IPAdapterFaceIDXL( + sd_pipe=shared.sd_model, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) + elif "Plus" in model: + original_load_ip_adapter = IPAdapterFaceIDPlus.load_ip_adapter + IPAdapterFaceIDPlus.load_ip_adapter = hijack_load_ip_adapter + + image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" + faceid_model = IPAdapterFaceIDPlus( + sd_pipe=shared.sd_model, + image_encoder_path=image_encoder_path, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) + elif "Portrait" in model: + original_load_ip_adapter = IPAdapterFaceIDPortrait.load_ip_adapter + IPAdapterFaceIDPortrait.load_ip_adapter = hijack_load_ip_adapter + + faceid_model = IPAdapterFaceIDPortrait( + sd_pipe=shared.sd_model, + ip_ckpt=model_path, + num_tokens=16, + n_cond=5, + device=devices.device, + torch_dtype=devices.dtype, + ) + else: + original_load_ip_adapter = IPAdapterFaceID.load_ip_adapter + IPAdapterFaceID.load_ip_adapter = hijack_load_ip_adapter + + faceid_model = IPAdapterFaceID( + sd_pipe=shared.sd_model, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) + + shortcut = "v2" in model + faceid_model_name = model + + face_embeds = [] + face_images = [] + for i, source_image in enumerate(source_images): + np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR) + faces = app.get(np_image) + if len(faces) == 0: + shared.log.error("FaceID: no faces found") + break + face_embeds.append(torch.from_numpy(faces[0].normed_embedding).unsqueeze(0)) + face_images.append(face_align.norm_crop(np_image, landmark=faces[0].kps, image_size=224)) + shared.log.debug(f'FaceID face: i={i+1} score={faces[0].det_score:.2f} gender={"female" if faces[0].gender==0 else "male"} age={faces[0].age} bbox={faces[0].bbox}') + p.extra_generation_params[f"FaceID {i+1}"] = f'{faces[0].det_score:.2f} {"female" if faces[0].gender==0 else "male"} {faces[0].age}y' + if len(face_embeds) == 0: + shared.log.error("FaceID: no faces found") + return None + face_embeds = torch.cat(face_embeds, dim=0) + + ip_model_dict = { # main generate dict + "num_samples": p.batch_size, + "width": p.width, + "height": p.height, + "num_inference_steps": p.steps, + "scale": scale, + "guidance_scale": p.cfg_scale, + "faceid_embeds": face_embeds.shape, # placeholder + } + # optional generate dict + if shortcut is not None: + ip_model_dict["shortcut"] = shortcut + if "Plus" in model: + ip_model_dict["s_scale"] = structure + shared.log.debug(f"FaceID args: {ip_model_dict}") + if "Plus" in model: + ip_model_dict["face_image"] = face_images + ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder + + # run generate + faceid_model.set_scale(scale) + extra_network_data = None + + for i in range(p.n_iter): + p.iteration = i + p.prompts = p.all_prompts[i * p.batch_size:(i + 1) * p.batch_size] + p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size] + p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts) + p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size] + + if not p.disable_extra_networks: + with devices.autocast(): + extra_networks.activate(p, extra_network_data) + + ip_model_dict.update({ + "prompt": p.prompts, + "negative_prompt": p.negative_prompts, + "seed": int(p.seeds[0]), + }) + debug(f"FaceID: {ip_model_dict}") + res = faceid_model.generate(**ip_model_dict) + if isinstance(res, list): + processed_images += res + + faceid_model.set_scale(0) + faceid_model = None + + if not cache: + faceid_model_weights = None + faceid_model_name = None + + devices.torch_gc() + + ipadapter.unapply(p.sd_model) if not p.disable_extra_networks: - with devices.autocast(): - extra_networks.activate(p, extra_network_data) + extra_networks.deactivate(p, extra_network_data) - ip_model_dict.update({ - "prompt": p.prompts, - "negative_prompt": p.negative_prompts, - "seed": int(p.seeds[0]), - }) - debug(f"FaceID: {ip_model_dict}") - res = faceid_model.generate(**ip_model_dict) - if isinstance(res, list): - processed_images += res - - if not p.disable_extra_networks: - extra_networks.deactivate(p, extra_network_data) + p.extra_generation_params["IP Adapter"] = f"{basename}:{scale}" + finally: + if faceid_model is not None and original_load_ip_adapter is not None: + faceid_model.__class__.load_ip_adapter = original_load_ip_adapter - faceid_model.set_scale(0) + if not shared.opts.cuda_compile: + sd_models.apply_token_merging(p.sd_model, 0) - if not cache: - faceid_model = None - faceid_model_name = None - devices.torch_gc() + script_callbacks.after_process_callback(p) - p.extra_generation_params["IP Adapter"] = f"{basename}:{scale}" return processed_images From c244e65f0898d6899a99a36db9bd1ae02503f29e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enes=20Sad=C4=B1k=20=C3=96zbek?= Date: Sat, 24 Feb 2024 16:43:26 +0300 Subject: [PATCH 12/44] faceid intend --- modules/face/faceid.py | 303 +++++++++++++++++++++-------------------- 1 file changed, 152 insertions(+), 151 deletions(-) diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 9cc2cc765..0daf39464 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -73,181 +73,182 @@ def face_id( script_callbacks.before_process_callback(p) - with context_hypertile_vae(p), context_hypertile_unet(p): - with devices.inference_context(): + with context_hypertile_vae(p), context_hypertile_unet(p), devices.inference_context(): + with devices.autocast(): + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) - with devices.autocast(): - p.init(p.all_prompts, p.all_seeds, p.all_subseeds) + ip_ckpt = FACEID_MODELS[model] + folder, filename = os.path.split(ip_ckpt) + basename, _ext = os.path.splitext(filename) + model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.diffusers_dir) - ip_ckpt = FACEID_MODELS[model] - folder, filename = os.path.split(ip_ckpt) - basename, _ext = os.path.splitext(filename) - model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.diffusers_dir) + if model_path is None: + shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}") + return None - if model_path is None: - shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}") - return None - if override: - shared.sd_model.scheduler = diffusers.DDIMScheduler( - num_train_timesteps=1000, - beta_start=0.00085, - beta_end=0.012, - beta_schedule="scaled_linear", - clip_sample=False, - set_alpha_to_one=False, - steps_offset=1, - ) + if override: + shared.sd_model.scheduler = diffusers.DDIMScheduler( + num_train_timesteps=1000, + beta_start=0.00085, + beta_end=0.012, + beta_schedule="scaled_linear", + clip_sample=False, + set_alpha_to_one=False, + steps_offset=1, + ) - if faceid_model_weights is None or faceid_model_name != model or not cache: - shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}") - faceid_model_weights = torch.load(model_path, map_location="cpu") - else: - shared.log.debug(f"FaceID cached: model={model} file={ip_ckpt}") + if faceid_model_weights is None or faceid_model_name != model or not cache: + shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}") + faceid_model_weights = torch.load(model_path, map_location="cpu") + else: + shared.log.debug(f"FaceID cached: model={model} file={ip_ckpt}") - if "XL Plus" in model: - image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" - original_load_ip_adapter = IPAdapterFaceIDPlusXL.load_ip_adapter - IPAdapterFaceIDPlusXL.load_ip_adapter = hijack_load_ip_adapter + if "XL Plus" in model: + image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" + original_load_ip_adapter = IPAdapterFaceIDPlusXL.load_ip_adapter + IPAdapterFaceIDPlusXL.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceIDPlusXL( - sd_pipe=shared.sd_model, - image_encoder_path=image_encoder_path, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) - elif "XL" in model: - original_load_ip_adapter = IPAdapterFaceIDXL.load_ip_adapter - IPAdapterFaceIDXL.load_ip_adapter = hijack_load_ip_adapter + faceid_model = IPAdapterFaceIDPlusXL( + sd_pipe=shared.sd_model, + image_encoder_path=image_encoder_path, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) + elif "XL" in model: + original_load_ip_adapter = IPAdapterFaceIDXL.load_ip_adapter + IPAdapterFaceIDXL.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceIDXL( - sd_pipe=shared.sd_model, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) - elif "Plus" in model: - original_load_ip_adapter = IPAdapterFaceIDPlus.load_ip_adapter - IPAdapterFaceIDPlus.load_ip_adapter = hijack_load_ip_adapter + faceid_model = IPAdapterFaceIDXL( + sd_pipe=shared.sd_model, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) + elif "Plus" in model: + original_load_ip_adapter = IPAdapterFaceIDPlus.load_ip_adapter + IPAdapterFaceIDPlus.load_ip_adapter = hijack_load_ip_adapter - image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" - faceid_model = IPAdapterFaceIDPlus( - sd_pipe=shared.sd_model, - image_encoder_path=image_encoder_path, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) - elif "Portrait" in model: - original_load_ip_adapter = IPAdapterFaceIDPortrait.load_ip_adapter - IPAdapterFaceIDPortrait.load_ip_adapter = hijack_load_ip_adapter + image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" + faceid_model = IPAdapterFaceIDPlus( + sd_pipe=shared.sd_model, + image_encoder_path=image_encoder_path, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) + elif "Portrait" in model: + original_load_ip_adapter = IPAdapterFaceIDPortrait.load_ip_adapter + IPAdapterFaceIDPortrait.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceIDPortrait( - sd_pipe=shared.sd_model, - ip_ckpt=model_path, - num_tokens=16, - n_cond=5, - device=devices.device, - torch_dtype=devices.dtype, - ) - else: - original_load_ip_adapter = IPAdapterFaceID.load_ip_adapter - IPAdapterFaceID.load_ip_adapter = hijack_load_ip_adapter + faceid_model = IPAdapterFaceIDPortrait( + sd_pipe=shared.sd_model, + ip_ckpt=model_path, + num_tokens=16, + n_cond=5, + device=devices.device, + torch_dtype=devices.dtype, + ) + else: + original_load_ip_adapter = IPAdapterFaceID.load_ip_adapter + IPAdapterFaceID.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceID( - sd_pipe=shared.sd_model, - ip_ckpt=model_path, - lora_rank=128, - num_tokens=4, - device=devices.device, - torch_dtype=devices.dtype, - ) + faceid_model = IPAdapterFaceID( + sd_pipe=shared.sd_model, + ip_ckpt=model_path, + lora_rank=128, + num_tokens=4, + device=devices.device, + torch_dtype=devices.dtype, + ) - shortcut = "v2" in model - faceid_model_name = model + shortcut = "v2" in model + faceid_model_name = model - face_embeds = [] - face_images = [] - for i, source_image in enumerate(source_images): - np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR) - faces = app.get(np_image) - if len(faces) == 0: - shared.log.error("FaceID: no faces found") - break - face_embeds.append(torch.from_numpy(faces[0].normed_embedding).unsqueeze(0)) - face_images.append(face_align.norm_crop(np_image, landmark=faces[0].kps, image_size=224)) - shared.log.debug(f'FaceID face: i={i+1} score={faces[0].det_score:.2f} gender={"female" if faces[0].gender==0 else "male"} age={faces[0].age} bbox={faces[0].bbox}') - p.extra_generation_params[f"FaceID {i+1}"] = f'{faces[0].det_score:.2f} {"female" if faces[0].gender==0 else "male"} {faces[0].age}y' - if len(face_embeds) == 0: + face_embeds = [] + face_images = [] + for i, source_image in enumerate(source_images): + np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR) + faces = app.get(np_image) + if len(faces) == 0: shared.log.error("FaceID: no faces found") - return None - face_embeds = torch.cat(face_embeds, dim=0) + break + face_embeds.append(torch.from_numpy(faces[0].normed_embedding).unsqueeze(0)) + face_images.append(face_align.norm_crop(np_image, landmark=faces[0].kps, image_size=224)) + shared.log.debug(f'FaceID face: i={i+1} score={faces[0].det_score:.2f} gender={"female" if faces[0].gender==0 else "male"} age={faces[0].age} bbox={faces[0].bbox}') + p.extra_generation_params[f"FaceID {i+1}"] = f'{faces[0].det_score:.2f} {"female" if faces[0].gender==0 else "male"} {faces[0].age}y' - ip_model_dict = { # main generate dict - "num_samples": p.batch_size, - "width": p.width, - "height": p.height, - "num_inference_steps": p.steps, - "scale": scale, - "guidance_scale": p.cfg_scale, - "faceid_embeds": face_embeds.shape, # placeholder - } - # optional generate dict - if shortcut is not None: - ip_model_dict["shortcut"] = shortcut - if "Plus" in model: - ip_model_dict["s_scale"] = structure - shared.log.debug(f"FaceID args: {ip_model_dict}") - if "Plus" in model: - ip_model_dict["face_image"] = face_images - ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder + if len(face_embeds) == 0: + shared.log.error("FaceID: no faces found") + return None + face_embeds = torch.cat(face_embeds, dim=0) - # run generate - faceid_model.set_scale(scale) - extra_network_data = None + ip_model_dict = { # main generate dict + "num_samples": p.batch_size, + "width": p.width, + "height": p.height, + "num_inference_steps": p.steps, + "scale": scale, + "guidance_scale": p.cfg_scale, + "faceid_embeds": face_embeds.shape, # placeholder + } - for i in range(p.n_iter): - p.iteration = i - p.prompts = p.all_prompts[i * p.batch_size:(i + 1) * p.batch_size] - p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size] - p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts) - p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size] + # optional generate dict + if shortcut is not None: + ip_model_dict["shortcut"] = shortcut + if "Plus" in model: + ip_model_dict["s_scale"] = structure + shared.log.debug(f"FaceID args: {ip_model_dict}") + if "Plus" in model: + ip_model_dict["face_image"] = face_images + ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder - if not p.disable_extra_networks: - with devices.autocast(): - extra_networks.activate(p, extra_network_data) - ip_model_dict.update({ - "prompt": p.prompts, - "negative_prompt": p.negative_prompts, - "seed": int(p.seeds[0]), - }) - debug(f"FaceID: {ip_model_dict}") - res = faceid_model.generate(**ip_model_dict) - if isinstance(res, list): - processed_images += res + faceid_model.set_scale(scale) + extra_network_data = None - faceid_model.set_scale(0) - faceid_model = None + for i in range(p.n_iter): + p.iteration = i + p.prompts = p.all_prompts[i * p.batch_size:(i + 1) * p.batch_size] + p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size] + p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts) + p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size] - if not cache: - faceid_model_weights = None - faceid_model_name = None + if not p.disable_extra_networks: + with devices.autocast(): + extra_networks.activate(p, extra_network_data) - devices.torch_gc() + ip_model_dict.update({ + "prompt": p.prompts, + "negative_prompt": p.negative_prompts, + "seed": int(p.seeds[0]), + }) + debug(f"FaceID: {ip_model_dict}") + res = faceid_model.generate(**ip_model_dict) + if isinstance(res, list): + processed_images += res - ipadapter.unapply(p.sd_model) + faceid_model.set_scale(0) + faceid_model = None - if not p.disable_extra_networks: - extra_networks.deactivate(p, extra_network_data) + if not cache: + faceid_model_weights = None + faceid_model_name = None - p.extra_generation_params["IP Adapter"] = f"{basename}:{scale}" + devices.torch_gc() + + ipadapter.unapply(p.sd_model) + + if not p.disable_extra_networks: + extra_networks.deactivate(p, extra_network_data) + + p.extra_generation_params["IP Adapter"] = f"{basename}:{scale}" finally: if faceid_model is not None and original_load_ip_adapter is not None: faceid_model.__class__.load_ip_adapter = original_load_ip_adapter From 974f19e84b0c668d1b787cbfe592b5676aaa4b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enes=20Sad=C4=B1k=20=C3=96zbek?= Date: Sat, 24 Feb 2024 17:05:25 +0300 Subject: [PATCH 13/44] faceid formatting --- modules/face/faceid.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 0daf39464..94667a765 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -67,6 +67,7 @@ def face_id( try: shared.prompt_styles.apply_styles_to_extra(p) + if not shared.opts.cuda_compile: sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio()) sd_hijack_freeu.apply_freeu(p, shared.backend == shared.Backend.ORIGINAL) @@ -173,6 +174,7 @@ def face_id( face_embeds = [] face_images = [] + for i, source_image in enumerate(source_images): np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR) faces = app.get(np_image) @@ -187,8 +189,8 @@ def face_id( if len(face_embeds) == 0: shared.log.error("FaceID: no faces found") return None - face_embeds = torch.cat(face_embeds, dim=0) + face_embeds = torch.cat(face_embeds, dim=0) ip_model_dict = { # main generate dict "num_samples": p.batch_size, "width": p.width, @@ -202,13 +204,15 @@ def face_id( # optional generate dict if shortcut is not None: ip_model_dict["shortcut"] = shortcut + if "Plus" in model: ip_model_dict["s_scale"] = structure + shared.log.debug(f"FaceID args: {ip_model_dict}") if "Plus" in model: ip_model_dict["face_image"] = face_images - ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder + ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder faceid_model.set_scale(scale) extra_network_data = None @@ -229,8 +233,10 @@ def face_id( "negative_prompt": p.negative_prompts, "seed": int(p.seeds[0]), }) + debug(f"FaceID: {ip_model_dict}") res = faceid_model.generate(**ip_model_dict) + if isinstance(res, list): processed_images += res From 6239d266f4b4ce7af5340abe20a0a36753c8a766 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 09:45:49 -0500 Subject: [PATCH 14/44] remove training --- CHANGELOG.md | 3 + TODO.md | 2 - modules/api/api.py | 9 +- modules/api/train.py | 90 ---- modules/hypernetworks/hypernetwork.py | 350 +--------------- modules/hypernetworks/ui.py | 31 -- modules/script_callbacks.py | 18 - modules/sd_models.py | 7 +- modules/textual_inversion/autocrop.py | 337 --------------- modules/textual_inversion/dataset.py | 223 ---------- modules/textual_inversion/image_embedding.py | 18 +- modules/textual_inversion/learn_schedule.py | 73 ---- modules/textual_inversion/preprocess.py | 217 ---------- modules/textual_inversion/test_embedding.png | Bin 489220 -> 0 bytes .../textual_inversion/textual_inversion.py | 389 +----------------- modules/textual_inversion/ti_logging.py | 22 - modules/textual_inversion/ui.py | 35 -- modules/ui.py | 6 - modules/ui_train.py | 379 ----------------- scripts/image2video.py | 6 +- 20 files changed, 27 insertions(+), 2188 deletions(-) delete mode 100644 modules/api/train.py delete mode 100644 modules/hypernetworks/ui.py delete mode 100644 modules/textual_inversion/autocrop.py delete mode 100644 modules/textual_inversion/dataset.py delete mode 100644 modules/textual_inversion/learn_schedule.py delete mode 100644 modules/textual_inversion/preprocess.py delete mode 100644 modules/textual_inversion/test_embedding.png delete mode 100644 modules/textual_inversion/ti_logging.py delete mode 100644 modules/textual_inversion/ui.py delete mode 100644 modules/ui_train.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 163647ad4..ae64e9b3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - **Improvements** - default theme updates - additional built-in theme *black-gray* +- **Internal** + - remove obsolete textual inversion training code + - remove obsolete hypernetworks training code - **Fixes** - fix extra networks refresh - improve ZLUDA installer when using `--use-zluda` cli param, thanks @lshqqytiger diff --git a/TODO.md b/TODO.md index a77609141..651e25315 100644 --- a/TODO.md +++ b/TODO.md @@ -15,8 +15,6 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - async lowvram: - remove builtin: controlnet - remove builtin: image-browser -- remove training: ti -- remove training: hypernetwork ## Control missing features diff --git a/modules/api/api.py b/modules/api/api.py index 761151a05..4224f78d3 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -5,7 +5,7 @@ from fastapi import FastAPI, APIRouter, Depends, Request from fastapi.security import HTTPBasic, HTTPBasicCredentials from fastapi.exceptions import HTTPException from modules import errors, shared, postprocessing -from modules.api import models, endpoints, script, train, helpers, server, nvml, generate +from modules.api import models, endpoints, script, helpers, server, nvml, generate errors.install() @@ -77,13 +77,6 @@ class Api: self.add_api_route("/sdapi/v1/reload-checkpoint", endpoints.post_reload_checkpoint, methods=["POST"]) self.add_api_route("/sdapi/v1/refresh-vae", endpoints.post_refresh_vae, methods=["POST"]) - # train api - self.add_api_route("/sdapi/v1/create/embedding", train.post_create_embedding, methods=["POST"], response_model=models.ResCreate) - self.add_api_route("/sdapi/v1/create/hypernetwork", train.post_create_hypernetwork, methods=["POST"], response_model=models.ResCreate) - self.add_api_route("/sdapi/v1/preprocess", train.post_preprocess, methods=["POST"], response_model=models.ResPreprocess) - self.add_api_route("/sdapi/v1/train/embedding", train.post_train_embedding, methods=["POST"], response_model=models.ResTrain) - self.add_api_route("/sdapi/v1/train/hypernetwork", train.post_train_hypernetwork, methods=["POST"], response_model=models.ResTrain) - def add_api_route(self, path: str, endpoint, **kwargs): if (shared.cmd_opts.auth or shared.cmd_opts.auth_file) and shared.cmd_opts.api_only: return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs) diff --git a/modules/api/train.py b/modules/api/train.py deleted file mode 100644 index 8fb47fb1d..000000000 --- a/modules/api/train.py +++ /dev/null @@ -1,90 +0,0 @@ -from modules import shared, sd_hijack, devices -from modules.api import models -from modules.textual_inversion.preprocess import preprocess - - -def post_create_embedding(args: dict): - from modules.textual_inversion.textual_inversion import create_embedding - try: - shared.state.begin('api-embedding') - filename = create_embedding(**args) # create empty embedding - sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() # reload embeddings so new one can be immediately used - shared.state.end() - return models.CreateResponse(info = f"create embedding filename: {filename}") - except AssertionError as e: - shared.state.end() - return models.TrainResponse(info = f"create embedding error: {e}") - -def post_create_hypernetwork(args: dict): - from modules.hypernetworks.hypernetwork import create_hypernetwork - try: - shared.state.begin('api-hypernetwork') - filename = create_hypernetwork(**args) # create empty embedding # pylint: disable=E1111 - shared.state.end() - return models.CreateResponse(info = f"create hypernetwork filename: {filename}") - except AssertionError as e: - shared.state.end() - return models.TrainResponse(info = f"create hypernetwork error: {e}") - -def post_preprocess(args: dict): - try: - shared.state.begin('api-preprocess') - preprocess(**args) # quick operation unless blip/booru interrogation is enabled - shared.state.end() - return models.PreprocessResponse(info = 'preprocess complete') - except KeyError as e: - shared.state.end() - return models.PreprocessResponse(info = f"preprocess error: invalid token: {e}") - except AssertionError as e: - shared.state.end() - return models.PreprocessResponse(info = f"preprocess error: {e}") - except FileNotFoundError as e: - shared.state.end() - return models.PreprocessResponse(info = f'preprocess error: {e}') - -def post_train_embedding(args: dict): - from modules.textual_inversion.textual_inversion import train_embedding - try: - shared.state.begin('api-embedding') - apply_optimizations = False - error = None - filename = '' - if not apply_optimizations: - sd_hijack.undo_optimizations() - try: - _embedding, filename = train_embedding(**args) # can take a long time to complete - except Exception as e: - error = e - finally: - if not apply_optimizations: - sd_hijack.apply_optimizations() - shared.state.end() - return models.TrainResponse(info = f"train embedding complete: filename: {filename} error: {error}") - except AssertionError as msg: - shared.state.end() - return models.TrainResponse(info = f"train embedding error: {msg}") - -def post_train_hypernetwork(args: dict): - from modules.hypernetworks.hypernetwork import train_hypernetwork - try: - shared.state.begin('api-hypernetwork') - shared.loaded_hypernetworks = [] - apply_optimizations = False - error = None - filename = '' - if not apply_optimizations: - sd_hijack.undo_optimizations() - try: - _hypernetwork, filename = train_hypernetwork(**args) - except Exception as e: - error = e - finally: - shared.sd_model.cond_stage_model.to(devices.device) - shared.sd_model.first_stage_model.to(devices.device) - if not apply_optimizations: - sd_hijack.apply_optimizations() - shared.state.end() - return models.TrainResponse(info=f"train embedding complete: filename: {filename} error: {error}") - except AssertionError: - shared.state.end() - return models.TrainResponse(info=f"train embedding error: {error}") diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index 4a634c96e..6e13ece24 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -1,23 +1,13 @@ -import datetime -import html import os -from collections import deque import inspect from statistics import stdev, mean from rich import progress -import tqdm import torch from torch import einsum from torch.nn.init import normal_, xavier_normal_, xavier_uniform_, kaiming_normal_, kaiming_uniform_, zeros_ from einops import rearrange, repeat from ldm.util import default -from modules import devices, processing, sd_models, shared, hashes, errors, files_cache -import modules.textual_inversion.dataset -from modules.textual_inversion import textual_inversion, ti_logging -from modules.textual_inversion.learn_schedule import LearnRateScheduler - - -optimizer_dict = {optim_name : cls_obj for optim_name, cls_obj in inspect.getmembers(torch.optim, inspect.isclass) if optim_name != "Optimizer"} +from modules import devices, shared, hashes, errors, files_cache class HypernetworkModule(torch.nn.Module): @@ -410,341 +400,3 @@ def report_statistics(loss_info:dict): print(recent) except Exception as e: print(e) - - -def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False, dropout_structure=None): - # Remove illegal characters from name. - name = "".join( x for x in name if (x.isalnum() or x in "._- ")) - assert name, "Name cannot be empty!" - fn = os.path.join(shared.opts.hypernetwork_dir, f"{name}.pt") - if not overwrite_old: - assert not os.path.exists(fn), f"file {fn} already exists" - if type(layer_structure) == str: - layer_structure = [float(x.strip()) for x in layer_structure.split(",")] - if use_dropout and dropout_structure and type(dropout_structure) == str: - dropout_structure = [float(x.strip()) for x in dropout_structure.split(",")] - else: - dropout_structure = [0] * len(layer_structure) - hypernet = modules.hypernetworks.hypernetwork.Hypernetwork( - name=name, - enable_sizes=[int(x) for x in enable_sizes], - layer_structure=layer_structure, - activation_func=activation_func, - weight_init=weight_init, - add_layer_norm=add_layer_norm, - use_dropout=use_dropout, - 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): # pylint: disable=unused-argument - # images allows training previews to have infotext. Importing it at the top causes a circular import problem. - from modules import images, sd_hijack_checkpoint - - save_hypernetwork_every = save_hypernetwork_every or 0 - create_image_every = create_image_every or 0 - template_file = textual_inversion.textual_inversion_templates.get(template_filename, None) - textual_inversion.validate_train_inputs(hypernetwork_name, learn_rate, batch_size, gradient_step, data_root, template_file, template_filename, steps, save_hypernetwork_every, create_image_every, name="hypernetwork") - template_file = template_file.path - - path = shared.hypernetworks.get(hypernetwork_name, None) - hypernetwork = Hypernetwork() - hypernetwork.load(path) - shared.loaded_hypernetworks = [hypernetwork] - - shared.state.job = "train" - shared.state.textinfo = "Initializing hypernetwork training..." - shared.state.job_count = steps - - hypernetwork_name = hypernetwork_name.rsplit('(', 1)[0] - filename = os.path.join(shared.opts.hypernetwork_dir, f'{hypernetwork_name}.pt') - - log_directory = os.path.join(log_directory, datetime.datetime.now().strftime("%Y-%m-%d"), hypernetwork_name) - unload = shared.opts.unload_models_when_training - - if save_hypernetwork_every > 0: - hypernetwork_dir = os.path.join(log_directory, "hypernetworks") - os.makedirs(hypernetwork_dir, exist_ok=True) - else: - hypernetwork_dir = None - - if create_image_every > 0: - images_dir = os.path.join(log_directory, "images") - os.makedirs(images_dir, exist_ok=True) - else: - images_dir = None - - checkpoint = sd_models.select_checkpoint() - - initial_step = hypernetwork.step or 0 - if initial_step >= steps: - shared.state.textinfo = "Model has already been trained beyond specified max steps" - return hypernetwork, filename - - scheduler = LearnRateScheduler(learn_rate, steps, initial_step) - - clip_grad = torch.nn.utils.clip_grad_value_ if clip_grad_mode == "value" else torch.nn.utils.clip_grad_norm_ if clip_grad_mode == "norm" else None - if clip_grad: - clip_grad_sched = LearnRateScheduler(clip_grad_value, steps, initial_step, verbose=False) - - if shared.opts.training_enable_tensorboard: - tensorboard_writer = textual_inversion.tensorboard_setup(log_directory) - - # dataset loading may take a while, so input validations and early returns should be done before this - shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." - - pin_memory = shared.opts.pin_memory - - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, cond_model=shared.sd_model.cond_stage_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size, gradient_step=gradient_step, shuffle_tags=shuffle_tags, tag_drop_out=tag_drop_out, latent_sampling_method=latent_sampling_method, varsize=varsize, use_weight=use_weight) - - if shared.opts.save_training_settings_to_txt: - saved_params = dict( - model_name=checkpoint.model_name, model_hash=checkpoint.shorthash, num_of_dataset_images=len(ds), - **{field: getattr(hypernetwork, field) for field in ['layer_structure', 'activation_func', 'weight_init', 'add_layer_norm', 'use_dropout', ]} - ) - ti_logging.save_settings_to_file(log_directory, {**saved_params, **locals()}) - - latent_sampling_method = ds.latent_sampling_method - - dl = modules.textual_inversion.dataset.PersonalizedDataLoader(ds, latent_sampling_method=latent_sampling_method, batch_size=ds.batch_size, pin_memory=pin_memory) - - old_parallel_processing_allowed = shared.parallel_processing_allowed - - if unload: - shared.parallel_processing_allowed = False - shared.sd_model.cond_stage_model.to(devices.cpu) - shared.sd_model.first_stage_model.to(devices.cpu) - - weights = hypernetwork.weights() - hypernetwork.train() - - # Here we use optimizer from saved HN, or we can specify as UI option. - if hypernetwork.optimizer_name in optimizer_dict: - optimizer = optimizer_dict[hypernetwork.optimizer_name](params=weights, lr=scheduler.learn_rate) - optimizer_name = hypernetwork.optimizer_name - else: - print(f"Optimizer type {hypernetwork.optimizer_name} is not defined!") - optimizer = torch.optim.AdamW(params=weights, lr=scheduler.learn_rate) - optimizer_name = 'AdamW' - - if hypernetwork.optimizer_state_dict: # This line must be changed if Optimizer type can be different from saved optimizer. - try: - optimizer.load_state_dict(hypernetwork.optimizer_state_dict) - except RuntimeError as e: - print("Cannot resume from saved optimizer!") - print(e) - - scaler = torch.cuda.amp.GradScaler() - - batch_size = ds.batch_size - gradient_step = ds.gradient_step - # n steps = batch_size * gradient_step * n image processed - steps_per_epoch = len(ds) // batch_size // gradient_step - max_steps_per_epoch = len(ds) // batch_size - (len(ds) // batch_size) % gradient_step - loss_step = 0 - _loss_step = 0 #internal - # size = len(ds.indexes) - # loss_dict = defaultdict(lambda : deque(maxlen = 1024)) - loss_logging = deque(maxlen=len(ds) * 3) # this should be configurable parameter, this is 3 * epoch(dataset size) - # losses = torch.zeros((size,)) - # previous_mean_losses = [0] - # previous_mean_loss = 0 - # print("Mean loss of {} elements".format(size)) - - _steps_without_grad = 0 - - last_saved_file = "" - last_saved_image = "" - forced_filename = "" - - pbar = tqdm.tqdm(total=steps - initial_step) - try: - sd_hijack_checkpoint.add() - - for _i in range((steps-initial_step) * gradient_step): - if scheduler.finished: - break - if shared.state.interrupted: - break - for j, batch in enumerate(dl): - # works as a drop_last=True for gradient accumulation - if j == max_steps_per_epoch: - break - scheduler.apply(optimizer, hypernetwork.step) - if scheduler.finished: - break - if shared.state.interrupted: - break - - if clip_grad: - clip_grad_sched.step(hypernetwork.step) - - with devices.autocast(): - x = batch.latent_sample.to(devices.device, non_blocking=pin_memory) - if use_weight: - w = batch.weight.to(devices.device, non_blocking=pin_memory) - if tag_drop_out != 0 or shuffle_tags: - shared.sd_model.cond_stage_model.to(devices.device) - c = shared.sd_model.cond_stage_model(batch.cond_text).to(devices.device, non_blocking=pin_memory) - shared.sd_model.cond_stage_model.to(devices.cpu) - else: - c = stack_conds(batch.cond).to(devices.device, non_blocking=pin_memory) - if use_weight: - loss = shared.sd_model.weighted_forward(x, c, w)[0] / gradient_step - del w - else: - loss = shared.sd_model.forward(x, c)[0] / gradient_step - del x - del c - _loss_step += loss.item() - - scaler.scale(loss).backward() - # go back until we reach gradient accumulation steps - if (j + 1) % gradient_step != 0: - continue - loss_logging.append(_loss_step) - if clip_grad: - clip_grad(weights, clip_grad_sched.learn_rate) - - scaler.step(optimizer) - scaler.update() - hypernetwork.step += 1 - pbar.update() - optimizer.zero_grad(set_to_none=True) - loss_step = _loss_step - _loss_step = 0 - steps_done = hypernetwork.step + 1 - epoch_num = hypernetwork.step // steps_per_epoch - epoch_step = hypernetwork.step % steps_per_epoch - - description = f"Training hypernetwork [Epoch {epoch_num}: {epoch_step+1}/{steps_per_epoch}]loss: {loss_step:.7f}" - pbar.set_description(description) - if hypernetwork_dir is not None and steps_done % save_hypernetwork_every == 0: - # Before saving, change name to match current checkpoint. - hypernetwork_name_every = f'{hypernetwork_name}-{steps_done}' - last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name_every}.pt') - hypernetwork.optimizer_name = optimizer_name - if shared.opts.save_optimizer_state: - hypernetwork.optimizer_state_dict = optimizer.state_dict() - save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, last_saved_file) - hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. - - - - if shared.opts.training_enable_tensorboard: - epoch_num = hypernetwork.step // len(ds) - epoch_step = hypernetwork.step - (epoch_num * len(ds)) + 1 - mean_loss = sum(loss_logging) / len(loss_logging) - textual_inversion.tensorboard_add(tensorboard_writer, loss=mean_loss, global_step=hypernetwork.step, step=epoch_step, learn_rate=scheduler.learn_rate, epoch_num=epoch_num) - - textual_inversion.write_loss(log_directory, "hypernetwork_loss.csv", hypernetwork.step, steps_per_epoch, { - "loss": f"{loss_step:.7f}", - "learn_rate": scheduler.learn_rate - }) - - if images_dir is not None and steps_done % create_image_every == 0: - forced_filename = f'{hypernetwork_name}-{steps_done}' - last_saved_image = os.path.join(images_dir, forced_filename) - hypernetwork.eval() - rng_state = torch.get_rng_state() - cuda_rng_state = None - cuda_rng_state = torch.cuda.get_rng_state_all() - shared.sd_model.cond_stage_model.to(devices.device) - shared.sd_model.first_stage_model.to(devices.device) - - p = processing.StableDiffusionProcessingTxt2Img( - sd_model=shared.sd_model, - do_not_save_grid=True, - do_not_save_samples=True, - ) - - p.disable_extra_networks = True - - if preview_from_txt2img: - p.prompt = preview_prompt - p.negative_prompt = preview_negative_prompt - p.steps = preview_steps - p.sampler_name = processing.get_sampler_name(preview_sampler_index) - p.cfg_scale = preview_cfg_scale - p.seed = preview_seed - p.width = preview_width - p.height = preview_height - else: - p.prompt = batch.cond_text[0] - p.steps = 20 - p.width = training_width - p.height = training_height - - preview_text = p.prompt - - processed = processing.process_images(p) - image = processed.images[0] if len(processed.images) > 0 else None - - if unload: - shared.sd_model.cond_stage_model.to(devices.cpu) - shared.sd_model.first_stage_model.to(devices.cpu) - torch.set_rng_state(rng_state) - torch.cuda.set_rng_state_all(cuda_rng_state) - hypernetwork.train() - if image is not None: - shared.state.assign_current_image(image) - if shared.opts.training_enable_tensorboard and shared.opts.training_tensorboard_save_images: - 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 += f", prompt: {preview_text}" - - shared.state.job_no = hypernetwork.step - - shared.state.textinfo = f""" -

-Loss: {loss_step:.7f}
-Step: {steps_done}
-Last prompt: {html.escape(batch.cond_text[0])}
-Last saved hypernetwork: {html.escape(last_saved_file)}
-Last saved image: {html.escape(last_saved_image)}
-

-""" - except Exception as e: - errors.display(e, 'hypernetwork train') - finally: - pbar.leave = False - pbar.close() - hypernetwork.eval() - #report_statistics(loss_dict) - sd_hijack_checkpoint.remove() - - - - filename = os.path.join(shared.opts.hypernetwork_dir, f'{hypernetwork_name}.pt') - hypernetwork.optimizer_name = optimizer_name - if shared.opts.save_optimizer_state: - hypernetwork.optimizer_state_dict = optimizer.state_dict() - save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename) - - del optimizer - hypernetwork.optimizer_state_dict = None # dereference it after saving, to save memory. - shared.sd_model.cond_stage_model.to(devices.device) - shared.sd_model.first_stage_model.to(devices.device) - shared.parallel_processing_allowed = old_parallel_processing_allowed - - return hypernetwork, filename - -def save_hypernetwork(hypernetwork, checkpoint, hypernetwork_name, filename): - old_hypernetwork_name = hypernetwork.name - old_sd_checkpoint = hypernetwork.sd_checkpoint if hasattr(hypernetwork, "sd_checkpoint") else None - old_sd_checkpoint_name = hypernetwork.sd_checkpoint_name if hasattr(hypernetwork, "sd_checkpoint_name") else None - try: - hypernetwork.sd_checkpoint = checkpoint.shorthash - hypernetwork.sd_checkpoint_name = checkpoint.model_name - hypernetwork.name = hypernetwork_name - hypernetwork.save(filename) - except Exception: - hypernetwork.sd_checkpoint = old_sd_checkpoint - hypernetwork.sd_checkpoint_name = old_sd_checkpoint_name - hypernetwork.name = old_hypernetwork_name - raise diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py deleted file mode 100644 index 42ca9b5b6..000000000 --- a/modules/hypernetworks/ui.py +++ /dev/null @@ -1,31 +0,0 @@ -import html -import gradio as gr -import modules.hypernetworks.hypernetwork -from modules import devices, sd_hijack, shared - -not_available = ["hardswish", "multiheadattention"] -keys = [x for x in modules.hypernetworks.hypernetwork.HypernetworkModule.activation_dict.keys() if x not in not_available] - - -def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, activation_func=None, weight_init=None, add_layer_norm=False, use_dropout=False, dropout_structure=None): - filename = modules.hypernetworks.hypernetwork.create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure, activation_func, weight_init, add_layer_norm, use_dropout, dropout_structure) - return gr.Dropdown.update(choices=sorted(shared.hypernetworks)), f"Created: {filename}", "" - - -def train_hypernetwork(*args): - shared.loaded_hypernetworks = [] - assert not shared.cmd_opts.lowvram, 'Training models with lowvram is not possible' - try: - sd_hijack.undo_optimizations() - hypernetwork, filename = modules.hypernetworks.hypernetwork.train_hypernetwork(*args) - res = f""" -Training {'interrupted' if shared.state.interrupted else 'finished'} at {hypernetwork.step} steps. -Hypernetwork saved to {html.escape(filename)} -""" - return res, "" - except Exception as e: - raise RuntimeError("Hypernetwork error") from e - finally: - shared.sd_model.cond_stage_model.to(devices.device) - shared.sd_model.first_stage_model.to(devices.device) - sd_hijack.apply_optimizations() diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py index 0b84bc8fe..6c91edf44 100644 --- a/modules/script_callbacks.py +++ b/modules/script_callbacks.py @@ -109,7 +109,6 @@ callback_map = dict( callbacks_after_process=[], callbacks_model_loaded=[], callbacks_ui_tabs=[], - callbacks_ui_train_tabs=[], callbacks_ui_settings=[], callbacks_before_image_saved=[], callbacks_image_saved=[], @@ -212,16 +211,6 @@ def ui_tabs_callback(): return res -def ui_train_tabs_callback(params: UiTrainTabParams): - for c in callback_map['callbacks_ui_train_tabs']: - try: - t0 = time.time() - c.callback(params) - timer(t0, c.script, 'ui_train_tabs') - except Exception as e: - report_exception(e, c, 'callbacks_ui_train_tabs') - - def ui_settings_callback(): for c in callback_map['callbacks_ui_settings']: try: @@ -434,13 +423,6 @@ def on_ui_tabs(callback): add_callback(callback_map['callbacks_ui_tabs'], callback) -def on_ui_train_tabs(callback): - """register a function to be called when the UI is creating new tabs for the train tab. - Create your new tabs with gr.Tab. - """ - add_callback(callback_map['callbacks_ui_train_tabs'], callback) - - def on_ui_settings(callback): """register a function to be called before UI settings are populated; add your settings by using shared.opts.add_option(shared.OptionInfo(...)) """ diff --git a/modules/sd_models.py b/modules/sd_models.py index 798324442..d2c5aaaf0 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -740,8 +740,10 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model'): sd_model.unet.to(memory_format=torch.channels_last) -def move_model(model, device=None): - if model is not None and not getattr(model, 'has_accelerate', False): +def move_model(model, device=None, force=False): + if model is not None: + if getattr(model, 'has_accelerate', False) and not force: + return debug_move(f'Model move: to={device} class={model.__class__} function={sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access try: model.to(device) @@ -1416,6 +1418,7 @@ def convert_to_faketensors(tensor): return tensor except Exception: pass + return tensor def disable_offload(sd_model): diff --git a/modules/textual_inversion/autocrop.py b/modules/textual_inversion/autocrop.py deleted file mode 100644 index b4bf9828e..000000000 --- a/modules/textual_inversion/autocrop.py +++ /dev/null @@ -1,337 +0,0 @@ -import os -import cv2 -import requests -import numpy as np -from PIL import ImageDraw - -GREEN = "#0F0" -BLUE = "#00F" -RED = "#F00" - - -def crop_image(im, settings): - """ Intelligently crop an image to the subject matter """ - - scale_by = 1 - if is_landscape(im.width, im.height): - scale_by = settings.crop_height / im.height - elif is_portrait(im.width, im.height): - scale_by = settings.crop_width / im.width - elif is_square(im.width, im.height): - if is_square(settings.crop_width, settings.crop_height): - scale_by = settings.crop_width / im.width - elif is_landscape(settings.crop_width, settings.crop_height): - scale_by = settings.crop_width / im.width - elif is_portrait(settings.crop_width, settings.crop_height): - scale_by = settings.crop_height / im.height - - im = im.resize((int(im.width * scale_by), int(im.height * scale_by))) - im_debug = im.copy() - - focus = focal_point(im_debug, settings) - - # take the focal point and turn it into crop coordinates that try to center over the focal - # point but then get adjusted back into the frame - y_half = int(settings.crop_height / 2) - x_half = int(settings.crop_width / 2) - - x1 = focus.x - x_half - if x1 < 0: - x1 = 0 - elif x1 + settings.crop_width > im.width: - x1 = im.width - settings.crop_width - - y1 = focus.y - y_half - if y1 < 0: - y1 = 0 - elif y1 + settings.crop_height > im.height: - y1 = im.height - settings.crop_height - - x2 = x1 + settings.crop_width - y2 = y1 + settings.crop_height - - crop = [x1, y1, x2, y2] - - results = [] - - results.append(im.crop(tuple(crop))) - - if settings.annotate_image: - d = ImageDraw.Draw(im_debug) - rect = list(crop) - rect[2] -= 1 - rect[3] -= 1 - d.rectangle(rect, outline=GREEN) - results.append(im_debug) - if settings.destop_view_image: - im_debug.show() - - return results - -def focal_point(im, settings): - corner_points = image_corner_points(im, settings) if settings.corner_points_weight > 0 else [] - entropy_points = image_entropy_points(im, settings) if settings.entropy_points_weight > 0 else [] - face_points = image_face_points(im, settings) if settings.face_points_weight > 0 else [] - - pois = [] - - weight_pref_total = 0 - if len(corner_points) > 0: - weight_pref_total += settings.corner_points_weight - if len(entropy_points) > 0: - weight_pref_total += settings.entropy_points_weight - if len(face_points) > 0: - weight_pref_total += settings.face_points_weight - - corner_centroid = None - if len(corner_points) > 0: - corner_centroid = centroid(corner_points) - corner_centroid.weight = settings.corner_points_weight / weight_pref_total - pois.append(corner_centroid) - - entropy_centroid = None - if len(entropy_points) > 0: - entropy_centroid = centroid(entropy_points) - entropy_centroid.weight = settings.entropy_points_weight / weight_pref_total - pois.append(entropy_centroid) - - face_centroid = None - if len(face_points) > 0: - face_centroid = centroid(face_points) - face_centroid.weight = settings.face_points_weight / weight_pref_total - pois.append(face_centroid) - - average_point = poi_average(pois, settings) - - if settings.annotate_image: - d = ImageDraw.Draw(im) - max_size = min(im.width, im.height) * 0.07 - if corner_centroid is not None: - color = BLUE - box = corner_centroid.bounding(max_size * corner_centroid.weight) - d.text((box[0], box[1]-15), f"Edge: {corner_centroid.weight:.02f}", fill=color) - d.ellipse(box, outline=color) - if len(corner_points) > 1: - for f in corner_points: - d.rectangle(f.bounding(4), outline=color) - if entropy_centroid is not None: - color = "#ff0" - box = entropy_centroid.bounding(max_size * entropy_centroid.weight) - d.text((box[0], box[1]-15), f"Entropy: {entropy_centroid.weight:.02f}", fill=color) - d.ellipse(box, outline=color) - if len(entropy_points) > 1: - for f in entropy_points: - d.rectangle(f.bounding(4), outline=color) - if face_centroid is not None: - color = RED - box = face_centroid.bounding(max_size * face_centroid.weight) - d.text((box[0], box[1]-15), f"Face: {face_centroid.weight:.02f}", fill=color) - d.ellipse(box, outline=color) - if len(face_points) > 1: - for f in face_points: - d.rectangle(f.bounding(4), outline=color) - - d.ellipse(average_point.bounding(max_size), outline=GREEN) - - return average_point - - -def image_face_points(im, settings): - if settings.dnn_model_path is not None: - detector = cv2.FaceDetectorYN.create( - settings.dnn_model_path, - "", - (im.width, im.height), - 0.9, # score threshold - 0.3, # nms threshold - 5000 # keep top k before nms - ) - faces = detector.detect(np.array(im)) - results = [] - if faces[1] is not None: - for face in faces[1]: - x = face[0] - y = face[1] - w = face[2] - h = face[3] - results.append( - PointOfInterest( - int(x + (w * 0.5)), # face focus left/right is center - int(y + (h * 0.33)), # face focus up/down is close to the top of the head - size = w, - weight = 1/len(faces[1]) - ) - ) - return results - else: - np_im = np.array(im) - gray = cv2.cvtColor(np_im, cv2.COLOR_BGR2GRAY) - - tries = [ - [ f'{cv2.data.haarcascades}haarcascade_eye.xml', 0.01 ], - [ f'{cv2.data.haarcascades}haarcascade_frontalface_default.xml', 0.05 ], - [ f'{cv2.data.haarcascades}haarcascade_profileface.xml', 0.05 ], - [ f'{cv2.data.haarcascades}haarcascade_frontalface_alt.xml', 0.05 ], - [ f'{cv2.data.haarcascades}haarcascade_frontalface_alt2.xml', 0.05 ], - [ f'{cv2.data.haarcascades}haarcascade_frontalface_alt_tree.xml', 0.05 ], - [ f'{cv2.data.haarcascades}haarcascade_eye_tree_eyeglasses.xml', 0.05 ], - [ f'{cv2.data.haarcascades}haarcascade_upperbody.xml', 0.05 ] - ] - for t in tries: - classifier = cv2.CascadeClassifier(t[0]) - minsize = int(min(im.width, im.height) * t[1]) # at least N percent of the smallest side - try: - faces = classifier.detectMultiScale(gray, scaleFactor=1.1, - minNeighbors=7, minSize=(minsize, minsize), flags=cv2.CASCADE_SCALE_IMAGE) - except Exception: - continue - - if len(faces) > 0: - rects = [[f[0], f[1], f[0] + f[2], f[1] + f[3]] for f in faces] - return [PointOfInterest((r[0] +r[2]) // 2, (r[1] + r[3]) // 2, size=abs(r[0]-r[2]), weight=1/len(rects)) for r in rects] - return [] - - -def image_corner_points(im, settings): # pylint: disable=unused-argument - grayscale = im.convert("L") - - # naive attempt at preventing focal points from collecting at watermarks near the bottom - gd = ImageDraw.Draw(grayscale) - gd.rectangle([0, im.height*.9, im.width, im.height], fill="#999") - - np_im = np.array(grayscale) - - points = cv2.goodFeaturesToTrack( - np_im, - maxCorners=100, - qualityLevel=0.04, - minDistance=min(grayscale.width, grayscale.height)*0.06, - useHarrisDetector=False, - ) - - if points is None: - return [] - - focal_points = [] - for point in points: - x, y = point.ravel() - focal_points.append(PointOfInterest(x, y, size=4, weight=1/len(points))) - - return focal_points - - -def image_entropy_points(im, settings): - landscape = im.height < im.width - portrait = im.height > im.width - if landscape: - move_idx = [0, 2] - move_max = im.size[0] - elif portrait: - move_idx = [1, 3] - move_max = im.size[1] - else: - return [] - - e_max = 0 - crop_current = [0, 0, settings.crop_width, settings.crop_height] - crop_best = crop_current - while crop_current[move_idx[1]] < move_max: - crop = im.crop(tuple(crop_current)) - e = image_entropy(crop) - - if e > e_max: - e_max = e - crop_best = list(crop_current) - - crop_current[move_idx[0]] += 4 - crop_current[move_idx[1]] += 4 - - x_mid = int(crop_best[0] + settings.crop_width/2) - y_mid = int(crop_best[1] + settings.crop_height/2) - - return [PointOfInterest(x_mid, y_mid, size=25, weight=1.0)] - - -def image_entropy(im): - # greyscale image entropy - # band = np.asarray(im.convert("L")) - band = np.asarray(im.convert("1"), dtype=np.uint8) - hist, _ = np.histogram(band, bins=range(0, 256)) - hist = hist[hist > 0] - return -np.log2(hist / hist.sum()).sum() - -def centroid(pois): - x = [poi.x for poi in pois] - y = [poi.y for poi in pois] - return PointOfInterest(sum(x)/len(pois), sum(y)/len(pois)) - - -def poi_average(pois, settings): # pylint: disable=unused-argument - weight = 0.0 - x = 0.0 - y = 0.0 - for poi in pois: - weight += poi.weight - x += poi.x * poi.weight - y += poi.y * poi.weight - avg_x = round(weight and x / weight) - avg_y = round(weight and y / weight) - - return PointOfInterest(avg_x, avg_y) - - -def is_landscape(w, h): - return w > h - - -def is_portrait(w, h): - return h > w - - -def is_square(w, h): - return w == h - - -def download_and_cache_models(dirname): - download_url = 'https://github.com/opencv/opencv_zoo/blob/91fb0290f50896f38a0ab1e558b74b16bc009428/models/face_detection_yunet/face_detection_yunet_2022mar.onnx?raw=true' - model_file_name = 'face_detection_yunet.onnx' - if not os.path.exists(dirname): - os.makedirs(dirname, exist_ok=True) - cache_file = os.path.join(dirname, model_file_name) - if not os.path.exists(cache_file): - print(f"downloading face detection model from '{download_url}' to '{cache_file}'") - response = requests.get(download_url, timeout=60*60*2) - with open(cache_file, "wb") as f: - f.write(response.content) - - if os.path.exists(cache_file): - return cache_file - return None - - -class PointOfInterest: - def __init__(self, x, y, weight=1.0, size=10): - self.x = x - self.y = y - self.weight = weight - self.size = size - - def bounding(self, size): - return [ - self.x - size//2, - self.y - size//2, - self.x + size//2, - self.y + size//2 - ] - - -class Settings: - def __init__(self, crop_width=512, crop_height=512, corner_points_weight=0.5, entropy_points_weight=0.5, face_points_weight=0.5, annotate_image=False, dnn_model_path=None): - self.crop_width = crop_width - self.crop_height = crop_height - self.corner_points_weight = corner_points_weight - self.entropy_points_weight = entropy_points_weight - self.face_points_weight = face_points_weight - self.annotate_image = annotate_image - self.destop_view_image = False - self.dnn_model_path = dnn_model_path diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py deleted file mode 100644 index 10efb5c95..000000000 --- a/modules/textual_inversion/dataset.py +++ /dev/null @@ -1,223 +0,0 @@ -import os -import re -import random -from collections import defaultdict -import numpy as np -import torch -from PIL import Image -from torch.utils.data import Dataset, DataLoader, Sampler -from torchvision import transforms -import tqdm -from ldm.modules.distributions.distributions import DiagonalGaussianDistribution -from modules import devices, shared - -re_numbers_at_start = re.compile(r"^[-\d]+\s*") - - -class DatasetEntry: - def __init__(self, filename=None, filename_text=None, latent_dist=None, latent_sample=None, cond=None, cond_text=None, pixel_values=None, weight=None): - self.filename = filename - self.filename_text = filename_text - self.weight = weight - self.latent_dist = latent_dist - self.latent_sample = latent_sample - self.cond = cond - self.cond_text = cond_text - self.pixel_values = pixel_values - - -class PersonalizedBase(Dataset): - def __init__(self, data_root, width, height, repeats, flip_p=0.5, placeholder_token="*", model=None, cond_model=None, device=None, template_file=None, include_cond=False, batch_size=1, gradient_step=1, shuffle_tags=False, tag_drop_out=0, latent_sampling_method='once', varsize=False, use_weight=False): - re_word = re.compile(shared.opts.dataset_filename_word_regex) if len(shared.opts.dataset_filename_word_regex) > 0 else None - - self.placeholder_token = placeholder_token - self.flip = transforms.RandomHorizontalFlip(p=flip_p) - self.dataset = [] - with open(template_file, "r", encoding="utf8") as file: - lines = [x.strip() for x in file.readlines()] - self.lines = lines - - assert data_root, 'dataset directory not specified' - assert os.path.isdir(data_root), "Dataset directory doesn't exist" - assert os.listdir(data_root), "Dataset directory is empty" - - self.image_paths = [os.path.join(data_root, file_path) for file_path in os.listdir(data_root)] - self.shuffle_tags = shuffle_tags - self.tag_drop_out = tag_drop_out - groups = defaultdict(list) - shared.log.info(f"TI Training: Preparing dataset: {data_root}") - for path in tqdm.tqdm(self.image_paths): - alpha_channel = None - if shared.state.interrupted: - raise RuntimeError("interrupted") - try: - image = Image.open(path) - if use_weight and 'A' in image.getbands(): - alpha_channel = image.getchannel('A') - image = image.convert('RGB') - if not varsize: - image = image.resize((width, height), Image.Resampling.BICUBIC) - except Exception: - continue - - text_filename = f"{os.path.splitext(path)[0]}.txt" - filename = os.path.basename(path) - - if os.path.exists(text_filename): - with open(text_filename, "r", encoding="utf8") as file: - filename_text = file.read() - else: - filename_text = os.path.splitext(filename)[0] - filename_text = re.sub(re_numbers_at_start, '', filename_text) - if re_word: - tokens = re_word.findall(filename_text) - filename_text = (shared.opts.dataset_filename_join_string or "").join(tokens) - - npimage = np.array(image).astype(np.uint8) - npimage = (npimage / 127.5 - 1.0).astype(np.float32) - - torchdata = torch.from_numpy(npimage).permute(2, 0, 1).to(device=device, dtype=torch.float32) - latent_sample = None - - with devices.autocast(): - latent_dist = model.encode_first_stage(torchdata.unsqueeze(dim=0)) - - if latent_sampling_method == "deterministic": - if isinstance(latent_dist, DiagonalGaussianDistribution): - latent_dist.std = torch.exp(0 * latent_dist.logvar) - else: - latent_sampling_method = "once" - latent_sample = model.get_first_stage_encoding(latent_dist).squeeze().to(devices.cpu) - - if use_weight and alpha_channel is not None: - channels, *latent_size = latent_sample.shape - weight_img = alpha_channel.resize(latent_size) - npweight = np.array(weight_img).astype(np.float32) - #Repeat for every channel in the latent sample - weight = torch.tensor([npweight] * channels).reshape([channels] + latent_size) - #Normalize the weight to a minimum of 0 and a mean of 1, that way the loss will be comparable to default. - weight -= weight.min() - weight /= weight.mean() - elif use_weight: - #If an image does not have a alpha channel, add a ones weight map anyway so we can stack it later - weight = torch.ones(latent_sample.shape) - else: - weight = None - - if latent_sampling_method == "random": - entry = DatasetEntry(filename=path, filename_text=filename_text, latent_dist=latent_dist, weight=weight) - else: - entry = DatasetEntry(filename=path, filename_text=filename_text, latent_sample=latent_sample, weight=weight) - - if not (self.tag_drop_out != 0 or self.shuffle_tags): - entry.cond_text = self.create_text(filename_text) - - if include_cond and not (self.tag_drop_out != 0 or self.shuffle_tags): - with devices.autocast(): - entry.cond = cond_model([entry.cond_text]).to(devices.cpu).squeeze(0) - groups[image.size].append(len(self.dataset)) - self.dataset.append(entry) - del torchdata - del latent_dist - del latent_sample - del weight - - self.length = len(self.dataset) - self.groups = list(groups.values()) - assert self.length > 0, "No images have been found in the dataset." - self.batch_size = min(batch_size, self.length) - self.gradient_step = min(gradient_step, self.length // self.batch_size) - self.latent_sampling_method = latent_sampling_method - - def create_text(self, filename_text): - text = random.choice(self.lines) - tags = filename_text.split(',') - if self.tag_drop_out != 0: - tags = [t for t in tags if random.random() > self.tag_drop_out] - if self.shuffle_tags: - random.shuffle(tags) - text = text.replace("[filewords]", ','.join(tags)) - text = text.replace("[name]", self.placeholder_token) - return text - - def __len__(self): - return self.length - - def __getitem__(self, i): - entry = self.dataset[i] - if self.tag_drop_out != 0 or self.shuffle_tags: - entry.cond_text = self.create_text(entry.filename_text) - if self.latent_sampling_method == "random": - entry.latent_sample = shared.sd_model.get_first_stage_encoding(entry.latent_dist).to(devices.cpu) - return entry - - -class GroupedBatchSampler(Sampler): - def __init__(self, data_source: PersonalizedBase, batch_size: int): - super().__init__(data_source) - - n = len(data_source) - self.groups = data_source.groups - self.len = n_batch = n // batch_size - expected = [len(g) / n * n_batch * batch_size for g in data_source.groups] - self.base = [int(e) // batch_size for e in expected] - self.n_rand_batches = nrb = n_batch - sum(self.base) - self.probs = [e%batch_size/nrb/batch_size if nrb>0 else 0 for e in expected] - self.batch_size = batch_size - - def __len__(self): - return self.len - - def __iter__(self): - b = self.batch_size - - for g in self.groups: - random.shuffle(g) - - batches = [] - for g in self.groups: - batches.extend(g[i*b:(i+1)*b] for i in range(len(g) // b)) - for _ in range(self.n_rand_batches): - rand_group = random.choices(self.groups, self.probs)[0] - batches.append(random.choices(rand_group, k=b)) - - random.shuffle(batches) - - yield from batches - - -class PersonalizedDataLoader(DataLoader): - def __init__(self, dataset, latent_sampling_method="once", batch_size=1, pin_memory=False): - super(PersonalizedDataLoader, self).__init__(dataset, batch_sampler=GroupedBatchSampler(dataset, batch_size), pin_memory=pin_memory) - if latent_sampling_method == "random": - self.collate_fn = collate_wrapper_random - else: - self.collate_fn = collate_wrapper - - -class BatchLoader: - def __init__(self, data): - self.cond_text = [entry.cond_text for entry in data] - self.cond = [entry.cond for entry in data] - self.latent_sample = torch.stack([entry.latent_sample for entry in data]).squeeze(1) - if all(entry.weight is not None for entry in data): - self.weight = torch.stack([entry.weight for entry in data]).squeeze(1) - else: - self.weight = None - - def pin_memory(self): - self.latent_sample = self.latent_sample.pin_memory() - return self - -def collate_wrapper(batch): - return BatchLoader(batch) - -class BatchLoaderRandom(BatchLoader): - def __init__(self, data): - super().__init__(data) - - def pin_memory(self): - return self - -def collate_wrapper_random(batch): - return BatchLoaderRandom(batch) diff --git a/modules/textual_inversion/image_embedding.py b/modules/textual_inversion/image_embedding.py index a33d3e450..c9fe40767 100644 --- a/modules/textual_inversion/image_embedding.py +++ b/modules/textual_inversion/image_embedding.py @@ -8,17 +8,17 @@ from modules.shared import opts class EmbeddingEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, torch.Tensor): - return {'TORCHTENSOR': obj.cpu().detach().numpy().tolist()} - return json.JSONEncoder.default(self, obj) + def default(self, o): + if isinstance(o, torch.Tensor): + return {'TORCHTENSOR': o.cpu().detach().numpy().tolist()} + return json.JSONEncoder.default(self, o) class EmbeddingDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): json.JSONDecoder.__init__(self, *args, object_hook=self.object_hook, **kwargs) - def object_hook(self, d): + def object_hook(self, d): # pylint: disable=E0202 if 'TORCHTENSOR' in d: return torch.from_numpy(np.array(d['TORCHTENSOR'])) return d @@ -41,8 +41,8 @@ def lcg(m=2**32, a=1664525, c=1013904223, seed=0): def xor_block(block): - g = lcg() - randblock = np.array([next(g) for _ in range(np.prod(block.shape))]).astype(np.uint8).reshape(block.shape) + blk = lcg() + randblock = np.array([next(blk) for _ in range(np.prod(block.shape))]).astype(np.uint8).reshape(block.shape) return np.bitwise_xor(block.astype(np.uint8), randblock & 0x0F) @@ -110,7 +110,7 @@ def crop_black(img, tol=0): def extract_image_data_embed(image): d = 3 - outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1], image.size[0], d).astype(np.uint8)) & 0x0F + outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1], image.size[0], d).astype(np.uint8)) & 0x0F # pylint: disable=E1121 black_cols = np.where(np.sum(outarr, axis=(0, 2)) == 0) if black_cols[0].shape[0] < 2: return None @@ -182,7 +182,7 @@ if __name__ == '__main__': new_image = Image.new('RGBA', (512, 512), (255, 255, 200, 255)) cap_image = caption_image_overlay(new_image, 'title', 'footerLeft', 'footerMid', 'footerRight') - test_embed = {'string_to_param': {'*': torch.from_numpy(np.random.random((2, 4096)))}} + test_embed = {'string_to_param': {'*': torch.from_numpy(np.random.random((2, 4096)))}} # noqa: NPY002 embedded_image = insert_image_data_embed(cap_image, test_embed) diff --git a/modules/textual_inversion/learn_schedule.py b/modules/textual_inversion/learn_schedule.py deleted file mode 100644 index 35f169efc..000000000 --- a/modules/textual_inversion/learn_schedule.py +++ /dev/null @@ -1,73 +0,0 @@ -class LearnScheduleIterator: - def __init__(self, learn_rate, max_steps, cur_step=0): - """ - specify learn_rate as "0.001:100, 0.00001:1000, 1e-5:10000" to have lr of 0.001 until step 100, 0.00001 until 1000, and 1e-5 until 10000 - """ - - pairs = learn_rate.split(',') - self.rates = [] - self.it = 0 - self.maxit = 0 - try: - for pair in pairs: - if not pair.strip(): - continue - tmp = pair.split(':') - if len(tmp) == 2: - step = int(tmp[1]) - if step > cur_step: - self.rates.append((float(tmp[0]), min(step, max_steps))) - self.maxit += 1 - if step > max_steps: - return - elif step == -1: - self.rates.append((float(tmp[0]), max_steps)) - self.maxit += 1 - return - else: - self.rates.append((float(tmp[0]), max_steps)) - self.maxit += 1 - return - assert self.rates - except (ValueError, AssertionError) as e: - raise RuntimeError('Invalid learning rate schedule. It should be a number or, for example, like "0.001:100, 0.00001:1000, 1e-5:10000" to have lr of 0.001 until step 100, 0.00001 until 1000, and 1e-5 until 10000.') from e - - - def __iter__(self): - return self - - def __next__(self): - if self.it < self.maxit: - self.it += 1 - return self.rates[self.it - 1] - else: - raise StopIteration - - -class LearnRateScheduler: - def __init__(self, learn_rate, max_steps, cur_step=0, verbose=True): - self.schedules = LearnScheduleIterator(learn_rate, max_steps, cur_step) - (self.learn_rate, self.end_step) = next(self.schedules) - self.verbose = verbose - self.finished = False - - def step(self, step_number): - if step_number < self.end_step: - return False - - try: - (self.learn_rate, self.end_step) = next(self.schedules) - except StopIteration: - self.finished = True - return False - return True - - def apply(self, optimizer, step_number): - if not self.step(step_number): - return - - # if self.verbose: - # tqdm.tqdm.write(f'Training at rate of {self.learn_rate} until step {self.end_step}') - - for pg in optimizer.param_groups: - pg['lr'] = self.learn_rate diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py deleted file mode 100644 index 2959ebe66..000000000 --- a/modules/textual_inversion/preprocess.py +++ /dev/null @@ -1,217 +0,0 @@ -import os -import math -from tqdm import tqdm -from PIL import Image, ImageOps -from modules import paths, shared, images, deepbooru -from modules.textual_inversion import autocrop - - -def preprocess(id_task, process_src, process_dst, process_width, process_height, preprocess_txt_action, process_keep_original_size=False, process_keep_channels=False, process_flip=False, process_split=False, process_caption_only=False, process_caption=False, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_focal_crop=False, 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, 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): # pylint: disable=unused-argument - try: - if process_caption: - shared.interrogator.load() - - if process_caption_deepbooru: - deepbooru.model.start() - - preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_keep_original_size, process_keep_channels, process_flip, process_split, process_caption, process_caption_deepbooru, process_caption_only, split_threshold, 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) - - finally: - - if process_caption: - shared.interrogator.send_blip_to_ram() - - if process_caption_deepbooru: - deepbooru.model.stop() - - -class PreprocessParams: - src = None - dstdir = None - subindex = 0 - flip = False - process_caption_only = False - process_caption = False - process_caption_deepbooru = False - preprocess_txt_action = None - - -def save_pic_with_caption(image, index, params: PreprocessParams, existing_caption=None, existing_caption_filename=None): - caption = "" - if params.process_caption: - caption += shared.interrogator.generate_caption(image) - if params.process_caption_deepbooru: - if len(caption) > 0: - caption += ", " - caption += deepbooru.model.tag_multi(image) - - filename_part = params.src - filename_part = os.path.splitext(filename_part)[0] - filename_part = os.path.basename(filename_part) - - basename = f"{index:05}-{params.subindex}-{filename_part}" - if not params.process_caption_only: - image.save(os.path.join(params.dstdir, f"{basename}.png")) - - if params.preprocess_txt_action == 'prepend' and existing_caption: - caption = f"{existing_caption} {caption}" - elif params.preprocess_txt_action == 'append' and existing_caption: - caption = f"{caption} {existing_caption}" - elif params.preprocess_txt_action == 'copy' and existing_caption: - caption = existing_caption - caption = caption.strip() - if len(caption) > 0: - if params.process_caption_only: - fn = os.path.join(params.dstdir, f"{filename_part}.txt") - elif existing_caption_filename is not None: - fn = existing_caption_filename - else: - fn = os.path.join(params.dstdir, f"{basename}.txt") - with open(fn, "w", encoding="utf8") as file: - file.write(caption) - - params.subindex += 1 - - -def save_pic(image, index, params, existing_caption=None, existing_caption_filename=None): - save_pic_with_caption(image, index, params, existing_caption=existing_caption, existing_caption_filename=existing_caption_filename) - if params.flip: - save_pic_with_caption(ImageOps.mirror(image), index, params, existing_caption=existing_caption, existing_caption_filename=existing_caption_filename) - - -def split_pic(image, inverse_xy, width, height, overlap_ratio): - if inverse_xy: - from_w, from_h = image.height, image.width - to_w, to_h = height, width - else: - from_w, from_h = image.width, image.height - to_w, to_h = width, height - h = from_h * to_w // from_w - if inverse_xy: - image = image.resize((h, to_w)) - else: - image = image.resize((to_w, h)) - - split_count = math.ceil((h - to_h * overlap_ratio) / (to_h * (1.0 - overlap_ratio))) - y_step = (h - to_h) / (split_count - 1) - for i in range(split_count): - y = int(y_step * i) - if inverse_xy: - splitted = image.crop((y, 0, y + to_h, to_w)) - else: - splitted = image.crop((0, y, to_w, y + to_h)) - yield splitted - -# not using torchvision.transforms.CenterCrop because it doesn't allow float regions -def center_crop(image: Image, w: int, h: int): - iw, ih = image.size - if ih / h < iw / w: - sw = w * ih / h - box = (iw - sw) / 2, 0, iw - (iw - sw) / 2, ih - else: - sh = h * iw / w - box = 0, (ih - sh) / 2, iw, ih - (ih - sh) / 2 - return image.resize((w, h), Image.Resampling.LANCZOS, box) - - -def multicrop_pic(image: Image, mindim, maxdim, minarea, maxarea, objective, threshold): - iw, ih = image.size - err = lambda w, h: 1-(lambda x: x if x < 1 else 1/x)(iw/ih/(w/h)) # pylint: disable=unnecessary-lambda-assignment,unnecessary-direct-lambda-call - wh = max(((w, h) for w in range(mindim, maxdim+1, 64) for h in range(mindim, maxdim+1, 64) - if minarea <= w * h <= maxarea and err(w, h) <= threshold), - key= lambda wh: (wh[0]*wh[1], -err(*wh))[::1 if objective=='Maximize area' else -1], - default=None - ) - return wh and center_crop(image, *wh) - - -def preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_keep_original_size, process_keep_channels, process_flip, process_split, process_caption, process_caption_deepbooru, process_caption_only, split_threshold, 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): - - width = process_width - height = process_height - src = os.path.abspath(process_src) - dst = os.path.abspath(process_dst) - split_threshold = max(0.0, min(1.0, split_threshold)) - overlap_ratio = max(0.0, min(0.9, overlap_ratio)) - assert src != dst, 'same directory specified as source and destination' - os.makedirs(dst, exist_ok=True) - files = os.listdir(src) - shared.state.job = "preprocess" - shared.state.textinfo = "Preprocessing..." - shared.state.job_count = len(files) - params = PreprocessParams() - params.dstdir = dst - params.flip = process_flip - params.process_caption_only = process_caption_only - params.process_caption = process_caption - params.process_caption_deepbooru = process_caption_deepbooru - params.preprocess_txt_action = preprocess_txt_action - pbar = tqdm(files) - for index, imagefile in enumerate(pbar): - params.subindex = 0 - filename = os.path.join(src, imagefile) - try: - img = Image.open(filename) - img = ImageOps.exif_transpose(img) - if not process_keep_channels: - img = img.convert("RGB") - except Exception: - continue - - description = f"Preprocessing image {index + 1}/{len(files)}" - pbar.set_description(description) - shared.state.textinfo = description - params.src = filename - existing_caption = None - existing_caption_filename = f"{os.path.splitext(filename)[0]}.txt" - if os.path.exists(existing_caption_filename): - with open(existing_caption_filename, 'r', encoding="utf8") as file: - existing_caption = file.read() - else: - existing_caption_filename = None - if shared.state.interrupted: - break - if img.height > img.width: - ratio = (img.width * height) / (img.height * width) - inverse_xy = False - else: - ratio = (img.height * width) / (img.width * height) - inverse_xy = True - process_default_resize = True - if process_split and ratio < 1.0 and ratio <= split_threshold: - for splitted in split_pic(img, inverse_xy, width, height, overlap_ratio): - save_pic(splitted, index, params, existing_caption=existing_caption, existing_caption_filename=existing_caption_filename) - process_default_resize = False - if process_focal_crop and img.height != img.width: - dnn_model_path = None - try: - dnn_model_path = autocrop.download_and_cache_models(os.path.join(paths.models_path, "opencv")) - except Exception as e: - shared.log.error(f"TI unable to load face detection model for auto crop selection. Falling back to lower quality haar method. {e}") - autocrop_settings = autocrop.Settings( - crop_width = width, - crop_height = height, - face_points_weight = process_focal_crop_face_weight, - entropy_points_weight = process_focal_crop_entropy_weight, - corner_points_weight = process_focal_crop_edges_weight, - annotate_image = process_focal_crop_debug, - dnn_model_path = dnn_model_path, - ) - for focal in autocrop.crop_image(img, autocrop_settings): - save_pic(focal, index, params, existing_caption=existing_caption) - process_default_resize = False - - if process_multicrop: - cropped = multicrop_pic(img, process_multicrop_mindim, process_multicrop_maxdim, process_multicrop_minarea, process_multicrop_maxarea, process_multicrop_objective, process_multicrop_threshold) - if cropped is not None: - save_pic(cropped, index, params, existing_caption=existing_caption) - else: - shared.log.error(f"TI skipped {img.width}x{img.height} image {filename} (can't find suitable size within error threshold)") - process_default_resize = False - if process_keep_original_size: - save_pic(img, index, params, existing_caption=existing_caption) - process_default_resize = False - if process_default_resize: - img = images.resize_image(1, img, width, height) - save_pic(img, index, params, existing_caption=existing_caption) - shared.state.nextjob() diff --git a/modules/textual_inversion/test_embedding.png b/modules/textual_inversion/test_embedding.png deleted file mode 100644 index 07e2d9afaeaff3751b68a7c0f49d8b3466474282..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 489220 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

-Loss: {loss_step:.7f}
-Step: {steps_done}
-Last prompt: {html.escape(batch.cond_text[0])}
-Last saved embedding: {html.escape(last_saved_file)}
-Last saved image: {html.escape(last_saved_image)}
-

-""" - filename = os.path.join(shared.opts.embeddings_dir, f'{embedding_name}.pt') - save_embedding(embedding, optimizer, checkpoint, embedding_name, filename, remove_cached_checksum=True) - except Exception as e: - errors.display(e, 'embedding train') - finally: - pbar.leave = False - pbar.close() - shared.sd_model.first_stage_model.to(devices.device) - shared.parallel_processing_allowed = old_parallel_processing_allowed - sd_hijack_checkpoint.remove() - return embedding, filename - - -def save_embedding(embedding, optimizer, checkpoint, embedding_name, filename, remove_cached_checksum=True): - old_embedding_name = embedding.name - old_sd_checkpoint = embedding.sd_checkpoint if hasattr(embedding, "sd_checkpoint") else None - old_sd_checkpoint_name = embedding.sd_checkpoint_name if hasattr(embedding, "sd_checkpoint_name") else None - old_cached_checksum = embedding.cached_checksum if hasattr(embedding, "cached_checksum") else None - try: - embedding.sd_checkpoint = checkpoint.shorthash - embedding.sd_checkpoint_name = checkpoint.model_name - if remove_cached_checksum: - embedding.cached_checksum = None - embedding.name = embedding_name - embedding.optimizer_state_dict = optimizer.state_dict() - embedding.save(filename) - except Exception: - embedding.sd_checkpoint = old_sd_checkpoint - embedding.sd_checkpoint_name = old_sd_checkpoint_name - embedding.name = old_embedding_name - embedding.cached_checksum = old_cached_checksum - raise diff --git a/modules/textual_inversion/ti_logging.py b/modules/textual_inversion/ti_logging.py deleted file mode 100644 index 1116ec91d..000000000 --- a/modules/textual_inversion/ti_logging.py +++ /dev/null @@ -1,22 +0,0 @@ -import datetime -import json -import os - -saved_params_shared = {"model_name", "model_hash", "initial_step", "num_of_dataset_images", "learn_rate", "batch_size", "clip_grad_mode", "clip_grad_value", "gradient_step", "data_root", "log_directory", "training_width", "training_height", "steps", "create_image_every", "template_file", "latent_sampling_method"} -saved_params_ti = {"embedding_name", "num_vectors_per_token", "save_embedding_every", "save_image_with_stored_embedding"} -saved_params_hypernet = {"hypernetwork_name", "layer_structure", "activation_func", "weight_init", "add_layer_norm", "use_dropout", "save_hypernetwork_every"} -saved_params_all = saved_params_shared | saved_params_ti | saved_params_hypernet -saved_params_previews = {"preview_prompt", "preview_negative_prompt", "preview_steps", "preview_sampler_index", "preview_cfg_scale", "preview_seed", "preview_width", "preview_height"} - - -def save_settings_to_file(log_directory, all_params): - now = datetime.datetime.now() - params = {"datetime": now.strftime("%Y-%m-%d %H:%M:%S")} - keys = saved_params_all - if all_params.get('preview_from_txt2img'): - keys = keys | saved_params_previews - params.update({k: v for k, v in all_params.items() if k in keys}) - filename = f"settings-{now.strftime('%Y-%m-%d_%H-%M-%S')}.json" - with open(os.path.join(log_directory, filename), "w", encoding='utf-8') as file: - print(f'Training settings file: {os.path.join(log_directory, filename)}') - json.dump(params, file, indent=2) diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py deleted file mode 100644 index 9c5d7e3c4..000000000 --- a/modules/textual_inversion/ui.py +++ /dev/null @@ -1,35 +0,0 @@ -import html -import gradio as gr -import modules.textual_inversion.textual_inversion -import modules.textual_inversion.preprocess -from modules import shared - - -def create_embedding(name, initialization_text, nvpt, overwrite_old): - from modules import sd_hijack - filename = modules.textual_inversion.textual_inversion.create_embedding(name, nvpt, overwrite_old, init_text=initialization_text) - sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() - return gr.Dropdown.update(choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())), f"Created: {filename}", "" - - -def preprocess(*args): - modules.textual_inversion.preprocess.preprocess(*args) - return f"Preprocessing {'interrupted' if shared.state.interrupted else 'finished'}.", "" - - -def train_embedding(*args): - from modules import sd_hijack - assert not shared.cmd_opts.lowvram, 'Training models with lowvram not possible' - apply_optimizations = False - try: - if not apply_optimizations: - sd_hijack.undo_optimizations() - embedding, filename = modules.textual_inversion.textual_inversion.train_embedding(*args) - res = f"Training {'interrupted' if shared.state.interrupted else 'finished'} at {embedding.step} steps. Embedding saved to {html.escape(filename)}" - return res, "" - except Exception as e: - shared.log.error(f"Exception in train_embedding: {e}") - raise RuntimeError from e - finally: - if not apply_optimizations: - sd_hijack.apply_optimizations() diff --git a/modules/ui.py b/modules/ui.py index b773f6231..b059bbd36 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -144,11 +144,6 @@ def create_ui(startup_timer = None): ui_postprocessing.create_ui() timer.startup.record("ui-extras") - with gr.Blocks(analytics_enabled=False) as train_interface: - from modules import ui_train - ui_train.create_ui() - timer.startup.record("ui-train") - with gr.Blocks(analytics_enabled=False) as models_interface: from modules import ui_models ui_models.create_ui() @@ -377,7 +372,6 @@ def create_ui(startup_timer = None): interfaces += [(control_interface, "Control", "control")] if control_interface is not None else [] interfaces += [(extras_interface, "Process", "process")] interfaces += [(interrogate_interface, "Interrogate", "interrogate")] - interfaces += [(train_interface, "Train", "train")] interfaces += [(models_interface, "Models", "models")] interfaces += script_callbacks.ui_tabs_callback() interfaces += [(settings_interface, "System", "system")] diff --git a/modules/ui_train.py b/modules/ui_train.py deleted file mode 100644 index 263adf1bf..000000000 --- a/modules/ui_train.py +++ /dev/null @@ -1,379 +0,0 @@ -import os -import gradio as gr -from modules import script_callbacks, shared -from modules.ui_common import create_refresh_button -from modules.ui_sections import create_sampler_inputs -from modules.call_queue import wrap_gradio_gpu_call - - -def create_ui(): - from modules.textual_inversion import textual_inversion - import modules.hypernetworks.ui - dummy_component = gr.Label(visible=False) - - with gr.Row(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', 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) - elif tab == 'pr': - return gr_show(True), gr_show(False), gr_show(False) - else: - return gr_show(False), gr_show(False), gr_show(False) - - ### preview tab - - with gr.Tab(label="Preview settings", id="train_preview_tab") as tab_preview: - tab_preview.select(fn=lambda: train_tab_change('pr'), inputs=[], outputs=[action_pp, action_ti, action_hn]) - prompt = gr.Textbox(label="Prompt", value="", placeholder="Prompt to be used for previews", lines=2) - negative = gr.Textbox(label="Negative prompt", value="", placeholder="Negative prompt to be used for previews", lines=2) - steps, sampler_index = create_sampler_inputs('train', accordion=False) - cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='CFG scale', value=6.0) - seed = gr.Number(label='Initial seed', value=-1) - with gr.Row(): - width = gr.Slider(minimum=64, maximum=8192, step=8, label="Width", value=512) - height = gr.Slider(minimum=64, maximum=8192, step=8, label="Height", value=512) - txt2img_preview_params = [prompt, negative, steps, sampler_index, cfg_scale, seed, width, height] - - ### preprocess tab - - with gr.Tab(label="Preprocess images", id="preprocess_images") as tab_preprocess: - tab_preprocess.select(fn=lambda: 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.HTML('

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.HTML('

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) - - from modules.textual_inversion import ui - 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(ui.preprocess, extra_outputs=[gr.update()]), - _js="startTrainMonitor", - 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 - if shared.backend == shared.Backend.ORIGINAL: - from modules import sd_hijack - with gr.Tab(label="Train embedding", id="train_embedding_tab") as tab_ti: - tab_ti.select(fn=lambda: 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.HTML('

Select existing embedding to continue training or create a new one

') - with gr.Row(): - 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.HTML('

Training parameters

') - ti_learn_rate = gr.Textbox(label='Embedding Learning rate', placeholder="Embedding Learning rate", value="0.005") - with gr.Row(): - 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.HTML('

Training images

') - ti_dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") - with gr.Row(): - 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.HTML('

Dataset processing

') - with gr.Row(): - 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.HTML('

Training outputs

') - with gr.Row(): - 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="Defaults to train/log/embedding", value="") - - 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="startTrainMonitor", - 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 - - if shared.backend == shared.Backend.ORIGINAL: - from modules import sd_hijack - with gr.Tab(label="Train hypernetwork", id="train_hypernetwork_tab") as tab_hn: - tab_hn.select(fn=lambda: train_tab_change('hn'), inputs=[], outputs=[action_pp, action_ti, action_hn]) - gr.HTML('

Select existing hypernetwork to continue training or create a new one

') - with gr.Row(): - with gr.Column(): - with gr.Row(): - 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.HTML('

Training parameters

') - hn_learn_rate = gr.Textbox(label='Hypernetwork Learning rate', placeholder="Hypernetwork Learning rate", value="0.00001") - with gr.Row(): - 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.HTML('

Training images

') - hn_dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images") - with gr.Row(): - 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.HTML('

Dataset processing

') - with gr.Row(): - 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.HTML('

Training outputs

') - with gr.Row(): - 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="startTrainMonitor", - 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) diff --git a/scripts/image2video.py b/scripts/image2video.py index 4fcea0cde..71da691e5 100644 --- a/scripts/image2video.py +++ b/scripts/image2video.py @@ -16,8 +16,8 @@ class Script(scripts.Script): return 'Image-to-Video' def show(self, is_img2img): - # return is_img2img if shared.backend == shared.Backend.DIFFUSERS else False - return False + return is_img2img if shared.backend == shared.Backend.DIFFUSERS else False + # return False # return signature is array of gradio components def ui(self, _is_img2img): @@ -85,7 +85,7 @@ class Script(scripts.Script): motion_adapter = diffusers.MotionAdapter.from_pretrained(repo_id) motion_adapter.to(devices.device, devices.dtype) shared.sd_model = sd_models.switch_pipe(diffusers.PIAPipeline, shared.sd_model, { 'motion_adapter': motion_adapter }) - sd_models.move_model(shared.sd_model, devices.device) # move pipeline to device + sd_models.move_model(shared.sd_model, devices.device, force=True) # move pipeline to device if num_frames > 0: p.task_args['num_frames'] = num_frames p.task_args['image'] = p.init_images[0] From 0f2f030b04e01cfc360afc90f58bbd779e3e4b8e Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 09:54:57 -0500 Subject: [PATCH 15/44] add vgen --- CHANGELOG.md | 4 ++++ TODO.md | 1 - scripts/image2video.py | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae64e9b3c..bd9d0e346 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Update for 2024-02-24 +- **Image2Video** + - new module for creating videos from images + - simply enable from *img2img -> scripts -> image2video* + - based on [VGen](https://huggingface.co/ali-vilab/i2vgen-xl) - **Improvements** - default theme updates - additional built-in theme *black-gray* diff --git a/TODO.md b/TODO.md index 651e25315..03af7e25b 100644 --- a/TODO.md +++ b/TODO.md @@ -10,7 +10,6 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - init latents: variations, tiling, img2img - x-adapter: - diffusers public callbacks -- image2video: pia and vgen pipelines - video2video - async lowvram: - remove builtin: controlnet diff --git a/scripts/image2video.py b/scripts/image2video.py index 71da691e5..91b265a39 100644 --- a/scripts/image2video.py +++ b/scripts/image2video.py @@ -6,7 +6,7 @@ from modules import scripts, processing, shared, images, sd_models, devices MODELS = [ { 'name': 'None', 'info': '' }, - { 'name': 'PIA', 'url': 'openmmlab/PIA-condition-adapter', 'info': '
Open MMLab Personalized Image Animator' }, + # { 'name': 'PIA', 'url': 'openmmlab/PIA-condition-adapter', 'info': 'Open MMLab Personalized Image Animator' }, { 'name': 'VGen', 'url': 'ali-vilab/i2vgen-xl', 'info': 'Alibaba VGen' }, ] @@ -75,12 +75,12 @@ class Script(scripts.Script): shared.log.debug(f'Image2Video: model={model_name} frames={num_frames}, video={video_type} duration={duration} loop={gif_loop} pad={mp4_pad} interpolate={mp4_interpolate}') p.ops.append('image2video') p.do_not_save_grid = True + orig_pipeline = shared.sd_model if model_name == 'PIA': if shared.sd_model_type != 'sd': shared.log.error('Image2Video PIA: base model must be SD15') return - orig_pipeline = shared.sd_model shared.log.info(f'Image2Video PIA load: model={repo_id}') motion_adapter = diffusers.MotionAdapter.from_pretrained(repo_id) motion_adapter.to(devices.device, devices.dtype) @@ -101,7 +101,6 @@ class Script(scripts.Script): shared.log.debug(f'Image2Video PIA: args={p.task_args}') processed = processing.process_images(p) shared.sd_model.motion_adapter = None - shared.sd_model = orig_pipeline if model_name == 'VGen': if not isinstance(shared.sd_model, diffusers.I2VGenXLPipeline): @@ -121,6 +120,7 @@ class Script(scripts.Script): shared.log.debug(f'Image2Video VGen: args={p.task_args}') processed = processing.process_images(p) + shared.sd_model = orig_pipeline if video_type != 'None' and processed is not None: images.save_video(p, filename=None, images=processed.images, video_type=video_type, duration=duration, loop=gif_loop, pad=mp4_pad, interpolate=mp4_interpolate) return processed From 5ac36c6bf155f5f104fbc6fe55b8c93f90f9abf2 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 10:02:06 -0500 Subject: [PATCH 16/44] faceid improvements --- CHANGELOG.md | 4 ++-- modules/face/faceid.py | 26 +------------------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd9d0e346..82aa9c037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,8 @@ - simply enable from *img2img -> scripts -> image2video* - based on [VGen](https://huggingface.co/ali-vilab/i2vgen-xl) - **Improvements** - - default theme updates - - additional built-in theme *black-gray* + - **FaceID** extend support for LoRA, HyperTile and FreeU, thanks @Trojaner + - default theme updates and additional built-in theme *black-gray* - **Internal** - remove obsolete textual inversion training code - remove obsolete hypernetworks training code diff --git a/modules/face/faceid.py b/modules/face/faceid.py index 94667a765..7639152f9 100644 --- a/modules/face/faceid.py +++ b/modules/face/faceid.py @@ -75,18 +75,14 @@ def face_id( script_callbacks.before_process_callback(p) with context_hypertile_vae(p), context_hypertile_unet(p), devices.inference_context(): - with devices.autocast(): - p.init(p.all_prompts, p.all_seeds, p.all_subseeds) - + p.init(p.all_prompts, p.all_seeds, p.all_subseeds) ip_ckpt = FACEID_MODELS[model] folder, filename = os.path.split(ip_ckpt) basename, _ext = os.path.splitext(filename) model_path = hf.hf_hub_download(repo_id=folder, filename=filename, cache_dir=shared.opts.diffusers_dir) - if model_path is None: shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}") return None - if override: shared.sd_model.scheduler = diffusers.DDIMScheduler( num_train_timesteps=1000, @@ -97,7 +93,6 @@ def face_id( set_alpha_to_one=False, steps_offset=1, ) - if faceid_model_weights is None or faceid_model_name != model or not cache: shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}") faceid_model_weights = torch.load(model_path, map_location="cpu") @@ -108,7 +103,6 @@ def face_id( image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" original_load_ip_adapter = IPAdapterFaceIDPlusXL.load_ip_adapter IPAdapterFaceIDPlusXL.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceIDPlusXL( sd_pipe=shared.sd_model, image_encoder_path=image_encoder_path, @@ -121,7 +115,6 @@ def face_id( elif "XL" in model: original_load_ip_adapter = IPAdapterFaceIDXL.load_ip_adapter IPAdapterFaceIDXL.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceIDXL( sd_pipe=shared.sd_model, ip_ckpt=model_path, @@ -133,7 +126,6 @@ def face_id( elif "Plus" in model: original_load_ip_adapter = IPAdapterFaceIDPlus.load_ip_adapter IPAdapterFaceIDPlus.load_ip_adapter = hijack_load_ip_adapter - image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K" faceid_model = IPAdapterFaceIDPlus( sd_pipe=shared.sd_model, @@ -147,7 +139,6 @@ def face_id( elif "Portrait" in model: original_load_ip_adapter = IPAdapterFaceIDPortrait.load_ip_adapter IPAdapterFaceIDPortrait.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceIDPortrait( sd_pipe=shared.sd_model, ip_ckpt=model_path, @@ -159,7 +150,6 @@ def face_id( else: original_load_ip_adapter = IPAdapterFaceID.load_ip_adapter IPAdapterFaceID.load_ip_adapter = hijack_load_ip_adapter - faceid_model = IPAdapterFaceID( sd_pipe=shared.sd_model, ip_ckpt=model_path, @@ -171,10 +161,8 @@ def face_id( shortcut = "v2" in model faceid_model_name = model - face_embeds = [] face_images = [] - for i, source_image in enumerate(source_images): np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR) faces = app.get(np_image) @@ -204,16 +192,12 @@ def face_id( # optional generate dict if shortcut is not None: ip_model_dict["shortcut"] = shortcut - if "Plus" in model: ip_model_dict["s_scale"] = structure - shared.log.debug(f"FaceID args: {ip_model_dict}") if "Plus" in model: ip_model_dict["face_image"] = face_images - ip_model_dict["faceid_embeds"] = face_embeds # overwrite placeholder - faceid_model.set_scale(scale) extra_network_data = None @@ -223,20 +207,16 @@ def face_id( p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size] p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts) p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size] - if not p.disable_extra_networks: with devices.autocast(): extra_networks.activate(p, extra_network_data) - ip_model_dict.update({ "prompt": p.prompts, "negative_prompt": p.negative_prompts, "seed": int(p.seeds[0]), }) - debug(f"FaceID: {ip_model_dict}") res = faceid_model.generate(**ip_model_dict) - if isinstance(res, list): processed_images += res @@ -246,11 +226,9 @@ def face_id( if not cache: faceid_model_weights = None faceid_model_name = None - devices.torch_gc() ipadapter.unapply(p.sd_model) - if not p.disable_extra_networks: extra_networks.deactivate(p, extra_network_data) @@ -258,10 +236,8 @@ def face_id( finally: if faceid_model is not None and original_load_ip_adapter is not None: faceid_model.__class__.load_ip_adapter = original_load_ip_adapter - if not shared.opts.cuda_compile: sd_models.apply_token_merging(p.sd_model, 0) - script_callbacks.after_process_callback(p) return processed_images From 03ec491a694fbb8f34f98d7dead41869c2dcc939 Mon Sep 17 00:00:00 2001 From: Jonas Kanafani Date: Sat, 24 Feb 2024 16:11:22 +0100 Subject: [PATCH 17/44] Add pytorch nightly support for ROCm 6.0 (installer) (dev) --- installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer.py b/installer.py index 1ee471bd3..2b2f80321 100644 --- a/installer.py +++ b/installer.py @@ -488,7 +488,7 @@ def check_torch(): log.info('Using CPU-only torch') torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision') else: - if rocm_ver in {"5.7"}: + if rocm_ver in {"5.7", "6.0"}: torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}') elif rocm_ver in {"5.5", "5.6"}: torch_command = os.environ.get('TORCH_COMMAND', f'torch torchvision --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}') From 17f2f8d98f99ebb9d7eb30909bdc5083ad8bf276 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 11:04:01 -0500 Subject: [PATCH 18/44] add include mask in output, improve model offload compatibility --- CHANGELOG.md | 2 ++ TODO.md | 5 ++--- modules/control/run.py | 6 ++++++ modules/processing.py | 4 ++++ modules/processing_diffusers.py | 10 +++------- modules/sd_models.py | 6 ++++++ modules/shared.py | 1 + scripts/differential_diffusion.py | 28 ++++++++++++++++------------ 8 files changed, 40 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82aa9c037..bc1fa1e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,13 @@ - based on [VGen](https://huggingface.co/ali-vilab/i2vgen-xl) - **Improvements** - **FaceID** extend support for LoRA, HyperTile and FreeU, thanks @Trojaner + - new setting in image options *include mask in output* - default theme updates and additional built-in theme *black-gray* - **Internal** - remove obsolete textual inversion training code - remove obsolete hypernetworks training code - **Fixes** + - improve model offload compatibility - fix extra networks refresh - improve ZLUDA installer when using `--use-zluda` cli param, thanks @lshqqytiger diff --git a/TODO.md b/TODO.md index 03af7e25b..69c6c1311 100644 --- a/TODO.md +++ b/TODO.md @@ -7,11 +7,10 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - defork - stable cascade: - ipadapter masking: -- init latents: variations, tiling, img2img - x-adapter: -- diffusers public callbacks -- video2video - async lowvram: +- init latents: variations, tiling, img2img +- diffusers public callbacks - remove builtin: controlnet - remove builtin: image-browser diff --git a/modules/control/run.py b/modules/control/run.py index 7f359d240..94e38a8fa 100644 --- a/modules/control/run.py +++ b/modules/control/run.py @@ -482,6 +482,8 @@ def control_run(units: List[unit.Unit], inputs, inits, mask, unit_type: str, is_ debug(f'Control exec pipeline: task={sd_models.get_diffusers_task(pipe)} class={pipe.__class__}') debug(f'Control exec pipeline: p={vars(p)}') debug(f'Control exec pipeline: args={p.task_args} image={p.task_args.get("image", None)} control={p.task_args.get("control_image", None)} mask={p.task_args.get("mask_image", None) or p.image_mask} ref={p.task_args.get("ref_image", None)}') + if sd_models.get_diffusers_task(pipe) != sd_models.DiffusersTaskType.TEXT_2_IMAGE: # force vae back to gpu if not in txt2img mode + sd_models.move_model(pipe.vae, devices.device) p.scripts = scripts.scripts_control p.script_args = input_script_args processed = p.scripts.run(p, *input_script_args) @@ -508,6 +510,10 @@ def control_run(units: List[unit.Unit], inputs, inits, mask, unit_type: str, is_ output_image = images.resize_image(resize_mode_after, output_image, width_after, height_after, resize_name_after) output_images.append(output_image) + if shared.opts.include_mask: + if processed_image is not None and isinstance(processed_image, Image.Image): + output_images.append(processed_image) + if is_generator: image_txt = f'{output_image.width}x{output_image.height}' if output_image is not None else 'None' if video is not None: diff --git a/modules/processing.py b/modules/processing.py index b11cbe60a..521d4502b 100644 --- a/modules/processing.py +++ b/modules/processing.py @@ -396,6 +396,10 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed: if not p.disable_extra_networks: extra_networks.deactivate(p, extra_network_data) + if shared.opts.include_mask: + if getattr(p, 'image_mask', None) is not None and isinstance(p.image_mask, Image.Image): + output_images.append(p.image_mask) + processed = Processed( p, images_list=output_images, diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index e04513398..254f94d72 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -345,7 +345,6 @@ def process_diffusers(p: processing.StableDiffusionProcessing): p.task_args['sag_scale'] = p.sag_scale else: shared.log.warning(f'SAG incompatible scheduler: current={sd_model.scheduler.__class__.__name__} supported={supported}') - if shared.opts.cuda_compile_backend == "olive-ai": sd_model = olive_check_parameters_changed(p, is_refiner_enabled()) if sd_model.__class__.__name__ == "OnnxRawPipeline": @@ -362,12 +361,6 @@ def process_diffusers(p: processing.StableDiffusionProcessing): shared.sd_model = orig_pipeline return results - if shared.opts.diffusers_move_base: - sd_models.move_model(shared.sd_model, devices.device) - - # recompile if a parameter changes - sd_models_compile.openvino_recompile_model(p, hires=False, refiner=False) - # pipeline type is set earlier in processing, but check for sanity is_control = getattr(p, 'is_control', False) is True has_images = len(getattr(p, 'init_images' ,[])) > 0 @@ -378,6 +371,9 @@ def process_diffusers(p: processing.StableDiffusionProcessing): if len(getattr(p, 'init_images' ,[])) == 0: p.init_images = [TF.to_pil_image(torch.rand((3, getattr(p, 'height', 512), getattr(p, 'width', 512))))] + sd_models.move_model(shared.sd_model, devices.device) + sd_models_compile.openvino_recompile_model(p, hires=False, refiner=False) # recompile if a parameter changes + use_refiner_start = is_txt2img() and is_refiner_enabled() and not p.is_hr_pass and p.refiner_start > 0 and p.refiner_start < 1 use_denoise_start = not is_txt2img() and p.refiner_start > 0 and p.refiner_start < 1 diff --git a/modules/sd_models.py b/modules/sd_models.py index d2c5aaaf0..2b80c0fdf 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -742,6 +742,12 @@ def set_diffuser_options(sd_model, vae = None, op: str = 'model'): def move_model(model, device=None, force=False): if model is not None: + if getattr(model, 'vae', None) is not None and get_diffusers_task(model) != DiffusersTaskType.TEXT_2_IMAGE: + if device == devices.device: # force vae back to gpu if not in txt2img mode + model.vae.to(device) + if hasattr(model.vae, '_hf_hook'): + debug_move(f'Model move: to={device} class={model.vae.__class__} function={sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access + model.vae._hf_hook.execution_device = device # pylint: disable=protected-access if getattr(model, 'has_accelerate', False) and not force: return debug_move(f'Model move: to={device} class={model.__class__} function={sys._getframe(1).f_code.co_name}') # pylint: disable=protected-access diff --git a/modules/shared.py b/modules/shared.py index f07c079b5..6a1e4039c 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -507,6 +507,7 @@ options_templates.update(options_section(('saving-images', "Image Options"), { "img_max_size_mp": OptionInfo(250, "Maximum image size (MP)", gr.Slider, {"minimum": 100, "maximum": 2000, "step": 1}), "webp_lossless": OptionInfo(False, "WebP lossless compression"), "save_selected_only": OptionInfo(True, "Save only saves selected image"), + "include_mask": OptionInfo(False, "Include mask in outputs"), "samples_save_zip": OptionInfo(True, "Create ZIP archive"), "image_sep_metadata": OptionInfo("

Metadata/Logging

", "", gr.HTML), diff --git a/scripts/differential_diffusion.py b/scripts/differential_diffusion.py index e876f05ed..f0cfbf2eb 100644 --- a/scripts/differential_diffusion.py +++ b/scripts/differential_diffusion.py @@ -1518,7 +1518,7 @@ class StableDiffusionDiffImg2ImgPipeline(DiffusionPipeline): negative_prompt=None, prompt_embeds: Optional[torch.FloatTensor] = None, negative_prompt_embeds: Optional[torch.FloatTensor] = None, - lora_scale: Optional[float] = None, + lora_scale: Optional[float] = None, # pylint: disable=unused-argument clip_skip: Optional[int] = None, ): if prompt is not None and isinstance(prompt, str): @@ -1892,11 +1892,11 @@ class Script(scripts.Script): image = gr.Image(label="Image map", show_label=False, type="pil", source="upload", interactive=True, tool="editor", visible=True, image_mode='RGB') return enabled, strength, invert, model, image - def depthmap(self, image_init: Image.Image, image_map: Image.Image, model: str, strength: float, invert: bool, output_type="tensor"): + def depthmap(self, image_init: Image.Image, image_map: Image.Image, model: str, strength: float, invert: bool): global detector # pylint: disable=global-statement from modules.control.proc.dpt import DPTDetector if image_init is None: - return None, None + return None, None, None image_map = None if image_map is not None: image_map = image_map.resize(image_init.size, Image.Resampling.LANCZOS) @@ -1916,14 +1916,14 @@ class Script(scripts.Script): init_img_hash = hashlib.sha256(image_map.tobytes()).hexdigest()[0:8] # pylint: disable=attribute-defined-outside-init images.save_image(image_map, path=shared.opts.outdir_init_images, basename=None, forced_filename=init_img_hash, suffix="-init-image") else: - return None, None - if output_type == "tensor": - image_map = transforms.ToTensor()(image_map) - image_map = image_map.to(devices.device) - image_init = 2 * transforms.ToTensor()(image_init) - 1 - image_init = image_init.unsqueeze(0) - image_init = image_init.to(devices.device) - return image_init, image_map + return None, None, None + image_mask = image_map.copy() + image_map = transforms.ToTensor()(image_map) + image_map = image_map.to(devices.device) + image_init = 2 * transforms.ToTensor()(image_init) - 1 + image_init = image_init.unsqueeze(0) + image_init = image_init.to(devices.device) + return image_init, image_map, image_mask def run(self, p: processing.StableDiffusionProcessingImg2Img, enabled, strength, invert, model, image): # pylint: disable=arguments-differ if not enabled: @@ -1935,7 +1935,7 @@ class Script(scripts.Script): shared.log.error('Differential-diffusion: no input images') return - image_init, image_map = self.depthmap(p.init_images[0], image, model, strength, invert, output_type="tensor") + image_init, image_map, image_mask = self.depthmap(p.init_images[0], image, model, strength, invert) if image_map is None: shared.log.error('Differential-diffusion: no image map') return @@ -1974,6 +1974,7 @@ class Script(scripts.Script): p.task_args['original_image'] = image_init shared.log.debug(f'Differential-diffusion: pipeline={pipe.__class__.__name__} strength={strength} model={model} auto={image is None}') shared.sd_model = pipe + sd_models.move_model(pipe.vae, devices.device, force=True) except Exception as e: shared.log.error(f'Differential-diffusion: pipeline creation failed: {e}') errors.display(e, 'Differential-diffusion: pipeline creation failed') @@ -1981,6 +1982,9 @@ class Script(scripts.Script): # run pipeline processed: processing.Processed = processing.process_images(p) # runs processing using main loop + if shared.opts.include_mask: + if image_mask is not None and isinstance(image_mask, Image.Image): + processed.images.append(image_mask) # restore pipeline and params pipe = None From 709a93a0f20bfcce8e22e7581525d0d7a4d46922 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 11:06:12 -0500 Subject: [PATCH 19/44] update changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc1fa1e76..1245287da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,15 +8,16 @@ - based on [VGen](https://huggingface.co/ali-vilab/i2vgen-xl) - **Improvements** - **FaceID** extend support for LoRA, HyperTile and FreeU, thanks @Trojaner - - new setting in image options *include mask in output* + - new setting in image options: *include mask in output* - default theme updates and additional built-in theme *black-gray* + - add **ROCm** 6.0 nightly option to installer, thanks @jicka - **Internal** - remove obsolete textual inversion training code - remove obsolete hypernetworks training code - **Fixes** - improve model offload compatibility - fix extra networks refresh - - improve ZLUDA installer when using `--use-zluda` cli param, thanks @lshqqytiger + - improve ZLUDA installer with `--use-zluda` cli param, thanks @lshqqytiger ## Update for 2024-02-22 From 810fd8b970bd02c71f4e5bc752a162f5e82a1f40 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 11:52:38 -0500 Subject: [PATCH 20/44] theme tweaks --- TODO.md | 1 + html/locale_en.json | 2 +- javascript/sdnext.css | 11 ++++++----- modules/sd_hijack_hypertile.py | 5 +++-- modules/ui_sections.py | 2 +- wiki | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/TODO.md b/TODO.md index 69c6c1311..dab3a98fe 100644 --- a/TODO.md +++ b/TODO.md @@ -5,6 +5,7 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma ## Candidates for next release - defork +- stable diffusion 3.0 - stable cascade: - ipadapter masking: - x-adapter: diff --git a/html/locale_en.json b/html/locale_en.json index e16e2c54c..85fbd3570 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -133,7 +133,7 @@ {"id":"","label":"Refiner start","localized":"","hint":"Refiner pass will start when base model is this much complete (set to 0 or 1 to run after full base model run)"}, {"id":"","label":"Refiner steps","localized":"","hint":"Number of steps to use for refiner pass"}, {"id":"","label":"Secondary CFG Scale","localized":"","hint":"CFG scale used for refiner pass"}, - {"id":"","label":"Guidance rescale","localized":"","hint":"Rescale CFG generated noise to avoid overexposed images"}, + {"id":"","label":"Rescale guidance","localized":"","hint":"Rescale CFG generated noise to avoid overexposed images"}, {"id":"","label":"Secondary Prompt","localized":"","hint":"Prompt used for both second encoder in base model (if it exists) and for refiner pass (if enabled)"}, {"id":"","label":"Secondary negative prompt","localized":"","hint":"Negative prompt used for both second encoder in base model (if it exists) and for refiner pass (if enabled)"}, {"id":"","label":"Width","localized":"","hint":"Image width"}, diff --git a/javascript/sdnext.css b/javascript/sdnext.css index 597c6b7cc..b72342356 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -1,5 +1,5 @@ @font-face { font-family: 'NotoSans'; font-display: swap; font-style: normal; font-weight: 100; src: local('NotoSans'), url('notosans-nerdfont-regular.ttf') } -:root { --left-column: 550px; } +:root { --left-column: 520px; } a { font-weight: bold; cursor: pointer; } h2 { margin-top: 1em !important; font-size: var(--text-xxl) !important; } footer { display: none; margin-top: 0 !important;} @@ -45,7 +45,7 @@ input[type='color'] { width: 64px; height: 32px; } .gradio-textbox { overflow: visible !important; } .gradio-radio { padding: 0 !important; width: max-content !important; } .gradio-slider { margin-right: var(--spacing-sm) !important; width: max-content !important } -.gradio-slider input[type="number"] { width: 6em; font-size: var(--text-xs); height: 16px; text-align: right; } +.gradio-slider input[type="number"] { width: 5em; font-size: var(--text-xs); height: 16px; text-align: right; padding: 0; } /* custom gradio elements */ .accordion-compact { padding: 8px 0px 4px 0px !important; } @@ -301,9 +301,10 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt --spacing-xxs: 1px; --spacing-xs: 2px; --spacing-sm: 3px; - --spacing-lg: 4px; - --spacing-xl: 5px; - --spacing-xxl: 6px; + --spacing-md: 4px; + --spacing-lg: 5px; + --spacing-xl: 6px; + --spacing-xxl: 7px; } @media (hover: none) and (pointer: coarse) { /* Apply different styles for devices with coarse pointers dependant on screen resolution */ diff --git a/modules/sd_hijack_hypertile.py b/modules/sd_hijack_hypertile.py index cbcd0360b..296ceefc5 100644 --- a/modules/sd_hijack_hypertile.py +++ b/modules/sd_hijack_hypertile.py @@ -22,6 +22,7 @@ error_reported = False reset_needed = False skip_hypertile = False + def iterative_closest_divisors(hw:int, aspect_ratio:float) -> tuple[int, int]: """ Finds h and w such that h*w = hw and h/w = aspect_ratio @@ -34,6 +35,7 @@ def iterative_closest_divisors(hw:int, aspect_ratio:float) -> tuple[int, int]: closest_pair = pairs[ratios.index(closest_ratio)] # closest pair of divisors to aspect_ratio return closest_pair + @cache def find_hw_candidates(hw:int, aspect_ratio:float) -> tuple[int, int]: """ @@ -96,7 +98,7 @@ def split_attention(layer: nn.Module, tile_size: int=256, min_tile_size: int=128 def self_attn_forward(forward: Callable) -> Callable: @wraps(forward) def wrapper(*args, **kwargs): - global height, width, max_h, max_w, reset_needed, error_reported, skip_hypertile # pylint: disable=global-statement + global height, width, max_h, max_w, reset_needed, error_reported # pylint: disable=global-statement if skip_hypertile: return forward(*args, **kwargs) x = args[0] @@ -198,7 +200,6 @@ def context_hypertile_vae(p): return split_attention(vae, tile_size=tile_size, min_tile_size=128, swap_size=shared.opts.hypertile_vae_swap_size) - def context_hypertile_unet(p): from modules import shared if p.sd_model is None or not shared.opts.hypertile_unet_enabled: diff --git a/modules/ui_sections.py b/modules/ui_sections.py index f5ccb41de..7a958399c 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -106,7 +106,7 @@ def create_advanced_inputs(tab): cfg_end = gr.Slider(minimum=0.0, maximum=1.0, step=0.1, label='CFG end', value=1.0, elem_id=f"{tab}_cfg_end") with gr.Row(): image_cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='Secondary guidance', value=6.0, elem_id=f"{tab}_image_cfg_scale") - diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id=f"{tab}_image_cfg_rescale", visible=shared.backend == shared.Backend.DIFFUSERS) + diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Rescale guidance', value=0.7, elem_id=f"{tab}_image_cfg_rescale", visible=shared.backend == shared.Backend.DIFFUSERS) diffusers_sag_scale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Attention guidance', value=0.0, elem_id=f"{tab}_image_sag_scale", visible=shared.backend == shared.Backend.DIFFUSERS) with gr.Row(): clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=0, maximum=12, step=0.1, elem_id=f"{tab}_clip_skip", interactive=True) diff --git a/wiki b/wiki index ddd8158ac..0c9322422 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit ddd8158ac1b86cfaba1b5fa9929bb5214775bb9f +Subproject commit 0c9322422f3aca5cf78e0310e87d1767c3242552 From ffb8f16b7b0bf6cefa9c32faa06c8515a34889fe Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 24 Feb 2024 14:42:26 -0500 Subject: [PATCH 21/44] add vqa models to interrogate --- CHANGELOG.md | 2 + modules/ui_interrogate.py | 34 ++++++---- modules/vqa.py | 126 ++++++++++++++++++++++++++++++++++++++ wiki | 2 +- 4 files changed, 152 insertions(+), 12 deletions(-) create mode 100644 modules/vqa.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 1245287da..0ec6cdbdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - new module for creating videos from images - simply enable from *img2img -> scripts -> image2video* - based on [VGen](https://huggingface.co/ali-vilab/i2vgen-xl) +- **VQA** visual question & answer in interrogate + - with support for multiple variations of base models: *GIT, BLIP, ViLT, PIX* - **Improvements** - **FaceID** extend support for LoRA, HyperTile and FreeU, thanks @Trojaner - new setting in image options: *include mask in output* diff --git a/modules/ui_interrogate.py b/modules/ui_interrogate.py index bbf0cc074..930fe8bb9 100644 --- a/modules/ui_interrogate.py +++ b/modules/ui_interrogate.py @@ -185,6 +185,10 @@ def create_ui(): movement = gr.Label(label="Movement", num_top_classes=5) trending = gr.Label(label="Trending", num_top_classes=5) flavor = gr.Label(label="Flavor", num_top_classes=5) + with gr.Row(): + clip_model = gr.Dropdown([], value='ViT-L-14/openai', label='CLIP Model') + ui_common.create_refresh_button(clip_model, get_models, lambda: {"choices": get_models()}, 'refresh_interrogate_models') + mode = gr.Radio(['best', 'fast', 'classic', 'caption', 'negative'], label='Mode', value='best') with gr.Row(): btn_interrogate_img = gr.Button("Interrogate", variant='primary') btn_analyze_img = gr.Button("Analyze", variant='primary') @@ -193,6 +197,9 @@ def create_ui(): buttons = parameters_copypaste.create_buttons(["txt2img", "img2img", "extras", "control"]) for tabname, button in buttons.items(): parameters_copypaste.register_paste_params_button(parameters_copypaste.ParamBinding(paste_button=button, tabname=tabname, source_text_component=prompt, source_image_component=image,)) + btn_interrogate_img.click(interrogate_image, inputs=[image, clip_model, mode], outputs=prompt) + btn_analyze_img.click(analyze_image, inputs=[image, clip_model], outputs=[medium, artist, movement, trending, flavor]) + btn_unload.click(unload) with gr.Tab("Batch"): with gr.Row(): batch_files = gr.File(label="Files", show_label=True, file_count='multiple', file_types=['image'], type='file', interactive=True, height=100) @@ -204,16 +211,21 @@ def create_ui(): batch = gr.Text(label="Prompts", lines=10) with gr.Row(): write = gr.Checkbox(label='Write prompts to files', value=False) + with gr.Row(): + clip_model = gr.Dropdown([], value='ViT-L-14/openai', label='CLIP Model') + ui_common.create_refresh_button(clip_model, get_models, lambda: {"choices": get_models()}, 'refresh_interrogate_models') with gr.Row(): btn_interrogate_batch = gr.Button("Interrogate", variant='primary') - with gr.Column(): - with gr.Row(): - # clip_model = gr.Dropdown(get_models(), value='ViT-L-14/openai', label='CLIP Model') - clip_model = gr.Dropdown([], value='ViT-L-14/openai', label='CLIP Model') - ui_common.create_refresh_button(clip_model, get_models, lambda: {"choices": get_models()}, 'refresh_interrogate_models') - with gr.Row(): - mode = gr.Radio(['best', 'fast', 'classic', 'caption', 'negative'], label='Mode', value='best') - btn_interrogate_img.click(interrogate_image, inputs=[image, clip_model, mode], outputs=prompt) - btn_analyze_img.click(analyze_image, inputs=[image, clip_model], outputs=[medium, artist, movement, trending, flavor]) - btn_interrogate_batch.click(interrogate_batch, inputs=[batch_files, batch_folder, batch_str, clip_model, mode, write], outputs=[batch]) - btn_unload.click(unload) + btn_interrogate_batch.click(interrogate_batch, inputs=[batch_files, batch_folder, batch_str, clip_model, mode, write], outputs=[batch]) + with gr.Tab("VQA"): + from modules import vqa + with gr.Row(): + vqa_image = gr.Image(type='pil', label="Image") + with gr.Row(): + vqa_question = gr.Textbox(label="Question") + with gr.Row(): + vqa_answer = gr.Textbox(label="Answer", lines=3) + with gr.Row(): + vqa_model = gr.Dropdown(list(vqa.MODELS), value='None', label='VQA Model') + vqa_submit = gr.Button("Interrogate", variant='primary') + vqa_submit.click(vqa.interrogate, inputs=[vqa_question, vqa_image, vqa_model], outputs=[vqa_answer]) diff --git a/modules/vqa.py b/modules/vqa.py new file mode 100644 index 000000000..8a9aa3415 --- /dev/null +++ b/modules/vqa.py @@ -0,0 +1,126 @@ +import torch +import transformers +from PIL import Image +from modules import shared, devices + + +processor = None +model = None +loaded: str = None +MODELS = { + "None": None, + "GIT TextCaps Base": "microsoft/git-base-textcaps", # 0.7GB + "GIT VQA Base": "microsoft/git-base-vqav2", # 0.7GB + "GIT VQA Large": "microsoft/git-large-vqav2", # 1.6GB + "BLIP Base": "Salesforce/blip-vqa-base", # 1.5GB + "BLIP Large": "Salesforce/blip-vqa-capfilt-large", # 1.5GB + "ViLT Base": "dandelin/vilt-b32-finetuned-vqa", # 0.5GB + "Pix Textcaps": "google/pix2struct-textcaps-base", # 1.1GB +} + + +def git(question: str, image: Image.Image, repo: str = None): + global processor, model, loaded # pylint: disable=global-statement + if model is None or loaded != repo: + model = transformers.GitForCausalLM.from_pretrained(repo) + processor = transformers.GitProcessor.from_pretrained(repo) + loaded = repo + model.to(devices.device, devices.dtype) + shared.log.debug(f'VQA: class={model.__class__.__name__} processor={processor.__class__} model={repo}') + + pixel_values = processor(images=image, return_tensors="pt").pixel_values + git_dict = {} + git_dict['pixel_values'] = pixel_values.to(devices.device, devices.dtype) + if len(question) > 0: + input_ids = processor(text=question, add_special_tokens=False).input_ids + input_ids = [processor.tokenizer.cls_token_id] + input_ids + input_ids = torch.tensor(input_ids).unsqueeze(0) + git_dict['input_ids'] = input_ids.to(devices.device) + with devices.inference_context(): + generated_ids = model.generate(**git_dict) + response = processor.batch_decode(generated_ids, skip_special_tokens=True)[0] + + model.to(devices.cpu) + shared.log.debug(f'VQA: response={response}') + return response + + +def blip(question: str, image: Image.Image, repo: str = None): + global processor, model, loaded # pylint: disable=global-statement + if model is None or loaded != repo: + model = transformers.BlipForQuestionAnswering.from_pretrained(repo) + processor = transformers.BlipProcessor.from_pretrained(repo) + loaded = repo + model.to(devices.device, devices.dtype) + inputs = processor(image, question, return_tensors="pt") + inputs = inputs.to(devices.device, devices.dtype) + with devices.inference_context(): + outputs = model.generate(**inputs) + response = processor.decode(outputs[0], skip_special_tokens=True) + + model.to(devices.cpu) + shared.log.debug(f'VQA: response={response}') + return response + + +def vilt(question: str, image: Image.Image, repo: str = None): + global processor, model, loaded # pylint: disable=global-statement + if model is None or loaded != repo: + model = transformers.ViltForQuestionAnswering.from_pretrained(repo) + processor = transformers.ViltProcessor.from_pretrained(repo) + loaded = repo + model.to(devices.device) + shared.log.debug(f'VQA: class={model.__class__.__name__} processor={processor.__class__} model={repo}') + + inputs = processor(image, question, return_tensors="pt") + inputs = inputs.to(devices.device) + with devices.inference_context(): + outputs = model(**inputs) + logits = outputs.logits + idx = logits.argmax(-1).item() + response = model.config.id2label[idx] + + model.to(devices.cpu) + shared.log.debug(f'VQA: response={response}') + return response + + +def pix(question: str, image: Image.Image, repo: str = None): + global processor, model, loaded # pylint: disable=global-statement + if model is None or loaded != repo: + model = transformers.Pix2StructForConditionalGeneration.from_pretrained(repo) + processor = transformers.Pix2StructProcessor.from_pretrained(repo) + loaded = repo + model.to(devices.device) + shared.log.debug(f'VQA: class={model.__class__.__name__} processor={processor.__class__} model={repo}') + + if len(question) > 0: + inputs = processor(images=image, text=question, return_tensors="pt").to(devices.device) + else: + inputs = processor(images=image, return_tensors="pt").to(devices.device) + with devices.inference_context(): + outputs = model.generate(**inputs) + response = processor.decode(outputs[0], skip_special_tokens=True) + + model.to(devices.cpu) + shared.log.debug(f'VQA: response={response}') + return response + + +def interrogate(vqa_question, vqa_image, vqa_model): + vqa_model = MODELS.get(vqa_model, None) + shared.log.debug(f'VQA: model="{vqa_model}" question={vqa_question} image={vqa_image}') + if vqa_image is None: + return 'no image provided' + if vqa_model is None: + return 'no model selected' + if 'git' in vqa_model.lower(): + return git(vqa_question, vqa_image, vqa_model) + if 'vilt' in vqa_model.lower(): + return vilt(vqa_question, vqa_image, vqa_model) + if 'blip' in vqa_model.lower(): + return blip(vqa_question, vqa_image, vqa_model) + if 'pix' in vqa_model.lower(): + return pix(vqa_question, vqa_image, vqa_model) + else: + return 'unknown model' diff --git a/wiki b/wiki index 0c9322422..71c8836ae 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 0c9322422f3aca5cf78e0310e87d1767c3242552 +Subproject commit 71c8836ae428b6929e544dfa8d9ad6293bfdb976 From f73e3a3bcf6a503f1599aa72a264f76c93381e81 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sun, 25 Feb 2024 08:09:43 -0500 Subject: [PATCH 22/44] exception handler for memmon --- CHANGELOG.md | 3 ++- modules/memmon.py | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ec6cdbdb..d7bb8c847 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2024-02-24 +## Update for 2024-02-25 - **Image2Video** - new module for creating videos from images @@ -19,6 +19,7 @@ - **Fixes** - improve model offload compatibility - fix extra networks refresh + - exception handler around vram memory stats gather - improve ZLUDA installer with `--use-zluda` cli param, thanks @lshqqytiger ## Update for 2024-02-22 diff --git a/modules/memmon.py b/modules/memmon.py index ceb53d972..6887e1e1c 100644 --- a/modules/memmon.py +++ b/modules/memmon.py @@ -28,12 +28,15 @@ class MemUsageMonitor(): def reset(self): if not self.disabled: - torch.cuda.reset_peak_memory_stats(self.device) - self.data['retries'] = 0 - self.data['oom'] = 0 - # torch.cuda.reset_accumulated_memory_stats(self.device) - # torch.cuda.reset_max_memory_allocated(self.device) - # torch.cuda.reset_max_memory_cached(self.device) + try: + torch.cuda.reset_peak_memory_stats(self.device) + self.data['retries'] = 0 + self.data['oom'] = 0 + # torch.cuda.reset_accumulated_memory_stats(self.device) + # torch.cuda.reset_max_memory_allocated(self.device) + # torch.cuda.reset_max_memory_cached(self.device) + except Exception: + pass def read(self): if not self.disabled: From a13335a6571c8d29f2b1dd5df0ff4307242fdeba Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 24 Feb 2024 21:20:09 -0600 Subject: [PATCH 23/44] Diffusers tiling --- modules/processing_diffusers.py | 8 ++++++++ modules/ui_sections.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index 254f94d72..fc64724ac 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -37,6 +37,13 @@ def process_diffusers(p: processing.StableDiffusionProcessing): for j in range(len(decoded)): images.save_image(decoded[j], path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix=suffix) + def apply_circular(enable): + try: + for layer in [layer for layer in shared.sd_model.unet.modules() if type(layer) is torch.nn.Conv2d]: + layer.padding_mode = 'circular' if enable else 'zeros' + except Exception as e: + debug(f"Diffusers tiling failed: {e}") + def diffusers_callback_legacy(step: int, timestep: int, latents: typing.Union[torch.FloatTensor, np.ndarray]): if isinstance(latents, np.ndarray): # latents from Onnx pipelines is ndarray. latents = torch.from_numpy(latents) @@ -159,6 +166,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): def set_pipeline_args(model, prompts: list, negative_prompts: list, prompts_2: typing.Optional[list]=None, negative_prompts_2: typing.Optional[list]=None, desc:str='', **kwargs): t0 = time.time() + apply_circular(p.tiling) if hasattr(model, "set_progress_bar_config"): model.set_progress_bar_config(bar_format='Progress {rate_fmt}{postfix} {bar} {percentage:3.0f}% {n_fmt}/{total_fmt} {elapsed} {remaining} ' + '\x1b[38;5;71m' + desc, ncols=80, colour='#327fba') args = {} diff --git a/modules/ui_sections.py b/modules/ui_sections.py index 7a958399c..2d099eb4f 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -115,7 +115,7 @@ def create_advanced_inputs(tab): with gr.Row(): full_quality = gr.Checkbox(label='Full quality', value=True, elem_id=f"{tab}_full_quality") restore_faces = gr.Checkbox(label='Face restore', value=False, visible=len(shared.face_restorers) > 1, elem_id=f"{tab}_restore_faces") - tiling = gr.Checkbox(label='Tiling', value=False, elem_id=f"{tab}_tiling", visible=shared.backend == shared.Backend.ORIGINAL) + tiling = gr.Checkbox(label='Tiling', value=False, elem_id=f"{tab}_tiling", visible=True) return cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, diffusers_sag_scale, cfg_end, full_quality, restore_faces, tiling def create_correction_inputs(tab): From 316b74cd15df9c13522742035d73856666b577de Mon Sep 17 00:00:00 2001 From: AI-Casanova <54461896+AI-Casanova@users.noreply.github.com> Date: Sat, 24 Feb 2024 21:56:48 -0600 Subject: [PATCH 24/44] VAE circular padding --- modules/processing_diffusers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index fc64724ac..fc8f95c7a 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -41,6 +41,8 @@ def process_diffusers(p: processing.StableDiffusionProcessing): try: for layer in [layer for layer in shared.sd_model.unet.modules() if type(layer) is torch.nn.Conv2d]: layer.padding_mode = 'circular' if enable else 'zeros' + for layer in [layer for layer in shared.sd_model.vae.modules() if type(layer) is torch.nn.Conv2d]: + layer.padding_mode = 'circular' if enable else 'zeros' except Exception as e: debug(f"Diffusers tiling failed: {e}") From 81ddae9068be13f644ac2f54775aa3169564d95e Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sun, 25 Feb 2024 08:10:59 -0500 Subject: [PATCH 25/44] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7bb8c847..2552eb46e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - with support for multiple variations of base models: *GIT, BLIP, ViLT, PIX* - **Improvements** - **FaceID** extend support for LoRA, HyperTile and FreeU, thanks @Trojaner + - **Tiling** now extends to both Unet and VAE producing smoother outputs, thanks @AI-Casanova - new setting in image options: *include mask in output* - default theme updates and additional built-in theme *black-gray* - add **ROCm** 6.0 nightly option to installer, thanks @jicka From bba2658e93eb1c793922e039b731c27d92f8d0cb Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 26 Feb 2024 09:47:13 -0500 Subject: [PATCH 26/44] fix sdp-memory-attention in original --- CHANGELOG.md | 3 ++- modules/sd_hijack.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2552eb46e..6ea35f244 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log for SD.Next -## Update for 2024-02-25 +## Update for 2024-02-26 - **Image2Video** - new module for creating videos from images @@ -20,6 +20,7 @@ - **Fixes** - improve model offload compatibility - fix extra networks refresh + - fix sdp memory attention in backend original - exception handler around vram memory stats gather - improve ZLUDA installer with `--use-zluda` cli param, thanks @lshqqytiger diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py index d2c31fffb..6360982b8 100644 --- a/modules/sd_hijack.py +++ b/modules/sd_hijack.py @@ -56,11 +56,11 @@ def apply_optimizations(): if can_use_sdp and shared.opts.cross_attention_optimization == "Scaled-Dot-Product": optimization_method = 'sdp' if 'Memory attention' in shared.opts.sdp_options: - ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.scaled_dot_product_no_mem_attention_forward - ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.sdp_no_mem_attnblock_forward - else: ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.scaled_dot_product_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.sdp_attnblock_forward + else: + ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.scaled_dot_product_no_mem_attention_forward + ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.sdp_no_mem_attnblock_forward if shared.xformers_available and shared.opts.cross_attention_optimization == "xFormers": ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward From 3488dd2cf6d2825dd40e65ae02a459e1c8830828 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Mon, 26 Feb 2024 17:38:09 -0500 Subject: [PATCH 27/44] use model yaml if present --- CHANGELOG.md | 2 ++ modules/sd_models.py | 41 ++++++++++++++++++++++++----------------- modules/shared_items.py | 2 ++ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea35f244..265604dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - new setting in image options: *include mask in output* - default theme updates and additional built-in theme *black-gray* - add **ROCm** 6.0 nightly option to installer, thanks @jicka + - support models with their own YAML model config files - **Internal** - remove obsolete textual inversion training code - remove obsolete hypernetworks training code @@ -21,6 +22,7 @@ - improve model offload compatibility - fix extra networks refresh - fix sdp memory attention in backend original + - fix autodetect v2.1 models - exception handler around vram memory stats gather - improve ZLUDA installer with `--use-zluda` cli param, thanks @lshqqytiger diff --git a/modules/sd_models.py b/modules/sd_models.py index 2b80c0fdf..f587a34b2 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -553,14 +553,16 @@ def detect_pipeline(f: str, op: str = 'model', warning=True): elif (size >= 316 and size <= 324) or (size >= 156 and size <= 164): # 320 or 160 warn(f'Model detected as VAE model, but attempting to load as model: {op}={f} size={size} MB') guess = 'VAE' - elif size >= 5351 and size <= 5359: # 5353 - guess = 'Stable Diffusion' # SD v2 + elif size >= 4970 and size <= 4976: # 4973 + guess = 'Stable Diffusion 2' # SD v2 but could be eps or v-prediction + # elif size < 0: # unknown + # guess = 'Stable Diffusion 2B' elif size >= 5791 and size <= 5799: # 5795 if shared.backend == shared.Backend.ORIGINAL: warn(f'Model detected as SD-XL refiner model, but attempting to load using backend=original: {op}={f} size={size} MB') if op == 'model': warn(f'Model detected as SD-XL refiner model, but attempting to load a base model: {op}={f} size={size} MB') - guess = 'Stable Diffusion XL' + guess = 'Stable Diffusion XL Refiner' elif (size >= 6611 and size <= 7220): # 6617, HassakuXL is 6776, monkrenRealisticINT_v10 is 7217 if shared.backend == shared.Backend.ORIGINAL: warn(f'Model detected as SD-XL base model, but attempting to load using backend=original: {op}={f} size={size} MB') @@ -758,6 +760,23 @@ def move_model(model, device=None, force=False): devices.torch_gc() +def get_load_config(model_file, model_type): + yaml = os.path.splitext(model_file)[0] + '.yaml' + if os.path.exists(yaml): + return yaml + elif model_type == 'Stable Diffusion': + return 'configs/v1-inference.yaml' + elif model_type == 'Stable Diffusion XL': + return 'configs/sd_xl_base.yaml' + elif model_type == 'Stable Diffusion XL Refiner': + return 'configs/sd_xl_refiner.yaml' + elif model_type == 'Stable Diffusion 2': + return None # dont know if its eps or v so let diffusers sort it out + # return 'configs/v2-inference-512-base.yaml' + # return 'configs/v2-inference-768-v.yaml' + return None + + def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'): # pylint: disable=unused-argument if shared.cmd_opts.profile: import cProfile @@ -926,20 +945,8 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No diffusers_load_config['force_zeros_for_empty_prompt '] = shared.opts.diffusers_force_zeros if shared.opts.diffusers_aesthetics_score: diffusers_load_config['requires_aesthetics_score'] = shared.opts.diffusers_aesthetics_score - if 'inpainting' in checkpoint_info.path.lower(): - diffusers_load_config['config_files'] = { - 'v1': 'configs/v1-inpainting-inference.yaml', - 'v2': 'configs/v2-inference-768-v.yaml', - 'xl': 'configs/sd_xl_base.yaml', - 'xl_refiner': 'configs/sd_xl_refiner.yaml', - } - else: - diffusers_load_config['config_files'] = { - 'v1': 'configs/v1-inference.yaml', - 'v2': 'configs/v2-inference-768-v.yaml', - 'xl': 'configs/sd_xl_base.yaml', - 'xl_refiner': 'configs/sd_xl_refiner.yaml', - } + # diffusers_load_config['config_files'] = get_load_config(checkpoint_info.path.lower()) + diffusers_load_config['original_config_file'] = get_load_config(checkpoint_info.path, model_type) if hasattr(pipeline, 'from_single_file'): diffusers_load_config['use_safetensors'] = True if shared.opts.disable_accelerate: diff --git a/modules/shared_items.py b/modules/shared_items.py index f87925e27..dc7fa185e 100644 --- a/modules/shared_items.py +++ b/modules/shared_items.py @@ -42,11 +42,13 @@ def get_pipelines(): pipelines = { # note: not all pipelines can be used manually as they require prior pipeline next to decoder pipeline 'Autodetect': None, 'Stable Diffusion': getattr(diffusers, 'StableDiffusionPipeline', None), + 'Stable Diffusion 2': getattr(diffusers, 'StableDiffusionPipeline', None), 'Stable Diffusion Inpaint': getattr(diffusers, 'StableDiffusionInpaintPipeline', None), 'Stable Diffusion Img2Img': getattr(diffusers, 'StableDiffusionImg2ImgPipeline', None), 'Stable Diffusion Instruct': getattr(diffusers, 'StableDiffusionInstructPix2PixPipeline', None), 'Stable Diffusion Upscale': getattr(diffusers, 'StableDiffusionUpscalePipeline', None), 'Stable Diffusion XL': getattr(diffusers, 'StableDiffusionXLPipeline', None), + 'Stable Diffusion XL Refiner': getattr(diffusers, 'StableDiffusionXLPipeline', None), 'Stable Diffusion XL Img2Img': getattr(diffusers, 'StableDiffusionXLImg2ImgPipeline', None), 'Stable Diffusion XL Inpaint': getattr(diffusers, 'StableDiffusionXLInpaintPipeline', None), 'Stable Diffusion XL Instruct': getattr(diffusers, 'StableDiffusionXLInstructPix2PixPipeline', None), From 36dac2af9c0351e01a80035d87b332484835514b Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 27 Feb 2024 07:46:28 -0500 Subject: [PATCH 28/44] extend use of move_model --- CHANGELOG.md | 3 +- README.md | 126 +++++++++++++++++----------- installer.py | 10 ++- modules/cmd_args.py | 1 - modules/control/units/controlnet.py | 8 +- modules/control/units/reference.py | 7 +- modules/control/units/t2iadapter.py | 8 +- modules/control/units/xs.py | 8 +- modules/sd_models.py | 6 +- wiki | 2 +- 10 files changed, 110 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 265604dd9..3a8d96737 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,8 @@ - remove obsolete textual inversion training code - remove obsolete hypernetworks training code - **Fixes** - - improve model offload compatibility + - improve model cpu offload compatibility + - improve model sequential offload compatibility - fix extra networks refresh - fix sdp memory attention in backend original - fix autodetect v2.1 models diff --git a/README.md b/README.md index a9c92b20b..9318ba1a5 100644 --- a/README.md +++ b/README.md @@ -56,19 +56,6 @@ For screenshots and informations on other available themes, see [Themes Wiki](ht Supports **SD 1.x** and **SD 2.x** models All other model types such as *SD-XL, LCM, PixArt, Segmind, Kandinsky, etc.* require backend **Diffusers** -## Control - -**SD.Next** comes with built-in control for all types of text2image, image2image, video2video and batch processing - -*Control interface*: -![Screenshot-Control](html/screenshot-control.jpg) - -*Control processors*: -![Screenshot-Process](html/screenshot-processors.jpg) - -*Masking*: -![Screenshot-Mask](html/screenshot-mask.jpg) - ## Model support Additional models will be added as they become available and there is public interest in them @@ -110,7 +97,6 @@ Also supported are modifiers such as: *InstantID*: ![Screenshot-InstantID](html/screenshot-instantid.jpg) - > [!IMPORTANT] > - Loading any model other than standard SD 1.x / SD 2.x requires use of backend **Diffusers** > - Loading any other models using **Original** backend is not supported @@ -151,51 +137,89 @@ Also supported are modifiers such as: Once SD.Next is installed, simply run `webui.ps1` or `webui.bat` (*Windows*) or `webui.sh` (*Linux or MacOS*) -Below is partial list of all available parameters, run `webui --help` for the full list: +List of available parameters, run `webui --help` for the full & up-to-date list: Server options: - --config CONFIG Use specific server configuration file, default: config.json - --ui-config UI_CONFIG Use specific UI configuration file, default: ui-config.json - --medvram Split model stages and keep only active part in VRAM, default: False - --lowvram Split model components and keep only active part in VRAM, default: False - --ckpt CKPT Path to model checkpoint to load immediately, default: None - --vae VAE Path to VAE checkpoint to load immediately, default: None - --data-dir DATA_DIR Base path where all user data is stored, default: - --models-dir MODELS_DIR Base path where all models are stored, default: models - --share Enable UI accessible through Gradio site, default: False - --insecure Enable extensions tab regardless of other options, default: False - --listen Launch web server using public IP address, default: False - --auth AUTH Set access authentication like "user:pwd,user:pwd"" - --autolaunch Open the UI URL in the system's default browser upon launch - --docs Mount API docs, default: False - --no-hashing Disable hashing of checkpoints, default: False - --no-metadata Disable reading of metadata from models, default: False - --backend {original,diffusers} force model pipeline type + --config CONFIG Use specific server configuration file, default: config.json + --ui-config UI_CONFIG Use specific UI configuration file, default: ui-config.json + --medvram Split model stages and keep only active part in VRAM, default: False + --lowvram Split model components and keep only active part in VRAM, default: False + --ckpt CKPT Path to model checkpoint to load immediately, default: None + --vae VAE Path to VAE checkpoint to load immediately, default: None + --data-dir DATA_DIR Base path where all user data is stored, default: + --models-dir MODELS_DIR Base path where all models are stored, default: models + --allow-code Allow custom script execution, default: False + --share Enable UI accessible through Gradio site, default: False + --insecure Enable extensions tab regardless of other options, default: False + --use-cpu USE_CPU [USE_CPU ...] Force use CPU for specified modules, default: [] + --listen Launch web server using public IP address, default: False + --port PORT Launch web server with given server port, default: 7860 + --freeze Disable editing settings + --auth AUTH Set access authentication like "user:pwd,user:pwd"" + --auth-file AUTH_FILE Set access authentication using file, default: None + --autolaunch Open the UI URL in the system's default browser upon launch + --docs Mount API docs, default: False + --api-only Run in API only mode without starting UI + --api-log Enable logging of all API requests, default: False + --device-id DEVICE_ID Select the default CUDA device to use, default: None + --cors-origins CORS_ORIGINS Allowed CORS origins as comma-separated list, default: None + --cors-regex CORS_REGEX Allowed CORS origins as regular expression, default: None + --tls-keyfile TLS_KEYFILE Enable TLS and specify key file, default: None + --tls-certfile TLS_CERTFILE Enable TLS and specify cert file, default: None + --tls-selfsign Enable TLS with self-signed certificates, default: False + --server-name SERVER_NAME Sets hostname of server, default: None + --no-hashing Disable hashing of checkpoints, default: False + --no-metadata Disable reading of metadata from models, default: False + --disable-queue Disable queues, default: False + --subpath SUBPATH Customize the URL subpath for usage with reverse proxy + --backend {original,diffusers} force model pipeline type + --allowed-paths ALLOWED_PATHS [ALLOWED_PATHS ...] add additional paths to paths allowed for web access Setup options: - --debug Run installer with debug logging, default: False - --reset Reset main repository to latest version, default: False - --upgrade Upgrade main repository to latest version, default: False - --requirements Force re-check of requirements, default: False - --quick Run with startup sequence only, default: False - --use-directml Use DirectML if no compatible GPU is detected, default: False - --use-openvino Use Intel OpenVINO backend, default: False - --use-ipex Force use Intel OneAPI XPU backend, default: False - --use-cuda Force use nVidia CUDA backend, default: False - --use-rocm Force use AMD ROCm backend, default: False - --use-xformers Force use xFormers cross-optimization, default: False - --skip-requirements Skips checking and installing requirements, default: False - --skip-extensions Skips running individual extension installers, default: False - --skip-git Skips running all GIT operations, default: False - --skip-torch Skips running Torch checks, default: False - --skip-all Skips running all checks, default: False - --experimental Allow unsupported versions of libraries, default: False - --reinstall Force reinstallation of all requirements, default: False - --safe Run in safe mode with no user extensions + --reset Reset main repository to latest version, default: False + --upgrade Upgrade main repository to latest version, default: False + --requirements Force re-check of requirements, default: False + --quick Bypass version checks, default: False + --use-directml Use DirectML if no compatible GPU is detected, default: False + --use-openvino Use Intel OpenVINO backend, default: False + --use-ipex Force use Intel OneAPI XPU backend, default: False + --use-cuda Force use nVidia CUDA backend, default: False + --use-rocm Force use AMD ROCm backend, default: False + --use-zluda Force use ZLUDA, AMD GPUs only, default: False + --use-xformers Force use xFormers cross-optimization, default: False + --skip-requirements Skips checking and installing requirements, default: False + --skip-extensions Skips running individual extension installers, default: False + --skip-git Skips running all GIT operations, default: False + --skip-torch Skips running Torch checks, default: False + --skip-all Skips running all checks, default: False + --skip-env Skips setting of env variables during startup, default: False + --experimental Allow unsupported versions of libraries, default: False + --reinstall Force reinstallation of all requirements, default: False + --test Run test only and exit + --version Print version information + --ignore Ignore any errors and attempt to continue + --safe Run in safe mode with no user extensions + Logging options: + --log LOG Set log file, default: None + --debug Run installer with debug logging, default: False + --profile Run profiler, default: False ## Notes +### Control + +**SD.Next** comes with built-in control for all types of text2image, image2image, video2video and batch processing + +*Control interface*: +![Screenshot-Control](html/screenshot-control.jpg) + +*Control processors*: +![Screenshot-Process](html/screenshot-processors.jpg) + +*Masking*: +![Screenshot-Mask](html/screenshot-mask.jpg) + ### **Extensions** SD.Next comes with several extensions pre-installed: diff --git a/installer.py b/installer.py index 2b2f80321..bccd86d30 100644 --- a/installer.py +++ b/installer.py @@ -1028,8 +1028,6 @@ def check_timestamp(): def add_args(parser): group = parser.add_argument_group('Setup options') - group.add_argument("--log", type=str, default=os.environ.get("SD_LOG", None), help="Set log file, default: %(default)s") - group.add_argument('--debug', default = os.environ.get("SD_DEBUG",False), action='store_true', help = "Run installer with debug logging, default: %(default)s") group.add_argument('--reset', default = os.environ.get("SD_RESET",False), action='store_true', help = "Reset main repository to latest version, default: %(default)s") group.add_argument('--upgrade', default = os.environ.get("SD_UPGRADE",False), action='store_true', help = "Upgrade main repository to latest version, default: %(default)s") group.add_argument('--requirements', default = os.environ.get("SD_REQUIREMENTS",False), action='store_true', help = "Force re-check of requirements, default: %(default)s") @@ -1039,6 +1037,7 @@ def add_args(parser): group.add_argument("--use-ipex", default = os.environ.get("SD_USEIPEX",False), action='store_true', help="Force use Intel OneAPI XPU backend, default: %(default)s") group.add_argument("--use-cuda", default = os.environ.get("SD_USECUDA",False), action='store_true', help="Force use nVidia CUDA backend, default: %(default)s") group.add_argument("--use-rocm", default = os.environ.get("SD_USEROCM",False), action='store_true', help="Force use AMD ROCm backend, default: %(default)s") + group.add_argument('--use-zluda', default=os.environ.get("SD_USEZLUDA", False), action='store_true', help = "Force use ZLUDA, AMD GPUs only, default: %(default)s") group.add_argument("--use-xformers", default = os.environ.get("SD_USEXFORMERS",False), action='store_true', help="Force use xFormers cross-optimization, default: %(default)s") group.add_argument('--skip-requirements', default = os.environ.get("SD_SKIPREQUIREMENTS",False), action='store_true', help = "Skips checking and installing requirements, default: %(default)s") group.add_argument('--skip-extensions', default = os.environ.get("SD_SKIPEXTENSION",False), action='store_true', help = "Skips running individual extension installers, default: %(default)s") @@ -1053,6 +1052,13 @@ def add_args(parser): group.add_argument('--ignore', default = os.environ.get("SD_IGNORE",False), action='store_true', help = "Ignore any errors and attempt to continue") group.add_argument('--safe', default = os.environ.get("SD_SAFE",False), action='store_true', help = "Run in safe mode with no user extensions") + group = parser.add_argument_group('Logging options') + group.add_argument("--log", type=str, default=os.environ.get("SD_LOG", None), help="Set log file, default: %(default)s") + group.add_argument('--debug', default = os.environ.get("SD_DEBUG",False), action='store_true', help = "Run installer with debug logging, default: %(default)s") + group.add_argument("--profile", default=os.environ.get("SD_PROFILE", False), action='store_true', help="Run profiler, default: %(default)s") + group.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help = "Mount API docs, default: %(default)s") + group.add_argument("--api-log", default=os.environ.get("SD_APILOG", False), action='store_true', help="Enable logging of all API requests, default: %(default)s") + def parse_args(parser): # command line args diff --git a/modules/cmd_args.py b/modules/cmd_args.py index dcec93c87..afbe239fe 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -27,7 +27,6 @@ group.add_argument("--auth-file", type=str, default=os.environ.get("SD_AUTHFILE" group.add_argument("--autolaunch", default=os.environ.get("SD_AUTOLAUNCH", False), action='store_true', help="Open the UI URL in the system's default browser upon launch") group.add_argument('--docs', default=os.environ.get("SD_DOCS", False), action='store_true', help = "Mount API docs, default: %(default)s") group.add_argument('--api-only', default=os.environ.get("SD_APIONLY", False), action='store_true', help = "Run in API only mode without starting UI") -group.add_argument("--api-log", default=os.environ.get("SD_APILOG", False), action='store_true', help="Enable logging of all API requests, default: %(default)s") group.add_argument("--device-id", type=str, default=os.environ.get("SD_DEVICEID", None), help="Select the default CUDA device to use, default: %(default)s") group.add_argument("--cors-origins", type=str, default=os.environ.get("SD_CORSORIGINS", None), help="Allowed CORS origins as comma-separated list, default: %(default)s") group.add_argument("--cors-regex", type=str, default=os.environ.get("SD_CORSREGEX", None), help="Allowed CORS origins as regular expression, default: %(default)s") diff --git a/modules/control/units/controlnet.py b/modules/control/units/controlnet.py index 3d98a4a1e..e407fa598 100644 --- a/modules/control/units/controlnet.py +++ b/modules/control/units/controlnet.py @@ -4,7 +4,7 @@ from typing import Union from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline, ControlNetModel, StableDiffusionControlNetPipeline, StableDiffusionXLControlNetPipeline from modules.control.units import detect from modules.shared import log, opts, listdir -from modules import errors +from modules import errors, sd_models what = 'ControlNet' @@ -193,7 +193,8 @@ class ControlNetPipeline(): scheduler=pipeline.scheduler, feature_extractor=getattr(pipeline, 'feature_extractor', None), controlnet=controlnet, # can be a list - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) elif detect.is_sd15(pipeline): self.pipeline = StableDiffusionControlNetPipeline( vae=pipeline.vae, @@ -205,7 +206,8 @@ class ControlNetPipeline(): requires_safety_checker=False, safety_checker=None, controlnet=controlnet, # can be a list - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) else: log.error(f'Control {what} pipeline: class={pipeline.__class__.__name__} unsupported model type') return diff --git a/modules/control/units/reference.py b/modules/control/units/reference.py index a8fca7790..bb24b96d2 100644 --- a/modules/control/units/reference.py +++ b/modules/control/units/reference.py @@ -4,6 +4,7 @@ import diffusers.utils from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline from modules.shared import log, opts from modules.control.units import detect +from modules import sd_models what = 'Reference' @@ -34,7 +35,8 @@ class ReferencePipeline(): unet=pipeline.unet, scheduler=pipeline.scheduler, feature_extractor=getattr(pipeline, 'feature_extractor', None), - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) elif detect.is_sd15(pipeline): cls = diffusers.utils.get_class_from_dynamic_module('stable_diffusion_reference', module_file='pipeline.py') self.pipeline = cls( @@ -46,7 +48,8 @@ class ReferencePipeline(): feature_extractor=getattr(pipeline, 'feature_extractor', None), requires_safety_checker=False, safety_checker=None, - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) else: log.error(f'Control {what} pipeline: class={pipeline.__class__.__name__} unsupported model type') return diff --git a/modules/control/units/t2iadapter.py b/modules/control/units/t2iadapter.py index 6514d0a63..b745d122a 100644 --- a/modules/control/units/t2iadapter.py +++ b/modules/control/units/t2iadapter.py @@ -3,7 +3,7 @@ import time from typing import Union from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline, T2IAdapter, MultiAdapter, StableDiffusionAdapterPipeline, StableDiffusionXLAdapterPipeline # pylint: disable=unused-import from modules.shared import log -from modules import errors +from modules import errors, sd_models from modules.control.units import detect @@ -128,7 +128,8 @@ class AdapterPipeline(): scheduler=pipeline.scheduler, feature_extractor=getattr(pipeline, 'feature_extractor', None), adapter=adapter, - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) elif detect.is_sd15(pipeline): self.pipeline = StableDiffusionAdapterPipeline( vae=pipeline.vae, @@ -140,7 +141,8 @@ class AdapterPipeline(): requires_safety_checker=False, safety_checker=None, adapter=adapter, - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) else: log.error(f'Control {what} pipeline: class={pipeline.__class__.__name__} unsupported model type') return diff --git a/modules/control/units/xs.py b/modules/control/units/xs.py index 4f5396356..1fc13ad3e 100644 --- a/modules/control/units/xs.py +++ b/modules/control/units/xs.py @@ -3,7 +3,7 @@ import time from typing import Union from diffusers import StableDiffusionPipeline, StableDiffusionXLPipeline from modules.shared import log, opts, listdir -from modules import errors +from modules import errors, sd_models from modules.control.units.xs_model import ControlNetXSModel from modules.control.units.xs_pipe import StableDiffusionControlNetXSPipeline, StableDiffusionXLControlNetXSPipeline from modules.control.units import detect @@ -126,7 +126,8 @@ class ControlNetXSPipeline(): scheduler=pipeline.scheduler, # feature_extractor=getattr(pipeline, 'feature_extractor', None), controlnet=controlnet, # can be a list - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) elif detect.is_sd15(pipeline): self.pipeline = StableDiffusionControlNetXSPipeline( vae=pipeline.vae, @@ -138,7 +139,8 @@ class ControlNetXSPipeline(): requires_safety_checker=False, safety_checker=None, controlnet=controlnet, # can be a list - ).to(pipeline.device) + ) + sd_models.move_model(self.pipeline, pipeline.device) else: log.error(f'Control {what} pipeline: class={pipeline.__class__.__name__} unsupported model type') return diff --git a/modules/sd_models.py b/modules/sd_models.py index f587a34b2..90fb37449 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -1130,7 +1130,8 @@ def switch_pipe(cls: diffusers.DiffusionPipeline, pipeline: diffusers.DiffusionP unet=pipeline.unet, scheduler=pipeline.scheduler, feature_extractor=getattr(pipeline, 'feature_extractor', None), - ).to(pipeline.device) + ) + move_model(new_pipe, pipeline.device) switch_mode = 'sdxl' elif 'tokenizer' in possible and hasattr(pipeline, 'tokenizer'): new_pipe = cls( @@ -1142,7 +1143,8 @@ def switch_pipe(cls: diffusers.DiffusionPipeline, pipeline: diffusers.DiffusionP feature_extractor=getattr(pipeline, 'feature_extractor', None), requires_safety_checker=False, safety_checker=None, - ).to(pipeline.device) + ) + move_model(new_pipe, pipeline.device) switch_mode = 'sd' else: shared.log.error(f'Pipeline switch error: {pipeline.__class__.__name__} unrecognized') diff --git a/wiki b/wiki index 71c8836ae..46e7d15eb 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 71c8836ae428b6929e544dfa8d9ad6293bfdb976 +Subproject commit 46e7d15ebc47858179cc8ef8f7c3d2f14e2489a0 From 21b92b0b5c6f49700c2c3ae247515a38b3a8c0a8 Mon Sep 17 00:00:00 2001 From: brknsoul Date: Tue, 27 Feb 2024 10:37:08 +1030 Subject: [PATCH 29/44] Update postprocessing_upscale.py --- scripts/postprocessing_upscale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/postprocessing_upscale.py b/scripts/postprocessing_upscale.py index 6f1783361..066aa30d6 100644 --- a/scripts/postprocessing_upscale.py +++ b/scripts/postprocessing_upscale.py @@ -16,7 +16,7 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing): with gr.Row(elem_id="extras_upscale"): with gr.Tabs(elem_id="extras_resize_mode"): with gr.TabItem('Scale by', elem_id="extras_scale_by_tab") as tab_scale_by: - upscaling_resize = gr.Slider(minimum=1.0, maximum=8.0, step=0.05, label="Resize", value=2.0, elem_id="extras_upscaling_resize") + upscaling_resize = gr.Slider(minimum=0.1, maximum=8.0, step=0.05, label="Resize", value=2.0, elem_id="extras_upscaling_resize") with gr.TabItem('Scale to', elem_id="extras_scale_to_tab") as tab_scale_to: with gr.Row(): From d179d8b6683fc06f34dd34cd8069d6c82c21b638 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 27 Feb 2024 09:15:17 -0500 Subject: [PATCH 30/44] update second pass behavior --- CHANGELOG.md | 5 ++ TODO.md | 1 + modules/processing_class.py | 16 +++--- modules/processing_diffusers.py | 91 +++++++++++++++++++-------------- modules/processing_helpers.py | 2 +- modules/processing_info.py | 8 +-- modules/ui_sections.py | 24 ++++----- modules/ui_txt2img.py | 12 +---- 8 files changed, 83 insertions(+), 76 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a8d96737..e3838f32d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ - based on [VGen](https://huggingface.co/ali-vilab/i2vgen-xl) - **VQA** visual question & answer in interrogate - with support for multiple variations of base models: *GIT, BLIP, ViLT, PIX* +- **Second Pass / Refine** + - independent upscale and hires options: run hires without upscale or upscale without hires or both + - upscale can now run 0.1-8.0 scale and will also run if enabled at 1.0 to allow for upscalers that simply improve image quality + - update ui section to reflect changes + - *note*: behavior using backend:original is unchanged for backwards compatibilty - **Improvements** - **FaceID** extend support for LoRA, HyperTile and FreeU, thanks @Trojaner - **Tiling** now extends to both Unet and VAE producing smoother outputs, thanks @AI-Casanova diff --git a/TODO.md b/TODO.md index dab3a98fe..4e8741126 100644 --- a/TODO.md +++ b/TODO.md @@ -6,6 +6,7 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - defork - stable diffusion 3.0 +- EDMEulerScheduler: - stable cascade: - ipadapter masking: - x-adapter: diff --git a/modules/processing_class.py b/modules/processing_class.py index 05bfec177..6207317af 100644 --- a/modules/processing_class.py +++ b/modules/processing_class.py @@ -261,14 +261,14 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing): self.hr_upscale_to_y = self.hr_resize_y self.truncate_x = (self.hr_upscale_to_x - target_w) // 8 self.truncate_y = (self.hr_upscale_to_y - target_h) // 8 - # special case: the user has chosen to do nothing - if (self.hr_upscale_to_x == self.width and self.hr_upscale_to_y == self.height) or self.hr_upscaler is None or self.hr_upscaler == 'None': - self.is_hr_pass = False - return - self.is_hr_pass = True - hypertile_set(self, hr=True) - shared.state.job_count = 2 * self.n_iter - shared.log.debug(f'Init hires: upscaler="{self.hr_upscaler}" sampler="{self.hr_sampler_name}" resize={self.hr_resize_x}x{self.hr_resize_y} upscale={self.hr_upscale_to_x}x{self.hr_upscale_to_y}') + if shared.backend == shared.Backend.ORIGINAL: # diffusers are handled in processing_diffusers + if (self.hr_upscale_to_x == self.width and self.hr_upscale_to_y == self.height) or self.hr_upscaler is None or self.hr_upscaler == 'None': # special case: the user has chosen to do nothing + self.is_hr_pass = False + return + self.is_hr_pass = True + hypertile_set(self, hr=True) + shared.state.job_count = 2 * self.n_iter + shared.log.debug(f'Init hires: upscaler="{self.hr_upscaler}" sampler="{self.hr_sampler_name}" resize={self.hr_resize_x}x{self.hr_resize_y} upscale={self.hr_upscale_to_x}x{self.hr_upscale_to_y}') def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts): from modules import processing_original diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index fc8f95c7a..b6d5c4c5e 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -388,6 +388,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): use_denoise_start = not is_txt2img() and p.refiner_start > 0 and p.refiner_start < 1 shared.sd_model = update_pipeline(shared.sd_model, p) + shared.log.info(f'Base: class={shared.sd_model.__class__.__name__}') base_args = set_pipeline_args( model=shared.sd_model, prompts=p.prompts, @@ -448,54 +449,65 @@ def process_diffusers(p: processing.StableDiffusionProcessing): shared.sd_model = orig_pipeline return results - # optional hires pass - if p.enable_hr and getattr(p, 'hr_upscaler', 'None') != 'None' and len(getattr(p, 'init_images', [])) == 0: + # optional second pass + if p.enable_hr and len(getattr(p, 'init_images', [])) == 0: p.is_hr_pass = True - latent_scale_mode = shared.latent_upscale_modes.get(p.hr_upscaler, None) if (hasattr(p, "hr_upscaler") and p.hr_upscaler is not None) else shared.latent_upscale_modes.get(shared.latent_upscale_default_mode, "None") if p.is_hr_pass: p.init_hr() prev_job = shared.state.job - if hasattr(p, 'height') and hasattr(p, 'width') and (p.width != p.hr_upscale_to_x or p.height != p.hr_upscale_to_y): + + # upscale + if hasattr(p, 'height') and hasattr(p, 'width') and p.hr_upscaler is not None and p.hr_upscaler != 'None': + shared.log.info(f'Upscale: upscaler="{p.hr_upscaler}" resize={p.hr_resize_x}x{p.hr_resize_y} upscale={p.hr_upscale_to_x}x{p.hr_upscale_to_y}') p.ops.append('upscale') if shared.opts.save and not p.do_not_save_samples and shared.opts.save_images_before_highres_fix and hasattr(shared.sd_model, 'vae'): save_intermediate(latents=output.images, suffix="-before-hires") shared.state.job = 'upscale' output.images = resize_hires(p, latents=output.images) - if (latent_scale_mode is not None or p.hr_force) and p.denoising_strength > 0: - p.ops.append('hires') - sd_models_compile.openvino_recompile_model(p, hires=True, refiner=False) - shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE) - if shared.sd_model.__class__.__name__ == "OnnxRawPipeline": - shared.sd_model = preprocess_onnx_pipeline(p) - update_sampler(shared.sd_model, second_pass=True) - hires_args = set_pipeline_args( - model=shared.sd_model, - prompts=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts, - negative_prompts=[p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts, - prompts_2=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts, - negative_prompts_2=[p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts, - num_inference_steps=calculate_hires_steps(p), - eta=shared.opts.scheduler_eta, - guidance_scale=p.image_cfg_scale if p.image_cfg_scale is not None else p.cfg_scale, - guidance_rescale=p.diffusers_guidance_rescale, - output_type='latent' if hasattr(shared.sd_model, 'vae') else 'np', - clip_skip=p.clip_skip, - image=output.images, - strength=p.denoising_strength, - desc='Hires', - ) - shared.state.job = 'hires' - shared.state.sampling_steps = hires_args['num_inference_steps'] - try: - sd_models_compile.check_deepcache(enable=True) - output = shared.sd_model(**hires_args) # pylint: disable=not-callable - if isinstance(output, dict): - output = SimpleNamespace(**output) - sd_models_compile.check_deepcache(enable=False) - sd_models_compile.openvino_post_compile(op="base") - except AssertionError as e: - shared.log.info(e) - p.init_images = [] + sd_hijack_hypertile.hypertile_set(p, hr=True) + + latent_upscale = shared.latent_upscale_modes.get(p.hr_upscaler, None) + if (latent_upscale is not None or p.hr_force) and p.denoising_strength > 0: + p.ops.append('hires') + sd_models_compile.openvino_recompile_model(p, hires=True, refiner=False) + if shared.sd_model.__class__.__name__ == "OnnxRawPipeline": + shared.sd_model = preprocess_onnx_pipeline(p) + p.hr_force = True + + # hires + if p.hr_force: + shared.state.job_count = 2 * p.n_iter + shared.sd_model = sd_models.set_diffuser_pipe(shared.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE) + update_sampler(shared.sd_model, second_pass=True) + shared.log.info(f'HiRes: class={shared.sd_model.__class__.__name__} sampler="{p.hr_sampler_name}"') + hires_args = set_pipeline_args( + model=shared.sd_model, + prompts=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts, + negative_prompts=[p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts, + prompts_2=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts, + negative_prompts_2=[p.refiner_negative] if len(p.refiner_negative) > 0 else p.negative_prompts, + num_inference_steps=calculate_hires_steps(p), + eta=shared.opts.scheduler_eta, + guidance_scale=p.image_cfg_scale if p.image_cfg_scale is not None else p.cfg_scale, + guidance_rescale=p.diffusers_guidance_rescale, + output_type='latent' if hasattr(shared.sd_model, 'vae') else 'np', + clip_skip=p.clip_skip, + image=output.images, + strength=p.denoising_strength, + desc='Hires', + ) + shared.state.job = 'hires' + shared.state.sampling_steps = hires_args['num_inference_steps'] + try: + sd_models_compile.check_deepcache(enable=True) + output = shared.sd_model(**hires_args) # pylint: disable=not-callable + if isinstance(output, dict): + output = SimpleNamespace(**output) + sd_models_compile.check_deepcache(enable=False) + sd_models_compile.openvino_post_compile(op="base") + except AssertionError as e: + shared.log.info(e) + p.init_images = [] shared.state.job = prev_job shared.state.nextjob() p.is_hr_pass = False @@ -529,6 +541,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): image = processing_vae.vae_decode(latents=image, model=shared.sd_model, full_quality=p.full_quality, output_type='pil') p.extra_generation_params['Noise level'] = noise_level output_type = 'np' + shared.log.info(f'Refiner: class={shared.sd_refiner.__class__.__name__}') refiner_args = set_pipeline_args( model=shared.sd_refiner, prompts=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else p.prompts[i], diff --git a/modules/processing_helpers.py b/modules/processing_helpers.py index 0da7ab470..e9ecc43a6 100644 --- a/modules/processing_helpers.py +++ b/modules/processing_helpers.py @@ -352,7 +352,7 @@ def resize_hires(p, latents): # input=latents output=pil first_pass_images = processing_vae.vae_decode(latents=latents, model=shared.sd_model, full_quality=p.full_quality, output_type='pil') return first_pass_images latent_upscaler = shared.latent_upscale_modes.get(p.hr_upscaler, None) - shared.log.info(f'Hires: upscaler={p.hr_upscaler} width={p.hr_upscale_to_x} height={p.hr_upscale_to_y} images={latents.shape[0]}') + # shared.log.info(f'Hires: upscaler={p.hr_upscaler} width={p.hr_upscale_to_x} height={p.hr_upscale_to_y} images={latents.shape[0]}') if latent_upscaler is not None: latents = torch.nn.functional.interpolate(latents, size=(p.hr_upscale_to_y // 8, p.hr_upscale_to_x // 8), mode=latent_upscaler["mode"], antialias=latent_upscaler["antialias"]) first_pass_images = processing_vae.vae_decode(latents=latents, model=shared.sd_model, full_quality=p.full_quality, output_type='pil') diff --git a/modules/processing_info.py b/modules/processing_info.py index 4e1a860da..218e1accd 100644 --- a/modules/processing_info.py +++ b/modules/processing_info.py @@ -72,10 +72,10 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No args["Second pass"] = p.enable_hr args["Hires force"] = p.hr_force args["Hires steps"] = p.hr_second_pass_steps - args["Hires upscaler"] = p.hr_upscaler - args["Hires upscale"] = p.hr_scale - args["Hires resize"] = f"{p.hr_resize_x}x{p.hr_resize_y}" - args["Hires size"] = f"{p.hr_upscale_to_x}x{p.hr_upscale_to_y}" + args["Hires upscaler"] = p.hr_upscaler if p.hr_upscaler is not None and p.hr_upscaler != 'None' else None + args["Hires upscale"] = p.hr_scale if p.hr_upscaler is not None and p.hr_upscaler != 'None' else None + args["Hires resize"] = f"{p.hr_resize_x}x{p.hr_resize_y}" if p.hr_upscaler is not None and p.hr_upscaler != 'None' else None + args["Hires size"] = f"{p.hr_upscale_to_x}x{p.hr_upscale_to_y}" if p.hr_upscaler is not None and p.hr_upscaler != 'None' else None args["Denoising strength"] = p.denoising_strength args["Hires sampler"] = p.hr_sampler_name args["Image CFG scale"] = p.image_cfg_scale diff --git a/modules/ui_sections.py b/modules/ui_sections.py index 2d099eb4f..6035bcca7 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -185,24 +185,22 @@ def create_sampler_and_steps_selection(choices, tabname): def create_hires_inputs(tab): - with gr.Accordion(open=False, label="Second pass", elem_id=f"{tab}_second_pass", elem_classes=["small-accordion"]): + with gr.Accordion(open=False, label="Refine", elem_id=f"{tab}_second_pass", elem_classes=["small-accordion"]): with gr.Group(): with gr.Row(elem_id=f"{tab}_hires_row1"): enable_hr = gr.Checkbox(label='Enable second pass', value=False, elem_id=f"{tab}_enable_hr") - with gr.Row(elem_id=f"{tab}_hires_row2"): - hr_sampler_index = gr.Dropdown(label='Secondary sampler', elem_id=f"{tab}_sampling_alt", choices=[x.name for x in sd_samplers.samplers], value='Default', type="index") - denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Denoising strength', value=0.5, elem_id=f"{tab}_denoising_strength") - with gr.Row(elem_id=f"{tab}_hires_finalres", variant="compact"): - hr_final_resolution = gr.HTML(value="", elem_id=f"{tab}_hr_finalres", label="Upscaled resolution", interactive=False) with gr.Row(elem_id=f"{tab}_hires_fix_row1", variant="compact"): hr_upscaler = gr.Dropdown(label="Upscaler", elem_id=f"{tab}_hr_upscaler", choices=[*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]], value=shared.latent_upscale_default_mode) - hr_force = gr.Checkbox(label='Force Hires', value=False, elem_id=f"{tab}_hr_force") - with gr.Row(elem_id=f"{tab}_hires_fix_row2", variant="compact"): - hr_second_pass_steps = gr.Slider(minimum=0, maximum=99, step=1, label='Hires steps', elem_id=f"{tab}_steps_alt", value=20) - hr_scale = gr.Slider(minimum=1.0, maximum=8.0, step=0.05, label="Upscale by", value=2.0, elem_id=f"{tab}_hr_scale") + hr_scale = gr.Slider(minimum=0.1, maximum=8.0, step=0.05, label="Rescale by", value=2.0, elem_id=f"{tab}_hr_scale") with gr.Row(elem_id=f"{tab}_hires_fix_row3", variant="compact"): - hr_resize_x = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize width to", value=0, elem_id=f"{tab}_hr_resize_x") - hr_resize_y = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize height to", value=0, elem_id=f"{tab}_hr_resize_y") + hr_resize_x = gr.Slider(minimum=0, maximum=4096, step=8, label="Width resize", value=0, elem_id=f"{tab}_hr_resize_x") + hr_resize_y = gr.Slider(minimum=0, maximum=4096, step=8, label="Height resize", value=0, elem_id=f"{tab}_hr_resize_y") + with gr.Row(elem_id=f"{tab}_hires_fix_row2", variant="compact"): + hr_force = gr.Checkbox(label='Force HiRes', value=False, elem_id=f"{tab}_hr_force") + hr_sampler_index = gr.Dropdown(label='Secondary sampler', elem_id=f"{tab}_sampling_alt", choices=[x.name for x in sd_samplers.samplers], value='Default', type="index") + with gr.Row(elem_id=f"{tab}_hires_row2"): + hr_second_pass_steps = gr.Slider(minimum=0, maximum=99, step=1, label='HiRes steps', elem_id=f"{tab}_steps_alt", value=20) + denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Strength', value=0.5, elem_id=f"{tab}_denoising_strength") with gr.Group(visible=shared.backend == shared.Backend.DIFFUSERS): with gr.Row(elem_id=f"{tab}_refiner_row1", variant="compact"): refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Refiner start', value=0.8, elem_id=f"{tab}_refiner_start") @@ -211,7 +209,7 @@ def create_hires_inputs(tab): refiner_prompt = gr.Textbox(value='', label='Secondary prompt', elem_id=f"{tab}_refiner_prompt") with gr.Row(elem_id="txt2img_refiner_row4", variant="compact"): refiner_negative = gr.Textbox(value='', label='Secondary negative prompt', elem_id=f"{tab}_refiner_neg_prompt") - return enable_hr, hr_sampler_index, denoising_strength, hr_final_resolution, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative + return enable_hr, hr_sampler_index, denoising_strength, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative def create_resize_inputs(tab, images, scale_visible=True, mode=None, accordion=True, latent=False): diff --git a/modules/ui_txt2img.py b/modules/ui_txt2img.py index 025d45c44..ca6920a77 100644 --- a/modules/ui_txt2img.py +++ b/modules/ui_txt2img.py @@ -47,22 +47,12 @@ def create_ui(): seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('txt2img') cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, sag_scale, cfg_end, full_quality, restore_faces, tiling = ui_sections.create_advanced_inputs('txt2img') hdr_mode, hdr_brightness, hdr_color, hdr_sharpen, hdr_clamp, hdr_boundary, hdr_threshold, hdr_maximize, hdr_max_center, hdr_max_boundry, hdr_color_picker, hdr_tint_ratio, = ui_sections.create_correction_inputs('txt2img') - enable_hr, hr_sampler_index, denoising_strength, hr_final_resolution, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative = ui_sections.create_hires_inputs('txt2img') + enable_hr, hr_sampler_index, denoising_strength, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative = ui_sections.create_hires_inputs('txt2img') override_settings = ui_common.create_override_inputs('txt2img') with gr.Group(elem_id="txt2img_script_container"): txt2img_script_inputs = modules.scripts.scripts_txt2img.setup_ui(parent='txt2img', accordion=True) - hr_resolution_preview_inputs = [width, height, hr_scale, hr_resize_x, hr_resize_y, hr_upscaler] - for preview_input in hr_resolution_preview_inputs: - preview_input.change( - fn=calc_resolution_hires, - _js="onCalcResolutionHires", - inputs=hr_resolution_preview_inputs, - outputs=[hr_final_resolution], - show_progress=False, - ) - txt2img_gallery, txt2img_generation_info, txt2img_html_info, _txt2img_html_info_formatted, txt2img_html_log = ui_common.create_output_panel("txt2img", preview=True, prompt=None) ui_common.connect_reuse_seed(seed, reuse_seed, txt2img_generation_info, is_subseed=False) ui_common.connect_reuse_seed(subseed, reuse_subseed, txt2img_generation_info, is_subseed=True) From 1603418243cab104cb1e13545f12252089f8c936 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 27 Feb 2024 09:30:51 -0500 Subject: [PATCH 31/44] add submit function to negative prompt --- javascript/ui.js | 10 +++++----- modules/ui_img2img.py | 5 +++-- modules/ui_txt2img.py | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/javascript/ui.js b/javascript/ui.js index 8edfba11b..4d61d7566 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -241,11 +241,11 @@ function clearPrompts(prompt, negative_prompt) { return [prompt, negative_prompt]; } -const promptTokecountUpdateFuncs = {}; +const promptTokenCountUpdateFuncs = {}; function recalculatePromptTokens(name) { - if (promptTokecountUpdateFuncs[name]) { - promptTokecountUpdateFuncs[name](); + if (promptTokenCountUpdateFuncs[name]) { + promptTokenCountUpdateFuncs[name](); } } @@ -330,8 +330,8 @@ onAfterUiUpdate(async () => { if (counter.parentElement === prompt.parentElement) return; prompt.parentElement.insertBefore(counter, prompt); prompt.parentElement.style.position = 'relative'; - promptTokecountUpdateFuncs[id] = () => { update_token_counter(id_button); }; - localTextarea.addEventListener('input', promptTokecountUpdateFuncs[id]); + promptTokenCountUpdateFuncs[id] = () => { update_token_counter(id_button); }; + localTextarea.addEventListener('input', promptTokenCountUpdateFuncs[id]); if (!promptsInitialized) log('initPrompts'); promptsInitialized = true; } diff --git a/modules/ui_img2img.py b/modules/ui_img2img.py index 404c578dc..8defb34eb 100644 --- a/modules/ui_img2img.py +++ b/modules/ui_img2img.py @@ -38,7 +38,7 @@ def create_ui(): modules.scripts.scripts_current = modules.scripts.scripts_img2img modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True) with gr.Blocks(analytics_enabled=False) as _img2img_interface: - img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_paste, img2img_extra_networks_button, img2img_token_counter, img2img_token_button, img2img_negative_token_counter, img2img_negative_token_button = ui_sections.create_toprow(is_img2img=True, id_part="img2img") + img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, img2img_submit, img2img_paste, img2img_extra_networks_button, img2img_token_counter, img2img_token_button, img2img_negative_token_counter, img2img_negative_token_button = ui_sections.create_toprow(is_img2img=True, id_part="img2img") img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False) with gr.Row(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks_ui: @@ -207,7 +207,8 @@ def create_ui(): show_progress=False, ) img2img_prompt.submit(**img2img_dict) - submit.click(**img2img_dict) + img2img_negative_prompt.submit(**img2img_dict) + img2img_submit.click(**img2img_dict) dummy_component = gr.Textbox(visible=False, value='dummy') interrogate_args = dict( diff --git a/modules/ui_txt2img.py b/modules/ui_txt2img.py index ca6920a77..7a58acbb8 100644 --- a/modules/ui_txt2img.py +++ b/modules/ui_txt2img.py @@ -87,6 +87,7 @@ def create_ui(): show_progress=False, ) txt2img_prompt.submit(**txt2img_dict) + txt2img_negative_prompt.submit(**txt2img_dict) txt2img_submit.click(**txt2img_dict) txt2img_paste_fields = [ # prompt From 61c3eb85e0fe209266461f61598824c60bf6f427 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 27 Feb 2024 14:45:03 -0500 Subject: [PATCH 32/44] bfloat16 to float --- CHANGELOG.md | 3 ++- modules/deepbooru.py | 2 +- modules/lama.py | 2 +- modules/processing_correction.py | 10 +++++----- scripts/xyz_grid.py | 3 +++ 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3838f32d..c0f4ebabe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,9 +26,10 @@ - **Fixes** - improve model cpu offload compatibility - improve model sequential offload compatibility + - improve bfloat16 compatibility - fix extra networks refresh - fix sdp memory attention in backend original - - fix autodetect v2.1 models + - fix autodetect sd21 models - exception handler around vram memory stats gather - improve ZLUDA installer with `--use-zluda` cli param, thanks @lshqqytiger diff --git a/modules/deepbooru.py b/modules/deepbooru.py index 8b822bf95..099a32fe8 100644 --- a/modules/deepbooru.py +++ b/modules/deepbooru.py @@ -63,7 +63,7 @@ class DeepDanbooru: with devices.inference_context(), devices.autocast(): x = torch.from_numpy(a).to(devices.device) - y = self.model(x)[0].detach().cpu().numpy() + y = self.model(x)[0].detach().float().cpu().numpy() probability_dict = {} diff --git a/modules/lama.py b/modules/lama.py index 06e360caa..0656ba521 100644 --- a/modules/lama.py +++ b/modules/lama.py @@ -96,7 +96,7 @@ class SimpleLama: image, mask = prepare_img_and_mask(image, mask, self.device) with devices.inference_context(): inpainted = self.model(image, mask) - cur_res = inpainted[0].permute(1, 2, 0).detach().cpu().numpy() + cur_res = inpainted[0].permute(1, 2, 0).detach().float().cpu().numpy() cur_res = np.clip(cur_res * 255, 0, 255).astype(np.uint8) cur_res = Image.fromarray(cur_res) return cur_res diff --git a/modules/processing_correction.py b/modules/processing_correction.py index 892c1e8c7..6afaaa8d3 100644 --- a/modules/processing_correction.py +++ b/modules/processing_correction.py @@ -46,11 +46,11 @@ def soft_clamp_tensor(tensor, threshold=0.8, boundary=4): def center_tensor(tensor, channel_shift=0.0, full_shift=0.0, offset=0.0): if channel_shift == 0 and full_shift == 0 and offset == 0: return tensor - debug(f'HDR center: Before Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).cpu().numpy()}') + debug(f'HDR center: Before Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).float().cpu().numpy()}') tensor -= tensor.mean(dim=(-1, -2), keepdim=True) * channel_shift tensor -= tensor.mean() * full_shift - offset debug(f'HDR center: channel-shift={channel_shift} full-shift={full_shift}') - debug(f'HDR center: After Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).cpu().numpy()}') + debug(f'HDR center: After Adjustment: Full mean={tensor.mean().item()} Channel means={tensor.mean(dim=(-1, -2)).float().cpu().numpy()}') return tensor @@ -122,9 +122,9 @@ def correction_callback(p, timestep, kwargs): for i in range(latents.shape[0]): latents[i] = correction(p, timestep, latents[i]) debug(f"Full Mean: {latents[i].mean().item()}") - debug(f"Channel Means: {latents[i].mean(dim=(-1, -2), keepdim=True).flatten().cpu().numpy()}") - debug(f"Channel Mins: {latents[i].min(-1, keepdim=True)[0].min(-2, keepdim=True)[0].flatten().cpu().numpy()}") - debug(f"Channel Maxes: {latents[i].max(-1, keepdim=True)[0].min(-2, keepdim=True)[0].flatten().cpu().numpy()}") + debug(f"Channel Means: {latents[i].mean(dim=(-1, -2), keepdim=True).flatten().float().cpu().numpy()}") + debug(f"Channel Mins: {latents[i].min(-1, keepdim=True)[0].min(-2, keepdim=True)[0].flatten().float().cpu().numpy()}") + debug(f"Channel Maxes: {latents[i].max(-1, keepdim=True)[0].min(-2, keepdim=True)[0].flatten().float().cpu().numpy()}") elif len(latents.shape) == 5 and latents.shape[0] == 1: # probably animatediff latents = latents.squeeze(0).permute(1, 0, 2, 3) for i in range(latents.shape[0]): diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index ab93a6d96..9d2022641 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -298,6 +298,9 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend processed: processing.Processed = cell(x, y, z, ix, iy, iz) if processed_result is None: processed_result = copy(processed) + if processed_result is None: + shared.log.error('XYZ grid: no processing results') + return processing.Processed(p, []) processed_result.images = [None] * list_size processed_result.all_prompts = [None] * list_size processed_result.all_seeds = [None] * list_size From c11ff37b614241483749d972a1c77fa5eade0ad6 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 27 Feb 2024 14:51:04 -0500 Subject: [PATCH 33/44] broader move model use --- modules/face/instantid.py | 2 +- modules/ipadapter.py | 4 ++-- modules/masking.py | 5 +++-- scripts/image2video.py | 2 +- scripts/x_adapter.py | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/face/instantid.py b/modules/face/instantid.py index 74141da3d..9c03452bb 100644 --- a/modules/face/instantid.py +++ b/modules/face/instantid.py @@ -41,7 +41,7 @@ def instant_id(p: processing.StableDiffusionProcessing, app, source_images, stre face_adapter = hf.hf_hub_download(repo_id=REPO_ID, filename="ip-adapter.bin") if controlnet_model is None or not cache: controlnet_model = ControlNetModel.from_pretrained(REPO_ID, subfolder="ControlNetModel", torch_dtype=devices.dtype, cache_dir=shared.opts.diffusers_dir) - controlnet_model.to(devices.device, devices.dtype) + sd_models.move_model(controlnet_model, devices.device) processing.process_init(p) diff --git a/modules/ipadapter.py b/modules/ipadapter.py index bbfba531a..32cfdb486 100644 --- a/modules/ipadapter.py +++ b/modules/ipadapter.py @@ -10,7 +10,7 @@ TODO ipadapter items: import os import time from PIL import Image -from modules import processing, shared, devices +from modules import processing, shared, devices, sd_models base_repo = "h94/IP-Adapter" @@ -163,7 +163,7 @@ def apply(pipe, p: processing.StableDiffusionProcessing, adapter_names=[], adapt except Exception as e: shared.log.error(f'IP adapter: failed to load image encoder: {e}') return - pipe.image_encoder.to(devices.device) + sd_models.move_model(pipe.image_encoder, devices.device) # main code t0 = time.time() diff --git a/modules/masking.py b/modules/masking.py index 2bf304ba4..34d9f174e 100644 --- a/modules/masking.py +++ b/modules/masking.py @@ -8,7 +8,7 @@ import numpy as np import cv2 from PIL import Image, ImageFilter, ImageOps from transformers import SamModel, SamImageProcessor, MaskGenerationPipeline -from modules import shared, errors, devices, ui_components, ui_symbols, paths +from modules import shared, errors, devices, ui_components, ui_symbols, paths, sd_models from modules.memstats import memory_stats @@ -480,7 +480,8 @@ def run_lama(input_image: gr.Image, input_mask: gr.Image = None): shared.log.debug(f'Mask LaMa loading: model={modules.lama.LAMA_MODEL_URL}') lama_model = modules.lama.SimpleLama() shared.log.debug(f'Mask LaMa loaded: {memory_stats()}') - lama_model.model.to(devices.device) + sd_models.move_model(lama_model.model, devices.device) + result = lama_model(input_image, input_mask) if shared.opts.control_move_processor: lama_model.model.to('cpu') diff --git a/scripts/image2video.py b/scripts/image2video.py index 91b265a39..0c8c476a2 100644 --- a/scripts/image2video.py +++ b/scripts/image2video.py @@ -83,7 +83,7 @@ class Script(scripts.Script): return shared.log.info(f'Image2Video PIA load: model={repo_id}') motion_adapter = diffusers.MotionAdapter.from_pretrained(repo_id) - motion_adapter.to(devices.device, devices.dtype) + sd_models.move_model(motion_adapter, devices.device) shared.sd_model = sd_models.switch_pipe(diffusers.PIAPipeline, shared.sd_model, { 'motion_adapter': motion_adapter }) sd_models.move_model(shared.sd_model, devices.device, force=True) # move pipeline to device if num_frames > 0: diff --git a/scripts/x_adapter.py b/scripts/x_adapter.py index f6ea70db2..f22facb4c 100644 --- a/scripts/x_adapter.py +++ b/scripts/x_adapter.py @@ -58,7 +58,7 @@ class Script(scripts.Script): adapter.load_state_dict(adapter_dict) try: if adapter is not None: - adapter.to(devices.device) + sd_models.move_model(adapter, devices.device) except Exception: pass if adapter is None: From e3c143250294a264cdb1b60bcf8d5a9f82e559e7 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 27 Feb 2024 17:11:37 -0500 Subject: [PATCH 34/44] experimental playground 2.5 support --- CHANGELOG.md | 9 +++ html/reference.json | 5 ++ ...ndai--playground-v2.5-1024px-aesthetic.jpg | Bin 0 -> 52058 bytes modules/sd_models.py | 65 +++++++++--------- modules/sd_samplers_diffusers.py | 12 ++++ 5 files changed, 60 insertions(+), 31 deletions(-) create mode 100644 models/Reference/playgroundai--playground-v2.5-1024px-aesthetic.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index c0f4ebabe..aff2c5db9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,16 @@ # Change Log for SD.Next +## TODO + +- EDM samplers for Playground require diffusers==0.27.0 +- StableCascade requires diffuers side-branch + ## Update for 2024-02-26 +- [Playground v2.5](https://huggingface.co/playgroundai/playground-v2.5-1024px-aesthetic) + - new model version from Playground: based on SDXL, but with some cool new concepts + - download using networks -> reference + - set sampler to DPM++ 2M EDM or Euler EDM - **Image2Video** - new module for creating videos from images - simply enable from *img2img -> scripts -> image2video* diff --git a/html/reference.json b/html/reference.json index f05fee1fe..c0d84b466 100644 --- a/html/reference.json +++ b/html/reference.json @@ -169,6 +169,11 @@ "desc": "Playground v2 is a diffusion-based text-to-image generative model. The model was trained from scratch by the research team at Playground. Images generated by Playground v2 are favored 2.5 times more than those produced by Stable Diffusion XL, according to Playground’s user study.", "preview": "playgroundai--playground-v2-1024px-aesthetic.jpg" }, + "Playground v2.5": { + "path": "playground-v2.5-1024px-aesthetic.fp16.safetensors@https://huggingface.co/playgroundai/playground-v2.5-1024px-aesthetic/resolve/main/playground-v2.5-1024px-aesthetic.fp16.safetensors?download=true", + "desc": "Playground v2.5 is a diffusion-based text-to-image generative model, and a successor to Playground v2. Playground v2.5 is the state-of-the-art open-source model in aesthetic quality. Our user studies demonstrate that our model outperforms SDXL, Playground v2, PixArt-α, DALL-E 3, and Midjourney 5.2.", + "preview": "playgroundai--playground-v2-1024px-aesthetic.jpg" + }, "DeepFloyd IF Medium": { "path": "DeepFloyd/IF-I-M-v1.0", "desc": "DeepFloyd-IF is a pixel-based text-to-image triple-cascaded diffusion model, that can generate pictures with new state-of-the-art for photorealism and language understanding. The result is a highly efficient model that outperforms current state-of-the-art models, achieving a zero-shot FID-30K score of 6.66 on the COCO dataset. It is modular and composed of frozen text mode and three pixel cascaded diffusion modules, each designed to generate images of increasing resolution: 64x64, 256x256, and 1024x1024.", diff --git a/models/Reference/playgroundai--playground-v2.5-1024px-aesthetic.jpg b/models/Reference/playgroundai--playground-v2.5-1024px-aesthetic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2c46bbb5c90b6be596c7d49500272e133bb2d26 GIT binary patch literal 52058 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 2048 else False - if large and k == 'ss_datasets': - continue - if large and k == 'workflow': - continue - if large and k == 'prompt': - continue - if large and k == 'ss_bucket_info': - continue - if v[0:1] == '{': - try: - v = json.loads(v) - if large and k == 'ss_tag_frequency': - v = { i: len(j) for i, j in v.items() } - if large and k == 'sd_merge_models': - scrub_dict(v, ['sd_merge_recipe']) - except Exception: - pass - res[k] = v + try: + metadata_len = file.read(8) + metadata_len = int.from_bytes(metadata_len, "little") + json_start = file.read(2) + if metadata_len <= 2 or json_start not in (b'{"', b"{'"): + shared.log.error(f"Model metadata invalid: fn={filename}") + json_data = json_start + file.read(metadata_len-2) + json_obj = json.loads(json_data) + for k, v in json_obj.get("__metadata__", {}).items(): + if v.startswith("data:"): + v = 'data' + if k == 'format' and v == 'pt': + continue + large = True if len(v) > 2048 else False + if large and k == 'ss_datasets': + continue + if large and k == 'workflow': + continue + if large and k == 'prompt': + continue + if large and k == 'ss_bucket_info': + continue + if v[0:1] == '{': + try: + v = json.loads(v) + if large and k == 'ss_tag_frequency': + v = { i: len(j) for i, j in v.items() } + if large and k == 'sd_merge_models': + scrub_dict(v, ['sd_merge_recipe']) + except Exception: + pass + res[k] = v + except Exception as e: + shared.log.error(f"Model metadata: fn={filename} {e}") sd_metadata[filename] = res global sd_metadata_pending # pylint: disable=global-statement sd_metadata_pending += 1 diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index eb2742210..8299ea567 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -72,6 +72,14 @@ samplers_data_diffusers = [ sd_samplers_common.SamplerData('SA Solver', lambda model: DiffusionSampler('SA Solver', SASolverScheduler, model), [], {}), ] +try: # diffusers==0.27.0 + from diffusers import EDMDPMSolverMultistepScheduler, EDMEulerScheduler + config['DPM++ 2M EDM'] = { 'solver_order': 2, 'solver_type': 'midpoint', 'final_sigmas_type': 'zero' } # 'algorithm_type': 'dpmsolver++' + config['Euler EDM'] = { } + samplers_data_diffusers.append(sd_samplers_common.SamplerData('DPM++ 2M EDM', lambda model: DiffusionSampler('DPM++ 2M EDM', EDMDPMSolverMultistepScheduler, model), [], {})) + samplers_data_diffusers.append(sd_samplers_common.SamplerData('Euler EDM', lambda model: DiffusionSampler('Euler EDM', EDMEulerScheduler, model), [], {})) +except Exception: + pass class DiffusionSampler: def __init__(self, name, constructor, model, **kwargs): @@ -126,6 +134,10 @@ class DiffusionSampler: self.config['algorithm_type'] = shared.opts.schedulers_dpm_solver if name == 'DEIS': self.config['algorithm_type'] = 'deis' + if 'EDM' in name: + del self.config['beta_start'] + del self.config['beta_end'] + del self.config['beta_schedule'] # validate all config params signature = inspect.signature(constructor, follow_wrapped=True) possible = signature.parameters.keys() From e0754f7acafefe2045369e5ee87cd58a5c51b7d8 Mon Sep 17 00:00:00 2001 From: Seunghoon Lee Date: Wed, 28 Feb 2024 18:15:58 +0900 Subject: [PATCH 35/44] automatically download zluda, add zluda in PATH --- installer.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/installer.py b/installer.py index bccd86d30..a132b7e36 100644 --- a/installer.py +++ b/installer.py @@ -481,7 +481,27 @@ def check_torch(): if args.use_zluda: torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.2.0 torchvision --index-url https://download.pytorch.org/whl/cu118') log.warning("ZLUDA support: experimental") + paths = os.environ.get('PATH', '.') zluda_need_dll_patch = is_windows and not installed('torch') + zluda_path = find_zluda() + if zluda_path is None: + import urllib.request + if is_windows: + import zipfile + archive_type = zipfile.ZipFile + zluda_url = 'https://github.com/lshqqytiger/ZLUDA/releases/download/v3.5-win/ZLUDA-windows-amd64.zip' + else: + import tarfile + archive_type = tarfile.TarFile + zluda_url = 'https://github.com/vosen/ZLUDA/releases/download/v3/zluda-3-linux.tar.gz' + urllib.request.urlretrieve(zluda_url, '_zluda') + with archive_type('_zluda', 'r') as f: + f.extractall('.zluda') + zluda_path = os.path.abspath('./.zluda') + os.remove('_zluda') + log.debug(f'Found ZLUDA in {zluda_path}') + if zluda_path not in paths: + os.environ['PATH'] += ';' + zluda_path elif is_windows: # TODO TBD after ROCm for Windows is released log.warning("HIP SDK is detected, but no Torch release for Windows available") log.info("For ZLUDA support specify '--use-zluda'") @@ -909,7 +929,7 @@ def get_onnxruntime_source_for_rocm(rocm_ver): return 'onnxruntime-gpu' -def patch_zluda(): +def find_zluda(): zluda_path = os.environ.get('ZLUDA', None) if zluda_path is None: paths = os.environ.get('PATH', '').split(';') @@ -917,6 +937,11 @@ def patch_zluda(): if os.path.exists(os.path.join(path, 'zluda_redirect.dll')): zluda_path = path break + return zluda_path + + +def patch_zluda(): + zluda_path = find_zluda() if zluda_path is None: log.warning('Failed to automatically patch torch with ZLUDA. Could not find ZLUDA from PATH.') return From ea42bc5aa818f08bd14d00eb49f6805043957c37 Mon Sep 17 00:00:00 2001 From: Seunghoon Lee Date: Wed, 28 Feb 2024 18:17:54 +0900 Subject: [PATCH 36/44] cleanup --- installer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/installer.py b/installer.py index a132b7e36..8b7aa18cc 100644 --- a/installer.py +++ b/installer.py @@ -481,7 +481,6 @@ def check_torch(): if args.use_zluda: torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.2.0 torchvision --index-url https://download.pytorch.org/whl/cu118') log.warning("ZLUDA support: experimental") - paths = os.environ.get('PATH', '.') zluda_need_dll_patch = is_windows and not installed('torch') zluda_path = find_zluda() if zluda_path is None: @@ -500,8 +499,9 @@ def check_torch(): zluda_path = os.path.abspath('./.zluda') os.remove('_zluda') log.debug(f'Found ZLUDA in {zluda_path}') + paths = os.environ.get('PATH', '.') if zluda_path not in paths: - os.environ['PATH'] += ';' + zluda_path + os.environ['PATH'] = paths + ';' + zluda_path elif is_windows: # TODO TBD after ROCm for Windows is released log.warning("HIP SDK is detected, but no Torch release for Windows available") log.info("For ZLUDA support specify '--use-zluda'") From 537170fa2d3e1e2bc34132f6552d6bb8d2f4ab7c Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 28 Feb 2024 11:11:45 -0500 Subject: [PATCH 37/44] fix api info endpoint --- CHANGELOG.md | 3 +- cli/simple-info.py | 62 ++++++++++++++++++++++++++++++++++++++++ modules/api/endpoints.py | 2 -- wiki | 2 +- 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100755 cli/simple-info.py diff --git a/CHANGELOG.md b/CHANGELOG.md index aff2c5db9..5e2e6382a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ - EDM samplers for Playground require diffusers==0.27.0 - StableCascade requires diffuers side-branch -## Update for 2024-02-26 +## Update for 2024-02-28 - [Playground v2.5](https://huggingface.co/playgroundai/playground-v2.5-1024px-aesthetic) - new model version from Playground: based on SDXL, but with some cool new concepts @@ -39,6 +39,7 @@ - fix extra networks refresh - fix sdp memory attention in backend original - fix autodetect sd21 models + - fix api info endpoint - exception handler around vram memory stats gather - improve ZLUDA installer with `--use-zluda` cli param, thanks @lshqqytiger diff --git a/cli/simple-info.py b/cli/simple-info.py new file mode 100755 index 000000000..dc607b39a --- /dev/null +++ b/cli/simple-info.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +import os +import io +import time +import base64 +import logging +import argparse +import requests +import urllib3 +from PIL import Image + +sd_url = os.environ.get('SDAPI_URL', "http://127.0.0.1:7860") +sd_username = os.environ.get('SDAPI_USR', None) +sd_password = os.environ.get('SDAPI_PWD', None) + +logging.basicConfig(level = logging.INFO, format = '%(asctime)s %(levelname)s: %(message)s') +log = logging.getLogger(__name__) +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + + +def auth(): + if sd_username is not None and sd_password is not None: + return requests.auth.HTTPBasicAuth(sd_username, sd_password) + return None + + +def get(endpoint: str, dct: dict = None): + req = requests.get(f'{sd_url}{endpoint}', json=dct, timeout=300, verify=False, auth=auth()) + if req.status_code != 200: + return { 'error': req.status_code, 'reason': req.reason, 'url': req.url } + else: + return req.json() + + +def post(endpoint: str, dct: dict = None): + req = requests.post(f'{sd_url}{endpoint}', json = dct, timeout=300, verify=False, auth=auth()) + if req.status_code != 200: + return { 'error': req.status_code, 'reason': req.reason, 'url': req.url } + else: + return req.json() + + +def encode(fn): + with open(fn, 'rb') as f: + content = f.read() + encoded = base64.b64encode(content).decode() + return encoded + + +def info(args): # pylint: disable=redefined-outer-name + t0 = time.time() + data = post('/sdapi/v1/png-info', { 'image': encode(args.input) }) + t1 = time.time() + log.info(f'received: {data} time={t1-t0:.2f}') + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description = 'simple-info') + parser.add_argument('--input', required=True, help='input image') + args = parser.parse_args() + log.info(f'info: {args}') + info(args) diff --git a/modules/api/endpoints.py b/modules/api/endpoints.py index f28c3bd8b..1337ccc8d 100644 --- a/modules/api/endpoints.py +++ b/modules/api/endpoints.py @@ -146,8 +146,6 @@ def post_pnginfo(req: models.ReqImageInfo): geninfo, items = images.read_info_from_image(image) if geninfo is None: geninfo = "" - if items and items['parameters']: - del items['parameters'] params = generation_parameters_copypaste.parse_generation_parameters(geninfo) script_callbacks.infotext_pasted_callback(geninfo, params) return models.ResImageInfo(info=geninfo, items=items, parameters=params) diff --git a/wiki b/wiki index 46e7d15eb..5c52cbb73 160000 --- a/wiki +++ b/wiki @@ -1 +1 @@ -Subproject commit 46e7d15ebc47858179cc8ef8f7c3d2f14e2489a0 +Subproject commit 5c52cbb7301c3e008a9dfd76702f9321ae7b3a34 From c8ed8659be31176220a2b13d2371d3f89f0b85ac Mon Sep 17 00:00:00 2001 From: Disty0 Date: Wed, 28 Feb 2024 19:41:42 +0300 Subject: [PATCH 38/44] Update Stable Cascade pipeline --- modules/sd_models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 6e9e96fcf..f4795d537 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -867,9 +867,11 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No scheduler=decoder.scheduler, vqgan=decoder.vqgan, prior_prior=prior.prior, + prior_text_encoder=prior.text_encoder, + prior_tokenizer=prior.tokenizer, prior_scheduler=prior.scheduler, - feature_extractor=prior.feature_extractor, - image_encoder=prior.image_encoder) + prior_feature_extractor=prior.feature_extractor, + prior_image_encoder=prior.image_encoder) except Exception as e: shared.log.error(f'Diffusers Failed loading {op}: {checkpoint_info.path} {e}') if debug_load: From 7e0f0ae24f2bce98341c418470dff28eac00adcb Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 28 Feb 2024 11:42:22 -0500 Subject: [PATCH 39/44] update stable cascade pipeline --- cli/simple-info.py | 15 +++++---------- modules/sd_models.py | 9 +++++++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cli/simple-info.py b/cli/simple-info.py index dc607b39a..4d1fd6d75 100755 --- a/cli/simple-info.py +++ b/cli/simple-info.py @@ -1,18 +1,18 @@ #!/usr/bin/env python import os -import io import time import base64 import logging import argparse import requests import urllib3 -from PIL import Image + sd_url = os.environ.get('SDAPI_URL', "http://127.0.0.1:7860") sd_username = os.environ.get('SDAPI_USR', None) sd_password = os.environ.get('SDAPI_PWD', None) + logging.basicConfig(level = logging.INFO, format = '%(asctime)s %(levelname)s: %(message)s') log = logging.getLogger(__name__) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) @@ -40,16 +40,11 @@ def post(endpoint: str, dct: dict = None): return req.json() -def encode(fn): - with open(fn, 'rb') as f: - content = f.read() - encoded = base64.b64encode(content).decode() - return encoded - - def info(args): # pylint: disable=redefined-outer-name t0 = time.time() - data = post('/sdapi/v1/png-info', { 'image': encode(args.input) }) + with open(args.input, 'rb') as f: + content = f.read() + data = post('/sdapi/v1/png-info', { 'image': base64.b64encode(content).decode() }) t1 = time.time() log.info(f'received: {data} time={t1-t0:.2f}') diff --git a/modules/sd_models.py b/modules/sd_models.py index f4795d537..9635b4368 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -856,10 +856,13 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No if model_type in ['Stable Cascade']: # forced pipeline # TODO experimental stable cascade try: + shared.log.debug(f'StableCascade experimental: args={diffusers_load_config} device={devices.device} dtype={devices.dtype}') diffusers_load_config.pop("vae", None) diffusers_load_config.pop("variant", None) decoder = diffusers.StableCascadeDecoderPipeline.from_pretrained("stabilityai/stable-cascade", cache_dir=shared.opts.diffusers_dir, revision="refs/pr/17", **diffusers_load_config) + shared.log.debug(f'StableCascade decoder: scale={decoder.latent_dim_scale}') prior = diffusers.StableCascadePriorPipeline.from_pretrained("stabilityai/stable-cascade-prior", cache_dir=shared.opts.diffusers_dir, **diffusers_load_config) + shared.log.debug(f'StableCascade prior: scale={prior.resolution_multiple}') sd_model = diffusers.StableCascadeCombinedPipeline( tokenizer=decoder.tokenizer, text_encoder=decoder.text_encoder, @@ -869,9 +872,11 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No prior_prior=prior.prior, prior_text_encoder=prior.text_encoder, prior_tokenizer=prior.tokenizer, + prior_tokenizer=prior.tokenizer, prior_scheduler=prior.scheduler, - prior_feature_extractor=prior.feature_extractor, - prior_image_encoder=prior.image_encoder) + prior_prior_feature_extractor=prior.feature_extractor, + prior_prior_image_encoder=prior.image_encoder) + shared.log.debug(f'StableCascade combined: {sd_model.__class__.__name__}') except Exception as e: shared.log.error(f'Diffusers Failed loading {op}: {checkpoint_info.path} {e}') if debug_load: From db22bd5440772592736424c189e174e7d7352b43 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 28 Feb 2024 11:45:57 -0500 Subject: [PATCH 40/44] cleanup --- modules/sd_models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/sd_models.py b/modules/sd_models.py index 9635b4368..0b7bab037 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -872,7 +872,6 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No prior_prior=prior.prior, prior_text_encoder=prior.text_encoder, prior_tokenizer=prior.tokenizer, - prior_tokenizer=prior.tokenizer, prior_scheduler=prior.scheduler, prior_prior_feature_extractor=prior.feature_extractor, prior_prior_image_encoder=prior.image_encoder) From 4b911ea822e4e0d77f103903f0f49720dad75dfd Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Wed, 28 Feb 2024 15:12:05 -0500 Subject: [PATCH 41/44] add support for json configs per model component --- CHANGELOG.md | 3 +- ...ground-v2.5-1024px-aesthetic.fp16_vae.json | 43 +++++++++++++++++ modules/processing_diffusers.py | 2 +- modules/processing_vae.py | 15 +++++- modules/sd_models.py | 48 +++++++++++++++++-- modules/sd_samplers_diffusers.py | 2 + requirements.txt | 2 +- 7 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 configs/playground-v2.5-1024px-aesthetic.fp16_vae.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e2e6382a..cee66fbb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ - [Playground v2.5](https://huggingface.co/playgroundai/playground-v2.5-1024px-aesthetic) - new model version from Playground: based on SDXL, but with some cool new concepts - download using networks -> reference - - set sampler to DPM++ 2M EDM or Euler EDM + - set sampler to *DPM++ 2M EDM* or *Euler EDM* (EDM are new family of samplers) - **Image2Video** - new module for creating videos from images - simply enable from *img2img -> scripts -> image2video* @@ -29,6 +29,7 @@ - default theme updates and additional built-in theme *black-gray* - add **ROCm** 6.0 nightly option to installer, thanks @jicka - support models with their own YAML model config files + - support models with their own JSON per-component config files, for example: `playground-v2.5_vae.config` - **Internal** - remove obsolete textual inversion training code - remove obsolete hypernetworks training code diff --git a/configs/playground-v2.5-1024px-aesthetic.fp16_vae.json b/configs/playground-v2.5-1024px-aesthetic.fp16_vae.json new file mode 100644 index 000000000..f00799d4b --- /dev/null +++ b/configs/playground-v2.5-1024px-aesthetic.fp16_vae.json @@ -0,0 +1,43 @@ +{ + "_class_name": "AutoencoderKL", + "_diffusers_version": "0.27.0.dev0", + "act_fn": "silu", + "block_out_channels": [ + 128, + 256, + 512, + 512 + ], + "down_block_types": [ + "DownEncoderBlock2D", + "DownEncoderBlock2D", + "DownEncoderBlock2D", + "DownEncoderBlock2D" + ], + "force_upcast": true, + "in_channels": 3, + "latent_channels": 4, + "layers_per_block": 2, + "norm_num_groups": 32, + "out_channels": 3, + "sample_size": 1024, + "up_block_types": [ + "UpDecoderBlock2D", + "UpDecoderBlock2D", + "UpDecoderBlock2D", + "UpDecoderBlock2D" + ], + "latents_mean": [ + -1.6574, + 1.886, + -1.383, + 2.5155 + ], + "latents_std": [ + 8.4927, + 5.9022, + 6.5498, + 5.2299 + ], + "scaling_factor": 0.5 +} diff --git a/modules/processing_diffusers.py b/modules/processing_diffusers.py index b6d5c4c5e..f4250582d 100644 --- a/modules/processing_diffusers.py +++ b/modules/processing_diffusers.py @@ -229,7 +229,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing): if 'latents' in possible and getattr(p, "init_latent", None) is not None: args['latents'] = p.init_latent if 'output_type' in possible: - if hasattr(model, 'vae'): + if not hasattr(model, 'vae'): args['output_type'] = 'np' # only set latent if model has vae # stable cascade diff --git a/modules/processing_vae.py b/modules/processing_vae.py index 985bcdac4..793f2aeb8 100644 --- a/modules/processing_vae.py +++ b/modules/processing_vae.py @@ -46,9 +46,20 @@ def full_vae_decode(latents, model): model.upcast_vae() if hasattr(model.vae, "post_quant_conv"): latents = latents.to(next(iter(model.vae.post_quant_conv.parameters())).dtype) - decoded = model.vae.decode(latents / model.vae.config.scaling_factor, return_dict=False)[0] - # Delete PyTorch VAE after OpenVINO compile + # normalize latents + latents_mean = model.vae.config.get("latents_mean", None) + latents_std = model.vae.config.get("latents_std", None) + scaling_factor = model.vae.config.get("scaling_factor", None) + if latents_mean and latents_std: + latents_mean = (torch.tensor(latents_mean).view(1, 4, 1, 1).to(latents.device, latents.dtype)) + latents_std = (torch.tensor(latents_std).view(1, 4, 1, 1).to(latents.device, latents.dtype)) + latents = latents * latents_std / scaling_factor + latents_mean + else: + latents = latents / scaling_factor + decoded = model.vae.decode(latents, return_dict=False)[0] + + # delete vae after OpenVINO compile if shared.opts.cuda_compile and shared.opts.cuda_compile_backend == "openvino_fx" and shared.compiled_model_state.first_pass_vae: shared.compiled_model_state.first_pass_vae = False if not shared.opts.openvino_disable_memory_cleanup and hasattr(shared.sd_model, "vae"): diff --git a/modules/sd_models.py b/modules/sd_models.py index 0b7bab037..0ca0774cd 100644 --- a/modules/sd_models.py +++ b/modules/sd_models.py @@ -780,6 +780,50 @@ def get_load_config(model_file, model_type): return None +def patch_diffuser_config(sd_model, model_file): + def load_config(fn, k): + model_file = os.path.splitext(fn)[0] + cfg_file = f'{model_file}_{k}.json' + try: + if os.path.exists(cfg_file): + with open(cfg_file, 'r', encoding='utf-8') as f: + return json.load(f) + cfg_file = f'{os.path.join(paths.sd_configs_path, os.path.basename(model_file))}_{k}.json' + if os.path.exists(cfg_file): + with open(cfg_file, 'r', encoding='utf-8') as f: + return json.load(f) + except Exception: + pass + return {} + + if sd_model is None: + return sd_model + if hasattr(sd_model, 'unet') and hasattr(sd_model.unet, 'config') and 'inpaint' in model_file.lower(): + if debug_load: + shared.log.debug('Model config patch: type=inpaint') + sd_model.unet.config.in_channels = 9 + if not hasattr(sd_model, '_internal_dict'): + return sd_model + for c in sd_model._internal_dict.keys(): # pylint: disable=protected-access + component = getattr(sd_model, c, None) + if hasattr(component, 'config'): + if debug_load: + shared.log.debug(f'Model config: component={c} config={component.config}') + override = load_config(model_file, c) + updated = {} + for k, v in override.items(): + if k.startswith('_'): + continue + if v != component.config.get(k, None): + if hasattr(component.config, '__frozen'): + component.config.__frozen = False # pylint: disable=protected-access + component.config[k] = v + updated[k] = v + if updated and debug_load: + shared.log.debug(f'Model config: component={c} override={updated}') + return sd_model + + def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'): # pylint: disable=unused-argument if shared.cmd_opts.profile: import cProfile @@ -966,9 +1010,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No else: sd_hijack_accelerate.restore_accelerate() sd_model = pipeline.from_single_file(checkpoint_info.path, **diffusers_load_config) - if sd_model is not None and hasattr(sd_model, 'unet') and hasattr(sd_model.unet, 'config') and 'inpainting' in checkpoint_info.path.lower(): - shared.log.debug('Model patch: type=inpaint') - sd_model.unet.config.in_channels = 9 + sd_model = patch_diffuser_config(sd_model, checkpoint_info.path) elif hasattr(pipeline, 'from_ckpt'): sd_model = pipeline.from_ckpt(checkpoint_info.path, **diffusers_load_config) else: diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index 8299ea567..e463282ae 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -146,5 +146,7 @@ class DiffusionSampler: if key not in possible: shared.log.warning(f'Sampler: sampler="{name}" config={self.config} invalid={key}') del self.config[key] + # shared.log.debug(f'Sampler: sampler="{name}" config={self.config}') self.sampler = constructor(**self.config) + # shared.log.debug(f'Sampler: class="{self.sampler.__class__.__name__}" config={self.sampler.config}') self.sampler.name = name diff --git a/requirements.txt b/requirements.txt index 4ffec69bd..996f09d40 100644 --- a/requirements.txt +++ b/requirements.txt @@ -55,7 +55,7 @@ pandas protobuf==3.20.3 pytorch_lightning==1.9.4 tokenizers==0.15.2 -transformers==4.37.2 +transformers==4.38.1 tomesd==0.1.3 urllib3==1.26.18 Pillow==10.2.0 From 9f9fc1f47ba416f77717408b50a81060d34d9060 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Thu, 29 Feb 2024 09:01:35 -0500 Subject: [PATCH 42/44] add koala-700m --- CHANGELOG.md | 6 +++++- html/reference.json | 8 ++++++++ .../etri-vilab--koala-700m-llava-cap.jpg | Bin 0 -> 40208 bytes 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 models/Reference/etri-vilab--koala-700m-llava-cap.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index cee66fbb6..03b7bf7f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,16 @@ - EDM samplers for Playground require diffusers==0.27.0 - StableCascade requires diffuers side-branch -## Update for 2024-02-28 +## Update for 2024-02-29 - [Playground v2.5](https://huggingface.co/playgroundai/playground-v2.5-1024px-aesthetic) - new model version from Playground: based on SDXL, but with some cool new concepts - download using networks -> reference - set sampler to *DPM++ 2M EDM* or *Euler EDM* (EDM are new family of samplers) +- [KOALA 700M](https://github.com/youngwanLEE/sdxl-koala) + - another very fast & light sd-xl model where original unet was compressed and distilled to 54% of original size + - download using networks -> reference + - *note* to download fp16 variant (recommended), set settings -> diffusers -> preferred model variant - **Image2Video** - new module for creating videos from images - simply enable from *img2img -> scripts -> image2video* diff --git a/html/reference.json b/html/reference.json index c0d84b466..e67014603 100644 --- a/html/reference.json +++ b/html/reference.json @@ -189,6 +189,14 @@ "desc": "Amused is a lightweight text to image model based off of the muse architecture. Amused is particularly useful in applications that require a lightweight and fast model such as generating many images quickly at once.", "preview": "amused--amused-512.jpg" }, + "KOALA 700M": { + "path": "huggingface/etri-vilab/koala-700m-llava-cap", + "variant": "fp16", + "skip": true, + "desc": "Fast text-to-image model, called KOALA, by compressing SDXL's U-Net and distilling knowledge from SDXL into our model. KOALA-700M can generate a 1024x1024 image in less than 1.5 seconds on an NVIDIA 4090 GPU, which is more than 2x faster than SDXL.", + "preview": "etri-vilab--koala-700m-llava-cap.jpg" + }, + "Tsinghua UniDiffuser": { "path": "thu-ml/unidiffuser-v1", "desc": "UniDiffuser is a unified diffusion framework to fit all distributions relevant to a set of multi-modal data in one transformer. UniDiffuser is able to perform image, text, text-to-image, image-to-text, and image-text pair generation by setting proper timesteps without additional overhead.\nSpecifically, UniDiffuser employs a variation of transformer, called U-ViT, which parameterizes the joint noise prediction network. Other components perform as encoders and decoders of different modalities, including a pretrained image autoencoder from Stable Diffusion, a pretrained image ViT-B/32 CLIP encoder, a pretrained text ViT-L CLIP encoder, and a GPT-2 text decoder finetuned by ourselves.", diff --git a/models/Reference/etri-vilab--koala-700m-llava-cap.jpg b/models/Reference/etri-vilab--koala-700m-llava-cap.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c3b63a0417aec1113d29ea2cbc67f34df128f614 GIT binary patch literal 40208 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 Date: Thu, 29 Feb 2024 09:46:59 -0500 Subject: [PATCH 43/44] update changelog --- CHANGELOG.md | 4 ++-- TODO.md | 2 -- javascript/sdnext.css | 4 ++-- modules/modelloader.py | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b7bf7f6..c40fc0981 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ ## TODO -- EDM samplers for Playground require diffusers==0.27.0 -- StableCascade requires diffuers side-branch +- EDM samplers for Playground require `diffusers==0.27.0` +- StableCascade requires diffusers `kashif/diffusers.git@wuerstchen-v3` ## Update for 2024-02-29 diff --git a/TODO.md b/TODO.md index 4e8741126..79ab68161 100644 --- a/TODO.md +++ b/TODO.md @@ -6,8 +6,6 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma - defork - stable diffusion 3.0 -- EDMEulerScheduler: -- stable cascade: - ipadapter masking: - x-adapter: - async lowvram: diff --git a/javascript/sdnext.css b/javascript/sdnext.css index b72342356..f752c707f 100644 --- a/javascript/sdnext.css +++ b/javascript/sdnext.css @@ -107,8 +107,8 @@ div#extras_scale_to_tab div.form{ flex-direction: row; } #mode_img2img .gradio-image>div.fixed-height, #mode_img2img .gradio-image>div.fixed-height img{ height: 480px !important; max-height: 480px !important; min-height: 480px !important; } #img2img_sketch, #img2maskimg, #inpaint_sketch { overflow: overlay !important; resize: auto; background: var(--panel-background-fill); z-index: 5; } .image-buttons button{ min-width: auto; } -.infotext { overflow-wrap: break-word; line-height: 1.5em; } -.infotext>p { padding-left: 1em; text-indent: -1em; white-space: pre-wrap; } +.infotext { overflow-wrap: break-word; line-height: 1.5em; font-size: 0.95em !important; } +.infotext > p { padding-left: 1em; text-indent: -1em; white-space: pre-wrap; color: var(--block-info-text-color) !important; } .tooltip { display: block; position: fixed; top: 1em; right: 1em; padding: 0.5em; background: var(--input-background-fill); color: var(--body-text-color); border: 1pt solid var(--button-primary-border-color); width: 22em; min-height: 1.3em; font-size: var(--text-xs); transition: opacity 0.2s ease-in; pointer-events: none; opacity: 0; z-index: 999; } .tooltip-show { opacity: 0.9; } diff --git a/modules/modelloader.py b/modules/modelloader.py index 36e7435f8..91cedbf83 100644 --- a/modules/modelloader.py +++ b/modules/modelloader.py @@ -186,14 +186,14 @@ def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config except Exception as e: err = e ok = False - debug(f"Diffusers download error: {hub_id} {e}") + debug(f'Diffusers download error: id="{hub_id}" {e}') if not ok and 'Repository Not Found' not in str(err): try: download_config.pop('load_connected_pipeline', None) download_config.pop('variant', None) pipeline_dir = hf.snapshot_download(hub_id, **download_config) except Exception as e: - debug(f"Diffusers download error: {hub_id} {e}") + debug(f'Diffusers download error: id="{hub_id}" {e}') if 'gated' in str(e): shared.log.error(f'Diffusers download error: id="{hub_id}" model access requires login') return None From 43457945b64d1fa09d68952e13c3b856163de198 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Fri, 1 Mar 2024 08:55:43 -0500 Subject: [PATCH 44/44] add lcd sampler --- .pylintrc | 1 + CHANGELOG.md | 12 +- modules/sd_samplers_diffusers.py | 4 + modules/tcd/__init__.py | 660 +++++++++++++++++++++++++++++++ pyproject.toml | 1 + scripts/xyz_grid.py | 2 +- 6 files changed, 677 insertions(+), 3 deletions(-) create mode 100644 modules/tcd/__init__.py diff --git a/.pylintrc b/.pylintrc index 1fb193efe..113525778 100644 --- a/.pylintrc +++ b/.pylintrc @@ -16,6 +16,7 @@ ignore-paths=/usr/lib/.*$, ^modules/dml/.*$, ^modules/models/diffusion/.*$, ^modules/xadapters/.*$, + ^modules/tcd/.*$, ignore-patterns= ignored-modules= jobs=0 diff --git a/CHANGELOG.md b/CHANGELOG.md index c40fc0981..f48e47b66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,12 @@ - EDM samplers for Playground require `diffusers==0.27.0` - StableCascade requires diffusers `kashif/diffusers.git@wuerstchen-v3` -## Update for 2024-02-29 +## Update for 2024-03-01 - [Playground v2.5](https://huggingface.co/playgroundai/playground-v2.5-1024px-aesthetic) - new model version from Playground: based on SDXL, but with some cool new concepts - download using networks -> reference - - set sampler to *DPM++ 2M EDM* or *Euler EDM* (EDM are new family of samplers) + - set sampler to *DPM++ 2M EDM* or *Euler EDM* - [KOALA 700M](https://github.com/youngwanLEE/sdxl-koala) - another very fast & light sd-xl model where original unet was compressed and distilled to 54% of original size - download using networks -> reference @@ -26,6 +26,13 @@ - upscale can now run 0.1-8.0 scale and will also run if enabled at 1.0 to allow for upscalers that simply improve image quality - update ui section to reflect changes - *note*: behavior using backend:original is unchanged for backwards compatibilty +- **Samplers** + - [TCD](https://mhh0318.github.io/tcd/): Trajectory Consistency Distillation + new sampler that produces consistent results in a very low number of steps (comparable to LCM but without reliance on LoRA) + for best results, use with TCD LoRA: + - *DPM++ 2M EDM* and *Euler EDM* + EDM is a new solver algorithm currently available for DPM++2M and Euler samplers + Note that using EDM samplers with non-EDM optimized models will provide just noise and vice-versa - **Improvements** - **FaceID** extend support for LoRA, HyperTile and FreeU, thanks @Trojaner - **Tiling** now extends to both Unet and VAE producing smoother outputs, thanks @AI-Casanova @@ -45,6 +52,7 @@ - fix sdp memory attention in backend original - fix autodetect sd21 models - fix api info endpoint + - fix sampler eta in xyz grid, thanks @AI-Casanova - exception handler around vram memory stats gather - improve ZLUDA installer with `--use-zluda` cli param, thanks @lshqqytiger diff --git a/modules/sd_samplers_diffusers.py b/modules/sd_samplers_diffusers.py index e463282ae..936b955c5 100644 --- a/modules/sd_samplers_diffusers.py +++ b/modules/sd_samplers_diffusers.py @@ -2,6 +2,7 @@ import os import inspect from modules import shared from modules import sd_samplers_common +from modules.tcd import TCDScheduler debug = shared.log.trace if os.environ.get('SD_SAMPLER_DEBUG', None) is not None else lambda *args, **kwargs: None @@ -50,6 +51,7 @@ config = { 'PNDM': { 'skip_prk_steps': False, 'set_alpha_to_one': False, 'steps_offset': 0 }, 'LCM': { 'beta_start': 0.00085, 'beta_end': 0.012, 'beta_schedule': "scaled_linear", 'set_alpha_to_one': True, 'rescale_betas_zero_snr': False, 'thresholding': False }, 'SA Solver': {'predictor_order': 2, 'corrector_order': 2, 'thresholding': False, 'lower_order_final': True, 'use_karras_sigmas': False, 'timestep_spacing': 'linspace'}, + 'TCD': { 'set_alpha_to_one': True, 'rescale_betas_zero_snr': False, 'beta_schedule': 'scaled_linear' }, } samplers_data_diffusers = [ @@ -70,6 +72,7 @@ samplers_data_diffusers = [ sd_samplers_common.SamplerData('Heun', lambda model: DiffusionSampler('Heun', HeunDiscreteScheduler, model), [], {}), sd_samplers_common.SamplerData('LCM', lambda model: DiffusionSampler('LCM', LCMScheduler, model), [], {}), sd_samplers_common.SamplerData('SA Solver', lambda model: DiffusionSampler('SA Solver', SASolverScheduler, model), [], {}), + sd_samplers_common.SamplerData('TCD', lambda model: DiffusionSampler('TCD', TCDScheduler, model), [], {}), ] try: # diffusers==0.27.0 @@ -81,6 +84,7 @@ try: # diffusers==0.27.0 except Exception: pass + class DiffusionSampler: def __init__(self, name, constructor, model, **kwargs): if name == 'Default': diff --git a/modules/tcd/__init__.py b/modules/tcd/__init__.py new file mode 100644 index 000000000..bff12ab5a --- /dev/null +++ b/modules/tcd/__init__.py @@ -0,0 +1,660 @@ +# Copied from: https://github.com/jabir-zheng/TCD/blob/main/scheduling_tcd.py +# pylint: skip-file + +# Copyright 2023 Stanford University Team and The HuggingFace Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# DISCLAIMER: This code is strongly influenced by https://github.com/pesser/pytorch_diffusion +# and https://github.com/hojonathanho/diffusion + +import math +from dataclasses import dataclass +from typing import List, Optional, Tuple, Union + +import numpy as np +import torch + +from diffusers.configuration_utils import ConfigMixin, register_to_config +from diffusers.utils import BaseOutput, logging +from diffusers.utils.torch_utils import randn_tensor +from diffusers.schedulers.scheduling_utils import SchedulerMixin + + +logger = logging.get_logger(__name__) # pylint: disable=invalid-name + + +@dataclass +class TCDSchedulerOutput(BaseOutput): + """ + Output class for the scheduler's `step` function output. + + Args: + prev_sample (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)` for images): + Computed sample `(x_{t-1})` of previous timestep. `prev_sample` should be used as next model input in the + denoising loop. + pred_noised_sample (`torch.FloatTensor` of shape `(batch_size, num_channels, height, width)` for images): + The predicted noised sample `(x_{s})` based on the model output from the current timestep. + """ + + prev_sample: torch.FloatTensor + pred_noised_sample: Optional[torch.FloatTensor] = None + + +# Copied from diffusers.schedulers.scheduling_ddpm.betas_for_alpha_bar +def betas_for_alpha_bar( + num_diffusion_timesteps, + max_beta=0.999, + alpha_transform_type="cosine", +): + """ + Create a beta schedule that discretizes the given alpha_t_bar function, which defines the cumulative product of + (1-beta) over time from t = [0,1]. + + Contains a function alpha_bar that takes an argument t and transforms it to the cumulative product of (1-beta) up + to that part of the diffusion process. + + + Args: + num_diffusion_timesteps (`int`): the number of betas to produce. + max_beta (`float`): the maximum beta to use; use values lower than 1 to + prevent singularities. + alpha_transform_type (`str`, *optional*, default to `cosine`): the type of noise schedule for alpha_bar. + Choose from `cosine` or `exp` + + Returns: + betas (`np.ndarray`): the betas used by the scheduler to step the model outputs + """ + if alpha_transform_type == "cosine": + + def alpha_bar_fn(t): + return math.cos((t + 0.008) / 1.008 * math.pi / 2) ** 2 + + elif alpha_transform_type == "exp": + + def alpha_bar_fn(t): + return math.exp(t * -12.0) + + else: + raise ValueError(f"Unsupported alpha_tranform_type: {alpha_transform_type}") + + betas = [] + for i in range(num_diffusion_timesteps): + t1 = i / num_diffusion_timesteps + t2 = (i + 1) / num_diffusion_timesteps + betas.append(min(1 - alpha_bar_fn(t2) / alpha_bar_fn(t1), max_beta)) + return torch.tensor(betas, dtype=torch.float32) + + +# Copied from diffusers.schedulers.scheduling_ddim.rescale_zero_terminal_snr +def rescale_zero_terminal_snr(betas: torch.FloatTensor) -> torch.FloatTensor: + """ + Rescales betas to have zero terminal SNR Based on https://arxiv.org/pdf/2305.08891.pdf (Algorithm 1) + + + Args: + betas (`torch.FloatTensor`): + the betas that the scheduler is being initialized with. + + Returns: + `torch.FloatTensor`: rescaled betas with zero terminal SNR + """ + # Convert betas to alphas_bar_sqrt + alphas = 1.0 - betas + alphas_cumprod = torch.cumprod(alphas, dim=0) + alphas_bar_sqrt = alphas_cumprod.sqrt() + + # Store old values. + alphas_bar_sqrt_0 = alphas_bar_sqrt[0].clone() + alphas_bar_sqrt_T = alphas_bar_sqrt[-1].clone() + + # Shift so the last timestep is zero. + alphas_bar_sqrt -= alphas_bar_sqrt_T + + # Scale so the first timestep is back to the old value. + alphas_bar_sqrt *= alphas_bar_sqrt_0 / (alphas_bar_sqrt_0 - alphas_bar_sqrt_T) + + # Convert alphas_bar_sqrt to betas + alphas_bar = alphas_bar_sqrt**2 # Revert sqrt + alphas = alphas_bar[1:] / alphas_bar[:-1] # Revert cumprod + alphas = torch.cat([alphas_bar[0:1], alphas]) + betas = 1 - alphas + + return betas + + +class TCDScheduler(SchedulerMixin, ConfigMixin): + """ + `TCDScheduler` incorporates the `Strategic Stochastic Sampling` introduced by the paper `Trajectory Consistency Distillation`, + extending the original Multistep Consistency Sampling to enable unrestricted trajectory traversal. + + This model inherits from [`SchedulerMixin`] and [`ConfigMixin`]. [`~ConfigMixin`] takes care of storing all config + attributes that are passed in the scheduler's `__init__` function, such as `num_train_timesteps`. They can be + accessed via `scheduler.config.num_train_timesteps`. [`SchedulerMixin`] provides general loading and saving + functionality via the [`SchedulerMixin.save_pretrained`] and [`~SchedulerMixin.from_pretrained`] functions. + + Args: + num_train_timesteps (`int`, defaults to 1000): + The number of diffusion steps to train the model. + beta_start (`float`, defaults to 0.0001): + The starting `beta` value of inference. + beta_end (`float`, defaults to 0.02): + The final `beta` value. + beta_schedule (`str`, defaults to `"linear"`): + The beta schedule, a mapping from a beta range to a sequence of betas for stepping the model. Choose from + `linear`, `scaled_linear`, or `squaredcos_cap_v2`. + trained_betas (`np.ndarray`, *optional*): + Pass an array of betas directly to the constructor to bypass `beta_start` and `beta_end`. + original_inference_steps (`int`, *optional*, defaults to 50): + The default number of inference steps used to generate a linearly-spaced timestep schedule, from which we + will ultimately take `num_inference_steps` evenly spaced timesteps to form the final timestep schedule. + clip_sample (`bool`, defaults to `True`): + Clip the predicted sample for numerical stability. + clip_sample_range (`float`, defaults to 1.0): + The maximum magnitude for sample clipping. Valid only when `clip_sample=True`. + set_alpha_to_one (`bool`, defaults to `True`): + Each diffusion step uses the alphas product value at that step and at the previous one. For the final step + there is no previous alpha. When this option is `True` the previous alpha product is fixed to `1`, + otherwise it uses the alpha value at step 0. + steps_offset (`int`, defaults to 0): + An offset added to the inference steps. You can use a combination of `offset=1` and + `set_alpha_to_one=False` to make the last step use step 0 for the previous alpha product like in Stable + Diffusion. + prediction_type (`str`, defaults to `epsilon`, *optional*): + Prediction type of the scheduler function; can be `epsilon` (predicts the noise of the diffusion process), + `sample` (directly predicts the noisy sample`) or `v_prediction` (see section 2.4 of [Imagen + Video](https://imagen.research.google/video/paper.pdf) paper). + thresholding (`bool`, defaults to `False`): + Whether to use the "dynamic thresholding" method. This is unsuitable for latent-space diffusion models such + as Stable Diffusion. + dynamic_thresholding_ratio (`float`, defaults to 0.995): + The ratio for the dynamic thresholding method. Valid only when `thresholding=True`. + sample_max_value (`float`, defaults to 1.0): + The threshold value for dynamic thresholding. Valid only when `thresholding=True`. + timestep_spacing (`str`, defaults to `"leading"`): + The way the timesteps should be scaled. Refer to Table 2 of the [Common Diffusion Noise Schedules and + Sample Steps are Flawed](https://huggingface.co/papers/2305.08891) for more information. + timestep_scaling (`float`, defaults to 10.0): + The factor the timesteps will be multiplied by when calculating the consistency model boundary conditions + `c_skip` and `c_out`. Increasing this will decrease the approximation error (although the approximation + error at the default of `10.0` is already pretty small). + rescale_betas_zero_snr (`bool`, defaults to `False`): + Whether to rescale the betas to have zero terminal SNR. This enables the model to generate very bright and + dark samples instead of limiting it to samples with medium brightness. Loosely related to + [`--offset_noise`](https://github.com/huggingface/diffusers/blob/74fd735eb073eb1d774b1ab4154a0876eb82f055/examples/dreambooth/train_dreambooth.py#L506). + """ + + order = 1 + + @register_to_config + def __init__( + self, + num_train_timesteps: int = 1000, + beta_start: float = 0.00085, + beta_end: float = 0.012, + beta_schedule: str = "scaled_linear", + trained_betas: Optional[Union[np.ndarray, List[float]]] = None, + original_inference_steps: int = 50, + clip_sample: bool = False, + clip_sample_range: float = 1.0, + set_alpha_to_one: bool = True, + steps_offset: int = 0, + prediction_type: str = "epsilon", + thresholding: bool = False, + dynamic_thresholding_ratio: float = 0.995, + sample_max_value: float = 1.0, + timestep_spacing: str = "leading", + timestep_scaling: float = 10.0, + rescale_betas_zero_snr: bool = False, + ): + if trained_betas is not None: + self.betas = torch.tensor(trained_betas, dtype=torch.float32) + elif beta_schedule == "linear": + self.betas = torch.linspace(beta_start, beta_end, num_train_timesteps, dtype=torch.float32) + elif beta_schedule == "scaled_linear": + # this schedule is very specific to the latent diffusion model. + self.betas = torch.linspace(beta_start**0.5, beta_end**0.5, num_train_timesteps, dtype=torch.float32) ** 2 + elif beta_schedule == "squaredcos_cap_v2": + # Glide cosine schedule + self.betas = betas_for_alpha_bar(num_train_timesteps) + else: + raise NotImplementedError(f"{beta_schedule} does is not implemented for {self.__class__}") + + # Rescale for zero SNR + if rescale_betas_zero_snr: + self.betas = rescale_zero_terminal_snr(self.betas) + + self.alphas = 1.0 - self.betas + self.alphas_cumprod = torch.cumprod(self.alphas, dim=0) + + # At every step in ddim, we are looking into the previous alphas_cumprod + # For the final step, there is no previous alphas_cumprod because we are already at 0 + # `set_alpha_to_one` decides whether we set this parameter simply to one or + # whether we use the final alpha of the "non-previous" one. + self.final_alpha_cumprod = torch.tensor(1.0) if set_alpha_to_one else self.alphas_cumprod[0] + + # standard deviation of the initial noise distribution + self.init_noise_sigma = 1.0 + + # setable values + self.num_inference_steps = None + self.timesteps = torch.from_numpy(np.arange(0, num_train_timesteps)[::-1].copy().astype(np.int64)) + self.custom_timesteps = False + + self._step_index = None + + # Copied from diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler._init_step_index + def _init_step_index(self, timestep): + if isinstance(timestep, torch.Tensor): + timestep = timestep.to(self.timesteps.device) + + index_candidates = (self.timesteps == timestep).nonzero() + + # The sigma index that is taken for the **very** first `step` + # is always the second index (or the last index if there is only 1) + # This way we can ensure we don't accidentally skip a sigma in + # case we start in the middle of the denoising schedule (e.g. for image-to-image) + if len(index_candidates) > 1: + step_index = index_candidates[1] + else: + step_index = index_candidates[0] + + self._step_index = step_index.item() + + @property + def step_index(self): + return self._step_index + + def scale_model_input(self, sample: torch.FloatTensor, timestep: Optional[int] = None) -> torch.FloatTensor: + """ + Ensures interchangeability with schedulers that need to scale the denoising model input depending on the + current timestep. + + Args: + sample (`torch.FloatTensor`): + The input sample. + timestep (`int`, *optional*): + The current timestep in the diffusion chain. + Returns: + `torch.FloatTensor`: + A scaled input sample. + """ + return sample + + def _get_variance(self, timestep, prev_timestep): + alpha_prod_t = self.alphas_cumprod[timestep] + alpha_prod_t_prev = self.alphas_cumprod[prev_timestep] if prev_timestep >= 0 else self.final_alpha_cumprod + beta_prod_t = 1 - alpha_prod_t + beta_prod_t_prev = 1 - alpha_prod_t_prev + + variance = (beta_prod_t_prev / beta_prod_t) * (1 - alpha_prod_t / alpha_prod_t_prev) + + return variance + + # Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler._threshold_sample + def _threshold_sample(self, sample: torch.FloatTensor) -> torch.FloatTensor: + """ + "Dynamic thresholding: At each sampling step we set s to a certain percentile absolute pixel value in xt0 (the + prediction of x_0 at timestep t), and if s > 1, then we threshold xt0 to the range [-s, s] and then divide by + s. Dynamic thresholding pushes saturated pixels (those near -1 and 1) inwards, thereby actively preventing + pixels from saturation at each step. We find that dynamic thresholding results in significantly better + photorealism as well as better image-text alignment, especially when using very large guidance weights." + + https://arxiv.org/abs/2205.11487 + """ + dtype = sample.dtype + batch_size, channels, *remaining_dims = sample.shape + + if dtype not in (torch.float32, torch.float64): + sample = sample.float() # upcast for quantile calculation, and clamp not implemented for cpu half + + # Flatten sample for doing quantile calculation along each image + sample = sample.reshape(batch_size, channels * np.prod(remaining_dims)) + + abs_sample = sample.abs() # "a certain percentile absolute pixel value" + + s = torch.quantile(abs_sample, self.config.dynamic_thresholding_ratio, dim=1) + s = torch.clamp( + s, min=1, max=self.config.sample_max_value + ) # When clamped to min=1, equivalent to standard clipping to [-1, 1] + s = s.unsqueeze(1) # (batch_size, 1) because clamp will broadcast along dim=0 + sample = torch.clamp(sample, -s, s) / s # "we threshold xt0 to the range [-s, s] and then divide by s" + + sample = sample.reshape(batch_size, channels, *remaining_dims) + sample = sample.to(dtype) + + return sample + + def set_timesteps( + self, + num_inference_steps: Optional[int] = None, + device: Union[str, torch.device] = None, + original_inference_steps: Optional[int] = None, + timesteps: Optional[List[int]] = None, + strength: int = 1.0, + ): + """ + Sets the discrete timesteps used for the diffusion chain (to be run before inference). + + Args: + num_inference_steps (`int`, *optional*): + The number of diffusion steps used when generating samples with a pre-trained model. If used, + `timesteps` must be `None`. + device (`str` or `torch.device`, *optional*): + The device to which the timesteps should be moved to. If `None`, the timesteps are not moved. + original_inference_steps (`int`, *optional*): + The original number of inference steps, which will be used to generate a linearly-spaced timestep + schedule (which is different from the standard `diffusers` implementation). We will then take + `num_inference_steps` timesteps from this schedule, evenly spaced in terms of indices, and use that as + our final timestep schedule. If not set, this will default to the `original_inference_steps` attribute. + timesteps (`List[int]`, *optional*): + Custom timesteps used to support arbitrary spacing between timesteps. If `None`, then the default + timestep spacing strategy of equal spacing between timesteps on the training/distillation timestep + schedule is used. If `timesteps` is passed, `num_inference_steps` must be `None`. + """ + # 0. Check inputs + if num_inference_steps is None and timesteps is None: + raise ValueError("Must pass exactly one of `num_inference_steps` or `custom_timesteps`.") + + if num_inference_steps is not None and timesteps is not None: + raise ValueError("Can only pass one of `num_inference_steps` or `custom_timesteps`.") + + # 1. Calculate the TCD original training/distillation timestep schedule. + original_steps = ( + original_inference_steps if original_inference_steps is not None else self.config.original_inference_steps + ) + + if original_steps is not None: + if original_steps > self.config.num_train_timesteps: + raise ValueError( + f"`original_steps`: {original_steps} cannot be larger than `self.config.train_timesteps`:" + f" {self.config.num_train_timesteps} as the unet model trained with this scheduler can only handle" + f" maximal {self.config.num_train_timesteps} timesteps." + ) + # TCD Timesteps Setting + # The skipping step parameter k from the paper. + k = self.config.num_train_timesteps // original_steps + # TCD Training/Distillation Steps Schedule + tcd_origin_timesteps = np.asarray(list(range(1, int(original_steps * strength) + 1))) * k - 1 + else: + tcd_origin_timesteps = np.asarray(list(range(0, int(self.config.num_train_timesteps * strength)))) + + # 2. Calculate the TCD inference timestep schedule. + if timesteps is not None: + # 2.1 Handle custom timestep schedules. + train_timesteps = set(tcd_origin_timesteps) + non_train_timesteps = [] + for i in range(1, len(timesteps)): + if timesteps[i] >= timesteps[i - 1]: + raise ValueError("`custom_timesteps` must be in descending order.") + + if timesteps[i] not in train_timesteps: + non_train_timesteps.append(timesteps[i]) + + if timesteps[0] >= self.config.num_train_timesteps: + raise ValueError( + f"`timesteps` must start before `self.config.train_timesteps`:" + f" {self.config.num_train_timesteps}." + ) + + # Raise warning if timestep schedule does not start with self.config.num_train_timesteps - 1 + if strength == 1.0 and timesteps[0] != self.config.num_train_timesteps - 1: + logger.warning( + f"The first timestep on the custom timestep schedule is {timesteps[0]}, not" + f" `self.config.num_train_timesteps - 1`: {self.config.num_train_timesteps - 1}. You may get" + f" unexpected results when using this timestep schedule." + ) + + # Raise warning if custom timestep schedule contains timesteps not on original timestep schedule + if non_train_timesteps: + logger.warning( + f"The custom timestep schedule contains the following timesteps which are not on the original" + f" training/distillation timestep schedule: {non_train_timesteps}. You may get unexpected results" + f" when using this timestep schedule." + ) + + # Raise warning if custom timestep schedule is longer than original_steps + if original_steps is not None: + if len(timesteps) > original_steps: + logger.warning( + f"The number of timesteps in the custom timestep schedule is {len(timesteps)}, which exceeds the" + f" the length of the timestep schedule used for training: {original_steps}. You may get some" + f" unexpected results when using this timestep schedule." + ) + else: + if len(timesteps) > self.config.num_train_timesteps: + logger.warning( + f"The number of timesteps in the custom timestep schedule is {len(timesteps)}, which exceeds the" + f" the length of the timestep schedule used for training: {self.config.num_train_timesteps}. You may get some" + f" unexpected results when using this timestep schedule." + ) + + timesteps = np.array(timesteps, dtype=np.int64) + self.num_inference_steps = len(timesteps) + self.custom_timesteps = True + + # Apply strength (e.g. for img2img pipelines) (see StableDiffusionImg2ImgPipeline.get_timesteps) + init_timestep = min(int(self.num_inference_steps * strength), self.num_inference_steps) + t_start = max(self.num_inference_steps - init_timestep, 0) + timesteps = timesteps[t_start * self.order :] + # TODO: also reset self.num_inference_steps? + else: + # 2.2 Create the "standard" TCD inference timestep schedule. + if num_inference_steps > self.config.num_train_timesteps: + raise ValueError( + f"`num_inference_steps`: {num_inference_steps} cannot be larger than `self.config.train_timesteps`:" + f" {self.config.num_train_timesteps} as the unet model trained with this scheduler can only handle" + f" maximal {self.config.num_train_timesteps} timesteps." + ) + + if original_steps is not None: + skipping_step = len(tcd_origin_timesteps) // num_inference_steps + + if skipping_step < 1: + raise ValueError( + f"The combination of `original_steps x strength`: {original_steps} x {strength} is smaller than `num_inference_steps`: {num_inference_steps}. Make sure to either reduce `num_inference_steps` to a value smaller than {int(original_steps * strength)} or increase `strength` to a value higher than {float(num_inference_steps / original_steps)}." + ) + + self.num_inference_steps = num_inference_steps + + if original_steps is not None: + if num_inference_steps > original_steps: + raise ValueError( + f"`num_inference_steps`: {num_inference_steps} cannot be larger than `original_inference_steps`:" + f" {original_steps} because the final timestep schedule will be a subset of the" + f" `original_inference_steps`-sized initial timestep schedule." + ) + else: + if num_inference_steps > self.config.num_train_timesteps: + raise ValueError( + f"`num_inference_steps`: {num_inference_steps} cannot be larger than `num_train_timesteps`:" + f" {self.config.num_train_timesteps} because the final timestep schedule will be a subset of the" + f" `num_train_timesteps`-sized initial timestep schedule." + ) + + # TCD Inference Steps Schedule + tcd_origin_timesteps = tcd_origin_timesteps[::-1].copy() + # Select (approximately) evenly spaced indices from tcd_origin_timesteps. + inference_indices = np.linspace(0, len(tcd_origin_timesteps), num=num_inference_steps, endpoint=False) + inference_indices = np.floor(inference_indices).astype(np.int64) + timesteps = tcd_origin_timesteps[inference_indices] + + self.timesteps = torch.from_numpy(timesteps).to(device=device, dtype=torch.long) + + self._step_index = None + + def step( + self, + model_output: torch.FloatTensor, + timestep: int, + sample: torch.FloatTensor, + eta: float, + generator: Optional[torch.Generator] = None, + return_dict: bool = True, + ) -> Union[TCDSchedulerOutput, Tuple]: + """ + Predict the sample from the previous timestep by reversing the SDE. This function propagates the diffusion + process from the learned model outputs (most often the predicted noise). + + Args: + model_output (`torch.FloatTensor`): + The direct output from learned diffusion model. + timestep (`int`): + The current discrete timestep in the diffusion chain. + sample (`torch.FloatTensor`): + A current instance of a sample created by the diffusion process. + eta (`float`): + A stochastic parameter (referred to as `gamma` in the paper) used to control the stochasticity in every step. + When eta = 0, it represents deterministic sampling, whereas eta = 1 indicates full stochastic sampling. + generator (`torch.Generator`, *optional*): + A random number generator. + return_dict (`bool`, *optional*, defaults to `True`): + Whether or not to return a [`~schedulers.scheduling_tcd.TCDSchedulerOutput`] or `tuple`. + Returns: + [`~schedulers.scheduling_utils.TCDSchedulerOutput`] or `tuple`: + If return_dict is `True`, [`~schedulers.scheduling_tcd.TCDSchedulerOutput`] is returned, otherwise a + tuple is returned where the first element is the sample tensor. + """ + if self.num_inference_steps is None: + raise ValueError( + "Number of inference steps is 'None', you need to run 'set_timesteps' after creating the scheduler" + ) + + if self.step_index is None: + self._init_step_index(timestep) + + # 1. get previous step value + prev_step_index = self.step_index + 1 + if prev_step_index < len(self.timesteps): + prev_timestep = self.timesteps[prev_step_index] + else: + prev_timestep = torch.tensor(0) + + timestep_s = torch.floor((1 - eta) * prev_timestep).to(dtype=torch.long) + + # 2. compute alphas, betas + alpha_prod_t = self.alphas_cumprod[timestep] + beta_prod_t = 1 - alpha_prod_t + + alpha_prod_t_prev = self.alphas_cumprod[prev_timestep] if prev_timestep >= 0 else self.final_alpha_cumprod + _beta_prod_t_prev = 1 - alpha_prod_t_prev + + alpha_prod_s = self.alphas_cumprod[timestep_s] if timestep_s >= 0 else self.final_alpha_cumprod + beta_prod_s = 1 - alpha_prod_s + + # 3. Compute the predicted noised sample x_s based on the model parameterization + if self.config.prediction_type == "epsilon": # noise-prediction + pred_original_sample = (sample - beta_prod_t.sqrt() * model_output) / alpha_prod_t.sqrt() + pred_epsilon = model_output + pred_noised_sample = alpha_prod_s.sqrt() * pred_original_sample + beta_prod_s.sqrt() * pred_epsilon + elif self.config.prediction_type == "sample": # x-prediction + pred_original_sample = model_output + pred_epsilon = (sample - alpha_prod_t ** (0.5) * pred_original_sample) / beta_prod_t ** (0.5) + pred_noised_sample = alpha_prod_s.sqrt() * pred_original_sample + beta_prod_s.sqrt() * pred_epsilon + elif self.config.prediction_type == "v_prediction": # v-prediction + pred_original_sample = (alpha_prod_t**0.5) * sample - (beta_prod_t**0.5) * model_output + pred_epsilon = (alpha_prod_t**0.5) * model_output + (beta_prod_t**0.5) * sample + pred_noised_sample = alpha_prod_s.sqrt() * pred_original_sample + beta_prod_s.sqrt() * pred_epsilon + else: + raise ValueError( + f"prediction_type given as {self.config.prediction_type} must be one of `epsilon`, `sample` or" + " `v_prediction` for `TCDScheduler`." + ) + + # 4. Sample and inject noise z ~ N(0, I) for MultiStep Inference + # Noise is not used on the final timestep of the timestep schedule. + # This also means that noise is not used for one-step sampling. + # Eta (referred to as "gamma" in the paper) was introduced to control the stochasticity in every step. + # When eta = 0, it represents deterministic sampling, whereas eta = 1 indicates full stochastic sampling. + if eta > 0: + if self.step_index != self.num_inference_steps - 1: + noise = randn_tensor( + model_output.shape, generator=generator, device=model_output.device, dtype=pred_noised_sample.dtype + ) + prev_sample = (alpha_prod_t_prev / alpha_prod_s).sqrt() * pred_noised_sample + (1 - alpha_prod_t_prev / alpha_prod_s).sqrt() * noise + else: + prev_sample = pred_noised_sample + else: + prev_sample = pred_noised_sample + + # upon completion increase step index by one + self._step_index += 1 + + if not return_dict: + return (prev_sample, pred_noised_sample) + + return TCDSchedulerOutput(prev_sample=prev_sample, pred_noised_sample=pred_noised_sample) + + # Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler.add_noise + def add_noise( + self, + original_samples: torch.FloatTensor, + noise: torch.FloatTensor, + timesteps: torch.IntTensor, + ) -> torch.FloatTensor: + # Make sure alphas_cumprod and timestep have same device and dtype as original_samples + alphas_cumprod = self.alphas_cumprod.to(device=original_samples.device, dtype=original_samples.dtype) + timesteps = timesteps.to(original_samples.device) + + sqrt_alpha_prod = alphas_cumprod[timesteps] ** 0.5 + sqrt_alpha_prod = sqrt_alpha_prod.flatten() + while len(sqrt_alpha_prod.shape) < len(original_samples.shape): + sqrt_alpha_prod = sqrt_alpha_prod.unsqueeze(-1) + + sqrt_one_minus_alpha_prod = (1 - alphas_cumprod[timesteps]) ** 0.5 + sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.flatten() + while len(sqrt_one_minus_alpha_prod.shape) < len(original_samples.shape): + sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.unsqueeze(-1) + + noisy_samples = sqrt_alpha_prod * original_samples + sqrt_one_minus_alpha_prod * noise + return noisy_samples + + # Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler.get_velocity + def get_velocity( + self, sample: torch.FloatTensor, noise: torch.FloatTensor, timesteps: torch.IntTensor + ) -> torch.FloatTensor: + # Make sure alphas_cumprod and timestep have same device and dtype as sample + alphas_cumprod = self.alphas_cumprod.to(device=sample.device, dtype=sample.dtype) + timesteps = timesteps.to(sample.device) + + sqrt_alpha_prod = alphas_cumprod[timesteps] ** 0.5 + sqrt_alpha_prod = sqrt_alpha_prod.flatten() + while len(sqrt_alpha_prod.shape) < len(sample.shape): + sqrt_alpha_prod = sqrt_alpha_prod.unsqueeze(-1) + + sqrt_one_minus_alpha_prod = (1 - alphas_cumprod[timesteps]) ** 0.5 + sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.flatten() + while len(sqrt_one_minus_alpha_prod.shape) < len(sample.shape): + sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.unsqueeze(-1) + + velocity = sqrt_alpha_prod * noise - sqrt_one_minus_alpha_prod * sample + return velocity + + def __len__(self): + return self.config.num_train_timesteps + + # Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler.previous_timestep + def previous_timestep(self, timestep): + if self.custom_timesteps: + index = (self.timesteps == timestep).nonzero(as_tuple=True)[0][0] + if index == self.timesteps.shape[0] - 1: + prev_t = torch.tensor(-1) + else: + prev_t = self.timesteps[index + 1] + else: + num_inference_steps = ( + self.num_inference_steps if self.num_inference_steps else self.config.num_train_timesteps + ) + prev_t = timestep - self.config.num_train_timesteps // num_inference_steps + + return prev_t diff --git a/pyproject.toml b/pyproject.toml index 20b085569..780dc95be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,6 +16,7 @@ exclude = [ "modules/control/units/*_pipe.py", "modules/pipelines/*.py", "modules/xadapter/*.py", + "modules/tcd/*.py", ] [tool.ruff.lint] select = [ diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 9d2022641..e2ff148cd 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -246,7 +246,7 @@ axis_options = [ AxisOption("[Sampler] Sigma tmax", float, apply_field("s_tmax")), AxisOption("[Sampler] Sigma Churn", float, apply_field("s_churn")), AxisOption("[Sampler] Sigma noise", float, apply_field("s_noise")), - AxisOption("[Sampler] ETA", float, apply_field("eta")), + AxisOption("[Sampler] ETA", float, apply_setting("scheduler_eta")), AxisOption("[Sampler] Solver order", int, apply_setting("schedulers_solver_order")), AxisOption("[Second pass] Upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]), AxisOption("[Second pass] Sampler", str, apply_hr_sampler_name, fmt=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),

qXi 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�n75Gta#6i@*5GPrmzU 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 diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py index d775cc722..8cc81de4e 100644 --- a/modules/textual_inversion/textual_inversion.py +++ b/modules/textual_inversion/textual_inversion.py @@ -1,25 +1,17 @@ -from typing import List, Optional, Union -import csv -import html +from typing import List, Union import os import time from collections import namedtuple import torch -from tqdm import tqdm import safetensors.torch -import numpy as np -from PIL import Image, PngImagePlugin -from installer import install -from modules import shared, devices, processing, sd_models, images, errors -import modules.textual_inversion.dataset -from modules.textual_inversion.learn_schedule import LearnRateScheduler -from modules.textual_inversion.image_embedding import embedding_to_b64, embedding_from_b64, insert_image_data_embed, extract_image_data_embed, caption_image_overlay -from modules.textual_inversion.ti_logging import save_settings_to_file +from PIL import Image +from modules import shared, devices, sd_models, errors +from modules.textual_inversion.image_embedding import embedding_from_b64, extract_image_data_embed from modules.files_cache import directory_files, directory_mtime, extension_filter + debug = shared.log.trace if os.environ.get('SD_TI_DEBUG', None) is not None else lambda *args, **kwargs: None debug('Trace: TEXTUAL INVERSION') - TokenToAdd = namedtuple("TokenToAdd", ["clip_l", "clip_g"]) TextualInversionTemplate = namedtuple("TextualInversionTemplate", ["name", "path"]) textual_inversion_templates = {} @@ -386,374 +378,3 @@ class EmbeddingDatabase: if tokens[offset:offset + len(ids)] == ids: return embedding, len(ids) return None, None - - -def create_embedding(name, num_vectors_per_token, overwrite_old, init_text='*'): - cond_model = shared.sd_model.cond_stage_model - with devices.autocast(): - cond_model([""]) # will send cond model to GPU if lowvram/medvram is active - #cond_model expects at least some text, so we provide '*' as backup. - embedded = cond_model.encode_embedding_init_text(init_text or '*', num_vectors_per_token) - vec = torch.zeros((num_vectors_per_token, embedded.shape[1]), device=devices.device) - #Only copy if we provided an init_text, otherwise keep vectors as zeros - if init_text: - for i in range(num_vectors_per_token): - vec[i] = embedded[i * int(embedded.shape[0]) // num_vectors_per_token] - # Remove illegal characters from name. - name = "".join( x for x in name if (x.isalnum() or x in "._- ")) - fn = os.path.join(shared.opts.embeddings_dir, f"{name}.pt") - if not overwrite_old and os.path.exists(fn): - shared.log.warning(f"Embedding already exists: {fn}") - else: - embedding = Embedding(vec=vec, name=name, filename=fn) - embedding.step = 0 - embedding.save(fn) - shared.log.info(f'Created embedding: {fn} vectors {num_vectors_per_token} init {init_text}') - return fn - - -def write_loss(log_directory, filename, step, epoch_len, values): - if shared.opts.training_write_csv_every == 0: - return - if step % shared.opts.training_write_csv_every != 0: - return - write_csv_header = False if os.path.exists(os.path.join(log_directory, filename)) else True - with open(os.path.join(log_directory, filename), "a+", newline='', encoding='utf-8') as fout: - csv_writer = csv.DictWriter(fout, fieldnames=["step", "epoch", "epoch_step", *(values.keys())]) - if write_csv_header: - csv_writer.writeheader() - epoch = (step - 1) // epoch_len - epoch_step = (step - 1) % epoch_len - csv_writer.writerow({ - "step": step, - "epoch": epoch, - "epoch_step": epoch_step, - **values, - }) - - -def tensorboard_setup(log_directory): - install('tensorboard') - from torch.utils.tensorboard import SummaryWriter - os.makedirs(os.path.join(log_directory, "tensorboard"), exist_ok=True) - return SummaryWriter( - log_dir=os.path.join(log_directory, "tensorboard"), - flush_secs=shared.opts.training_tensorboard_flush_every) - - -def tensorboard_add(tensorboard_writer, loss, global_step, step, learn_rate, epoch_num): - tensorboard_add_scaler(tensorboard_writer, "Loss/train", loss, global_step) - tensorboard_add_scaler(tensorboard_writer, f"Loss/train/epoch-{epoch_num}", loss, step) - tensorboard_add_scaler(tensorboard_writer, "Learn rate/train", learn_rate, global_step) - tensorboard_add_scaler(tensorboard_writer, f"Learn rate/train/epoch-{epoch_num}", learn_rate, step) - - -def tensorboard_add_scaler(tensorboard_writer, tag, value, step): - tensorboard_writer.add_scalar(tag=tag, scalar_value=value, global_step=step) - - -def tensorboard_add_image(tensorboard_writer, tag, pil_image, step): - # Convert a pil image to a torch tensor - img_tensor = torch.as_tensor(np.array(pil_image, copy=True)) - img_tensor = img_tensor.view(pil_image.size[1], pil_image.size[0], len(pil_image.getbands())) - img_tensor = img_tensor.permute((2, 0, 1)) - tensorboard_writer.add_image(tag, img_tensor, global_step=step) - - -def validate_train_inputs(model_name, learn_rate, batch_size, gradient_step, data_root, template_file, template_filename, steps, save_model_every, create_image_every, name="embedding"): - assert model_name, f"{name} not selected" - assert learn_rate, "Learning rate is empty or 0" - assert isinstance(batch_size, int), "Batch size must be integer" - assert batch_size > 0, "Batch size must be positive" - assert isinstance(gradient_step, int), "Gradient accumulation step must be integer" - assert gradient_step > 0, "Gradient accumulation step must be positive" - assert data_root, "Dataset directory is empty" - assert os.path.isdir(data_root), "Dataset directory doesn't exist" - assert os.listdir(data_root), "Dataset directory is empty" - assert template_filename, "Prompt template file not selected" - assert template_file, f"Prompt template file {template_filename} not found" - assert os.path.isfile(template_file.path), f"Prompt template file {template_filename} doesn't exist" - assert steps, "Max steps is empty or 0" - assert isinstance(steps, int), "Max steps must be integer" - assert steps > 0, "Max steps must be positive" - assert isinstance(save_model_every, int), "Save {name} must be integer" - assert save_model_every >= 0, "Save {name} must be positive or 0" - assert isinstance(create_image_every, int), "Create image must be integer" - assert create_image_every >= 0, "Create image must be positive or 0" - - -def train_embedding(id_task, embedding_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_embedding_every, template_filename, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): # pylint: disable=unused-argument - from modules import sd_hijack, sd_hijack_checkpoint - - shared.log.debug(f'train_embedding: embedding_name={embedding_name}|learn_rate={learn_rate}|batch_size={batch_size}|gradient_step={gradient_step}|data_root={data_root}|log_directory={log_directory}|training_width={training_width}|training_height={training_height}|varsize={varsize}|steps={steps}|clip_grad_mode={clip_grad_mode}|clip_grad_value={clip_grad_value}|shuffle_tags={shuffle_tags}|tag_drop_out={tag_drop_out}|latent_sampling_method={latent_sampling_method}|use_weight={use_weight}|create_image_every={create_image_every}|save_embedding_every={save_embedding_every}|template_filename={template_filename}|save_image_with_stored_embedding={save_image_with_stored_embedding}|preview_from_txt2img={preview_from_txt2img}|preview_prompt={preview_prompt}|preview_negative_prompt={preview_negative_prompt}|preview_steps={preview_steps}|preview_sampler_index={preview_sampler_index}|preview_cfg_scale={preview_cfg_scale}|preview_seed={preview_seed}|preview_width={preview_width}|preview_height={preview_height}') - save_embedding_every = save_embedding_every or 0 - create_image_every = create_image_every or 0 - template_file = textual_inversion_templates.get(template_filename, None) - validate_train_inputs(embedding_name, learn_rate, batch_size, gradient_step, data_root, template_file, template_filename, steps, save_embedding_every, create_image_every, name="embedding") - if log_directory is None or log_directory == '': - log_directory = f"{os.path.join(shared.cmd_opts.data_dir, 'train/log/embeddings')}" - template_file = template_file.path - - shared.state.job = "train" - shared.state.textinfo = "Initializing textual inversion training..." - shared.state.job_count = steps - - filename = os.path.join(shared.opts.embeddings_dir, f'{embedding_name}.pt') - - if log_directory == '': - log_directory = f"{os.path.join(shared.cmd_opts.data_dir, 'train/log/embeddings')}" - log_directory = os.path.join(log_directory, embedding_name) - unload = shared.opts.unload_models_when_training - - if save_embedding_every > 0: - embedding_dir = os.path.join(log_directory, "embeddings") - os.makedirs(embedding_dir, exist_ok=True) - else: - embedding_dir = None - - if create_image_every > 0: - images_dir = os.path.join(log_directory, "images") - os.makedirs(images_dir, exist_ok=True) - else: - images_dir = None - - if create_image_every > 0 and save_image_with_stored_embedding: - images_embeds_dir = os.path.join(log_directory, "image_embeddings") - os.makedirs(images_embeds_dir, exist_ok=True) - else: - images_embeds_dir = None - - hijack = sd_hijack.model_hijack - embedding = hijack.embedding_db.word_embeddings[embedding_name] - checkpoint = sd_models.select_checkpoint() - initial_step = embedding.step or 0 - if initial_step >= steps: - shared.state.textinfo = "Model has already been trained beyond specified max steps" - return embedding, filename - scheduler = LearnRateScheduler(learn_rate, steps, initial_step) - clip_grad = torch.nn.utils.clip_grad_value_ if clip_grad_mode == "value" else \ - torch.nn.utils.clip_grad_norm_ if clip_grad_mode == "norm" else \ - None - if clip_grad: - clip_grad_sched = LearnRateScheduler(clip_grad_value, steps, initial_step, verbose=False) - # dataset loading may take a while, so input validations and early returns should be done before this - shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..." - old_parallel_processing_allowed = shared.parallel_processing_allowed - - if shared.opts.training_enable_tensorboard: - tensorboard_writer = tensorboard_setup(log_directory) - - pin_memory = shared.opts.pin_memory - # init dataset - ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, model=shared.sd_model, cond_model=shared.sd_model.cond_stage_model, device=devices.device, template_file=template_file, batch_size=batch_size, gradient_step=gradient_step, shuffle_tags=shuffle_tags, tag_drop_out=tag_drop_out, latent_sampling_method=latent_sampling_method, varsize=varsize, use_weight=use_weight) - - if shared.opts.save_training_settings_to_txt: - save_settings_to_file(log_directory, {**dict(model_name=checkpoint.model_name, model_hash=checkpoint.shorthash, num_of_dataset_images=len(ds), num_vectors_per_token=len(embedding.vec)), **locals()}) - latent_sampling_method = ds.latent_sampling_method - # init dataloader - dl = modules.textual_inversion.dataset.PersonalizedDataLoader(ds, latent_sampling_method=latent_sampling_method, batch_size=ds.batch_size, pin_memory=pin_memory) - if unload: - shared.parallel_processing_allowed = False - shared.sd_model.first_stage_model.to(devices.cpu) - - embedding.vec.requires_grad = True - optimizer = torch.optim.AdamW([embedding.vec], lr=scheduler.learn_rate, weight_decay=0.0) - if shared.opts.save_optimizer_state: - optimizer_state_dict = None - if os.path.exists(f"{filename}.optim"): - optimizer_saved_dict = torch.load(f"{filename}.optim", map_location='cpu') - if embedding.checksum() == optimizer_saved_dict.get('hash', None): - optimizer_state_dict = optimizer_saved_dict.get('optimizer_state_dict', None) - if optimizer_state_dict is not None: - optimizer.load_state_dict(optimizer_state_dict) - shared.log.info("Load existing optimizer from checkpoint") - else: - shared.log.info("No saved optimizer exists in checkpoint") - - scaler = torch.cuda.amp.GradScaler() - - batch_size = ds.batch_size - gradient_step = ds.gradient_step - # n steps = batch_size * gradient_step * n image processed - steps_per_epoch = len(ds) // batch_size // gradient_step - max_steps_per_epoch = len(ds) // batch_size - (len(ds) // batch_size) % gradient_step - loss_step = 0 - _loss_step = 0 #internal - last_saved_file = "" - last_saved_image = "" - forced_filename = "" - embedding_yet_to_be_embedded = False - is_training_inpainting_model = shared.sd_model.model.conditioning_key in {'hybrid', 'concat'} - img_c = None - - pbar = tqdm(total=steps - initial_step) - try: - sd_hijack_checkpoint.add() - for _i in range((steps-initial_step) * gradient_step): - if scheduler.finished: - break - if shared.state.interrupted: - break - for j, batch in enumerate(dl): - # works as a drop_last=True for gradient accumulation - if j == max_steps_per_epoch: - break - scheduler.apply(optimizer, embedding.step) - if scheduler.finished: - break - if shared.state.interrupted: - break - if clip_grad: - clip_grad_sched.step(embedding.step) - with devices.autocast(): - x = batch.latent_sample.to(devices.device, non_blocking=pin_memory) - if use_weight: - w = batch.weight.to(devices.device, non_blocking=pin_memory) - c = shared.sd_model.cond_stage_model(batch.cond_text) - if is_training_inpainting_model: - if img_c is None: - img_c = processing.txt2img_image_conditioning(shared.sd_model, c, training_width, training_height) - cond = {"c_concat": [img_c], "c_crossattn": [c]} - else: - cond = c - if use_weight: - loss = shared.sd_model.weighted_forward(x, cond, w)[0] / gradient_step - del w - else: - loss = shared.sd_model.forward(x, cond)[0] / gradient_step - del x - _loss_step += loss.item() - - scaler.scale(loss).backward() - # go back until we reach gradient accumulation steps - if (j + 1) % gradient_step != 0: - continue - if clip_grad: - clip_grad(embedding.vec, clip_grad_sched.learn_rate) - - scaler.step(optimizer) - scaler.update() - embedding.step += 1 - pbar.update() - optimizer.zero_grad(set_to_none=True) - loss_step = _loss_step - _loss_step = 0 - steps_done = embedding.step + 1 - epoch_num = embedding.step // steps_per_epoch - - description = f"Training textual inversion step {embedding.step} loss: {loss_step:.5f} lr: {scheduler.learn_rate:.5f}" - pbar.set_description(description) - if embedding_dir is not None and steps_done % save_embedding_every == 0: - # Before saving, change name to match current checkpoint. - embedding_name_every = f'{embedding_name}-{steps_done}' - last_saved_file = os.path.join(embedding_dir, f'{embedding_name_every}.pt') - save_embedding(embedding, optimizer, checkpoint, embedding_name_every, last_saved_file, remove_cached_checksum=True) - embedding_yet_to_be_embedded = True - - write_loss(log_directory, f"{embedding_name}.csv", embedding.step, steps_per_epoch, { "loss": f"{loss_step:.7f}", "learn_rate": scheduler.learn_rate }) - - if images_dir is not None and steps_done % create_image_every == 0: - forced_filename = f'{embedding_name}-{steps_done}' - last_saved_image = os.path.join(images_dir, forced_filename) - shared.sd_model.first_stage_model.to(devices.device) - - p = processing.StableDiffusionProcessingTxt2Img( - sd_model=shared.sd_model, - do_not_save_grid=True, - do_not_save_samples=True, - do_not_reload_embeddings=True, - ) - - if preview_from_txt2img: - p.prompt = preview_prompt - p.negative_prompt = preview_negative_prompt - p.steps = preview_steps - p.sampler_name = processing.get_sampler_name(preview_sampler_index) - p.cfg_scale = preview_cfg_scale - p.seed = preview_seed - p.width = preview_width - p.height = preview_height - else: - p.prompt = batch.cond_text[0] - p.steps = 20 - p.width = training_width - p.height = training_height - - preview_text = p.prompt - processed = processing.process_images(p) - image = processed.images[0] if len(processed.images) > 0 else None - - if unload: - shared.sd_model.first_stage_model.to(devices.cpu) - - if image is not None: - shared.state.assign_current_image(image) - 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}" - if shared.opts.training_enable_tensorboard and shared.opts.training_tensorboard_save_images: - tensorboard_add_image(tensorboard_writer, f"Validation at epoch {epoch_num}", image, embedding.step) - - if save_image_with_stored_embedding and os.path.exists(last_saved_file) and embedding_yet_to_be_embedded: - last_saved_image_chunks = os.path.join(images_embeds_dir, f'{embedding_name}-{steps_done}.png') - info = PngImagePlugin.PngInfo() - data = torch.load(last_saved_file) - info.add_text("sd-ti-embedding", embedding_to_b64(data)) - title = f"<{data.get('name', '???')}>" - try: - vectorSize = list(data['string_to_param'].values())[0].shape[0] - except Exception: - vectorSize = '?' - checkpoint = sd_models.select_checkpoint() - footer_left = checkpoint.model_name - footer_mid = f'[{checkpoint.shorthash}]' - footer_right = f'{vectorSize}v {steps_done}s' - captioned_image = caption_image_overlay(image, title, footer_left, footer_mid, footer_right) - captioned_image = insert_image_data_embed(captioned_image, data) - captioned_image.save(last_saved_image_chunks, "PNG", pnginfo=info) - embedding_yet_to_be_embedded = 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 = embedding.step - shared.state.textinfo = f""" -