mirror of
https://github.com/vladmandic/automatic
synced 2026-09-18 16:54:33 +02:00
Merge branch 'master' of https://github.com/vladmandic/automatic into notification-sounds
This commit is contained in:
@@ -24,15 +24,12 @@ jobs:
|
||||
python-version: 3.10.6
|
||||
cache: pip
|
||||
cache-dependency-path: requirements.txt
|
||||
- name: Install PyLint
|
||||
run: |
|
||||
- name: Test Startup
|
||||
run: |
|
||||
export COMMANDLINE_ARGS="--debug --test"
|
||||
python launch.py
|
||||
- name: Linting
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pylint
|
||||
# This lets PyLint check to see if it can resolve imports
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
export COMMANDLINE_ARGS="--skip-torch-cuda-test --exit"
|
||||
python launch.py
|
||||
- name: Analysing the code with pylint
|
||||
run: |
|
||||
pylint $(git ls-files '*.py')
|
||||
|
||||
@@ -11,6 +11,7 @@ fail-under=10
|
||||
ignore=CVS
|
||||
ignore-paths=^repositories/.*$,
|
||||
^extensions/.*$,
|
||||
^extensions-builtin/.*$,
|
||||
/usr/lib/.*$,
|
||||
ignore-patterns=
|
||||
ignored-modules=
|
||||
@@ -141,6 +142,8 @@ disable=raw-checker-failed,
|
||||
consider-using-dict-items,
|
||||
dangerous-default-value,
|
||||
unnecessary-dunder-call,
|
||||
invalid-name,
|
||||
R0801,
|
||||
enable=c-extension-no-member
|
||||
|
||||
[METHOD_ARGS]
|
||||
|
||||
@@ -4,21 +4,22 @@
|
||||
|
||||
Stuff to be fixed...
|
||||
|
||||
- Run VAE with hires at 1280
|
||||
- Transformers version
|
||||
- Move Restart Server from WebUI to Launch and reload modules
|
||||
- Follow-up on `p.script_args`
|
||||
- Mdularize `cli` scripts
|
||||
|
||||
## Features
|
||||
|
||||
Stuff to be added...
|
||||
|
||||
- Update README
|
||||
- Update `README.md`
|
||||
- Add Gradio theme maker
|
||||
- Create new GitHub hooks/actions for CI/CD
|
||||
- Redo Extensions tab: see <https://vladmandic.github.io/sd-extension-manager/pages/extensions.html>
|
||||
- Redo Extensions tab: <https://vladmandic.github.io/sd-extension-manager/pages/extensions.html>
|
||||
- Stream-load models as option for slow storage
|
||||
- Auto-test `torch.layer_norm` for FP16
|
||||
- Monitor file changes by misbehaving extensions
|
||||
- Kitchen theme: <https://github.com/canisminor1990/sd-webui-kitchen-theme>
|
||||
- Lightbox improvements
|
||||
|
||||
## Investigate
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import io
|
||||
import json
|
||||
import time
|
||||
from PIL import Image
|
||||
import sdapi as sdapi
|
||||
import sdapi
|
||||
from util import Map, log
|
||||
|
||||
|
||||
|
||||
Submodule extensions-builtin/a1111-sd-webui-lycoris updated: ce584a0ff8...4d74a7b889
Submodule extensions-builtin/sd-extension-system-info updated: cc86ce8887...70ab5cf312
Submodule extensions-builtin/sd-webui-controlnet updated: 2bc4400011...070d08f752
Submodule extensions-builtin/stable-diffusion-webui-images-browser updated: 2c988c08c7...84cb617498
@@ -1,12 +1,10 @@
|
||||
<div class='card' style={style} onclick={card_clicked}>
|
||||
{metadata_button}
|
||||
|
||||
<div class='actions'>
|
||||
<div class='additional'>
|
||||
<ul>
|
||||
<li><a href="#" title="replace preview image with currently selected in gallery" onclick={save_card_preview}>replace preview</a></li>
|
||||
<li><a href="#" title="replace preview description with currently selected in gallery" onclick={save_card_description}>replace description</a></li>
|
||||
<li><a href="#" title="read description" onclick={read_card_description}>read description</a></li>
|
||||
<li><a href="#" title="set preview image with current selection" onclick={save_card_preview}>Replace preview</a></li>
|
||||
<li><a href="#" title="read description" onclick={read_card_description}>Description</a> <a href="#" title="[replace]" onclick={save_card_description}>[Replace]</a></li>
|
||||
<li><a href="#" title="read metadata" onclick={read_card_metadata}>Metadata</a></li>
|
||||
</ul>
|
||||
<span style="display:none" class='search_term'>{search_term}</span>
|
||||
</div>
|
||||
@@ -14,4 +12,3 @@
|
||||
<span class='description'>{description}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<div class='card' style={style} onclick={card_clicked}>
|
||||
<div class='actions'>
|
||||
<div class='additional'>
|
||||
<ul>
|
||||
<li><a href="#" title="set preview image with current selection" onclick={save_card_preview}>Replace preview</a></li>
|
||||
<li><a href="#" title="read description" onclick={read_card_description}>Description</a> <a href="#" title="[replace]" onclick={save_card_description}>[Replace]</a></li>
|
||||
</ul>
|
||||
<span style="display:none" class='search_term'>{search_term}</span>
|
||||
</div>
|
||||
<span class='name'>{name}</span>
|
||||
<span class='description'>{description}</span>
|
||||
</div>
|
||||
</div>
|
||||
+62
-36
@@ -4,14 +4,14 @@ import json
|
||||
import time
|
||||
import shutil
|
||||
import logging
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
try:
|
||||
from modules.cmd_args import parser
|
||||
except:
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="Stable Diffusion", formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=55,indent_increment=2,width=200))
|
||||
|
||||
parser = argparse.ArgumentParser(description="Stable Diffusion", conflict_handler='resolve', formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=55, indent_increment=2, width=200))
|
||||
|
||||
class Dot(dict): # dot notation access to dictionary attributes
|
||||
__getattr__ = dict.get
|
||||
@@ -20,7 +20,7 @@ class Dot(dict): # dot notation access to dictionary attributes
|
||||
|
||||
|
||||
log = logging.getLogger("sd")
|
||||
args = Dot({ 'debug': False, 'upgrade': False, 'noupdate': False, 'skip-extensions': False, 'skip-requirements': False, 'reset': False })
|
||||
args = Dot({ 'debug': False, 'upgrade': False, 'no_directml': False, 'skip_update': False, 'skip_extensions': False, 'skip_requirements': False, 'skip_git': False, 'reset': False, 'use_ipex': False, 'experimental': False, 'test': False })
|
||||
quick_allowed = True
|
||||
errors = 0
|
||||
opts = {}
|
||||
@@ -90,6 +90,8 @@ def installed(package, friendly: str = None):
|
||||
|
||||
# install package using pip if not already installed
|
||||
def install(package, friendly: str = None, ignore: bool = False):
|
||||
if args.use_ipex and package == "pytorch_lightning==1.9.4":
|
||||
package = "pytorch_lightning==1.8.6"
|
||||
def pip(arg: str):
|
||||
arg = arg.replace('>=', '==')
|
||||
log.info(f'Installing package: {arg.replace("install", "").replace("--upgrade", "").replace("--no-deps", "").replace(" ", " ").strip()}')
|
||||
@@ -168,7 +170,6 @@ def clone(url, folder, commithash=None):
|
||||
|
||||
# check python version
|
||||
def check_python():
|
||||
import platform
|
||||
supported_minors = [9, 10]
|
||||
if args.experimental:
|
||||
supported_minors.append(11)
|
||||
@@ -188,26 +189,38 @@ def check_python():
|
||||
# check torch version
|
||||
def check_torch():
|
||||
if shutil.which('nvidia-smi') is not None or os.path.exists(os.path.join(os.environ.get('SystemRoot') or r'C:\Windows', 'System32', 'nvidia-smi.exe')):
|
||||
log.info('nVidia toolkit detected')
|
||||
log.info('nVidia CUDA toolkit detected')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchaudio torchvision --index-url https://download.pytorch.org/whl/cu118')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.17' if opts.get('cross_attention_optimization', '') == 'xFormers' else 'none')
|
||||
elif shutil.which('rocminfo') is not None or os.path.exists('/opt/rocm/bin/rocminfo'):
|
||||
log.info('AMD toolkit detected')
|
||||
log.info('AMD ROCm toolkit detected')
|
||||
os.environ.setdefault('HSA_OVERRIDE_GFX_VERSION', '10.3.0')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchvision torchaudio --index-url https://download.pytorch.org/whl/rocm5.4.2')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
else:
|
||||
log.info('Using CPU-only Torch')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchaudio torchvision')
|
||||
elif shutil.which('sycl-ls') is not None or os.path.exists('/opt/intel/oneapi') or args.use_ipex:
|
||||
log.info('Intel OneAPI Toolkit detected')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch==1.13.0a0+git6c9b55e torchvision==0.14.1a0 intel_extension_for_pytorch==1.13.120+xpu -f https://developer.intel.com/ipex-whl-stable-xpu')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
else:
|
||||
machine = platform.machine()
|
||||
if 'arm' not in machine and 'aarch' not in machine and not args.no_directml: # torch-directml is available on AMD64
|
||||
log.info('Using DirectML Backend')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.0 torchvision torch-directml')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
else:
|
||||
log.info('Using CPU-only Torch')
|
||||
torch_command = os.environ.get('TORCH_COMMAND', 'torch torchaudio torchvision')
|
||||
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
|
||||
if 'torch' in torch_command:
|
||||
install(torch_command, 'torch torchvision torchaudio')
|
||||
try:
|
||||
import torch
|
||||
log.info(f'Torch {torch.__version__}')
|
||||
if not torch.cuda.is_available():
|
||||
log.warning("Torch repoorts CUDA not available")
|
||||
else:
|
||||
if args.use_ipex:
|
||||
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
|
||||
log.info(f'Torch backend: Intel OneAPI {torch.__version__}')
|
||||
log.info(f'Torch detected GPU: {torch.xpu.get_device_name("xpu")} VRAM {round(torch.xpu.get_device_properties("xpu").total_memory / 1024 / 1024)}')
|
||||
elif torch.cuda.is_available():
|
||||
if torch.version.cuda:
|
||||
log.info(f'Torch backend: nVidia CUDA {torch.version.cuda} cuDNN {torch.backends.cudnn.version() if torch.backends.cudnn.is_available() else "N/A"}')
|
||||
elif torch.version.hip:
|
||||
@@ -216,6 +229,17 @@ def check_torch():
|
||||
log.warning('Unknown Torch backend')
|
||||
for device in [torch.cuda.device(i) for i in range(torch.cuda.device_count())]:
|
||||
log.info(f'Torch detected GPU: {torch.cuda.get_device_name(device)} VRAM {round(torch.cuda.get_device_properties(device).total_memory / 1024 / 1024)} Arch {torch.cuda.get_device_capability(device)} Cores {torch.cuda.get_device_properties(device).multi_processor_count}')
|
||||
else:
|
||||
try:
|
||||
import torch_directml # pylint: disable=import-error
|
||||
import pkg_resources
|
||||
version = pkg_resources.get_distribution("torch-directml")
|
||||
log.info(f'Torch backend: DirectML ({version})')
|
||||
for i in range(0, torch_directml.device_count()):
|
||||
log.info(f'Torch detected GPU: {torch_directml.device_name(i)}')
|
||||
log.info(f'DirectML default device: {torch_directml.device_name(torch_directml.default_device())}')
|
||||
except:
|
||||
log.warning("Torch repoorts CUDA not available")
|
||||
except Exception as e:
|
||||
log.error(f'Could not load torch: {e}')
|
||||
exit(1)
|
||||
@@ -229,6 +253,8 @@ def check_torch():
|
||||
install(tensorflow_package, 'tensorflow', ignore=True)
|
||||
except Exception as e:
|
||||
log.debug(f'Cannot install tensorflow package: {e}')
|
||||
if opts.get('cuda_compile_mode', '') == 'hidet':
|
||||
install('hidet', 'hidet')
|
||||
|
||||
|
||||
# install required packages
|
||||
@@ -306,7 +332,7 @@ def install_extensions():
|
||||
extensions = list_extensions(folder)
|
||||
log.info(f'Extensions enabled: {extensions}')
|
||||
for ext in extensions:
|
||||
if not args.noupdate:
|
||||
if not args.skip_update:
|
||||
try:
|
||||
update(os.path.join(folder, ext))
|
||||
except:
|
||||
@@ -330,7 +356,7 @@ def install_submodules():
|
||||
git('checkout master')
|
||||
log.info('Continuing setup')
|
||||
txt = git('submodule --quiet update --init --recursive')
|
||||
if not args.noupdate:
|
||||
if not args.skip_update:
|
||||
log.info('Updating submodules')
|
||||
submodules = git('submodule').splitlines()
|
||||
for submodule in submodules:
|
||||
@@ -341,15 +367,11 @@ def install_submodules():
|
||||
log.error(f'Error updating submodule: {submodule}')
|
||||
|
||||
|
||||
def ensure_package(pkg):
|
||||
try:
|
||||
import pkg # type: ignore
|
||||
except ImportError:
|
||||
install(pkg)
|
||||
|
||||
|
||||
def ensure_base_requirements():
|
||||
ensure_package('rich')
|
||||
try:
|
||||
import rich # pylint: disable=unused-import
|
||||
except ImportError:
|
||||
install('rich', 'rich')
|
||||
|
||||
|
||||
def install_requirements():
|
||||
@@ -445,7 +467,7 @@ def check_version():
|
||||
|
||||
|
||||
def update_wiki():
|
||||
if not args.noupdate:
|
||||
if not args.skip_update:
|
||||
log.info('Updating Wiki')
|
||||
try:
|
||||
update(os.path.join(os.path.dirname(__file__), "wiki"))
|
||||
@@ -486,19 +508,23 @@ def check_timestamp():
|
||||
return ok
|
||||
|
||||
|
||||
def add_args():
|
||||
group = parser.add_argument_group('Setup options')
|
||||
group.add_argument('--debug', default = False, action='store_true', help = "Run installer with debug logging, default: %(default)s")
|
||||
group.add_argument('--reset', default = False, action='store_true', help = "Reset main repository to latest version, default: %(default)s")
|
||||
group.add_argument('--upgrade', default = False, action='store_true', help = "Upgrade main repository to latest version, default: %(default)s")
|
||||
group.add_argument("--use-ipex", action='store_true', help="Use Intel OneAPI XPU backend, default: %(default)s", default=False)
|
||||
group.add_argument('--no-directml', default = False, action='store_true', help = "Use CPU instead of DirectML if no compatible GPU is detected, default: %(default)s")
|
||||
group.add_argument('--skip-update', default = False, action='store_true', help = "Skip update of extensions and submodules, default: %(default)s")
|
||||
group.add_argument('--skip-requirements', default = False, action='store_true', help = "Skips checking and installing requirements, default: %(default)s")
|
||||
group.add_argument('--skip-extensions', default = False, action='store_true', help = "Skips running individual extension installers, default: %(default)s")
|
||||
group.add_argument('--skip-git', default = False, action='store_true', help = "Skips running all GIT operations, default: %(default)s")
|
||||
group.add_argument('--experimental', default = False, action='store_true', help = "Allow unsupported versions of libraries, default: %(default)s")
|
||||
group.add_argument('--test', default = False, action='store_true', help = "Run test only, default: %(default)s")
|
||||
|
||||
|
||||
def parse_args():
|
||||
# command line args
|
||||
# parser = argparse.ArgumentParser(description = 'Setup for SD WebUI')
|
||||
if vars(parser)['_option_string_actions'].get('--debug', None) is not None:
|
||||
return
|
||||
parser.add_argument('--debug', default = False, action='store_true', help = "Run installer with debug logging, default: %(default)s")
|
||||
parser.add_argument('--reset', default = False, action='store_true', help = "Reset main repository to latest version, default: %(default)s")
|
||||
parser.add_argument('--upgrade', default = False, action='store_true', help = "Upgrade main repository to latest version, default: %(default)s")
|
||||
parser.add_argument('--noupdate', default = False, action='store_true', help = "Skip update of extensions and submodules, default: %(default)s")
|
||||
parser.add_argument('--skip-requirements', default = False, action='store_true', help = "Skips checking and installing requirements, default: %(default)s")
|
||||
parser.add_argument('--skip-extensions', default = False, action='store_true', help = "Skips running individual extension installers, default: %(default)s")
|
||||
parser.add_argument('--skip-git', default = False, action='store_true', help = "Skips running all GIT operations, default: %(default)s")
|
||||
parser.add_argument('--experimental', default = False, action='store_true', help = "Allow unsupported versions of libraries, default: %(default)s")
|
||||
global args # pylint: disable=global-statement
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -532,8 +558,8 @@ def git_reset():
|
||||
|
||||
def read_options():
|
||||
global opts # pylint: disable=global-statement
|
||||
if os.path.isfile(args.ui_settings_file):
|
||||
with open(args.ui_settings_file, "r", encoding="utf8") as file:
|
||||
if os.path.isfile(args.config):
|
||||
with open(args.config, "r", encoding="utf8") as file:
|
||||
opts = json.load(file)
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
.py-6 { padding-bottom: 0; }
|
||||
.rounded-lg { border-radius: 0; }
|
||||
.tabs { background-color: black; }
|
||||
.gradio-button.tool { border-radius: 0; height: 2em; }
|
||||
.gradio-button.tool { border-radius: 0; height: 2.0em; }
|
||||
.block.token-counter span { background-color: #222 !important; box-shadow: 2px 2px 2px #111; border: none !important; border-radius: 0; font-size: 0.8rem; }
|
||||
.tab-nav { zoom: 130%; margin-bottom: 16px; border-bottom: 2px solid #CE6400 !important; padding-bottom: 2px; }
|
||||
.label-wrap { margin: 16px 0px 8px 0px; }
|
||||
@@ -80,7 +80,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
#lightboxModal { background-color: rgba(20, 20, 20, 0.8) }
|
||||
#quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; }
|
||||
#quicksettings > div, #quicksettings > fieldset { min-width: 26em; max-width: 26em; line-height: 2em; }
|
||||
#refresh_sd_model_checkpoint { height: 40px; margin-left: -14px; background: #333333; box-shadow: none; }
|
||||
#refresh_sd_model_checkpoint { height: 48px; margin-left: -14px; background: #333333; box-shadow: none; }
|
||||
#refresh_txt2img_styles, #refresh_img2img_styles, #open_folder_txt2img, #open_folder_img2img, #open_folder_extras, #footer, #style_pos_col, #style_neg_col, #roll_col, #extras_upscaler_2, #extras_upscaler_2_visibility, #txt2img_res_switch_btn, #img2img_res_switch_btn, #txt2img_seed_resize_from_w, #txt2img_seed_resize_from_h, #txt2img_tiling { display: none; }
|
||||
#save-animation { border-radius: 0 !important; margin-bottom: 16px; background-color: #111111; }
|
||||
#script_list { padding: 4px; margin-top: 20px; margin-bottom: 20px; }
|
||||
@@ -103,6 +103,8 @@ svg.feather.feather-image, .feather .feather-image { display: none }
|
||||
#txt2img_tools, #img2img_tools { margin-top: 54px; scale: 120%; margin-left: 26px; }
|
||||
#txtimg_hr_finalres { max-width: 200px; }
|
||||
#pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) }
|
||||
#txt2img_extra_refresh, #txt2img_extra_close { height: 1.7em; }
|
||||
#extras_generate { margin-top: 8px; }
|
||||
|
||||
/* custom elements overrides */
|
||||
#steps-animation, #controlnet { border-width: 0; }
|
||||
|
||||
+16
-60
@@ -1,22 +1,17 @@
|
||||
|
||||
function setupExtraNetworksForTab(tabname){
|
||||
gradioApp().querySelector('#'+tabname+'_extra_tabs').classList.add('extra-networks')
|
||||
|
||||
var tabs = gradioApp().querySelector('#'+tabname+'_extra_tabs > div')
|
||||
var search = gradioApp().querySelector('#'+tabname+'_extra_search textarea')
|
||||
var refresh = gradioApp().getElementById(tabname+'_extra_refresh')
|
||||
var descriptInput = gradioApp().getElementById(tabname+ '_description_input')
|
||||
var close = gradioApp().getElementById(tabname+'_extra_close')
|
||||
|
||||
search.classList.add('search')
|
||||
tabs.appendChild(search)
|
||||
tabs.appendChild(refresh)
|
||||
tabs.appendChild(close)
|
||||
tabs.appendChild(descriptInput)
|
||||
|
||||
search.addEventListener("input", function(evt){
|
||||
searchTerm = search.value.toLowerCase()
|
||||
|
||||
gradioApp().querySelectorAll('#'+tabname+'_extra_tabs div.card').forEach(function(elem){
|
||||
text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase()
|
||||
elem.style.display = text.indexOf(searchTerm) == -1 ? "none" : ""
|
||||
@@ -29,19 +24,13 @@ var activePromptTextarea = {};
|
||||
function setupExtraNetworks(){
|
||||
setupExtraNetworksForTab('txt2img')
|
||||
setupExtraNetworksForTab('img2img')
|
||||
|
||||
function registerPrompt(tabname, id){
|
||||
var textarea = gradioApp().querySelector("#" + id + " > label > textarea");
|
||||
|
||||
if (! activePromptTextarea[tabname]){
|
||||
activePromptTextarea[tabname] = textarea
|
||||
}
|
||||
|
||||
textarea.addEventListener("focus", function(){
|
||||
if ( !activePromptTextarea[tabname]) activePromptTextarea[tabname] = textarea
|
||||
textarea.addEventListener("focus", function(){
|
||||
activePromptTextarea[tabname] = textarea;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
registerPrompt('txt2img', 'txt2img_prompt')
|
||||
registerPrompt('txt2img', 'txt2img_neg_prompt')
|
||||
registerPrompt('img2img', 'img2img_prompt')
|
||||
@@ -49,14 +38,12 @@ function setupExtraNetworks(){
|
||||
}
|
||||
|
||||
onUiLoaded(setupExtraNetworks)
|
||||
|
||||
var re_extranet = /<([^:]+:[^:]+):[\d\.]+>/;
|
||||
var re_extranet_g = /\s+<([^:]+:[^:]+):[\d\.]+>/g;
|
||||
|
||||
function tryToRemoveExtraNetworkFromPrompt(textarea, text){
|
||||
var m = text.match(re_extranet)
|
||||
if(! m) return false
|
||||
|
||||
var partToSearch = m[1]
|
||||
var replaced = false
|
||||
var newTextareaText = textarea.value.replaceAll(re_extranet_g, function(found, index){
|
||||
@@ -67,34 +54,25 @@ function tryToRemoveExtraNetworkFromPrompt(textarea, text){
|
||||
}
|
||||
return found;
|
||||
})
|
||||
|
||||
if(replaced){
|
||||
textarea.value = newTextareaText
|
||||
return true;
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function cardClicked(tabname, textToAdd, allowNegativePrompt){
|
||||
var textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea")
|
||||
|
||||
if(! tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)){
|
||||
textarea.value = textarea.value + opts.extra_networks_add_text_separator + textToAdd
|
||||
}
|
||||
|
||||
if (!tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)) textarea.value = textarea.value + opts.extra_networks_add_text_separator + textToAdd
|
||||
updateInput(textarea)
|
||||
}
|
||||
|
||||
function saveCardPreview(event, tabname, filename){
|
||||
var textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea')
|
||||
var button = gradioApp().getElementById(tabname + '_save_preview')
|
||||
|
||||
textarea.value = filename
|
||||
updateInput(textarea)
|
||||
|
||||
button.click()
|
||||
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
@@ -103,29 +81,23 @@ function saveCardDescription(event, tabname, filename, descript){
|
||||
var textarea = gradioApp().querySelector("#" + tabname + '_description_filename > label > textarea')
|
||||
var button = gradioApp().getElementById(tabname + '_save_description')
|
||||
var description = gradioApp().getElementById(tabname+ '_description_input')
|
||||
|
||||
textarea.value = filename
|
||||
description.value=descript
|
||||
updateInput(textarea)
|
||||
|
||||
button.click()
|
||||
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
function readCardDescription(event, tabname, filename, descript){
|
||||
function readCardDescription(event, tabname, filename, descript, extraPage, cardName){
|
||||
var textarea = gradioApp().querySelector("#" + tabname + '_description_filename > label > textarea')
|
||||
var description_textarea = gradioApp().querySelector("#" + tabname+ '_description_input > label > textarea')
|
||||
var button = gradioApp().getElementById(tabname + '_read_description')
|
||||
|
||||
textarea.value = filename
|
||||
description_textarea.value = descript
|
||||
|
||||
updateInput(textarea)
|
||||
updateInput(description_textarea)
|
||||
button.click()
|
||||
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
@@ -134,7 +106,6 @@ function extraNetworksSearchButton(tabs_id, event){
|
||||
searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > div > textarea')
|
||||
button = event.target
|
||||
text = button.classList.contains("search-all") ? "" : button.textContent.trim()
|
||||
|
||||
searchTextarea.value = text
|
||||
updateInput(searchTextarea)
|
||||
}
|
||||
@@ -146,40 +117,39 @@ function popup(contents){
|
||||
globalPopup = document.createElement('div')
|
||||
globalPopup.onclick = function(){ globalPopup.style.display = "none"; };
|
||||
globalPopup.classList.add('global-popup');
|
||||
|
||||
var close = document.createElement('div')
|
||||
close.classList.add('global-popup-close');
|
||||
close.onclick = function(){ globalPopup.style.display = "none"; };
|
||||
close.title = "Close";
|
||||
globalPopup.appendChild(close)
|
||||
|
||||
globalPopupInner = document.createElement('div')
|
||||
globalPopupInner.onclick = function(event){ event.stopPropagation(); return false; };
|
||||
globalPopupInner.classList.add('global-popup-inner');
|
||||
globalPopup.appendChild(globalPopupInner)
|
||||
|
||||
gradioApp().appendChild(globalPopup);
|
||||
}
|
||||
|
||||
globalPopupInner.innerHTML = '';
|
||||
globalPopupInner.appendChild(contents);
|
||||
|
||||
globalPopup.style.display = "flex";
|
||||
}
|
||||
|
||||
function extraNetworksShowMetadata(text){
|
||||
elem = document.createElement('pre')
|
||||
elem.classList.add('popup-metadata');
|
||||
elem.textContent = text;
|
||||
|
||||
popup(elem);
|
||||
function readCardMetadata(event, extraPage, cardName){
|
||||
requestGet("./sd_extra_networks/metadata", {"page": extraPage, "item": cardName}, function(data){
|
||||
if (data && data.metadata){
|
||||
elem = document.createElement('pre')
|
||||
elem.classList.add('popup-metadata');
|
||||
elem.textContent = data.metadata;
|
||||
popup(elem);
|
||||
}
|
||||
}, () => {})
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
function requestGet(url, data, handler, errorHandler){
|
||||
var xhr = new XMLHttpRequest();
|
||||
var args = Object.keys(data).map(function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) }).join('&')
|
||||
xhr.open("GET", url + "?" + args, true);
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
@@ -198,17 +168,3 @@ function requestGet(url, data, handler, errorHandler){
|
||||
var js = JSON.stringify(data);
|
||||
xhr.send(js);
|
||||
}
|
||||
|
||||
function extraNetworksRequestMetadata(event, extraPage, cardName){
|
||||
showError = function(){ extraNetworksShowMetadata("there was an error getting metadata"); }
|
||||
|
||||
requestGet("./sd_extra_networks/metadata", {"page": extraPage, "item": cardName}, function(data){
|
||||
if(data && data.metadata){
|
||||
extraNetworksShowMetadata(data.metadata)
|
||||
} else{
|
||||
showError()
|
||||
}
|
||||
}, showError)
|
||||
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
@@ -105,8 +105,8 @@ function setupImageForLightbox(e) {
|
||||
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1
|
||||
var event = isFirefox ? 'mousedown' : 'click'
|
||||
e.addEventListener(event, function (evt) {
|
||||
if(!opts.js_modal_lightbox || evt.button != 0) return;
|
||||
modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed)
|
||||
if (evt.button != 0) return;
|
||||
modalZoomSet(gradioApp().getElementById('modalImage'), true)
|
||||
evt.preventDefault()
|
||||
showModal(evt)
|
||||
}, true);
|
||||
|
||||
@@ -1,52 +1,32 @@
|
||||
// Monitors the gallery and sends a browser notification when the leading image is new.
|
||||
|
||||
let lastHeadImg = null;
|
||||
|
||||
let notificationButton = null;
|
||||
|
||||
const regExpTempImage = /(?<=\/|\\)tmp[\w\d]{8}\.png$/gm;
|
||||
|
||||
onUiUpdate(function(){
|
||||
if(notificationButton == null){
|
||||
notificationButton = gradioApp().getElementById('request_notifications')
|
||||
|
||||
if(notificationButton != null){
|
||||
notificationButton.addEventListener('click', function (evt) {
|
||||
Notification.requestPermission();
|
||||
},true);
|
||||
}
|
||||
if (notificationButton != null) notificationButton.addEventListener('click', (evt) => Notification.requestPermission(), true);
|
||||
}
|
||||
|
||||
const galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"][style*="display: block"] div[id$="_results"] .thumbnail-item > img');
|
||||
|
||||
if (galleryPreviews == null) return;
|
||||
|
||||
const headImg = galleryPreviews[0]?.src;
|
||||
|
||||
if (headImg == null || headImg == lastHeadImg) return;
|
||||
|
||||
if (headImg.search(regExpTempImage) != -1) return;
|
||||
|
||||
lastHeadImg = headImg;
|
||||
|
||||
// play notification sound if available
|
||||
gradioApp().querySelector('#audio_notification audio')?.play();
|
||||
|
||||
if (document.hasFocus()) return;
|
||||
|
||||
// Multiple copies of the images are in the DOM when one is selected. Dedup with a Set to get the real number generated.
|
||||
const imgs = new Set(Array.from(galleryPreviews).map(img => img.src));
|
||||
|
||||
const notification = new Notification(
|
||||
'Stable Diffusion',
|
||||
{
|
||||
'Stable Diffusion', {
|
||||
body: `Generated ${imgs.size > 1 ? imgs.size - opts.return_grid : 1} image${imgs.size > 1 ? 's' : ''}`,
|
||||
icon: headImg,
|
||||
image: headImg,
|
||||
}
|
||||
image: headImg }
|
||||
);
|
||||
|
||||
notification.onclick = function(_){
|
||||
notification.onclick = function(_) {
|
||||
parent.focus();
|
||||
this.close();
|
||||
};
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
### majority of this file is superflous, but used by some extensions as helpers during extension installation
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
import shlex
|
||||
import logging
|
||||
import setup
|
||||
import modules.paths_internal
|
||||
import modules.cmd_args
|
||||
|
||||
setup.ensure_base_requirements()
|
||||
from rich import print # pylint: disable=redefined-builtin,wrong-import-order
|
||||
|
||||
### majority of this file is superflous, but used by some extensions as helpers during extension installation
|
||||
|
||||
commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
|
||||
sys.argv += shlex.split(commandline_args)
|
||||
setup.extensions_preload(force=False)
|
||||
setup.parse_args()
|
||||
|
||||
import installer
|
||||
installer.add_args()
|
||||
installer.ensure_base_requirements()
|
||||
installer.extensions_preload(force=False)
|
||||
installer.parse_args()
|
||||
|
||||
import modules.cmd_args
|
||||
args, _ = modules.cmd_args.parser.parse_known_args()
|
||||
import modules.paths_internal
|
||||
script_path = modules.paths_internal.script_path
|
||||
extensions_dir = modules.paths_internal.extensions_dir
|
||||
git = os.environ.get('GIT', "git")
|
||||
@@ -40,6 +41,7 @@ def commit_hash():
|
||||
|
||||
def run(command, desc=None, errdesc=None, custom_env=None, live=False):
|
||||
if desc is not None:
|
||||
from rich import print # pylint: disable=redefined-builtin,wrong-import-order
|
||||
print(desc)
|
||||
if live:
|
||||
result = subprocess.run(command, check=False, shell=True, env=os.environ if custom_env is None else custom_env)
|
||||
@@ -61,7 +63,7 @@ def check_run(command):
|
||||
|
||||
|
||||
def is_installed(package):
|
||||
return setup.installed(package)
|
||||
return installer.installed(package)
|
||||
|
||||
|
||||
def repo_dir(name):
|
||||
@@ -84,17 +86,21 @@ def check_run_python(code):
|
||||
|
||||
|
||||
def git_clone(url, tgt, _name, commithash=None):
|
||||
setup.clone(url, tgt, commithash)
|
||||
installer.clone(url, tgt, commithash)
|
||||
|
||||
|
||||
def run_extension_installer(ext_dir):
|
||||
setup.run_extension_installer(ext_dir)
|
||||
installer.run_extension_installer(ext_dir)
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup.run_setup()
|
||||
setup.extensions_preload(force=True)
|
||||
setup.log.info(f"Server arguments: {sys.argv[1:]}")
|
||||
setup.log.debug('Starting WebUI')
|
||||
installer.run_setup()
|
||||
installer.extensions_preload(force=True)
|
||||
installer.log.info(f"Server arguments: {sys.argv[1:]}")
|
||||
installer.log.debug('Starting WebUI')
|
||||
logging.disable(logging.INFO)
|
||||
if args.test:
|
||||
installer.log.info("Test only")
|
||||
import webui
|
||||
exit(0)
|
||||
import webui
|
||||
webui.webui()
|
||||
|
||||
+64
-74
@@ -13,11 +13,11 @@ import piexif
|
||||
import piexif.helper
|
||||
import uvicorn
|
||||
import gradio as gr
|
||||
from gradio.processing_utils import decode_base64_to_file
|
||||
# from gradio_client.utils import decode_base64_to_file
|
||||
# from gradio.processing_utils import decode_base64_to_file # gradio 3.23
|
||||
from gradio_client.utils import decode_base64_to_file # gradio 3.28
|
||||
|
||||
from modules import errors, shared, sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing
|
||||
from modules.api.models import *
|
||||
from modules.api.models import * # pylint: disable=unused-wildcard-import, wildcard-import
|
||||
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
|
||||
from modules.textual_inversion.textual_inversion import create_embedding, train_embedding
|
||||
from modules.textual_inversion.preprocess import preprocess
|
||||
@@ -32,20 +32,19 @@ errors.install()
|
||||
def upscaler_to_index(name: str):
|
||||
try:
|
||||
return [x.name.lower() for x in shared.sd_upscalers].index(name.lower())
|
||||
except:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid upscaler, needs to be one of these: {' , '.join([x.name for x in sd_upscalers])}")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid upscaler, needs to be one of these: {' , '.join([x.name for x in sd_upscalers])}") from e
|
||||
|
||||
def script_name_to_index(name, scripts_list):
|
||||
try:
|
||||
return [script.title().lower() for script in scripts_list].index(name.lower())
|
||||
except:
|
||||
raise HTTPException(status_code=422, detail=f"Script '{name}' not found")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=422, detail=f"Script '{name}' not found") from e
|
||||
|
||||
def validate_sampler_name(name):
|
||||
config = sd_samplers.all_samplers_map.get(name, None)
|
||||
if config is None:
|
||||
raise HTTPException(status_code=404, detail="Sampler not found")
|
||||
|
||||
return name
|
||||
|
||||
def setUpscalers(req: dict):
|
||||
@@ -60,20 +59,19 @@ def decode_base64_to_image(encoding):
|
||||
try:
|
||||
image = Image.open(BytesIO(base64.b64decode(encoding)))
|
||||
return image
|
||||
except Exception:
|
||||
raise HTTPException(status_code=500, detail="Invalid encoded image")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail="Invalid encoded image") from e
|
||||
|
||||
def encode_pil_to_base64(image):
|
||||
with io.BytesIO() as output_bytes:
|
||||
|
||||
if opts.samples_format.lower() == 'png':
|
||||
use_metadata = False
|
||||
metadata = PngImagePlugin.PngInfo()
|
||||
for key, value in image.info.items():
|
||||
if isinstance(key, str) and isinstance(value, str):
|
||||
metadata.add_text(key, value)
|
||||
encoded_metadata = PngImagePlugin.PngInfo()
|
||||
for k, v in image.info.items():
|
||||
if isinstance(k, str) and isinstance(v, str):
|
||||
encoded_metadata.add_text(k, v)
|
||||
use_metadata = True
|
||||
image.save(output_bytes, format="PNG", pnginfo=(metadata if use_metadata else None), quality=opts.jpeg_quality)
|
||||
image.save(output_bytes, format="PNG", pnginfo=(encoded_metadata if use_metadata else None), quality=opts.jpeg_quality)
|
||||
|
||||
elif opts.samples_format.lower() in ("jpg", "jpeg", "webp"):
|
||||
parameters = image.info.get('parameters', None)
|
||||
@@ -84,12 +82,9 @@ def encode_pil_to_base64(image):
|
||||
image.save(output_bytes, format="JPEG", exif = exif_bytes, quality=opts.jpeg_quality)
|
||||
else:
|
||||
image.save(output_bytes, format="WEBP", exif = exif_bytes, quality=opts.jpeg_quality)
|
||||
|
||||
else:
|
||||
raise HTTPException(status_code=500, detail="Invalid image format")
|
||||
|
||||
bytes_data = output_bytes.getvalue()
|
||||
|
||||
return base64.b64encode(bytes_data)
|
||||
|
||||
|
||||
@@ -100,7 +95,6 @@ class Api:
|
||||
for auth in shared.cmd_opts.api_auth.split(","):
|
||||
user, password = auth.split(":")
|
||||
self.credentials[user] = password
|
||||
|
||||
self.router = APIRouter()
|
||||
self.app = app
|
||||
self.queue_lock = queue_lock
|
||||
@@ -135,7 +129,6 @@ class Api:
|
||||
self.add_api_route("/sdapi/v1/unload-checkpoint", self.unloadapi, methods=["POST"])
|
||||
self.add_api_route("/sdapi/v1/reload-checkpoint", self.reloadapi, methods=["POST"])
|
||||
self.add_api_route("/sdapi/v1/scripts", self.get_scripts_list, methods=["GET"], response_model=ScriptsList)
|
||||
|
||||
self.default_script_arg_txt2img = []
|
||||
self.default_script_arg_img2img = []
|
||||
|
||||
@@ -148,13 +141,11 @@ class Api:
|
||||
if credentials.username in self.credentials:
|
||||
if compare_digest(credentials.password, self.credentials[credentials.username]):
|
||||
return True
|
||||
|
||||
raise HTTPException(status_code=401, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"})
|
||||
|
||||
def get_selectable_script(self, script_name, script_runner):
|
||||
if script_name is None or script_name == "":
|
||||
return None, None
|
||||
|
||||
script_idx = script_name_to_index(script_name, script_runner.selectable_scripts)
|
||||
script = script_runner.selectable_scripts[script_idx]
|
||||
return script, script_idx
|
||||
@@ -162,13 +153,11 @@ class Api:
|
||||
def get_scripts_list(self):
|
||||
t2ilist = [str(title.lower()) for title in scripts.scripts_txt2img.titles]
|
||||
i2ilist = [str(title.lower()) for title in scripts.scripts_img2img.titles]
|
||||
|
||||
return ScriptsList(txt2img = t2ilist, img2img = i2ilist)
|
||||
|
||||
def get_script(self, script_name, script_runner):
|
||||
if script_name is None or script_name == "":
|
||||
return None, None
|
||||
|
||||
script_idx = script_name_to_index(script_name, script_runner.scripts)
|
||||
return script_runner.scripts[script_idx]
|
||||
|
||||
@@ -192,27 +181,28 @@ class Api:
|
||||
script_args[script.args_from:script.args_to] = ui_default_values
|
||||
return script_args
|
||||
|
||||
def init_script_args(self, request, default_script_args, selectable_scripts, selectable_idx, script_runner):
|
||||
def init_script_args(self, p, request, default_script_args, selectable_scripts, selectable_script_idx, script_runner):
|
||||
script_args = default_script_args.copy()
|
||||
# position 0 in script_arg is the idx+1 of the selectable script that is going to be run when using scripts.scripts_*2img.run()
|
||||
if selectable_scripts:
|
||||
# TODO this can corrupt values for other scripts
|
||||
script_args[selectable_scripts.args_from:selectable_scripts.args_to] = request.script_args
|
||||
script_args[0] = selectable_idx + 1
|
||||
|
||||
script_args[0] = selectable_script_idx + 1
|
||||
# Now check for always on scripts
|
||||
if request.alwayson_scripts and (len(request.alwayson_scripts) > 0):
|
||||
for alwayson_script_name in request.alwayson_scripts.keys():
|
||||
alwayson_script = self.get_script(alwayson_script_name, script_runner)
|
||||
if alwayson_script is None:
|
||||
raise HTTPException(status_code=422, detail=f"always on script {alwayson_script_name} not found")
|
||||
# Selectable script in always on script param check
|
||||
raise HTTPException(status_code=422, detail=f"Always on script not found: {alwayson_script_name}")
|
||||
if not alwayson_script.alwayson:
|
||||
raise HTTPException(status_code=422, detail=f"Cannot have a selectable script in the always on scripts params")
|
||||
# always on script with no arg should always run so you don't really need to add them to the requests
|
||||
raise HTTPException(status_code=422, detail=f"Selectable script cannot be in always on params: {alwayson_script_name}")
|
||||
if "args" in request.alwayson_scripts[alwayson_script_name]:
|
||||
# TODO this can corrupt values for other scripts
|
||||
script_args[alwayson_script.args_from:alwayson_script.args_to] = request.alwayson_scripts[alwayson_script_name]["args"]
|
||||
p.per_script_args[alwayson_script.title()] = request.alwayson_scripts[alwayson_script_name]["args"]
|
||||
return script_args
|
||||
|
||||
|
||||
def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
|
||||
script_runner = scripts.scripts_txt2img
|
||||
if not script_runner.scripts:
|
||||
@@ -221,7 +211,6 @@ class Api:
|
||||
if not self.default_script_arg_txt2img:
|
||||
self.default_script_arg_txt2img = self.init_default_script_args(script_runner)
|
||||
selectable_scripts, selectable_script_idx = self.get_selectable_script(txt2imgreq.script_name, script_runner)
|
||||
|
||||
populate = txt2imgreq.copy(update={ # Override __init__ params
|
||||
"sampler_name": validate_sampler_name(txt2imgreq.sampler_name or txt2imgreq.sampler_index),
|
||||
"do_not_save_samples": not txt2imgreq.save_images,
|
||||
@@ -229,14 +218,10 @@ class Api:
|
||||
})
|
||||
if populate.sampler_name:
|
||||
populate.sampler_index = None # prevent a warning later on
|
||||
|
||||
args = vars(populate)
|
||||
args.pop('script_name', None)
|
||||
args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
|
||||
args.pop('alwayson_scripts', None)
|
||||
|
||||
script_args = self.init_script_args(txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner)
|
||||
|
||||
send_images = args.pop('send_images', True)
|
||||
args.pop('save_images', None)
|
||||
|
||||
@@ -245,29 +230,25 @@ class Api:
|
||||
p.scripts = script_runner
|
||||
p.outpath_grids = opts.outdir_grids or opts.outdir_txt2img_grids
|
||||
p.outpath_samples = opts.outdir_samples or opts.outdir_txt2img_samples
|
||||
|
||||
shared.state.begin()
|
||||
script_args = self.init_script_args(p, txt2imgreq, self.default_script_arg_txt2img, selectable_scripts, selectable_script_idx, script_runner)
|
||||
if selectable_scripts is not None:
|
||||
p.script_args = script_args
|
||||
processed = scripts.scripts_txt2img.run(p, *p.script_args) # Need to pass args as list here
|
||||
processed = scripts.scripts_txt2img.run(p, *script_args) # Need to pass args as list here
|
||||
else:
|
||||
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
||||
processed = process_images(p)
|
||||
shared.state.end()
|
||||
|
||||
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
||||
|
||||
return TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js())
|
||||
|
||||
def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
|
||||
init_images = img2imgreq.init_images
|
||||
if init_images is None:
|
||||
raise HTTPException(status_code=404, detail="Init image not found")
|
||||
|
||||
mask = img2imgreq.mask
|
||||
if mask:
|
||||
mask = decode_base64_to_image(mask)
|
||||
|
||||
script_runner = scripts.scripts_img2img
|
||||
if not script_runner.scripts:
|
||||
script_runner.initialize_scripts(True)
|
||||
@@ -275,7 +256,6 @@ class Api:
|
||||
if not self.default_script_arg_img2img:
|
||||
self.default_script_arg_img2img = self.init_default_script_args(script_runner)
|
||||
selectable_scripts, selectable_script_idx = self.get_selectable_script(img2imgreq.script_name, script_runner)
|
||||
|
||||
populate = img2imgreq.copy(update={ # Override __init__ params
|
||||
"sampler_name": validate_sampler_name(img2imgreq.sampler_name or img2imgreq.sampler_index),
|
||||
"do_not_save_samples": not img2imgreq.save_images,
|
||||
@@ -284,15 +264,11 @@ class Api:
|
||||
})
|
||||
if populate.sampler_name:
|
||||
populate.sampler_index = None # prevent a warning later on
|
||||
|
||||
args = vars(populate)
|
||||
args.pop('include_init_images', None) # this is meant to be done by "exclude": True in model, but it's for a reason that I cannot determine.
|
||||
args.pop('script_name', None)
|
||||
args.pop('script_args', None) # will refeed them to the pipeline directly after initializing them
|
||||
args.pop('alwayson_scripts', None)
|
||||
|
||||
script_args = self.init_script_args(img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner)
|
||||
|
||||
send_images = args.pop('send_images', True)
|
||||
args.pop('save_images', None)
|
||||
|
||||
@@ -302,22 +278,19 @@ class Api:
|
||||
p.scripts = script_runner
|
||||
p.outpath_grids = opts.outdir_img2img_grids
|
||||
p.outpath_samples = opts.outdir_img2img_samples
|
||||
|
||||
shared.state.begin()
|
||||
script_args = self.init_script_args(p, img2imgreq, self.default_script_arg_img2img, selectable_scripts, selectable_script_idx, script_runner)
|
||||
if selectable_scripts is not None:
|
||||
p.script_args = script_args
|
||||
processed = scripts.scripts_img2img.run(p, *p.script_args) # Need to pass args as list here
|
||||
processed = scripts.scripts_img2img.run(p, *script_args) # Need to pass args as list here
|
||||
else:
|
||||
p.script_args = tuple(script_args) # Need to pass args as tuple here
|
||||
processed = process_images(p)
|
||||
shared.state.end()
|
||||
|
||||
b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else []
|
||||
|
||||
if not img2imgreq.include_init_images:
|
||||
img2imgreq.init_images = None
|
||||
img2imgreq.mask = None
|
||||
|
||||
return ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.js())
|
||||
|
||||
def extras_single_image_api(self, req: ExtrasSingleImageRequest):
|
||||
@@ -429,12 +402,11 @@ class Api:
|
||||
|
||||
def get_config(self):
|
||||
options = {}
|
||||
for key in shared.opts.data.keys():
|
||||
metadata = shared.opts.data_labels.get(key)
|
||||
if metadata is not None:
|
||||
options.update({key: shared.opts.data.get(key, shared.opts.data_labels.get(key).default)})
|
||||
for k in shared.opts.data.keys():
|
||||
if shared.opts.data_labels.get(k) is not None:
|
||||
options.update({k: shared.opts.data.get(k, shared.opts.data_labels.get(k).default)})
|
||||
else:
|
||||
options.update({key: shared.opts.data.get(key, None)})
|
||||
options.update({k: shared.opts.data.get(k, None)})
|
||||
|
||||
return options
|
||||
|
||||
@@ -512,20 +484,20 @@ class Api:
|
||||
filename = create_embedding(**args) # create empty embedding
|
||||
sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings() # reload embeddings so new one can be immediately used
|
||||
shared.state.end()
|
||||
return CreateResponse(info = "create embedding filename: {filename}".format(filename = filename))
|
||||
return CreateResponse(info = f"create embedding filename: {filename}")
|
||||
except AssertionError as e:
|
||||
shared.state.end()
|
||||
return TrainResponse(info = "create embedding error: {error}".format(error = e))
|
||||
return TrainResponse(info = f"create embedding error: {e}")
|
||||
|
||||
def create_hypernetwork(self, args: dict):
|
||||
try:
|
||||
shared.state.begin()
|
||||
filename = create_hypernetwork(**args) # create empty embedding # pylint: disable=E1111
|
||||
shared.state.end()
|
||||
return CreateResponse(info = "create hypernetwork filename: {filename}".format(filename = filename))
|
||||
return CreateResponse(info = f"create hypernetwork filename: {filename}")
|
||||
except AssertionError as e:
|
||||
shared.state.end()
|
||||
return TrainResponse(info = "create hypernetwork error: {error}".format(error = e))
|
||||
return TrainResponse(info = f"create hypernetwork error: {e}")
|
||||
|
||||
def preprocess(self, args: dict):
|
||||
try:
|
||||
@@ -535,13 +507,13 @@ class Api:
|
||||
return PreprocessResponse(info = 'preprocess complete')
|
||||
except KeyError as e:
|
||||
shared.state.end()
|
||||
return PreprocessResponse(info = "preprocess error: invalid token: {error}".format(error = e))
|
||||
return PreprocessResponse(info = f"preprocess error: invalid token: {e}")
|
||||
except AssertionError as e:
|
||||
shared.state.end()
|
||||
return PreprocessResponse(info = "preprocess error: {error}".format(error = e))
|
||||
return PreprocessResponse(info = f"preprocess error: {e}")
|
||||
except FileNotFoundError as e:
|
||||
shared.state.end()
|
||||
return PreprocessResponse(info = 'preprocess error: {error}'.format(error = e))
|
||||
return PreprocessResponse(info = f'preprocess error: {e}')
|
||||
|
||||
def train_embedding(self, args: dict):
|
||||
try:
|
||||
@@ -552,17 +524,17 @@ class Api:
|
||||
if not apply_optimizations:
|
||||
sd_hijack.undo_optimizations()
|
||||
try:
|
||||
embedding, filename = train_embedding(**args) # can take a long time to complete
|
||||
_embedding, filename = train_embedding(**args) # can take a long time to complete
|
||||
except Exception as e:
|
||||
error = e
|
||||
finally:
|
||||
if not apply_optimizations:
|
||||
sd_hijack.apply_optimizations()
|
||||
shared.state.end()
|
||||
return TrainResponse(info = "train embedding complete: filename: {filename} error: {error}".format(filename = filename, error = error))
|
||||
return TrainResponse(info = f"train embedding complete: filename: {filename} error: {error}")
|
||||
except AssertionError as msg:
|
||||
shared.state.end()
|
||||
return TrainResponse(info = "train embedding error: {msg}".format(msg = msg))
|
||||
return TrainResponse(info = f"train embedding error: {msg}")
|
||||
|
||||
def train_hypernetwork(self, args: dict):
|
||||
try:
|
||||
@@ -574,7 +546,7 @@ class Api:
|
||||
if not apply_optimizations:
|
||||
sd_hijack.undo_optimizations()
|
||||
try:
|
||||
hypernetwork, filename = train_hypernetwork(**args)
|
||||
_hypernetwork, filename = train_hypernetwork(**args)
|
||||
except Exception as e:
|
||||
error = e
|
||||
finally:
|
||||
@@ -583,10 +555,10 @@ class Api:
|
||||
if not apply_optimizations:
|
||||
sd_hijack.apply_optimizations()
|
||||
shared.state.end()
|
||||
return TrainResponse(info="train embedding complete: filename: {filename} error: {error}".format(filename=filename, error=error))
|
||||
except AssertionError as msg:
|
||||
return TrainResponse(info=f"train embedding complete: filename: {filename} error: {error}")
|
||||
except AssertionError:
|
||||
shared.state.end()
|
||||
return TrainResponse(info="train embedding error: {error}".format(error=error))
|
||||
return TrainResponse(info=f"train embedding error: {error}")
|
||||
|
||||
def shutdown(self):
|
||||
print('shutdown request received')
|
||||
@@ -600,7 +572,8 @@ class Api:
|
||||
|
||||
def get_memory(self):
|
||||
try:
|
||||
import os, psutil
|
||||
import os
|
||||
import psutil
|
||||
process = psutil.Process(os.getpid())
|
||||
res = process.memory_info() # only rss is cross-platform guaranteed so we dont rely on other values
|
||||
ram_total = 100 * res.rss / process.memory_percent() # and total memory is calculated as actual value is not cross-platform safe
|
||||
@@ -609,7 +582,24 @@ class Api:
|
||||
ram = { 'error': f'{err}' }
|
||||
try:
|
||||
import torch
|
||||
if torch.cuda.is_available():
|
||||
if shared.cmd_opts.use_ipex():
|
||||
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
|
||||
system = { 'free': (torch.xpu.get_device_properties("xpu").total_memory - torch.xpu.memory_allocated()), 'used': torch.xpu.memory_allocated(), 'total': torch.xpu.get_device_properties("xpu").total_memory }
|
||||
s = dict(torch.xpu.memory_stats("xpu"))
|
||||
allocated = { 'current': s['allocated_bytes.all.current'], 'peak': s['allocated_bytes.all.peak'] }
|
||||
reserved = { 'current': s['reserved_bytes.all.current'], 'peak': s['reserved_bytes.all.peak'] }
|
||||
active = { 'current': s['active_bytes.all.current'], 'peak': s['active_bytes.all.peak'] }
|
||||
inactive = { 'current': s['inactive_split_bytes.all.current'], 'peak': s['inactive_split_bytes.all.peak'] }
|
||||
warnings = { 'retries': s['num_alloc_retries'], 'oom': s['num_ooms'] }
|
||||
cuda = {
|
||||
'system': system,
|
||||
'active': active,
|
||||
'allocated': allocated,
|
||||
'reserved': reserved,
|
||||
'inactive': inactive,
|
||||
'events': warnings,
|
||||
}
|
||||
elif torch.cuda.is_available():
|
||||
s = torch.cuda.mem_get_info()
|
||||
system = { 'free': s[0], 'used': s[1] - s[0], 'total': s[1] }
|
||||
s = dict(torch.cuda.memory_stats(shared.device))
|
||||
|
||||
+16
-20
@@ -1,11 +1,10 @@
|
||||
import inspect
|
||||
from pydantic import BaseModel, Field, create_model
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Optional, Dict, List
|
||||
from pydantic import BaseModel, Field, create_model # pylint: disable=no-name-in-module
|
||||
from typing_extensions import Literal
|
||||
from inflection import underscore
|
||||
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
|
||||
from modules.shared import sd_upscalers, opts, parser
|
||||
from typing import Dict, List
|
||||
|
||||
API_NOT_ALLOWED = [
|
||||
"self",
|
||||
@@ -14,8 +13,6 @@ API_NOT_ALLOWED = [
|
||||
"outpath_samples",
|
||||
"outpath_grids",
|
||||
"sampler_index",
|
||||
# "do_not_save_samples",
|
||||
# "do_not_save_grid",
|
||||
"extra_generation_params",
|
||||
"overlay_images",
|
||||
"do_not_reload_embeddings",
|
||||
@@ -48,7 +45,7 @@ class PydanticModelGenerator:
|
||||
class_instance = None,
|
||||
additional_fields = None,
|
||||
):
|
||||
def field_type_generator(k, v):
|
||||
def field_type_generator(_k, v):
|
||||
# field_type = str if not overrides.get(k) else overrides[k]["type"]
|
||||
# print(k, v.annotation, v.default)
|
||||
field_type = v.annotation
|
||||
@@ -76,23 +73,21 @@ class PydanticModelGenerator:
|
||||
for (k,v) in self._class_data.items() if k not in API_NOT_ALLOWED
|
||||
]
|
||||
|
||||
for fields in additional_fields:
|
||||
for fld in additional_fields:
|
||||
self._model_def.append(ModelDef(
|
||||
field=underscore(fields["key"]),
|
||||
field_alias=fields["key"],
|
||||
field_type=fields["type"],
|
||||
field_value=fields["default"],
|
||||
field_exclude=fields["exclude"] if "exclude" in fields else False))
|
||||
field=underscore(fld["key"]),
|
||||
field_alias=fld["key"],
|
||||
field_type=fld["type"],
|
||||
field_value=fld["default"],
|
||||
field_exclude=fld["exclude"] if "exclude" in fld else False))
|
||||
|
||||
def generate_model(self):
|
||||
"""
|
||||
Creates a pydantic BaseModel
|
||||
from the json and overrides provided at initialization
|
||||
"""
|
||||
fields = {
|
||||
d.field: (d.field_type, Field(default=d.field_value, alias=d.field_alias, exclude=d.field_exclude)) for d in self._model_def
|
||||
}
|
||||
DynamicModel = create_model(self._model_name, **fields)
|
||||
model_fields = { d.field: (d.field_type, Field(default=d.field_value, alias=d.field_alias, exclude=d.field_exclude)) for d in self._model_def }
|
||||
DynamicModel = create_model(self._model_name, **model_fields)
|
||||
DynamicModel.__config__.allow_population_by_field_name = True
|
||||
DynamicModel.__config__.allow_mutation = True
|
||||
return DynamicModel
|
||||
@@ -209,7 +204,7 @@ for key, metadata in opts.data_labels.items():
|
||||
value = opts.data.get(key)
|
||||
optType = opts.typemap.get(type(metadata.default), type(value))
|
||||
|
||||
if (metadata is not None):
|
||||
if metadata is not None:
|
||||
fields.update({key: (Optional[optType], Field(
|
||||
default=metadata.default ,description=metadata.label))})
|
||||
else:
|
||||
@@ -220,10 +215,11 @@ OptionsModel = create_model("Options", **fields)
|
||||
flags = {}
|
||||
_options = vars(parser)['_option_string_actions']
|
||||
for key in _options:
|
||||
if(_options[key].dest != 'help'):
|
||||
if _options[key].dest != 'help':
|
||||
flag = _options[key]
|
||||
_type = str
|
||||
if _options[key].default is not None: _type = type(_options[key].default)
|
||||
if _options[key].default is not None:
|
||||
_type = type(_options[key].default)
|
||||
flags.update({flag.dest: (_type,Field(default=flag.default, description=flag.help))})
|
||||
|
||||
FlagsModel = create_model("Flags", **flags)
|
||||
@@ -288,4 +284,4 @@ class MemoryResponse(BaseModel):
|
||||
|
||||
class ScriptsList(BaseModel):
|
||||
txt2img: list = Field(default=None,title="Txt2img", description="Titles of scripts (txt2img)")
|
||||
img2img: list = Field(default=None,title="Img2img", description="Titles of scripts (img2img)")
|
||||
img2img: list = Field(default=None,title="Img2img", description="Titles of scripts (img2img)")
|
||||
|
||||
+91
-72
@@ -1,87 +1,106 @@
|
||||
import argparse
|
||||
import os
|
||||
from modules.paths_internal import data_path, sd_default_config, sd_model_file
|
||||
from modules.paths_internal import data_path
|
||||
|
||||
parser = argparse.ArgumentParser(description="Stable Diffusion", formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=55,indent_increment=2,width=200))
|
||||
parser = argparse.ArgumentParser(description="SD.Next", conflict_handler='resolve', epilog='For other options see UI Settings page', prog='', add_help=True, formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=55, indent_increment=2, width=200))
|
||||
parser._optionals = parser.add_argument_group('Other options') # pylint: disable=protected-access
|
||||
group = parser.add_argument_group('Server options')
|
||||
|
||||
parser.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
|
||||
parser.add_argument("--ui-settings-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'config.json'))
|
||||
parser.add_argument("--ui-config-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'ui-config.json'))
|
||||
parser.add_argument("--config", type=str, default=sd_default_config, help=argparse.SUPPRESS)
|
||||
parser.add_argument("--theme", type=str, help=argparse.SUPPRESS, default=None)
|
||||
# main server args
|
||||
group.add_argument("--config", type=str, default=os.path.join(data_path, 'config.json'), help="Use specific configuration file, default: %(default)s")
|
||||
group.add_argument("--medvram", action='store_true', help="Split model stages and keep only active part in VRAM, default: %(default)s")
|
||||
group.add_argument("--lowvram", action='store_true', help="Split model components and keep only active part in VRAM, default: %(default)s")
|
||||
group.add_argument("--ckpt", type=str, default=None, help="Path to model checkpoint to load immediately, default: %(default)s")
|
||||
group.add_argument('--vae', type=str, default=None, help='Path to VAE checkpoint to load immediately, default: %(default)s')
|
||||
group.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="Base path where all user data is stored, default: %(default)s")
|
||||
group.add_argument("--models-dir", type=str, default="models", help="Base path where all models are stored, default: %(default)s",)
|
||||
group.add_argument("--allow-code", action='store_true', help="Allow custom script execution, default: %(default)s")
|
||||
group.add_argument("--share", action='store_true', help="Enable UI accessible through Gradio site, default: %(default)s")
|
||||
group.add_argument("--insecure", action='store_true', help="Enable extensions tab regardless of other options, default: %(default)s")
|
||||
group.add_argument("--use-cpu", nargs='+', default=[], type=str.lower, help="Force use CPU for specified modules, default: %(default)s")
|
||||
group.add_argument("--listen", action='store_true', help="Launch web server using public IP address, default: %(default)s")
|
||||
group.add_argument("--port", type=int, default=7860, help="Launch web server with given server port, default: %(default)s")
|
||||
group.add_argument("--freeze", action='store_true', help="Disable editing settings", default=False)
|
||||
group.add_argument("--auth", type=str, help='Set access authentication like "user:pwd,user:pwd""', default=None)
|
||||
group.add_argument("--authfile", type=str, help='Set access authentication using file, default: %(default)s', default=None)
|
||||
group.add_argument("--autolaunch", action='store_true', help="Open the UI URL in the system's default browser upon launch", default=False)
|
||||
group.add_argument("--api-auth", type=str, help='Set API authentication, default: %(default)s', default=None)
|
||||
group.add_argument("--api-log", default=False, action='store_true', help="Enable logging of all API requests, default: %(default)s")
|
||||
group.add_argument("--device-id", type=str, help="Select the default CUDA device to use, default: %(default)s", default=None)
|
||||
group.add_argument("--cors-origins", type=str, help="Allowed CORS origins as comma-separated list, default: %(default)s", default=None)
|
||||
group.add_argument("--cors-regex", type=str, help="Allowed CORS origins as regular expression, default: %(default)s", default=None)
|
||||
group.add_argument("--tls-keyfile", type=str, help="Enable TLS and specify key file, default: %(default)s", default=None)
|
||||
group.add_argument("--tls-certfile", type=str, help="Enable TLS and specify cert file, default: %(default)s", default=None)
|
||||
group.add_argument("--tls-selfsign", action="store_true", help="Enable TLS with self-signed certificates, default: %(default)s", default=None)
|
||||
group.add_argument("--server-name", type=str, help="Sets hostname of server, default: %(default)s", default=None)
|
||||
group.add_argument("--no-hashing", action='store_true', help="Disable hashing of checkpoints, default: %(default)s", default=False)
|
||||
group.add_argument("--no-download", action='store_true', help="Disable download of default model, default: %(default)s", default=False)
|
||||
group.add_argument("--profile", action='store_true', help="Run profiler, default: %(default)s")
|
||||
group.add_argument("--disable-queue", action='store_true', help="Disable queues, default: %(default)s")
|
||||
group.add_argument('--debug', default = False, action='store_true', help = "Run installer with debug logging, default: %(default)s")
|
||||
group.add_argument("--use-ipex", action='store_true', help="Use Intel OneAPI XPU backend, default: %(default)s", default=False)
|
||||
|
||||
parser.add_argument("--medvram", action='store_true', help="Enable model optimizations for sacrificing a little speed for low memory usage")
|
||||
parser.add_argument("--lowvram", action='store_true', help="Enable model optimizations for sacrificing a lot of speed for lowest memory usage")
|
||||
parser.add_argument("--lowram", action='store_true', help="Load checkpoint weights to VRAM instead of RAM")
|
||||
|
||||
parser.add_argument("--ckpt", type=str, default=sd_model_file, help="Path to checkpoint of stable diffusion model to load immediately",)
|
||||
parser.add_argument('--vae', type=str, help='Path to checkpoint of stable diffusion VAE model to load immediately', default=None)
|
||||
parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="Base path where all user data is stored")
|
||||
parser.add_argument("--models-dir", type=str, default="models", help="Nase path where all models are stored",)
|
||||
|
||||
parser.add_argument("--allow-code", action='store_true', help="Allow custom script execution")
|
||||
parser.add_argument("--share", action='store_true', help="Enable to make the UI accessible through Gradio site")
|
||||
parser.add_argument("--enable-insecure", action='store_true', help="Enable extensions tab regardless of other options")
|
||||
parser.add_argument("--use-cpu", nargs='+', help="Force use CPU for specified modules", default=[], type=str.lower)
|
||||
parser.add_argument("--listen", action='store_true', help="Launch web server using public IP address")
|
||||
parser.add_argument("--port", type=int, help="Launch web server with given server port", default=None)
|
||||
parser.add_argument("--hide-ui-dir-config", action='store_true', help="Hide directory configuration from UI", default=False)
|
||||
parser.add_argument("--freeze-settings", action='store_true', help="Disable editing settings", default=False)
|
||||
parser.add_argument("--gradio-auth", type=str, help='Set Gradio authentication like "username:password,username:password""', default=None)
|
||||
parser.add_argument("--gradio-auth-path", type=str, help='Set Gradio authentication using file', default=None)
|
||||
parser.add_argument("--autolaunch", action='store_true', help="Open the UI URL in the system's default browser upon launch", default=False)
|
||||
parser.add_argument("--disable-console-progressbars", action='store_true', help="Do not output progressbars to console", default=True)
|
||||
parser.add_argument("--disable-safe-unpickle", action='store_true', help="Disable checking models for malicious code", default=True)
|
||||
parser.add_argument("--api-auth", type=str, help='Set API authentication', default=None)
|
||||
parser.add_argument("--api-log", action='store_true', help="Enable logging of all API requests")
|
||||
parser.add_argument("--device-id", type=str, help="Select the default CUDA device to use", default=None)
|
||||
parser.add_argument("--cors-origins", type=str, help="Allowed CORS origin(s) in the form of a comma-separated list", default=None)
|
||||
parser.add_argument("--cors-regex", type=str, help="Allowed CORS origin(s) in the form of a single regular expression", default=None)
|
||||
parser.add_argument("--tls-keyfile", type=str, help="Partially enables TLS, requires --tls-certfile to fully function", default=None)
|
||||
parser.add_argument("--tls-certfile", type=str, help="Partially enables TLS, requires --tls-keyfile to fully function", default=None)
|
||||
parser.add_argument("--server-name", type=str, help="Sets hostname of server", default=None)
|
||||
parser.add_argument("--no-hashing", action='store_true', help="Disable sha256 hashing of checkpoints", default=False)
|
||||
parser.add_argument("--no-download-sd-model", action='store_true', help="Disable download of default model even if no model is found", default=False)
|
||||
parser.add_argument("--profile", action='store_true', help="Run profiler, default: %(default)s")
|
||||
parser.add_argument("--disable-queue", action='store_true', help="Disable Gradio queues and force use of HTTP instead of WebSockets, default: %(default)s")
|
||||
# removed args are added here as hidden in fixed format for compatbility reasons
|
||||
group.add_argument("-f", action='store_true', help=argparse.SUPPRESS) # allows running as root; implemented outside of webui
|
||||
group.add_argument("--ui-settings-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'config.json'))
|
||||
group.add_argument("--ui-config-file", type=str, help=argparse.SUPPRESS, default=os.path.join(data_path, 'ui-config.json'))
|
||||
group.add_argument("--hide-ui-dir-config", action='store_true', help=argparse.SUPPRESS, default=False)
|
||||
group.add_argument("--theme", type=str, help=argparse.SUPPRESS, default=None)
|
||||
group.add_argument("--disable-console-progressbars", action='store_true', help=argparse.SUPPRESS, default=True)
|
||||
group.add_argument("--disable-safe-unpickle", action='store_true', help=argparse.SUPPRESS, default=True)
|
||||
group.add_argument("--lowram", action='store_true', help=argparse.SUPPRESS)
|
||||
group.add_argument("--disable-extension-access", default = False, action='store_true', help=argparse.SUPPRESS)
|
||||
group.add_argument("--api", help=argparse.SUPPRESS, default=True)
|
||||
|
||||
|
||||
def compatibility_args(opts, args):
|
||||
parser.add_argument("--ckpt-dir", type=str, help=argparse.SUPPRESS, default=opts.ckpt_dir)
|
||||
parser.add_argument("--vae-dir", type=str, help=argparse.SUPPRESS, default=opts.vae_dir)
|
||||
parser.add_argument("--embeddings-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_dir)
|
||||
parser.add_argument("--embeddings-templates-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_templates_dir)
|
||||
parser.add_argument("--hypernetwork-dir", type=str, help=argparse.SUPPRESS, default=opts.hypernetwork_dir)
|
||||
parser.add_argument("--codeformer-models-path", type=str, help=argparse.SUPPRESS, default=opts.codeformer_models_path)
|
||||
parser.add_argument("--gfpgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.gfpgan_models_path)
|
||||
parser.add_argument("--esrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.esrgan_models_path)
|
||||
parser.add_argument("--bsrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.bsrgan_models_path)
|
||||
parser.add_argument("--realesrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.realesrgan_models_path)
|
||||
parser.add_argument("--scunet-models-path", help=argparse.SUPPRESS, default=opts.scunet_models_path)
|
||||
parser.add_argument("--swinir-models-path", help=argparse.SUPPRESS, default=opts.swinir_models_path)
|
||||
parser.add_argument("--ldsr-models-path", help=argparse.SUPPRESS, default=opts.ldsr_models_path)
|
||||
parser.add_argument("--clip-models-path", type=str, help=argparse.SUPPRESS, default=opts.clip_models_path)
|
||||
parser.add_argument("--disable-extension-access", default = False, action='store_true', help=argparse.SUPPRESS)
|
||||
parser.add_argument("--opt-channelslast", help=argparse.SUPPRESS, default=opts.opt_channelslast)
|
||||
parser.add_argument("--xformers", default = (opts.cross_attention_optimization == "xFormers"), action='store_true', help=argparse.SUPPRESS)
|
||||
parser.add_argument("--disable-nan-check", help=argparse.SUPPRESS, default=opts.disable_nan_check)
|
||||
parser.add_argument("--token-merging", help=argparse.SUPPRESS, default=opts.token_merging)
|
||||
parser.add_argument("--rollback-vae", help=argparse.SUPPRESS, default=opts.rollback_vae)
|
||||
parser.add_argument("--no-half", help=argparse.SUPPRESS, default=opts.no_half)
|
||||
parser.add_argument("--no-half-vae", help=argparse.SUPPRESS, default=opts.no_half_vae)
|
||||
parser.add_argument("--precision", help=argparse.SUPPRESS, default=opts.precision)
|
||||
parser.add_argument("--api", help=argparse.SUPPRESS, default=True)
|
||||
parser.add_argument("--sub-quad-q-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_q_chunk_size)
|
||||
parser.add_argument("--sub-quad-kv-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_kv_chunk_size)
|
||||
parser.add_argument("--sub-quad-chunk-threshold", help=argparse.SUPPRESS, default=opts.sub_quad_chunk_threshold)
|
||||
# removed args that have been moved to opts are added here as hidden with default values as defined in opts
|
||||
group.add_argument("--ckpt-dir", type=str, help=argparse.SUPPRESS, default=opts.ckpt_dir)
|
||||
group.add_argument("--vae-dir", type=str, help=argparse.SUPPRESS, default=opts.vae_dir)
|
||||
group.add_argument("--embeddings-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_dir)
|
||||
group.add_argument("--embeddings-templates-dir", type=str, help=argparse.SUPPRESS, default=opts.embeddings_templates_dir)
|
||||
group.add_argument("--hypernetwork-dir", type=str, help=argparse.SUPPRESS, default=opts.hypernetwork_dir)
|
||||
group.add_argument("--codeformer-models-path", type=str, help=argparse.SUPPRESS, default=opts.codeformer_models_path)
|
||||
group.add_argument("--gfpgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.gfpgan_models_path)
|
||||
group.add_argument("--esrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.esrgan_models_path)
|
||||
group.add_argument("--bsrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.bsrgan_models_path)
|
||||
group.add_argument("--realesrgan-models-path", type=str, help=argparse.SUPPRESS, default=opts.realesrgan_models_path)
|
||||
group.add_argument("--scunet-models-path", help=argparse.SUPPRESS, default=opts.scunet_models_path)
|
||||
group.add_argument("--swinir-models-path", help=argparse.SUPPRESS, default=opts.swinir_models_path)
|
||||
group.add_argument("--ldsr-models-path", help=argparse.SUPPRESS, default=opts.ldsr_models_path)
|
||||
group.add_argument("--clip-models-path", type=str, help=argparse.SUPPRESS, default=opts.clip_models_path)
|
||||
group.add_argument("--opt-channelslast", help=argparse.SUPPRESS, default=opts.opt_channelslast)
|
||||
group.add_argument("--xformers", default = (opts.cross_attention_optimization == "xFormers"), action='store_true', help=argparse.SUPPRESS)
|
||||
group.add_argument("--disable-nan-check", help=argparse.SUPPRESS, default=opts.disable_nan_check)
|
||||
group.add_argument("--token-merging", help=argparse.SUPPRESS, default=opts.token_merging)
|
||||
group.add_argument("--rollback-vae", help=argparse.SUPPRESS, default=opts.rollback_vae)
|
||||
group.add_argument("--no-half", help=argparse.SUPPRESS, default=opts.no_half)
|
||||
group.add_argument("--no-half-vae", help=argparse.SUPPRESS, default=opts.no_half_vae)
|
||||
group.add_argument("--precision", help=argparse.SUPPRESS, default=opts.precision)
|
||||
group.add_argument("--sub-quad-q-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_q_chunk_size)
|
||||
group.add_argument("--sub-quad-kv-chunk-size", help=argparse.SUPPRESS, default=opts.sub_quad_kv_chunk_size)
|
||||
group.add_argument("--sub-quad-chunk-threshold", help=argparse.SUPPRESS, default=opts.sub_quad_chunk_threshold)
|
||||
group.add_argument("--lora-dir", help=argparse.SUPPRESS, default=opts.lora_dir)
|
||||
group.add_argument("--lyco-dir", help=argparse.SUPPRESS, default=opts.lyco_dir)
|
||||
|
||||
# removed opts are added here with fixed values for compatibility reasons
|
||||
opts.use_old_emphasis_implementation = False
|
||||
opts.use_old_karras_scheduler_sigmas = False
|
||||
opts.no_dpmpp_sde_batch_determinism = False
|
||||
opts.use_old_hires_fix_width_height = False
|
||||
opts.lora_apply_to_outputs = False
|
||||
opts.do_not_show_images = False
|
||||
opts.add_model_hash_to_info = True
|
||||
opts.add_model_name_to_info = True
|
||||
opts.js_modal_lightbox = True
|
||||
opts.js_modal_lightbox_initially_zoomed = True
|
||||
opts.show_progress_in_title = False
|
||||
opts.sd_vae_as_default = True
|
||||
opts.enable_emphasis = True
|
||||
opts.enable_batch_seeds = True
|
||||
opts.multiple_tqdm = False
|
||||
opts.print_hypernet_extra = False
|
||||
opts.dimensions_and_batch_together = True
|
||||
|
||||
parser.add_argument("--lora-dir", help=argparse.SUPPRESS, default=opts.lora_dir)
|
||||
args = parser.parse_args()
|
||||
if 'lyco_dir' in args:
|
||||
args.lyco_dir = opts.lyco_dir
|
||||
|
||||
return args
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
import math
|
||||
import numpy as np
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from torch import nn, Tensor
|
||||
import torch.nn.functional as F
|
||||
from typing import Optional, List
|
||||
|
||||
@@ -7,6 +7,10 @@ https://github.com/samb-t/unleashing-transformers/blob/master/models/vqgan.py
|
||||
'''
|
||||
import numpy as np
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
import copy
|
||||
|
||||
@@ -3,6 +3,10 @@ import sys
|
||||
|
||||
import cv2
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
import modules.face_restoration
|
||||
from modules import shared, devices, modelloader, errors
|
||||
@@ -103,7 +107,10 @@ def setup_model(dirname):
|
||||
output = self.net(cropped_face_t, w=w if w is not None else shared.opts.code_former_weight, adain=True)[0]
|
||||
restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))
|
||||
del output
|
||||
torch.cuda.empty_cache()
|
||||
if cmd_opts.use_ipex:
|
||||
torch.xpu.empty_cache()
|
||||
else:
|
||||
torch.cuda.empty_cache()
|
||||
except Exception as error:
|
||||
print(f'\tFailed inference for CodeFormer: {error}', file=sys.stderr)
|
||||
restored_face = tensor2img(cropped_face_t, rgb2bgr=True, min_max=(-1, 1))
|
||||
|
||||
@@ -2,6 +2,10 @@ import os
|
||||
import re
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import numpy as np
|
||||
|
||||
from modules import modelloader, paths, deepbooru_model, devices, images, shared
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
|
||||
|
||||
+39
-12
@@ -1,6 +1,11 @@
|
||||
import sys
|
||||
import contextlib
|
||||
import torch
|
||||
from modules import shared
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
if sys.platform == "darwin":
|
||||
from modules import mac_specific
|
||||
@@ -21,18 +26,35 @@ def extract_device_id(args, name):
|
||||
|
||||
|
||||
def get_cuda_device_string():
|
||||
from modules import shared
|
||||
if shared.cmd_opts.use_ipex:
|
||||
return "xpu"
|
||||
else:
|
||||
if shared.cmd_opts.device_id is not None:
|
||||
return f"cuda:{shared.cmd_opts.device_id}"
|
||||
return "cuda"
|
||||
|
||||
|
||||
def get_dml_device_string():
|
||||
if shared.cmd_opts.device_id is not None:
|
||||
return f"cuda:{shared.cmd_opts.device_id}"
|
||||
return "cuda"
|
||||
return f"privateuseone:{shared.cmd_opts.device_id}"
|
||||
return "privateuseone:0"
|
||||
|
||||
|
||||
def get_optimal_device_name():
|
||||
if torch.cuda.is_available():
|
||||
if shared.cmd_opts.use_ipex:
|
||||
return "xpu"
|
||||
elif torch.cuda.is_available():
|
||||
return get_cuda_device_string()
|
||||
if has_mps():
|
||||
return "mps"
|
||||
return "cpu"
|
||||
try:
|
||||
import torch_directml
|
||||
if torch_directml.is_available():
|
||||
return get_dml_device_string()
|
||||
else:
|
||||
return "cpu"
|
||||
except:
|
||||
return "cpu"
|
||||
|
||||
|
||||
def get_optimal_device():
|
||||
@@ -40,21 +62,22 @@ def get_optimal_device():
|
||||
|
||||
|
||||
def get_device_for(task):
|
||||
from modules import shared
|
||||
if task in shared.cmd_opts.use_cpu:
|
||||
return cpu
|
||||
return get_optimal_device()
|
||||
|
||||
|
||||
def torch_gc():
|
||||
if torch.cuda.is_available():
|
||||
if shared.cmd_opts.use_ipex:
|
||||
with torch.xpu.device("xpu"):
|
||||
torch.xpu.empty_cache()
|
||||
elif torch.cuda.is_available():
|
||||
with torch.cuda.device(get_cuda_device_string()):
|
||||
torch.cuda.empty_cache()
|
||||
torch.cuda.ipc_collect()
|
||||
|
||||
|
||||
def set_cuda_params():
|
||||
from modules import shared
|
||||
if torch.cuda.is_available():
|
||||
try:
|
||||
torch.backends.cuda.matmul.allow_tf32 = shared.opts.cuda_allow_tf32
|
||||
@@ -118,16 +141,21 @@ def randn_without_seed(shape):
|
||||
|
||||
|
||||
def autocast(disable=False):
|
||||
from modules import shared
|
||||
if disable:
|
||||
return contextlib.nullcontext()
|
||||
if dtype == torch.float32 or shared.cmd_opts.precision == "Full":
|
||||
return contextlib.nullcontext()
|
||||
return torch.autocast("cuda")
|
||||
if shared.cmd_opts.use_ipex:
|
||||
return torch.xpu.amp.autocast(enabled=True, dtype=dtype, cache_enabled=False)
|
||||
else:
|
||||
return torch.autocast("cuda")
|
||||
|
||||
|
||||
def without_autocast(disable=False):
|
||||
return torch.autocast("cuda", enabled=False) if torch.is_autocast_enabled() and not disable else contextlib.nullcontext()
|
||||
if shared.cmd_opts.use_ipex:
|
||||
return torch.autocast("xpu", enabled=False) if torch.is_autocast_enabled() and not disable else contextlib.nullcontext()
|
||||
else:
|
||||
return torch.autocast("cuda", enabled=False) if torch.is_autocast_enabled() and not disable else contextlib.nullcontext()
|
||||
|
||||
|
||||
class NansException(Exception):
|
||||
@@ -135,7 +163,6 @@ class NansException(Exception):
|
||||
|
||||
|
||||
def test_for_nans(x, where):
|
||||
from modules import shared
|
||||
if shared.opts.disable_nan_check:
|
||||
return
|
||||
if not torch.all(torch.isnan(x)).item():
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import torch
|
||||
import torch_directml
|
||||
|
||||
import modules.dml.hijack
|
||||
|
||||
from .optimizer.unknown import UnknownOptimizer
|
||||
|
||||
class DirectML():
|
||||
def get_optimizer(device: torch.device):
|
||||
assert(device.type == 'privateuseone')
|
||||
try:
|
||||
device_name = torch_directml.device_name(device.index)
|
||||
if 'NVIDIA' in device_name or 'GeForce' in device_name:
|
||||
from .optimizer.nvidia import nVidiaOptimizer as optimizer
|
||||
elif 'AMD' in device_name or 'Radeon' in device_name:
|
||||
from .optimizer.amd import AMDOptimizer as optimizer
|
||||
elif 'Intel' in device_name:
|
||||
from .optimizer.intel import IntelOptimizer as optimizer
|
||||
else:
|
||||
return UnknownOptimizer
|
||||
return optimizer
|
||||
except:
|
||||
return UnknownOptimizer
|
||||
|
||||
def memory_stats(device: torch.device):
|
||||
optimizer = DirectML.get_optimizer(device)
|
||||
return optimizer.memory_stats(device.index)
|
||||
|
||||
# Alternative of torch.cuda for DirectML.
|
||||
torch.dml = DirectML
|
||||
@@ -0,0 +1,5 @@
|
||||
import modules.dml.hijack.kdiffusion
|
||||
import modules.dml.hijack.stablediffusion
|
||||
import modules.dml.hijack.torch
|
||||
import modules.dml.hijack.realesrgan_model
|
||||
import modules.dml.hijack.plms
|
||||
@@ -0,0 +1,89 @@
|
||||
import torch
|
||||
from tqdm.auto import tqdm
|
||||
|
||||
from modules.shared import device
|
||||
from k_diffusion import sampling
|
||||
|
||||
def dpm_solver_adaptive(self, x, t_start, t_end, order=3, rtol=0.05, atol=0.0078, h_init=0.05, pcoeff=0., icoeff=1., dcoeff=0., accept_safety=0.81, eta=0., s_noise=1., noise_sampler=None):
|
||||
noise_sampler = sampling.default_noise_sampler(x) if noise_sampler is None else noise_sampler
|
||||
if order not in {2, 3}:
|
||||
raise ValueError('order should be 2 or 3')
|
||||
forward = t_end > t_start
|
||||
if not forward and eta:
|
||||
raise ValueError('eta must be 0 for reverse sampling')
|
||||
h_init = abs(h_init) * (1 if forward else -1)
|
||||
atol = torch.tensor(atol).to(device)
|
||||
rtol = torch.tensor(rtol).to(device)
|
||||
s = t_start
|
||||
x_prev = x
|
||||
accept = True
|
||||
pid = sampling.PIDStepSizeController(h_init, pcoeff, icoeff, dcoeff, 1.5 if eta else order, accept_safety)
|
||||
info = {'steps': 0, 'nfe': 0, 'n_accept': 0, 'n_reject': 0}
|
||||
|
||||
while s < t_end - 1e-5 if forward else s > t_end + 1e-5:
|
||||
eps_cache = {}
|
||||
t = torch.minimum(t_end, s + pid.h) if forward else torch.maximum(t_end, s + pid.h)
|
||||
if eta:
|
||||
sd, su = sampling.get_ancestral_step(self.sigma(s), self.sigma(t), eta)
|
||||
t_ = torch.minimum(t_end, self.t(sd))
|
||||
su = (self.sigma(t) ** 2 - self.sigma(t_) ** 2) ** 0.5
|
||||
else:
|
||||
t_, su = t, 0.
|
||||
|
||||
eps, eps_cache = self.eps(eps_cache, 'eps', x, s)
|
||||
denoised = x - self.sigma(s) * eps
|
||||
|
||||
if order == 2:
|
||||
x_low, eps_cache = self.dpm_solver_1_step(x, s, t_, eps_cache=eps_cache)
|
||||
x_high, eps_cache = self.dpm_solver_2_step(x, s, t_, eps_cache=eps_cache)
|
||||
else:
|
||||
x_low, eps_cache = self.dpm_solver_2_step(x, s, t_, r1=1 / 3, eps_cache=eps_cache)
|
||||
x_high, eps_cache = self.dpm_solver_3_step(x, s, t_, eps_cache=eps_cache)
|
||||
delta = torch.maximum(atol, rtol * torch.maximum(x_low.abs(), x_prev.abs()))
|
||||
error = torch.linalg.norm((x_low - x_high) / delta) / x.numel() ** 0.5
|
||||
accept = pid.propose_step(error)
|
||||
if accept:
|
||||
x_prev = x_low
|
||||
x = x_high + su * s_noise * noise_sampler(self.sigma(s), self.sigma(t))
|
||||
s = t
|
||||
info['n_accept'] += 1
|
||||
else:
|
||||
info['n_reject'] += 1
|
||||
info['nfe'] += order
|
||||
info['steps'] += 1
|
||||
|
||||
if self.info_callback is not None:
|
||||
self.info_callback({'x': x, 'i': info['steps'] - 1, 't': s, 't_up': s, 'denoised': denoised, 'error': error, 'h': pid.h, **info})
|
||||
|
||||
return x, info
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
def sample_dpm_fast(model, x, sigma_min, sigma_max, n, extra_args=None, callback=None, disable=None, eta=0., s_noise=1., noise_sampler=None):
|
||||
"""DPM-Solver-Fast (fixed step size). See https://arxiv.org/abs/2206.00927."""
|
||||
if sigma_min <= 0 or sigma_max <= 0:
|
||||
raise ValueError('sigma_min and sigma_max must not be 0')
|
||||
with tqdm(total=n, disable=disable) as pbar:
|
||||
dpm_solver = sampling.DPMSolver(model, extra_args, eps_callback=pbar.update)
|
||||
if callback is not None:
|
||||
dpm_solver.info_callback = lambda info: callback({'sigma': dpm_solver.sigma(info['t']), 'sigma_hat': dpm_solver.sigma(info['t_up']), **info})
|
||||
return dpm_solver.dpm_solver_fast(x, dpm_solver.t(torch.tensor(sigma_max).to(device)), dpm_solver.t(torch.tensor(sigma_min).to(device)), n, eta, s_noise, noise_sampler)
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
def sample_dpm_adaptive(model, x, sigma_min, sigma_max, extra_args=None, callback=None, disable=None, order=3, rtol=0.05, atol=0.0078, h_init=0.05, pcoeff=0., icoeff=1., dcoeff=0., accept_safety=0.81, eta=0., s_noise=1., noise_sampler=None, return_info=False):
|
||||
"""DPM-Solver-12 and 23 (adaptive step size). See https://arxiv.org/abs/2206.00927."""
|
||||
if sigma_min <= 0 or sigma_max <= 0:
|
||||
raise ValueError('sigma_min and sigma_max must not be 0')
|
||||
with tqdm(disable=disable) as pbar:
|
||||
dpm_solver = sampling.DPMSolver(model, extra_args, eps_callback=pbar.update)
|
||||
if callback is not None:
|
||||
dpm_solver.info_callback = lambda info: callback({'sigma': dpm_solver.sigma(info['t']), 'sigma_hat': dpm_solver.sigma(info['t_up']), **info})
|
||||
x, info = dpm_solver.dpm_solver_adaptive(x, dpm_solver.t(torch.tensor(sigma_max).to(device)), dpm_solver.t(torch.tensor(sigma_min).to(device)), order, rtol, atol, h_init, pcoeff, icoeff, dcoeff, accept_safety, eta, s_noise, noise_sampler)
|
||||
if return_info:
|
||||
return x, info
|
||||
return x
|
||||
|
||||
sampling.DPMSolver.dpm_solver_adaptive = dpm_solver_adaptive
|
||||
sampling.sample_dpm_fast = sample_dpm_fast
|
||||
sampling.sample_dpm_adaptive = sample_dpm_adaptive
|
||||
@@ -0,0 +1,91 @@
|
||||
import torch
|
||||
|
||||
from ldm.models.diffusion.ddim import noise_like
|
||||
|
||||
import modules.sd_hijack_inpainting as plms_hijack
|
||||
|
||||
|
||||
@torch.no_grad()
|
||||
def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
|
||||
temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
|
||||
unconditional_guidance_scale=1., unconditional_conditioning=None, old_eps=None, t_next=None, dynamic_threshold=None):
|
||||
b, *_, device = *x.shape, x.device
|
||||
|
||||
def get_model_output(x, t):
|
||||
if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
|
||||
e_t = self.model.apply_model(x, t, c)
|
||||
else:
|
||||
x_in = torch.cat([x] * 2)
|
||||
t_in = torch.cat([t] * 2)
|
||||
|
||||
if isinstance(c, dict):
|
||||
assert isinstance(unconditional_conditioning, dict)
|
||||
c_in = dict()
|
||||
for k in c:
|
||||
if isinstance(c[k], list):
|
||||
c_in[k] = [
|
||||
torch.cat([unconditional_conditioning[k][i], c[k][i]])
|
||||
for i in range(len(c[k]))
|
||||
]
|
||||
else:
|
||||
c_in[k] = torch.cat([unconditional_conditioning[k], c[k]])
|
||||
else:
|
||||
c_in = torch.cat([unconditional_conditioning, c])
|
||||
|
||||
e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
|
||||
e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)
|
||||
|
||||
if score_corrector is not None:
|
||||
assert self.model.parameterization == "eps"
|
||||
e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
|
||||
|
||||
return e_t
|
||||
|
||||
alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
|
||||
alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
|
||||
sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
|
||||
sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
|
||||
|
||||
def get_x_prev_and_pred_x0(e_t, index):
|
||||
# select parameters corresponding to the currently considered timestep
|
||||
print(alphas[index]) # DML Solution: PLMS Sampling does not work without this print.
|
||||
a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
|
||||
a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
|
||||
sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
|
||||
sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device)
|
||||
|
||||
# current prediction for x_0
|
||||
pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
|
||||
if quantize_denoised:
|
||||
pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
|
||||
if dynamic_threshold is not None:
|
||||
from ldm.models.diffusion.sampling_util import norm_thresholding
|
||||
pred_x0 = norm_thresholding(pred_x0, dynamic_threshold)
|
||||
# direction pointing to x_t
|
||||
dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t
|
||||
noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
|
||||
if noise_dropout > 0.:
|
||||
noise = torch.nn.functional.dropout(noise, p=noise_dropout)
|
||||
x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
|
||||
return x_prev, pred_x0
|
||||
|
||||
e_t = get_model_output(x, t)
|
||||
if len(old_eps) == 0:
|
||||
# Pseudo Improved Euler (2nd order)
|
||||
x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t, index)
|
||||
e_t_next = get_model_output(x_prev, t_next)
|
||||
e_t_prime = (e_t + e_t_next) / 2
|
||||
elif len(old_eps) == 1:
|
||||
# 2nd order Pseudo Linear Multistep (Adams-Bashforth)
|
||||
e_t_prime = (3 * e_t - old_eps[-1]) / 2
|
||||
elif len(old_eps) == 2:
|
||||
# 3nd order Pseudo Linear Multistep (Adams-Bashforth)
|
||||
e_t_prime = (23 * e_t - 16 * old_eps[-1] + 5 * old_eps[-2]) / 12
|
||||
elif len(old_eps) >= 3:
|
||||
# 4nd order Pseudo Linear Multistep (Adams-Bashforth)
|
||||
e_t_prime = (55 * e_t - 59 * old_eps[-1] + 37 * old_eps[-2] - 9 * old_eps[-3]) / 24
|
||||
|
||||
x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t_prime, index)
|
||||
|
||||
return x_prev, pred_x0, e_t
|
||||
plms_hijack.p_sample_plms = p_sample_plms
|
||||
@@ -0,0 +1,69 @@
|
||||
import math
|
||||
import torch
|
||||
|
||||
from realesrgan import RealESRGANer
|
||||
|
||||
|
||||
# DML Solution: Some tensors turn 0 after Extended Slices. Move output to cpu and get it back.
|
||||
def tile_process(self):
|
||||
batch, channel, height, width = self.img.shape
|
||||
output_height = height * self.scale
|
||||
output_width = width * self.scale
|
||||
output_shape = (batch, channel, output_height, output_width)
|
||||
|
||||
# start with black image
|
||||
self.output = self.img.new_zeros(output_shape, device='cpu')
|
||||
tiles_x = math.ceil(width / self.tile_size)
|
||||
tiles_y = math.ceil(height / self.tile_size)
|
||||
|
||||
# loop over all tiles
|
||||
for y in range(tiles_y):
|
||||
for x in range(tiles_x):
|
||||
# extract tile from input image
|
||||
ofs_x = x * self.tile_size
|
||||
ofs_y = y * self.tile_size
|
||||
# input tile area on total image
|
||||
input_start_x = ofs_x
|
||||
input_end_x = min(ofs_x + self.tile_size, width)
|
||||
input_start_y = ofs_y
|
||||
input_end_y = min(ofs_y + self.tile_size, height)
|
||||
|
||||
# input tile area on total image with padding
|
||||
input_start_x_pad = max(input_start_x - self.tile_pad, 0)
|
||||
input_end_x_pad = min(input_end_x + self.tile_pad, width)
|
||||
input_start_y_pad = max(input_start_y - self.tile_pad, 0)
|
||||
input_end_y_pad = min(input_end_y + self.tile_pad, height)
|
||||
|
||||
# input tile dimensions
|
||||
input_tile_width = input_end_x - input_start_x
|
||||
input_tile_height = input_end_y - input_start_y
|
||||
tile_idx = y * tiles_x + x + 1
|
||||
input_tile = self.img[:, :, input_start_y_pad:input_end_y_pad, input_start_x_pad:input_end_x_pad]
|
||||
|
||||
# upscale tile
|
||||
try:
|
||||
with torch.no_grad():
|
||||
output_tile = self.model(input_tile)
|
||||
output_tile = output_tile.cpu()
|
||||
except RuntimeError as error:
|
||||
print('Error', error)
|
||||
print(f'\tTile {tile_idx}/{tiles_x * tiles_y}')
|
||||
|
||||
# output tile area on total image
|
||||
output_start_x = input_start_x * self.scale
|
||||
output_end_x = input_end_x * self.scale
|
||||
output_start_y = input_start_y * self.scale
|
||||
output_end_y = input_end_y * self.scale
|
||||
|
||||
# output tile area without padding
|
||||
output_start_x_tile = (input_start_x - input_start_x_pad) * self.scale
|
||||
output_end_x_tile = output_start_x_tile + input_tile_width * self.scale
|
||||
output_start_y_tile = (input_start_y - input_start_y_pad) * self.scale
|
||||
output_end_y_tile = output_start_y_tile + input_tile_height * self.scale
|
||||
|
||||
# put tile into output image
|
||||
self.output[:, :, output_start_y:output_end_y,
|
||||
output_start_x:output_end_x] = output_tile[:, :, output_start_y_tile:output_end_y_tile,
|
||||
output_start_x_tile:output_end_x_tile]
|
||||
self.output = self.output.to(self.device)
|
||||
RealESRGANer.tile_process = tile_process
|
||||
@@ -0,0 +1,80 @@
|
||||
import torch
|
||||
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.modules.diffusionmodules.util import noise_like
|
||||
|
||||
@torch.no_grad()
|
||||
def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
|
||||
temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
|
||||
unconditional_guidance_scale=1., unconditional_conditioning=None,
|
||||
dynamic_threshold=None):
|
||||
b, *_, device = *x.shape, x.device
|
||||
|
||||
if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
|
||||
model_output = self.model.apply_model(x, t, c)
|
||||
else:
|
||||
x_in = torch.cat([x] * 2)
|
||||
t_in = torch.cat([t] * 2)
|
||||
if isinstance(c, dict):
|
||||
assert isinstance(unconditional_conditioning, dict)
|
||||
c_in = dict()
|
||||
for k in c:
|
||||
if isinstance(c[k], list):
|
||||
c_in[k] = [torch.cat([
|
||||
unconditional_conditioning[k][i],
|
||||
c[k][i]]) for i in range(len(c[k]))]
|
||||
else:
|
||||
c_in[k] = torch.cat([
|
||||
unconditional_conditioning[k],
|
||||
c[k]])
|
||||
elif isinstance(c, list):
|
||||
c_in = list()
|
||||
assert isinstance(unconditional_conditioning, list)
|
||||
for i in range(len(c)):
|
||||
c_in.append(torch.cat([unconditional_conditioning[i], c[i]]))
|
||||
else:
|
||||
c_in = torch.cat([unconditional_conditioning, c])
|
||||
model_uncond, model_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
|
||||
model_output = model_uncond + unconditional_guidance_scale * (model_t - model_uncond)
|
||||
|
||||
if self.model.parameterization == "v":
|
||||
e_t = self.model.predict_eps_from_z_and_v(x, t, model_output)
|
||||
else:
|
||||
e_t = model_output
|
||||
|
||||
if score_corrector is not None:
|
||||
assert self.model.parameterization == "eps", 'not implemented'
|
||||
e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
|
||||
|
||||
alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
|
||||
alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
|
||||
sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
|
||||
sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
|
||||
# select parameters corresponding to the currently considered timestep
|
||||
print(alphas[index]) # DML Solution: DDIM Sampling does not work without this print.
|
||||
a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
|
||||
a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
|
||||
sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
|
||||
sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device)
|
||||
|
||||
# current prediction for x_0
|
||||
if self.model.parameterization != "v":
|
||||
pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
|
||||
else:
|
||||
pred_x0 = self.model.predict_start_from_z_and_v(x, t, model_output)
|
||||
|
||||
if quantize_denoised:
|
||||
pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
|
||||
|
||||
if dynamic_threshold is not None:
|
||||
raise NotImplementedError()
|
||||
|
||||
# direction pointing to x_t
|
||||
dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t
|
||||
noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
|
||||
if noise_dropout > 0.:
|
||||
noise = torch.nn.functional.dropout(noise, p=noise_dropout)
|
||||
x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
|
||||
return x_prev, pred_x0
|
||||
|
||||
DDIMSampler.p_sample_ddim = p_sample_ddim
|
||||
@@ -0,0 +1,5 @@
|
||||
import torch
|
||||
|
||||
from modules.sd_hijack_utils import CondFunc
|
||||
|
||||
CondFunc('torchsde._brownian.brownian_interval._randn', lambda _, size, dtype, device, seed: torch.randn(size, dtype=dtype, device=torch.device("cpu"), generator=torch.Generator(torch.device("cpu")).manual_seed(int(seed))).to(device), lambda _, size, dtype, device, seed: device.type == 'privateuseone')
|
||||
@@ -0,0 +1,7 @@
|
||||
from modules.dml.optimizer.optimizer import Optimizer
|
||||
from .driver.atiadlxx import ATIADLxx
|
||||
|
||||
class AMDOptimizer(Optimizer):
|
||||
driver: ATIADLxx = ATIADLxx()
|
||||
def memory_stats(index):
|
||||
return (AMDOptimizer.driver.iHyperMemorySize, AMDOptimizer.driver.get_dedicated_vram_usage(index))
|
||||
@@ -0,0 +1,46 @@
|
||||
import ctypes as C
|
||||
from .atiadlxx_apis import *
|
||||
from .atiadlxx_structures import *
|
||||
from .atiadlxx_defines import *
|
||||
|
||||
class ATIADLxx(object):
|
||||
iHyperMemorySize = 0
|
||||
|
||||
def __init__(self):
|
||||
self.context = ADL_CONTEXT_HANDLE()
|
||||
ADL2_Main_Control_Create(ADL_Main_Memory_Alloc, 1, C.byref(self.context))
|
||||
num_adapters = C.c_int(-1)
|
||||
ADL2_Adapter_NumberOfAdapters_Get(self.context, C.byref(num_adapters))
|
||||
AdapterInfoArray = (AdapterInfo * num_adapters.value)()
|
||||
ADL2_Adapter_AdapterInfo_Get(self.context, C.cast(AdapterInfoArray, LPAdapterInfo), C.sizeof(AdapterInfoArray))
|
||||
self.devices = []
|
||||
busNumbers = []
|
||||
for adapter in AdapterInfoArray:
|
||||
if adapter.iBusNumber not in busNumbers: # filter duplicate device
|
||||
self.devices.append(adapter)
|
||||
busNumbers.append(adapter.iBusNumber)
|
||||
self.iHyperMemorySize = self.get_memory_info2(0).iHyperMemorySize
|
||||
|
||||
def get_memory_info2(self, adapterIndex: int) -> ADLMemoryInfo2:
|
||||
info = ADLMemoryInfo2()
|
||||
|
||||
if ADL2_Adapter_MemoryInfo2_Get(self.context, adapterIndex, C.byref(info)) != ADL_OK:
|
||||
raise RuntimeError("ADL2: Failed to get MemoryInfo2")
|
||||
|
||||
return info
|
||||
|
||||
def get_dedicated_vram_usage(self, index: int) -> int:
|
||||
usage = C.c_int(-1)
|
||||
|
||||
if ADL2_Adapter_DedicatedVRAMUsage_Get(self.context, self.devices[index].iAdapterIndex, C.byref(usage)) != ADL_OK:
|
||||
raise RuntimeError("ADL2: Failed to get DedicatedVRAMUsage")
|
||||
|
||||
return usage.value
|
||||
|
||||
def get_vram_usage(self, index: int) -> int:
|
||||
usage = C.c_int(-1)
|
||||
|
||||
if ADL2_Adapter_VRAMUsage_Get(self.context, self.devices[index].iAdapterIndex, C.byref(usage)) != ADL_OK:
|
||||
raise RuntimeError("ADL2: Failed to get VRAMUsage")
|
||||
|
||||
return usage.value
|
||||
@@ -0,0 +1,45 @@
|
||||
import ctypes as C
|
||||
from platform import platform
|
||||
from .atiadlxx_structures import *
|
||||
|
||||
if 'Windows' in platform():
|
||||
atiadlxx = C.WinDLL("atiadlxx.dll")
|
||||
else:
|
||||
atiadlxx = C.CDLL("libatiadlxx.so") # Not tested on Linux system. But will be supported.
|
||||
|
||||
ADL_MAIN_MALLOC_CALLBACK = C.CFUNCTYPE(C.c_void_p, C.c_int)
|
||||
ADL_MAIN_FREE_CALLBACK = C.CFUNCTYPE(None, C.POINTER(C.c_void_p))
|
||||
|
||||
@ADL_MAIN_MALLOC_CALLBACK
|
||||
def ADL_Main_Memory_Alloc(iSize):
|
||||
return C._malloc(iSize)
|
||||
|
||||
@ADL_MAIN_FREE_CALLBACK
|
||||
def ADL_Main_Memory_Free(lpBuffer):
|
||||
if lpBuffer[0] is not None:
|
||||
C._free(lpBuffer[0])
|
||||
lpBuffer[0] = None
|
||||
|
||||
ADL2_Main_Control_Create = atiadlxx.ADL2_Main_Control_Create
|
||||
ADL2_Main_Control_Create.restype = C.c_int
|
||||
ADL2_Main_Control_Create.argtypes = [ADL_MAIN_MALLOC_CALLBACK, C.c_int, ADL_CONTEXT_HANDLE]
|
||||
|
||||
ADL2_Adapter_NumberOfAdapters_Get = atiadlxx.ADL2_Adapter_NumberOfAdapters_Get
|
||||
ADL2_Adapter_NumberOfAdapters_Get.restype = C.c_int
|
||||
ADL2_Adapter_NumberOfAdapters_Get.argtypes = [ADL_CONTEXT_HANDLE, C.POINTER(C.c_int)]
|
||||
|
||||
ADL2_Adapter_AdapterInfo_Get = atiadlxx.ADL2_Adapter_AdapterInfo_Get
|
||||
ADL2_Adapter_AdapterInfo_Get.restype = C.c_int
|
||||
ADL2_Adapter_AdapterInfo_Get.argtypes = [ADL_CONTEXT_HANDLE, LPAdapterInfo, C.c_int]
|
||||
|
||||
ADL2_Adapter_MemoryInfo2_Get = atiadlxx.ADL2_Adapter_MemoryInfo2_Get
|
||||
ADL2_Adapter_MemoryInfo2_Get.restype = C.c_int
|
||||
ADL2_Adapter_MemoryInfo2_Get.argtypes = [ADL_CONTEXT_HANDLE, C.c_int, C.POINTER(ADLMemoryInfo2)]
|
||||
|
||||
ADL2_Adapter_DedicatedVRAMUsage_Get = atiadlxx.ADL2_Adapter_DedicatedVRAMUsage_Get
|
||||
ADL2_Adapter_DedicatedVRAMUsage_Get.restype = C.c_int
|
||||
ADL2_Adapter_DedicatedVRAMUsage_Get.argtypes = [ADL_CONTEXT_HANDLE, C.c_int, C.POINTER(C.c_int)]
|
||||
|
||||
ADL2_Adapter_VRAMUsage_Get = atiadlxx.ADL2_Adapter_VRAMUsage_Get
|
||||
ADL2_Adapter_VRAMUsage_Get.restype = C.c_int
|
||||
ADL2_Adapter_VRAMUsage_Get.argtypes = [ADL_CONTEXT_HANDLE, C.c_int, C.POINTER(C.c_int)]
|
||||
@@ -0,0 +1 @@
|
||||
ADL_OK = 0
|
||||
@@ -0,0 +1,87 @@
|
||||
import ctypes as C
|
||||
|
||||
class _ADLPMActivity(C.Structure):
|
||||
__slot__ = [
|
||||
'iActivityPercent',
|
||||
'iCurrentBusLanes',
|
||||
'iCurrentBusSpeed',
|
||||
'iCurrentPerformanceLevel',
|
||||
'iEngineClock',
|
||||
'iMaximumBusLanes',
|
||||
'iMemoryClock',
|
||||
'iReserved',
|
||||
'iSize',
|
||||
'iVddc',
|
||||
]
|
||||
_ADLPMActivity._fields_ = [
|
||||
('iActivityPercent', C.c_int),
|
||||
('iCurrentBusLanes', C.c_int),
|
||||
('iCurrentBusSpeed', C.c_int),
|
||||
('iCurrentPerformanceLevel', C.c_int),
|
||||
('iEngineClock', C.c_int),
|
||||
('iMaximumBusLanes', C.c_int),
|
||||
('iMemoryClock', C.c_int),
|
||||
('iReserved', C.c_int),
|
||||
('iSize', C.c_int),
|
||||
('iVddc', C.c_int),
|
||||
]
|
||||
ADLPMActivity = _ADLPMActivity
|
||||
|
||||
class _ADLMemoryInfo2(C.Structure):
|
||||
__slot__ = [
|
||||
'iHyperMemorySize',
|
||||
'iInvisibleMemorySize',
|
||||
'iMemoryBandwidth',
|
||||
'iMemorySize',
|
||||
'iVisibleMemorySize',
|
||||
'strMemoryType'
|
||||
]
|
||||
_ADLMemoryInfo2._fields_ = [
|
||||
('iHyperMemorySize', C.c_longlong),
|
||||
('iInvisibleMemorySize', C.c_longlong),
|
||||
('iMemoryBandwidth', C.c_longlong),
|
||||
('iMemorySize', C.c_longlong),
|
||||
('iVisibleMemorySize', C.c_longlong),
|
||||
('strMemoryType', C.c_char * 256)
|
||||
]
|
||||
ADLMemoryInfo2 = _ADLMemoryInfo2
|
||||
|
||||
class _AdapterInfo(C.Structure):
|
||||
__slot__ = [
|
||||
'iSize',
|
||||
'iAdapterIndex',
|
||||
'strUDID',
|
||||
'iBusNumber',
|
||||
'iDeviceNumber',
|
||||
'iFunctionNumber',
|
||||
'iVendorID',
|
||||
'strAdapterName',
|
||||
'strDisplayName',
|
||||
'iPresent',
|
||||
'iExist',
|
||||
'strDriverPath',
|
||||
'strDriverPathExt',
|
||||
'strPNPString',
|
||||
'iOSDisplayIndex',
|
||||
]
|
||||
_AdapterInfo._fields_ = [
|
||||
('iSize', C.c_int),
|
||||
('iAdapterIndex', C.c_int),
|
||||
('strUDID', C.c_char * 256),
|
||||
('iBusNumber', C.c_int),
|
||||
('iDeviceNumber', C.c_int),
|
||||
('iFunctionNumber', C.c_int),
|
||||
('iVendorID', C.c_int),
|
||||
('strAdapterName', C.c_char * 256),
|
||||
('strDisplayName', C.c_char * 256),
|
||||
('iPresent', C.c_int),
|
||||
('iExist', C.c_int),
|
||||
('strDriverPath', C.c_char * 256),
|
||||
('strDriverPathExt', C.c_char * 256),
|
||||
('strPNPString', C.c_char * 256),
|
||||
('iOSDisplayIndex', C.c_int)
|
||||
]
|
||||
AdapterInfo = _AdapterInfo
|
||||
LPAdapterInfo = C.POINTER(_AdapterInfo)
|
||||
|
||||
ADL_CONTEXT_HANDLE = C.c_void_p
|
||||
@@ -0,0 +1,7 @@
|
||||
from modules.dml.optimizer.optimizer import Optimizer
|
||||
|
||||
class IntelOptimizer(Optimizer):
|
||||
def memory_stats(index):
|
||||
raise NotImplementedError()
|
||||
# DML TODO: Implement
|
||||
return
|
||||
@@ -0,0 +1,7 @@
|
||||
from modules.dml.optimizer.optimizer import Optimizer
|
||||
|
||||
class nVidiaOptimizer(Optimizer):
|
||||
def memory_stats(index):
|
||||
raise NotImplementedError()
|
||||
# DML TODO: Implement
|
||||
return
|
||||
@@ -0,0 +1,8 @@
|
||||
from abc import *
|
||||
from typing import *
|
||||
|
||||
class Optimizer(metaclass=ABCMeta):
|
||||
driver: Any = None
|
||||
@abstractmethod
|
||||
def memory_stats(index: int) -> Tuple[int, int]:
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
from modules.dml.optimizer.optimizer import Optimizer
|
||||
|
||||
class UnknownOptimizer(Optimizer):
|
||||
def memory_stats(index):
|
||||
# DML TODO: Implement
|
||||
return (1073741824, 0)
|
||||
@@ -2,6 +2,10 @@ import os
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from PIL import Image
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
import math
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ import html
|
||||
import shutil
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import tqdm
|
||||
import gradio as gr
|
||||
import safetensors.torch
|
||||
|
||||
@@ -316,7 +316,7 @@ infotext_to_setting_name_mapping = [
|
||||
('Token merging merge attention', 'token_merging_merge_attention'),
|
||||
('Token merging merge cross attention', 'token_merging_merge_cross_attention'),
|
||||
('Token merging merge mlp', 'token_merging_merge_mlp'),
|
||||
('Token merging maximum downsampling', 'token_merging_maximum_downsampling'),
|
||||
('Token merging maximum downsampling', 'token_merging_maximum_down_sampling'),
|
||||
('Token merging stride x', 'token_merging_stride_x'),
|
||||
('Token merging stride y', 'token_merging_stride_y')
|
||||
]
|
||||
|
||||
@@ -8,6 +8,10 @@ import inspect
|
||||
|
||||
import modules.textual_inversion.dataset
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import tqdm
|
||||
from einops import rearrange, repeat
|
||||
from ldm.util import default
|
||||
@@ -591,7 +595,10 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi
|
||||
print("Cannot resume from saved optimizer!")
|
||||
print(e)
|
||||
|
||||
scaler = torch.cuda.amp.GradScaler()
|
||||
if shared.cmd_opts.use_ipex:
|
||||
scaler = torch.xpu.amp.GradScaler()
|
||||
else:
|
||||
scaler = torch.cuda.amp.GradScaler()
|
||||
|
||||
batch_size = ds.batch_size
|
||||
gradient_step = ds.gradient_step
|
||||
@@ -708,7 +715,9 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi
|
||||
hypernetwork.eval()
|
||||
rng_state = torch.get_rng_state()
|
||||
cuda_rng_state = None
|
||||
if torch.cuda.is_available():
|
||||
if shared.cmd_opts.use_ipex:
|
||||
cuda_rng_state = torch.xpu.get_rng_state_all()
|
||||
elif torch.cuda.is_available():
|
||||
cuda_rng_state = torch.cuda.get_rng_state_all()
|
||||
shared.sd_model.cond_stage_model.to(devices.device)
|
||||
shared.sd_model.first_stage_model.to(devices.device)
|
||||
@@ -745,7 +754,9 @@ def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradi
|
||||
shared.sd_model.cond_stage_model.to(devices.cpu)
|
||||
shared.sd_model.first_stage_model.to(devices.cpu)
|
||||
torch.set_rng_state(rng_state)
|
||||
if torch.cuda.is_available():
|
||||
if shared.cmd_opts.use_ipex:
|
||||
torch.xpu.set_rng_state_all(cuda_rng_state)
|
||||
elif torch.cuda.is_available():
|
||||
torch.cuda.set_rng_state_all(cuda_rng_state)
|
||||
hypernetwork.train()
|
||||
if image is not None:
|
||||
|
||||
+12
-40
@@ -1,47 +1,35 @@
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
from PIL import Image, ImageOps, ImageFilter, ImageEnhance, ImageChops, UnidentifiedImageError
|
||||
|
||||
import modules.scripts
|
||||
from modules import sd_samplers
|
||||
from modules.generation_parameters_copypaste import create_override_settings_dict
|
||||
from modules.processing import Processed, StableDiffusionProcessingImg2Img, process_images
|
||||
from modules.shared import opts, state
|
||||
import modules.shared as shared
|
||||
import modules.processing as processing
|
||||
from modules.processing import Processed, StableDiffusionProcessingImg2Img, process_images, memory_stats
|
||||
from modules.shared import opts, cmd_opts, log, state, listfiles, sd_model
|
||||
from modules.ui import plaintext_to_html
|
||||
import modules.scripts
|
||||
import modules.processing as processing
|
||||
|
||||
|
||||
def process_batch(p, input_dir, output_dir, inpaint_mask_dir, args):
|
||||
processing.fix_seed(p)
|
||||
|
||||
images = shared.listfiles(input_dir)
|
||||
|
||||
images = listfiles(input_dir)
|
||||
is_inpaint_batch = False
|
||||
if inpaint_mask_dir:
|
||||
inpaint_masks = shared.listfiles(inpaint_mask_dir)
|
||||
inpaint_masks = listfiles(inpaint_mask_dir)
|
||||
is_inpaint_batch = len(inpaint_masks) > 0
|
||||
if is_inpaint_batch:
|
||||
print(f"\nInpaint batch is enabled. {len(inpaint_masks)} masks found.")
|
||||
|
||||
print(f"Will process {len(images)} images, creating {p.n_iter * p.batch_size} new images for each.")
|
||||
|
||||
save_normally = output_dir == ''
|
||||
|
||||
p.do_not_save_grid = True
|
||||
p.do_not_save_samples = not save_normally
|
||||
|
||||
state.job_count = len(images) * p.n_iter
|
||||
|
||||
for i, image in enumerate(images):
|
||||
state.job = f"{i+1} out of {len(images)}"
|
||||
if state.skipped:
|
||||
state.skipped = False
|
||||
|
||||
if state.interrupted:
|
||||
break
|
||||
|
||||
try:
|
||||
img = Image.open(image)
|
||||
except UnidentifiedImageError:
|
||||
@@ -62,26 +50,24 @@ def process_batch(p, input_dir, output_dir, inpaint_mask_dir, args):
|
||||
proc = modules.scripts.scripts_img2img.run(p, *args)
|
||||
if proc is None:
|
||||
proc = process_images(p)
|
||||
|
||||
for n, processed_image in enumerate(proc.images):
|
||||
filename = os.path.basename(image)
|
||||
|
||||
if n > 0:
|
||||
left, right = os.path.splitext(filename)
|
||||
filename = f"{left}-{n}{right}"
|
||||
|
||||
if not save_normally:
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
if processed_image.mode == 'RGBA':
|
||||
processed_image = processed_image.convert("RGB")
|
||||
processed_image.save(os.path.join(output_dir, filename))
|
||||
if cmd_opts.debug:
|
||||
log.info(f'Processed: {len(images)} Memory: {memory_stats()} batch')
|
||||
|
||||
|
||||
def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_styles, init_img, sketch, init_img_with_mask, inpaint_color_sketch, inpaint_color_sketch_orig, init_img_inpaint, init_mask_inpaint, steps: int, sampler_index: int, mask_blur: int, mask_alpha: float, inpainting_fill: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_input_dir: str, img2img_batch_output_dir: str, img2img_batch_inpaint_mask_dir: str, override_settings_texts, *args): # pylint: disable=unused-argument
|
||||
override_settings = create_override_settings_dict(override_settings_texts)
|
||||
|
||||
is_batch = mode == 5
|
||||
|
||||
if mode == 0: # img2img
|
||||
image = init_img.convert("RGB")
|
||||
mask = None
|
||||
@@ -108,15 +94,12 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
|
||||
else:
|
||||
image = None
|
||||
mask = None
|
||||
|
||||
# Use the EXIF orientation of photos taken by smartphones.
|
||||
if image is not None:
|
||||
image = ImageOps.exif_transpose(image)
|
||||
|
||||
assert 0. <= denoising_strength <= 1., 'can only work with strength in [0.0, 1.0]'
|
||||
|
||||
p = StableDiffusionProcessingImg2Img(
|
||||
sd_model=shared.sd_model,
|
||||
sd_model=sd_model,
|
||||
outpath_samples=opts.outdir_samples or opts.outdir_img2img_samples,
|
||||
outpath_grids=opts.outdir_grids or opts.outdir_img2img_grids,
|
||||
prompt=prompt,
|
||||
@@ -149,31 +132,20 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
|
||||
inpainting_mask_invert=inpainting_mask_invert,
|
||||
override_settings=override_settings,
|
||||
)
|
||||
|
||||
p.scripts = modules.scripts.scripts_img2img
|
||||
p.script_args = args
|
||||
|
||||
if mask:
|
||||
p.extra_generation_params["Mask blur"] = mask_blur
|
||||
|
||||
if is_batch:
|
||||
assert not shared.cmd_opts.hide_ui_dir_config, "Launched with --hide-ui-dir-config, batch img2img disabled"
|
||||
|
||||
assert not cmd_opts.hide_ui_dir_config, "Launched with --hide-ui-dir-config, batch img2img disabled"
|
||||
process_batch(p, img2img_batch_input_dir, img2img_batch_output_dir, img2img_batch_inpaint_mask_dir, args)
|
||||
|
||||
processed = Processed(p, [], p.seed, "")
|
||||
else:
|
||||
processed = modules.scripts.scripts_img2img.run(p, *args)
|
||||
if processed is None:
|
||||
processed = process_images(p)
|
||||
|
||||
p.close()
|
||||
|
||||
shared.total_tqdm.clear()
|
||||
|
||||
generation_info_js = processed.js()
|
||||
|
||||
if opts.do_not_show_images:
|
||||
processed.images = []
|
||||
|
||||
if cmd_opts.debug:
|
||||
log.info(f'Processed: {len(processed.images)} Memory: {memory_stats()} img')
|
||||
return processed.images, generation_info_js, plaintext_to_html(processed.info), plaintext_to_html(processed.comments)
|
||||
|
||||
@@ -5,6 +5,10 @@ from pathlib import Path
|
||||
import re
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import torch.hub
|
||||
|
||||
from torchvision import transforms
|
||||
|
||||
+1
-1
Submodule modules/lora updated: d52c524fc2...bc803e01c7
@@ -1,4 +1,8 @@
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from modules import devices
|
||||
|
||||
module_in_gpu = None
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import platform
|
||||
from modules.sd_hijack_utils import CondFunc
|
||||
from packaging import version
|
||||
|
||||
+42
-26
@@ -1,8 +1,13 @@
|
||||
import threading
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
from modules import shared
|
||||
|
||||
|
||||
class MemUsageMonitor(threading.Thread):
|
||||
@@ -17,60 +22,70 @@ class MemUsageMonitor(threading.Thread):
|
||||
self.name = name
|
||||
self.device = device
|
||||
self.opts = opts
|
||||
|
||||
self.daemon = True
|
||||
self.run_flag = threading.Event()
|
||||
self.data = defaultdict(int)
|
||||
|
||||
if not torch.cuda.is_available():
|
||||
self.disabled = True
|
||||
else:
|
||||
try:
|
||||
self.cuda_mem_get_info()
|
||||
torch.cuda.memory_stats(self.device)
|
||||
except Exception as e: # AMD or whatever
|
||||
print(f"Torch exception: {e}")
|
||||
self.disabled = True
|
||||
if shared.cmd_opts.use_ipex:
|
||||
try:
|
||||
self.cuda_mem_get_info()
|
||||
torch.cuda.memory_stats("xpu")
|
||||
except Exception as e: # AMD or whatever
|
||||
print(f"Torch exception: {e}")
|
||||
self.disabled = True
|
||||
else:
|
||||
try:
|
||||
self.cuda_mem_get_info()
|
||||
torch.cuda.memory_stats(self.device)
|
||||
except Exception as e: # AMD or whatever
|
||||
print(f"Torch exception: {e}")
|
||||
self.disabled = True
|
||||
|
||||
def cuda_mem_get_info(self):
|
||||
index = self.device.index if self.device.index is not None else torch.cuda.current_device()
|
||||
return torch.cuda.mem_get_info(index)
|
||||
if shared.cmd_opts.use_ipex:
|
||||
return [(torch.xpu.get_device_properties("xpu").total_memory - torch.xpu.memory_allocated()), torch.xpu.get_device_properties("xpu").total_memory]
|
||||
else:
|
||||
index = self.device.index if self.device.index is not None else torch.cuda.current_device()
|
||||
return torch.cuda.mem_get_info(index)
|
||||
|
||||
def run(self):
|
||||
if self.disabled:
|
||||
return
|
||||
|
||||
while True:
|
||||
self.run_flag.wait()
|
||||
|
||||
torch.cuda.reset_peak_memory_stats()
|
||||
if shared.cmd_opts.use_ipex:
|
||||
torch.xpu.reset_peak_memory_stats()
|
||||
else:
|
||||
torch.cuda.reset_peak_memory_stats()
|
||||
self.data.clear()
|
||||
|
||||
if self.opts.memmon_poll_rate <= 0:
|
||||
self.run_flag.clear()
|
||||
continue
|
||||
|
||||
self.data["min_free"] = self.cuda_mem_get_info()[0]
|
||||
|
||||
while self.run_flag.is_set():
|
||||
free, total = self.cuda_mem_get_info()
|
||||
free, _total = self.cuda_mem_get_info()
|
||||
self.data["min_free"] = min(self.data["min_free"], free)
|
||||
|
||||
time.sleep(1 / self.opts.memmon_poll_rate)
|
||||
|
||||
def dump_debug(self):
|
||||
print(self, 'recorded data:')
|
||||
for k, v in self.read().items():
|
||||
print(k, -(v // -(1024 ** 2)))
|
||||
|
||||
print(self, 'raw torch memory stats:')
|
||||
tm = torch.cuda.memory_stats(self.device)
|
||||
if shared.cmd_opts.use_ipex:
|
||||
tm = torch.xpu.memory_stats("xpu")
|
||||
else:
|
||||
tm = torch.cuda.memory_stats(self.device)
|
||||
for k, v in tm.items():
|
||||
if 'bytes' not in k:
|
||||
continue
|
||||
print('\t' if 'peak' in k else '', k, -(v // -(1024 ** 2)))
|
||||
|
||||
print(torch.cuda.memory_summary())
|
||||
if shared.cmd_opts.use_ipex:
|
||||
print(torch.xpu.memory_summary())
|
||||
else:
|
||||
print(torch.cuda.memory_summary())
|
||||
|
||||
def monitor(self):
|
||||
self.run_flag.set()
|
||||
@@ -80,14 +95,15 @@ class MemUsageMonitor(threading.Thread):
|
||||
free, total = self.cuda_mem_get_info()
|
||||
self.data["free"] = free
|
||||
self.data["total"] = total
|
||||
|
||||
torch_stats = torch.cuda.memory_stats(self.device)
|
||||
if shared.cmd_opts.use_ipex:
|
||||
torch_stats = torch.xpu.memory_stats("xpu")
|
||||
else:
|
||||
torch_stats = torch.cuda.memory_stats(self.device)
|
||||
self.data["active"] = torch_stats["active.all.current"]
|
||||
self.data["active_peak"] = torch_stats["active_bytes.all.peak"]
|
||||
self.data["reserved"] = torch_stats["reserved_bytes.all.current"]
|
||||
self.data["reserved_peak"] = torch_stats["reserved_bytes.all.peak"]
|
||||
self.data["system_peak"] = total - self.data["min_free"]
|
||||
|
||||
return self.data
|
||||
|
||||
def stop(self):
|
||||
|
||||
@@ -10,6 +10,10 @@ https://github.com/CompVis/taming-transformers
|
||||
# See more details in LICENSE.
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import torch.nn as nn
|
||||
import numpy as np
|
||||
import pytorch_lightning as pl
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
"""SAMPLING ONLY."""
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
from .uni_pc import NoiseScheduleVP, model_wrapper, UniPC
|
||||
from modules import shared, devices
|
||||
from ldm.modules.diffusionmodules.util import extract_into_tensor
|
||||
|
||||
|
||||
class UniPCSampler(object):
|
||||
@@ -15,6 +21,103 @@ class UniPCSampler(object):
|
||||
self.after_sample = None
|
||||
self.register_buffer('alphas_cumprod', to_torch(model.alphas_cumprod))
|
||||
|
||||
def make_schedule(self, ddim_num_steps, ddim_discretize="uniform", ddim_eta=0., verbose=True):
|
||||
# persist steps so we can eventually find denoising strength
|
||||
self.inflated_steps = ddim_num_steps
|
||||
|
||||
@torch.no_grad()
|
||||
def stochastic_encode(self, x0, t, use_original_steps=False, noise=None):
|
||||
if noise is None:
|
||||
noise = torch.randn_like(x0)
|
||||
|
||||
# first time we have all the info to get the real parameters from the ui
|
||||
# value from the hires steps slider:
|
||||
num_inference_steps = t[0] + 1
|
||||
# (num_inference_steps // denoising_strength):
|
||||
inflated_steps = self.inflated_steps
|
||||
# not exact:
|
||||
self.denoising_strength = num_inference_steps/inflated_steps
|
||||
|
||||
# values used for timesteps that generate noise in diffusers repo
|
||||
init_timestep = min(
|
||||
int(num_inference_steps * self.denoising_strength),
|
||||
num_inference_steps,
|
||||
)
|
||||
t_start = max(num_inference_steps - init_timestep, 0)
|
||||
|
||||
# actual number of steps we'll run
|
||||
self.steps = max(
|
||||
init_timestep,
|
||||
shared.opts.uni_pc_order+1,
|
||||
)
|
||||
|
||||
scheduler_timesteps = np.linspace(
|
||||
0,
|
||||
self.model.num_timesteps-1,
|
||||
num_inference_steps + 1,
|
||||
).round()[::-1][:-1].copy().astype(np.int64)
|
||||
_, unique_indices = np.unique(scheduler_timesteps, return_index=True)
|
||||
scheduler_timesteps = scheduler_timesteps[np.sort(unique_indices)]
|
||||
scheduler_timesteps = torch.from_numpy(scheduler_timesteps).to(t.device)
|
||||
|
||||
sample_timesteps = scheduler_timesteps[t_start:]
|
||||
latent_timestep = sample_timesteps[:1].repeat(x0.shape[0])
|
||||
|
||||
alphas_cumprod = self.alphas_cumprod
|
||||
sqrt_alpha_prod = alphas_cumprod[latent_timestep] ** 0.5
|
||||
sqrt_alpha_prod = sqrt_alpha_prod.flatten()
|
||||
while len(sqrt_alpha_prod.shape) < len(x0.shape):
|
||||
sqrt_alpha_prod = sqrt_alpha_prod.unsqueeze(-1)
|
||||
|
||||
sqrt_one_minus_alpha_prod = (1 - alphas_cumprod[latent_timestep]) ** 0.5
|
||||
sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.flatten()
|
||||
while len(sqrt_one_minus_alpha_prod.shape) < len(x0.shape):
|
||||
sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.unsqueeze(-1)
|
||||
|
||||
return (sqrt_alpha_prod * x0 + sqrt_one_minus_alpha_prod * noise)
|
||||
|
||||
def decode(self, x_latent, conditioning, t_start, unconditional_guidance_scale=1.0, unconditional_conditioning=None,
|
||||
use_original_steps=False, callback=None):
|
||||
#print(f'steps {self.steps} denoising {self.denoising_strength}')
|
||||
|
||||
noise_schedule = NoiseScheduleVP("discrete", alphas_cumprod=self.alphas_cumprod)
|
||||
|
||||
# same as in .sample(), i guess
|
||||
model_type = "v" if self.model.parameterization == "v" else "noise"
|
||||
|
||||
model_fn = model_wrapper(
|
||||
lambda x, t, c: self.model.apply_model(x, t, c),
|
||||
noise_schedule,
|
||||
model_type=model_type,
|
||||
guidance_type="classifier-free",
|
||||
#condition=conditioning,
|
||||
#unconditional_condition=unconditional_conditioning,
|
||||
guidance_scale=unconditional_guidance_scale,
|
||||
)
|
||||
|
||||
self.uni_pc = UniPC(
|
||||
model_fn,
|
||||
noise_schedule,
|
||||
predict_x0=True,
|
||||
thresholding=False,
|
||||
variant=shared.opts.uni_pc_variant,
|
||||
condition=conditioning,
|
||||
unconditional_condition=unconditional_conditioning,
|
||||
before_sample=self.before_sample,
|
||||
after_sample=self.after_sample,
|
||||
after_update=self.after_update,
|
||||
)
|
||||
|
||||
return self.uni_pc.sample(
|
||||
x_latent,
|
||||
steps=self.steps,
|
||||
skip_type=shared.opts.uni_pc_skip_type,
|
||||
method="multistep",
|
||||
order=shared.opts.uni_pc_order,
|
||||
lower_order_final=shared.opts.uni_pc_lower_order_final,
|
||||
t_start=self.denoising_strength,
|
||||
)
|
||||
|
||||
def register_buffer(self, name, attr):
|
||||
if type(attr) == torch.Tensor:
|
||||
if attr.device != devices.device:
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import torch.nn.functional as F
|
||||
import math
|
||||
import time
|
||||
|
||||
+53
-107
@@ -6,7 +6,12 @@ import random
|
||||
import logging
|
||||
from typing import Any, Dict, List
|
||||
|
||||
import psutil
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
|
||||
except:
|
||||
pass
|
||||
import numpy as np
|
||||
from PIL import Image, ImageFilter, ImageOps
|
||||
import cv2
|
||||
@@ -20,7 +25,7 @@ from blendmodes.blend import blendLayers, BlendType
|
||||
import modules.sd_hijack
|
||||
from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, script_callbacks, extra_networks, sd_vae_approx, scripts # pylint: disable=unused-import
|
||||
from modules.sd_hijack import model_hijack
|
||||
from modules.shared import opts, cmd_opts, state # pylint: disable=unused-import
|
||||
from modules.shared import opts, cmd_opts, state, log # pylint: disable=unused-import
|
||||
import modules.shared as shared
|
||||
import modules.paths as paths
|
||||
import modules.face_restoration
|
||||
@@ -30,17 +35,45 @@ import modules.sd_models as sd_models
|
||||
import modules.sd_vae as sd_vae
|
||||
import tomesd # pylint: disable=wrong-import-order
|
||||
|
||||
|
||||
# add a logger for the processing module
|
||||
logger = logging.getLogger(__name__)
|
||||
# manually set output level here since there is no option to do so yet through launch options
|
||||
# logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s %(message)s')
|
||||
|
||||
# some of those options should not be changed at all because they would break the model, so I removed them from options.
|
||||
opt_C = 4
|
||||
opt_f = 8
|
||||
|
||||
|
||||
def memory_stats():
|
||||
def gb(val: float):
|
||||
return round(val / 1024 / 1024 / 1024, 2)
|
||||
mem = {}
|
||||
try:
|
||||
process = psutil.Process(os.getpid())
|
||||
res = process.memory_info()
|
||||
ram_total = 100 * res.rss / process.memory_percent()
|
||||
ram = { 'used': gb(res.rss), 'total': gb(ram_total) }
|
||||
mem.update({ 'ram': ram })
|
||||
except Exception as e:
|
||||
mem.update({ 'ram': e })
|
||||
try:
|
||||
if cmd_opts.use_ipex:
|
||||
gpu = { 'used': gb(torch.xpu.memory_allocated()), 'total': gb(torch.xpu.get_device_properties("xpu").total_memory) }
|
||||
s = dict(torch.xpu.memory_stats("xpu"))
|
||||
mem.update({
|
||||
'gpu': gpu,
|
||||
'retries': s['num_alloc_retries'],
|
||||
'oom': s['num_ooms']
|
||||
})
|
||||
elif torch.cuda.is_available():
|
||||
s = torch.cuda.mem_get_info()
|
||||
gpu = { 'used': gb(s[1] - s[0]), 'total': gb(s[1]) }
|
||||
s = dict(torch.cuda.memory_stats(shared.device))
|
||||
mem.update({
|
||||
'gpu': gpu,
|
||||
'retries': s['num_alloc_retries'],
|
||||
'oom': s['num_ooms']
|
||||
})
|
||||
except:
|
||||
pass
|
||||
return mem
|
||||
|
||||
|
||||
def setup_color_correction(image):
|
||||
logging.info("Calibrating color correction.")
|
||||
correction_target = cv2.cvtColor(np.asarray(image.copy()), cv2.COLOR_RGB2LAB)
|
||||
@@ -160,7 +193,8 @@ class StableDiffusionProcessing:
|
||||
self.seed_resize_from_h = 0
|
||||
self.seed_resize_from_w = 0
|
||||
self.scripts = None
|
||||
self.script_args = script_args
|
||||
self.script_args = script_args or []
|
||||
self.per_script_args = {}
|
||||
self.all_prompts = None
|
||||
self.all_negative_prompts = None
|
||||
self.all_seeds = None
|
||||
@@ -316,7 +350,6 @@ class Processed:
|
||||
self.seed = int(self.seed if type(self.seed) != list else self.seed[0]) if self.seed is not None else -1
|
||||
self.subseed = int(self.subseed if type(self.subseed) != list else self.subseed[0]) if self.subseed is not None else -1
|
||||
self.is_using_inpainting_conditioning = p.is_using_inpainting_conditioning
|
||||
|
||||
self.all_prompts = all_prompts or p.all_prompts or [self.prompt]
|
||||
self.all_negative_prompts = all_negative_prompts or p.all_negative_prompts or [self.negative_prompt]
|
||||
self.all_seeds = all_seeds or p.all_seeds or [self.seed]
|
||||
@@ -519,7 +552,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
|
||||
if (opts.token_merging or cmd_opts.token_merging) and not opts.token_merging_hr_only:
|
||||
sd_models.apply_token_merging(sd_model=p.sd_model, hr=False)
|
||||
logger.debug('Token merging applied')
|
||||
log.debug('Token merging applied')
|
||||
|
||||
res = process_images_inner(p)
|
||||
|
||||
@@ -527,7 +560,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
||||
# undo model optimizations made by tomesd
|
||||
if opts.token_merging or cmd_opts.token_merging:
|
||||
tomesd.remove_patch(p.sd_model)
|
||||
logger.debug('Token merging model optimizations removed')
|
||||
log.debug('Token merging model optimizations removed')
|
||||
|
||||
# restore opts to original state
|
||||
if p.override_settings_restore_afterwards:
|
||||
@@ -738,47 +771,34 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
image_without_cc = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
||||
images.save_image(image_without_cc, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-color-correction")
|
||||
image = apply_color_correction(p.color_corrections[i], image)
|
||||
|
||||
image = apply_overlay(image, p.paste_to, i, p.overlay_images)
|
||||
|
||||
if opts.samples_save and not p.do_not_save_samples:
|
||||
images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p)
|
||||
|
||||
text = infotext(n, i)
|
||||
infotexts.append(text)
|
||||
if opts.enable_pnginfo:
|
||||
image.info["parameters"] = text
|
||||
output_images.append(image)
|
||||
|
||||
if hasattr(p, 'mask_for_overlay') and p.mask_for_overlay and any([opts.save_mask, opts.save_mask_composite, opts.return_mask, opts.return_mask_composite]):
|
||||
image_mask = p.mask_for_overlay.convert('RGB')
|
||||
image_mask_composite = Image.composite(image.convert('RGBA').convert('RGBa'), Image.new('RGBa', image.size), images.resize_image(2, p.mask_for_overlay, image.width, image.height).convert('L')).convert('RGBA')
|
||||
|
||||
if opts.save_mask:
|
||||
images.save_image(image_mask, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask")
|
||||
|
||||
if opts.save_mask_composite:
|
||||
images.save_image(image_mask_composite, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-mask-composite")
|
||||
|
||||
if opts.return_mask:
|
||||
output_images.append(image_mask)
|
||||
|
||||
if opts.return_mask_composite:
|
||||
output_images.append(image_mask_composite)
|
||||
|
||||
del x_samples_ddim
|
||||
|
||||
devices.torch_gc()
|
||||
|
||||
state.nextjob()
|
||||
|
||||
p.color_corrections = None
|
||||
|
||||
index_of_first_image = 0
|
||||
unwanted_grid_because_of_img_count = len(output_images) < 2 and opts.grid_only_if_multiple
|
||||
if (opts.return_grid or opts.grid_save) and not p.do_not_save_grid and not unwanted_grid_because_of_img_count:
|
||||
grid = images.image_grid(output_images, p.batch_size)
|
||||
|
||||
if opts.return_grid:
|
||||
text = infotext()
|
||||
infotexts.insert(0, text)
|
||||
@@ -786,32 +806,25 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
|
||||
grid.info["parameters"] = text
|
||||
output_images.insert(0, grid)
|
||||
index_of_first_image = 1
|
||||
|
||||
if opts.grid_save:
|
||||
images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename, p=p, grid=True)
|
||||
|
||||
if not p.disable_extra_networks and extra_network_data:
|
||||
extra_networks.deactivate(p, extra_network_data)
|
||||
|
||||
devices.torch_gc()
|
||||
|
||||
res = Processed(p, output_images, p.all_seeds[0], infotext(), comments="".join(["\n\n" + x for x in comments]), subseed=p.all_subseeds[0], index_of_first_image=index_of_first_image, infotexts=infotexts)
|
||||
|
||||
if p.scripts is not None:
|
||||
p.scripts.postprocess(p, res)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def old_hires_fix_first_pass_dimensions(width, height):
|
||||
"""old algorithm for auto-calculating first pass size"""
|
||||
|
||||
desired_pixel_count = 512 * 512
|
||||
actual_pixel_count = width * height
|
||||
scale = math.sqrt(desired_pixel_count / actual_pixel_count)
|
||||
width = math.ceil(scale * width / 64) * 64
|
||||
height = math.ceil(scale * height / 64) * 64
|
||||
|
||||
return width, height
|
||||
|
||||
|
||||
@@ -829,13 +842,11 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
self.hr_resize_y = hr_resize_y
|
||||
self.hr_upscale_to_x = hr_resize_x
|
||||
self.hr_upscale_to_y = hr_resize_y
|
||||
|
||||
if firstphase_width != 0 or firstphase_height != 0:
|
||||
self.hr_upscale_to_x = self.width
|
||||
self.hr_upscale_to_y = self.height
|
||||
self.width = firstphase_width
|
||||
self.height = firstphase_height
|
||||
|
||||
self.truncate_x = 0
|
||||
self.truncate_y = 0
|
||||
self.applied_old_hires_behavior_to = None
|
||||
@@ -847,17 +858,14 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
self.hr_resize_y = self.height
|
||||
self.hr_upscale_to_x = self.width
|
||||
self.hr_upscale_to_y = self.height
|
||||
|
||||
self.width, self.height = old_hires_fix_first_pass_dimensions(self.width, self.height)
|
||||
self.applied_old_hires_behavior_to = (self.width, self.height)
|
||||
|
||||
if self.hr_resize_x == 0 and self.hr_resize_y == 0:
|
||||
self.extra_generation_params["Hires upscale"] = self.hr_scale
|
||||
self.hr_upscale_to_x = int(self.width * self.hr_scale)
|
||||
self.hr_upscale_to_y = int(self.height * self.hr_scale)
|
||||
else:
|
||||
self.extra_generation_params["Hires resize"] = f"{self.hr_resize_x}x{self.hr_resize_y}"
|
||||
|
||||
if self.hr_resize_y == 0:
|
||||
self.hr_upscale_to_x = self.hr_resize_x
|
||||
self.hr_upscale_to_y = self.hr_resize_x * self.height // self.width
|
||||
@@ -869,17 +877,14 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
target_h = self.hr_resize_y
|
||||
src_ratio = self.width / self.height
|
||||
dst_ratio = self.hr_resize_x / self.hr_resize_y
|
||||
|
||||
if src_ratio < dst_ratio:
|
||||
self.hr_upscale_to_x = self.hr_resize_x
|
||||
self.hr_upscale_to_y = self.hr_resize_x * self.height // self.width
|
||||
else:
|
||||
self.hr_upscale_to_x = self.hr_resize_y * self.width // self.height
|
||||
self.hr_upscale_to_y = self.hr_resize_y
|
||||
|
||||
self.truncate_x = (self.hr_upscale_to_x - target_w) // opt_f
|
||||
self.truncate_y = (self.hr_upscale_to_y - target_h) // opt_f
|
||||
|
||||
# special case: the user has chosen to do nothing
|
||||
if self.hr_upscale_to_x == self.width and self.hr_upscale_to_y == self.height:
|
||||
self.enable_hr = False
|
||||
@@ -887,55 +892,41 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
self.extra_generation_params.pop("Hires upscale", None)
|
||||
self.extra_generation_params.pop("Hires resize", None)
|
||||
return
|
||||
|
||||
if not state.processing_has_refined_job_count:
|
||||
if state.job_count == -1:
|
||||
state.job_count = self.n_iter
|
||||
|
||||
shared.total_tqdm.updateTotal((self.steps + (self.hr_second_pass_steps or self.steps)) * state.job_count)
|
||||
state.job_count = state.job_count * 2
|
||||
state.processing_has_refined_job_count = True
|
||||
|
||||
if self.hr_second_pass_steps:
|
||||
self.extra_generation_params["Hires steps"] = self.hr_second_pass_steps
|
||||
|
||||
if self.hr_upscaler is not None:
|
||||
self.extra_generation_params["Hires upscaler"] = self.hr_upscaler
|
||||
|
||||
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts):
|
||||
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
|
||||
|
||||
latent_scale_mode = shared.latent_upscale_modes.get(self.hr_upscaler, None) if self.hr_upscaler is not None else shared.latent_upscale_modes.get(shared.latent_upscale_default_mode, "nearest")
|
||||
if self.enable_hr and latent_scale_mode is None:
|
||||
assert len([x for x in shared.sd_upscalers if x.name == self.hr_upscaler]) > 0, f"could not find upscaler named {self.hr_upscaler}"
|
||||
|
||||
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
||||
samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning, image_conditioning=self.txt2img_image_conditioning(x))
|
||||
|
||||
if not self.enable_hr:
|
||||
return samples
|
||||
|
||||
target_width = self.hr_upscale_to_x
|
||||
target_height = self.hr_upscale_to_y
|
||||
|
||||
def save_intermediate(image, index):
|
||||
"""saves image before applying hires fix, if enabled in options; takes as an argument either an image or batch with latent space images"""
|
||||
|
||||
if not opts.save or self.do_not_save_samples or not opts.save_images_before_highres_fix:
|
||||
return
|
||||
|
||||
if not isinstance(image, Image.Image):
|
||||
image = sd_samplers.sample_to_image(image, index, approximation=0)
|
||||
|
||||
info = create_infotext(self, self.all_prompts, self.all_seeds, self.all_subseeds, [], iteration=self.iteration, position_in_batch=index)
|
||||
images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], opts.samples_format, info=info, suffix="-before-highres-fix")
|
||||
|
||||
if latent_scale_mode is not None:
|
||||
for i in range(samples.shape[0]):
|
||||
save_intermediate(samples, i)
|
||||
|
||||
samples = torch.nn.functional.interpolate(samples, size=(target_height // opt_f, target_width // opt_f), mode=latent_scale_mode["mode"], antialias=latent_scale_mode["antialias"])
|
||||
|
||||
# Avoid making the inpainting conditioning unless necessary as
|
||||
# this does need some extra compute to decode / encode the image again.
|
||||
if getattr(self, "inpainting_mask_weight", shared.opts.inpainting_mask_weight) < 1.0:
|
||||
@@ -945,43 +936,32 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
else:
|
||||
decoded_samples = decode_first_stage(self.sd_model, samples)
|
||||
lowres_samples = torch.clamp((decoded_samples + 1.0) / 2.0, min=0.0, max=1.0)
|
||||
|
||||
batch_images = []
|
||||
for i, x_sample in enumerate(lowres_samples):
|
||||
x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2)
|
||||
x_sample = x_sample.astype(np.uint8)
|
||||
image = Image.fromarray(x_sample)
|
||||
|
||||
save_intermediate(image, i)
|
||||
|
||||
image = images.resize_image(0, image, target_width, target_height, upscaler_name=self.hr_upscaler)
|
||||
image = np.array(image).astype(np.float32) / 255.0
|
||||
image = np.moveaxis(image, 2, 0)
|
||||
batch_images.append(image)
|
||||
|
||||
decoded_samples = torch.from_numpy(np.array(batch_images))
|
||||
decoded_samples = decoded_samples.to(shared.device)
|
||||
decoded_samples = 2. * decoded_samples - 1.
|
||||
|
||||
samples = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(decoded_samples))
|
||||
|
||||
image_conditioning = self.img2img_image_conditioning(decoded_samples, samples)
|
||||
|
||||
shared.state.nextjob()
|
||||
|
||||
img2img_sampler_name = self.sampler_name
|
||||
if self.sampler_name in ['PLMS', 'UniPC']: # PLMS/UniPC do not support img2img so we just silently switch to DDIM
|
||||
img2img_sampler_name = shared.opts.fallback_sampler
|
||||
force_latent_upscaler = shared.opts.data.get('xyz_fallback_sampler')
|
||||
if self.sampler_name in ['PLMS'] or (force_latent_upscaler is not None and force_latent_upscaler != 'None'):
|
||||
img2img_sampler_name = force_latent_upscaler or shared.opts.fallback_sampler # PLMS does not support img2img, use fallback instead
|
||||
self.sampler = sd_samplers.create_sampler(img2img_sampler_name, self.sd_model)
|
||||
|
||||
samples = samples[:, :, self.truncate_y//2:samples.shape[2]-(self.truncate_y+1)//2, self.truncate_x//2:samples.shape[3]-(self.truncate_x+1)//2]
|
||||
|
||||
noise = create_random_tensors(samples.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=subseed_strength, p=self)
|
||||
|
||||
# GC now before running the next img2img to prevent running out of memory
|
||||
x = None
|
||||
devices.torch_gc()
|
||||
|
||||
# apply token merging optimizations from tomesd for high-res pass
|
||||
# check if hr_only so we are not redundantly patching
|
||||
if (cmd_opts.token_merging or opts.token_merging) and (opts.token_merging_hr_only or opts.token_merging_ratio_hr != opts.token_merging_ratio):
|
||||
@@ -989,13 +969,11 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
||||
if not opts.token_merging_hr_only:
|
||||
# clean patch done by first pass. (clobbering the first patch might be fine? this might be excessive)
|
||||
tomesd.remove_patch(self.sd_model)
|
||||
logger.debug('Temporarily removed token merging optimizations in preparation for next pass')
|
||||
log.debug('Temporarily removed token merging optimizations in preparation for next pass')
|
||||
|
||||
sd_models.apply_token_merging(sd_model=self.sd_model, hr=True)
|
||||
logger.debug('Applied token merging for high-res pass')
|
||||
|
||||
log.debug('Applied token merging for high-res pass')
|
||||
samples = self.sampler.sample_img2img(self, samples, noise, conditioning, unconditional_conditioning, steps=self.hr_second_pass_steps or self.steps, image_conditioning=image_conditioning)
|
||||
|
||||
return samples
|
||||
|
||||
|
||||
@@ -1004,7 +982,6 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
|
||||
def __init__(self, init_images: list = None, resize_mode: int = 0, denoising_strength: float = 0.75, image_cfg_scale: float = None, mask: Any = None, mask_blur: int = 4, inpainting_fill: int = 0, inpaint_full_res: bool = True, inpaint_full_res_padding: int = 0, inpainting_mask_invert: int = 0, initial_noise_multiplier: float = None, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.init_images = init_images
|
||||
self.resize_mode: int = resize_mode
|
||||
self.denoising_strength: float = denoising_strength
|
||||
@@ -1024,29 +1001,24 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
self.image_conditioning = None
|
||||
|
||||
def init(self, all_prompts, all_seeds, all_subseeds):
|
||||
if self.sampler_name in ['PLMS', 'UniPC']: # PLMS/UniPC do not support img2img so we just silently switch to DDIM
|
||||
self.sampler_name = shared.opts.fallback_sampler
|
||||
force_latent_upscaler = shared.opts.data.get('xyz_fallback_sampler')
|
||||
if self.sampler_name in ['PLMS'] or (force_latent_upscaler is not None and force_latent_upscaler != 'None'):
|
||||
self.sampler_name = force_latent_upscaler or shared.opts.fallback_sampler # PLMS does not support img2img, use fallback instead
|
||||
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
|
||||
crop_region = None
|
||||
|
||||
image_mask = self.image_mask
|
||||
|
||||
if image_mask is not None:
|
||||
image_mask = image_mask.convert('L')
|
||||
|
||||
if self.inpainting_mask_invert:
|
||||
image_mask = ImageOps.invert(image_mask)
|
||||
|
||||
if self.mask_blur > 0:
|
||||
image_mask = image_mask.filter(ImageFilter.GaussianBlur(self.mask_blur))
|
||||
|
||||
if self.inpaint_full_res:
|
||||
self.mask_for_overlay = image_mask
|
||||
mask = image_mask.convert('L')
|
||||
crop_region = masking.get_crop_region(np.array(mask), self.inpaint_full_res_padding)
|
||||
crop_region = masking.expand_crop_region(crop_region, self.width, self.height, mask.width, mask.height)
|
||||
x1, y1, x2, y2 = crop_region
|
||||
|
||||
mask = mask.crop(crop_region)
|
||||
image_mask = images.resize_image(2, mask, self.width, self.height)
|
||||
self.paste_to = (x1, y1, x2-x1, y2-y1)
|
||||
@@ -1055,67 +1027,49 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
np_mask = np.array(image_mask)
|
||||
np_mask = np.clip((np_mask.astype(np.float32)) * 2, 0, 255).astype(np.uint8)
|
||||
self.mask_for_overlay = Image.fromarray(np_mask)
|
||||
|
||||
self.overlay_images = []
|
||||
|
||||
latent_mask = self.latent_mask if self.latent_mask is not None else image_mask
|
||||
|
||||
add_color_corrections = opts.img2img_color_correction and self.color_corrections is None
|
||||
if add_color_corrections:
|
||||
self.color_corrections = []
|
||||
imgs = []
|
||||
for img in self.init_images:
|
||||
image = images.flatten(img, opts.img2img_background_color)
|
||||
|
||||
if crop_region is None and self.resize_mode != 3:
|
||||
image = images.resize_image(self.resize_mode, image, self.width, self.height)
|
||||
|
||||
if image_mask is not None:
|
||||
image_masked = Image.new('RGBa', (image.width, image.height))
|
||||
image_masked.paste(image.convert("RGBA").convert("RGBa"), mask=ImageOps.invert(self.mask_for_overlay.convert('L')))
|
||||
|
||||
self.overlay_images.append(image_masked.convert('RGBA'))
|
||||
|
||||
# crop_region is not None if we are doing inpaint full res
|
||||
if crop_region is not None:
|
||||
image = image.crop(crop_region)
|
||||
image = images.resize_image(2, image, self.width, self.height)
|
||||
|
||||
if image_mask is not None:
|
||||
if self.inpainting_fill != 1:
|
||||
image = masking.fill(image, latent_mask)
|
||||
|
||||
if add_color_corrections:
|
||||
self.color_corrections.append(setup_color_correction(image))
|
||||
|
||||
image = np.array(image).astype(np.float32) / 255.0
|
||||
image = np.moveaxis(image, 2, 0)
|
||||
|
||||
imgs.append(image)
|
||||
|
||||
if len(imgs) == 1:
|
||||
batch_images = np.expand_dims(imgs[0], axis=0).repeat(self.batch_size, axis=0)
|
||||
if self.overlay_images is not None:
|
||||
self.overlay_images = self.overlay_images * self.batch_size
|
||||
|
||||
if self.color_corrections is not None and len(self.color_corrections) == 1:
|
||||
self.color_corrections = self.color_corrections * self.batch_size
|
||||
|
||||
elif len(imgs) <= self.batch_size:
|
||||
self.batch_size = len(imgs)
|
||||
batch_images = np.array(imgs)
|
||||
else:
|
||||
raise RuntimeError(f"bad number of images passed: {len(imgs)}; expecting {self.batch_size} or less")
|
||||
|
||||
image = torch.from_numpy(batch_images)
|
||||
image = 2. * image - 1.
|
||||
image = image.to(shared.device)
|
||||
|
||||
self.init_latent = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(image))
|
||||
|
||||
if self.resize_mode == 3:
|
||||
self.init_latent = torch.nn.functional.interpolate(self.init_latent, size=(self.height // opt_f, self.width // opt_f), mode="bilinear")
|
||||
|
||||
if image_mask is not None:
|
||||
init_mask = latent_mask
|
||||
latmask = init_mask.convert('RGB').resize((self.init_latent.shape[3], self.init_latent.shape[2]))
|
||||
@@ -1123,31 +1077,23 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
||||
latmask = latmask[0]
|
||||
latmask = np.around(latmask)
|
||||
latmask = np.tile(latmask[None], (4, 1, 1))
|
||||
|
||||
self.mask = torch.asarray(1.0 - latmask).to(shared.device).type(self.sd_model.dtype)
|
||||
self.nmask = torch.asarray(latmask).to(shared.device).type(self.sd_model.dtype)
|
||||
|
||||
# this needs to be fixed to be done in sample() using actual seeds for batches
|
||||
if self.inpainting_fill == 2:
|
||||
self.init_latent = self.init_latent * self.mask + create_random_tensors(self.init_latent.shape[1:], all_seeds[0:self.init_latent.shape[0]]) * self.nmask
|
||||
elif self.inpainting_fill == 3:
|
||||
self.init_latent = self.init_latent * self.mask
|
||||
|
||||
self.image_conditioning = self.img2img_image_conditioning(image, self.init_latent, image_mask)
|
||||
|
||||
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts):
|
||||
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
||||
|
||||
if self.initial_noise_multiplier != 1.0:
|
||||
self.extra_generation_params["Noise multiplier"] = self.initial_noise_multiplier
|
||||
x *= self.initial_noise_multiplier
|
||||
|
||||
samples = self.sampler.sample_img2img(self, self.init_latent, x, conditioning, unconditional_conditioning, image_conditioning=self.image_conditioning)
|
||||
|
||||
if self.mask is not None:
|
||||
samples = samples * self.nmask + self.init_latent * self.mask
|
||||
|
||||
del x
|
||||
devices.torch_gc()
|
||||
|
||||
return samples
|
||||
|
||||
@@ -368,3 +368,7 @@ if __name__ == "__main__":
|
||||
doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)
|
||||
else:
|
||||
import torch # doctest faster
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -6,7 +6,7 @@ from PIL import Image
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
|
||||
from modules.upscaler import Upscaler, UpscalerData
|
||||
from modules.shared import cmd_opts, opts
|
||||
from modules.shared import cmd_opts, opts, device
|
||||
import modules.errors as errors
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class UpscalerRealESRGAN(Upscaler):
|
||||
half=not cmd_opts.no_half and not opts.upcast_sampling,
|
||||
tile=opts.ESRGAN_tile,
|
||||
tile_pad=opts.ESRGAN_tile_overlap,
|
||||
device=device,
|
||||
)
|
||||
|
||||
upsampled = upsampler.enhance(np.array(img), outscale=info.scale)[0]
|
||||
|
||||
@@ -6,6 +6,10 @@ import zipfile
|
||||
import re
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import numpy
|
||||
import _codecs
|
||||
|
||||
|
||||
+15
-16
@@ -3,7 +3,7 @@ import re
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
import gradio as gr
|
||||
from modules import shared, paths, script_callbacks, extensions, script_loading, scripts_postprocessing, errors
|
||||
from modules import paths, script_callbacks, extensions, script_loading, scripts_postprocessing, errors
|
||||
|
||||
AlwaysVisible = object()
|
||||
|
||||
@@ -345,56 +345,55 @@ class ScriptRunner:
|
||||
script = self.selectable_scripts[script_index-1]
|
||||
if script is None:
|
||||
return None
|
||||
script_args = args[script.args_from:script.args_to]
|
||||
processed = script.run(p, *script_args)
|
||||
shared.total_tqdm.clear()
|
||||
parsed = p.per_script_args.get(script.title(), args[script.args_from:script.args_to])
|
||||
processed = script.run(p, *parsed)
|
||||
return processed
|
||||
|
||||
def process(self, p, **kwargs):
|
||||
for script in self.alwayson_scripts:
|
||||
try:
|
||||
script_args = p.script_args[script.args_from:script.args_to]
|
||||
script.process(p, *script_args, **kwargs)
|
||||
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
|
||||
script.process(p, *args, **kwargs)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Running script process: {script.filename}')
|
||||
|
||||
def before_process_batch(self, p, **kwargs):
|
||||
for script in self.alwayson_scripts:
|
||||
try:
|
||||
script_args = p.script_args[script.args_from:script.args_to]
|
||||
script.before_process_batch(p, *script_args, **kwargs)
|
||||
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
|
||||
script.before_process_batch(p, *args, **kwargs)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Running script before process batch: {script.filename}')
|
||||
|
||||
def process_batch(self, p, **kwargs):
|
||||
for script in self.alwayson_scripts:
|
||||
try:
|
||||
script_args = p.script_args[script.args_from:script.args_to]
|
||||
script.process_batch(p, *script_args, **kwargs)
|
||||
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
|
||||
script.process_batch(p, *args, **kwargs)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Running script process batch: {script.filename}')
|
||||
|
||||
def postprocess(self, p, processed):
|
||||
for script in self.alwayson_scripts:
|
||||
try:
|
||||
script_args = p.script_args[script.args_from:script.args_to]
|
||||
script.postprocess(p, processed, *script_args)
|
||||
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
|
||||
script.postprocess(p, processed, *args)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Running script postprocess: {script.filename}')
|
||||
|
||||
def postprocess_batch(self, p, images, **kwargs):
|
||||
for script in self.alwayson_scripts:
|
||||
try:
|
||||
script_args = p.script_args[script.args_from:script.args_to]
|
||||
script.postprocess_batch(p, *script_args, images=images, **kwargs)
|
||||
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
|
||||
script.postprocess_batch(p, *args, images=images, **kwargs)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Running script before postprocess batch: {script.filename}')
|
||||
|
||||
def postprocess_image(self, p, pp: PostprocessImageArgs):
|
||||
for script in self.alwayson_scripts:
|
||||
try:
|
||||
script_args = p.script_args[script.args_from:script.args_to]
|
||||
script.postprocess_image(p, pp, *script_args)
|
||||
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
|
||||
script.postprocess_image(p, pp, *args)
|
||||
except Exception as e:
|
||||
errors.display(e, f'Running script postprocess image: {script.filename}')
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import ldm.modules.encoders.modules
|
||||
import open_clip
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import transformers.utils.hub
|
||||
|
||||
|
||||
|
||||
+15
-6
@@ -1,6 +1,10 @@
|
||||
from types import MethodType
|
||||
from rich import print # pylint: disable=redefined-builtin
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from torch.nn.functional import silu
|
||||
import ldm.modules.attention
|
||||
import ldm.modules.diffusionmodules.model
|
||||
@@ -92,12 +96,12 @@ def undo_optimizations():
|
||||
def fix_checkpoint():
|
||||
"""checkpoints are now added and removed in embedding/hypernet code, since torch doesn't want
|
||||
checkpoints to be added when not training (there's a warning)"""
|
||||
pass
|
||||
pass # pylint: disable=unnecessary-pass
|
||||
|
||||
|
||||
def weighted_loss(sd_model, pred, target, mean=True):
|
||||
#Calculate the weight normally, but ignore the mean
|
||||
loss = sd_model._old_get_loss(pred, target, mean=False)
|
||||
loss = sd_model._old_get_loss(pred, target, mean=False) # pylint: disable=protected-access
|
||||
|
||||
#Check if we have weights available
|
||||
weight = getattr(sd_model, '_custom_loss_weight', None)
|
||||
@@ -110,12 +114,12 @@ def weighted_loss(sd_model, pred, target, mean=True):
|
||||
def weighted_forward(sd_model, x, c, w, *args, **kwargs):
|
||||
try:
|
||||
#Temporarily append weights to a place accessible during loss calc
|
||||
sd_model._custom_loss_weight = w
|
||||
sd_model._custom_loss_weight = w # pylint: disable=protected-access
|
||||
|
||||
#Replace 'get_loss' with a weight-aware one. Otherwise we need to reimplement 'forward' completely
|
||||
#Keep 'get_loss', but don't overwrite the previous old_get_loss if it's already set
|
||||
if not hasattr(sd_model, '_old_get_loss'):
|
||||
sd_model._old_get_loss = sd_model.get_loss
|
||||
sd_model._old_get_loss = sd_model.get_loss # pylint: disable=protected-access
|
||||
sd_model.get_loss = MethodType(weighted_loss, sd_model)
|
||||
|
||||
#Run the standard forward function, but with the patched 'get_loss'
|
||||
@@ -129,7 +133,7 @@ def weighted_forward(sd_model, x, c, w, *args, **kwargs):
|
||||
|
||||
#If we have an old loss function, reset the loss function to the original one
|
||||
if hasattr(sd_model, '_old_get_loss'):
|
||||
sd_model.get_loss = sd_model._old_get_loss
|
||||
sd_model.get_loss = sd_model._old_get_loss # pylint: disable=protected-access
|
||||
del sd_model._old_get_loss
|
||||
|
||||
def apply_weighted_forward(sd_model):
|
||||
@@ -178,8 +182,13 @@ class StableDiffusionModelHijack:
|
||||
if opts.cuda_compile and opts.cuda_compile_mode != 'none':
|
||||
try:
|
||||
import torch._dynamo as dynamo # pylint: disable=unused-import
|
||||
torch._dynamo.config.verbose = True # pylint: disable=protected-access
|
||||
torch._dynamo.config.verbose = opts.cuda_compile_verbose # pylint: disable=protected-access
|
||||
torch._dynamo.config.suppress_errors = opts.cuda_compile_errors # pylint: disable=protected-access
|
||||
torch.backends.cudnn.benchmark = True
|
||||
if opts.cuda_compile_mode == 'hidet':
|
||||
import hidet
|
||||
hidet.torch.dynamo_config.use_tensor_core(True)
|
||||
hidet.torch.dynamo_config.search_space(2)
|
||||
m.model = torch.compile(m.model, mode="default", backend=opts.cuda_compile_mode, fullgraph=False, dynamic=False)
|
||||
print("Model compile enabled:", opts.cuda_compile_mode)
|
||||
except Exception as err:
|
||||
|
||||
@@ -2,6 +2,10 @@ import math
|
||||
from collections import namedtuple
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
from modules import prompt_parser, devices, sd_hijack
|
||||
from modules.shared import opts
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
import ldm.models.diffusion.ddpm
|
||||
import ldm.models.diffusion.ddim
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import open_clip.tokenizer
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
from modules import sd_hijack_clip, devices
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import math
|
||||
import psutil
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from torch import einsum
|
||||
|
||||
from ldm.util import default
|
||||
@@ -22,7 +26,15 @@ if shared.opts.cross_attention_optimization == "xFormers":
|
||||
|
||||
|
||||
def get_available_vram():
|
||||
if shared.device.type == 'cuda':
|
||||
if shared.cmd_opts.use_ipex:
|
||||
stats = torch.xpu.memory_stats("xpu")
|
||||
mem_active = stats['active_bytes.all.current']
|
||||
mem_reserved = stats['reserved_bytes.all.current']
|
||||
mem_free_xpu, _ = [(torch.xpu.get_device_properties("xpu").total_memory - torch.xpu.memory_allocated()), torch.xpu.get_device_properties("xpu").total_memory]
|
||||
mem_free_torch = mem_reserved - mem_active
|
||||
mem_free_total = mem_free_xpu + mem_free_torch
|
||||
return mem_free_total
|
||||
elif shared.device.type == 'cuda':
|
||||
stats = torch.cuda.memory_stats(shared.device)
|
||||
mem_active = stats['active_bytes.all.current']
|
||||
mem_reserved = stats['reserved_bytes.all.current']
|
||||
@@ -30,6 +42,9 @@ def get_available_vram():
|
||||
mem_free_torch = mem_reserved - mem_active
|
||||
mem_free_total = mem_free_cuda + mem_free_torch
|
||||
return mem_free_total
|
||||
elif shared.device.type == 'privateuseone':
|
||||
mem_total, mem_active = torch.dml.memory_stats(shared.device)
|
||||
return mem_total - mem_active * (1 << 20)
|
||||
else:
|
||||
return psutil.virtual_memory().available
|
||||
|
||||
@@ -186,16 +201,34 @@ def einsum_op_tensor_mem(q, k, v, max_tensor_mb):
|
||||
return einsum_op_slice_1(q, k, v, max(q.shape[1] // div, 1))
|
||||
|
||||
def einsum_op_cuda(q, k, v):
|
||||
stats = torch.cuda.memory_stats(q.device)
|
||||
mem_active = stats['active_bytes.all.current']
|
||||
mem_reserved = stats['reserved_bytes.all.current']
|
||||
mem_free_cuda, _ = torch.cuda.mem_get_info(q.device)
|
||||
mem_free_torch = mem_reserved - mem_active
|
||||
mem_free_total = mem_free_cuda + mem_free_torch
|
||||
# Divide factor of safety as there's copying and fragmentation
|
||||
return einsum_op_tensor_mem(q, k, v, mem_free_total / 3.3 / (1 << 20))
|
||||
if shared.cmd_opts.use_ipex:
|
||||
stats = torch.xpu.memory_stats("xpu")
|
||||
mem_active = stats['active_bytes.all.current']
|
||||
mem_reserved = stats['reserved_bytes.all.current']
|
||||
mem_free_xpu, _ = [(torch.xpu.get_device_properties("xpu").total_memory - torch.xpu.memory_allocated()), torch.xpu.get_device_properties("xpu").total_memory]
|
||||
mem_free_torch = mem_reserved - mem_active
|
||||
mem_free_total = mem_free_xpu + mem_free_torch
|
||||
# Divide factor of safety as there's copying and fragmentation
|
||||
return einsum_op_tensor_mem(q, k, v, mem_free_total / 3.3 / (1 << 20))
|
||||
else:
|
||||
stats = torch.cuda.memory_stats(q.device)
|
||||
mem_active = stats['active_bytes.all.current']
|
||||
mem_reserved = stats['reserved_bytes.all.current']
|
||||
mem_free_cuda, _ = torch.cuda.mem_get_info(q.device)
|
||||
mem_free_torch = mem_reserved - mem_active
|
||||
mem_free_total = mem_free_cuda + mem_free_torch
|
||||
# Divide factor of safety as there's copying and fragmentation
|
||||
return einsum_op_tensor_mem(q, k, v, mem_free_total / 3.3 / (1 << 20))
|
||||
|
||||
def einsum_op_dml(q, k, v):
|
||||
mem_total, mem_active = torch.dml.memory_stats(q.device)
|
||||
mem_reserved = mem_total / (1 << 20) * 0.7
|
||||
return einsum_op_tensor_mem(q, k, v, (mem_reserved - mem_active) if mem_reserved > mem_active else 1)
|
||||
|
||||
def einsum_op(q, k, v):
|
||||
if shared.cmd_opts.use_ipex:
|
||||
return einsum_op_cuda(q, k, v)
|
||||
|
||||
if q.device.type == 'cuda':
|
||||
return einsum_op_cuda(q, k, v)
|
||||
|
||||
@@ -204,6 +237,9 @@ def einsum_op(q, k, v):
|
||||
return einsum_op_mps_v1(q, k, v)
|
||||
return einsum_op_mps_v2(q, k, v)
|
||||
|
||||
if q.device.type == 'privateuseone':
|
||||
return einsum_op_dml(q, k, v)
|
||||
|
||||
# Smaller slices are faster due to L2/L3/SLC caches.
|
||||
# Tested on i7 with 8MB L3 cache.
|
||||
return einsum_op_tensor_mem(q, k, v, 32)
|
||||
@@ -386,8 +422,12 @@ def scaled_dot_product_attention_forward(self, x, context=None, mask=None):
|
||||
return hidden_states
|
||||
|
||||
def scaled_dot_product_no_mem_attention_forward(self, x, context=None, mask=None):
|
||||
with torch.backends.cuda.sdp_kernel(enable_flash=True, enable_math=True, enable_mem_efficient=False):
|
||||
return scaled_dot_product_attention_forward(self, x, context, mask)
|
||||
if shared.cmd_opts.use_ipex:
|
||||
with torch.backends.xpu.sdp_kernel(enable_flash=True, enable_math=True, enable_mem_efficient=False):
|
||||
return scaled_dot_product_attention_forward(self, x, context, mask)
|
||||
else:
|
||||
with torch.backends.cuda.sdp_kernel(enable_flash=True, enable_math=True, enable_mem_efficient=False):
|
||||
return scaled_dot_product_attention_forward(self, x, context, mask)
|
||||
|
||||
def cross_attention_attnblock_forward(self, x):
|
||||
h_ = x
|
||||
@@ -491,8 +531,12 @@ def sdp_attnblock_forward(self, x):
|
||||
return x + out
|
||||
|
||||
def sdp_no_mem_attnblock_forward(self, x):
|
||||
with torch.backends.cuda.sdp_kernel(enable_flash=True, enable_math=True, enable_mem_efficient=False):
|
||||
return sdp_attnblock_forward(self, x)
|
||||
if shared.cmd_opts.use_ipex:
|
||||
with torch.backends.xpu.sdp_kernel(enable_flash=True, enable_math=True, enable_mem_efficient=False):
|
||||
return sdp_attnblock_forward(self, x)
|
||||
else:
|
||||
with torch.backends.cuda.sdp_kernel(enable_flash=True, enable_math=True, enable_mem_efficient=False):
|
||||
return sdp_attnblock_forward(self, x)
|
||||
|
||||
def sub_quad_attnblock_forward(self, x):
|
||||
h_ = x
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from packaging import version
|
||||
|
||||
from modules import devices
|
||||
from modules.sd_hijack_utils import CondFunc
|
||||
from modules import shared
|
||||
|
||||
|
||||
class TorchHijackForUnet:
|
||||
@@ -67,7 +72,7 @@ def hijack_ddpm_edit():
|
||||
unet_needs_upcast = lambda *args, **kwargs: devices.unet_needs_upcast
|
||||
CondFunc('ldm.models.diffusion.ddpm.LatentDiffusion.apply_model', apply_model, unet_needs_upcast)
|
||||
CondFunc('ldm.modules.diffusionmodules.openaimodel.timestep_embedding', lambda orig_func, timesteps, *args, **kwargs: orig_func(timesteps, *args, **kwargs).to(torch.float32 if timesteps.dtype == torch.int64 else devices.dtype_unet), unet_needs_upcast)
|
||||
if version.parse(torch.__version__) <= version.parse("1.13.2") or torch.cuda.is_available():
|
||||
if version.parse(torch.__version__) <= version.parse("1.13.2") or torch.cuda.is_available() or shared.cmd_opts.use_ipex:
|
||||
CondFunc('ldm.modules.diffusionmodules.util.GroupNorm32.forward', lambda orig_func, self, *args, **kwargs: orig_func(self.float(), *args, **kwargs), unet_needs_upcast)
|
||||
CondFunc('ldm.modules.attention.GEGLU.forward', lambda orig_func, self, x: orig_func(self.float(), x.float()).to(devices.dtype_unet), unet_needs_upcast)
|
||||
CondFunc('open_clip.transformer.ResidualAttentionBlock.__init__', lambda orig_func, *args, **kwargs: kwargs.update({'act_layer': GELUHijack}) and False or orig_func(*args, **kwargs), lambda _, *args, **kwargs: kwargs.get('act_layer') is None or kwargs['act_layer'] == torch.nn.GELU)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
from modules import sd_hijack_clip, devices
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ from os import mkdir
|
||||
from urllib import request
|
||||
from rich import print, progress # pylint: disable=redefined-builtin
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import safetensors.torch
|
||||
from omegaconf import OmegaConf
|
||||
import tomesd
|
||||
@@ -118,7 +122,7 @@ def list_models():
|
||||
checkpoint_info.register()
|
||||
print(f'Available models: {shared.opts.ckpt_dir} {len(checkpoints_list)}')
|
||||
if len(checkpoints_list) == 0:
|
||||
if not shared.cmd_opts.no_download_sd_model:
|
||||
if not shared.cmd_opts.no_download:
|
||||
key = input('Download the default model? (y/N) ')
|
||||
if key.lower().startswith('y'):
|
||||
model_url = "https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned-emaonly.safetensors"
|
||||
@@ -232,6 +236,7 @@ def read_metadata_from_safetensors(filename):
|
||||
|
||||
def read_state_dict(checkpoint_file, map_location=None): # pylint: disable=unused-argument
|
||||
try:
|
||||
pl_sd = None
|
||||
with progress.open(checkpoint_file, 'rb', description=f'Loading weights: [cyan]{checkpoint_file}', auto_refresh=True) as f:
|
||||
_, extension = os.path.splitext(checkpoint_file)
|
||||
if 'v1-5-pruned-emaonly.safetensors' or 'vae-ft-mse-840000-ema-pruned.ckpt' in checkpoint_file:
|
||||
@@ -247,6 +252,7 @@ def read_state_dict(checkpoint_file, map_location=None): # pylint: disable=unuse
|
||||
buffer = io.BytesIO(f.read())
|
||||
pl_sd = torch.load(buffer, map_location='cpu')
|
||||
sd = get_state_dict_from_checkpoint(pl_sd)
|
||||
del pl_sd
|
||||
except Exception as e:
|
||||
errors.display(e, f'loading model: {checkpoint_file}')
|
||||
sd = None
|
||||
@@ -533,7 +539,6 @@ def unload_model_weights(sd_model=None, _info=None):
|
||||
sd_model = None
|
||||
gc.collect()
|
||||
devices.torch_gc()
|
||||
torch.cuda.empty_cache()
|
||||
print(f"Unloaded weights {timer.summary()}")
|
||||
return sd_model
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import os
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
from modules import paths, sd_disable_initialization
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from collections import namedtuple
|
||||
import numpy as np
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from PIL import Image
|
||||
from modules import devices, processing, images, sd_vae_approx
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ import ldm.models.diffusion.plms
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
|
||||
from modules.shared import state
|
||||
from modules import sd_samplers_common, prompt_parser, shared
|
||||
@@ -109,7 +113,6 @@ class VanillaStableDiffusionSampler:
|
||||
else:
|
||||
cond = {"c_concat": [image_conditioning], "c_crossattn": [cond]}
|
||||
unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
|
||||
|
||||
return x, ts, cond, unconditional_conditioning
|
||||
|
||||
def update_step(self, last_latent):
|
||||
@@ -117,17 +120,13 @@ class VanillaStableDiffusionSampler:
|
||||
self.last_latent = self.init_latent * self.mask + self.nmask * last_latent
|
||||
else:
|
||||
self.last_latent = last_latent
|
||||
|
||||
sd_samplers_common.store_latent(self.last_latent)
|
||||
|
||||
self.step += 1
|
||||
state.sampling_step = self.step
|
||||
shared.total_tqdm.update()
|
||||
|
||||
def after_sample(self, x, ts, cond, uncond, res):
|
||||
if not self.is_unipc:
|
||||
self.update_step(res[1])
|
||||
|
||||
return x, ts, cond, uncond, res
|
||||
|
||||
def unipc_after_update(self, x, model_x):
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from collections import deque
|
||||
import inspect
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import k_diffusion.sampling
|
||||
from modules import prompt_parser, devices, sd_samplers_common
|
||||
|
||||
@@ -231,7 +235,6 @@ class KDiffusionSampler:
|
||||
raise sd_samplers_common.InterruptedException
|
||||
|
||||
state.sampling_step = step
|
||||
shared.total_tqdm.update()
|
||||
|
||||
def launch_sampling(self, steps, func):
|
||||
state.sampling_steps = steps
|
||||
|
||||
+7
-1
@@ -3,8 +3,14 @@ import collections
|
||||
import glob
|
||||
from copy import deepcopy
|
||||
from rich import print # pylint: disable=redefined-builtin
|
||||
from modules import shared
|
||||
import torch
|
||||
from modules import paths, shared, devices, script_callbacks, sd_models
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
if shared.cmd_opts.use_ipex:
|
||||
print("Failed to import IPEX")
|
||||
from modules import paths, devices, script_callbacks, sd_models
|
||||
|
||||
|
||||
vae_ignore_keys = {"model_ema.decay", "model_ema.num_updates"}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import os
|
||||
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from torch import nn
|
||||
from modules import devices, paths
|
||||
|
||||
|
||||
+32
-37
@@ -5,18 +5,18 @@ import json
|
||||
import datetime
|
||||
import gradio as gr
|
||||
import tqdm
|
||||
from modules import errors, ui_components, shared_items, cmd_args
|
||||
from modules.paths_internal import models_path, script_path, data_path, sd_configs_path, sd_default_config, sd_model_file, default_sd_model_file, extensions_dir, extensions_builtin_dir # pylint: disable=W0611
|
||||
import modules.interrogate
|
||||
import modules.memmon
|
||||
import modules.styles
|
||||
import modules.devices as devices
|
||||
from modules import errors, ui_components, shared_items, cmd_args
|
||||
from modules.paths_internal import models_path, script_path, data_path, sd_configs_path, sd_default_config, sd_model_file, default_sd_model_file, extensions_dir, extensions_builtin_dir # pylint: disable=W0611
|
||||
import modules.paths_internal as paths
|
||||
from setup import log as setup_log # pylint: disable=E0611
|
||||
from installer import log as central_logger # pylint: disable=E0611
|
||||
|
||||
errors.install(gr)
|
||||
demo: gr.Blocks = None
|
||||
log = setup_log
|
||||
log = central_logger
|
||||
parser = cmd_args.parser
|
||||
url = 'https://github.com/vladmandic/automatic'
|
||||
if os.environ.get('IGNORE_CMD_ARGS_ERRORS', None) is None:
|
||||
@@ -49,14 +49,20 @@ ui_reorder_categories = [
|
||||
"scripts",
|
||||
]
|
||||
|
||||
cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or cmd_opts.server_name) and not cmd_opts.enable_insecure
|
||||
cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or cmd_opts.server_name) and not cmd_opts.insecure
|
||||
devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_esrgan, devices.device_codeformer = (devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'esrgan', 'codeformer'])
|
||||
device = devices.device
|
||||
is_device_dml = False
|
||||
sd_upscalers = []
|
||||
sd_model = None
|
||||
clip_model = None
|
||||
|
||||
|
||||
if device.type == 'privateuseone':
|
||||
import modules.dml # pylint: disable=ungrouped-imports
|
||||
is_device_dml = True
|
||||
|
||||
|
||||
def reload_hypernetworks():
|
||||
from modules.hypernetworks import hypernetwork
|
||||
global hypernetworks # pylint: disable=W0603
|
||||
@@ -223,27 +229,21 @@ options_templates.update(options_section(('sd', "Stable Diffusion"), {
|
||||
"sd_checkpoint_cache": OptionInfo(0, "Model checkpoints to cache in RAM", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae_checkpoint_cache": OptionInfo(0, "VAE checkpoints to cache in RAM", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1}),
|
||||
"sd_vae": OptionInfo("Automatic", "Select VAE", gr.Dropdown, lambda: {"choices": shared_items.sd_vae_items()}, refresh=shared_items.refresh_vae_list),
|
||||
"sd_vae_as_default": OptionInfo(True, "Ignore selected VAE for stable diffusion checkpoints that have their own .vae.pt next to them", gr.Checkbox, {"visible": False}),
|
||||
"inpainting_mask_weight": OptionInfo(1.0, "Inpainting conditioning mask strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"initial_noise_multiplier": OptionInfo(1.0, "Noise multiplier for img2img", gr.Slider, {"minimum": 0.5, "maximum": 1.5, "step": 0.01}),
|
||||
"img2img_color_correction": OptionInfo(False, "Apply color correction to img2img results to match original colors."),
|
||||
"img2img_fix_steps": OptionInfo(False, "For image processing do exactly the amount of steps as specified."),
|
||||
"img2img_background_color": OptionInfo("#ffffff", "With img2img, fill image's transparent parts with this color.", ui_components.FormColorPicker, {}),
|
||||
"enable_quantization": OptionInfo(True, "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds."),
|
||||
"enable_emphasis": OptionInfo(True, "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention", gr.Checkbox, {"visible": False}),
|
||||
"enable_batch_seeds": OptionInfo(True, "Make K-diffusion samplers produce same images in a batch as when making a single image", gr.Checkbox, {"visible": False}),
|
||||
"comma_padding_backtrack": OptionInfo(20, "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens", gr.Slider, {"minimum": 0, "maximum": 74, "step": 1 }),
|
||||
"CLIP_stop_at_last_layers": OptionInfo(1, "Clip skip", gr.Slider, {"minimum": 1, "maximum": 12, "step": 1, "visible": False}),
|
||||
"upcast_attn": OptionInfo(False, "Upcast cross attention layer to float32"),
|
||||
"cross_attention_optimization": OptionInfo("Scaled-Dot-Product", "Cross-attention optimization method", gr.Radio, lambda: {"choices": shared_items.list_crossattention() }),
|
||||
"cross_attention_optimization": OptionInfo("Sub-quadratic" if is_device_dml else "Scaled-Dot-Product", "Cross-attention optimization method", gr.Radio, lambda: {"choices": shared_items.list_crossattention() }),
|
||||
"cross_attention_options": OptionInfo([], "Cross-attention advanced options", gr.CheckboxGroup, lambda: {"choices": ['xFormers enable flash Attention', 'SDP disable memory attention']}),
|
||||
"sub_quad_q_chunk_size": OptionInfo(512, "Sub-quadratic cross-attention query chunk size for the layer optimization to use", gr.Slider, {"minimum": 16, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_kv_chunk_size": OptionInfo(512, "Sub-quadratic cross-attentionkv chunk size for the sub-quadratic cross-attention layer optimization to use", gr.Slider, {"minimum": 0, "maximum": 8192, "step": 8}),
|
||||
"sub_quad_chunk_threshold": OptionInfo(80, "Sub-quadratic cross-attention percentage of VRAM chunking threshold", gr.Slider, {"minimum": 0, "maximum": 100, "step": 1}),
|
||||
"always_batch_cond_uncond": OptionInfo(False, "Disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram"),
|
||||
"multiple_tqdm": OptionInfo(False, "Add a second progress bar to the console that shows progress for an entire job.", gr.Checkbox, {"visible": False}),
|
||||
"print_hypernet_extra": OptionInfo(False, "Print extra hypernetwork information to console.", gr.Checkbox, {"visible": False}),
|
||||
"dimensions_and_batch_together": OptionInfo(True, "", gr.Checkbox, {"visible": False}),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('system-paths', "System Paths"), {
|
||||
@@ -252,8 +252,6 @@ options_templates.update(options_section(('system-paths', "System Paths"), {
|
||||
"ckpt_dir": OptionInfo(os.path.join(paths.models_path, 'Stable-diffusion'), "Path to directory with stable diffusion checkpoints"),
|
||||
"vae_dir": OptionInfo(os.path.join(paths.models_path, 'VAE'), "Path to directory with VAE files"),
|
||||
"embeddings_dir": OptionInfo(os.path.join(paths.models_path, 'embeddings'), "Embeddings directory for textual inversion"),
|
||||
"embeddings_templates_dir": OptionInfo(os.path.join(paths.script_path, 'train/templates'), "Embeddings train templates directory"),
|
||||
"embeddings_train_log": OptionInfo(os.path.join(paths.script_path, 'train.csv'), "Embeddings train log file"),
|
||||
"hypernetwork_dir": OptionInfo(os.path.join(paths.models_path, 'hypernetworks'), "Hypernetwork directory"),
|
||||
"codeformer_models_path": OptionInfo(os.path.join(paths.models_path, 'Codeformer'), "Path to directory with codeformer model file(s)."),
|
||||
"gfpgan_models_path": OptionInfo(os.path.join(paths.models_path, 'GFPGAN'), "Path to directory with GFPGAN model file(s)"),
|
||||
@@ -316,9 +314,9 @@ options_templates.update(options_section(('cuda', "CUDA Settings"), {
|
||||
"memmon_poll_rate": OptionInfo(2, "VRAM usage polls per second during generation. Set to 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}),
|
||||
"precision": OptionInfo("Autocast", "Precision type", gr.Radio, lambda: {"choices": ["Autocast", "Full"]}),
|
||||
"cuda_dtype": OptionInfo("FP32" if sys.platform == "darwin" else "FP16", "Device precision type", gr.Radio, lambda: {"choices": ["FP32", "FP16", "BF16"]}),
|
||||
"no_half": OptionInfo(False, "Use full precision for model (--no-half)"),
|
||||
"no_half_vae": OptionInfo(False, "Use full precision for VAE (--no-half-vae)"),
|
||||
"upcast_sampling": OptionInfo(True if sys.platform == "darwin" else False, "Enable upcast sampling. Usually produces similar results to --no-half with better performance while using less memory"),
|
||||
"no_half": OptionInfo(True if is_device_dml else False, "Use full precision for model (--no-half)", None, None, lambda: print("Warning: Most of DirectML devices do not fully support half mode. Recommend to use full precision to model.") if is_device_dml else None),
|
||||
"no_half_vae": OptionInfo(True if is_device_dml else False, "Use full precision for VAE (--no-half-vae)"),
|
||||
"upcast_sampling": OptionInfo(True if sys.platform == "darwin" or cmd_opts.use_ipex else False, "Enable upcast sampling. Usually produces similar results to --no-half with better performance while using less memory"),
|
||||
"disable_nan_check": OptionInfo(True, "Do not check if produced images/latent spaces have NaN values"),
|
||||
"rollback_vae": OptionInfo(False, "Attempt to roll back VAE when produced NaN values, requires NaN check (experimental)"),
|
||||
"opt_channelslast": OptionInfo(False, "Use channels last as torch memory format "),
|
||||
@@ -326,15 +324,17 @@ options_templates.update(options_section(('cuda', "CUDA Settings"), {
|
||||
"cuda_allow_tf32": OptionInfo(True, "Allow TF32 math ops"),
|
||||
"cuda_allow_tf16_reduced": OptionInfo(True, "Allow TF16 reduced precision math ops"),
|
||||
"cuda_compile": OptionInfo(False, "Enable model compile (experimental)"),
|
||||
"cuda_compile_mode": OptionInfo("none", "Model compile mode (experimental)", gr.Radio, lambda: {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser']}),
|
||||
"cuda_compile_mode": OptionInfo("none", "Model compile mode (experimental)", gr.Radio, lambda: {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet']}),
|
||||
"cuda_compile_verbose": OptionInfo(True, "Model compile verbose mode"),
|
||||
"cuda_compile_errors": OptionInfo(True, "Model compile suppress errors"),
|
||||
}))
|
||||
|
||||
options_templates.update(options_section(('upscaling', "Upscaling"), {
|
||||
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers. 0 = no tiling.", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
"ESRGAN_tile_overlap": OptionInfo(8, "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
|
||||
"realesrgan_enabled_models": OptionInfo(["R-ESRGAN 4x+", "R-ESRGAN 4x+ Anime6B"], "Select which Real-ESRGAN models to show in the web UI.", gr.CheckboxGroup, lambda: {"choices": shared_items.realesrgan_models_names()}),
|
||||
"ESRGAN_tile": OptionInfo(192, "Tile size for ESRGAN upscalers (0 = no tiling)", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
"ESRGAN_tile_overlap": OptionInfo(8, "Tile overlap in pixels for ESRGAN upscalers", gr.Slider, {"minimum": 0, "maximum": 48, "step": 1}),
|
||||
"realesrgan_enabled_models": OptionInfo(["R-ESRGAN 4x+", "R-ESRGAN 4x+ Anime6B"], "Real-ESRGAN available models", gr.CheckboxGroup, lambda: {"choices": shared_items.realesrgan_models_names()}),
|
||||
"upscaler_for_img2img": OptionInfo("None", "Default upscaler for image resize operations", gr.Dropdown, lambda: {"choices": [x.name for x in sd_upscalers]}),
|
||||
"use_old_hires_fix_width_height": OptionInfo(False, "For hires fix, use width/height sliders to set final resolution rather than first pass (disables Upscale by, Resize width/height to)."),
|
||||
"use_old_hires_fix_width_height": OptionInfo(False, "Hires fix uses width & height to set final resolution rather than first pass"),
|
||||
"dont_fix_second_order_samplers_schedule": OptionInfo(False, "Do not fix prompt schedule for second order samplers."),
|
||||
}))
|
||||
|
||||
@@ -351,6 +351,7 @@ options_templates.update(options_section(('training', "Training"), {
|
||||
"save_training_settings_to_txt": OptionInfo(True, "Save textual inversion and hypernet settings to a text file whenever training starts."),
|
||||
"dataset_filename_word_regex": OptionInfo("", "Filename word regex"),
|
||||
"dataset_filename_join_string": OptionInfo(" ", "Filename join string"),
|
||||
"embeddings_templates_dir": OptionInfo(os.path.join(paths.script_path, 'train', 'templates'), "Embeddings train templates directory"),
|
||||
"training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}),
|
||||
"training_write_csv_every": OptionInfo(0, "Save an csv containing the loss to log directory every N steps, 0 to disable"),
|
||||
"training_enable_tensorboard": OptionInfo(False, "Enable tensorboard logging."),
|
||||
@@ -387,16 +388,10 @@ options_templates.update(options_section(('ui', "User interface"), {
|
||||
"return_grid": OptionInfo(True, "Show grid in results for web"),
|
||||
"return_mask": OptionInfo(False, "For inpainting, include the greyscale mask in results for web"),
|
||||
"return_mask_composite": OptionInfo(False, "For inpainting, include masked composite in results for web"),
|
||||
"do_not_show_images": OptionInfo(False, "Do not show any images in results for web"),
|
||||
"add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"),
|
||||
"add_model_name_to_info": OptionInfo(True, "Add model name to generation information"),
|
||||
"disable_weights_auto_swap": OptionInfo(True, "Do not change the selected model when reading generation parameters."),
|
||||
"send_seed": OptionInfo(True, "Send seed when sending prompt or image to other interface"),
|
||||
"send_size": OptionInfo(True, "Send size when sending prompt or image to another interface"),
|
||||
"font": OptionInfo("", "Font for image grids that have text"),
|
||||
"js_modal_lightbox": OptionInfo(True, "Enable full page image viewer", gr.Checkbox, {"visible": False}),
|
||||
"js_modal_lightbox_initially_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer", gr.Checkbox, {"visible": False}),
|
||||
"show_progress_in_title": OptionInfo(False, "Show generation progress in window title.", gr.Checkbox, {"visible": False}),
|
||||
"keyedit_precision_attention": OptionInfo(0.1, "Ctrl+up/down precision when editing (attention:1.1)", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
|
||||
"keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
|
||||
"quicksettings": OptionInfo("sd_model_checkpoint", "Quicksettings list"),
|
||||
@@ -417,7 +412,7 @@ options_templates.update(options_section(('ui', "Live previews"), {
|
||||
|
||||
options_templates.update(options_section(('sampler-params', "Sampler parameters"), {
|
||||
"show_samplers": OptionInfo(["Euler a", "UniPC", "DDIM", "DPM++ SDE", "DPM++ SDE", "DPM2 Karras", "DPM++ 2M Karras"], "Show samplers in user interface", gr.CheckboxGroup, lambda: {"choices": [x.name for x in list_samplers()]}),
|
||||
"fallback_sampler": OptionInfo("Euler a", "Fallback sampler if primary sampler is not compatible", gr.Dropdown, lambda: {"choices": [x.name for x in list_samplers()]}),
|
||||
"fallback_sampler": OptionInfo("Euler a", "Secondary sampler", gr.Dropdown, lambda: {"choices": ["None"] + [x.name for x in list_samplers()]}),
|
||||
"eta_ancestral": OptionInfo(1.0, "Noise multiplier for ancestral samplers (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"eta_ddim": OptionInfo(0.0, "Noise multiplier for DDIM (eta)", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
"ddim_discretize": OptionInfo('uniform', "DDIM discretize img2img", gr.Radio, {"choices": ['uniform', 'quad']}),
|
||||
@@ -434,14 +429,14 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters"
|
||||
|
||||
options_templates.update(options_section(('token_merging', 'Token Merging'), {
|
||||
"token_merging": OptionInfo(False, "Enable redundant token merging via tomesd. This can provide significant speed and memory improvements.", gr.Checkbox),
|
||||
"token_merging_ratio": OptionInfo(0.5, "Merging Ratio", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
|
||||
"token_merging_ratio": OptionInfo(0.5, "Merging Ratio. Higher merging ratio = faster generation, smaller VRAM usage, lower quality.", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
|
||||
"token_merging_hr_only": OptionInfo(True, "Apply only to high-res fix pass. Disabling can yield a ~20-35% speedup on contemporary resolutions.", gr.Checkbox),
|
||||
"token_merging_ratio_hr": OptionInfo(0.5, "Merging Ratio (high-res pass) - If 'Apply only to high-res' is enabled, this will always be the ratio used.", gr.Slider, {"minimum": 0, "maximum": 0.9, "step": 0.1}),
|
||||
"token_merging_random": OptionInfo(False, "Use random perturbations - Can improve outputs for certain samplers. For others, it may cause visual artifacting.", gr.Checkbox),
|
||||
"token_merging_merge_attention": OptionInfo(True, "Merge attention", gr.Checkbox),
|
||||
"token_merging_merge_cross_attention": OptionInfo(False, "Merge cross attention", gr.Checkbox),
|
||||
"token_merging_merge_mlp": OptionInfo(False, "Merge mlp", gr.Checkbox),
|
||||
"token_merging_maximum_down_sampling": OptionInfo(1, "Maximum down sampling", gr.Dropdown, lambda: {"choices": ["1", "2", "4", "8"]}),
|
||||
"token_merging_merge_attention": OptionInfo(True, "Merge attention (Recommend on)", gr.Checkbox),
|
||||
"token_merging_merge_cross_attention": OptionInfo(False, "Merge cross attention (Recommend off)", gr.Checkbox),
|
||||
"token_merging_merge_mlp": OptionInfo(False, "Merge mlp (Strongly recommend off)", gr.Checkbox),
|
||||
"token_merging_maximum_down_sampling": OptionInfo(1, "Maximum down sampling", gr.Radio, lambda: {"choices": [1, 2, 4, 8]}),
|
||||
"token_merging_stride_x": OptionInfo(2, "Stride - X", gr.Slider, {"minimum": 2, "maximum": 8, "step": 2}),
|
||||
"token_merging_stride_y": OptionInfo(2, "Stride - Y", gr.Slider, {"minimum": 2, "maximum": 8, "step": 2})
|
||||
}))
|
||||
@@ -472,7 +467,7 @@ class Options:
|
||||
def __setattr__(self, key, value):
|
||||
if self.data is not None:
|
||||
if key in self.data or key in self.data_labels:
|
||||
if cmd_opts.freeze_settings:
|
||||
if cmd_opts.freeze:
|
||||
print(f'Settings are frozen: {key}')
|
||||
return
|
||||
if cmd_opts.hide_ui_dir_config and key in restricted_opts:
|
||||
@@ -518,7 +513,7 @@ class Options:
|
||||
return data_label.default
|
||||
|
||||
def save(self, filename):
|
||||
assert not cmd_opts.freeze_settings, "saving settings is disabled"
|
||||
assert not cmd_opts.freeze, "saving settings is disabled"
|
||||
with open(filename, "w", encoding="utf8") as file:
|
||||
json.dump(self.data, file, indent=4)
|
||||
|
||||
@@ -591,7 +586,7 @@ opts = Options()
|
||||
batch_cond_uncond = opts.always_batch_cond_uncond or not (cmd_opts.lowvram or cmd_opts.medvram)
|
||||
parallel_processing_allowed = not cmd_opts.lowvram and not cmd_opts.medvram
|
||||
xformers_available = False
|
||||
config_filename = cmd_opts.ui_settings_file
|
||||
config_filename = cmd_opts.config
|
||||
os.makedirs(opts.hypernetwork_dir, exist_ok=True)
|
||||
hypernetworks = {}
|
||||
loaded_hypernetworks = []
|
||||
|
||||
@@ -14,6 +14,10 @@ from functools import partial
|
||||
import math
|
||||
from typing import Optional, NamedTuple, List
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from torch import Tensor
|
||||
from torch.utils.checkpoint import checkpoint
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@ import os
|
||||
import numpy as np
|
||||
import PIL
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from PIL import Image
|
||||
from torch.utils.data import Dataset, DataLoader, Sampler
|
||||
from torchvision import transforms
|
||||
|
||||
@@ -4,6 +4,10 @@ import numpy as np
|
||||
import zlib
|
||||
from PIL import Image, PngImagePlugin, ImageDraw, ImageFont
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
from modules.shared import opts
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
saved_params_shared = {"model_name", "model_hash", "initial_step", "num_of_dataset_images", "learn_rate", "batch_size", "clip_grad_mode", "clip_grad_value", "gradient_step", "data_root", "log_directory", "training_width", "training_height", "steps", "create_image_every", "template_file", "gradient_step", "latent_sampling_method"}
|
||||
saved_params_shared = {"model_name", "model_hash", "initial_step", "num_of_dataset_images", "learn_rate", "batch_size", "clip_grad_mode", "clip_grad_value", "gradient_step", "data_root", "log_directory", "training_width", "training_height", "steps", "create_image_every", "template_file", "latent_sampling_method"}
|
||||
saved_params_ti = {"embedding_name", "num_vectors_per_token", "save_embedding_every", "save_image_with_stored_embedding"}
|
||||
saved_params_hypernet = {"hypernetwork_name", "layer_structure", "activation_func", "weight_init", "add_layer_norm", "use_dropout", "save_hypernetwork_every"}
|
||||
saved_params_all = saved_params_shared | saved_params_ti | saved_params_hypernet
|
||||
@@ -12,13 +12,11 @@ saved_params_previews = {"preview_prompt", "preview_negative_prompt", "preview_s
|
||||
def save_settings_to_file(log_directory, all_params):
|
||||
now = datetime.datetime.now()
|
||||
params = {"datetime": now.strftime("%Y-%m-%d %H:%M:%S")}
|
||||
|
||||
keys = saved_params_all
|
||||
if all_params.get('preview_from_txt2img'):
|
||||
keys = keys | saved_params_previews
|
||||
|
||||
params.update({k: v for k, v in all_params.items() if k in keys})
|
||||
|
||||
filename = f'settings.json'
|
||||
with open(os.path.join(log_directory, filename), "w") as file:
|
||||
filename = f"{params['embedding_name']}-{now.strftime('%Y-%m-%d_%H-%M-%S')}.json"
|
||||
with open(os.path.join(log_directory, filename), "w", encoding='utf-8') as file:
|
||||
print(f'Training settings file: {os.path.join(log_directory, filename)}')
|
||||
json.dump(params, file, indent=2)
|
||||
|
||||
@@ -3,6 +3,10 @@ import html
|
||||
import csv
|
||||
from collections import namedtuple
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
|
||||
except:
|
||||
pass
|
||||
import tqdm
|
||||
import safetensors.torch
|
||||
from rich import print # pylint: disable=redefined-builtin
|
||||
@@ -174,7 +178,7 @@ class EmbeddingDatabase:
|
||||
if len(emb.shape) == 1:
|
||||
emb = emb.unsqueeze(0)
|
||||
else:
|
||||
raise Exception(f"Couldn't identify {filename} as neither textual inversion embedding nor diffuser concept.")
|
||||
raise RuntimeError(f"Couldn't identify {filename} as neither textual inversion embedding nor diffuser concept.")
|
||||
|
||||
vec = emb.detach().to(devices.device, dtype=torch.float32)
|
||||
embedding = Embedding(vec, name)
|
||||
@@ -279,20 +283,15 @@ def create_embedding(name, num_vectors_per_token, overwrite_old, init_text='*'):
|
||||
def write_loss(log_directory, filename, step, epoch_len, values):
|
||||
if shared.opts.training_write_csv_every == 0:
|
||||
return
|
||||
|
||||
if step % epoch_len != 0:
|
||||
if step % shared.opts.training_write_csv_every != 0:
|
||||
return
|
||||
write_csv_header = False if os.path.exists(os.path.join(log_directory, filename)) else True
|
||||
|
||||
with open(os.path.join(log_directory, filename), "a+", newline='', encoding='utf-8') as fout:
|
||||
csv_writer = csv.DictWriter(fout, fieldnames=["step", "epoch", "epoch_step", *(values.keys())])
|
||||
|
||||
if write_csv_header:
|
||||
csv_writer.writeheader()
|
||||
|
||||
epoch = (step - 1) // epoch_len
|
||||
epoch_step = (step - 1) % epoch_len
|
||||
|
||||
csv_writer.writerow({
|
||||
"step": step,
|
||||
"epoch": epoch,
|
||||
@@ -347,7 +346,8 @@ def validate_train_inputs(model_name, learn_rate, batch_size, gradient_step, dat
|
||||
assert log_directory, "Log directory is empty"
|
||||
|
||||
|
||||
def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, use_weight, create_image_every, save_embedding_every, template_filename, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height):
|
||||
def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, use_weight, create_image_every, save_embedding_every, template_filename, save_image_with_stored_embedding, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): # pylint: disable=unused_argument
|
||||
|
||||
save_embedding_every = save_embedding_every or 0
|
||||
create_image_every = create_image_every or 0
|
||||
template_file = textual_inversion_templates.get(template_filename, None)
|
||||
@@ -405,16 +405,11 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
tensorboard_writer = tensorboard_setup(log_directory)
|
||||
|
||||
pin_memory = shared.opts.pin_memory
|
||||
|
||||
ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=embedding_name, model=shared.sd_model, cond_model=shared.sd_model.cond_stage_model, device=devices.device, template_file=template_file, batch_size=batch_size, gradient_step=gradient_step, shuffle_tags=shuffle_tags, tag_drop_out=tag_drop_out, latent_sampling_method=latent_sampling_method, varsize=varsize, use_weight=use_weight)
|
||||
|
||||
if shared.opts.save_training_settings_to_txt:
|
||||
save_settings_to_file(log_directory, {**dict(model_name=checkpoint.model_name, model_hash=checkpoint.shorthash, num_of_dataset_images=len(ds), num_vectors_per_token=len(embedding.vec)), **locals()})
|
||||
|
||||
latent_sampling_method = ds.latent_sampling_method
|
||||
|
||||
dl = modules.textual_inversion.dataset.PersonalizedDataLoader(ds, latent_sampling_method=latent_sampling_method, batch_size=ds.batch_size, pin_memory=pin_memory)
|
||||
|
||||
if unload:
|
||||
shared.parallel_processing_allowed = False
|
||||
shared.sd_model.first_stage_model.to(devices.cpu)
|
||||
@@ -427,14 +422,16 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
optimizer_saved_dict = torch.load(filename + '.optim', map_location='cpu')
|
||||
if embedding.checksum() == optimizer_saved_dict.get('hash', None):
|
||||
optimizer_state_dict = optimizer_saved_dict.get('optimizer_state_dict', None)
|
||||
|
||||
if optimizer_state_dict is not None:
|
||||
optimizer.load_state_dict(optimizer_state_dict)
|
||||
print("Loaded existing optimizer from checkpoint")
|
||||
else:
|
||||
print("No saved optimizer exists in checkpoint")
|
||||
|
||||
scaler = torch.cuda.amp.GradScaler()
|
||||
if shared.cmd_opts.use_ipex:
|
||||
scaler = torch.xpu.amp.GradScaler()
|
||||
else:
|
||||
scaler = torch.cuda.amp.GradScaler()
|
||||
|
||||
batch_size = ds.batch_size
|
||||
gradient_step = ds.gradient_step
|
||||
@@ -443,12 +440,10 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
max_steps_per_epoch = len(ds) // batch_size - (len(ds) // batch_size) % gradient_step
|
||||
loss_step = 0
|
||||
_loss_step = 0 #internal
|
||||
|
||||
last_saved_file = "<none>"
|
||||
last_saved_image = "<none>"
|
||||
forced_filename = "<none>"
|
||||
embedding_yet_to_be_embedded = False
|
||||
|
||||
is_training_inpainting_model = shared.sd_model.model.conditioning_key in {'hybrid', 'concat'}
|
||||
img_c = None
|
||||
|
||||
@@ -470,7 +465,6 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
break
|
||||
if shared.state.interrupted:
|
||||
break
|
||||
|
||||
if clip_grad:
|
||||
clip_grad_sched.step(embedding.step)
|
||||
|
||||
@@ -479,32 +473,26 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
if use_weight:
|
||||
w = batch.weight.to(devices.device, non_blocking=pin_memory)
|
||||
c = shared.sd_model.cond_stage_model(batch.cond_text)
|
||||
|
||||
if is_training_inpainting_model:
|
||||
if img_c is None:
|
||||
img_c = processing.txt2img_image_conditioning(shared.sd_model, c, training_width, training_height)
|
||||
|
||||
cond = {"c_concat": [img_c], "c_crossattn": [c]}
|
||||
else:
|
||||
cond = c
|
||||
|
||||
if use_weight:
|
||||
loss = shared.sd_model.weighted_forward(x, cond, w)[0] / gradient_step
|
||||
del w
|
||||
else:
|
||||
loss = shared.sd_model.forward(x, cond)[0] / gradient_step
|
||||
del x
|
||||
|
||||
_loss_step += loss.item()
|
||||
scaler.scale(loss).backward()
|
||||
|
||||
scaler.scale(loss).backward()
|
||||
# go back until we reach gradient accumulation steps
|
||||
if (j + 1) % gradient_step != 0:
|
||||
continue
|
||||
|
||||
if clip_grad:
|
||||
clip_grad(embedding.vec, clip_grad_sched.learn_rate)
|
||||
|
||||
scaler.step(optimizer)
|
||||
scaler.update()
|
||||
embedding.step += 1
|
||||
@@ -512,9 +500,7 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
optimizer.zero_grad(set_to_none=True)
|
||||
loss_step = _loss_step
|
||||
_loss_step = 0
|
||||
|
||||
steps_done = embedding.step + 1
|
||||
|
||||
epoch_num = embedding.step // steps_per_epoch
|
||||
|
||||
description = f"Training textual inversion step {embedding.step} loss: {loss_step:.5f} lr: {scheduler.learn_rate:.5f}"
|
||||
@@ -526,15 +512,11 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
save_embedding(embedding, optimizer, checkpoint, embedding_name_every, last_saved_file, remove_cached_checksum=True)
|
||||
embedding_yet_to_be_embedded = True
|
||||
|
||||
write_loss(log_directory, shared.ops.embeddings_train_log, embedding.step, steps_per_epoch, {
|
||||
"loss": f"{loss_step:.7f}",
|
||||
"learn_rate": scheduler.learn_rate
|
||||
})
|
||||
write_loss(log_directory, f"{embedding_name}.csv", embedding.step, steps_per_epoch, { "loss": f"{loss_step:.7f}", "learn_rate": scheduler.learn_rate })
|
||||
|
||||
if images_dir is not None and steps_done % create_image_every == 0:
|
||||
forced_filename = f'{embedding_name}-{steps_done}'
|
||||
last_saved_image = os.path.join(images_dir, forced_filename)
|
||||
|
||||
shared.sd_model.first_stage_model.to(devices.device)
|
||||
|
||||
p = processing.StableDiffusionProcessingTxt2Img(
|
||||
@@ -560,7 +542,6 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
p.height = training_height
|
||||
|
||||
preview_text = p.prompt
|
||||
|
||||
processed = processing.process_images(p)
|
||||
image = processed.images[0] if len(processed.images) > 0 else None
|
||||
|
||||
@@ -569,35 +550,27 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
|
||||
if image is not None:
|
||||
shared.state.assign_current_image(image)
|
||||
|
||||
last_saved_image, _last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename, save_to_dirs=False)
|
||||
last_saved_image += f", prompt: {preview_text}"
|
||||
|
||||
if shared.opts.training_enable_tensorboard and shared.opts.training_tensorboard_save_images:
|
||||
tensorboard_add_image(tensorboard_writer, f"Validation at epoch {epoch_num}", image, embedding.step)
|
||||
|
||||
if save_image_with_stored_embedding and os.path.exists(last_saved_file) and embedding_yet_to_be_embedded:
|
||||
|
||||
last_saved_image_chunks = os.path.join(images_embeds_dir, f'{embedding_name}-{steps_done}.png')
|
||||
|
||||
info = PngImagePlugin.PngInfo()
|
||||
data = torch.load(last_saved_file)
|
||||
info.add_text("sd-ti-embedding", embedding_to_b64(data))
|
||||
title = f"<{data.get('name', '???')}>"
|
||||
|
||||
try:
|
||||
vectorSize = list(data['string_to_param'].values())[0].shape[0]
|
||||
except Exception:
|
||||
vectorSize = '?'
|
||||
|
||||
checkpoint = sd_models.select_checkpoint()
|
||||
footer_left = checkpoint.model_name
|
||||
footer_mid = f'[{checkpoint.shorthash}]'
|
||||
footer_right = f'{vectorSize}v {steps_done}s'
|
||||
|
||||
captioned_image = caption_image_overlay(image, title, footer_left, footer_mid, footer_right)
|
||||
captioned_image = insert_image_data_embed(captioned_image, data)
|
||||
|
||||
captioned_image.save(last_saved_image_chunks, "PNG", pnginfo=info)
|
||||
embedding_yet_to_be_embedded = False
|
||||
|
||||
@@ -605,7 +578,6 @@ def train_embedding(id_task, embedding_name, learn_rate, batch_size, gradient_st
|
||||
last_saved_image += f", prompt: {preview_text}"
|
||||
|
||||
shared.state.job_no = embedding.step
|
||||
|
||||
shared.state.textinfo = f"""
|
||||
<p>
|
||||
Loss: {loss_step:.7f}<br/>
|
||||
@@ -625,7 +597,6 @@ Last saved image: {html.escape(last_saved_image)}<br/>
|
||||
shared.sd_model.first_stage_model.to(devices.device)
|
||||
shared.parallel_processing_allowed = old_parallel_processing_allowed
|
||||
sd_hijack_checkpoint.remove()
|
||||
|
||||
return embedding, filename
|
||||
|
||||
|
||||
|
||||
+5
-7
@@ -1,16 +1,15 @@
|
||||
import modules.scripts
|
||||
from modules import sd_samplers
|
||||
from modules.generation_parameters_copypaste import create_override_settings_dict
|
||||
from modules.processing import StableDiffusionProcessingTxt2Img, process_images
|
||||
from modules.shared import opts
|
||||
import modules.shared as shared
|
||||
from modules.processing import StableDiffusionProcessingTxt2Img, process_images, memory_stats
|
||||
from modules.shared import opts, sd_model, cmd_opts, log
|
||||
from modules.ui import plaintext_to_html
|
||||
|
||||
|
||||
def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, seed_enable_extras: bool, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, override_settings_texts, *args): # pylint: disable=unused-argument
|
||||
override_settings = create_override_settings_dict(override_settings_texts)
|
||||
p = StableDiffusionProcessingTxt2Img(
|
||||
sd_model=shared.sd_model,
|
||||
sd_model=sd_model,
|
||||
outpath_samples=opts.outdir_samples or opts.outdir_txt2img_samples,
|
||||
outpath_grids=opts.outdir_grids or opts.outdir_txt2img_grids,
|
||||
prompt=prompt,
|
||||
@@ -46,8 +45,7 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step
|
||||
if processed is None:
|
||||
processed = process_images(p)
|
||||
p.close()
|
||||
shared.total_tqdm.clear()
|
||||
generation_info_js = processed.js()
|
||||
if opts.do_not_show_images:
|
||||
processed.images = []
|
||||
if cmd_opts.debug:
|
||||
log.info(f'Processed: {len(processed.images)} Memory: {memory_stats()} txt')
|
||||
return processed.images, generation_info_js, plaintext_to_html(processed.info), plaintext_to_html(processed.comments)
|
||||
|
||||
+4
-4
@@ -254,7 +254,7 @@ def setup_progressbar(*args, **kwargs): # pylint: disable=unused-argument
|
||||
def apply_setting(key, value):
|
||||
if value is None:
|
||||
return gr.update()
|
||||
if shared.cmd_opts.freeze_settings:
|
||||
if shared.cmd_opts.freeze:
|
||||
return gr.update()
|
||||
# dont allow model to be swapped when model hash exists in prompt
|
||||
if key == "sd_model_checkpoint" and opts.disable_weights_auto_swap:
|
||||
@@ -354,8 +354,8 @@ def create_ui():
|
||||
batch_size = gr.Slider(minimum=1, maximum=32, step=1, label='Batch size', value=1, elem_id="txt2img_batch_size")
|
||||
elif category == "cfg":
|
||||
with FormRow():
|
||||
cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0, elem_id="txt2img_cfg_scale")
|
||||
clip_skip = gr.Slider(label='CLIP Skip', value=1, minimum=1, maximum=4, step=1, elem_id='txt2img_clip_skip', interactive=True)
|
||||
cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=6.0, elem_id="txt2img_cfg_scale")
|
||||
clip_skip = gr.Slider(label='CLIP Skip', value=shared.opts.CLIP_stop_at_last_layers, minimum=1, maximum=4, step=1, elem_id='txt2img_clip_skip', interactive=True)
|
||||
clip_skip.change(fn=change_clip_skip, show_progress=False, inputs=clip_skip)
|
||||
elif category == "seed":
|
||||
seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs('txt2img')
|
||||
@@ -1292,7 +1292,7 @@ def create_ui():
|
||||
current_row = gr.Column(variant='compact')
|
||||
current_row.__enter__()
|
||||
previous_section = item.section
|
||||
if k in quicksettings_names and not shared.cmd_opts.freeze_settings:
|
||||
if k in quicksettings_names and not shared.cmd_opts.freeze:
|
||||
quicksettings_list.append((i, k, item))
|
||||
components.append(dummy_component)
|
||||
elif section_must_be_skipped:
|
||||
|
||||
@@ -66,10 +66,12 @@ def save_files(js_data, images, do_make_zip, index):
|
||||
|
||||
for image_index, filedata in enumerate(images, start_index):
|
||||
image = image_from_url_text(filedata)
|
||||
|
||||
is_grid = image_index < p.index_of_first_image
|
||||
i = 0 if is_grid else (image_index - p.index_of_first_image)
|
||||
|
||||
if len(p.all_seeds) <= i:
|
||||
p.all_seeds.append(p.seed)
|
||||
if len(p.all_prompts) <= i:
|
||||
p.all_prompts.append(p.prompt)
|
||||
fullfn, txt_fullfn = modules.images.save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs)
|
||||
|
||||
filename = os.path.relpath(fullfn, path)
|
||||
|
||||
@@ -54,7 +54,8 @@ class ExtraNetworksPage:
|
||||
def __init__(self, title):
|
||||
self.title = title
|
||||
self.name = title.lower()
|
||||
self.card_page = shared.html("extra-networks-card.html")
|
||||
self.card_long = shared.html("extra-networks-card-long.html")
|
||||
self.card_short = shared.html("extra-networks-card-short.html")
|
||||
self.allow_negative_prompt = False
|
||||
self.metadata = {}
|
||||
|
||||
@@ -128,10 +129,6 @@ class ExtraNetworksPage:
|
||||
height = f"height: {shared.opts.extra_networks_card_height}px;" if shared.opts.extra_networks_card_height else ''
|
||||
width = f"width: {shared.opts.extra_networks_card_width}px;" if shared.opts.extra_networks_card_width else ''
|
||||
background_image = f"background-image: url(\"{html.escape(preview)}\");" if preview else ''
|
||||
metadata_button = ""
|
||||
metadata = item.get("metadata")
|
||||
if metadata:
|
||||
metadata_button = f"<div class='metadata-button' title='Show metadata' onclick='extraNetworksRequestMetadata(event, {json.dumps(self.name)}, {json.dumps(item['name'])})'></div>"
|
||||
args = {
|
||||
"style": f"'{height}{width}{background_image}'",
|
||||
"prompt": item.get("prompt", None),
|
||||
@@ -142,11 +139,14 @@ class ExtraNetworksPage:
|
||||
"card_clicked": onclick,
|
||||
"save_card_description": '"' + html.escape(f"""return saveCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
"save_card_preview": '"' + html.escape(f"""return saveCardPreview(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])})""") + '"',
|
||||
"read_card_description": '"' + html.escape(f"""return readCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])}, {json.dumps(item["description"])})""") + '"',
|
||||
"read_card_description": '"' + html.escape(f"""return readCardDescription(event, {json.dumps(tabname)}, {json.dumps(item["local_preview"])}, {json.dumps(item["description"])}, {json.dumps(self.name)}, {json.dumps(item["name"])})""") + '"',
|
||||
"search_term": item.get("search_term", ""),
|
||||
"metadata_button": metadata_button,
|
||||
"read_card_metadata": '"' + html.escape(f"""return readCardMetadata(event, {json.dumps(self.name)}, {json.dumps(item["name"])})""") + '"',
|
||||
}
|
||||
return self.card_page.format(**args)
|
||||
if item.get("metadata"):
|
||||
return self.card_long.format(**args)
|
||||
else:
|
||||
return self.card_short.format(**args)
|
||||
|
||||
def find_preview(self, path):
|
||||
"""
|
||||
|
||||
@@ -15,7 +15,7 @@ class ExtraNetworksPageCheckpoints(ui_extra_networks.ExtraNetworksPage):
|
||||
def list_items(self):
|
||||
checkpoint: sd_models.CheckpointInfo
|
||||
for name, checkpoint in sd_models.checkpoints_list.items():
|
||||
path, ext = os.path.splitext(checkpoint.filename)
|
||||
path, _ext = os.path.splitext(checkpoint.filename)
|
||||
yield {
|
||||
"name": checkpoint.name_for_extra,
|
||||
"filename": path,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
from typing import Optional
|
||||
import torch
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex
|
||||
except:
|
||||
pass
|
||||
import torch.nn as nn
|
||||
from transformers import XLMRobertaModel,XLMRobertaTokenizer, BertPreTrainedModel, BertModel, BertConfig # pylint: disable=unused-import
|
||||
from transformers.models.xlm_roberta.configuration_xlm_roberta import XLMRobertaConfig
|
||||
|
||||
+3
-3
@@ -51,13 +51,13 @@ yapf
|
||||
scikit-image
|
||||
accelerate==0.18.0
|
||||
opencv-python==4.7.0.72
|
||||
diffusers==0.15.0
|
||||
diffusers==0.16.1
|
||||
einops==0.4.1
|
||||
gradio==3.23.0
|
||||
gradio==3.28.1
|
||||
numexpr==2.8.4
|
||||
pandas==1.5.3
|
||||
protobuf==3.20.3
|
||||
pytorch_lightning==1.9.4
|
||||
transformers==4.26.1
|
||||
transformers==4.28.1
|
||||
timm==0.6.13
|
||||
tomesd==0.1.2
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
from modules import scripts_postprocessing, shared
|
||||
import gradio as gr
|
||||
|
||||
from modules import scripts_postprocessing, shared
|
||||
from modules.ui_components import FormRow, ToolButton
|
||||
from modules.ui import switch_values_symbol
|
||||
|
||||
@@ -15,7 +13,7 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
|
||||
order = 1000
|
||||
|
||||
def ui(self):
|
||||
selected_tab = gr.State(value=0)
|
||||
selected_tab = gr.State(value=0) # pylint: disable=abstract-class-instantiated
|
||||
|
||||
with gr.Column():
|
||||
with FormRow():
|
||||
@@ -80,7 +78,7 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
|
||||
|
||||
return image
|
||||
|
||||
def process(self, pp: scripts_postprocessing.PostprocessedImage, upscale_mode=1, upscale_by=2.0, upscale_to_width=None, upscale_to_height=None, upscale_crop=False, upscaler_1_name=None, upscaler_2_name=None, upscaler_2_visibility=0.0):
|
||||
def process(self, pp: scripts_postprocessing.PostprocessedImage, upscale_mode=1, upscale_by=2.0, upscale_to_width=None, upscale_to_height=None, upscale_crop=False, upscaler_1_name=None, upscaler_2_name=None, upscaler_2_visibility=0.0): # pylint: disable=arguments-differ
|
||||
if upscaler_1_name == "None":
|
||||
upscaler_1_name = None
|
||||
|
||||
@@ -97,13 +95,13 @@ class ScriptPostprocessingUpscale(scripts_postprocessing.ScriptPostprocessing):
|
||||
assert upscaler2 or (upscaler_2_name is None), f'could not find upscaler named {upscaler_2_name}'
|
||||
|
||||
upscaled_image = self.upscale(pp.image, pp.info, upscaler1, upscale_mode, upscale_by, upscale_to_width, upscale_to_height, upscale_crop)
|
||||
pp.info[f"Postprocess upscaler"] = upscaler1.name
|
||||
pp.info["Postprocess upscaler"] = upscaler1.name
|
||||
|
||||
if upscaler2 and upscaler_2_visibility > 0:
|
||||
second_upscale = self.upscale(pp.image, pp.info, upscaler2, upscale_mode, upscale_by, upscale_to_width, upscale_to_height, upscale_crop)
|
||||
upscaled_image = Image.blend(upscaled_image, second_upscale, upscaler_2_visibility)
|
||||
|
||||
pp.info[f"Postprocess upscaler 2"] = upscaler2.name
|
||||
pp.info["Postprocess upscaler 2"] = upscaler2.name
|
||||
|
||||
pp.image = upscaled_image
|
||||
|
||||
@@ -125,7 +123,7 @@ class ScriptPostprocessingUpscaleSimple(ScriptPostprocessingUpscale):
|
||||
"upscaler_name": upscaler_name,
|
||||
}
|
||||
|
||||
def process(self, pp: scripts_postprocessing.PostprocessedImage, upscale_by=2.0, upscaler_name=None):
|
||||
def process(self, pp: scripts_postprocessing.PostprocessedImage, upscale_by=2.0, upscaler_name=None): # pylint: disable=arguments-differ
|
||||
if upscaler_name is None or upscaler_name == "None":
|
||||
return
|
||||
|
||||
@@ -133,4 +131,4 @@ class ScriptPostprocessingUpscaleSimple(ScriptPostprocessingUpscale):
|
||||
assert upscaler1, f'could not find upscaler named {upscaler_name}'
|
||||
|
||||
pp.image = self.upscale(pp.image, pp.info, upscaler1, 0, upscale_by, 0, 0, False)
|
||||
pp.info[f"Postprocess upscaler"] = upscaler1.name
|
||||
pp.info["Postprocess upscaler"] = upscaler1.name
|
||||
|
||||
@@ -130,8 +130,6 @@ class Script(scripts.Script):
|
||||
lines = [x.strip() for x in prompt_txt.splitlines()]
|
||||
lines = [x for x in lines if len(x) > 0]
|
||||
|
||||
p.do_not_save_grid = True
|
||||
|
||||
job_count = 0
|
||||
jobs = []
|
||||
|
||||
|
||||
+58
-42
@@ -1,26 +1,18 @@
|
||||
import re
|
||||
import csv
|
||||
import random
|
||||
from collections import namedtuple
|
||||
from copy import copy
|
||||
from itertools import permutations, chain
|
||||
import random
|
||||
import csv
|
||||
from io import StringIO
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
import modules.scripts as scripts
|
||||
import gradio as gr
|
||||
|
||||
from modules import images, paths, sd_samplers, processing, sd_models, sd_vae
|
||||
from modules.processing import process_images, Processed, StableDiffusionProcessingTxt2Img
|
||||
from modules.shared import opts, cmd_opts, state
|
||||
import modules.scripts as scripts
|
||||
import modules.shared as shared
|
||||
import modules.sd_samplers
|
||||
import modules.sd_models
|
||||
import modules.sd_vae
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
|
||||
from modules import images, sd_samplers, processing, sd_models, sd_vae
|
||||
from modules.processing import process_images, Processed, StableDiffusionProcessingTxt2Img
|
||||
from modules.shared import opts, state
|
||||
from modules.ui_components import ToolButton
|
||||
|
||||
fill_values_symbol = "\U0001f4d2" # 📒
|
||||
@@ -83,15 +75,15 @@ def confirm_samplers(p, xs):
|
||||
|
||||
|
||||
def apply_checkpoint(p, x, xs):
|
||||
info = modules.sd_models.get_closet_checkpoint_match(x)
|
||||
info = sd_models.get_closet_checkpoint_match(x)
|
||||
if info is None:
|
||||
raise RuntimeError(f"Unknown checkpoint: {x}")
|
||||
modules.sd_models.reload_model_weights(shared.sd_model, info)
|
||||
sd_models.reload_model_weights(shared.sd_model, info)
|
||||
|
||||
|
||||
def confirm_checkpoints(p, xs):
|
||||
for x in xs:
|
||||
if modules.sd_models.get_closet_checkpoint_match(x) is None:
|
||||
if sd_models.get_closet_checkpoint_match(x) is None:
|
||||
raise RuntimeError(f"Unknown checkpoint: {x}")
|
||||
|
||||
|
||||
@@ -108,26 +100,34 @@ def apply_upscale_latent_space(p, x, xs):
|
||||
|
||||
def find_vae(name: str):
|
||||
if name.lower() in ['auto', 'automatic']:
|
||||
return modules.sd_vae.unspecified
|
||||
return sd_vae.unspecified
|
||||
if name.lower() == 'none':
|
||||
return None
|
||||
else:
|
||||
choices = [x for x in sorted(modules.sd_vae.vae_dict, key=lambda x: len(x)) if name.lower().strip() in x.lower()]
|
||||
choices = [x for x in sorted(sd_vae.vae_dict, key=lambda x: len(x)) if name.lower().strip() in x.lower()]
|
||||
if len(choices) == 0:
|
||||
print(f"No VAE found for {name}; using automatic")
|
||||
return modules.sd_vae.unspecified
|
||||
return sd_vae.unspecified
|
||||
else:
|
||||
return modules.sd_vae.vae_dict[choices[0]]
|
||||
return sd_vae.vae_dict[choices[0]]
|
||||
|
||||
|
||||
def apply_vae(p, x, xs):
|
||||
modules.sd_vae.reload_vae_weights(shared.sd_model, vae_file=find_vae(x))
|
||||
sd_vae.reload_vae_weights(shared.sd_model, vae_file=find_vae(x))
|
||||
|
||||
|
||||
def apply_styles(p: StableDiffusionProcessingTxt2Img, x: str, _):
|
||||
p.styles.extend(x.split(','))
|
||||
|
||||
|
||||
def apply_fallback(p, x, xs):
|
||||
sampler_name = sd_samplers.samplers_map.get(x.lower(), None)
|
||||
if sampler_name is None:
|
||||
raise RuntimeError(f"Unknown sampler: {x}")
|
||||
|
||||
opts.data["xyz_fallback_sampler"] = sampler_name
|
||||
|
||||
|
||||
def apply_uni_pc_order(p, x, xs):
|
||||
opts.data["uni_pc_order"] = min(x, p.steps - 1)
|
||||
|
||||
@@ -145,6 +145,15 @@ def apply_face_restore(p, opt, x):
|
||||
|
||||
p.restore_faces = is_active
|
||||
|
||||
def apply_token_merging_ratio_hr(p, x, xs):
|
||||
opts.data["token_merging_ratio_hr"] = x
|
||||
|
||||
def apply_token_merging_ratio(p, x, xs):
|
||||
opts.data["token_merging_ratio"] = x
|
||||
|
||||
def apply_token_merging_random(p, x, xs):
|
||||
is_active = x.lower() in ('true', 'yes', 'y', '1')
|
||||
opts.data["token_merging_random"] = is_active
|
||||
|
||||
def format_value_add_label(p, opt, x):
|
||||
if type(x) == float:
|
||||
@@ -220,11 +229,15 @@ axis_options = [
|
||||
AxisOption("Clip skip", int, apply_clip_skip),
|
||||
AxisOption("Denoising", float, apply_field("denoising_strength")),
|
||||
AxisOptionTxt2Img("Hires upscaler", str, apply_field("hr_upscaler"), choices=lambda: [*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]]),
|
||||
AxisOptionTxt2Img("Fallback latent upscaler sampler", str, apply_fallback, format_value=format_value, confirm=confirm_samplers, choices=lambda: [x.name for x in sd_samplers.samplers]),
|
||||
AxisOptionImg2Img("Cond. Image Mask Weight", float, apply_field("inpainting_mask_weight")),
|
||||
AxisOption("VAE", str, apply_vae, cost=0.7, choices=lambda: list(sd_vae.vae_dict)),
|
||||
AxisOption("Styles", str, apply_styles, choices=lambda: list(shared.prompt_styles.styles)),
|
||||
AxisOption("UniPC Order", int, apply_uni_pc_order, cost=0.5),
|
||||
AxisOption("Face restore", str, apply_face_restore, format_value=format_value),
|
||||
AxisOption("ToMe ratio",float,apply_token_merging_ratio),
|
||||
AxisOption("ToMe ratio for Hires fix",float,apply_token_merging_ratio_hr),
|
||||
AxisOption("ToMe random pertubations",str,apply_token_merging_random, choices = lambda: ["Yes","No"])
|
||||
]
|
||||
|
||||
|
||||
@@ -332,7 +345,6 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
|
||||
if draw_legend:
|
||||
z_grid = images.draw_grid_annotations(z_grid, sub_grid_size[0], sub_grid_size[1], title_texts, [[images.GridAnnotation()]])
|
||||
processed_result.images.insert(0, z_grid)
|
||||
#TODO: Deeper aspects of the program rely on grid info being misaligned between metadata arrays, which is not ideal.
|
||||
#processed_result.all_prompts.insert(0, processed_result.all_prompts[0])
|
||||
#processed_result.all_seeds.insert(0, processed_result.all_seeds[0])
|
||||
processed_result.infotexts.insert(0, processed_result.infotexts[0])
|
||||
@@ -342,18 +354,26 @@ def draw_xyz_grid(p, xs, ys, zs, x_labels, y_labels, z_labels, cell, draw_legend
|
||||
|
||||
class SharedSettingsStackHelper(object):
|
||||
def __enter__(self):
|
||||
#Save overridden settings so they can be restored later.
|
||||
self.CLIP_stop_at_last_layers = opts.CLIP_stop_at_last_layers
|
||||
self.vae = opts.sd_vae
|
||||
self.uni_pc_order = opts.uni_pc_order
|
||||
|
||||
self.token_merging_ratio_hr = opts.token_merging_ratio_hr
|
||||
self.token_merging_ratio = opts.token_merging_ratio
|
||||
self.token_merging_random = opts.token_merging_random
|
||||
|
||||
def __exit__(self, exc_type, exc_value, tb):
|
||||
#Restore overriden settings after plot generation.
|
||||
opts.data["sd_vae"] = self.vae
|
||||
opts.data["uni_pc_order"] = self.uni_pc_order
|
||||
modules.sd_models.reload_model_weights()
|
||||
modules.sd_vae.reload_vae_weights()
|
||||
sd_models.reload_model_weights()
|
||||
sd_vae.reload_vae_weights()
|
||||
|
||||
opts.data["CLIP_stop_at_last_layers"] = self.CLIP_stop_at_last_layers
|
||||
|
||||
opts.data["token_merging_ratio_hr"] = self.token_merging_ratio_hr
|
||||
opts.data["token_merging_ratio"] = self.token_merging_ratio
|
||||
opts.data["token_merging_random"] = self.token_merging_random
|
||||
|
||||
re_range = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\(([+-]\d+)\s*\))?\s*")
|
||||
re_range_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\(([+-]\d+(?:.\d*)?)\s*\))?\s*")
|
||||
@@ -390,15 +410,13 @@ class Script(scripts.Script):
|
||||
fill_z_button = ToolButton(value=fill_values_symbol, elem_id="xyz_grid_fill_z_tool_button", visible=False)
|
||||
|
||||
with gr.Row(variant="compact", elem_id="axis_options"):
|
||||
with gr.Column():
|
||||
draw_legend = gr.Checkbox(label='Draw legend', value=True, elem_id=self.elem_id("draw_legend"))
|
||||
no_fixed_seeds = gr.Checkbox(label='Keep -1 for seeds', value=False, elem_id=self.elem_id("no_fixed_seeds"))
|
||||
with gr.Column():
|
||||
include_lone_images = gr.Checkbox(label='Include Sub Images', value=False, elem_id=self.elem_id("include_lone_images"))
|
||||
include_sub_grids = gr.Checkbox(label='Include Sub Grids', value=False, elem_id=self.elem_id("include_sub_grids"))
|
||||
with gr.Column():
|
||||
margin_size = gr.Slider(label="Grid margins (px)", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
|
||||
|
||||
draw_legend = gr.Checkbox(label='Draw legend', value=True, elem_id=self.elem_id("draw_legend"))
|
||||
no_fixed_seeds = gr.Checkbox(label='Keep -1 for seeds', value=False, elem_id=self.elem_id("no_fixed_seeds"))
|
||||
include_lone_images = gr.Checkbox(label='Include Sub Images', value=False, elem_id=self.elem_id("include_lone_images"))
|
||||
include_sub_grids = gr.Checkbox(label='Include Sub Grids', value=False, elem_id=self.elem_id("include_sub_grids"))
|
||||
with gr.Row(variant="compact", elem_id="axis_options"):
|
||||
margin_size = gr.Slider(label="Grid margins (px)", minimum=0, maximum=500, value=0, step=2, elem_id=self.elem_id("margin_size"))
|
||||
|
||||
with gr.Row(variant="compact", elem_id="swap_axes"):
|
||||
swap_xy_axes_button = gr.Button(value="Swap X/Y axes", elem_id="xy_grid_swap_axes_button")
|
||||
swap_yz_axes_button = gr.Button(value="Swap Y/Z axes", elem_id="yz_grid_swap_axes_button")
|
||||
@@ -459,7 +477,7 @@ class Script(scripts.Script):
|
||||
|
||||
def run(self, p, x_type, x_values, x_values_dropdown, y_type, y_values, y_values_dropdown, z_type, z_values, z_values_dropdown, draw_legend, include_lone_images, include_sub_grids, no_fixed_seeds, margin_size):
|
||||
if not no_fixed_seeds:
|
||||
modules.processing.fix_seed(p)
|
||||
processing.fix_seed(p)
|
||||
|
||||
if not opts.return_grid:
|
||||
p.batch_size = 1
|
||||
@@ -489,7 +507,7 @@ class Script(scripts.Script):
|
||||
start = int(mc.group(1))
|
||||
end = int(mc.group(2))
|
||||
num = int(mc.group(3)) if mc.group(3) is not None else 1
|
||||
|
||||
|
||||
valslist_ext += [int(x) for x in np.linspace(start=start, stop=end, num=num).tolist()]
|
||||
else:
|
||||
valslist_ext.append(val)
|
||||
@@ -511,7 +529,7 @@ class Script(scripts.Script):
|
||||
start = float(mc.group(1))
|
||||
end = float(mc.group(2))
|
||||
num = int(mc.group(3)) if mc.group(3) is not None else 1
|
||||
|
||||
|
||||
valslist_ext += np.linspace(start=start, stop=end, num=num).tolist()
|
||||
else:
|
||||
valslist_ext.append(val)
|
||||
@@ -586,7 +604,6 @@ class Script(scripts.Script):
|
||||
cell_console_text = f"; {image_cell_count} images per cell" if image_cell_count > 1 else ""
|
||||
plural_s = 's' if len(zs) > 1 else ''
|
||||
print(f"X/Y/Z plot will create {len(xs) * len(ys) * len(zs) * image_cell_count} images on {len(zs)} {len(xs)}x{len(ys)} grid{plural_s}{cell_console_text}. (Total steps to process: {total_steps})")
|
||||
shared.total_tqdm.updateTotal(total_steps)
|
||||
|
||||
state.xyz_plot_x = AxisInfo(x_opt, xs)
|
||||
state.xyz_plot_y = AxisInfo(y_opt, ys)
|
||||
@@ -699,13 +716,12 @@ class Script(scripts.Script):
|
||||
# Auto-save main and sub-grids:
|
||||
grid_count = z_count + 1 if z_count > 1 else 1
|
||||
for g in range(grid_count):
|
||||
#TODO: See previous comment about intentional data misalignment.
|
||||
adj_g = g-1 if g > 0 else g
|
||||
images.save_image(processed.images[g], p.outpath_grids, "xyz_grid", info=processed.infotexts[g], extension=opts.grid_format, prompt=processed.all_prompts[adj_g], seed=processed.all_seeds[adj_g], grid=True, p=processed)
|
||||
|
||||
if not include_sub_grids:
|
||||
# Done with sub-grids, drop all related information:
|
||||
for sg in range(z_count):
|
||||
for _sg in range(z_count):
|
||||
del processed.images[1]
|
||||
del processed.all_prompts[1]
|
||||
del processed.all_seeds[1]
|
||||
|
||||
@@ -1,165 +1,37 @@
|
||||
|
||||
/* general gradio fixes */
|
||||
|
||||
:root, .dark{
|
||||
--checkbox-label-gap: 0.25em 0.1em;
|
||||
--section-header-text-size: 12pt;
|
||||
--block-background-fill: transparent;
|
||||
}
|
||||
|
||||
.block.padded:not(.gradio-accordion) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
div.gradio-container{
|
||||
max-width: unset !important;
|
||||
}
|
||||
|
||||
.hidden{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.compact{
|
||||
background: transparent !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
div.form{
|
||||
border-width: 0;
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
overflow: visible;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.block.gradio-dropdown,
|
||||
.block.gradio-slider,
|
||||
.block.gradio-checkbox,
|
||||
.block.gradio-textbox,
|
||||
.block.gradio-radio,
|
||||
.block.gradio-checkboxgroup,
|
||||
.block.gradio-number,
|
||||
.block.gradio-colorpicker
|
||||
{
|
||||
border-width: 0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.gap.compact{
|
||||
padding: 0;
|
||||
gap: 0.2em 0;
|
||||
}
|
||||
|
||||
div.compact{
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.gradio-dropdown label span:not(.has-info),
|
||||
.gradio-textbox label span:not(.has-info),
|
||||
.gradio-number label span:not(.has-info)
|
||||
{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.gradio-dropdown ul.options{
|
||||
z-index: 3000;
|
||||
min-width: fit-content;
|
||||
max-width: inherit;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.gradio-dropdown ul.options li.item {
|
||||
padding: 0.05em 0;
|
||||
}
|
||||
|
||||
.gradio-dropdown ul.options li.item:not(:has(.hide)) {
|
||||
background-color: var(--neutral-100);
|
||||
}
|
||||
|
||||
.dark .gradio-dropdown ul.options li.item:not(:has(.hide)) {
|
||||
background-color: var(--neutral-900);
|
||||
}
|
||||
|
||||
.gradio-dropdown div.wrap.wrap.wrap.wrap{
|
||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.gradio-dropdown:not(.multiselect) .wrap-inner.wrap-inner.wrap-inner{
|
||||
flex-wrap: unset;
|
||||
}
|
||||
|
||||
.gradio-dropdown .single-select{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gradio-dropdown .token-remove.remove-all.remove-all{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gradio-dropdown.multiselect .token-remove.remove-all.remove-all{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.gradio-slider input[type="number"]{
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.block.gradio-checkbox {
|
||||
margin: 0.75em 1.5em 0 0;
|
||||
}
|
||||
|
||||
.gradio-html div.wrap{
|
||||
height: 100%;
|
||||
}
|
||||
div.gradio-html.min{
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.block.gradio-gallery{
|
||||
background: var(--input-background-fill);
|
||||
}
|
||||
|
||||
.gradio-container .prose a, .gradio-container .prose a:visited{
|
||||
color: unset;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
:root, .dark{ --checkbox-label-gap: 0.25em 0.1em; --section-header-text-size: 12pt; --block-background-fill: transparent;}
|
||||
div.gradio-container{ max-width: unset !important; }
|
||||
div.form{ border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em; }
|
||||
div.compact{ gap: 1em; }
|
||||
div.gradio-html.min{ min-height: 0; }
|
||||
.block.gradio-checkbox { margin: 0.75em 1.5em 0 0; }
|
||||
.block.gradio-dropdown, .block.gradio-slider, .block.gradio-checkbox, .block.gradio-textbox, .block.gradio-radio, .block.gradio-checkboxgroup, .block.gradio-number, .block.gradio-colorpicker { border-width: 0 !important; box-shadow: none !important;}
|
||||
.block.gradio-gallery{ background: var(--input-background-fill); }
|
||||
.block.padded:not(.gradio-accordion) { padding: 0 !important; }
|
||||
.compact{ background: transparent !important; padding: 0 !important; }
|
||||
.dark .gradio-dropdown ul.options li.item:not(:has(.hide)) { background-color: var(--neutral-900); }
|
||||
.gap.compact{ padding: 0; gap: 0.2em 0; }
|
||||
.gradio-container .prose a, .gradio-container .prose a:visited{ color: unset; text-decoration: none; }
|
||||
.gradio-dropdown .single-select{ white-space: nowrap; overflow: hidden; }
|
||||
.gradio-dropdown .token-remove.remove-all.remove-all{ display: none; }
|
||||
.gradio-dropdown div.wrap.wrap.wrap.wrap{ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); }
|
||||
.gradio-dropdown label span:not(.has-info), .gradio-textbox label span:not(.has-info), .gradio-number label span:not(.has-info) { margin-bottom: 0; }
|
||||
.gradio-dropdown ul.options li.item { padding: 0.05em 0; }
|
||||
.gradio-dropdown ul.options li.item:not(:has(.hide)) { background-color: var(--neutral-100); }
|
||||
.gradio-dropdown ul.options{ z-index: 3000; min-width: fit-content; max-width: inherit; white-space: nowrap; }
|
||||
.gradio-dropdown:not(.multiselect) .wrap-inner.wrap-inner.wrap-inner{ flex-wrap: unset; }
|
||||
.gradio-dropdown.multiselect .token-remove.remove-all.remove-all{ display: flex; }
|
||||
.gradio-dropdown.multiselect div.wrap-inner { overflow-x: hidden; overflow-y: auto; max-height: 50vh; overflow-wrap: anywhere; }
|
||||
.gradio-html div.wrap{ height: 100%; }
|
||||
.gradio-slider input[type="number"]{ width: 6em; }
|
||||
.hidden{ display: none; }
|
||||
|
||||
/* general styled components */
|
||||
|
||||
.gradio-button.tool{
|
||||
max-width: 2.2em;
|
||||
min-width: 2.2em !important;
|
||||
height: 2.4em;
|
||||
align-self: end;
|
||||
line-height: 1em;
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
|
||||
.gradio-button.secondary-down{
|
||||
background: var(--button-secondary-background-fill);
|
||||
color: var(--button-secondary-text-color);
|
||||
}
|
||||
.gradio-button.secondary-down, .gradio-button.secondary-down:hover{
|
||||
box-shadow: 1px 1px 1px rgba(0,0,0,0.25) inset, 0px 0px 3px rgba(0,0,0,0.15) inset;
|
||||
}
|
||||
.gradio-button.secondary-down:hover{
|
||||
background: var(--button-secondary-background-fill-hover);
|
||||
color: var(--button-secondary-text-color-hover);
|
||||
}
|
||||
|
||||
.checkboxes-row{
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: 0em;
|
||||
}
|
||||
.checkboxes-row > div{
|
||||
flex: 0;
|
||||
white-space: nowrap;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.gradio-button.tool{ max-width: 2.2em; min-width: 2.2em !important; height: 2.4em; align-self: end; line-height: 1em; border-radius: 0.5em; }
|
||||
.gradio-button.secondary-down{ background: var(--button-secondary-background-fill); color: var(--button-secondary-text-color); }
|
||||
.gradio-button.secondary-down, .gradio-button.secondary-down:hover{ box-shadow: 1px 1px 1px rgba(0,0,0,0.25) inset, 0px 0px 3px rgba(0,0,0,0.15) inset; }
|
||||
.gradio-button.secondary-down:hover{ background: var(--button-secondary-background-fill-hover); color: var(--button-secondary-text-color-hover); }
|
||||
.checkboxes-row{ margin-bottom: 0.5em; margin-left: 0em; }
|
||||
.checkboxes-row > div{ flex: 0; white-space: nowrap; min-width: auto; }
|
||||
button.custom-button{
|
||||
border-radius: var(--button-large-radius);
|
||||
padding: var(--button-large-padding);
|
||||
@@ -176,9 +48,7 @@ button.custom-button{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
/* txt2img/img2img specific */
|
||||
|
||||
.block.token-counter{
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
@@ -201,13 +71,8 @@ button.custom-button{
|
||||
border: 2px solid rgba(255,0,0,0.4) !important;
|
||||
}
|
||||
|
||||
.block.token-counter div{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.block.token-counter span{
|
||||
padding: 0.1em 0.75em;
|
||||
}
|
||||
.block.token-counter div{ display: inline; }
|
||||
.block.token-counter span{ padding: 0.1em 0.75em; }
|
||||
|
||||
[id$=_subseed_show]{
|
||||
min-width: auto !important;
|
||||
@@ -642,47 +507,15 @@ footer {
|
||||
}
|
||||
|
||||
/* extra networks UI */
|
||||
.extra-networks > div > [id *= '_extra_']{ margin: 0.3em; }
|
||||
.extra-network-subdirs{ padding: 0.2em 0.35em; }
|
||||
.extra-network-subdirs button{ margin: 0 0.15em; }
|
||||
.extra-networks .tab-nav .search{ display: inline-block; max-width: 16em; margin: 0.3em; align-self: center; width: 16em; }
|
||||
#txt2img_extra_view, #img2img_extra_view { width: auto; }
|
||||
.extra-network-cards .nocards, .extra-network-thumbs .nocards{ margin: 1.25em 0.5em 0.5em 0.5em; }
|
||||
.extra-network-cards .nocards h1, .extra-network-thumbs .nocards h1{ font-size: 1.5em; margin-bottom: 1em; }
|
||||
.extra-network-cards .nocards li, .extra-network-thumbs .nocards li{ margin-left: 0.5em; }
|
||||
|
||||
.extra-networks > div > [id *= '_extra_']{
|
||||
margin: 0.3em;
|
||||
}
|
||||
|
||||
.extra-network-subdirs{
|
||||
padding: 0.2em 0.35em;
|
||||
}
|
||||
|
||||
.extra-network-subdirs button{
|
||||
margin: 0 0.15em;
|
||||
}
|
||||
.extra-networks .tab-nav .search{
|
||||
display: inline-block;
|
||||
max-width: 16em;
|
||||
margin: 0.3em;
|
||||
align-self: center;
|
||||
width: 16em;
|
||||
}
|
||||
|
||||
#txt2img_extra_view, #img2img_extra_view {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.extra-network-cards .nocards, .extra-network-thumbs .nocards{
|
||||
margin: 1.25em 0.5em 0.5em 0.5em;
|
||||
}
|
||||
|
||||
.extra-network-cards .nocards h1, .extra-network-thumbs .nocards h1{
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.extra-network-cards .nocards li, .extra-network-thumbs .nocards li{
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
.extra-network-cards .card .metadata-button:before, .extra-network-thumbs .card .metadata-button:before{
|
||||
content: "🛈";
|
||||
}
|
||||
.extra-network-cards .card .metadata-button, .extra-network-thumbs .card .metadata-button{
|
||||
display: none;
|
||||
position: absolute;
|
||||
@@ -693,23 +526,14 @@ footer {
|
||||
font-size: 22pt;
|
||||
width: 1.5em;
|
||||
}
|
||||
.extra-network-cards .card:hover .metadata-button, .extra-network-thumbs .card:hover .metadata-button{
|
||||
display: inline-block;
|
||||
}
|
||||
.extra-network-cards .card .metadata-button:hover, .extra-network-thumbs .card .metadata-button:hover{
|
||||
color: red;
|
||||
}
|
||||
|
||||
|
||||
.extra-network-thumbs {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
.extra-network-cards .card:hover .metadata-button, .extra-network-thumbs .card:hover .metadata-button{ display: inline-block; }
|
||||
.extra-network-thumbs { display: flex; flex-flow: row wrap; gap: 10px; }
|
||||
.extra-network-cards .card .additional a:hover, .extra-network-thumbs .card .additional a:hover { color: darkorange }
|
||||
|
||||
.extra-network-thumbs .card {
|
||||
height: 6em;
|
||||
width: 6em;
|
||||
display: inline-block;
|
||||
height: 9em;
|
||||
width: 9em;
|
||||
cursor: pointer;
|
||||
background-image: url('./file=html/card-no-preview.png');
|
||||
background-size: cover;
|
||||
@@ -717,25 +541,8 @@ footer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.extra-network-thumbs .card:hover .additional a {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.extra-network-thumbs .actions .additional a {
|
||||
background-image: url('./file=html/image-update.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: none;
|
||||
font-size: 0;
|
||||
text-align: -9999;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .additional, .extra-network-thumbs .card .additional { white-space: nowrap; overflow: hidden; }
|
||||
.extra-network-thumbs .card:hover .additional a { display: inline-block; }
|
||||
.extra-network-thumbs .actions .name {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
@@ -749,11 +556,7 @@ footer {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.extra-network-thumbs .card:hover .actions .name {
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.extra-network-thumbs .card:hover .actions .name { white-space: normal; word-break: break-all; }
|
||||
.extra-network-cards .card{
|
||||
display: inline-block;
|
||||
margin: 0.5em;
|
||||
@@ -762,22 +565,15 @@ footer {
|
||||
box-shadow: 0 0 5px rgba(128, 128, 128, 0.5);
|
||||
border-radius: 0.2em;
|
||||
position: relative;
|
||||
|
||||
background-size: auto 100%;
|
||||
background-position: center;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
|
||||
background-image: url('./file=html/card-no-preview.png')
|
||||
}
|
||||
|
||||
.extra-network-cards .card:hover{
|
||||
box-shadow: 0 0 2px 0.3em rgba(0, 128, 255, 0.35);
|
||||
}
|
||||
|
||||
.extra-network-cards .card .actions .additional{
|
||||
display: none;
|
||||
}
|
||||
.extra-network-cards .card:hover { box-shadow: 0 0 2px 0.3em rgba(0, 128, 255, 0.35); }
|
||||
.extra-network-cards .card .actions .additional, .extra-network-thumbs .card .actions .additional{ display: none; }
|
||||
|
||||
.extra-network-cards .card .actions{
|
||||
position: absolute;
|
||||
@@ -790,58 +586,13 @@ footer {
|
||||
text-shadow: 0 0 0.2em black;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .actions *{
|
||||
color: white;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .actions:hover{
|
||||
box-shadow: 0 0 0.75em 0.75em rgba(0,0,0,0.5) !important;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .actions .name{
|
||||
font-size: 1.7em;
|
||||
font-weight: bold;
|
||||
line-break: anywhere;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .actions .description {
|
||||
display: block;
|
||||
max-height: 3em;
|
||||
white-space: pre-wrap;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .actions .description:hover {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.extra-network-cards .card .actions:hover .additional{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.extra-network-cards .card ul{
|
||||
margin: 0.25em 0 0.75em 0.25em;
|
||||
cursor: unset;
|
||||
}
|
||||
|
||||
.extra-network-cards .card ul a{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.extra-network-cards .card ul a:hover{
|
||||
color: red;
|
||||
}
|
||||
|
||||
.theme-preview {
|
||||
display: none;
|
||||
position: fixed;
|
||||
border: 4px solid var(--neutral-600);
|
||||
box-shadow: 2px 2px 2px 2px var(--neutral-700);
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
max-width: 75vw;
|
||||
z-index: 999;
|
||||
}
|
||||
.extra-network-cards .card .actions *{ color: white; }
|
||||
.extra-network-cards .card .actions:hover { box-shadow: 0 0 0.75em 0.75em rgba(0,0,0,0.5) !important; }
|
||||
.extra-network-cards .card .actions .name { font-size: 1.7em; font-weight: bold; line-break: anywhere; }
|
||||
.extra-network-cards .card .actions .description { display: block; max-height: 3em; white-space: pre-wrap; line-height: 1.1; }
|
||||
.extra-network-cards .card .actions .description:hover { max-height: none; }
|
||||
.extra-network-cards .card .actions:hover .additional, .extra-network-thumbs .card:hover .additional{ display: block; }
|
||||
.extra-network-cards .card ul{ margin: 0.25em 0 0.75em 0.25em; cursor: unset; }
|
||||
.extra-network-cards .card ul a{ cursor: pointer; }
|
||||
.extra-network-cards .card ul a:hover{ color: red; }
|
||||
.theme-preview { display: none; position: fixed; border: 4px solid var(--neutral-600); box-shadow: 2px 2px 2px 2px var(--neutral-700); top: 0; bottom: 0; left: 0; right: 0; margin: auto; max-width: 75vw; z-index: 999; }
|
||||
|
||||
@@ -12,6 +12,10 @@ from modules import timer, errors
|
||||
startup_timer = timer.Timer()
|
||||
|
||||
import torch # pylint: disable=C0411
|
||||
try:
|
||||
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
|
||||
except:
|
||||
pass
|
||||
import torchvision # pylint: disable=W0611,C0411
|
||||
import pytorch_lightning # pytorch_lightning should be imported after torch, but it re-enables warnings on import so import once to disable them # pylint: disable=W0611,C0411
|
||||
logging.getLogger("xformers").addFilter(lambda record: 'A matching Triton is not available' not in record.getMessage())
|
||||
@@ -105,7 +109,7 @@ def initialize():
|
||||
startup_timer.record("vae")
|
||||
|
||||
shared.opts.onchange("sd_vae", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False)
|
||||
shared.opts.onchange("sd_vae_as_default", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False)
|
||||
# shared.opts.onchange("sd_vae_as_default", wrap_queued_call(lambda: modules.sd_vae.reload_vae_weights()), call=False)
|
||||
shared.opts.onchange("temp_dir", ui_tempdir.on_tmpdir_changed)
|
||||
shared.opts.onchange("gradio_theme", shared.reload_gradio_theme)
|
||||
startup_timer.record("opts onchange")
|
||||
@@ -198,19 +202,20 @@ def start_ui():
|
||||
shared.demo.queue(16)
|
||||
|
||||
gradio_auth_creds = []
|
||||
if cmd_opts.gradio_auth:
|
||||
gradio_auth_creds += [x.strip() for x in cmd_opts.gradio_auth.strip('"').replace('\n', '').split(',') if x.strip()]
|
||||
if cmd_opts.gradio_auth_path:
|
||||
with open(cmd_opts.gradio_auth_path, 'r', encoding="utf8") as file:
|
||||
if cmd_opts.auth:
|
||||
gradio_auth_creds += [x.strip() for x in cmd_opts.auth.strip('"').replace('\n', '').split(',') if x.strip()]
|
||||
if cmd_opts.authfile:
|
||||
with open(cmd_opts.authfile, 'r', encoding="utf8") as file:
|
||||
for line in file.readlines():
|
||||
gradio_auth_creds += [x.strip() for x in line.split(',') if x.strip()]
|
||||
|
||||
app, _local_url, _share_url = shared.demo.launch(
|
||||
share=cmd_opts.share,
|
||||
server_name=server_name,
|
||||
server_port=cmd_opts.port,
|
||||
server_port=cmd_opts.port if cmd_opts.port != 7860 else None,
|
||||
ssl_keyfile=cmd_opts.tls_keyfile,
|
||||
ssl_certfile=cmd_opts.tls_certfile,
|
||||
ssl_verify=False if cmd_opts.tls_selfsign else True,
|
||||
debug=False,
|
||||
auth=[tuple(cred.split(':')) for cred in gradio_auth_creds] if gradio_auth_creds else None,
|
||||
inbrowser=cmd_opts.autolaunch,
|
||||
|
||||
+1
-1
Submodule wiki updated: 12603bcdec...4cbdffaa95
Reference in New Issue
Block a user