From f6679fcc777bf843242d876580b27d13318f50df Mon Sep 17 00:00:00 2001
From: Vladimir Mandic
Date: Fri, 17 Mar 2023 10:08:07 -0400
Subject: [PATCH] add global exception handler
---
README.md | 19 +++-
automatic.sh | 8 +-
launch.py | 99 +------------------
modules/call_queue.py | 4 +-
modules/codeformer_model.py | 3 +-
modules/extensions.py | 3 +-
modules/gfpgan_model.py | 3 +-
modules/hypernetworks/hypernetwork.py | 5 +-
modules/images.py | 5 +-
modules/img2img.py | 1 -
modules/interrogate.py | 3 +-
modules/localization.py | 4 +-
modules/prompt_parser.py | 3 +-
modules/realesrgan_model.py | 8 +-
modules/safe.py | 9 +-
modules/script_callbacks.py | 4 +-
modules/script_loading.py | 4 +-
modules/scripts.py | 22 ++---
modules/sd_hijack.py | 18 ++--
modules/sd_hijack_optimizations.py | 4 +-
modules/shared.py | 17 +++-
.../textual_inversion/textual_inversion.py | 5 +-
modules/ui.py | 5 +-
modules/ui_extensions.py | 5 +-
scripts/prompts_from_file.py | 4 +-
webui.py | 33 -------
26 files changed, 90 insertions(+), 208 deletions(-)
diff --git a/README.md b/README.md
index bc524b43a..cd45fecdf 100644
--- a/README.md
+++ b/README.md
@@ -117,22 +117,35 @@ Fork does differ in few things:
- Drops compatibility with `python` **3.7** and requires **3.9**
Recommended is **Python 3.10**
Note that **Python 3.11** or **3.12** are NOT supported
+- New global exception handler
- Drops localizations
- Updated **Python** libraries to latest known compatible versions
e.g. `accelerate`, `transformers`, `numpy`, etc.
- Includes opinionated **System** and **Options** configuration
e.g. `samplers`, `upscalers`, etc.
-- Includes reskinned **UI**
- Black and orange dark theme with fixed width options panels and larger previews
+- Does not rely on `Accelerate` as it only affects distributed systems
+- Optimized startup order
+ Gradio web server will be initialized much earlier which model load is done in the background
- Includes **SD2** configuration files
- Uses simplified folder structure
e.g. `/train`, `/outputs/*`
- Modified training templates
- Built-in `LoRA`, `LyCORIS`, `Custom Diffusion`, `Dreambooth` training
+User Interface:
+
+- Includes reskinned **UI**
+ Black and orange dark theme with fixed width options panels and larger previews
+
+Optimizations:
+
+- Runs with `SDP` memory attention enabled by default if supported by system
+- Fallback to `XFormers` if SDP is not supported
+- If either `SDP` or `XFormers` are not supported, falls back to usual cmd line arguments
+
Only Python library which is not auto-updated is `PyTorch` itself as that is very system specific
-Fork is compatible with regular **PyTorch 1.13** as well as pre-releases of **PyTorch** **2.0** and **2.1**
+Fork is compatible with regular **PyTorch 1.13**, **PyTorch 2.0** as well as pre-releases of **PyTorch** **2.1**
See [Wiki](https://github.com/vladmandic/automatic/wiki/Torch-Optimizations) for **Torch** optimization notes
diff --git a/automatic.sh b/automatic.sh
index c5ad0bc03..b2906206d 100755
--- a/automatic.sh
+++ b/automatic.sh
@@ -17,10 +17,11 @@ if [ "$PYTHON" == "" ]; then
fi
# Note: Some defaults are changed in shared.py
-CMD="launch.py --xformers --skip-install --skip-torch-cuda-test --cors-allow-origins=http://127.0.0.1:7860"
+CMD="launch.py --skip-install --cors-allow-origins=http://127.0.0.1:7860"
MODE=optimized
+# Sanity checks
if [[ $(id -u) -eq 0 ]]; then
echo "Running as root, aborting"
exit 1
@@ -32,6 +33,7 @@ if [ $? -ne 0 ]; then
exit 1
fi
+# Parse arguments
for i in "$@"; do
case $i in
update)
@@ -57,7 +59,6 @@ for i in "$@"; do
done
echo "SD server: $MODE"
-
VER=$(git log -1 --pretty=format:"%h %ad")
URL=$(git remote get-url origin)
LSB=$(lsb_release -ds 2>/dev/null)
@@ -70,7 +71,6 @@ echo "Last Merge: $MERGE"
echo "System"
echo "- Platform: $LSB $UNAME"
echo "- nVIDIA: $SMI"
-"$PYTHON" -c 'import torch; import platform; print("- Python:", platform.python_version(), "Torch:", torch.__version__, "CUDA:", torch.version.cuda, "cuDNN:", torch.backends.cudnn.version(), "GPU:", torch.cuda.get_device_name(torch.cuda.current_device()), "Arch:", torch.cuda.get_device_capability());'
git-version () {
pushd $1 >/dev/null
@@ -108,6 +108,7 @@ fi
if [ "$MODE" == install ]; then
"$PYTHON" -m pip --version
+ "$PYTHON" -c 'import torch; import platform; print("- Python:", platform.python_version(), "Torch:", torch.__version__, "CUDA:", torch.version.cuda, "cuDNN:", torch.backends.cudnn.version(), "GPU:", torch.cuda.get_device_name(torch.cuda.current_device()), "Arch:", torch.cuda.get_device_capability());'
echo "Installing general requirements"
"$PYTHON" -m pip install --disable-pip-version-check --quiet --no-warn-conflicts --requirement requirements.txt
@@ -159,4 +160,3 @@ exec "$PYTHON" $CMD
# export LD_PRELOAD=libtcmalloc.so
# TORCH_CUDA_ARCH_LIST="8.6"
# --opt-channelslast
-# --opt-sdp-attention
diff --git a/launch.py b/launch.py
index a2f74bac4..e2bef4ffe 100644
--- a/launch.py
+++ b/launch.py
@@ -16,7 +16,6 @@ args, _ = parser.parse_known_args(sys.argv)
script_path = os.path.dirname(__file__)
data_path = os.getcwd()
-
dir_repos = "repositories"
dir_extensions = "extensions"
python = sys.executable
@@ -40,22 +39,7 @@ def check_python_version():
if not (major == 3 and minor in supported_minors):
import modules.errors
-
- modules.errors.print_error_explanation(f"""
-INCOMPATIBLE PYTHON VERSION
-
-This program is tested with 3.10.6 Python, but you have {major}.{minor}.{micro}.
-If you encounter an error with "RuntimeError: Couldn't install torch." message,
-or any other error regarding unsuccessful package (library) installation,
-please downgrade (or upgrade) to the latest version of 3.10 Python
-and delete current Python and "venv" folder in WebUI's directory.
-
-You can download 3.10 Python from here: https://www.python.org/downloads/release/python-3109/
-
-{"Alternatively, use a binary release of WebUI: https://github.com/AUTOMATIC1111/stable-diffusion-webui/releases" if is_windows else ""}
-
-Use --skip-python-version-check to suppress this warning.
-""")
+ modules.errors.print_error_explanation(f"Incompatible Python version: {major}.{minor}.{micro} required 3.9-3.11")
def commit_hash():
@@ -182,23 +166,6 @@ def git_pull_recursive(dir):
print(f"Couldn't perform 'git pull' on repository in '{subdir}':\n{e.output.decode('utf-8').strip()}\n")
-def version_check(commit):
- try:
- import requests
- commits = requests.get('https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/branches/master').json()
- if commit != "" and commits['commit']['sha'] != commit:
- print("--------------------------------------------------------")
- print("| You are not up to date with the most recent release. |")
- print("| Consider running `git pull` to update. |")
- print("--------------------------------------------------------")
- elif commits['commit']['sha'] == commit:
- print("You are up to date with the most recent release.")
- else:
- print("Not a git clone, can't perform version check.")
- except Exception as e:
- print("version check failed", e)
-
-
def run_extension_installer(extension_dir):
path_installer = os.path.join(extension_dir, "install.py")
if not os.path.isfile(path_installer):
@@ -241,11 +208,9 @@ def run_extensions_installers(settings_file):
def prepare_environment():
global skip_install
- torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117")
requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt")
commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
- xformers_package = os.environ.get('XFORMERS_PACKAGE', 'xformers==0.0.16rc425')
gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379")
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1")
openclip_package = os.environ.get('OPENCLIP_PACKAGE', "git+https://github.com/mlfoundations/open_clip.git@bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b")
@@ -267,14 +232,8 @@ def prepare_environment():
sys.argv, _ = extract_arg(sys.argv, '-f')
sys.argv, update_all_extensions = extract_arg(sys.argv, '--update-all-extensions')
- sys.argv, skip_torch_cuda_test = extract_arg(sys.argv, '--skip-torch-cuda-test')
sys.argv, skip_python_version_check = extract_arg(sys.argv, '--skip-python-version-check')
- sys.argv, reinstall_xformers = extract_arg(sys.argv, '--reinstall-xformers')
- sys.argv, reinstall_torch = extract_arg(sys.argv, '--reinstall-torch')
- sys.argv, update_check = extract_arg(sys.argv, '--update-check')
- sys.argv, run_tests, test_dir = extract_opt(sys.argv, '--tests')
sys.argv, skip_install = extract_arg(sys.argv, '--skip-install')
- xformers = '--xformers' in sys.argv
ngrok = '--ngrok' in sys.argv
if not skip_python_version_check:
@@ -282,15 +241,6 @@ def prepare_environment():
commit = commit_hash()
- # print(f"Python {sys.version}")
- # print(f"Commit hash: {commit}")
-
- if reinstall_torch or not is_installed("torch") or not is_installed("torchvision"):
- run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch", live=True)
-
- if not skip_torch_cuda_test:
- run_python("import torch; assert torch.cuda.is_available(), 'Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'")
-
if not is_installed("gfpgan"):
run_pip(f"install {gfpgan_package}", "gfpgan")
@@ -300,18 +250,6 @@ def prepare_environment():
if not is_installed("open_clip"):
run_pip(f"install {openclip_package}", "open_clip")
- if (not is_installed("xformers") or reinstall_xformers) and xformers:
- if platform.system() == "Windows":
- if platform.python_version().startswith("3.10"):
- run_pip(f"install -U -I --no-deps {xformers_package}", "xformers")
- else:
- print("Installation of xformers is not supported in this version of Python.")
- print("You can also check this and build manually: https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers#building-xformers-on-windows-by-duckness")
- if not is_installed("xformers"):
- exit(0)
- elif platform.system() == "Linux":
- run_pip(f"install {xformers_package}", "xformers")
-
if not is_installed("pyngrok") and ngrok:
run_pip("install pyngrok", "ngrok")
@@ -335,51 +273,22 @@ def prepare_environment():
run_extensions_installers(settings_file=args.ui_settings_file)
- if update_check:
- version_check(commit)
-
if update_all_extensions:
git_pull_recursive(os.path.join(data_path, dir_extensions))
- if run_tests:
- exitcode = tests(test_dir)
- exit(exitcode)
-
-
-def tests(test_dir):
- if "--api" not in sys.argv:
- sys.argv.append("--api")
- if "--ckpt" not in sys.argv:
- sys.argv.append("--ckpt")
- sys.argv.append(os.path.join(script_path, "test/test_files/empty.pt"))
- if "--skip-torch-cuda-test" not in sys.argv:
- sys.argv.append("--skip-torch-cuda-test")
- if "--disable-nan-check" not in sys.argv:
- sys.argv.append("--disable-nan-check")
-
- print(f"Launching Web UI in another process for testing with arguments: {' '.join(sys.argv[1:])}")
-
- os.environ['COMMANDLINE_ARGS'] = ""
- with open(os.path.join(script_path, 'test/stdout.txt'), "w", encoding="utf8") as stdout, open(os.path.join(script_path, 'test/stderr.txt'), "w", encoding="utf8") as stderr:
- proc = subprocess.Popen([sys.executable, *sys.argv], stdout=stdout, stderr=stderr)
-
- # import test.server_poll
- # exitcode = test.server_poll.run_tests(proc, test_dir)
-
- print(f"Stopping Web UI process with id {proc.pid}")
- proc.kill()
- return 0
-
def start():
print(f"Launching server with arguments: {' '.join(sys.argv[1:])}")
+ rich_installed = False
try:
from rich.traceback import install
from rich.console import Console
console = Console()
install(show_locals=True, max_frames=2, extra_lines=1, word_wrap=False, width=min([console.width, 200]))
+ rich_installed = True
except:
+ import traceback
pass # if rich is not installed do nothing
import webui
diff --git a/modules/call_queue.py b/modules/call_queue.py
index f0c441a09..17f247567 100644
--- a/modules/call_queue.py
+++ b/modules/call_queue.py
@@ -1,7 +1,6 @@
import html
import sys
import threading
-import traceback
import time
import cProfile, pstats, io
@@ -75,8 +74,7 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
if len(argStr) > max_debug_str_len:
print(f"(Argument list truncated at {max_debug_str_len}/{len(argStr)} characters)", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
-
+ shared.exception()
shared.state.job = ""
shared.state.job_count = 0
diff --git a/modules/codeformer_model.py b/modules/codeformer_model.py
index 8d84bbc90..e9c668b61 100644
--- a/modules/codeformer_model.py
+++ b/modules/codeformer_model.py
@@ -1,6 +1,5 @@
import os
import sys
-import traceback
import cv2
import torch
@@ -138,6 +137,6 @@ def setup_model(dirname):
except Exception:
print("Error setting up CodeFormer:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
# sys.path = stored_sys_path
diff --git a/modules/extensions.py b/modules/extensions.py
index ed4b58fe3..f4f51cd45 100644
--- a/modules/extensions.py
+++ b/modules/extensions.py
@@ -1,6 +1,5 @@
import os
import sys
-import traceback
import time
import git
@@ -34,7 +33,7 @@ class Extension:
repo = git.Repo(path)
except Exception:
print(f"Error reading github repository info from {path}:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
if repo is None or repo.bare:
self.remote = None
diff --git a/modules/gfpgan_model.py b/modules/gfpgan_model.py
index fbe6215a6..80ad6f1c6 100644
--- a/modules/gfpgan_model.py
+++ b/modules/gfpgan_model.py
@@ -1,6 +1,5 @@
import os
import sys
-import traceback
import facexlib
import gfpgan
@@ -113,4 +112,4 @@ def setup_model(dirname):
shared.face_restorers.append(FaceRestorerGFPGAN())
except Exception:
print("Error setting up GFPGAN:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py
index f6ef42d5a..b859271d0 100644
--- a/modules/hypernetworks/hypernetwork.py
+++ b/modules/hypernetworks/hypernetwork.py
@@ -4,7 +4,6 @@ import glob
import html
import os
import sys
-import traceback
import inspect
import modules.textual_inversion.dataset
@@ -332,7 +331,7 @@ def load_hypernetwork(name):
hypernetwork.load(path)
except Exception:
print(f"Error loading hypernetwork {path}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
return None
return hypernetwork
@@ -771,7 +770,7 @@ Last saved image: {html.escape(last_saved_image)}
"""
except Exception:
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
finally:
pbar.leave = False
pbar.close()
diff --git a/modules/images.py b/modules/images.py
index 3e7c64eb6..2846e7982 100644
--- a/modules/images.py
+++ b/modules/images.py
@@ -1,6 +1,5 @@
import datetime
import sys
-import traceback
import pytz
import io
@@ -421,7 +420,7 @@ class FilenameGenerator:
except Exception:
replacement = None
print(f"Error adding [{pattern}] to filename", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
if replacement is not None:
res += str(replacement)
@@ -666,7 +665,7 @@ Negative prompt: {json_info["uc"]}
Steps: {json_info["steps"]}, Sampler: {sampler}, CFG scale: {json_info["scale"]}, Seed: {json_info["seed"]}, Size: {image.width}x{image.height}, Clip skip: 2, ENSD: 31337"""
except Exception:
print("Error parsing NovelAI image generation parameters:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
return geninfo, items
diff --git a/modules/img2img.py b/modules/img2img.py
index c973b7708..622167ce7 100644
--- a/modules/img2img.py
+++ b/modules/img2img.py
@@ -1,7 +1,6 @@
import math
import os
import sys
-import traceback
import numpy as np
from PIL import Image, ImageOps, ImageFilter, ImageEnhance, ImageChops
diff --git a/modules/interrogate.py b/modules/interrogate.py
index cbb806832..31f37db4c 100644
--- a/modules/interrogate.py
+++ b/modules/interrogate.py
@@ -1,6 +1,5 @@
import os
import sys
-import traceback
from collections import namedtuple
from pathlib import Path
import re
@@ -218,7 +217,7 @@ class InterrogateModels:
except Exception:
print("Error interrogating", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
res += ""
self.unload()
diff --git a/modules/localization.py b/modules/localization.py
index 353a6baa1..368cecd58 100644
--- a/modules/localization.py
+++ b/modules/localization.py
@@ -1,7 +1,7 @@
import json
import os
import sys
-import traceback
+import modules.shared as shared
localizations = {}
@@ -33,6 +33,6 @@ def localization_js(current_localization_name):
data = json.load(file)
except Exception:
print(f"Error loading localization from {fn}:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
return f"var localization = {json.dumps(data)}\n"
diff --git a/modules/prompt_parser.py b/modules/prompt_parser.py
index 696653725..2a60bd2c9 100644
--- a/modules/prompt_parser.py
+++ b/modules/prompt_parser.py
@@ -94,8 +94,7 @@ def get_learned_conditioning_prompt_schedules(prompts, steps):
tree = schedule_parser.parse(prompt)
except lark.exceptions.LarkError as e:
if 0:
- import traceback
- traceback.print_exc()
+ shared.exception()
return [[steps, prompt]]
return [[t, at_step(t, tree)] for t in collect_steps(steps, tree)]
diff --git a/modules/realesrgan_model.py b/modules/realesrgan_model.py
index aad4a6298..7020f8791 100644
--- a/modules/realesrgan_model.py
+++ b/modules/realesrgan_model.py
@@ -1,6 +1,5 @@
import os
import sys
-import traceback
import numpy as np
from PIL import Image
@@ -9,6 +8,7 @@ from realesrgan import RealESRGANer
from modules.upscaler import Upscaler, UpscalerData
from modules.shared import cmd_opts, opts
+import modules.shared as shared
class UpscalerRealESRGAN(Upscaler):
@@ -29,7 +29,7 @@ class UpscalerRealESRGAN(Upscaler):
except Exception:
print("Error importing Real-ESRGAN:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
self.enable = False
self.scalers = []
@@ -68,7 +68,7 @@ class UpscalerRealESRGAN(Upscaler):
return info
except Exception as e:
print(f"Error making Real-ESRGAN models list: {e}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
return None
def load_models(self, _):
@@ -126,4 +126,4 @@ def get_realesrgan_models(scaler):
return models
except Exception as e:
print("Error making Real-ESRGAN models list:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
diff --git a/modules/safe.py b/modules/safe.py
index 82d44be31..1e99e9eb9 100644
--- a/modules/safe.py
+++ b/modules/safe.py
@@ -4,7 +4,6 @@ import io
import pickle
import collections
import sys
-import traceback
import torch
import numpy
@@ -136,16 +135,12 @@ def load_with_extra(filename, extra_handler=None, *args, **kwargs):
except pickle.UnpicklingError:
print(f"Error verifying pickled file from {filename}:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
- print("-----> !!!! The file is most likely corrupted !!!! <-----", file=sys.stderr)
- print("You can skip this check with --disable-safe-unpickle commandline argument, but that is not going to help you.\n\n", file=sys.stderr)
+ shared.exception()
return None
except Exception:
print(f"Error verifying pickled file from {filename}:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
- print("\nThe file may be malicious, so the program is not going to read it.", file=sys.stderr)
- print("You can skip this check with --disable-safe-unpickle commandline argument.\n\n", file=sys.stderr)
+ shared.exception()
return None
return unsafe_torch_load(filename, *args, **kwargs)
diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py
index 079118761..8a96839a4 100644
--- a/modules/script_callbacks.py
+++ b/modules/script_callbacks.py
@@ -1,7 +1,7 @@
import sys
-import traceback
from collections import namedtuple
import inspect
+import modules.shared as shared
from typing import Optional, Dict, Any
from fastapi import FastAPI
@@ -10,7 +10,7 @@ from gradio import Blocks
def report_exception(c, job):
print(f"Error executing callback {job} for {c.script}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
class ImageSaveParams:
diff --git a/modules/script_loading.py b/modules/script_loading.py
index a7d2203fc..e919d8c58 100644
--- a/modules/script_loading.py
+++ b/modules/script_loading.py
@@ -1,6 +1,6 @@
import os
import sys
-import traceback
+import modules.shared as shared
import importlib.util
from types import ModuleType
@@ -29,4 +29,4 @@ def preload_extensions(extensions_dir, parser):
except Exception:
print(f"Error running preload() for {preload_script}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
diff --git a/modules/scripts.py b/modules/scripts.py
index 8de19884b..99c6531f0 100644
--- a/modules/scripts.py
+++ b/modules/scripts.py
@@ -1,7 +1,6 @@
import os
import re
import sys
-import traceback
from collections import namedtuple
import gradio as gr
@@ -250,7 +249,8 @@ def load_scripts():
except Exception:
print(f"Error loading script: {scriptfile.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
+
finally:
sys.path = syspath
@@ -263,7 +263,7 @@ def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
return res
except Exception:
print(f"Error calling: {filename}/{funcname}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
return default
@@ -409,7 +409,7 @@ class ScriptRunner:
script.process(p, *script_args)
except Exception:
print(f"Error running process: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def before_process_batch(self, p, **kwargs):
for script in self.alwayson_scripts:
@@ -418,7 +418,7 @@ class ScriptRunner:
script.before_process_batch(p, *script_args, **kwargs)
except Exception:
print(f"Error running before_process_batch: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def process_batch(self, p, **kwargs):
for script in self.alwayson_scripts:
@@ -427,7 +427,7 @@ class ScriptRunner:
script.process_batch(p, *script_args, **kwargs)
except Exception:
print(f"Error running process_batch: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def postprocess(self, p, processed):
for script in self.alwayson_scripts:
@@ -436,7 +436,7 @@ class ScriptRunner:
script.postprocess(p, processed, *script_args)
except Exception:
print(f"Error running postprocess: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def postprocess_batch(self, p, images, **kwargs):
for script in self.alwayson_scripts:
@@ -445,7 +445,7 @@ class ScriptRunner:
script.postprocess_batch(p, *script_args, images=images, **kwargs)
except Exception:
print(f"Error running postprocess_batch: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def postprocess_image(self, p, pp: PostprocessImageArgs):
for script in self.alwayson_scripts:
@@ -454,7 +454,7 @@ class ScriptRunner:
script.postprocess_image(p, pp, *script_args)
except Exception:
print(f"Error running postprocess_batch: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def before_component(self, component, **kwargs):
for script in self.scripts:
@@ -462,7 +462,7 @@ class ScriptRunner:
script.before_component(component, **kwargs)
except Exception:
print(f"Error running before_component: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def after_component(self, component, **kwargs):
for script in self.scripts:
@@ -470,7 +470,7 @@ class ScriptRunner:
script.after_component(component, **kwargs)
except Exception:
print(f"Error running after_component: {script.filename}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def reload_sources(self, cache):
for si, script in list(enumerate(self.scripts)):
diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py
index f4bb0266f..4b80bae88 100644
--- a/modules/sd_hijack.py
+++ b/modules/sd_hijack.py
@@ -39,12 +39,7 @@ def apply_optimizations():
can_use_sdp = hasattr(torch.nn.functional, "scaled_dot_product_attention") and callable(getattr(torch.nn.functional, "scaled_dot_product_attention")) # not everyone has torch 2.x to use sdp
- if cmd_opts.force_enable_xformers or (cmd_opts.xformers and shared.xformers_available and torch.version.cuda and (6, 0) <= torch.cuda.get_device_capability(shared.device) <= (9, 0)):
- print("Applying xformers cross attention optimization.")
- ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward
- ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward
- optimization_method = 'xformers'
- elif cmd_opts.opt_sdp_no_mem_attention and can_use_sdp:
+ if cmd_opts.opt_sdp_no_mem_attention and can_use_sdp:
print("Applying scaled dot product cross attention optimization (without memory efficient attention).")
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.scaled_dot_product_no_mem_attention_forward
ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.sdp_no_mem_attnblock_forward
@@ -54,6 +49,11 @@ def apply_optimizations():
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.scaled_dot_product_attention_forward
ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.sdp_attnblock_forward
optimization_method = 'sdp'
+ elif cmd_opts.force_enable_xformers or (cmd_opts.xformers and shared.xformers_available and torch.version.cuda and (6, 0) <= torch.cuda.get_device_capability(shared.device) <= (9, 0)):
+ print("Applying xformers cross attention optimization.")
+ ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.xformers_attention_forward
+ ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.xformers_attnblock_forward
+ optimization_method = 'xformers'
elif cmd_opts.opt_sub_quad_attention:
print("Applying sub-quadratic cross attention optimization.")
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.sub_quad_attention_forward
@@ -62,16 +62,16 @@ def apply_optimizations():
elif cmd_opts.opt_split_attention_v1:
print("Applying v1 cross attention optimization.")
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_v1
- optimization_method = 'V1'
+ optimization_method = 'v1'
elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention_invokeai or not cmd_opts.opt_split_attention and not torch.cuda.is_available()):
print("Applying cross attention optimization (InvokeAI).")
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward_invokeAI
- optimization_method = 'InvokeAI'
+ optimization_method = 'invokeai'
elif not cmd_opts.disable_opt_split_attention and (cmd_opts.opt_split_attention or torch.cuda.is_available()):
print("Applying cross attention optimization (Doggettx).")
ldm.modules.attention.CrossAttention.forward = sd_hijack_optimizations.split_cross_attention_forward
ldm.modules.diffusionmodules.model.AttnBlock.forward = sd_hijack_optimizations.cross_attention_attnblock_forward
- optimization_method = 'Doggettx'
+ optimization_method = 'doggettx'
return optimization_method
diff --git a/modules/sd_hijack_optimizations.py b/modules/sd_hijack_optimizations.py
index 2e307b5d0..394e9619d 100644
--- a/modules/sd_hijack_optimizations.py
+++ b/modules/sd_hijack_optimizations.py
@@ -1,6 +1,5 @@
import math
import sys
-import traceback
import psutil
import torch
@@ -20,8 +19,7 @@ if shared.cmd_opts.xformers or shared.cmd_opts.force_enable_xformers:
import xformers.ops
shared.xformers_available = True
except Exception:
- print("Cannot import xformers", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ pass
def get_available_vram():
diff --git a/modules/shared.py b/modules/shared.py
index 2d72e4d4d..bbf7624be 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -58,7 +58,7 @@ parser.add_argument("--esrgan-models-path", type=str, help="Path to directory wi
parser.add_argument("--bsrgan-models-path", type=str, help="Path to directory with BSRGAN model file(s).", default=os.path.join(models_path, 'BSRGAN'))
parser.add_argument("--realesrgan-models-path", type=str, help="Path to directory with RealESRGAN model file(s).", default=os.path.join(models_path, 'RealESRGAN'))
parser.add_argument("--clip-models-path", type=str, help="Path to directory with CLIP model file(s).", default=None)
-parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers")
+parser.add_argument("--xformers", action='store_true', help="enable xformers for cross attention layers", default=True)
parser.add_argument("--force-enable-xformers", action='store_true', help="enable xformers for cross attention layers regardless of whether the checking code thinks you can run it; do not make bug reports if this fails to work")
parser.add_argument("--xformers-flash-attention", action='store_true', help="enable xformers with Flash Attention to improve reproducibility (supported for SD2.x or variant only)")
parser.add_argument("--deepdanbooru", action='store_true', help="does not do anything")
@@ -69,7 +69,7 @@ parser.add_argument("--sub-quad-kv-chunk-size", type=int, help="kv chunk size fo
parser.add_argument("--sub-quad-chunk-threshold", type=int, help="the percentage of VRAM threshold for the sub-quadratic cross-attention layer optimization to use chunking", default=None)
parser.add_argument("--opt-split-attention-invokeai", action='store_true', help="force-enables InvokeAI's cross-attention layer optimization. By default, it's on when cuda is unavailable.")
parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find")
-parser.add_argument("--opt-sdp-attention", action='store_true', help="enable scaled dot product cross-attention layer optimization; requires PyTorch 2.*")
+parser.add_argument("--opt-sdp-attention", action='store_true', help="enable scaled dot product cross-attention layer optimization; requires PyTorch 2.*", default=True)
parser.add_argument("--opt-sdp-no-mem-attention", action='store_true', help="enable scaled dot product cross-attention layer optimization without memory efficient attention, makes image generation deterministic; requires PyTorch 2.*")
parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization")
parser.add_argument("--disable-nan-check", action='store_true', help="do not check if produced images/latent spaces have nans; useful for running without a checkpoint in CI", default=True)
@@ -742,3 +742,16 @@ def html(filename):
return file.read()
return ""
+
+try:
+ from rich.console import Console
+ console = Console()
+except:
+ console = None
+ import traceback
+
+def exception():
+ if console is not None:
+ console.print_exception(show_locals=True, max_frames=10, extra_lines=1, suppress=[gr], word_wrap=False, width=min([console.width, 200]))
+ else:
+ print(traceback.format_exc(), file=sys.stderr)
diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py
index 995da753e..841110ef4 100644
--- a/modules/textual_inversion/textual_inversion.py
+++ b/modules/textual_inversion/textual_inversion.py
@@ -1,6 +1,5 @@
import os
import sys
-import traceback
import inspect
from collections import namedtuple
@@ -206,7 +205,7 @@ class EmbeddingDatabase:
self.load_from_file(fullfn, fn)
except Exception:
print(f"Error loading embedding {fn}:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
continue
def load_textual_inversion_embeddings(self, force_reload=False):
@@ -623,7 +622,7 @@ Last saved image: {html.escape(last_saved_image)}
filename = os.path.join(shared.cmd_opts.embeddings_dir, f'{embedding_name}.pt')
save_embedding(embedding, optimizer, checkpoint, embedding_name, filename, remove_cached_checksum=True)
except Exception:
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
pass
finally:
pbar.leave = False
diff --git a/modules/ui.py b/modules/ui.py
index fa5a87633..029d02a62 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -8,7 +8,6 @@ import random
import sys
import tempfile
import time
-import traceback
from functools import partial, reduce
import warnings
@@ -1637,7 +1636,7 @@ def create_ui():
results = modules.extras.run_modelmerger(*args)
except Exception as e:
print("Error loading/saving model file:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
modules.sd_models.list_models() # to remove the potentially missing models from the list
return [*[gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"]
return results
@@ -1681,7 +1680,7 @@ def create_ui():
except Exception:
error_loading = True
print("Error loading settings:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
def loadsave(path, x):
def apply_field(obj, field, condition=None, init_field=None):
diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py
index 14e29f832..73674af59 100644
--- a/modules/ui_extensions.py
+++ b/modules/ui_extensions.py
@@ -3,7 +3,6 @@ import os.path
import shutil
import sys
import time
-import traceback
import git
@@ -41,7 +40,7 @@ def apply_and_restart(disable_list, update_list):
ext.fetch_and_reset_hard()
except Exception:
print(f"Error getting updates for {ext.name}:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
shared.opts.disabled_extensions = disabled
shared.opts.save(shared.config_filename)
@@ -66,7 +65,7 @@ def check_updates(id_task, disable_list):
ext.check_updates()
except Exception:
print(f"Error checking updates for {ext.name}:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
shared.state.nextjob()
diff --git a/scripts/prompts_from_file.py b/scripts/prompts_from_file.py
index 76dc5778b..d5f029362 100644
--- a/scripts/prompts_from_file.py
+++ b/scripts/prompts_from_file.py
@@ -3,7 +3,7 @@ import math
import os
import random
import sys
-import traceback
+import modules.shared as shared
import shlex
import modules.scripts as scripts
@@ -141,7 +141,7 @@ class Script(scripts.Script):
args = cmdargs(line)
except Exception:
print(f"Error parsing line {line} as commandline:", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
+ shared.exception()
args = {"prompt": line}
else:
args = {"prompt": line}
diff --git a/webui.py b/webui.py
index de6accfe4..36ea1b808 100644
--- a/webui.py
+++ b/webui.py
@@ -64,40 +64,7 @@ else:
server_name = "0.0.0.0" if cmd_opts.listen else None
-def check_versions():
- if shared.cmd_opts.skip_version_check:
- return
-
- expected_torch_version = "1.13.1"
-
- if version.parse(torch.__version__) < version.parse(expected_torch_version):
- errors.print_error_explanation(f"""
-You are running torch {torch.__version__}.
-The program is tested to work with torch {expected_torch_version}.
-To reinstall the desired version, run with commandline flag --reinstall-torch.
-Beware that this will cause a lot of large files to be downloaded, as well as
-there are reports of issues with training tab on the latest version.
-
-Use --skip-version-check commandline argument to disable this check.
- """.strip())
-
- expected_xformers_version = "0.0.16rc425"
- if shared.xformers_available:
- import xformers
-
- if version.parse(xformers.__version__) < version.parse(expected_xformers_version):
- errors.print_error_explanation(f"""
-You are running xformers {xformers.__version__}.
-The program is tested to work with xformers {expected_xformers_version}.
-To reinstall the desired version, run with commandline flag --reinstall-xformers.
-
-Use --skip-version-check commandline argument to disable this check.
- """.strip())
-
-
def initialize():
- check_versions()
-
extensions.list_extensions()
startup_timer.record("list extensions")