Merge pull request #3194 from vladmandic/master

merge master to dev
This commit is contained in:
Vladimir Mandic
2024-06-02 11:59:02 -04:00
committed by GitHub
39 changed files with 225 additions and 116 deletions
+21 -4
View File
@@ -1,5 +1,26 @@
# Change Log for SD.Next
## Update for 2024-06-02
- fix textual inversion loading
- fix gallery mtime display
- fix extra network scrollable area when using modernui
- fix control prompts list handling
- fix restore variation seed and strength
- fix negative prompt parsing from metadata
- fix stable cascade progress monitoring
- fix variation seed with hires pass
- fix loading models trained with onetrainer
- add variation seed info to metadata
- workaround for scale-by when using modernui
- lock torch-directml version
- improve xformers installer
- improve ultralytics installer (face-hires)
- improve triton installer (compile)
- improve insightface installer (faceip)
- improve mim installer (dwpose)
- add dpm++ 1s and dpm++ 3m aliases for dpm++ 2m scheduler with different orders
## Update for 2024-05-28
### Highlights for 2024-05-28
@@ -11,10 +32,6 @@ For details on how to enable and use it, see [Home](https://github.com/BinaryQua
**ModernUI** is still in early development and not all features are available yet, please report [issues and feedback](https://github.com/BinaryQuantumSoul/sdnext-modernui/issues)
Thanks to @BinaryQuantumSoul for his hard work on this project!
![Screenshot-ModernUI](html/screenshot-modernui.jpg)
![Screenshot-ModernUI-Img](html/screenshot-modernui-img2img.jpg)
![Screenshot-ModernUI-Control](html/screenshot-modernui-control.jpg)
*What else?*
#### New built-in features
+1
View File
@@ -142,6 +142,7 @@ Also supported are modifiers such as:
- [Step-by-step install guide](https://github.com/vladmandic/automatic/wiki/Installation)
- [Advanced install notes](https://github.com/vladmandic/automatic/wiki/Advanced-Install)
- [Video: install and use](https://www.youtube.com/watch?v=nWTnTyFTuAs)
- [Common installation errors](https://github.com/vladmandic/automatic/discussions/1627)
- [FAQ](https://github.com/vladmandic/automatic/discussions/1011)
+19
View File
@@ -2,6 +2,10 @@
Main ToDo list can be found at [GitHub projects](https://github.com/users/vladmandic/projects)
## Fix
- ultralytics package install
## Future Candidates
- stable diffusion 3.0: unreleased
@@ -10,10 +14,25 @@ Main ToDo list can be found at [GitHub projects](https://github.com/users/vladma
- async lowvram: <https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14855>
- fp8: <https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/14031>
- profiling: <https://github.com/lllyasviel/stable-diffusion-webui-forge/discussions/716>
- kohya-hires-fix: <https://github.com/huggingface/diffusers/pull/7633>
- hunyuan-dit: <https://github.com/huggingface/diffusers/pull/8290>
- init latents: variations, img2img
- diffusers public callbacks
- include reference styles
- lora: sc lora, dora, etc
- controlnet: additional models
- resadapter: <https://github.com/bytedance/res-adapter>
- t-gate: <https://huggingface.co/docs/diffusers/main/en/optimization/tgate>
## Experimental
- [MuLan](https://github.com/mulanai/MuLan) Multi-langunage prompts - wirte your prompts in ~110 auto-detected languages!
Compatible with SD15 and SDXL
Enable in scripts -> MuLan and set encoder to `InternVL-14B-224px` encoder
(that is currently only supported encoder, but others will be added)
Note: Model will be auto-downloaded on first use: note its huge size of 27GB
Even executing it in FP16 context will require ~16GB of VRAM for text encoder alone
*Note*: Uses fixed prompt parser, so no prompt attention will be used
- [SDXL Flash Mini](https://huggingface.co/sd-community/sdxl-flash-mini)
SDXL type that weighs less, consumes less video memory, and the quality has not dropped much
to use, simply select from *networks -> models -> reference -> SDXL Flash Mini*
+18 -17
View File
@@ -1,3 +1,4 @@
from functools import lru_cache
import os
import sys
import json
@@ -171,6 +172,7 @@ def print_profile(profiler: cProfile.Profile, msg: str):
# check if package is installed
@lru_cache()
def installed(package, friendly: str = None, reload = False, quiet = False):
ok = True
try:
@@ -201,12 +203,12 @@ def installed(package, friendly: str = None, reload = False, quiet = False):
# log.debug(f"Package version found: {p[0]} {package_version}")
if len(p) > 1:
exact = package_version == p[1]
ok = ok and (exact or args.experimental)
if not exact and not quiet:
if args.experimental:
log.warning(f"Package allowing experimental: {p[0]} {package_version} required {p[1]}")
else:
log.warning(f"Package version mismatch: {p[0]} {package_version} required {p[1]}")
ok = ok and (exact or args.experimental)
else:
if not quiet:
log.debug(f"Package not found: {p[0]}")
@@ -227,6 +229,7 @@ def uninstall(package, quiet = False):
return res
@lru_cache()
def pip(arg: str, ignore: bool = False, quiet: bool = False):
arg = arg.replace('>=', '==')
if not quiet:
@@ -248,13 +251,15 @@ def pip(arg: str, ignore: bool = False, quiet: bool = False):
# install package using pip if not already installed
def install(package, friendly: str = None, ignore: bool = False):
@lru_cache()
def install(package, friendly: str = None, ignore: bool = False, reinstall: bool = False, no_deps: bool = False):
res = ''
if args.reinstall or args.upgrade:
global quick_allowed # pylint: disable=global-statement
quick_allowed = False
if args.reinstall or not installed(package, friendly):
res = pip(f"install --upgrade {package}", ignore=ignore)
if args.reinstall or reinstall or not installed(package, friendly, quiet=False):
deps = '' if not no_deps else '--no-deps'
res = pip(f"install --upgrade {deps} {package}", ignore=ignore)
try:
import imp # pylint: disable=deprecated-module
imp.reload(pkg_resources)
@@ -264,6 +269,7 @@ def install(package, friendly: str = None, ignore: bool = False):
# execute git command
@lru_cache()
def git(arg: str, folder: str = None, ignore: bool = False):
if args.skip_git:
return ''
@@ -434,12 +440,13 @@ def check_torch():
log.debug(f'Torch overrides: cuda={args.use_cuda} rocm={args.use_rocm} ipex={args.use_ipex} diml={args.use_directml} openvino={args.use_openvino}')
log.debug(f'Torch allowed: cuda={allow_cuda} rocm={allow_rocm} ipex={allow_ipex} diml={allow_directml} openvino={allow_openvino}')
torch_command = os.environ.get('TORCH_COMMAND', '')
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
xformers_package = os.environ.get('XFORMERS_PACKAGE', '--pre xformers') if opts.get('cross_attention_optimization', '') == 'xFormers' or args.use_xformers else 'none'
triton_command = os.environ.get('TRITON_COMMAND', 'triton') if sys.platform == 'linux' else None
def is_rocm_available():
if not allow_rocm:
return False
if installed('torch-directml'):
if installed('torch-directml', quiet=True):
log.debug('DirectML installation is detected. Skipping HIP SDK check.')
return False
if platform.system() == 'Windows':
@@ -452,14 +459,7 @@ def check_torch():
pass
elif allow_cuda and (shutil.which('nvidia-smi') is not None or args.use_xformers or os.path.exists(os.path.join(os.environ.get('SystemRoot') or r'C:\Windows', 'System32', 'nvidia-smi.exe'))):
log.info('nVidia CUDA toolkit detected: nvidia-smi present')
if not args.use_xformers:
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/cu121')
xformers_package = os.environ.get('XFORMERS_PACKAGE', '--pre triton xformers --index-url https://download.pytorch.org/whl/cu121')
else:
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/cu118')
xformers_package = os.environ.get('XFORMERS_PACKAGE', '--pre triton xformers --index-url https://download.pytorch.org/whl/cu118')
if opts.get('cross_attention_optimization', '') != 'xFormers':
xformers_package = 'none'
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision --index-url https://download.pytorch.org/whl/cu121')
install('onnxruntime-gpu', 'onnxruntime-gpu', ignore=True)
elif is_rocm_available():
is_windows = platform.system() == 'Windows'
@@ -555,7 +555,6 @@ def check_torch():
ort_version = os.environ.get('ONNXRUNTIME_VERSION', None)
ort_package = os.environ.get('ONNXRUNTIME_PACKAGE', f"--pre onnxruntime-training{'' if ort_version is None else ('==' + ort_version)} --index-url https://pypi.lsh.sh/{rocm_ver[0]}{rocm_ver[2]} --extra-index-url https://pypi.org/simple")
install(ort_package, 'onnxruntime-training')
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
elif allow_ipex and (args.use_ipex or shutil.which('sycl-ls') is not None or shutil.which('sycl-ls.exe') is not None or os.environ.get('ONEAPI_ROOT') is not None or os.path.exists('/opt/intel/oneapi') or os.path.exists("C:/Program Files (x86)/Intel/oneAPI") or os.path.exists("C:/oneAPI")):
args.use_ipex = True # pylint: disable=attribute-defined-outside-init
log.info('Intel OneAPI Toolkit detected')
@@ -623,6 +622,8 @@ def check_torch():
if not installed('torch', quiet=True):
log.debug(f'Installing torch: {torch_command}')
install(torch_command, 'torch torchvision')
if triton_command is not None:
install(triton_command, 'triton')
else:
try:
import torch
@@ -666,7 +667,7 @@ def check_torch():
install(f'--no-deps {xformers_package}', ignore=True)
import torch
import xformers # pylint: disable=unused-import
elif not args.experimental and not args.use_xformers:
elif not args.experimental and not args.use_xformers and opts.get('cross_attention_optimization', '') != 'xFormers':
uninstall('xformers')
except Exception as e:
log.debug(f'Cannot install xformers package: {e}')
@@ -863,7 +864,7 @@ def install_requirements():
with open('requirements.txt', 'r', encoding='utf8') as f:
lines = [line.strip() for line in f.readlines() if line.strip() != '' and not line.startswith('#') and line is not None]
for line in lines:
install(line)
_res = install(line)
if args.profile:
print_profile(pr, 'Requirements')
+2 -2
View File
@@ -163,7 +163,7 @@ class GalleryFile extends HTMLElement {
this.width = cache.width;
this.height = cache.height;
this.size = cache.size;
this.mtime = new Date(1000 * cache.mtime);
this.mtime = new Date(cache.mtime);
} else {
try {
const json = await delayFetchThumb(this.src);
@@ -175,7 +175,7 @@ class GalleryFile extends HTMLElement {
this.width = json.width;
this.height = json.height;
this.size = json.size;
this.mtime = new Date(1000 * json.mtime);
this.mtime = new Date(json.mtime);
await idbAdd({
hash: this.hash,
folder: this.folder,
+13 -3
View File
@@ -9,6 +9,7 @@ os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
import cv2
import numpy as np
from PIL import Image
from installer import installed, install, log
from modules.control.util import HWC3, resize_image
from .draw import draw_bodypose, draw_handpose, draw_facepose
checked_ok = False
@@ -16,11 +17,17 @@ checked_ok = False
def check_dependencies():
global checked_ok # pylint: disable=global-statement
from installer import installed, install, log
packages = [('openmim', 'openmim'), ('mmengine', 'mmengine'), ('mmcv', 'mmcv'), ('mmpose', 'mmpose'), ('mmdet', 'mmdet')]
packages = [
('openmim==0.3.9', 'openmim'),
('mmengine==0.10.4', 'mmengine'),
('mmcv==2.1.0', 'mmcv'),
('mmpose==1.3.1', 'mmpose'),
('mmdet==3.3.0', 'mmdet'),
]
packages = []
for pkg in packages:
if not installed(pkg[1], reload=True, quiet=True):
install(pkg[0], pkg[1], ignore=False)
install(pkg[0], pkg[1], ignore=False, no_deps=True)
try:
import mmcv # pylint: disable=unused-import
checked_ok = True
@@ -46,6 +53,7 @@ def draw_pose(pose, H, W):
class DWposeDetector:
def __init__(self, det_config=None, det_ckpt=None, pose_config=None, pose_ckpt=None, device="cpu"):
self.pose_estimation = None
if not checked_ok:
if not check_dependencies():
return
@@ -57,6 +65,8 @@ class DWposeDetector:
return self
def __call__(self, input_image, detect_resolution=512, image_resolution=512, output_type="pil", min_confidence=0.3, **kwargs):
if self.pose_estimation is None:
log.error("DWPose: not loaded")
input_image = cv2.cvtColor(np.array(input_image, dtype=np.uint8), cv2.COLOR_RGB2BGR)
input_image = HWC3(input_image)
+21 -1
View File
@@ -86,6 +86,13 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini
if mask is not None and input_type == 0:
input_type = 1 # inpaint always requires control_image
if sampler_index is None:
shared.log.warning('Sampler: invalid')
sampler_index = 0
if hr_sampler_index is None:
shared.log.warning('Sampler: invalid')
hr_sampler_index = 0
p = StableDiffusionProcessingControl(
prompt = prompt,
negative_prompt = negative,
@@ -128,7 +135,20 @@ def control_run(units: List[unit.Unit] = [], inputs: List[Image.Image] = [], ini
outpath_samples=shared.opts.outdir_samples or shared.opts.outdir_control_samples,
outpath_grids=shared.opts.outdir_grids or shared.opts.outdir_control_grids,
)
processing.process_init(p)
# processing.process_init(p)
resize_mode_before = resize_mode_before if resize_name_before != 'None' and inputs is not None and len(inputs) > 0 else 0
# TODO monkey-patch for modernui missing tabs.select event
if selected_scale_tab_before == 0 and resize_name_before != 'None' and scale_by_before != 1 and inputs is not None and len(inputs) > 0:
shared.log.debug('Control: override resize mode=before')
selected_scale_tab_before = 1
if selected_scale_tab_after == 0 and resize_name_after != 'None' and scale_by_after != 1:
shared.log.debug('Control: override resize mode=after')
selected_scale_tab_after = 1
if selected_scale_tab_mask == 0 and resize_name_mask != 'None' and scale_by_mask != 1:
shared.log.debug('Control: override resize mode=mask')
selected_scale_tab_mask = 1
# set initial resolution
if resize_mode_before != 0 or inputs is None or inputs == [None]:
p.width, p.height = width_before, height_before # pylint: disable=attribute-defined-outside-init
-1
View File
@@ -112,7 +112,6 @@ class Script(scripts.Script):
input_images[i] = Image.open(image['name'])
processed = None
processing.process_init(p)
if mode == 'FaceID': # faceid runs as ipadapter in its own pipeline
from modules.face.insightface import get_app
app = get_app('buffalo_l')
+33 -24
View File
@@ -75,7 +75,6 @@ def face_id(
script_callbacks.before_process_callback(p)
with context_hypertile_vae(p), context_hypertile_unet(p), devices.inference_context():
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
ip_ckpt = FACEID_MODELS[model]
folder, filename = os.path.split(ip_ckpt)
basename, _ext = os.path.splitext(filename)
@@ -83,23 +82,13 @@ def face_id(
if model_path is None:
shared.log.error(f"FaceID download failed: model={model} file={ip_ckpt}")
return None
if override:
shared.sd_model.scheduler = diffusers.DDIMScheduler(
num_train_timesteps=1000,
beta_start=0.00085,
beta_end=0.012,
beta_schedule="scaled_linear",
clip_sample=False,
set_alpha_to_one=False,
steps_offset=1,
)
if faceid_model_weights is None or faceid_model_name != model or not cache:
shared.log.debug(f"FaceID load: model={model} file={ip_ckpt}")
faceid_model_weights = torch.load(model_path, map_location="cpu")
else:
shared.log.debug(f"FaceID cached: model={model} file={ip_ckpt}")
if "XL Plus" in model:
if "XL Plus" in model and shared.sd_model_type == 'sd':
image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K"
original_load_ip_adapter = IPAdapterFaceIDPlusXL.load_ip_adapter
IPAdapterFaceIDPlusXL.load_ip_adapter = hijack_load_ip_adapter
@@ -112,7 +101,7 @@ def face_id(
device=devices.device,
torch_dtype=devices.dtype,
)
elif "XL" in model:
elif "XL" in model and shared.sd_model_type == 'sdxl':
original_load_ip_adapter = IPAdapterFaceIDXL.load_ip_adapter
IPAdapterFaceIDXL.load_ip_adapter = hijack_load_ip_adapter
faceid_model = IPAdapterFaceIDXL(
@@ -123,7 +112,7 @@ def face_id(
device=devices.device,
torch_dtype=devices.dtype,
)
elif "Plus" in model:
elif "Plus" in model and shared.sd_model_type == 'sd':
original_load_ip_adapter = IPAdapterFaceIDPlus.load_ip_adapter
IPAdapterFaceIDPlus.load_ip_adapter = hijack_load_ip_adapter
image_encoder_path = "laion/CLIP-ViT-H-14-laion2B-s32B-b79K"
@@ -136,7 +125,7 @@ def face_id(
device=devices.device,
torch_dtype=devices.dtype,
)
elif "Portrait" in model:
elif "Portrait" in model and shared.sd_model_type == 'sd':
original_load_ip_adapter = IPAdapterFaceIDPortrait.load_ip_adapter
IPAdapterFaceIDPortrait.load_ip_adapter = hijack_load_ip_adapter
faceid_model = IPAdapterFaceIDPortrait(
@@ -147,7 +136,7 @@ def face_id(
device=devices.device,
torch_dtype=devices.dtype,
)
else:
elif "Base" in model and shared.sd_model_type == 'sd':
original_load_ip_adapter = IPAdapterFaceID.load_ip_adapter
IPAdapterFaceID.load_ip_adapter = hijack_load_ip_adapter
faceid_model = IPAdapterFaceID(
@@ -158,11 +147,26 @@ def face_id(
device=devices.device,
torch_dtype=devices.dtype,
)
else:
shared.log.error(f'FaceID model not supported: model="{model}" class={shared.sd_model.__class__.__name__}')
return None
if override:
shared.sd_model.scheduler = diffusers.DDIMScheduler(
num_train_timesteps=1000,
beta_start=0.00085,
beta_end=0.012,
beta_schedule="scaled_linear",
clip_sample=False,
set_alpha_to_one=False,
steps_offset=1,
)
shortcut = "v2" in model
faceid_model_name = model
face_embeds = []
face_images = []
for i, source_image in enumerate(source_images):
np_image = cv2.cvtColor(np.array(source_image), cv2.COLOR_RGB2BGR)
faces = app.get(np_image)
@@ -201,19 +205,24 @@ def face_id(
faceid_model.set_scale(scale)
extra_network_data = None
for i in range(p.n_iter):
p.iteration = i
p.prompts = p.all_prompts[i * p.batch_size:(i + 1) * p.batch_size]
p.negative_prompts = p.all_negative_prompts[i * p.batch_size:(i + 1) * p.batch_size]
if p.all_prompts is None or len(p.all_prompts) == 0:
processing.process_init(p)
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
for n in range(p.n_iter):
p.iteration = n
p.prompts = p.all_prompts[n * p.batch_size:(n+1) * p.batch_size]
p.negative_prompts = p.all_negative_prompts[n * p.batch_size:(n+1) * p.batch_size]
p.seeds = p.all_seeds[n * p.batch_size:(n+1) * p.batch_size]
p.subseeds = p.all_subseeds[n * p.batch_size:(n+1) * p.batch_size]
p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts)
p.seeds = p.all_seeds[i * p.batch_size:(i + 1) * p.batch_size]
if not p.disable_extra_networks:
with devices.autocast():
extra_networks.activate(p, extra_network_data)
ip_model_dict.update({
"prompt": p.prompts,
"negative_prompt": p.negative_prompts,
"seed": int(p.seeds[0]),
"prompt": p.prompts[0],
"negative_prompt": p.negative_prompts[0],
"seed": p.seeds[0],
})
debug(f"FaceID: {ip_model_dict}")
res = faceid_model.generate(**ip_model_dict)
+9 -8
View File
@@ -9,14 +9,15 @@ instightface_mp = None
def get_app(mp_name):
global insightface_app, instightface_mp # pylint: disable=global-statement
from installer import installed, install
packages = [
('insightface', 'insightface'),
('git+https://github.com/tencent-ailab/IP-Adapter.git', 'ip_adapter'),
]
for pkg in packages:
if not installed(pkg[1], reload=False, quiet=True):
install(pkg[0], pkg[1], ignore=False)
from installer import install, installed
if not installed('insightface', reload=False, quiet=True):
install('insightface', 'insightface', ignore=False)
install('albumentations==1.4.3', 'albumentations', ignore=False, reinstall=True)
install('pydantic==1.10.15', 'pydantic', ignore=False, reinstall=True)
if not installed('ip_adapter', reload=False, quiet=True):
install('git+https://github.com/tencent-ailab/IP-Adapter.git', 'ip_adapter', ignore=False)
if insightface_app is None or mp_name != instightface_mp:
from insightface.app import FaceAnalysis
import huggingface_hub as hf
+5 -4
View File
@@ -43,8 +43,6 @@ def instant_id(p: processing.StableDiffusionProcessing, app, source_images, stre
controlnet_model = ControlNetModel.from_pretrained(REPO_ID, subfolder="ControlNetModel", torch_dtype=devices.dtype, cache_dir=shared.opts.diffusers_dir)
sd_models.move_model(controlnet_model, devices.device)
processing.process_init(p)
# create new pipeline
orig_pipeline = shared.sd_model # backup current pipeline definition
shared.sd_model = StableDiffusionXLInstantIDPipeline(
@@ -66,6 +64,9 @@ def instant_id(p: processing.StableDiffusionProcessing, app, source_images, stre
shared.sd_model.to(dtype=devices.dtype)
# pipeline specific args
if p.all_prompts is None or len(p.all_prompts) == 0:
processing.process_init(p)
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
orig_prompt_attention = shared.opts.prompt_attention
shared.opts.data['prompt_attention'] = 'Fixed attention' # otherwise need to deal with class_tokens_mask
p.task_args['image_embeds'] = face_embeds[0].shape # placeholder
@@ -73,8 +74,8 @@ def instant_id(p: processing.StableDiffusionProcessing, app, source_images, stre
p.task_args['controlnet_conditioning_scale'] = float(conditioning)
p.task_args['ip_adapter_scale'] = float(strength)
shared.log.debug(f"InstantID args: {p.task_args}")
p.task_args['prompt'] = p.all_prompts[0] # override all logic
p.task_args['negative_prompt'] = p.all_negative_prompts[0]
p.task_args['prompt'] = p.all_prompts[0] if p.all_prompts is not None else p.prompt
p.task_args['negative_prompt'] = p.all_negative_prompts[0] if p.all_negative_prompts is not None else p.negative_prompt
p.task_args['image_embeds'] = face_embeds[0] # overwrite placeholder
# run processing
+4 -1
View File
@@ -17,6 +17,9 @@ def photo_maker(p: processing.StableDiffusionProcessing, input_images, trigger,
return None
# validate prompt
if p.all_prompts is None or len(p.all_prompts) == 0:
processing.process_init(p)
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
trigger_ids = shared.sd_model.tokenizer.encode(trigger) + shared.sd_model.tokenizer_2.encode(trigger)
prompt_ids1 = shared.sd_model.tokenizer.encode(p.all_prompts[0])
prompt_ids2 = shared.sd_model.tokenizer_2.encode(p.all_prompts[0])
@@ -49,7 +52,7 @@ def photo_maker(p: processing.StableDiffusionProcessing, input_images, trigger,
shared.opts.data['prompt_attention'] = 'Fixed attention' # otherwise need to deal with class_tokens_mask
p.task_args['input_id_images'] = input_images
p.task_args['start_merge_step'] = int(start * p.steps)
p.task_args['prompt'] = p.all_prompts[0] # override all logic
p.task_args['prompt'] = p.all_prompts[0] if p.all_prompts is not None else p.prompt
photomaker_path = hf.hf_hub_download(repo_id="TencentARC/PhotoMaker", filename="photomaker-v1.bin", repo_type="model", cache_dir=shared.opts.diffusers_dir)
shared.log.debug(f'PhotoMaker: model={photomaker_path} images={len(input_images)} trigger={trigger} args={p.task_args}')
@@ -217,6 +217,8 @@ def parse_generation_parameters(infotext, no_prompt=False):
params.pop(next(iter(params)))
params_idx = sanitized.find(f'{first_param}:') if first_param else -1
negative_idx = infotext.find("Negative prompt:")
if 'Steps:' in sanitized:
params_idx = max(params_idx, sanitized.find('Steps:'))
if negative_idx == -1: # prompt can be without negative prompt
prompt = infotext[:params_idx] if params_idx > 0 else infotext
+3 -2
View File
@@ -231,7 +231,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type
return im.resize((w, h), resample=Image.Resampling.LANCZOS) # force for mask
scale = max(w / im.width, h / im.height)
if scale > 1.0:
upscalers = [x for x in shared.sd_upscalers if x.name == upscaler_name]
upscalers = [x for x in shared.sd_upscalers if x.name.lower().replace('-', ' ') == upscaler_name.lower().replace('-', ' ')]
if len(upscalers) > 0:
upscaler = upscalers[0]
im = upscaler.scaler.upscale(im, scale, upscaler.data_path)
@@ -240,8 +240,9 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None, output_type
if upscaler is not None:
im = latent(im, w, h, upscaler)
else:
upscaler = upscalers[0]
upscaler = shared.sd_upscalers[0]
shared.log.warning(f"Resize upscaler: invalid={upscaler_name} fallback={upscaler.name}")
shared.log.debug(f"Resize upscaler: available={[u.name for u in shared.sd_upscalers]}")
if im.width != w or im.height != h: # probably downsample after upscaler created larger image
im = im.resize((w, h), resample=Image.Resampling.LANCZOS)
return im
+1
View File
@@ -152,6 +152,7 @@ def img2img(id_task: str, mode: int,
shared.log.debug('Init image not set')
if sampler_index is None:
shared.log.warning('Sampler: invalid')
sampler_index = 0
override_settings = create_override_settings_dict(override_settings_texts)
+3 -3
View File
@@ -223,7 +223,7 @@ def process_init(p: StableDiffusionProcessing):
if p.all_seeds is None:
reset_prompts = True
if type(seed) == list:
p.all_seeds = seed
p.all_seeds = [int(s) for s in seed]
else:
if shared.opts.sequential_seed:
p.all_seeds = [int(seed) + (x if p.subseed_strength == 0 else 0) for x in range(len(p.all_prompts))]
@@ -232,14 +232,14 @@ def process_init(p: StableDiffusionProcessing):
for i in range(len(p.all_prompts)):
seed = get_fixed_seed(p.seed)
p.all_seeds.append(int(seed) + (i if p.subseed_strength == 0 else 0))
if p.all_subseeds is None:
if type(subseed) == list:
p.all_subseeds = subseed
p.all_subseeds = [int(s) for s in subseed]
else:
p.all_subseeds = [int(subseed) + x for x in range(len(p.all_prompts))]
if reset_prompts:
p.all_prompts, p.all_negative_prompts = shared.prompt_styles.apply_styles_to_prompts(p.all_prompts, p.all_negative_prompts, p.styles, p.all_seeds)
def process_images_inner(p: StableDiffusionProcessing) -> Processed:
"""this is the main loop that both txt2img and img2img use; it calls func_init once inside all the scopes and func_sample once per batch"""
if type(p.prompt) == list:
+2 -1
View File
@@ -150,7 +150,8 @@ def set_pipeline_args(p, model, prompts: list, negative_prompts: list, prompts_2
if 'generator' in possible:
args['generator'] = get_generator(p)
if 'latents' in possible and getattr(p, "init_latent", None) is not None:
args['latents'] = p.init_latent
if sd_models.get_diffusers_task(model) == sd_models.DiffusersTaskType.TEXT_2_IMAGE:
args['latents'] = p.init_latent
if 'output_type' in possible:
if not hasattr(model, 'vae'):
args['output_type'] = 'np' # only set latent if model has vae
+3 -3
View File
@@ -103,7 +103,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing):
clip_skip=p.clip_skip,
desc='Base',
)
shared.state.sampling_steps = base_args.get('num_inference_steps', None) or p.steps
shared.state.sampling_steps = base_args.get('prior_num_inference_steps', None) or base_args.get('num_inference_steps', None) or p.steps
p.extra_generation_params['Pipeline'] = shared.sd_model.__class__.__name__
if shared.opts.scheduler_eta is not None and shared.opts.scheduler_eta > 0 and shared.opts.scheduler_eta < 1:
p.extra_generation_params["Sampler Eta"] = shared.opts.scheduler_eta
@@ -211,7 +211,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing):
desc='Hires',
)
shared.state.job = 'HiRes'
shared.state.sampling_steps = hires_args.get('num_inference_steps', None) or p.steps
shared.state.sampling_steps = hires_args.get('prior_num_inference_steps', None) or hires_args.get('num_inference_steps', None) or p.steps
try:
sd_models_compile.check_deepcache(enable=True)
output = shared.sd_model(**hires_args) # pylint: disable=not-callable
@@ -276,7 +276,7 @@ def process_diffusers(p: processing.StableDiffusionProcessing):
clip_skip=p.clip_skip,
desc='Refiner',
)
shared.state.sampling_steps = refiner_args.get('num_inference_steps', None) or p.steps
shared.state.sampling_steps = refiner_args.get('prior_num_inference_steps', None) or refiner_args.get('num_inference_steps', None) or p.steps
try:
if 'requires_aesthetics_score' in shared.sd_refiner.config: # sdxl-model needs false and sdxl-refiner needs true
shared.sd_refiner.register_to_config(requires_aesthetics_score = getattr(shared.sd_refiner, 'tokenizer', None) is None)
+3 -1
View File
@@ -216,7 +216,8 @@ def decode_first_stage(model, x, full_quality=True):
def get_fixed_seed(seed):
if seed is None or seed == '' or seed == -1:
return int(random.randrange(4294967294))
random.seed()
seed = int(random.randrange(4294967294))
return seed
@@ -526,6 +527,7 @@ def update_sampler(p, sd_model, second_pass=False):
if hasattr(sd_model, 'scheduler') and sampler_selection != 'Default':
sampler = sd_samplers.all_samplers_map.get(sampler_selection, None)
if sampler is None:
shared.log.warning(f'Sampler: sampler="{sampler_selection}" not found')
sampler = sd_samplers.all_samplers_map.get("UniPC")
if len(getattr(p, 'timesteps', [])) > 0:
if 'schedulers_use_karras' in shared.opts.data:
-2
View File
@@ -64,8 +64,6 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
"Operations": '; '.join(ops).replace('"', '') if len(p.ops) > 0 else 'none',
}
if 'txt2img' in p.ops:
pass
if shared.backend == shared.Backend.ORIGINAL:
args["Variation seed"] = all_subseeds[index] if p.subseed_strength > 0 else None
args["Variation strength"] = p.subseed_strength if p.subseed_strength > 0 else None
if 'hires' in p.ops or 'upscale' in p.ops:
+1
View File
@@ -230,6 +230,7 @@ def pad_to_same_length(pipe, embeds):
try:
if getattr(pipe, "prior_pipe", None) and getattr(pipe.prior_pipe, "text_encoder", None) is not None: # Cascade
empty_embed = pipe.prior_pipe.encode_prompt(device, 1, 1, False, "")
empty_embed = [torch.zeros(empty_embed[0].shape, device=empty_embed[0].device, dtype=empty_embed[0].dtype)]
else: # SDXL
empty_embed = pipe.encode_prompt("")
except TypeError: # SD1.5
+3 -1
View File
@@ -12,10 +12,11 @@ import os.path
from os import mkdir
from urllib import request
from enum import Enum
import diffusers
import diffusers.loaders.single_file_utils
from rich import progress # pylint: disable=redefined-builtin
import torch
import safetensors.torch
import diffusers
from omegaconf import OmegaConf
from transformers import logging as transformers_logging
from ldm.util import instantiate_from_config
@@ -1056,6 +1057,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
else:
diffusers_load_config['config'] = get_load_config(checkpoint_info.path, model_type, config_type='json')
if hasattr(pipeline, 'from_single_file'):
diffusers.loaders.single_file_utils.CHECKPOINT_KEY_NAMES["clip"] = "cond_stage_model.transformer.text_model.embeddings.position_embedding.weight" # TODO patch for diffusers==0.28.0
diffusers_load_config['use_safetensors'] = True
diffusers_load_config['cache_dir'] = shared.opts.hfcache_dir # use hfcache instead of diffusers dir as this is for config only in case of single-file
if shared.opts.disable_accelerate:
+8 -4
View File
@@ -27,7 +27,7 @@ class CompiledModelState:
deepcache_worker = None
def apply_compile_to_model(sd_model, function, options):
def apply_compile_to_model(sd_model, function, options, op=None):
if "Model" in options:
if hasattr(sd_model, 'unet') and hasattr(sd_model.unet, 'config'):
sd_model.unet = function(sd_model.unet)
@@ -38,7 +38,11 @@ def apply_compile_to_model(sd_model, function, options):
sd_model.decoder = sd_model.decoder_pipe.decoder = function(sd_model.decoder_pipe.decoder)
if hasattr(sd_model, 'prior_pipe') and hasattr(sd_model, 'prior_prior'):
sd_model.prior_prior = None
if op == "nncf" and "StableCascade" in sd_model.__class__.__name__: # fixes dtype errors
backup_clip_txt_pooled_mapper = copy.deepcopy(sd_model.prior_pipe.prior.clip_txt_pooled_mapper)
sd_model.prior_prior = sd_model.prior_pipe.prior = function(sd_model.prior_pipe.prior)
if op == "nncf" and "StableCascade" in sd_model.__class__.__name__:
sd_model.prior_prior.clip_txt_pooled_mapper = sd_model.prior_pipe.prior.clip_txt_pooled_mapper = backup_clip_txt_pooled_mapper
if "VAE" in options:
if hasattr(sd_model, 'vae') and hasattr(sd_model.vae, 'decode'):
sd_model.vae = function(sd_model.vae)
@@ -88,7 +92,7 @@ def ipex_optimize(sd_model):
devices.torch_gc()
return model
sd_model = apply_compile_to_model(sd_model, ipex_optimize_model, shared.opts.ipex_optimize)
sd_model = apply_compile_to_model(sd_model, ipex_optimize_model, shared.opts.ipex_optimize, op="ipex")
t1 = time.time()
shared.log.info(f"IPEX Optimize: time={t1-t0:.2f}")
@@ -120,7 +124,7 @@ def nncf_compress_weights(sd_model):
shared.compiled_model_state = CompiledModelState()
shared.compiled_model_state.is_compiled = True
sd_model = apply_compile_to_model(sd_model, nncf_compress_model, shared.opts.nncf_compress_weights)
sd_model = apply_compile_to_model(sd_model, nncf_compress_model, shared.opts.nncf_compress_weights, op="nncf")
t1 = time.time()
shared.log.info(f"Compress Weights: time={t1-t0:.2f}")
@@ -267,7 +271,7 @@ def compile_torch(sd_model):
except Exception as e:
shared.log.error(f"Torch inductor config error: {e}")
sd_model = apply_compile_to_model(sd_model, torch_compile_model, shared.opts.cuda_compile)
sd_model = apply_compile_to_model(sd_model, torch_compile_model, shared.opts.cuda_compile, op="compile")
setup_logging() # compile messes with logging so reset is needed
if shared.opts.cuda_compile_precompile:
+1
View File
@@ -55,6 +55,7 @@ def create_sampler(name, model):
return model.scheduler
config = find_sampler_config(name)
if config is None or config.constructor is None:
# shared.log.warning(f'Sampler: sampler="{name}" not found')
return None
if shared.backend == shared.Backend.ORIGINAL:
sampler = config.constructor(model)
+8 -8
View File
@@ -46,7 +46,9 @@ config = {
'UniPC': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'predict_x0': 'bh2', 'lower_order_final': True, 'timestep_spacing': 'linspace' },
'DEIS': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "deis", 'solver_type': "logrho", 'lower_order_final': True, 'timestep_spacing': 'linspace' },
'DPM++': { 'solver_order': 2, 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'sigma_min' },
'DPM++ 2M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace' },
'DPM++ 1S': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace', 'solver_order': 1 },
'DPM++ 2M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace', 'solver_order': 2 },
'DPM++ 3M': { 'thresholding': False, 'sample_max_value': 1.0, 'algorithm_type': "dpmsolver++", 'solver_type': "midpoint", 'lower_order_final': True, 'use_karras_sigmas': False, 'final_sigmas_type': 'zero', 'timestep_spacing': 'linspace', 'solver_order': 3 },
'DPM SDE': { 'use_karras_sigmas': False, 'noise_sampler_seed': None, 'timestep_spacing': 'linspace', 'steps_offset': 0 },
'Euler a': { 'rescale_betas_zero_snr': False, 'timestep_spacing': 'linspace' },
'Euler': { 'interpolation_type': "linear", 'use_karras_sigmas': False, 'rescale_betas_zero_snr': False, 'timestep_spacing': 'linspace' },
@@ -77,7 +79,9 @@ samplers_data_diffusers = [
sd_samplers_common.SamplerData('Euler', lambda model: DiffusionSampler('Euler', EulerDiscreteScheduler, model), [], {}),
sd_samplers_common.SamplerData('Euler a', lambda model: DiffusionSampler('Euler a', EulerAncestralDiscreteScheduler, model), [], {}),
sd_samplers_common.SamplerData('DPM++', lambda model: DiffusionSampler('DPM++', DPMSolverSinglestepScheduler, model), [], {}),
sd_samplers_common.SamplerData('DPM++ 1S', lambda model: DiffusionSampler('DPM++ 1S', DPMSolverMultistepScheduler, model), [], {}),
sd_samplers_common.SamplerData('DPM++ 2M', lambda model: DiffusionSampler('DPM++ 2M', DPMSolverMultistepScheduler, model), [], {}),
sd_samplers_common.SamplerData('DPM++ 3M', lambda model: DiffusionSampler('DPM++ 3M', DPMSolverMultistepScheduler, model), [], {}),
sd_samplers_common.SamplerData('DPM SDE', lambda model: DiffusionSampler('DPM SDE', DPMSolverSDEScheduler, model), [], {}),
sd_samplers_common.SamplerData('PNDM', lambda model: DiffusionSampler('PNDM', PNDMScheduler, model), [], {}),
@@ -107,10 +111,6 @@ class DiffusionSampler:
return
for key, value in config.get('All', {}).items(): # apply global defaults
self.config[key] = value
# shared.log.debug(f'Sampler: name={name} type=all config={self.config}')
for key, value in config.get(name, {}).items(): # apply diffusers per-scheduler defaults
self.config[key] = value
# shared.log.debug(f'Sampler: name={name} type=scheduler config={self.config}')
if hasattr(model.scheduler, 'scheduler_config'): # find model defaults
orig_config = model.scheduler.scheduler_config
else:
@@ -118,11 +118,11 @@ class DiffusionSampler:
for key, value in orig_config.items(): # apply model defaults
if key in self.config:
self.config[key] = value
# shared.log.debug(f'Sampler: name={name} type=model config={self.config}')
for key, value in config.get(name, {}).items(): # apply diffusers per-scheduler defaults
self.config[key] = value
for key, value in kwargs.items(): # apply user args, if any
if key in self.config:
self.config[key] = value
# shared.log.debug(f'Sampler: name={name} type=user config={self.config}')
# finally apply user preferences
if shared.opts.schedulers_prediction_type != 'default':
self.config['prediction_type'] = shared.opts.schedulers_prediction_type
@@ -136,7 +136,7 @@ class DiffusionSampler:
self.config['thresholding'] = shared.opts.schedulers_use_thresholding
if 'lower_order_final' in self.config:
self.config['lower_order_final'] = shared.opts.schedulers_use_loworder
if 'solver_order' in self.config:
if 'solver_order' in self.config and 'DPM' not in name:
self.config['solver_order'] = shared.opts.schedulers_solver_order
if 'predict_x0' in self.config:
self.config['predict_x0'] = shared.opts.uni_pc_variant
+1 -1
View File
@@ -754,7 +754,7 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), {
"facehires_max_size": OptionInfo(0, "Max face size", gr.Slider, {"minimum": 0, "maximum": 1024, "step": 1}),
"facehires_padding": OptionInfo(10, "Face padding", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
"face_restoration_unload": OptionInfo(False, "Move model to CPU when complete"),
"facehires_strength": OptionInfo(0.0, "Face HiRes strength", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
"facehires_strength": OptionInfo(0.0, "Face restore strength", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
"code_former_weight": OptionInfo(0.2, "CodeFormer weight parameter", gr.Slider, {"minimum": 0, "maximum": 1, "step": 0.01}),
"postprocessing_sep_upscalers": OptionInfo("<h2>Upscaling</h2>", "", gr.HTML),
+5 -1
View File
@@ -81,8 +81,10 @@ def apply_file_wildcards(prompt, replaced = [], not_found = [], recursion=0, see
def apply_wildcards_to_prompt(prompt, all_wildcards, seed=-1, silent=False):
if len(prompt) == 0:
return prompt
if seed > 0:
old_state = None
if seed > 0 and len(all_wildcards) > 0:
random.seed(seed)
old_state = random.getstate()
replaced = {}
t0 = time.time()
for style_wildcards in all_wildcards:
@@ -104,6 +106,8 @@ def apply_wildcards_to_prompt(prompt, all_wildcards, seed=-1, silent=False):
shared.log.debug(f'Wildcards applied: {replaced} path="{shared.opts.wildcards_dir}" type=style time={t1-t0:.2f}')
if (len(replaced_file) > 0 or len(not_found) > 0) and not silent:
shared.log.debug(f'Wildcards applied: {replaced_file} missing: {not_found} path="{shared.opts.wildcards_dir}" type=file time={t2-t2:.2f} ')
if old_state is not None:
random.setstate(old_state)
return prompt
@@ -140,7 +140,7 @@ class EmbeddingDatabase:
def get_expected_shape(self):
if shared.backend == shared.Backend.DIFFUSERS:
return 0
if shared.sd_loaded:
if not shared.sd_loaded:
shared.log.error('Model not loaded')
return 0
vec = shared.sd_model.cond_stage_model.encode_embedding_init_text(",", 1)
+2
View File
@@ -32,8 +32,10 @@ def txt2img(id_task,
override_settings = create_override_settings_dict(override_settings_texts)
if sampler_index is None:
shared.log.warning('Sampler: invalid')
sampler_index = 0
if hr_sampler_index is None:
shared.log.warning('Sampler: invalid')
hr_sampler_index = 0
p = processing.StableDiffusionProcessingTxt2Img(
+15 -9
View File
@@ -348,31 +348,37 @@ def create_override_inputs(tab): # pylint: disable=unused-argument
return override_settings
def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, is_subseed):
def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, is_subseed, subseed_strength=None):
""" Connects a 'reuse (sub)seed' button's click event so that it copies last used
(sub)seed value from generation info the to the seed field. If copying subseed and subseed strength
was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
def copy_seed(gen_info_string: str, index: int):
res = -1
restore_seed = -1
restore_strength = -1
try:
gen_info = json.loads(gen_info_string)
shared.log.debug(f'Reuse: info={gen_info}')
index -= gen_info.get('index_of_first_image', 0)
index = int(index)
if is_subseed and gen_info.get('subseed_strength', 0) > 0:
if is_subseed:
all_subseeds = gen_info.get('all_subseeds', [-1])
res = all_subseeds[index if 0 <= index < len(all_subseeds) else 0]
restore_seed = all_subseeds[index if 0 <= index < len(all_subseeds) else 0]
restore_strength = gen_info.get('subseed_strength', 0)
else:
all_seeds = gen_info.get('all_seeds', [-1])
res = all_seeds[index if 0 <= index < len(all_seeds) else 0]
restore_seed = all_seeds[index if 0 <= index < len(all_seeds) else 0]
except json.decoder.JSONDecodeError:
if gen_info_string != '':
shared.log.error(f"Error parsing JSON generation info: {gen_info_string}")
return [res, gr_show(False)]
if is_subseed is not None:
return [restore_seed, gr_show(False), restore_strength]
else:
return [restore_seed, gr_show(False)]
dummy_component = gr.Number(visible=False, value=0)
reuse_seed.click(fn=copy_seed, _js="(x, y) => [x, selected_gallery_index()]", show_progress=False, inputs=[generation_info, dummy_component], outputs=[seed, dummy_component])
if subseed_strength is None:
reuse_seed.click(fn=copy_seed, _js="(x, y) => [x, selected_gallery_index()]", show_progress=False, inputs=[generation_info, dummy_component], outputs=[seed, dummy_component])
else:
reuse_seed.click(fn=copy_seed, _js="(x, y) => [x, selected_gallery_index()]", show_progress=False, inputs=[generation_info, dummy_component], outputs=[seed, dummy_component, subseed_strength])
def update_token_counter(text, steps):
+2 -1
View File
@@ -1,12 +1,13 @@
import os
from datetime import datetime
from urllib.parse import unquote
import gradio as gr
from PIL import Image
from modules import shared, ui_symbols, ui_common, images, ui_control_helpers
from modules.ui_components import ToolButton
def read_media(fn):
fn = unquote(fn).replace('%3A', ':')
if not os.path.isfile(fn):
shared.log.error(f'Gallery not found: file="{fn}"')
return [[], None, '', '', f'Media not found: {fn}']
+1 -1
View File
@@ -157,7 +157,7 @@ def create_ui():
img2img_gallery, img2img_generation_info, img2img_html_info, _img2img_html_info_formatted, img2img_html_log = ui_common.create_output_panel("img2img", prompt=img2img_prompt)
ui_common.connect_reuse_seed(seed, reuse_seed, img2img_generation_info, is_subseed=False)
ui_common.connect_reuse_seed(subseed, reuse_subseed, img2img_generation_info, is_subseed=True)
ui_common.connect_reuse_seed(subseed, reuse_subseed, img2img_generation_info, is_subseed=True, subseed_strength=subseed_strength)
img2img_prompt_img.change(fn=modules.images.image_data, inputs=[img2img_prompt_img], outputs=[img2img_prompt, img2img_prompt_img])
dummy_component1 = gr.Textbox(visible=False, value='dummy')
+5 -5
View File
@@ -136,7 +136,7 @@ def create_seed_inputs(tab, reuse_visible=True):
with gr.Row(visible=False):
seed_resize_from_w = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from width", value=0, elem_id=f"{tab}_seed_resize_from_w")
seed_resize_from_h = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from height", value=0, elem_id=f"{tab}_seed_resize_from_h")
random_seed.click(fn=lambda: [-1, -1], show_progress=False, inputs=[], outputs=[seed, subseed])
random_seed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[seed])
random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed])
return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w
@@ -316,10 +316,10 @@ def create_resize_inputs(tab, images, accordion=True, latent=False):
with gr.Row(visible=True) as _resize_group:
with gr.Column(elem_id=f"{tab}_column_size"):
selected_scale_tab = gr.State(value=0) # pylint: disable=abstract-class-instantiated
with gr.Tabs():
with gr.Tab(label="Fixed") as tab_scale_to:
with gr.Tabs(elem_id=f"{tab}_scale_tabs"):
with gr.Tab(label="Fixed", elem_id=f"{tab}_scale_tab_fixed") as tab_scale_to:
with gr.Row():
with gr.Column(elem_id=f"{tab}_column_size"):
with gr.Column(elem_id=f"{tab}_column_size_fixed"):
with gr.Row():
width = gr.Slider(minimum=64, maximum=8192, step=8, label="Width", value=512, elem_id=f"{tab}_width")
height = gr.Slider(minimum=64, maximum=8192, step=8, label="Height", value=512, elem_id=f"{tab}_height")
@@ -332,7 +332,7 @@ def create_resize_inputs(tab, images, accordion=True, latent=False):
detect_image_size_btn = ToolButton(value=ui_symbols.detect, elem_id=f"{tab}_detect_image_size_btn")
el = tab.split('_')[0]
detect_image_size_btn.click(fn=lambda w, h, _: (w or gr.update(), h or gr.update()), _js=f'currentImageResolution{el}', inputs=[dummy_component, dummy_component, dummy_component], outputs=[width, height], show_progress=False)
with gr.Tab(label="Scale") as tab_scale_by:
with gr.Tab(label="Scale", elem_id=f"{tab}_scale_tab_scale") as tab_scale_by:
scale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label="Scale", value=1.0, elem_id=f"{tab}_scale")
for component in images:
component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False)
+1 -1
View File
@@ -56,7 +56,7 @@ def create_ui():
txt2img_gallery, txt2img_generation_info, txt2img_html_info, _txt2img_html_info_formatted, txt2img_html_log = ui_common.create_output_panel("txt2img", preview=True, prompt=txt2img_prompt)
ui_common.connect_reuse_seed(seed, reuse_seed, txt2img_generation_info, is_subseed=False)
ui_common.connect_reuse_seed(subseed, reuse_subseed, txt2img_generation_info, is_subseed=True)
ui_common.connect_reuse_seed(subseed, reuse_subseed, txt2img_generation_info, is_subseed=True, subseed_strength=subseed_strength)
dummy_component = gr.Textbox(visible=False, value='dummy')
txt2img_args = [
+4 -3
View File
@@ -5,6 +5,7 @@ import torch
from torch._prims_common import DeviceLikeType
import onnxruntime as ort
from modules import shared, devices
from modules.onnx_impl.execution_providers import available_execution_providers, ExecutionProvider
PLATFORM = sys.platform
@@ -61,10 +62,10 @@ def initialize_zluda():
shared.opts.sdp_options = ['Math attention']
# ONNX Runtime is not supported
ort.capi._pybind_state.get_available_providers = lambda: [v for v in ort.get_available_providers() if v != 'CUDAExecutionProvider'] # pylint: disable=protected-access
ort.capi._pybind_state.get_available_providers = lambda: [v for v in available_execution_providers if v != ExecutionProvider.CUDA] # pylint: disable=protected-access
ort.get_available_providers = ort.capi._pybind_state.get_available_providers # pylint: disable=protected-access
if shared.opts.onnx_execution_provider == 'CUDAExecutionProvider':
shared.opts.onnx_execution_provider = 'CPUExecutionProvider'
if shared.opts.onnx_execution_provider == ExecutionProvider.CUDA:
shared.opts.onnx_execution_provider = ExecutionProvider.CPU
devices.device_codeformer = devices.cpu
+1 -1
View File
@@ -32,7 +32,7 @@ class FaceRestorerYolo(FaceRestoration):
def dependencies(self):
import installer
installer.install('ultralytics', ignore=False)
installer.install('ultralytics', ignore=True)
def predict(
self,
+1
View File
@@ -554,6 +554,7 @@ class Script(scripts.Script):
processing.fix_seed(p)
if not shared.opts.return_grid:
p.batch_size = 1
def process_axis(opt, vals, vals_dropdown):
if opt.label == 'Nothing':
return [0]
+1 -1
Submodule wiki updated: f17d12033e...709796f975