mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 09:14:35 +02:00
+21
-4
@@ -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!
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
*What else?*
|
||||
|
||||
#### New built-in features
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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*
|
||||
|
||||
Submodule extensions-builtin/sdnext-modernui updated: c79be7ffeb...0b56557c15
+18
-17
@@ -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')
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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):
|
||||
|
||||
@@ -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}']
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user