update upscalers

This commit is contained in:
Vladimir Mandic
2023-09-30 09:20:22 -04:00
parent f11cf4b29a
commit d01f01c981
10 changed files with 57 additions and 40 deletions
+11 -4
View File
@@ -8,7 +8,7 @@
- Add HAT upscaler
- Switch Diffusers prompt parser
This is a big one, with some major changes and new functionality...
This is a big one, with some major changes and new functionality...
And probably the biggest release since introduction of **Diffusers**
Note that for this release its recommended to perform a clean install (fresh `git clone`)
@@ -71,14 +71,15 @@ Upgrades are still possible and supported, but above is recommended for best exp
thanks @AI-Casanova
- better **Lora** handling
thanks @AI-Casanova
- new setting: *settings -> diffusers -> force inpaint*
- new setting: *settings -> diffusers -> force inpaint*
as some models behave better when in *inpaint* mode even for normal *img2img* tasks
- **Upscalers**:
- pretty much a rewrite and tons of new upscalers - built-in list is now at **42**
- fix long outstanding memory leak in legacy code, amazing this went undetected for so long
- more high quality upscalers available by default
*SwinIR:2, ESRGAN:12, RealESRGAN:6, SCUNet:2*
**SwinIR** (2), **ESRGAN** (12), **RealESRGAN** (6), **SCUNet** (2)
- two additional latent upscalers based on SD upscale models when using Diffusers backend
*SD Upscale 2x, SD Upscale 4x*
**SD Upscale 2x**, **SD Upscale 4x***
Note: Recommended usage for *SD Upscale* is by using second pass instead of upscaler
as it allows for tuning of prompt, seed, sampler settings which are used to guide upscaler
- upscalers are available in **xyz grid**
@@ -88,6 +89,12 @@ Upgrades are still possible and supported, but above is recommended for best exp
simply set *denoising strength* to 0 so hires does not get triggered
- unified init/download/execute/progress code
- easier installation
- and if that is not enough, install extension:
<https://github.com/vladmandic/sd-extension-chainner>
and it will add 15 more upscalers from different families:
**HAT** (6), **RealHAT** (2), **DAT** (1), **RRDBNet** (1), **SPSRNet** (1), **SRFormer** (2), **SwiftSR** (2)
and yes, you can download and add your own, just place them in `models/chaiNNer`
note: extension will probably be added to default built-in list in the near-future
- **Samplers**:
- moved ui options to submenu
- default list for new installs is now all samplers, list can be modified in settings
+10 -10
View File
@@ -5,17 +5,17 @@
],
"ESRGAN": [
["4x GAN", "https://github.com/cszn/KAIR/releases/download/v1.0/ESRGAN.pth"],
["4x Ultrasharp", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4x-UltraSharp.pth"],
["4x Valar", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4x_Valar_v1.pth"],
["4x Box", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4xBox.pth"],
["4x BigFace V3", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4x_BigFace_v3.pth"],
["4x Remacri", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4x_foolhardy_Remacri.pth"],
["4x NMKD Siax", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4x_NMKD-Siax_200k.pth"],
["4x NMKD Superscale", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4x_NMKD-Superscale-SP_178000_G.pth"],
["4x NMKD YandereNeo", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/4x_NMKD-YandereNeoXL_200k.pth"],
["4x Ultrasharp", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-UltraSharp-4x.pth"],
["4x Valar", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-Valar-4x.pth"],
["4x Box", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-Box-4x.pth"],
["4x BigFace V3", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-BigFace-v3-4x.pth"],
["4x Remacri", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-Remacri-4x.pth"],
["4x NMKD Siax", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-NMKD-Siax-4x.pth"],
["4x NMKD Superscale", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-NMKD-Superscale-4x.pth"],
["4x NMKD YandereNeoXL", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-NMKD-YandereNeoXL-4x.pth"],
["8x NMKD Faces", "https://huggingface.co/Zabin/Resizers/resolve/main/8x_NMKD-Faces_160000_G.pth"],
["8x Superscale", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/8x_NMKD-Superscale_150000_G.pth"],
["8x HugePaint", "https://huggingface.co/Aptronym/SDNext/resolve/main/Upscalers/8x_HugePaint_v1.pth"]
["8x Superscale", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-NMKD-Superscale-8x.pth"],
["8x HugePaint", "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/ESRGAN-HugePaint-8x.pth"]
],
"RealESRGAN": [
["4x General V3", "https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-general-x4v3.pth"],
+4
View File
@@ -692,6 +692,10 @@ def ensure_base_requirements():
import rich # pylint: disable=unused-import
except ImportError:
install('rich', 'rich')
try:
import rich # pylint: disable=unused-import
except ImportError:
pass
def install_requirements():
+4 -5
View File
@@ -527,6 +527,7 @@ def load_upscalers():
classname = str(cls)
if classname not in used_classes:
used_classes[classname] = cls
names = []
for cls in reversed(used_classes.values()):
name = cls.__name__
cmd_name = f"{name.lower().replace('upscaler', '')}_models_path"
@@ -535,8 +536,6 @@ def load_upscalers():
scaler.user_path = commandline_model_path
scaler.model_download_path = commandline_model_path or scaler.model_path
datas += scaler.scalers
shared.sd_upscalers = sorted(
datas,
key=lambda x: x.name.lower() if not isinstance(x.scaler, (UpscalerNone, UpscalerLanczos, UpscalerNearest)) else "" # Special case for UpscalerNone keeps it at the beginning of the list.
)
shared.log.debug(f"Loaded upscalers: total={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])}")
names.append(name[8:])
shared.sd_upscalers = sorted(datas, key=lambda x: x.name.lower() if not isinstance(x.scaler, (UpscalerNone, UpscalerLanczos, UpscalerNearest)) else "") # Special case for UpscalerNone keeps it at the beginning of the list.
shared.log.debug(f"Loaded upscalers: total={len(shared.sd_upscalers)} downloaded={len([x for x in shared.sd_upscalers if x.data_path is not None and os.path.isfile(x.data_path)])} user={len([x for x in shared.sd_upscalers if x.custom])} {names}")
+2 -2
View File
@@ -2,7 +2,7 @@ import PIL.Image
import numpy as np
import torch
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn
from modules import devices, script_callbacks
from modules import devices
from modules.postprocess.scunet_model_arch import SCUNet as net
from modules.shared import opts, log, console, device
from modules.upscaler import Upscaler
@@ -67,7 +67,7 @@ class UpscalerSCUNet(Upscaler):
output = E.div_(W)
return output
def do_upscale(self, img: PIL.Image.Image, selected_file): # pylint: disable=arguments-renamed
def do_upscale(self, img: PIL.Image.Image, selected_file):
devices.torch_gc()
model = self.load_model(selected_file)
if model is None:
@@ -6,7 +6,7 @@ from modules.upscaler import Upscaler, UpscalerData
class UpscalerSD(Upscaler):
def __init__(self, dirname): # pylint: disable=super-init-not-called
self.name = "StableDiffusion"
self.name = "SDUpscale"
self.user_path = dirname
if shared.backend != shared.Backend.DIFFUSERS:
super().__init__()
+9 -6
View File
@@ -13,13 +13,16 @@ def load_module(path):
module_spec = importlib.util.spec_from_file_location(os.path.basename(path), path)
module = importlib.util.module_from_spec(module_spec)
try:
# stdout = io.StringIO()
with contextlib.redirect_stdout(io.StringIO()) as stdout:
if '/sd-extension-' in path: # safe extensions without stdout intercept
module_spec.loader.exec_module(module)
setup_logging() # reset since scripts can hijaack logging
for line in stdout.getvalue().splitlines():
if len(line) > 0:
errors.log.info(f"Extension: script='{os.path.relpath(path)}' {line.strip()}")
else:
# stdout = io.StringIO()
with contextlib.redirect_stdout(io.StringIO()) as stdout:
module_spec.loader.exec_module(module)
setup_logging() # reset since scripts can hijaack logging
for line in stdout.getvalue().splitlines():
if len(line) > 0:
errors.log.info(f"Extension: script='{os.path.relpath(path)}' {line.strip()}")
except Exception as e:
errors.display(e, f'Module load: {path}')
return module
+14 -11
View File
@@ -97,23 +97,26 @@ class ExtraNetworksPageStyles(ui_extra_networks.ExtraNetworksPage):
def list_items(self):
for k, style in shared.prompt_styles.styles.items():
fn = os.path.splitext(style.filename)[0]
txt = f'Prompt: {style.prompt}'
if len(style.negative_prompt) > 0:
fn = os.path.splitext(getattr(style, 'filename', ''))[0]
name = getattr(style, 'name', '')
if name == '':
continue
txt = f'Prompt: {getattr(style, "prompt", "")}'
if len(getattr(style, 'negative_prompt', '')) > 0:
txt += f'\nNegative: {style.negative_prompt}'
yield {
"type": 'Style',
"name": style.name,
"name": name,
"title": k,
"filename": style.filename,
"search_term": f'{txt} {self.search_terms_from_path(style.name)}',
"preview": style.preview if style.preview is not None and style.preview.startswith('data:') else self.find_preview(fn),
"description": style.description if style.description is not None and len(style.description) > 0 else txt,
"prompt": style.prompt or '',
"negative": style.negative_prompt or '',
"extra": style.extra or '',
"search_term": f'{txt} {self.search_terms_from_path(name)}',
"preview": style.preview if getattr(style, 'preview', None) is not None and style.preview.startswith('data:') else self.find_preview(fn),
"description": style.description if getattr(style, 'description', None) is not None and len(style.description) > 0 else txt,
"prompt": getattr(style, 'prompt', ''),
"negative": getattr(style, 'negative_prompt', ''),
"extra": getattr(style, 'extra', ''),
"local_preview": f"{fn}.{shared.opts.samples_format}",
"onclick": '"' + html.escape(f"""return selectStyle({json.dumps(style.name)})""") + '"',
"onclick": '"' + html.escape(f"""return selectStyle({json.dumps(name)})""") + '"',
}
def allowed_directories_for_previews(self):
+1
View File
@@ -304,6 +304,7 @@ def webui(restart=False):
load_model()
shared.opts.save(shared.config_filename)
log.info(f"Startup time: {timer.startup.summary()}")
timer.startup.reset()
if not restart:
# override all loggers to use the same handlers as the main logger