mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 01:04:32 +02:00
Merge branch 'master' into vlad3
This commit is contained in:
+4
-1
@@ -1,10 +1,13 @@
|
||||
# Change Log for SD.Next
|
||||
|
||||
## Update for 2023-09-15
|
||||
## Update for 2023-09-18
|
||||
|
||||
Downgrade of `diffusers` to 0.20.2 due to critical issue with model offloading
|
||||
This means that new model **Wuerstchen** is not supported until diffusers issue is resolved
|
||||
|
||||
- Added **change log** to UI, see *System -> Changelog*
|
||||
- **Extra networks**: faster search, ability to show/hide/sort networks
|
||||
|
||||
## Update for 2023-09-13
|
||||
|
||||
Started as a mostly a service release with quite a few fixes, but then...
|
||||
|
||||
@@ -69,10 +69,10 @@ Additional models will be added as they become available and there is public int
|
||||
- *nVidia* GPUs using **CUDA** libraries on both *Windows and Linux*
|
||||
- *AMD* GPUs using **ROCm** libraries on *Linux*.
|
||||
Support will be extended to *Windows* once AMD releases ROCm for Windows
|
||||
- Any GPU compatibile with *DirectX* on *Windows* using **DirectML** libraries.
|
||||
This includes support for AMD GPUs that are not supported by native ROCm libraries
|
||||
- *Intel Arc* GPUs using **OneAPI** with *IPEX XPU* libraries on both *Windows and Linux*
|
||||
- *Intel* GPUs using **OpenVINO** libraries on both *Windows and Linux*
|
||||
- Any GPU compatible with *DirectX* on *Windows* using **DirectML** libraries.
|
||||
This includes support for AMD GPUs that are not supported by native ROCm libraries
|
||||
- Any GPU compatible with **OpenVINO** libraries on both *Windows and Linux*
|
||||
- *Apple M1/M2* on *OSX* using built-in support in Torch with **MPS** optimizations
|
||||
|
||||
## Install & Run
|
||||
@@ -175,7 +175,7 @@ General goals:
|
||||
### **Sponsors**
|
||||
|
||||
<div align="center">
|
||||
<!-- sponsors --><a href="https://github.com/Tillerz"><img src="https://github.com/Tillerz.png" width="60px" alt="Tillerz" /></a><a href="https://github.com/allangrant"><img src="https://github.com/allangrant.png" width="60px" alt="Allan Grant" /></a><a href="https://github.com/demib72"><img src="https://github.com/demib72.png" width="60px" alt="Michael Harris" /></a><a href="https://github.com/BrentOzar"><img src="https://github.com/BrentOzar.png" width="60px" alt="Brent Ozar" /></a><a href="https://github.com/AimwiseTonix"><img src="https://github.com/AimwiseTonix.png" width="60px" alt="ToniX" /></a><a href="https://github.com/inktomi"><img src="https://github.com/inktomi.png" width="60px" alt="Matthew Runo" /></a><a href="https://github.com/HELLO-WORLD-SAS"><img src="https://github.com/HELLO-WORLD-SAS.png" width="60px" alt="HELLO WORLD SAS" /></a><a href="https://github.com/4joeknight4"><img src="https://github.com/4joeknight4.png" width="60px" alt="" /></a><a href="https://github.com/SaladTechnologies"><img src="https://github.com/SaladTechnologies.png" width="60px" alt="Salad Technologies" /></a><a href="https://github.com/gymdreams8"><img src="https://github.com/gymdreams8.png" width="60px" alt="Gym Dreams • GymDreams8" /></a><!-- sponsors -->
|
||||
<!-- sponsors --><a href="https://github.com/allangrant"><img src="https://github.com/allangrant.png" width="60px" alt="Allan Grant" /></a><a href="https://github.com/demib72"><img src="https://github.com/demib72.png" width="60px" alt="Michael Harris" /></a><a href="https://github.com/BrentOzar"><img src="https://github.com/BrentOzar.png" width="60px" alt="Brent Ozar" /></a><a href="https://github.com/AimwiseTonix"><img src="https://github.com/AimwiseTonix.png" width="60px" alt="ToniX" /></a><a href="https://github.com/inktomi"><img src="https://github.com/inktomi.png" width="60px" alt="Matthew Runo" /></a><a href="https://github.com/HELLO-WORLD-SAS"><img src="https://github.com/HELLO-WORLD-SAS.png" width="60px" alt="HELLO WORLD SAS" /></a><a href="https://github.com/4joeknight4"><img src="https://github.com/4joeknight4.png" width="60px" alt="" /></a><a href="https://github.com/SaladTechnologies"><img src="https://github.com/SaladTechnologies.png" width="60px" alt="Salad Technologies" /></a><a href="https://github.com/gymdreams8"><img src="https://github.com/gymdreams8.png" width="60px" alt="Gym Dreams • GymDreams8" /></a><!-- sponsors -->
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
@@ -2,8 +2,6 @@ import os
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
|
||||
from modules.upscaler import Upscaler, UpscalerData
|
||||
from ldsr_model_arch import LDSR
|
||||
from modules import shared, script_callbacks
|
||||
@@ -42,6 +40,7 @@ class UpscalerLDSR(Upscaler):
|
||||
print("Renaming model from model.pth to model.ckpt")
|
||||
os.rename(old_model_path, new_model_path)
|
||||
|
||||
from modules.modelloader import load_file_from_url
|
||||
if local_safetensors_path is not None and os.path.exists(local_safetensors_path):
|
||||
model = local_safetensors_path
|
||||
else:
|
||||
|
||||
@@ -7,8 +7,6 @@ import numpy as np
|
||||
import torch
|
||||
from tqdm import tqdm
|
||||
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
|
||||
import modules.upscaler
|
||||
from modules import devices, modelloader, script_callbacks
|
||||
from scunet_model_arch import SCUNet as net
|
||||
@@ -121,6 +119,7 @@ class UpscalerScuNET(modules.upscaler.Upscaler):
|
||||
def load_model(self, path: str):
|
||||
device = devices.get_device_for('scunet')
|
||||
if "http" in path:
|
||||
from modules.modelloader import load_file_from_url
|
||||
filename = load_file_from_url(url=self.model_url, model_dir=self.model_download_path, file_name="%s.pth" % self.name, progress=True)
|
||||
else:
|
||||
filename = path
|
||||
|
||||
@@ -2,8 +2,7 @@ import os
|
||||
import numpy as np
|
||||
import torch
|
||||
from PIL import Image
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
from tqdm.rich import tqdm
|
||||
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn
|
||||
from swinir_model_arch import SwinIR as net
|
||||
from swinir_model_arch_v2 import Swin2SR as net2
|
||||
from modules import modelloader, devices, script_callbacks, shared
|
||||
@@ -45,11 +44,13 @@ class UpscalerSwinIR(Upscaler):
|
||||
|
||||
def load_model(self, path, scale=4):
|
||||
if "http" in path:
|
||||
dl_name = "%s%s" % (self.model_name.replace(" ", "_"), ".pth")
|
||||
from modules.modelloader import load_file_from_url
|
||||
dl_name = "%s%s" % (self.model_name.replace(" ", "_"), ".pth") # pylint: disable=consider-using-f-string
|
||||
filename = load_file_from_url(url=path, model_dir=self.model_download_path, file_name=dl_name, progress=True)
|
||||
else:
|
||||
filename = path
|
||||
if filename is None or not os.path.exists(filename):
|
||||
shared.log.error(f"Model failed loading: type=SwinIR model={filename}")
|
||||
return None
|
||||
model_v2 = net2(
|
||||
upscale=scale,
|
||||
@@ -78,6 +79,8 @@ class UpscalerSwinIR(Upscaler):
|
||||
resi_connection="3conv",
|
||||
)
|
||||
pretrained_model = torch.load(filename)
|
||||
shared.log.info(f"Model loaded: type=SwinIR model={filename}")
|
||||
|
||||
for model in [model_v1, model_v2]:
|
||||
for param in ["params_ema", "params", None]:
|
||||
try:
|
||||
@@ -140,7 +143,8 @@ def inference(img, model, tile, tile_overlap, window_size, scale):
|
||||
E = torch.zeros(b, c, h * sf, w * sf, dtype=devices.dtype, device=device_swinir).type_as(img)
|
||||
W = torch.zeros_like(E, dtype=devices.dtype, device=device_swinir)
|
||||
|
||||
with tqdm(total=len(h_idx_list) * len(w_idx_list), desc="Upscaling SwinIR") as pbar:
|
||||
with Progress(TextColumn('[cyan]{task.description}'), BarColumn(), TaskProgressColumn(), TimeRemainingColumn(), TimeElapsedColumn(), console=shared.console) as progress:
|
||||
task = progress.add_task(description="Upscaling Initializing", total=len(h_idx_list) * len(w_idx_list))
|
||||
for h_idx in h_idx_list:
|
||||
if state.interrupted or state.skipped:
|
||||
break
|
||||
@@ -159,7 +163,7 @@ def inference(img, model, tile, tile_overlap, window_size, scale):
|
||||
W[
|
||||
..., h_idx * sf: (h_idx + tile) * sf, w_idx * sf: (w_idx + tile) * sf
|
||||
].add_(out_patch_mask)
|
||||
pbar.update(1)
|
||||
progress.update(task, advance=1, description="Upscaling")
|
||||
output = E.div_(W)
|
||||
|
||||
return output
|
||||
|
||||
Submodule extensions-builtin/sd-extension-system-info updated: 83dd4d8f65...b73ffdcc8d
+7
-7
@@ -356,7 +356,7 @@
|
||||
{"id":"","label":"Enable splitting of hires batch processing","localized":"","hint":"Reduces VRAM usage when using hires fix on batches of images"},
|
||||
{"id":"","label":"Load models using stream loading method","localized":"","hint":"When loading models attempt stream loading optimized for slow or network storage"},
|
||||
{"id":"","label":"When loading models attempt to reuse previous model dictionary","localized":"","hint":""},
|
||||
{"id":"","label":"Disable cross-attention layer optimization","localized":"","hint":"Disable the all cross-attention optimization. May result in higher VRAM usage and longer generation times"},
|
||||
{"id":"","label":"Disabled","localized":"","hint":""},
|
||||
{"id":"","label":"xFormers","localized":"","hint":"Memory optimization. Non-Deterministic (different results each time)"},
|
||||
{"id":"","label":"Scaled-Dot-Product","localized":"","hint":"Memory optimization. Non-Deterministic unless SDP memory attention is disabled."},
|
||||
{"id":"","label":"Doggettx's","localized":"","hint":""},
|
||||
@@ -365,9 +365,9 @@
|
||||
{"id":"","label":"Split attention","localized":"","hint":""},
|
||||
{"id":"","label":"xFormers enable flash Attention","localized":"","hint":""},
|
||||
{"id":"","label":"SDP disable memory attention","localized":"","hint":""},
|
||||
{"id":"","label":"Sub-quadratic cross-attention query chunk size","localized":"","hint":""},
|
||||
{"id":"","label":"Sub-quadratic cross-attention kv chunk size","localized":"","hint":""},
|
||||
{"id":"","label":"Sub-quadratic cross-attention chunking threshold","localized":"","hint":""},
|
||||
{"id":"","label":"cross-attention query chunk size","localized":"","hint":""},
|
||||
{"id":"","label":"cross-attention kv chunk size","localized":"","hint":""},
|
||||
{"id":"","label":"cross-attention chunking threshold","localized":"","hint":""},
|
||||
{"id":"","label":"Full parser","localized":"","hint":""},
|
||||
{"id":"","label":"Compel parser","localized":"","hint":""},
|
||||
{"id":"","label":"A1111 parser","localized":"","hint":""},
|
||||
@@ -466,9 +466,9 @@
|
||||
{"id":"","label":"Auto","localized":"","hint":""},
|
||||
{"id":"","label":"Dark","localized":"","hint":""},
|
||||
{"id":"","label":"Light","localized":"","hint":""},
|
||||
{"id":"","label":"Show grid in results for web","localized":"","hint":""},
|
||||
{"id":"","label":"For inpainting, include the greyscale mask in results for web","localized":"","hint":""},
|
||||
{"id":"","label":"For inpainting, include masked composite in results for web","localized":"","hint":""},
|
||||
{"id":"","label":"Show grid in results","localized":"","hint":""},
|
||||
{"id":"","label":"For inpainting, include the greyscale mask in results","localized":"","hint":""},
|
||||
{"id":"","label":"For inpainting, include masked composite in results","localized":"","hint":""},
|
||||
{"id":"","label":"Do not change selected model when reading generation parameters","localized":"","hint":""},
|
||||
{"id":"","label":"Send seed when sending prompt or image to other interface","localized":"","hint":""},
|
||||
{"id":"","label":"Send size when sending prompt or image to another interface","localized":"","hint":""},
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
+2
-2
@@ -430,7 +430,7 @@ def check_torch():
|
||||
elif allow_openvino and args.use_openvino:
|
||||
#Remove this after 2.1.0 releases
|
||||
log.info('Using OpenVINO')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', '--pre torch==2.1.0.dev20230726+cpu torchvision==0.16.0.dev20230726+cpu -f https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', '--pre torch==2.1.0.dev20230820+cpu torchvision==0.16.0.dev20230820+cpu -f https://download.pytorch.org/whl/nightly/cpu/torch_nightly.html')
|
||||
else:
|
||||
machine = platform.machine()
|
||||
if sys.platform == 'darwin':
|
||||
@@ -496,7 +496,7 @@ def check_torch():
|
||||
if opts.get('cuda_compile_backend', '') == 'hidet':
|
||||
install('hidet', 'hidet')
|
||||
if args.use_openvino or opts.get('cuda_compile_backend', '') == 'openvino_fx':
|
||||
install('openvino==2023.1.0.dev20230811', 'openvino')
|
||||
install('openvino==2023.1.0', 'openvino')
|
||||
os.environ.setdefault('PYTORCH_TRACING_MODE', 'TORCHFX')
|
||||
if args.profile:
|
||||
print_profile(pr, 'Torch')
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/* generic html tags */
|
||||
:root, .light, .dark {
|
||||
--font: 'system-ui', 'ui-sans-serif', 'system-ui', "Roboto", sans-serif;
|
||||
--font-mono: 'ui-monospace', 'Consolas', monospace;
|
||||
--font-size: 16px;
|
||||
--left-column: 490px;
|
||||
--primary-100: #2b303b;
|
||||
--primary-200: #15181e;
|
||||
--primary-300: #0a0c0e;
|
||||
--primary-400: #566176;
|
||||
--primary-500: #483a90;
|
||||
--primary-700: #6b7994;
|
||||
--primary-800: #5b49b3;
|
||||
--highlight-color: var(--primary-500);
|
||||
--inactive-color: var(--primary--800);
|
||||
--body-text-color: var(--neutral-100);
|
||||
--body-text-color-subdued: var(--neutral-300);
|
||||
--background-color: var(--primary-100);
|
||||
--background-fill-primary: var(--input-background-fill);
|
||||
--input-padding: 8px;
|
||||
--input-background-fill: var(--primary-200);
|
||||
--input-shadow: none;
|
||||
--button-secondary-text-color: white;
|
||||
--button-secondary-background-fill: var(--primary-400);
|
||||
--button-secondary-background-fill-hover: var(--primary-700);
|
||||
--block-title-text-color: var(--neutral-300);
|
||||
--radius-sm: 1px;
|
||||
--radius-lg: 6px;
|
||||
--spacing-md: 4px;
|
||||
--spacing-xxl: 8px;
|
||||
--line-sm: 1.2em;
|
||||
--line-md: 1.4em;
|
||||
}
|
||||
|
||||
html { font-size: var(--font-size); }
|
||||
body, button, input, select, textarea { font-family: var(--font);}
|
||||
button { font-size: 1.2rem; max-width: 400px; }
|
||||
img { background-color: var(--background-color); }
|
||||
input[type=range] { height: var(--line-sm); appearance: none; margin-top: 0; min-width: 160px; background-color: var(--background-color); width: 100%; background: transparent; }
|
||||
input[type=range]::-webkit-slider-runnable-track, input[type=range]::-moz-range-track { width: 100%; height: 6px; cursor: pointer; background: var(--primary-400); border-radius: var(--radius-lg); border: 0px solid #222222; }
|
||||
input[type=range]::-webkit-slider-thumb, input[type=range]::-moz-range-thumb { border: 0px solid #000000; height: var(--line-sm); width: 8px; border-radius: var(--radius-lg); background: white; cursor: pointer; appearance: none; margin-top: 0px; }
|
||||
input[type=range]::-moz-range-progress { background-color: var(--primary-500); height: 6px; border-radius: var(--radius-lg); }
|
||||
::-webkit-scrollbar-track { background: #333333; }
|
||||
::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px #111111; }
|
||||
div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; margin-bottom: 6px; }
|
||||
div.compact { gap: 1em; }
|
||||
|
||||
/* 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: #111111 !important; box-shadow: 2px 2px 3px #111111; border-width: 0; padding: 4px; margin: 12px 0px 12px 0px }
|
||||
.gr-button { font-weight: normal; box-shadow: 2px 2px 3px #111111; 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: 2px 2px 3px #111111; }
|
||||
.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: #333333 !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; box-shadow: 2px 2px 2px #111; border: none !important; font-size: 0.8rem; }
|
||||
.tab-nav { zoom: 120%; margin-top: 10px; margin-bottom: 10px; border-bottom: 2px solid var(--highlight-color) !important; padding-bottom: 2px; }
|
||||
div.tab-nav button.selected {background-color: var(--button-primary-background-fill);}
|
||||
#settings div.tab-nav button.selected {background-color: var(--background-color); color: var(--primary-800); font-weight: bold;}
|
||||
.label-wrap { background-color: #363c4a; padding: 16px 8px 8px 8px; border-radius: var(--radius-lg);}
|
||||
.gradio-slider input[type="number"] { width: 4.5em; font-size: 0.8rem; height: 20px; }
|
||||
.gradio-button.tool { border: none; box-shadow: none; border-radius: var(--radius-lg);}
|
||||
button.selected {background: var(--button-primary-background-fill);}
|
||||
.center.boundedheight.flex {background-color: var(--input-background-fill);}
|
||||
.compact {border-radius: var(--border-radius-lg);}
|
||||
#logMonitorData {background-color: var(--input-background-fill);}
|
||||
#tab_extensions table td, #tab_extensions table th, #tab_config table td, #tab_config table th { border: none; padding: 0.5em; background-color: var(--primary-200); }
|
||||
#tab_extensions table, #tab_config table { width: 96vw; }
|
||||
#tab_extensions table input[type=checkbox] {appearance: none; border-radius: 0px;}
|
||||
#tab_extensions button:hover { background-color: var(--button-secondary-background-fill-hover);}
|
||||
|
||||
/* 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); }
|
||||
.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-800); color: white; border: none; border-radius: var(--radius-lg) }
|
||||
#system_row > button, #settings_row > button, #config_row > button { max-width: 190px; }
|
||||
|
||||
/* 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 { background-color: var(--background-color); box-shadow: 4px 4px 4px 0px #333333 !important; }
|
||||
#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.1rem; }
|
||||
#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: #111111; 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-top: -2px; height: 2.4em; }
|
||||
#quicksettings button {padding: 0 0.5em 0.1em 0.5em;}
|
||||
#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; }
|
||||
#script_list { padding: 4px; margin-top: 20px; margin-bottom: 20px; }
|
||||
#settings > div.flex-wrap { width: 15em; }
|
||||
#txt2img_cfg_scale { min-width: 200px; }
|
||||
#txt2img_checkboxes, #img2img_checkboxes { background-color: transparent; }
|
||||
#txt2img_checkboxes, #img2img_checkboxes { margin-bottom: 0.2em; }
|
||||
#txt2img_actions_column, #img2img_actions_column { flex-flow: wrap; justify-content: space-between; }
|
||||
#txt2img_enqueue_wrapper, #img2img_enqueue_wrapper { min-width: unset; width: 48%; }
|
||||
#txt2img_generate_box, #img2img_generate_box { min-width: unset; width: 48%; }
|
||||
|
||||
#extras_upscale { margin-top: 10px }
|
||||
#txt2img_progress_row > div { min-width: var(--left-column); max-width: var(--left-column); }
|
||||
#txt2img_results, #img2img_results, #extras_results { background-color: var(--background-color); padding: 0; }
|
||||
#txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: #111111; padding-top: 16px; }
|
||||
#pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) }
|
||||
#txt2img_tools, #img2img_tools { margin-top: -4px; margin-bottom: -4px; }
|
||||
#txt2img_styles_row, #img2img_styles_row { margin-top: -6px; z-index: 200; }
|
||||
|
||||
/* custom elements overrides */
|
||||
#steps-animation, #controlnet { border-width: 0; }
|
||||
|
||||
/* 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(--primary-400);
|
||||
--checkbox-background-color-focus: var(--primary-700);
|
||||
--checkbox-background-color-hover: var(--primary-700);
|
||||
--checkbox-background-color-selected: var(--primary-500);
|
||||
--checkbox-border-color: transparent;
|
||||
--checkbox-border-color-focus: var(--primary-800);
|
||||
--checkbox-border-color-hover: var(--primary-800);
|
||||
--checkbox-border-color-selected: var(--primary-800);
|
||||
--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-text-color: #ef4444;
|
||||
--input-background-fill-focus: var(--secondary-600);
|
||||
--input-background-fill-hover: var(--input-background-fill);
|
||||
--input-border-color: var(--background-color);
|
||||
--input-border-color-focus: var(--primary-800);
|
||||
--input-placeholder-color: var(--neutral-500);
|
||||
--input-shadow-focus: None;
|
||||
--loader_color: None;
|
||||
--slider_color: None;
|
||||
--stat-background-fill: linear-gradient(to right, var(--primary-400), var(--primary-800));
|
||||
--table-border-color: var(--neutral-700);
|
||||
--table-even-background-fill: var(--primary-300);
|
||||
--table-odd-background-fill: var(--primary-200);
|
||||
--table-row-focus: var(--color-accent-soft);
|
||||
--button-border-width: var(--input-border-width);
|
||||
--button-cancel-background-fill: linear-gradient(to bottom right, #dc2626, #b91c1c);
|
||||
--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-hover: var(--button-cancel-text-color);
|
||||
--button-primary-background-fill: var(--primary-500);
|
||||
--button-primary-background-fill-hover: var(--primary-800);
|
||||
--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-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: #333333;
|
||||
--neutral-900: #111827;
|
||||
--neutral-950: #0b0f19;
|
||||
--spacing-xxs: 1px;
|
||||
--spacing-xs: 2px;
|
||||
--spacing-sm: 4px;
|
||||
--spacing-lg: 8px;
|
||||
--spacing-xl: 10px;
|
||||
--radius-xxs: 0;
|
||||
--radius-xs: 0;
|
||||
--radius-md: 0;
|
||||
--radius-xl: 0;
|
||||
--radius-xxl: 0;
|
||||
--text-xxs: 9px;
|
||||
--text-xs: 10px;
|
||||
--text-sm: 12px;
|
||||
--text-md: 14px;
|
||||
--text-lg: 16px;
|
||||
--text-xl: 22px;
|
||||
--text-xxl: 26px;
|
||||
--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 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
--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: 0;
|
||||
--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: 1px;
|
||||
--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: 600;
|
||||
--slider-color: ;
|
||||
--table-radius: var(--radius-lg);
|
||||
--button-large-padding: 2px 10px;
|
||||
--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;
|
||||
}
|
||||
@@ -34,9 +34,10 @@ async function createSplash() {
|
||||
</div>`;
|
||||
document.body.insertAdjacentHTML('beforeend', splash);
|
||||
await preloadImages();
|
||||
const imgElement = `<div class="splash-img" alt="logo" style="background-image: url(file=html/logo-bg-${dark ? 'dark' : 'light'}.jpg), url(file=html/logo-bg-${num}.jpg); background-blend-mode: ${dark ? 'darken' : 'lighten'}"></div>`;
|
||||
const imgElement = `<div class="splash-img" alt="logo" style="background-image: url(file=html/logo-bg-${dark ? 'dark' : 'light'}.jpg), url(file=html/logo-bg-${num}.jpg); background-blend-mode: ${dark ? 'multiply' : 'lighten'}"></div>`;
|
||||
document.getElementById('splash').insertAdjacentHTML('afterbegin', imgElement);
|
||||
}
|
||||
|
||||
async function removeSplash() {
|
||||
const splash = document.getElementById('splash');
|
||||
if (splash) splash.remove();
|
||||
|
||||
@@ -75,7 +75,7 @@ let executedOnLoaded = false;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const mutationObserver = new MutationObserver((m) => {
|
||||
if (!executedOnLoaded && gradioApp().querySelector('#txt2img_prompt')) {
|
||||
if (!executedOnLoaded && gradioApp().getElementById('txt2img_prompt')) {
|
||||
executedOnLoaded = true;
|
||||
executeCallbacks(uiLoadedCallbacks);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ async function setHints() {
|
||||
if (localeData.data.length === 0) {
|
||||
const res = await fetch('/file=html/locale_en.json');
|
||||
const json = await res.json();
|
||||
localeData.data = Object.values(json).flat();
|
||||
localeData.data = Object.values(json).flat().filter((e) => e.hint.length > 0);
|
||||
for (const e of localeData.data) e.label = e.label.toLowerCase().trim();
|
||||
}
|
||||
const elements = [
|
||||
|
||||
+18
-4
@@ -1,6 +1,7 @@
|
||||
:root, .dark{ --checkbox-label-gap: 0.25em 0.1em; --section-header-text-size: 12pt; --block-background-fill: transparent;}
|
||||
a { font-weight: bold; cursor: pointer; }
|
||||
h2 { margin-top: 1em !important; font-size: 1.4em !important; }
|
||||
table { overflow-x: auto !important; overflow-y: auto !important; }
|
||||
div.gradio-container{ max-width: unset !important; padding: 8px !important; }
|
||||
div.tabitem { padding: 0 !important; }
|
||||
div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em 1em; flex-grow: 1 !important; }
|
||||
@@ -230,7 +231,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
|
||||
.extra-networks .description { flex: 3; }
|
||||
.extra-networks .tab-nav > button { margin-right: 0; height: 24px; padding: 2px 4px 2px 4px; }
|
||||
.extra-networks-tab { padding: 0 !important; }
|
||||
.extra-network-subdirs { background: var(--input-background-fill); overflow-x: hidden; overflow-y: auto; min-width: max(20%, 120px); padding-top: 0.5em; }
|
||||
.extra-network-subdirs { background: var(--input-background-fill); overflow-x: hidden; overflow-y: auto; min-width: max(15%, 120px); padding-top: 0.5em; }
|
||||
.extra-networks-page { display: flex }
|
||||
.extra-networks .custom-button { width: 120px; width: 100%; background: none; justify-content: left; text-align: left; padding: 2px 8px 2px 16px; text-indent: -8px; box-shadow: none; line-break: auto; }
|
||||
.extra-networks .custom-button:hover { background: var(--button-primary-background-fill) }
|
||||
@@ -252,7 +253,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
|
||||
#txt2img_description, #img2img_description { max-height: 63px; overflow-y: auto !important; }
|
||||
#txt2img_description > label > textarea, #img2img_description > label > textarea { font-size: 0.9em }
|
||||
|
||||
/* controlnet */
|
||||
/* controlnet
|
||||
.controlnet_control_type .controlnet_control_type_filter_group .wrap:last-of-type { display: grid; grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
||||
fieldset.controlnet_resize_mode_radio .wrap:last-of-type, fieldset.controlnet_control_mode_radio .wrap:last-of-type { flex-direction: column; }
|
||||
div.controlnet_preprocessor_model { display: grid; grid-auto-flow: row; grid-template-columns: 1fr max-content; }
|
||||
@@ -263,6 +264,7 @@ div.controlnet_image_controls { display: grid; grid-template-columns: repeat(4,
|
||||
div.controlnet_image_controls .controlnet_invert_warning { grid-column: 1 / -1; }
|
||||
div.controlnet_image_controls button { justify-self: center; }
|
||||
div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: row; }
|
||||
*/
|
||||
|
||||
/* specific elements */
|
||||
#modelmerger_interp_description { margin-top: 1em; margin-bottom: 1em; }
|
||||
@@ -281,20 +283,27 @@ div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; gri
|
||||
.log-monitor { display: none; justify-content: unset !important; overflow: hidden; padding: 0; margin-top: auto; font-family: monospace; font-size: 0.85em; }
|
||||
.log-monitor td, .log-monitor th { padding-left: 1em; }
|
||||
|
||||
/* changelog */
|
||||
.md h2 { background-color: var(--background-fill-primary); padding: 0.5em; }
|
||||
.md ul { list-style-type: square !important; text-indent: 1em; margin-left: 4em; }
|
||||
.md li { list-style-position: outside !important; text-indent: 0; }
|
||||
.md p { margin-left: 2em; }
|
||||
|
||||
/* custom component */
|
||||
.folder-selector textarea { height: 2em !important; padding: 6px !important; }
|
||||
|
||||
/* Workaround for Gradio dropdowns capturing clicks during and after fadeout */
|
||||
.gradio-dropdown > label > div > div:first-child:not(.showOptions) ~ ul.options { pointer-events: none; }
|
||||
|
||||
.splash { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 100; display: block; text-align: center; }
|
||||
.splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: move 5s infinite alternate; }
|
||||
.splash { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 1000; display: block; text-align: center; }
|
||||
.splash-img { margin: 10% auto 0 auto; width: 512px; background-repeat: no-repeat; height: 512px; animation: color 10s infinite alternate; }
|
||||
.loading { color: white; position: absolute; top: 20%; left: 50%; transform: translateX(-50%); }
|
||||
.loader { width: 300px; height: 300px; border: var(--spacing-md) solid transparent; border-radius: 50%; border-top: var(--spacing-md) solid var(--primary-600); animation: spin 4s linear infinite; position: relative; }
|
||||
.loader::before, .loader::after { content: ""; position: absolute; top: 6px; bottom: 6px; left: 6px; right: 6px; border-radius: 50%; border: var(--spacing-md) solid transparent; }
|
||||
.loader::before { border-top-color: var(--primary-900); animation: 3s spin linear infinite; }
|
||||
.loader::after { border-top-color: var(--primary-300); animation: spin 1.5s linear infinite; }
|
||||
|
||||
|
||||
@keyframes move {
|
||||
from { background-position-x: 0, -40px; }
|
||||
to { background-position-x: 0, 40px; }
|
||||
@@ -303,3 +312,8 @@ div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; gri
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes color {
|
||||
from { filter: hue-rotate(0deg) }
|
||||
to { filter: hue-rotate(360deg) }
|
||||
}
|
||||
|
||||
+1
-2
@@ -504,9 +504,8 @@ class Api:
|
||||
}
|
||||
|
||||
def get_extra_networks(self, page: Optional[str] = None, name: Optional[str] = None, filename: Optional[str] = None, title: Optional[str] = None, fullname: Optional[str] = None, hash: Optional[str] = None): # pylint: disable=redefined-builtin
|
||||
import modules.ui_extra_networks
|
||||
res = []
|
||||
for pg in modules.ui_extra_networks.extra_pages:
|
||||
for pg in shared.extra_networks:
|
||||
if page is not None and pg.name != page.lower():
|
||||
continue
|
||||
for item in pg.items:
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ def torch_gc(force=False):
|
||||
if oom > previous_oom:
|
||||
previous_oom = oom
|
||||
shared.log.warning(f'GPU out-of-memory error: {mem}')
|
||||
if used > 95:
|
||||
if used > 90:
|
||||
shared.log.info(f'GPU high memory utilization: {used}% {mem}')
|
||||
force = True
|
||||
if not force:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import math
|
||||
import torch
|
||||
from realesrgan import RealESRGANer
|
||||
from modules.realesrgan_model_arch import RealESRGANer
|
||||
|
||||
|
||||
# DML Solution: Some of contents of output tensor turn to 0 after Extended Slices. Move it to cpu.
|
||||
|
||||
+19
-13
@@ -3,12 +3,12 @@ import os
|
||||
import numpy as np
|
||||
import torch
|
||||
from PIL import Image
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn
|
||||
|
||||
import modules.esrgan_model_arch as arch
|
||||
from modules import modelloader, images, devices
|
||||
from modules.upscaler import Upscaler, UpscalerData
|
||||
from modules.shared import opts
|
||||
from modules.shared import opts, log, console
|
||||
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ class UpscalerESRGAN(Upscaler):
|
||||
|
||||
def load_model(self, path: str):
|
||||
if "http" in path:
|
||||
from modules.modelloader import load_file_from_url
|
||||
filename = load_file_from_url(
|
||||
url=self.model_url,
|
||||
model_dir=self.model_download_path,
|
||||
@@ -161,10 +162,11 @@ class UpscalerESRGAN(Upscaler):
|
||||
else:
|
||||
filename = path
|
||||
if not os.path.exists(filename) or filename is None:
|
||||
print(f"Unable to load {self.model_path} from {filename}")
|
||||
log.error(f"Model failed loading: type=ESRGAN model={filename}")
|
||||
return None
|
||||
|
||||
state_dict = torch.load(filename, map_location='cpu' if devices.device_esrgan.type == 'mps' else None)
|
||||
log.info(f"Model loaded: type=ESRGAN model={filename}")
|
||||
|
||||
if "params_ema" in state_dict:
|
||||
state_dict = state_dict["params_ema"]
|
||||
@@ -216,16 +218,20 @@ def esrgan_upscale(model, img):
|
||||
newtiles = []
|
||||
scale_factor = 1
|
||||
|
||||
for y, h, row in grid.tiles:
|
||||
newrow = []
|
||||
for tiledata in row:
|
||||
x, w, tile = tiledata
|
||||
|
||||
output = upscale_without_tiling(model, tile)
|
||||
scale_factor = output.width // tile.width
|
||||
|
||||
newrow.append([x * scale_factor, w * scale_factor, output])
|
||||
newtiles.append([y * scale_factor, h * scale_factor, newrow])
|
||||
with Progress(TextColumn('[cyan]{task.description}'), BarColumn(), TaskProgressColumn(), TimeRemainingColumn(), TimeElapsedColumn(), console=console) as progress:
|
||||
total = 0
|
||||
for _y, _h, row in grid.tiles:
|
||||
total += len(row)
|
||||
task = progress.add_task(description="Upscaling", total=total)
|
||||
for y, h, row in grid.tiles:
|
||||
newrow = []
|
||||
for tiledata in row:
|
||||
x, w, tile = tiledata
|
||||
output = upscale_without_tiling(model, tile)
|
||||
scale_factor = output.width // tile.width
|
||||
newrow.append([x * scale_factor, w * scale_factor, output])
|
||||
progress.update(task, advance=1, description="Upscaling")
|
||||
newtiles.append([y * scale_factor, h * scale_factor, newrow])
|
||||
|
||||
newgrid = images.Grid(newtiles, grid.tile_w * scale_factor, grid.tile_h * scale_factor, grid.image_w * scale_factor, grid.image_h * scale_factor, grid.overlap * scale_factor)
|
||||
output = images.combine_grid(newgrid)
|
||||
|
||||
@@ -29,12 +29,13 @@ def gfpgann():
|
||||
latest_file = max(models, key=os.path.getctime)
|
||||
model_file = latest_file
|
||||
else:
|
||||
print("Unable to load gfpgan model!")
|
||||
shared.log.error(f"Model failed loading: type=GFPGAN model={model_file}")
|
||||
return None
|
||||
if hasattr(facexlib.detection.retinaface, 'device'):
|
||||
facexlib.detection.retinaface.device = devices.device_gfpgan
|
||||
model = gfpgan_constructor(model_path=model_file, upscale=1, arch='clean', channel_multiplier=2, bg_upsampler=None, device=devices.device_gfpgan)
|
||||
loaded_gfpgan_model = model
|
||||
shared.log.info(f"Model loaded: type=GFPGAN model={model_file}")
|
||||
|
||||
return model
|
||||
|
||||
|
||||
+22
-10
@@ -291,7 +291,8 @@ def sanitize_filename_part(text, replace_spaces=True):
|
||||
|
||||
class FilenameGenerator:
|
||||
replacements = {
|
||||
'batch_number': lambda self: NOTHING if self.index <= 1 else self.index,
|
||||
'batch_number': lambda self: self.batch_number,
|
||||
'iter_number': lambda self: self.iter_number,
|
||||
'cfg': lambda self: self.p and self.p.cfg_scale,
|
||||
'clip_skip': lambda self: self.p and self.p.clip_skip,
|
||||
'date': lambda self: datetime.datetime.now().strftime('%Y-%m-%d'),
|
||||
@@ -320,12 +321,17 @@ class FilenameGenerator:
|
||||
}
|
||||
default_time_format = '%Y%m%d%H%M%S'
|
||||
|
||||
def __init__(self, p, seed, prompt, image, index):
|
||||
def __init__(self, p, seed, prompt, image, grid=False):
|
||||
self.p = p
|
||||
self.seed = seed
|
||||
self.prompt = prompt
|
||||
self.image = image
|
||||
self.index = index if self.p is None or self.p.batch_size == 1 else self.p.batch_index + 1
|
||||
if not grid:
|
||||
self.batch_number = NOTHING if self.p is None or getattr(self.p, 'batch_size', 1) == 1 else (self.p.batch_index + 1 if hasattr(self.p, 'batch_index') else NOTHING)
|
||||
self.iter_number = NOTHING if self.p is None or getattr(self.p, 'n_iter', 1) == 1 else (self.p.iteration + 1 if hasattr(self.p, 'iteration') else NOTHING)
|
||||
else:
|
||||
self.batch_number = NOTHING
|
||||
self.iter_number = NOTHING
|
||||
|
||||
def hasprompt(self, *args):
|
||||
lower = self.prompt.lower()
|
||||
@@ -449,14 +455,14 @@ def atomically_save_image():
|
||||
image_format = 'JPEG'
|
||||
if shared.opts.image_watermark_enabled:
|
||||
image = set_watermark(image, shared.opts.image_watermark)
|
||||
shared.log.debug(f'Saving: image={fn} type={image_format} size={image.width}x{image.height}')
|
||||
shared.log.debug(f'Saving: image="{fn}" type={image_format} size={image.width}x{image.height}')
|
||||
# actual save
|
||||
exifinfo = (exifinfo or "") if shared.opts.image_metadata else ""
|
||||
if image_format == 'PNG':
|
||||
pnginfo_data = PngImagePlugin.PngInfo()
|
||||
for k, v in params.pnginfo.items():
|
||||
pnginfo_data.add_text(k, str(v))
|
||||
image.save(fn, format=image_format, quality=shared.opts.jpeg_quality, pnginfo=pnginfo_data if shared.opts.image_metadata else None)
|
||||
image.save(fn, format=image_format, optimize=True, compress_level=9, pnginfo=pnginfo_data if shared.opts.image_metadata else None)
|
||||
elif image_format == 'JPEG':
|
||||
if image.mode == 'RGBA':
|
||||
shared.log.warning('Saving RGBA image as JPEG: Alpha channel will be lost')
|
||||
@@ -464,7 +470,7 @@ def atomically_save_image():
|
||||
elif image.mode == 'I;16':
|
||||
image = image.point(lambda p: p * 0.0038910505836576).convert("L")
|
||||
exif_bytes = piexif.dump({ "Exif": { piexif.ExifIFD.UserComment: piexif.helper.UserComment.dump(exifinfo, encoding="unicode") } })
|
||||
image.save(fn, format=image_format, quality=shared.opts.jpeg_quality, exif=exif_bytes)
|
||||
image.save(fn, format=image_format, optimize=True, quality=shared.opts.jpeg_quality, exif=exif_bytes)
|
||||
elif image_format == 'WEBP':
|
||||
if image.mode == 'I;16':
|
||||
image = image.point(lambda p: p * 0.0038910505836576).convert("RGB")
|
||||
@@ -489,8 +495,14 @@ def atomically_save_image():
|
||||
with open(os.path.join(paths.data_path, "params.txt"), "w", encoding="utf8") as file:
|
||||
file.write(exifinfo)
|
||||
if shared.opts.save_log_fn != '' and len(exifinfo) > 0:
|
||||
entry = { 'filename': filename, 'time': datetime.datetime.now().isoformat(), 'info': exifinfo }
|
||||
shared.writefile(entry, os.path.join(paths.data_path, shared.opts.save_log_fn), mode='a+')
|
||||
fn = os.path.join(paths.data_path, shared.opts.save_log_fn)
|
||||
entries = shared.readfile(fn)
|
||||
idx = len(list(entries))
|
||||
if idx == 0:
|
||||
entries = []
|
||||
entry = { 'id': idx, 'filename': filename, 'time': datetime.datetime.now().isoformat(), 'info': exifinfo }
|
||||
entries.append(entry)
|
||||
shared.writefile(entries, fn, mode='w')
|
||||
save_queue.task_done()
|
||||
|
||||
|
||||
@@ -499,7 +511,7 @@ save_thread = threading.Thread(target=atomically_save_image, daemon=True)
|
||||
save_thread.start()
|
||||
|
||||
|
||||
def save_image(image, path, basename, seed=None, prompt=None, extension='jpg', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None, index=0):
|
||||
def save_image(image, path, basename, seed=None, prompt=None, extension='jpg', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None):
|
||||
"""Save an image.
|
||||
Args:
|
||||
image (`PIL.Image`):
|
||||
@@ -537,7 +549,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='jpg', i
|
||||
return None, None
|
||||
if path is None or len(path) == 0: # set default path to avoid errors when functions are triggered manually or via api and param is not set
|
||||
path = shared.opts.outdir_save
|
||||
namegen = FilenameGenerator(p, seed, prompt, image, index)
|
||||
namegen = FilenameGenerator(p, seed, prompt, image, grid=grid)
|
||||
if save_to_dirs is None:
|
||||
save_to_dirs = (grid and shared.opts.grid_save_to_dirs) or (not grid and shared.opts.save_to_dirs and not no_prompt)
|
||||
if save_to_dirs:
|
||||
|
||||
@@ -17,7 +17,11 @@ def ipex_init(): # pylint: disable=too-many-statements
|
||||
torch.cuda.device = torch.xpu.device
|
||||
torch.cuda.device_count = torch.xpu.device_count
|
||||
torch.cuda.device_of = torch.xpu.device_of
|
||||
torch.cuda.getDeviceIdListForCard = torch.xpu.getDeviceIdListForCard
|
||||
# getDeviceIdListForCard is renamed since https://github.com/intel/intel-extension-for-pytorch/commit/835b41fd5c8b6facf9efee8312f20699850ee592
|
||||
if hasattr(torch.xpu, 'getDeviceIdListForCard'):
|
||||
torch.cuda.getDeviceIdListForCard = torch.xpu.getDeviceIdListForCard
|
||||
else:
|
||||
torch.cuda.getDeviceIdListForCard = torch.xpu.get_device_id_list_per_card
|
||||
torch.cuda.get_device_name = torch.xpu.get_device_name
|
||||
torch.cuda.get_device_properties = torch.xpu.get_device_properties
|
||||
torch.cuda.init = torch.xpu.init
|
||||
|
||||
@@ -64,7 +64,13 @@ def torch_bmm(input, mat2, *, out=None):
|
||||
original_scaled_dot_product_attention = torch.nn.functional.scaled_dot_product_attention
|
||||
def scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=0.0, is_causal=False):
|
||||
#ARC GPUs can't allocate more than 4GB to a single block, Slice it:
|
||||
shape_one, batch_size_attention, query_tokens, shape_four = query.shape
|
||||
if len(query.shape) == 3:
|
||||
batch_size_attention, query_tokens, shape_four = query.shape
|
||||
shape_one = 1
|
||||
no_shape_one = True
|
||||
else:
|
||||
shape_one, batch_size_attention, query_tokens, shape_four = query.shape
|
||||
no_shape_one = False
|
||||
block_multiply = 3.6 if query.dtype == torch.float32 else 1.8
|
||||
block_size = (shape_one * batch_size_attention * query_tokens * shape_four) / 1024 * block_multiply #MB
|
||||
split_slice_size = batch_size_attention
|
||||
@@ -101,21 +107,39 @@ def scaled_dot_product_attention(query, key, value, attn_mask=None, dropout_p=0.
|
||||
for i2 in range(query_tokens // split_2_slice_size): # pylint: disable=invalid-name
|
||||
start_idx_2 = i2 * split_2_slice_size
|
||||
end_idx_2 = (i2 + 1) * split_2_slice_size
|
||||
hidden_states[:, start_idx:end_idx, start_idx_2:end_idx_2] = original_scaled_dot_product_attention(
|
||||
query[:, start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
key[:, start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
value[:, start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
attn_mask=attn_mask[:, start_idx:end_idx, start_idx_2:end_idx_2] if attn_mask is not None else attn_mask,
|
||||
if no_shape_one:
|
||||
hidden_states[start_idx:end_idx, start_idx_2:end_idx_2] = original_scaled_dot_product_attention(
|
||||
query[start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
key[start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
value[start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
attn_mask=attn_mask[start_idx:end_idx, start_idx_2:end_idx_2] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal
|
||||
)
|
||||
else:
|
||||
hidden_states[:, start_idx:end_idx, start_idx_2:end_idx_2] = original_scaled_dot_product_attention(
|
||||
query[:, start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
key[:, start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
value[:, start_idx:end_idx, start_idx_2:end_idx_2],
|
||||
attn_mask=attn_mask[:, start_idx:end_idx, start_idx_2:end_idx_2] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal
|
||||
)
|
||||
else:
|
||||
if no_shape_one:
|
||||
hidden_states[start_idx:end_idx] = original_scaled_dot_product_attention(
|
||||
query[start_idx:end_idx],
|
||||
key[start_idx:end_idx],
|
||||
value[start_idx:end_idx],
|
||||
attn_mask=attn_mask[start_idx:end_idx] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal
|
||||
)
|
||||
else:
|
||||
hidden_states[:, start_idx:end_idx] = original_scaled_dot_product_attention(
|
||||
query[:, start_idx:end_idx],
|
||||
key[:, start_idx:end_idx],
|
||||
value[:, start_idx:end_idx],
|
||||
attn_mask=attn_mask[:, start_idx:end_idx] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal
|
||||
)
|
||||
else:
|
||||
hidden_states[:, start_idx:end_idx] = original_scaled_dot_product_attention(
|
||||
query[:, start_idx:end_idx],
|
||||
key[:, start_idx:end_idx],
|
||||
value[:, start_idx:end_idx],
|
||||
attn_mask=attn_mask[:, start_idx:end_idx] if attn_mask is not None else attn_mask,
|
||||
dropout_p=dropout_p, is_causal=is_causal
|
||||
)
|
||||
else:
|
||||
return original_scaled_dot_product_attention(
|
||||
query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import sys
|
||||
import torch
|
||||
from openvino.frontend import FrontEndManager
|
||||
from openvino.frontend.pytorch.fx_decoder import TorchFXPythonDecoder
|
||||
@@ -13,6 +14,25 @@ from hashlib import sha256
|
||||
import functools
|
||||
from modules import shared, devices
|
||||
|
||||
def BUILD_MAP_UNPACK(self, inst):
|
||||
items = self.popn(inst.argval)
|
||||
# ensure everything is a dict
|
||||
items = [BuiltinVariable(dict).call_function(self, [x], {}) for x in items] # noqa: F821
|
||||
result = dict()
|
||||
for x in items:
|
||||
assert isinstance(x, ConstDictVariable) # noqa: F821
|
||||
result.update(x.items)
|
||||
self.push(
|
||||
ConstDictVariable( # noqa: F821
|
||||
result,
|
||||
dict,
|
||||
mutable_local=MutableLocal(), # noqa: F821
|
||||
**VariableTracker.propagate(items), # noqa: F821
|
||||
)
|
||||
)
|
||||
tmp_torch = sys.modules["torch"]
|
||||
tmp_torch.BUILD_MAP_UNPACK_WITH_CALL = BUILD_MAP_UNPACK
|
||||
|
||||
compiled_cache = {}
|
||||
max_openvino_partitions = 0
|
||||
partitioned_modules = {}
|
||||
@@ -65,10 +85,6 @@ def get_device():
|
||||
shared.log.warning("OpenVINO: No compatible GPU detected!")
|
||||
os.environ.setdefault('OPENVINO_TORCH_BACKEND_DEVICE', device)
|
||||
shared.log.debug(f"OpenVINO Device: {device}")
|
||||
if shared.opts.cuda_compile_errors and device not in core.available_devices:
|
||||
shared.log.error(f"OpenVINO: Specified device {device} is not in the list of OpenVINO Available Devices")
|
||||
assert device in core.available_devices, f"OpenVINO: Specified device {device} is not in the list of OpenVINO Available Devices"
|
||||
|
||||
return device
|
||||
|
||||
def cache_root_path():
|
||||
|
||||
+13
-9
@@ -472,6 +472,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
|
||||
"CFG scale": p.cfg_scale,
|
||||
"Size": f"{p.width}x{p.height}",
|
||||
"Batch": f'{p.n_iter}x{p.batch_size}' if p.n_iter > 1 or p.batch_size > 1 else None,
|
||||
"Index": f'{p.iteration + 1}x{index + 1}' if (p.n_iter > 1 or p.batch_size > 1) and index >= 0 else None,
|
||||
"Parser": shared.opts.prompt_attention,
|
||||
"Model": None if (not shared.opts.add_model_name_to_info) or (not shared.sd_model.sd_checkpoint_info.model_name) else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', ''),
|
||||
"Model hash": getattr(p, 'sd_model_hash', None if (not shared.opts.add_model_hash_to_info) or (not shared.sd_model.sd_model_hash) else shared.sd_model.sd_model_hash),
|
||||
@@ -798,7 +799,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
p.scripts.postprocess_batch_list(p, batch_params, batch_number=n)
|
||||
x_samples_ddim = batch_params.images
|
||||
|
||||
def infotext(index=0): # pylint: disable=function-redefined # noqa: F811
|
||||
def infotext(index): # pylint: disable=function-redefined # noqa: F811
|
||||
return create_infotext(p, p.prompts, p.seeds, p.subseeds, index=index, all_negative_prompts=p.negative_prompts)
|
||||
|
||||
for i, x_sample in enumerate(x_samples_ddim):
|
||||
@@ -816,7 +817,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
p.restore_faces = False
|
||||
info = infotext(i)
|
||||
p.restore_faces = orig
|
||||
images.save_image(Image.fromarray(x_sample), path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-face-restoration")
|
||||
images.save_image(Image.fromarray(x_sample), path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-face-restore")
|
||||
p.ops.append('face')
|
||||
x_sample = modules.face_restoration.restore_faces(x_sample)
|
||||
image = Image.fromarray(x_sample)
|
||||
@@ -831,7 +832,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
info = infotext(i)
|
||||
p.color_corrections = orig
|
||||
image_without_cc = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
||||
images.save_image(image_without_cc, path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-color-correction")
|
||||
images.save_image(image_without_cc, path=p.outpath_samples, basename="", seed=p.seeds[i], prompt=p.prompts[i], extension=shared.opts.samples_format, info=info, p=p, suffix="-before-color-correct")
|
||||
p.ops.append('color')
|
||||
image = apply_color_correction(p.color_corrections[i], image)
|
||||
image = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
||||
@@ -840,7 +841,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
image.info["parameters"] = text
|
||||
output_images.append(image)
|
||||
if shared.opts.samples_save and not p.do_not_save_samples:
|
||||
images.save_image(image, p.outpath_samples, "", p.seeds[i], p.prompts[i], shared.opts.samples_format, info=text, p=p)
|
||||
images.save_image(image, p.outpath_samples, "", p.seeds[i], p.prompts[i], shared.opts.samples_format, info=text, p=p) # main save image
|
||||
if hasattr(p, 'mask_for_overlay') and p.mask_for_overlay and any([shared.opts.save_mask, shared.opts.save_mask_composite, shared.opts.return_mask, shared.opts.return_mask_composite]):
|
||||
image_mask = p.mask_for_overlay.convert('RGB')
|
||||
image_mask_composite = Image.composite(image.convert('RGBA').convert('RGBa'), Image.new('RGBa', image.size), images.resize_image(3, p.mask_for_overlay, image.width, image.height).convert('L')).convert('RGBA')
|
||||
@@ -865,13 +866,13 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
if images.check_grid_size(output_images):
|
||||
grid = images.image_grid(output_images, p.batch_size)
|
||||
if shared.opts.return_grid:
|
||||
text = infotext()
|
||||
text = infotext(-1)
|
||||
infotexts.insert(0, text)
|
||||
grid.info["parameters"] = text
|
||||
output_images.insert(0, grid)
|
||||
index_of_first_image = 1
|
||||
if shared.opts.grid_save:
|
||||
images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], shared.opts.grid_format, info=infotext(), short_filename=not shared.opts.grid_extended_filename, p=p, grid=True)
|
||||
images.save_image(grid, p.outpath_grids, "", p.all_seeds[0], p.all_prompts[0], shared.opts.grid_format, info=infotext(-1), short_filename=not shared.opts.grid_extended_filename, p=p, grid=True, suffix="-grid") # main save grid
|
||||
|
||||
if not p.disable_extra_networks and extra_network_data:
|
||||
modules.extra_networks.deactivate(p, extra_network_data)
|
||||
@@ -880,7 +881,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
p,
|
||||
images_list=output_images,
|
||||
seed=p.all_seeds[0],
|
||||
info=infotext(),
|
||||
info=infotext(0),
|
||||
comments="\n".join(comments),
|
||||
subseed=p.all_subseeds[0],
|
||||
index_of_first_image=index_of_first_image,
|
||||
@@ -964,6 +965,9 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
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
|
||||
if self.denoising_strength == 0:
|
||||
self.is_hr_pass = False
|
||||
return
|
||||
self.is_hr_pass = True
|
||||
if not shared.state.processing_has_refined_job_count:
|
||||
if shared.state.job_count == -1:
|
||||
@@ -987,7 +991,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
info = create_infotext(self, self.all_prompts, self.all_seeds, self.all_subseeds, [], iteration=self.iteration, position_in_batch=index)
|
||||
self.extra_generation_params = orig1
|
||||
self.restore_faces = orig2
|
||||
images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], shared.opts.samples_format, info=info, suffix="-before-hires", index=index+1)
|
||||
images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], shared.opts.samples_format, info=info, suffix="-before-hires")
|
||||
|
||||
if shared.backend == shared.Backend.DIFFUSERS:
|
||||
modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.TEXT_2_IMAGE)
|
||||
@@ -1140,7 +1144,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
self.init_img_width = img.width # pylint: disable=attribute-defined-outside-init
|
||||
self.init_img_height = img.height # pylint: disable=attribute-defined-outside-init
|
||||
if shared.opts.save_init_img:
|
||||
images.save_image(img, path=shared.opts.outdir_init_images, basename=None, forced_filename=self.init_img_hash, save_to_dirs=False)
|
||||
images.save_image(img, path=shared.opts.outdir_init_images, basename=None, forced_filename=self.init_img_hash, save_to_dirs=False, suffix="-init-image")
|
||||
image = images.flatten(img, shared.opts.img2img_background_color)
|
||||
if crop_region is None and self.resize_mode != 4:
|
||||
image = images.resize_image(self.resize_mode, image, self.width, self.height)
|
||||
|
||||
@@ -65,7 +65,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
|
||||
def full_vae_decode(latents, model):
|
||||
t0 = time.time()
|
||||
if shared.opts.diffusers_move_unet and not model.has_accelerate:
|
||||
if shared.opts.diffusers_move_unet and not getattr(model, 'has_accelerate', False):
|
||||
shared.log.debug('Moving to CPU: model=UNet')
|
||||
unet_device = model.unet.device
|
||||
model.unet.to(devices.cpu)
|
||||
@@ -80,7 +80,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
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]
|
||||
if shared.opts.diffusers_move_unet and not model.has_accelerate:
|
||||
if shared.opts.diffusers_move_unet and not getattr(model, 'has_accelerate', False):
|
||||
model.unet.to(unet_device)
|
||||
t1 = time.time()
|
||||
shared.log.debug(f'VAE decode: name={sd_vae.loaded_vae_file if sd_vae.loaded_vae_file is not None else "baked"} dtype={model.vae.dtype} upcast={upcast} images={latents.shape[0]} latents={latents.shape} time={round(t1-t0, 3)}s')
|
||||
@@ -88,7 +88,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
|
||||
def full_vae_encode(image, model):
|
||||
shared.log.debug(f'VAE encode: name={sd_vae.loaded_vae_file if sd_vae.loaded_vae_file is not None else "baked"} dtype={model.vae.dtype} upcast={model.vae.config.get("force_upcast", None)}')
|
||||
if shared.opts.diffusers_move_unet and not model.has_accelerate:
|
||||
if shared.opts.diffusers_move_unet and not getattr(model, 'has_accelerate', False):
|
||||
shared.log.debug('Moving to CPU: model=UNet')
|
||||
unet_device = model.unet.device
|
||||
model.unet.to(devices.cpu)
|
||||
@@ -96,7 +96,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
if not shared.cmd_opts.lowvram and not shared.opts.diffusers_seq_cpu_offload:
|
||||
model.vae.to(devices.device)
|
||||
encoded = model.vae.encode(image.to(model.vae.device, model.vae.dtype))
|
||||
if shared.opts.diffusers_move_unet and not model.has_accelerate:
|
||||
if shared.opts.diffusers_move_unet and not getattr(model, 'has_accelerate', False):
|
||||
model.unet.to(unet_device)
|
||||
return encoded
|
||||
|
||||
@@ -315,10 +315,11 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
task_specific_kwargs = {"image": p.init_images, "mask_image": p.mask, "strength": p.denoising_strength, "height": 8 * math.ceil(p.height / 8), "width": 8 * math.ceil(p.width / 8)}
|
||||
|
||||
if shared.state.interrupted or shared.state.skipped:
|
||||
unload_diffusers_lora()
|
||||
if lora_state['active']:
|
||||
unload_diffusers_lora()
|
||||
return results
|
||||
|
||||
if shared.opts.diffusers_move_base and not shared.sd_model.has_accelerate:
|
||||
if shared.opts.diffusers_move_base and not getattr(shared.sd_model, 'has_accelerate', False):
|
||||
shared.sd_model.to(devices.device)
|
||||
|
||||
is_img2img = bool(sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.IMAGE_2_IMAGE or sd_models.get_diffusers_task(shared.sd_model) == sd_models.DiffusersTaskType.INPAINTING)
|
||||
@@ -357,15 +358,16 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
output = shared.sd_model(**base_args) # pylint: disable=not-callable
|
||||
except AssertionError as e:
|
||||
shared.log.info(e)
|
||||
except ValueError as e:
|
||||
shared.state.interrupted = True
|
||||
shared.log.error(e)
|
||||
|
||||
if hasattr(shared.sd_model, 'embedding_db') and len(shared.sd_model.embedding_db.embeddings_used) > 0:
|
||||
p.extra_generation_params['Embeddings'] = ', '.join(shared.sd_model.embedding_db.embeddings_used)
|
||||
|
||||
if lora_state['active']:
|
||||
p.extra_generation_params['LoRA method'] = shared.opts.diffusers_lora_loader
|
||||
unload_diffusers_lora()
|
||||
|
||||
if shared.state.interrupted or shared.state.skipped:
|
||||
if lora_state['active']:
|
||||
unload_diffusers_lora()
|
||||
return results
|
||||
|
||||
# optional hires pass
|
||||
@@ -407,11 +409,15 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
except AssertionError as e:
|
||||
shared.log.info(e)
|
||||
|
||||
if lora_state['active']:
|
||||
p.extra_generation_params['LoRA method'] = shared.opts.diffusers_lora_loader
|
||||
unload_diffusers_lora()
|
||||
|
||||
# optional refiner pass or decode
|
||||
if is_refiner_enabled:
|
||||
if shared.opts.save and not p.do_not_save_samples and shared.opts.save_images_before_refiner and hasattr(shared.sd_model, 'vae'):
|
||||
save_intermediate(latents=output.images, suffix="-before-refiner")
|
||||
if shared.opts.diffusers_move_base and not shared.sd_model.has_accelerate:
|
||||
if shared.opts.diffusers_move_base and not getattr(shared.sd_model, 'has_accelerate', False):
|
||||
shared.log.debug('Moving to CPU: model=base')
|
||||
shared.sd_model.to(devices.cpu)
|
||||
devices.torch_gc()
|
||||
@@ -423,9 +429,11 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
sd_samplers.create_sampler(sampler.name, shared.sd_refiner) # TODO(Patrick): For wrapped pipelines this is currently a no-op
|
||||
|
||||
if shared.state.interrupted or shared.state.skipped:
|
||||
if lora_state['active']:
|
||||
unload_diffusers_lora()
|
||||
return results
|
||||
|
||||
if shared.opts.diffusers_move_refiner and not shared.sd_refiner.has_accelerate:
|
||||
if shared.opts.diffusers_move_refiner and not getattr(shared.sd_refiner, 'has_accelerate', False):
|
||||
shared.sd_refiner.to(devices.device)
|
||||
refiner_is_sdxl = bool("StableDiffusionXL" in shared.sd_refiner.__class__.__name__)
|
||||
p.ops.append('refine')
|
||||
@@ -461,7 +469,7 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
|
||||
for refiner_image in refiner_images:
|
||||
results.append(refiner_image)
|
||||
|
||||
if shared.opts.diffusers_move_refiner and not shared.sd_refiner.has_accelerate:
|
||||
if shared.opts.diffusers_move_refiner and not getattr(shared.sd_refiner, 'has_accelerate', False):
|
||||
shared.log.debug('Moving to CPU: model=refiner')
|
||||
shared.sd_refiner.to(devices.cpu)
|
||||
devices.torch_gc()
|
||||
|
||||
+14
-19
@@ -1,12 +1,9 @@
|
||||
import os
|
||||
import sys
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
from modules.upscaler import Upscaler, UpscalerData
|
||||
from modules.shared import opts, device
|
||||
from modules.shared import opts, device, log
|
||||
from modules import modelloader
|
||||
import modules.errors as errors
|
||||
|
||||
|
||||
class UpscalerRealESRGAN(Upscaler):
|
||||
@@ -16,8 +13,7 @@ class UpscalerRealESRGAN(Upscaler):
|
||||
super().__init__()
|
||||
try:
|
||||
from basicsr.archs.rrdbnet_arch import RRDBNet # pylint: disable=unused-import
|
||||
from realesrgan import RealESRGANer # pylint: disable=unused-import
|
||||
from realesrgan.archs.srvgg_arch import SRVGGNetCompact # pylint: disable=unused-import
|
||||
from modules.realesrgan_model_arch import RealESRGANer, SRVGGNetCompact # pylint: disable=unused-import
|
||||
self.enable = True
|
||||
self.scalers = []
|
||||
scalers = self.load_models(path)
|
||||
@@ -28,11 +24,9 @@ class UpscalerRealESRGAN(Upscaler):
|
||||
local_model_candidates = [local_model for local_model in local_model_paths if local_model.endswith(f"{filename}.pth")]
|
||||
if local_model_candidates:
|
||||
scaler.local_data_path = local_model_candidates[0]
|
||||
if scaler.name in opts.realesrgan_enabled_models:
|
||||
self.scalers.append(scaler)
|
||||
|
||||
self.scalers.append(scaler)
|
||||
except Exception as e:
|
||||
errors.display(e, 'real-esrgan')
|
||||
log.error(f"Error loading Real-ESRGAN: model={path} {e}")
|
||||
self.enable = False
|
||||
self.scalers = []
|
||||
|
||||
@@ -41,14 +35,13 @@ class UpscalerRealESRGAN(Upscaler):
|
||||
return img
|
||||
|
||||
try:
|
||||
from realesrgan import RealESRGANer
|
||||
from modules.realesrgan_model_arch import RealESRGANer
|
||||
except Exception:
|
||||
print("Error importing Real-ESRGAN:", file=sys.stderr)
|
||||
log.error("Error importing Real-ESRGAN:")
|
||||
return img
|
||||
|
||||
info = self.load_model(selected_model)
|
||||
if not os.path.exists(info.local_data_path):
|
||||
print(f"Unable to load RealESRGAN model: {info.name}")
|
||||
if info is None or not os.path.exists(info.local_data_path):
|
||||
return img
|
||||
|
||||
upsampler = RealESRGANer(
|
||||
@@ -70,13 +63,15 @@ class UpscalerRealESRGAN(Upscaler):
|
||||
try:
|
||||
info = next(iter([scaler for scaler in self.scalers if scaler.data_path == path]), None)
|
||||
if info is None:
|
||||
print(f"Unable to find model info: {path}")
|
||||
log.error(f"Model failed loading: type=R-ESRGAN model={info.name}")
|
||||
return None
|
||||
if info.local_data_path.startswith("http"):
|
||||
from modules.modelloader import load_file_from_url
|
||||
info.local_data_path = load_file_from_url(url=info.data_path, model_dir=self.model_download_path, progress=True)
|
||||
log.info(f"Model loaded: type=R-ESRGAN model={info.name}")
|
||||
return info
|
||||
except Exception as e:
|
||||
errors.display(e, 'real-esrgan model list')
|
||||
log.error(f"Model failed loading: type=R-ESRGAN model={info.name} {e}")
|
||||
return None
|
||||
|
||||
def load_models(self, _):
|
||||
@@ -86,7 +81,7 @@ class UpscalerRealESRGAN(Upscaler):
|
||||
def get_realesrgan_models(scaler):
|
||||
try:
|
||||
from basicsr.archs.rrdbnet_arch import RRDBNet
|
||||
from realesrgan.archs.srvgg_arch import SRVGGNetCompact
|
||||
from modules.realesrgan_model_arch import SRVGGNetCompact # pylint: disable=unused-import
|
||||
models = [
|
||||
UpscalerData(
|
||||
name="R-ESRGAN General 4xV3",
|
||||
@@ -132,6 +127,6 @@ def get_realesrgan_models(scaler):
|
||||
),
|
||||
]
|
||||
return models
|
||||
except Exception:
|
||||
print("Error creating Real-ESRGAN models list", file=sys.stderr)
|
||||
except Exception as e:
|
||||
log.error(f'Error creating Real-ESRGAN models list: {e}')
|
||||
return []
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
import os
|
||||
import math
|
||||
import queue
|
||||
import threading
|
||||
import cv2
|
||||
import numpy as np
|
||||
import torch
|
||||
from torch.nn import functional as F
|
||||
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn
|
||||
from modules.shared import log, console
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
class RealESRGANer():
|
||||
"""A helper class for upsampling images with RealESRGAN.
|
||||
|
||||
Args:
|
||||
scale (int): Upsampling scale factor used in the networks. It is usually 2 or 4.
|
||||
model_path (str): The path to the pretrained model. It can be urls (will first download it automatically).
|
||||
model (nn.Module): The defined network. Default: None.
|
||||
tile (int): As too large images result in the out of GPU memory issue, so this tile option will first crop
|
||||
input images into tiles, and then process each of them. Finally, they will be merged into one image.
|
||||
0 denotes for do not use tile. Default: 0.
|
||||
tile_pad (int): The pad size for each tile, to remove border artifacts. Default: 10.
|
||||
pre_pad (int): Pad the input images to avoid border artifacts. Default: 10.
|
||||
half (float): Whether to use half precision during inference. Default: False.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
scale,
|
||||
model_path,
|
||||
dni_weight=None,
|
||||
model=None,
|
||||
tile=0,
|
||||
tile_pad=10,
|
||||
pre_pad=10,
|
||||
half=False,
|
||||
device=None,
|
||||
gpu_id=None):
|
||||
self.scale = scale
|
||||
self.tile_size = tile
|
||||
self.tile_pad = tile_pad
|
||||
self.pre_pad = pre_pad
|
||||
self.mod_scale = None
|
||||
self.half = half
|
||||
|
||||
# initialize model
|
||||
if gpu_id:
|
||||
self.device = torch.device(
|
||||
f'cuda:{gpu_id}' if torch.cuda.is_available() else 'cpu') if device is None else device
|
||||
else:
|
||||
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') if device is None else device
|
||||
|
||||
if isinstance(model_path, list):
|
||||
# dni
|
||||
assert len(model_path) == len(dni_weight), 'model_path and dni_weight should have the save length.'
|
||||
loadnet = self.dni(model_path[0], model_path[1], dni_weight)
|
||||
else:
|
||||
# if the model_path starts with https, it will first download models to the folder: weights
|
||||
if model_path.startswith('https://'):
|
||||
from modules.modelloader import load_file_from_url
|
||||
model_path = load_file_from_url(url=model_path, model_dir=os.path.join(ROOT_DIR, 'weights'), progress=True, file_name=None)
|
||||
loadnet = torch.load(model_path, map_location=torch.device('cpu'))
|
||||
|
||||
# prefer to use params_ema
|
||||
if 'params_ema' in loadnet:
|
||||
keyname = 'params_ema'
|
||||
else:
|
||||
keyname = 'params'
|
||||
model.load_state_dict(loadnet[keyname], strict=True)
|
||||
|
||||
model.eval()
|
||||
self.model = model.to(self.device)
|
||||
if self.half:
|
||||
self.model = self.model.half()
|
||||
|
||||
def dni(self, net_a, net_b, dni_weight, key='params', loc='cpu'):
|
||||
"""Deep network interpolation.
|
||||
|
||||
``Paper: Deep Network Interpolation for Continuous Imagery Effect Transition``
|
||||
"""
|
||||
net_a = torch.load(net_a, map_location=torch.device(loc))
|
||||
net_b = torch.load(net_b, map_location=torch.device(loc))
|
||||
for k, v_a in net_a[key].items():
|
||||
net_a[key][k] = dni_weight[0] * v_a + dni_weight[1] * net_b[key][k]
|
||||
return net_a
|
||||
|
||||
def pre_process(self, img):
|
||||
"""Pre-process, such as pre-pad and mod pad, so that the images can be divisible
|
||||
"""
|
||||
img = torch.from_numpy(np.transpose(img, (2, 0, 1))).float()
|
||||
self.img = img.unsqueeze(0).to(self.device)
|
||||
if self.half:
|
||||
self.img = self.img.half()
|
||||
|
||||
# pre_pad
|
||||
if self.pre_pad != 0:
|
||||
self.img = F.pad(self.img, (0, self.pre_pad, 0, self.pre_pad), 'reflect')
|
||||
# mod pad for divisible borders
|
||||
if self.scale == 2:
|
||||
self.mod_scale = 2
|
||||
elif self.scale == 1:
|
||||
self.mod_scale = 4
|
||||
if self.mod_scale is not None:
|
||||
self.mod_pad_h, self.mod_pad_w = 0, 0
|
||||
_, _, h, w = self.img.size()
|
||||
if (h % self.mod_scale != 0):
|
||||
self.mod_pad_h = (self.mod_scale - h % self.mod_scale)
|
||||
if (w % self.mod_scale != 0):
|
||||
self.mod_pad_w = (self.mod_scale - w % self.mod_scale)
|
||||
self.img = F.pad(self.img, (0, self.mod_pad_w, 0, self.mod_pad_h), 'reflect')
|
||||
|
||||
def process(self):
|
||||
# model inference
|
||||
self.output = self.model(self.img)
|
||||
|
||||
def tile_process(self):
|
||||
"""It will first crop input images to tiles, and then process each tile.
|
||||
Finally, all the processed tiles are merged into one images.
|
||||
|
||||
Modified from: https://github.com/ata4/esrgan-launcher
|
||||
"""
|
||||
batch, channel, height, width = self.img.shape
|
||||
output_height = height * self.scale
|
||||
output_width = width * self.scale
|
||||
output_shape = (batch, channel, output_height, output_width)
|
||||
|
||||
# start with black image
|
||||
self.output = self.img.new_zeros(output_shape)
|
||||
tiles_x = math.ceil(width / self.tile_size)
|
||||
tiles_y = math.ceil(height / self.tile_size)
|
||||
|
||||
# loop over all tiles
|
||||
with Progress(TextColumn('[cyan]{task.description}'), BarColumn(), TaskProgressColumn(), TimeRemainingColumn(), TimeElapsedColumn(), console=console) as progress:
|
||||
task = progress.add_task(description="Upscaling", total=tiles_y * tiles_x)
|
||||
with torch.no_grad():
|
||||
for y in range(tiles_y):
|
||||
for x in range(tiles_x):
|
||||
# extract tile from input image
|
||||
ofs_x = x * self.tile_size
|
||||
ofs_y = y * self.tile_size
|
||||
# input tile area on total image
|
||||
input_start_x = ofs_x
|
||||
input_end_x = min(ofs_x + self.tile_size, width)
|
||||
input_start_y = ofs_y
|
||||
input_end_y = min(ofs_y + self.tile_size, height)
|
||||
|
||||
# input tile area on total image with padding
|
||||
input_start_x_pad = max(input_start_x - self.tile_pad, 0)
|
||||
input_end_x_pad = min(input_end_x + self.tile_pad, width)
|
||||
input_start_y_pad = max(input_start_y - self.tile_pad, 0)
|
||||
input_end_y_pad = min(input_end_y + self.tile_pad, height)
|
||||
|
||||
# input tile dimensions
|
||||
input_tile_width = input_end_x - input_start_x
|
||||
input_tile_height = input_end_y - input_start_y
|
||||
tile_idx = y * tiles_x + x + 1 # noqa
|
||||
input_tile = self.img[:, :, input_start_y_pad:input_end_y_pad, input_start_x_pad:input_end_x_pad]
|
||||
|
||||
# upscale tile
|
||||
try:
|
||||
output_tile = self.model(input_tile)
|
||||
except Exception as e:
|
||||
log.error(f'Upscale error: type=R-ESRGAN {e}')
|
||||
|
||||
# output tile area on total image
|
||||
output_start_x = input_start_x * self.scale
|
||||
output_end_x = input_end_x * self.scale
|
||||
output_start_y = input_start_y * self.scale
|
||||
output_end_y = input_end_y * self.scale
|
||||
|
||||
# output tile area without padding
|
||||
output_start_x_tile = (input_start_x - input_start_x_pad) * self.scale
|
||||
output_end_x_tile = output_start_x_tile + input_tile_width * self.scale
|
||||
output_start_y_tile = (input_start_y - input_start_y_pad) * self.scale
|
||||
output_end_y_tile = output_start_y_tile + input_tile_height * self.scale
|
||||
|
||||
# put tile into output image
|
||||
self.output[:, :, output_start_y:output_end_y,
|
||||
output_start_x:output_end_x] = output_tile[:, :, output_start_y_tile:output_end_y_tile,
|
||||
output_start_x_tile:output_end_x_tile]
|
||||
progress.update(task, advance=1, description="Upscaling")
|
||||
|
||||
def post_process(self):
|
||||
# remove extra pad
|
||||
if self.mod_scale is not None:
|
||||
_, _, h, w = self.output.size()
|
||||
self.output = self.output[:, :, 0:h - self.mod_pad_h * self.scale, 0:w - self.mod_pad_w * self.scale]
|
||||
# remove prepad
|
||||
if self.pre_pad != 0:
|
||||
_, _, h, w = self.output.size()
|
||||
self.output = self.output[:, :, 0:h - self.pre_pad * self.scale, 0:w - self.pre_pad * self.scale]
|
||||
return self.output
|
||||
|
||||
@torch.no_grad()
|
||||
def enhance(self, img, outscale=None, alpha_upsampler='realesrgan'):
|
||||
h_input, w_input = img.shape[0:2]
|
||||
# img: numpy
|
||||
img = img.astype(np.float32)
|
||||
if np.max(img) > 256: # 16-bit image
|
||||
max_range = 65535
|
||||
else:
|
||||
max_range = 255
|
||||
img = img / max_range
|
||||
if len(img.shape) == 2: # gray image
|
||||
img_mode = 'L'
|
||||
img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
|
||||
elif img.shape[2] == 4: # RGBA image with alpha channel
|
||||
img_mode = 'RGBA'
|
||||
alpha = img[:, :, 3]
|
||||
img = img[:, :, 0:3]
|
||||
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
||||
if alpha_upsampler == 'realesrgan':
|
||||
alpha = cv2.cvtColor(alpha, cv2.COLOR_GRAY2RGB)
|
||||
else:
|
||||
img_mode = 'RGB'
|
||||
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
||||
|
||||
# ------------------- process image (without the alpha channel) ------------------- #
|
||||
self.pre_process(img)
|
||||
if self.tile_size > 0:
|
||||
self.tile_process()
|
||||
else:
|
||||
self.process()
|
||||
output_img = self.post_process()
|
||||
output_img = output_img.data.squeeze().float().cpu().clamp_(0, 1).numpy()
|
||||
output_img = np.transpose(output_img[[2, 1, 0], :, :], (1, 2, 0))
|
||||
if img_mode == 'L':
|
||||
output_img = cv2.cvtColor(output_img, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
# ------------------- process the alpha channel if necessary ------------------- #
|
||||
if img_mode == 'RGBA':
|
||||
if alpha_upsampler == 'realesrgan':
|
||||
self.pre_process(alpha)
|
||||
if self.tile_size > 0:
|
||||
self.tile_process()
|
||||
else:
|
||||
self.process()
|
||||
output_alpha = self.post_process()
|
||||
output_alpha = output_alpha.data.squeeze().float().cpu().clamp_(0, 1).numpy()
|
||||
output_alpha = np.transpose(output_alpha[[2, 1, 0], :, :], (1, 2, 0))
|
||||
output_alpha = cv2.cvtColor(output_alpha, cv2.COLOR_BGR2GRAY)
|
||||
else: # use the cv2 resize for alpha channel
|
||||
h, w = alpha.shape[0:2]
|
||||
output_alpha = cv2.resize(alpha, (w * self.scale, h * self.scale), interpolation=cv2.INTER_LINEAR)
|
||||
|
||||
# merge the alpha channel
|
||||
output_img = cv2.cvtColor(output_img, cv2.COLOR_BGR2BGRA)
|
||||
output_img[:, :, 3] = output_alpha
|
||||
|
||||
# ------------------------------ return ------------------------------ #
|
||||
if max_range == 65535: # 16-bit image
|
||||
output = (output_img * 65535.0).round().astype(np.uint16)
|
||||
else:
|
||||
output = (output_img * 255.0).round().astype(np.uint8)
|
||||
|
||||
if outscale is not None and outscale != float(self.scale):
|
||||
output = cv2.resize(
|
||||
output, (
|
||||
int(w_input * outscale),
|
||||
int(h_input * outscale),
|
||||
), interpolation=cv2.INTER_LANCZOS4)
|
||||
|
||||
return output, img_mode
|
||||
|
||||
|
||||
class PrefetchReader(threading.Thread):
|
||||
"""Prefetch images.
|
||||
|
||||
Args:
|
||||
img_list (list[str]): A image list of image paths to be read.
|
||||
num_prefetch_queue (int): Number of prefetch queue.
|
||||
"""
|
||||
|
||||
def __init__(self, img_list, num_prefetch_queue):
|
||||
super().__init__()
|
||||
self.que = queue.Queue(num_prefetch_queue)
|
||||
self.img_list = img_list
|
||||
|
||||
def run(self):
|
||||
for img_path in self.img_list:
|
||||
img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
|
||||
self.que.put(img)
|
||||
|
||||
self.que.put(None)
|
||||
|
||||
def __next__(self):
|
||||
next_item = self.que.get()
|
||||
if next_item is None:
|
||||
raise StopIteration
|
||||
return next_item
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
|
||||
class IOConsumer(threading.Thread):
|
||||
|
||||
def __init__(self, opt, que, qid):
|
||||
super().__init__()
|
||||
self._queue = que
|
||||
self.qid = qid
|
||||
self.opt = opt
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
msg = self._queue.get()
|
||||
if isinstance(msg, str) and msg == 'quit':
|
||||
break
|
||||
|
||||
output = msg['output']
|
||||
save_path = msg['save_path']
|
||||
cv2.imwrite(save_path, output)
|
||||
|
||||
from basicsr.utils.registry import ARCH_REGISTRY
|
||||
from torch import nn as nn
|
||||
from torch.nn import functional as F # noqa
|
||||
|
||||
|
||||
class SRVGGNetCompact(nn.Module):
|
||||
"""A compact VGG-style network structure for super-resolution.
|
||||
|
||||
It is a compact network structure, which performs upsampling in the last layer and no convolution is
|
||||
conducted on the HR feature space.
|
||||
|
||||
Args:
|
||||
num_in_ch (int): Channel number of inputs. Default: 3.
|
||||
num_out_ch (int): Channel number of outputs. Default: 3.
|
||||
num_feat (int): Channel number of intermediate features. Default: 64.
|
||||
num_conv (int): Number of convolution layers in the body network. Default: 16.
|
||||
upscale (int): Upsampling factor. Default: 4.
|
||||
act_type (str): Activation type, options: 'relu', 'prelu', 'leakyrelu'. Default: prelu.
|
||||
"""
|
||||
|
||||
def __init__(self, num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=16, upscale=4, act_type='prelu'):
|
||||
super(SRVGGNetCompact, self).__init__()
|
||||
self.num_in_ch = num_in_ch
|
||||
self.num_out_ch = num_out_ch
|
||||
self.num_feat = num_feat
|
||||
self.num_conv = num_conv
|
||||
self.upscale = upscale
|
||||
self.act_type = act_type
|
||||
|
||||
self.body = nn.ModuleList()
|
||||
# the first conv
|
||||
self.body.append(nn.Conv2d(num_in_ch, num_feat, 3, 1, 1))
|
||||
# the first activation
|
||||
if act_type == 'relu':
|
||||
activation = nn.ReLU(inplace=True)
|
||||
elif act_type == 'prelu':
|
||||
activation = nn.PReLU(num_parameters=num_feat)
|
||||
elif act_type == 'leakyrelu':
|
||||
activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
|
||||
self.body.append(activation)
|
||||
|
||||
# the body structure
|
||||
for _ in range(num_conv):
|
||||
self.body.append(nn.Conv2d(num_feat, num_feat, 3, 1, 1))
|
||||
# activation
|
||||
if act_type == 'relu':
|
||||
activation = nn.ReLU(inplace=True)
|
||||
elif act_type == 'prelu':
|
||||
activation = nn.PReLU(num_parameters=num_feat)
|
||||
elif act_type == 'leakyrelu':
|
||||
activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
|
||||
self.body.append(activation)
|
||||
|
||||
# the last conv
|
||||
self.body.append(nn.Conv2d(num_feat, num_out_ch * upscale * upscale, 3, 1, 1))
|
||||
# upsample
|
||||
self.upsampler = nn.PixelShuffle(upscale)
|
||||
|
||||
def forward(self, x):
|
||||
out = x
|
||||
for i in range(0, len(self.body)):
|
||||
out = self.body[i](out)
|
||||
|
||||
out = self.upsampler(out)
|
||||
# add the nearest upsampled image, so that the network learns the residual
|
||||
base = F.interpolate(x, scale_factor=self.upscale, mode='nearest')
|
||||
out += base
|
||||
return out
|
||||
+4
-11
@@ -37,45 +37,38 @@ def apply_optimizations():
|
||||
can_use_sdp = hasattr(torch.nn.functional, "scaled_dot_product_attention") and callable(torch.nn.functional.scaled_dot_product_attention)
|
||||
if devices.device == torch.device("cpu"):
|
||||
if opts.cross_attention_optimization == "Scaled-Dot-Product":
|
||||
shared.log.warning("Scaled dot product cross attention is not available on CPU")
|
||||
shared.log.warning("Cross-attention: Scaled dot product is not available on CPU")
|
||||
can_use_sdp = False
|
||||
if opts.cross_attention_optimization == "xFormers":
|
||||
shared.log.warning("xFormers cross attention is not available on CPU")
|
||||
shared.log.warning("Cross-attention: xFormers is not available on CPU")
|
||||
shared.xformers_available = False
|
||||
|
||||
if opts.cross_attention_optimization == "Disable cross-attention layer optimization":
|
||||
shared.log.warning("Cross-attention optimization disabled")
|
||||
shared.log.info(f"Cross-attention: optimization={opts.cross_attention_optimization} options={opts.cross_attention_options}")
|
||||
if opts.cross_attention_optimization == "Disabled":
|
||||
optimization_method = 'none'
|
||||
if can_use_sdp and opts.cross_attention_optimization == "Scaled-Dot-Product" and 'SDP disable memory attention' in opts.cross_attention_options:
|
||||
shared.log.info("Applying scaled dot product cross attention optimization (without memory efficient attention)")
|
||||
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
|
||||
optimization_method = 'sdp-no-mem'
|
||||
elif can_use_sdp and opts.cross_attention_optimization == "Scaled-Dot-Product":
|
||||
shared.log.info("Applying scaled dot product cross attention optimization")
|
||||
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
|
||||
optimization_method = 'sdp'
|
||||
if shared.xformers_available and opts.cross_attention_optimization == "xFormers":
|
||||
shared.log.info("Applying xformers cross attention optimization")
|
||||
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward
|
||||
ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward
|
||||
optimization_method = 'xformers'
|
||||
if opts.cross_attention_optimization == "Sub-quadratic":
|
||||
shared.log.info("Applying sub-quadratic cross attention optimization")
|
||||
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.sub_quad_attention_forward
|
||||
ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.sub_quad_attnblock_forward
|
||||
optimization_method = 'sub-quadratic'
|
||||
if opts.cross_attention_optimization == "Split attention":
|
||||
shared.log.info("Applying split attention optimization")
|
||||
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1
|
||||
optimization_method = 'v1'
|
||||
if opts.cross_attention_optimization == "InvokeAI's":
|
||||
shared.log.info("Applying InvokeAI cross attention optimization")
|
||||
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_invokeAI
|
||||
optimization_method = 'invokeai'
|
||||
if opts.cross_attention_optimization == "Doggettx's":
|
||||
shared.log.info("Applying Doggettx cross attention optimization")
|
||||
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward
|
||||
ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward
|
||||
optimization_method = 'doggettx'
|
||||
|
||||
+15
-15
@@ -261,7 +261,7 @@ def select_checkpoint(op='model'):
|
||||
return None
|
||||
checkpoint_info = get_closet_checkpoint_match(model_checkpoint)
|
||||
if checkpoint_info is not None:
|
||||
shared.log.debug(f'Select checkpoint: {op} {checkpoint_info.title if checkpoint_info is not None else None}')
|
||||
shared.log.debug(f'Select checkpoint: {op}="{checkpoint_info.title if checkpoint_info is not None else None}"')
|
||||
return checkpoint_info
|
||||
if len(checkpoints_list) == 0 and not shared.cmd_opts.no_download:
|
||||
shared.log.error("Cannot run without a checkpoint")
|
||||
@@ -275,7 +275,7 @@ def select_checkpoint(op='model'):
|
||||
shared.log.info("Selecting first available checkpoint")
|
||||
# shared.log.warning(f"Loading fallback checkpoint: {checkpoint_info.title}")
|
||||
shared.opts.data['sd_model_checkpoint'] = checkpoint_info.title
|
||||
shared.log.debug(f'Select checkpoint: {checkpoint_info.title if checkpoint_info is not None else None}')
|
||||
shared.log.debug(f'Select checkpoint: {op}="{checkpoint_info.title if checkpoint_info is not None else None}"')
|
||||
return checkpoint_info
|
||||
|
||||
|
||||
@@ -896,7 +896,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
|
||||
|
||||
base_sent_to_cpu=False
|
||||
if (shared.opts.cuda_compile and shared.opts.cuda_compile_backend != 'none') or shared.opts.ipex_optimize:
|
||||
if op == 'refiner' and not sd_model.has_accelerate:
|
||||
if op == 'refiner' and not getattr(sd_model, 'has_accelerate', False):
|
||||
gpu_vram = memory_stats().get('gpu', {})
|
||||
free_vram = gpu_vram.get('total', 0) - gpu_vram.get('used', 0)
|
||||
refiner_enough_vram = free_vram >= 7 if "StableDiffusionXL" in sd_model.__class__.__name__ else 3
|
||||
@@ -917,7 +917,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
|
||||
devices.torch_gc(force=True)
|
||||
sd_model.to(devices.device)
|
||||
base_sent_to_cpu=True
|
||||
elif not sd_model.has_accelerate:
|
||||
elif not getattr(sd_model, 'has_accelerate', False):
|
||||
sd_model.to(devices.device)
|
||||
|
||||
compile_diffusers(sd_model)
|
||||
@@ -931,10 +931,10 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
|
||||
shared.opts.data["sd_checkpoint_hash"] = checkpoint_info.sha256
|
||||
if hasattr(sd_model, "set_progress_bar_config"):
|
||||
sd_model.set_progress_bar_config(bar_format='Progress {rate_fmt}{postfix} {bar} {percentage:3.0f}% {n_fmt}/{total_fmt} {elapsed} {remaining}', ncols=80, colour='#327fba')
|
||||
if op == 'refiner' and shared.opts.diffusers_move_refiner and not sd_model.has_accelerate:
|
||||
if op == 'refiner' and shared.opts.diffusers_move_refiner and not getattr(sd_model, 'has_accelerate', False):
|
||||
shared.log.debug('Moving refiner model to CPU')
|
||||
sd_model.to(devices.cpu)
|
||||
elif not sd_model.has_accelerate: # In offload modes, accelerate will move models around
|
||||
elif not getattr(sd_model, 'has_accelerate', False): # In offload modes, accelerate will move models around
|
||||
sd_model.to(devices.device)
|
||||
if op == 'refiner' and base_sent_to_cpu:
|
||||
shared.log.debug('Moving base model back to GPU')
|
||||
@@ -965,10 +965,10 @@ class DiffusersTaskType(Enum):
|
||||
INPAINTING = 3
|
||||
|
||||
def set_diffuser_pipe(pipe, new_pipe_type):
|
||||
sd_checkpoint_info = pipe.sd_checkpoint_info if hasattr(pipe, "sd_checkpoint_info") else None
|
||||
sd_model_checkpoint = pipe.sd_model_checkpoint if hasattr(pipe, "sd_model_checkpoint") else None
|
||||
sd_model_hash = pipe.sd_model_hash if hasattr(pipe, "sd_model_hash") else None
|
||||
has_accelerate = pipe.has_accelerate if hasattr(pipe, "has_accelerate") else None
|
||||
sd_checkpoint_info = getattr(pipe, "sd_checkpoint_info", None)
|
||||
sd_model_checkpoint = getattr(pipe, "sd_model_checkpoint", None)
|
||||
sd_model_hash = getattr(pipe, "sd_model_hash", None)
|
||||
has_accelerate = getattr(pipe, "has_accelerate", None)
|
||||
|
||||
if new_pipe_type == DiffusersTaskType.TEXT_2_IMAGE:
|
||||
new_pipe = diffusers.AutoPipelineForText2Image.from_pipe(pipe)
|
||||
@@ -1067,6 +1067,7 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None,
|
||||
shared.log.info(f'LDM: {line.strip()}')
|
||||
shared.log.debug(f"Model created from config: {checkpoint_config}")
|
||||
sd_model.used_config = checkpoint_config
|
||||
sd_model.has_accelerate = False
|
||||
timer.record("create")
|
||||
ok = load_model_weights(sd_model, checkpoint_info, state_dict, timer)
|
||||
if not ok:
|
||||
@@ -1090,7 +1091,6 @@ def load_model(checkpoint_info=None, already_loaded_state_dict=None, timer=None,
|
||||
sd_hijack.model_hijack.hijack(sd_model)
|
||||
timer.record("hijack")
|
||||
sd_model.eval()
|
||||
sd_model.has_accelerate = False
|
||||
if op == 'refiner':
|
||||
model_data.sd_refiner = sd_model
|
||||
else:
|
||||
@@ -1126,12 +1126,12 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model')
|
||||
current_checkpoint_info = getattr(sd_model, 'sd_checkpoint_info', None)
|
||||
if current_checkpoint_info is not None and checkpoint_info is not None and current_checkpoint_info.filename == checkpoint_info.filename:
|
||||
return
|
||||
if not sd_model.has_accelerate:
|
||||
if not getattr(sd_model, 'has_accelerate', False):
|
||||
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
|
||||
lowvram.send_everything_to_cpu()
|
||||
else:
|
||||
sd_model.to(devices.cpu)
|
||||
if (reuse_dict or shared.opts.model_reuse_dict) and not sd_model.has_accelerate:
|
||||
if (reuse_dict or shared.opts.model_reuse_dict) and not getattr(sd_model, 'has_accelerate', False):
|
||||
shared.log.info('Reusing previous model dictionary')
|
||||
sd_hijack.model_hijack.undo_hijack(sd_model)
|
||||
else:
|
||||
@@ -1164,7 +1164,7 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model')
|
||||
timer.record("hijack")
|
||||
script_callbacks.model_loaded_callback(sd_model)
|
||||
timer.record("callbacks")
|
||||
if sd_model is not None and not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram and not sd_model.has_accelerate:
|
||||
if sd_model is not None and not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram and not getattr(sd_model, 'has_accelerate', False):
|
||||
sd_model.to(devices.device)
|
||||
timer.record("device")
|
||||
shared.log.info(f"Weights loaded in {timer.summary()}")
|
||||
@@ -1172,7 +1172,7 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model')
|
||||
|
||||
def disable_offload(sd_model):
|
||||
from accelerate.hooks import remove_hook_from_module
|
||||
if not sd_model.has_accelerate:
|
||||
if not getattr(sd_model, 'has_accelerate', False):
|
||||
return
|
||||
for _name, model in sd_model.components.items():
|
||||
if not isinstance(model, torch.nn.Module):
|
||||
|
||||
@@ -55,6 +55,29 @@ def samples_to_image_grid(samples, approximation=None):
|
||||
return images.image_grid([single_sample_to_image(sample, approximation) for sample in samples])
|
||||
|
||||
|
||||
def images_tensor_to_samples(image, approximation=None, model=None):
|
||||
'''image[0, 1] -> latent'''
|
||||
if approximation is None:
|
||||
approximation = approximation_indexes.get(shared.opts.show_progress_type, 0)
|
||||
if approximation == 3:
|
||||
image = image.to(devices.device, devices.dtype)
|
||||
x_latent = sd_vae_taesd.encode(image)
|
||||
else:
|
||||
if model is None:
|
||||
model = shared.sd_model
|
||||
model.first_stage_model.to(devices.dtype_vae)
|
||||
image = image.to(shared.device, dtype=devices.dtype_vae)
|
||||
image = image * 2 - 1
|
||||
if len(image) > 1:
|
||||
x_latent = torch.stack([
|
||||
model.get_first_stage_encoding(model.encode_first_stage(torch.unsqueeze(img, 0)))[0]
|
||||
for img in image
|
||||
])
|
||||
else:
|
||||
x_latent = model.get_first_stage_encoding(model.encode_first_stage(image))
|
||||
return x_latent
|
||||
|
||||
|
||||
def store_latent(decoded):
|
||||
shared.state.current_latent = decoded
|
||||
if shared.opts.live_previews_enable and shared.opts.show_progress_every_n_steps > 0 and shared.state.sampling_step % shared.opts.show_progress_every_n_steps == 0:
|
||||
|
||||
+2
-2
@@ -243,7 +243,7 @@ def reload_vae_weights(sd_model=None, vae_file=unspecified):
|
||||
vae_source = "function-argument"
|
||||
if loaded_vae_file == vae_file:
|
||||
return
|
||||
if not sd_model.has_accelerate:
|
||||
if not getattr(sd_model, 'has_accelerate', False):
|
||||
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
|
||||
lowvram.send_everything_to_cpu()
|
||||
else:
|
||||
@@ -265,6 +265,6 @@ def reload_vae_weights(sd_model=None, vae_file=unspecified):
|
||||
if vae is not None:
|
||||
sd_model.vae = vae
|
||||
|
||||
if not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram and not sd_model.has_accelerate:
|
||||
if not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram and not getattr(sd_model, 'has_accelerate', False):
|
||||
sd_model.to(devices.device)
|
||||
return sd_model
|
||||
|
||||
+43
-35
@@ -11,7 +11,7 @@ from enum import Enum
|
||||
import gradio as gr
|
||||
import fasteners
|
||||
from rich.console import Console
|
||||
from modules import errors, ui_components, shared_items, cmd_args
|
||||
from modules import errors, shared_items, cmd_args, ui_components
|
||||
from modules.paths_internal import models_path, script_path, data_path, sd_configs_path, sd_default_config, sd_model_file, default_sd_model_file, extensions_dir, extensions_builtin_dir # pylint: disable=W0611
|
||||
from modules.dml import memory_providers, default_memory_provider, directml_do_hijack
|
||||
import modules.interrogate
|
||||
@@ -37,6 +37,7 @@ interrogator = modules.interrogate.InterrogateModels("interrogate")
|
||||
sd_upscalers = []
|
||||
face_restorers = []
|
||||
tab_names = []
|
||||
extra_networks = []
|
||||
options_templates = {}
|
||||
hypernetworks = {}
|
||||
loaded_hypernetworks = []
|
||||
@@ -71,21 +72,12 @@ restricted_opts = {
|
||||
compatibility_opts = ['clip_skip', 'uni_pc_lower_order_final', 'uni_pc_order']
|
||||
console = Console(log_time=True, log_time_format='%H:%M:%S-%f')
|
||||
|
||||
def is_url(string):
|
||||
parsed_url = urlparse(string)
|
||||
return all([parsed_url.scheme, parsed_url.netloc])
|
||||
|
||||
|
||||
class Backend(Enum):
|
||||
ORIGINAL = 1
|
||||
DIFFUSERS = 2
|
||||
|
||||
|
||||
def reload_hypernetworks():
|
||||
from modules.hypernetworks import hypernetwork
|
||||
global hypernetworks # pylint: disable=W0603
|
||||
hypernetworks = hypernetwork.list_hypernetworks(opts.hypernetwork_dir)
|
||||
|
||||
|
||||
class State:
|
||||
skipped = False
|
||||
@@ -192,6 +184,7 @@ class State:
|
||||
self.current_image = image
|
||||
self.id_live_preview += 1
|
||||
|
||||
|
||||
state = State()
|
||||
state.server_start = time.time()
|
||||
if not hasattr(cmd_opts, "use_openvino"):
|
||||
@@ -251,6 +244,17 @@ def list_checkpoint_tiles():
|
||||
default_checkpoint = list_checkpoint_tiles()[0] if len(list_checkpoint_tiles()) > 0 else "model.ckpt"
|
||||
|
||||
|
||||
def is_url(string):
|
||||
parsed_url = urlparse(string)
|
||||
return all([parsed_url.scheme, parsed_url.netloc])
|
||||
|
||||
|
||||
def reload_hypernetworks():
|
||||
from modules.hypernetworks import hypernetwork
|
||||
global hypernetworks # pylint: disable=W0603
|
||||
hypernetworks = hypernetwork.list_hypernetworks(opts.hypernetwork_dir)
|
||||
|
||||
|
||||
def refresh_checkpoints():
|
||||
import modules.sd_models # pylint: disable=W0621
|
||||
return modules.sd_models.list_models()
|
||||
@@ -336,7 +340,7 @@ def readfile(filename, silent=False):
|
||||
return data
|
||||
|
||||
|
||||
def writefile(data, filename, mode='w'):
|
||||
def writefile(data, filename, mode='w', silent=False):
|
||||
|
||||
def default(obj):
|
||||
log.error(f"Saving: {filename} not a valid object: {obj}")
|
||||
@@ -346,7 +350,8 @@ def writefile(data, filename, mode='w'):
|
||||
with fasteners.InterProcessLock(f"{filename}.lock"):
|
||||
# skipkeys=True, ensure_ascii=True, check_circular=True, allow_nan=True
|
||||
output = json.dumps(data, indent=2, default=default)
|
||||
log.debug(f'Saving: {filename} len={len(output)}')
|
||||
if not silent:
|
||||
log.debug(f'Saving: {filename} len={len(output)}')
|
||||
with open(filename, mode, encoding="utf8") as file:
|
||||
file.write(output)
|
||||
except Exception as e:
|
||||
@@ -372,24 +377,26 @@ options_templates.update(options_section(('sd', "Execution & Models"), {
|
||||
"sd_checkpoint_autoload": OptionInfo(True, "Model autoload on server start"),
|
||||
"sd_model_checkpoint": OptionInfo(default_checkpoint, "Base model", gr.Dropdown, lambda: {"choices": list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_model_refiner": OptionInfo('None', "Refiner model", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"sd_checkpoint_cache": OptionInfo(0, "Number of cached models", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae_checkpoint_cache": OptionInfo(0, "Number of cached VAEs", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae": OptionInfo("Automatic", "VAE model", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list),
|
||||
"sd_model_dict": OptionInfo('None', "Use baseline data from a different model", gr.Dropdown, lambda: {"choices": ['None'] + list_checkpoint_tiles()}, refresh=refresh_checkpoints),
|
||||
"stream_load": OptionInfo(False, "Load models using stream loading method"),
|
||||
"model_reuse_dict": OptionInfo(False, "When loading models attempt to reuse previous model dictionary"),
|
||||
"model_reuse_dict": OptionInfo(False, "When loading models attempt to reuse previous model dictionary", gr.Checkbox, {"visible": False}),
|
||||
"prompt_attention": OptionInfo("Full parser", "Prompt attention parser", gr.Radio, lambda: {"choices": ["Full parser", "Compel parser", "A1111 parser", "Fixed attention"] }),
|
||||
"prompt_mean_norm": OptionInfo(True, "Prompt attention mean normalization"),
|
||||
"comma_padding_backtrack": OptionInfo(20, "Prompt padding for long prompts", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }),
|
||||
"sd_checkpoint_cache": OptionInfo(0, "Number of cached models", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae_checkpoint_cache": OptionInfo(0, "Number of cached VAEs", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_disable_ckpt": OptionInfo(False, "Disallow usage of models in ckpt format"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('optimizations', "Optimizations"), {
|
||||
"cross_attention_optimization": OptionInfo(cross_attention_optimization_default, "Cross-attention optimization method", gr.Radio, lambda: {"choices": shared_items.list_crossattention() }),
|
||||
"cross_attention_options": OptionInfo([], "Cross-attention advanced options", gr.CheckboxGroup, lambda: {"choices": ['xFormers enable flash Attention', 'SDP disable memory attention']}),
|
||||
"sub_quad_q_chunk_size": OptionInfo(512, "Sub-quadratic cross-attention query chunk size", gr.Slider, {"minimum": 16, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_kv_chunk_size": OptionInfo(512, "Sub-quadratic cross-attention kv chunk size", gr.Slider, {"minimum": 0, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_chunk_threshold": OptionInfo(80, "Sub-quadratic cross-attention chunking threshold", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
|
||||
"sub_quad_sep": OptionInfo("<h2>Sub-quadratic options</h2>", "", gr.HTML),
|
||||
"sub_quad_q_chunk_size": OptionInfo(512, "cross-attention query chunk size", gr.Slider, {"minimum": 16, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_kv_chunk_size": OptionInfo(512, "cross-attention kv chunk size", gr.Slider, {"minimum": 0, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_chunk_threshold": OptionInfo(80, "cross-attention chunking threshold", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
|
||||
"token_merging_sep": OptionInfo("<h2>Token Merging</h2>", "", gr.HTML),
|
||||
"token_merging_ratio": OptionInfo(0.0, "Token merging ratio", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}),
|
||||
"token_merging_ratio_img2img": OptionInfo(0.0, "Token merging ratio for img2img", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}),
|
||||
"token_merging_ratio_hr": OptionInfo(0.0, "Token merging ratio for hires pass", gr.Slider, {"minimum": 0.0, "maximum": 0.9, "step": 0.1}),
|
||||
@@ -437,7 +444,7 @@ options_templates.update(options_section(('diffusers', "Diffusers Settings"), {
|
||||
"diffusers_attention_slicing": OptionInfo(True if devices.backend == "ipex" else False, "Enable attention slicing"),
|
||||
"diffusers_model_load_variant": OptionInfo("default", "Diffusers model loading variant", gr.Radio, lambda: {"choices": ['default', 'fp32', 'fp16']}),
|
||||
"diffusers_vae_load_variant": OptionInfo("default", "Diffusers VAE loading variant", gr.Radio, lambda: {"choices": ['default', 'fp32', 'fp16']}),
|
||||
"diffusers_lora_loader": OptionInfo("diffusers", "Diffusers LoRA loading variant", gr.Radio, lambda: {"choices": ['diffusers', 'sequential apply', 'merge and apply']}),
|
||||
"diffusers_lora_loader": OptionInfo("diffusers" if cmd_opts.use_openvino else "sequential apply", "Diffusers LoRA loading variant", gr.Radio, lambda: {"choices": ['diffusers', 'sequential apply', 'merge and apply']}),
|
||||
"diffusers_force_zeros": OptionInfo(True, "Force zeros for prompts when empty"),
|
||||
"diffusers_aesthetics_score": OptionInfo(False, "Require aesthetics score"),
|
||||
}))
|
||||
@@ -525,19 +532,19 @@ options_templates.update(options_section(('saving-paths', "Image Naming & Paths"
|
||||
options_templates.update(options_section(('ui', "User Interface"), {
|
||||
"gradio_theme": OptionInfo("black-teal", "UI theme", gr.Dropdown, lambda: {"choices": list_themes()}, refresh=refresh_themes),
|
||||
"theme_style": OptionInfo("Auto", "Theme mode", gr.Radio, {"choices": ["Auto", "Dark", "Light"]}),
|
||||
"tooltips": OptionInfo("UI Tooltips", "UI tooltips", gr.Radio, {"choices": ["None", "Browser default", "UI tooltips"]}),
|
||||
"return_grid": OptionInfo(True, "Show grid in results for web"),
|
||||
"return_mask": OptionInfo(False, "For inpainting, include the greyscale mask in results for web"),
|
||||
"return_mask_composite": OptionInfo(False, "For inpainting, include masked composite in results for web"),
|
||||
"tooltips": OptionInfo("UI Tooltips", "UI tooltips", gr.Radio, {"choices": ["None", "Browser default", "UI tooltips"], "visible": False}),
|
||||
"return_grid": OptionInfo(True, "Show grid in results"),
|
||||
"return_mask": OptionInfo(False, "For inpainting, include the greyscale mask in results"),
|
||||
"return_mask_composite": OptionInfo(False, "For inpainting, include masked composite in results"),
|
||||
"disable_weights_auto_swap": OptionInfo(True, "Do not change selected model when reading generation parameters"),
|
||||
"send_seed": OptionInfo(True, "Send seed when sending prompt or image to other interface"),
|
||||
"send_size": OptionInfo(True, "Send size when sending prompt or image to another interface"),
|
||||
"font": OptionInfo("", "Font for image grids that have text"),
|
||||
"keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
|
||||
"keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
|
||||
"keyedit_delimiters": OptionInfo(".,\/!?%^*;:{}=`~()", "Ctrl+up/down word delimiters"), # pylint: disable=anomalous-backslash-in-string
|
||||
"keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001, "visible": False}),
|
||||
"keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001, "visible": False}),
|
||||
"keyedit_delimiters": OptionInfo(".,\/!?%^*;:{}=`~()", "Ctrl+up/down word delimiters", gr.Textbox, { "visible": False }), # pylint: disable=anomalous-backslash-in-string
|
||||
"quicksettings_list": OptionInfo(["sd_model_checkpoint"] if backend == Backend.ORIGINAL else ["sd_model_checkpoint", "sd_model_refiner"], "Quicksettings list", ui_components.DropdownMulti, lambda: {"choices": list(opts.data_labels.keys())}),
|
||||
"ui_scripts_reorder": OptionInfo("", "UI scripts order"),
|
||||
"ui_scripts_reorder": OptionInfo("", "UI scripts order", gr.Textbox, { "visible": False }),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('live-preview', "Live Previews"), {
|
||||
@@ -548,7 +555,7 @@ options_templates.update(options_section(('live-preview', "Live Previews"), {
|
||||
"notification_audio_path": OptionInfo("html/notification.mp3","Path to notification sound", component_args=hide_dirs, folder=True),
|
||||
"show_progress_every_n_steps": OptionInfo(1, "Live preview display period", gr.Slider, {"minimum": -1, "maximum": 32, "step": 1}),
|
||||
"show_progress_type": OptionInfo("Approximate NN", "Live preview method", gr.Radio, {"choices": ["Full VAE", "Approximate NN", "Approximate simple", "TAESD"]}),
|
||||
"live_preview_content": OptionInfo("Combined", "Live preview subject", gr.Radio, {"choices": ["Combined", "Prompt", "Negative prompt"]}),
|
||||
"live_preview_content": OptionInfo("Combined", "Live preview subject", gr.Radio, {"choices": ["Combined", "Prompt", "Negative prompt"], "visible": False}),
|
||||
"live_preview_refresh_period": OptionInfo(500, "Progress update period", gr.Slider, {"minimum": 0, "maximum": 5000, "step": 25}),
|
||||
"logmonitor_show": OptionInfo(True, "Show log view"),
|
||||
"logmonitor_refresh_period": OptionInfo(5000, "Log view update period", gr.Slider, {"minimum": 0, "maximum": 30000, "step": 25}),
|
||||
@@ -606,7 +613,7 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), {
|
||||
"postprocessing_sep_upscalers": OptionInfo("<h2>Upscaling</h2>", "", gr.HTML),
|
||||
'upscaling_max_images_in_cache': OptionInfo(5, "Maximum number of images in upscaling cache", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"upscaler_for_img2img": OptionInfo("None", "Default upscaler for image resize operations", gr.Dropdown, lambda: {"choices": [x.name for x in sd_upscalers]}),
|
||||
"realesrgan_enabled_models": OptionInfo(["R-ESRGAN 4x+", "R-ESRGAN 4x+ Anime6B"], "Real-ESRGAN available models", gr.CheckboxGroup, lambda: {"choices": shared_items.realesrgan_models_names()}),
|
||||
# "realesrgan_enabled_models": OptionInfo(["R-ESRGAN 4x+", "R-ESRGAN 4x+ Anime6B"], "Real-ESRGAN available models", gr.CheckboxGroup, lambda: {"choices": shared_items.realesrgan_models_names()}),
|
||||
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
"ESRGAN_tile_overlap": OptionInfo(8, "Tile overlap in pixels for ESRGAN upscalers", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
|
||||
"SCUNET_tile": OptionInfo(256, "Tile size for SCUNET upscalers", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
@@ -634,7 +641,7 @@ options_templates.update(options_section(('interrogate', "Interrogate"), {
|
||||
"interrogate_clip_num_beams": OptionInfo(1, "Interrogate: num_beams for BLIP", gr.Slider, {"minimum": 1, "maximum": 16, "step": 1}),
|
||||
"interrogate_clip_min_length": OptionInfo(32, "Interrogate: minimum description length", gr.Slider, {"minimum": 1, "maximum": 128, "step": 1}),
|
||||
"interrogate_clip_max_length": OptionInfo(192, "Interrogate: maximum description length", gr.Slider, {"minimum": 1, "maximum": 256, "step": 1}),
|
||||
"interrogate_clip_dict_limit": OptionInfo(2048, "CLIP: maximum number of lines in text file"),
|
||||
"interrogate_clip_dict_limit": OptionInfo(2048, "CLIP: maximum number of lines in text file", gr.Slider, { "visible": False }),
|
||||
"interrogate_clip_skip_categories": OptionInfo(["artists", "movements", "flavors"], "Interrogate: skip categories", gr.CheckboxGroup, lambda: {"choices": modules.interrogate.category_types()}, refresh=modules.interrogate.category_types),
|
||||
"interrogate_deepbooru_score_threshold": OptionInfo(0.65, "Interrogate: deepbooru score threshold", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
|
||||
"deepbooru_sort_alpha": OptionInfo(False, "Interrogate: deepbooru sort alphabetically"),
|
||||
@@ -644,17 +651,18 @@ options_templates.update(options_section(('interrogate', "Interrogate"), {
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
|
||||
"extra_networks": OptionInfo(["All"], "Extra networks", ui_components.DropdownMulti, lambda: {"choices": ['All'] + [en.title for en in extra_networks]}),
|
||||
"extra_networks_card_cover": OptionInfo("sidebar", "UI position", gr.Radio, lambda: {"choices": ["cover", "inline", "sidebar"]}),
|
||||
"extra_networks_height": OptionInfo(53, "UI height (%)", gr.Slider, {"minimum": 10, "maximum": 100, "step": 1}),
|
||||
"extra_networks_sidebar_width": OptionInfo(35, "UI sidebar width (%)", gr.Slider, {"minimum": 10, "maximum": 80, "step": 1}),
|
||||
"extra_networks_card_lazy": OptionInfo(True, "UI card preview lazy loading"),
|
||||
"extra_networks_card_lazy": OptionInfo(True, "UI card preview lazy loading", gr.Checkbox, { "visible": False }),
|
||||
"extra_networks_card_size": OptionInfo(160, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
|
||||
"extra_networks_card_square": OptionInfo(True, "UI disable variable aspect ratio"),
|
||||
"extra_networks_card_fit": OptionInfo("cover", "UI image contain method", gr.Radio, lambda: {"choices": ["contain", "cover", "fill"]}),
|
||||
"extra_networks_card_fit": OptionInfo("cover", "UI image contain method", gr.Radio, lambda: {"choices": ["contain", "cover", "fill"], "visible": False}),
|
||||
"extra_network_skip_indexing": OptionInfo(False, "Do not automatically build extra network pages", gr.Checkbox),
|
||||
"lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all LoRA types", gr.Checkbox),
|
||||
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple LoRA", gr.Checkbox),
|
||||
"extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple LoRA", gr.Checkbox, { "visible": False }),
|
||||
"extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01, "visible": False}),
|
||||
"sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, lambda: { "choices": ["None"] + list(hypernetworks.keys()), "visible": False }, refresh=reload_hypernetworks),
|
||||
}))
|
||||
|
||||
@@ -829,7 +837,7 @@ else:
|
||||
opts.data['sd_backend'] = 'diffusers' if backend == Backend.DIFFUSERS else 'original'
|
||||
opts.data['uni_pc_lower_order_final'] = opts.schedulers_use_loworder
|
||||
opts.data['uni_pc_order'] = opts.schedulers_solver_order
|
||||
opts.data['diffusers_lora_loader'] = 'diffusers' # TODO broken in diffusers=0.21
|
||||
# opts.data['diffusers_lora_loader'] = 'diffusers' # TODO broken in diffusers=0.21
|
||||
log.info(f'Engine: backend={backend} compute={devices.backend} mode={devices.inference_context.__name__} device={devices.get_optimal_device_name()}')
|
||||
log.info(f'Device: {print_dict(devices.get_gpu_info())}')
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ def refresh_vae_list():
|
||||
|
||||
def list_crossattention():
|
||||
return [
|
||||
"Disable cross-attention layer optimization",
|
||||
"Disabled",
|
||||
"xFormers",
|
||||
"Scaled-Dot-Product",
|
||||
"Doggettx's",
|
||||
|
||||
+7
-2
@@ -392,7 +392,7 @@ def create_ui(startup_timer = None):
|
||||
with FormGroup():
|
||||
with FormRow(elem_id="sampler_selection_txt2img_alt_row1"):
|
||||
latent_index = gr.Dropdown(label='Secondary sampler', elem_id="txt2img_sampling_alt", choices=[x.name for x in modules.sd_samplers.samplers], value='Default', type="index")
|
||||
denoising_strength = gr.Slider(minimum=0.05, maximum=1.0, step=0.01, label='Denoising strength', value=0.5, elem_id="txt2img_denoising_strength")
|
||||
denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoising strength', value=0.5, elem_id="txt2img_denoising_strength")
|
||||
with FormRow(elem_id="txt2img_hires_finalres", variant="compact"):
|
||||
hr_final_resolution = FormHTML(value="", elem_id="txtimg_hr_finalres", label="Upscaled resolution", interactive=False)
|
||||
with FormRow(elem_id="txt2img_hires_fix_row1", variant="compact"):
|
||||
@@ -678,7 +678,7 @@ def create_ui(startup_timer = None):
|
||||
|
||||
with FormGroup(visible=show_denoise.value, elem_id=f"{tab}_denoise_group") as denoise_group:
|
||||
with FormRow():
|
||||
denoising_strength = gr.Slider(minimum=0.05, maximum=1.0, step=0.01, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength")
|
||||
denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoising strength', value=0.75, elem_id="img2img_denoising_strength")
|
||||
refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="img2img_refiner_start")
|
||||
|
||||
with FormGroup(visible=show_advanced.value, elem_id=f"{tab}_advanced_group") as advanced_group:
|
||||
@@ -1076,6 +1076,11 @@ def create_ui(startup_timer = None):
|
||||
loadsave.create_ui()
|
||||
create_dirty_indicator("tab_defaults", [], interactive=False)
|
||||
|
||||
with gr.TabItem("Change log", id="change_log", elem_id="system_tab_changelog"):
|
||||
with open('CHANGELOG.md', 'r', encoding='utf-8') as f:
|
||||
md = f.read()
|
||||
gr.Markdown(md)
|
||||
|
||||
with gr.TabItem("Licenses", id="system_licenses", elem_id="system_tab_licenses"):
|
||||
gr.HTML(modules.shared.html("licenses.html"), elem_id="licenses", elem_classes="licenses")
|
||||
create_dirty_indicator("tab_licenses", [], interactive=False)
|
||||
|
||||
+12
-6
@@ -75,15 +75,21 @@ def save_files(js_data, images, html_info, index):
|
||||
class PObject: # pylint: disable=too-few-public-methods
|
||||
def __init__(self, d=None):
|
||||
if d is not None:
|
||||
for key, value in d.items():
|
||||
setattr(self, key, value)
|
||||
self.seed = getattr(self, 'seed', None) or getattr(self, 'Seed', None)
|
||||
for k, v in d.items():
|
||||
setattr(self, k, v)
|
||||
self.prompt = getattr(self, 'prompt', None) or getattr(self, 'Prompt', None)
|
||||
self.all_seeds = getattr(self, 'all_seeds', [self.seed])
|
||||
self.all_prompts = getattr(self, 'all_prompts', [self.prompt])
|
||||
self.negative_prompt = getattr(self, 'negative_prompt', None)
|
||||
self.all_negative_prompt = getattr(self, 'all_negative_prompts', [self.negative_prompt])
|
||||
self.seed = getattr(self, 'seed', None) or getattr(self, 'Seed', None)
|
||||
self.all_seeds = getattr(self, 'all_seeds', [self.seed])
|
||||
self.subseed = getattr(self, 'subseed', None)
|
||||
self.all_subseeds = getattr(self, 'all_subseeds', [self.subseed])
|
||||
self.width = getattr(self, 'width', None)
|
||||
self.height = getattr(self, 'height', None)
|
||||
self.index_of_first_image = getattr(self, 'index_of_first_image', 0)
|
||||
self.infotexts = getattr(self, 'infotexts', [html_info])
|
||||
self.infotext = self.infotexts[0] if len(self.infotexts) > 0 else html_info
|
||||
self.index_of_first_image = getattr(self, 'index_of_first_image', 0)
|
||||
try:
|
||||
data = json.loads(js_data)
|
||||
except Exception:
|
||||
@@ -115,7 +121,7 @@ def save_files(js_data, images, html_info, index):
|
||||
destination = os.path.join(destination, dirname)
|
||||
os.makedirs(destination, exist_ok = True)
|
||||
shutil.copy(fullfn, destination)
|
||||
shared.log.info(f"Copying image: {fullfn} -> {destination}")
|
||||
shared.log.info(f'Copying image: file="{fullfn}" folder="{destination}"')
|
||||
tgt_filename = os.path.join(destination, os.path.basename(fullfn))
|
||||
modules.script_callbacks.image_save_btn_callback(tgt_filename)
|
||||
else:
|
||||
|
||||
@@ -16,10 +16,10 @@ from modules.ui_components import ToolButton
|
||||
import modules.ui_symbols as symbols
|
||||
|
||||
|
||||
extra_pages = []
|
||||
allowed_dirs = []
|
||||
dir_cache = {} # key=path, value=(mtime, listdir(path))
|
||||
refresh_time = None
|
||||
extra_pages = shared.extra_networks
|
||||
|
||||
|
||||
def listdir(path):
|
||||
@@ -37,9 +37,9 @@ def listdir(path):
|
||||
|
||||
def register_page(page):
|
||||
# registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions
|
||||
extra_pages.append(page)
|
||||
shared.extra_networks.append(page)
|
||||
allowed_dirs.clear()
|
||||
for page in extra_pages:
|
||||
for page in shared.extra_networks:
|
||||
for folder in page.allowed_directories_for_previews():
|
||||
if folder not in allowed_dirs:
|
||||
allowed_dirs.append(os.path.abspath(folder))
|
||||
@@ -58,7 +58,7 @@ def fetch_file(filename: str = ""):
|
||||
|
||||
|
||||
def get_metadata(page: str = "", item: str = ""):
|
||||
page = next(iter([x for x in extra_pages if x.name == page]), None)
|
||||
page = next(iter([x for x in shared.extra_networks if x.name == page]), None)
|
||||
if page is None:
|
||||
return JSONResponse({ 'metadata': 'none' })
|
||||
metadata = page.metadata.get(item, 'none')
|
||||
@@ -69,7 +69,7 @@ def get_metadata(page: str = "", item: str = ""):
|
||||
|
||||
|
||||
def get_info(page: str = "", item: str = ""):
|
||||
page = next(iter([x for x in extra_pages if x.name == page]), None)
|
||||
page = next(iter([x for x in shared.extra_networks if x.name == page]), None)
|
||||
if page is None:
|
||||
return JSONResponse({ 'info': 'none' })
|
||||
info = page.info.get(item, 'none')
|
||||
@@ -128,7 +128,7 @@ class ExtraNetworksPage:
|
||||
shared.log.error(f'Cannot evaluate extra network prompt: {item["prompt"]} {e}')
|
||||
|
||||
if not any(self.title in x.label for x in xyz_grid.axis_options):
|
||||
if self.title == 'Checkpoints':
|
||||
if self.title == 'Model':
|
||||
return
|
||||
opt = xyz_grid.AxisOption(f"[Network] {self.title}", str, add_prompt, choices=lambda: [x["name"] for x in self.items])
|
||||
xyz_grid.axis_options.append(opt)
|
||||
@@ -308,7 +308,7 @@ class ExtraNetworksPage:
|
||||
shared.log.error(f'Extra network save preview: {filename} {e}')
|
||||
return
|
||||
is_allowed = False
|
||||
for page in extra_pages:
|
||||
for page in shared.extra_networks:
|
||||
if any(path_is_parent(x, filename) for x in page.allowed_directories_for_previews()):
|
||||
is_allowed = True
|
||||
break
|
||||
@@ -339,7 +339,7 @@ class ExtraNetworksPage:
|
||||
|
||||
|
||||
def initialize():
|
||||
extra_pages.clear()
|
||||
shared.extra_networks.clear()
|
||||
|
||||
|
||||
def register_pages():
|
||||
@@ -353,6 +353,21 @@ def register_pages():
|
||||
register_page(ExtraNetworksPageHypernetworks())
|
||||
|
||||
|
||||
def get_pages():
|
||||
pages = []
|
||||
if 'All' in shared.opts.extra_networks:
|
||||
pages = shared.extra_networks
|
||||
else:
|
||||
titles = [page.title for page in shared.extra_networks]
|
||||
for page in shared.opts.extra_networks:
|
||||
try:
|
||||
idx = titles.index(page)
|
||||
except ValueError:
|
||||
continue
|
||||
pages.append(shared.extra_networks[idx])
|
||||
return pages
|
||||
|
||||
|
||||
class ExtraNetworksUi:
|
||||
def __init__(self):
|
||||
self.pages = None
|
||||
@@ -384,7 +399,7 @@ def create_ui(container, button, tabname, skip_indexing = False):
|
||||
if ui.tabname == 'txt2img': # refresh only once
|
||||
global refresh_time # pylint: disable=global-statement
|
||||
refresh_time = time.time()
|
||||
for page in extra_pages:
|
||||
for page in get_pages():
|
||||
page.create_page(ui.tabname, skip_indexing)
|
||||
with gr.Tab(page.title, id=page.title.lower().replace(" ", "_"), elem_classes="extra-networks-tab"):
|
||||
hmtl = gr.HTML(page.html, elem_id=f'{tabname}{page.name}_extra_page', elem_classes="extra-networks-page")
|
||||
@@ -396,16 +411,16 @@ def create_ui(container, button, tabname, skip_indexing = False):
|
||||
return is_visible, gr.update(visible=is_visible), gr.update(variant=("secondary-down" if is_visible else "secondary"))
|
||||
|
||||
def en_refresh(title):
|
||||
res = []
|
||||
for page in extra_pages:
|
||||
pages = []
|
||||
for page in get_pages():
|
||||
if title is None or title == '' or title == page.title or len(page.html) == 0:
|
||||
page.refresh()
|
||||
page.refresh_time = None
|
||||
page.create_page(ui.tabname)
|
||||
shared.log.debug(f"Refreshing Extra networks: page='{page.title}' items={len(page.items)} tab={ui.tabname}")
|
||||
res.append(page.html)
|
||||
pages.append(page.html)
|
||||
ui.search.update(value = ui.search.value)
|
||||
return res
|
||||
return pages
|
||||
|
||||
state_visible = gr.State(value=False) # pylint: disable=abstract-class-instantiated
|
||||
button.click(fn=toggle_visibility, inputs=[state_visible], outputs=[state_visible, container, button])
|
||||
@@ -423,15 +438,13 @@ def path_is_parent(parent_path, child_path):
|
||||
def setup_ui(ui, gallery):
|
||||
|
||||
def save_preview(pagename, index, images, filename):
|
||||
res = []
|
||||
for page in extra_pages:
|
||||
pages = []
|
||||
for page in get_pages():
|
||||
if pagename is None or pagename == '' or pagename == page.title or len(page.html) == 0:
|
||||
page.save_preview(index, images, filename)
|
||||
res.append(page.create_page(ui.tabname))
|
||||
else:
|
||||
res.append(page.html)
|
||||
return res
|
||||
|
||||
page.create_page(ui.tabname)
|
||||
pages.append(page.html)
|
||||
return pages
|
||||
|
||||
ui.button_save_preview.click(
|
||||
fn=save_preview,
|
||||
@@ -441,14 +454,13 @@ def setup_ui(ui, gallery):
|
||||
)
|
||||
|
||||
def save_description(pagename, filename, desc):
|
||||
res = []
|
||||
for page in extra_pages:
|
||||
pages = []
|
||||
for page in get_pages():
|
||||
if pagename is None or pagename == '' or pagename == page.title or len(page.html) == 0:
|
||||
page.save_description(filename, desc)
|
||||
res.append(page.create_page(ui.tabname))
|
||||
else:
|
||||
res.append(page.html)
|
||||
return res
|
||||
page.create_page(ui.tabname)
|
||||
pages.append(page.html)
|
||||
return pages
|
||||
|
||||
ui.button_save_description.click(
|
||||
fn=save_description,
|
||||
|
||||
@@ -7,7 +7,7 @@ from modules import shared, ui_extra_networks, sd_models
|
||||
|
||||
class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
|
||||
def __init__(self):
|
||||
super().__init__('Checkpoints')
|
||||
super().__init__('Model')
|
||||
|
||||
def refresh(self):
|
||||
shared.refresh_checkpoints()
|
||||
|
||||
@@ -5,7 +5,7 @@ from modules import shared, ui_extra_networks
|
||||
|
||||
class ExtraNetworksPageHypernetworks(ui_extra_networks.ExtraNetworksPage):
|
||||
def __init__(self):
|
||||
super().__init__('Hypernetworks')
|
||||
super().__init__('Hypernetwork')
|
||||
|
||||
def refresh(self):
|
||||
shared.reload_hypernetworks()
|
||||
|
||||
@@ -6,7 +6,7 @@ from modules import shared, ui_extra_networks
|
||||
|
||||
class ExtraNetworksPageStyles(ui_extra_networks.ExtraNetworksPage):
|
||||
def __init__(self):
|
||||
super().__init__('Styles')
|
||||
super().__init__('Style')
|
||||
|
||||
def refresh(self):
|
||||
shared.prompt_styles.reload()
|
||||
|
||||
@@ -7,7 +7,7 @@ from modules.textual_inversion.textual_inversion import Embedding
|
||||
|
||||
class ExtraNetworksPageTextualInversion(ui_extra_networks.ExtraNetworksPage):
|
||||
def __init__(self):
|
||||
super().__init__('Textual Inversion')
|
||||
super().__init__('Embedding')
|
||||
self.allow_negative_prompt = True
|
||||
|
||||
def refresh(self):
|
||||
|
||||
@@ -61,7 +61,7 @@ def pil_to_temp_file(self, img, dir: str, format="png") -> str: # pylint: disabl
|
||||
file_obj = tempfile.NamedTemporaryFile(delete=False, suffix=".png", dir=dir)
|
||||
img.save(file_obj, pnginfo=(metadata if use_metadata else None))
|
||||
name = file_obj.name
|
||||
shared.log.debug(f'Saving temp image: {name}')
|
||||
shared.log.debug(f'Saving temp: image="{name}"')
|
||||
return name
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ opencv-contrib-python-headless
|
||||
piexif
|
||||
psutil
|
||||
pyyaml
|
||||
realesrgan
|
||||
resize-right
|
||||
rich
|
||||
safetensors
|
||||
|
||||
Reference in New Issue
Block a user