Merge branch 'master' into ipex-native-win

This commit is contained in:
Disty0
2023-08-16 20:27:57 +03:00
committed by GitHub
48 changed files with 1662 additions and 220 deletions
+46 -1
View File
@@ -1,5 +1,51 @@
# Change Log for SD.Next
## Update for 2023-08-14
- general:
- update all metadata saved with images
see <https://github.com/vladmandic/automatic/wiki/Metadata> for details
(work-in-progress)
- improved **amd** installer with support for **navi 2x & 3x** and **rocm 5.4/5.5/5.6**
thanks @evshiron
- fix img2img resizing (applies to original, diffusers, hires)
- diffusers:
- enable batch img2img workflows
- original:
- new samplers: **dpm++ 3M sde** (standard and karras variations)
enable in *settings -> samplers -> show samplers*
## Update for 2023-08-11
This is a big one that's been cooking in `dev` for a while now, but finally ready for release...
- diffusers:
- **pipeline autodetect**
if pipeline is set to autodetect (default for new installs), app will try to autodetect pipeline based on selected model
this should reduce user errors such as loading **sd-xl** model when **sd** pipeline is selected
- **quick vae decode** as alternative to full vae decode which is very resource intensive
quick decode is based on `taesd` and produces lower quality, but its great for tests or grids as it runs much faster and uses far less vram
disabled by default, selectable in *txt2img/img2img -> advanced -> full quality*
- **prompt attention** for sd and sd-xl
supports both `full parser` and native `compel`
thanks @ai-casanova
- advanced **lora load/apply** methods
in addition to standard lora loading that was recently added to sd-xl using diffusers, now we have
- **sequential apply** (load & apply multiple loras in sequential manner) and
- **merge and apply** (load multiple loras and merge before applying to model)
see *settings -> diffusers -> lora methods*
thanks @hameerabbasi and @ai-casanova
- **sd-xl vae** from safetensors now applies correct config
result is that 3rd party vaes can be used without washed out colors
- options for optimized memory handling for lower memory usage
see *settings -> diffusers*
- general:
- new **civitai model search and download**
native support for civitai, integrated into ui as *models -> civitai*
- updated requirements
this time its a bigger change so upgrade may take longer to install new requirements
- improved **extra networks** performance with large number of networks
## Update for 2023-08-05
Another minor update, but it unlocks some cool new items...
@@ -11,7 +57,6 @@ Another minor update, but it unlocks some cool new items...
- new torch 2.0 with ipex (intel arc)
- additional callbacks for extensions
enables latest comfyui extension
- update requirements
## Update for 2023-07-30
+9 -5
View File
@@ -71,15 +71,15 @@ Additional models will be added as they become available and there is public int
- *Intel Arc* GPUs using *Intel OneAPI* **Ipex/XPU** libraries
- *Apple M1/M2* on *OSX* using built-in support in Torch with **MPS** optimizations
## [Installation Instructions](https://github.com/vladmandic/automatic/wiki/Installation)
## Install & Run
### Common Problems
- [Common Installation Errors ](https://github.com/vladmandic/automatic/discussions/1627)
- [Q&A Discussions](https://github.com/vladmandic/automatic/discussions/1011)
- [Step-by-step install guide](https://github.com/vladmandic/automatic/wiki/Installation)
- [Advanced install notes](https://github.com/vladmandic/automatic/wiki/Advanced-Install)
### Installation Notes
- [Common installation errors](https://github.com/vladmandic/automatic/discussions/1627)
- [FAQ](https://github.com/vladmandic/automatic/discussions/1011)
- Server can run without virtual environment,
but it is recommended to use it to avoid library version conflicts with other applications
- **nVidia/CUDA** and **AMD/ROCm** are auto-detected if present and available,
@@ -87,6 +87,10 @@ Additional models will be added as they become available and there is public int
as installer will assume CPU-only environment
- Full startup sequence is logged in `sdnext.log`, so if you encounter any issues, please check it first
### Run
Once SD.Next is installed, simply run `webui.bat` (*Windows*) or `webui.sh` (*Linux or MacOS*)
Below is partial list of all available parameters, run `webui --help` for the full list:
Setup options:
+2
View File
@@ -26,6 +26,7 @@ Stuff to be added, in no particular order...
- Port `p.all_hr_prompts`
- Import core repos to reduce dependencies
- Update `gradio`
- Parse StabilityAI `modelspec` metadata
- Non-technical:
- Create additional themes
- Update Wiki
@@ -41,6 +42,7 @@ Stuff to be added, in no particular order...
- Style editor (use json format instead of csv)
- Profile manager (for config.json and ui-config.json)
- Multi-user support
- Add [SAG](https://huggingface.co/docs/diffusers/v0.19.3/en/api/pipelines/self_attention_guidance),(https://github.com/ashen-sensored/sd_webui_SAG)
- Image phash and hdash using `imagehash`
- Model merge using `git-rebasin`
- Enable refiner-style workflow for `ldm` backend
Executable
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env python
import os
import time
import datetime
import logging
import urllib3
import requests
class Dot(dict):
__getattr__ = dict.get
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
opts = Dot({
"timeout": 3600,
"frequency": 60,
"action": "sudo shutdown now",
"url": "https://127.0.0.1:7860",
"user": "",
"password": "",
})
log_format = '%(asctime)s %(levelname)s: %(message)s'
logging.basicConfig(level = logging.INFO, format = log_format)
log = logging.getLogger("sd")
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
status = None
def progress():
auth = requests.auth.HTTPBasicAuth(opts.user, opts.password) if opts.user is not None and len(opts.user) > 0 and opts.password is not None and len(opts.password) > 0 else None
req = requests.get(f'{opts.url}/sdapi/v1/progress?skip_current_image=true', verify=False, auth=auth, timeout=60)
if req.status_code != 200:
log.error({ 'url': req.url, 'request': req.status_code, 'reason': req.reason })
return status
else:
res = Dot(req.json())
log.debug({ 'url': req.url, 'request': req.status_code, 'result': res })
return res
log.info(f'sdnext monitor started: {opts}')
while True:
try:
status = progress()
state = status.get('state', {})
last_job = state.get('job_timestamp', None)
if last_job is None:
log.warning(f'sdnext montoring cannot get last job info: {status}')
else:
last_job = datetime.datetime.strptime(last_job, "%Y%m%d%H%M%S")
elapsed = datetime.datetime.now() - last_job
timeout = round(opts.timeout - elapsed.total_seconds())
log.info(f'sdnext: last_job={last_job} elapsed={elapsed} timeout={timeout}')
if timeout < 0:
log.warning(f'sdnext reached: timeout={opts.timeout} action={opts.action}')
os.system(opts.action)
except Exception as e:
log.error(f'sdnext monitor error: {e}')
finally:
time.sleep(opts.frequency)
Executable → Regular
View File
+18 -4
View File
@@ -1,19 +1,24 @@
#!/usr/bin/env python
import os
import io
import sys
import base64
import logging
import requests
import urllib3
from PIL import Image
sd_url = os.environ.get('SDAPI_URL', "http://127.0.0.1:7860")
sd_username = os.environ.get('SDAPI_USR', None)
sd_password = os.environ.get('SDAPI_PWD', None)
logging.basicConfig(level = logging.INFO, format = '%(asctime)s %(levelname)s: %(message)s')
log = logging.getLogger(__name__)
sd_url = "http://127.0.0.1:7860"
options = {
"init_images": [],
"prompt": "city at night",
"negative_prompt": "foggy, blurry",
"steps": 1,
"steps": 20,
"batch_size": 1,
"n_iter": 1,
"seed": -1,
@@ -24,9 +29,17 @@ options = {
"save_images": False,
"send_images": True,
}
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def auth():
if sd_username is not None and sd_password is not None:
return requests.auth.HTTPBasicAuth(sd_username, sd_password)
return None
def post(endpoint: str, dct: dict = None):
req = requests.post(f'{sd_url}{endpoint}', json = dct, timeout=300)
req = requests.post(f'{sd_url}{endpoint}', json = dct, timeout=300, verify=False, auth=auth())
if req.status_code != 200:
return { 'error': req.status_code, 'reason': req.reason, 'url': req.url }
else:
@@ -44,7 +57,8 @@ def encode(f):
def generate(num: int = 0):
log.info(f'sending generate request: {num+1} {options}')
options['init_images'] = [encode('../html/logo.png')]
options['init_images'] = [encode('html/logo-dark.png')]
options['batch_size'] = len(options['init_images'])
data = post('/sdapi/v1/img2img', options)
if 'images' in data:
for i in range(len(data['images'])):
+3
View File
@@ -5,6 +5,7 @@ import sys
import base64
import logging
import requests
import urllib3
from PIL import Image
sd_url = os.environ.get('SDAPI_URL', "http://127.0.0.1:7860")
@@ -13,6 +14,7 @@ sd_password = os.environ.get('SDAPI_PWD', None)
logging.basicConfig(level = logging.INFO, format = '%(asctime)s %(levelname)s: %(message)s')
log = logging.getLogger(__name__)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
filename='/tmp/simple-txt2img.jpg'
model = None # desired model name, will be set if not none
@@ -31,6 +33,7 @@ options = {
"send_images": True,
}
def auth():
if sd_username is not None and sd_password is not None:
return requests.auth.HTTPBasicAuth(sd_username, sd_password)
+2 -2
View File
@@ -375,7 +375,7 @@ def check_versions():
log.info('checking accelerate')
error = False
import accelerate
if accelerate.__version__ != '0.19.0':
if accelerate.__version__ != '0.20.3':
log.error(f'invalid accelerate version: accelerate=0.19.0 found={accelerate.__version__}')
error = True
log.info('checking diffusers')
@@ -384,7 +384,7 @@ def check_versions():
log.error(f'invalid diffusers version: diffusers=0.10.2 found={diffusers.__version__}')
error = True
if error:
log.info('> pip install accelerate==0.19.0 diffusers==0.10.2')
log.info('> pip install accelerate==0.20.3 diffusers==0.10.2')
exit(1)
+98
View File
@@ -0,0 +1,98 @@
model:
target: sgm.models.diffusion.DiffusionEngine
params:
scale_factor: 0.13025
disable_first_stage_autocast: True
denoiser_config:
target: sgm.modules.diffusionmodules.denoiser.DiscreteDenoiser
params:
num_idx: 1000
weighting_config:
target: sgm.modules.diffusionmodules.denoiser_weighting.EpsWeighting
scaling_config:
target: sgm.modules.diffusionmodules.denoiser_scaling.EpsScaling
discretization_config:
target: sgm.modules.diffusionmodules.discretizer.LegacyDDPMDiscretization
network_config:
target: sgm.modules.diffusionmodules.openaimodel.UNetModel
params:
adm_in_channels: 2816
num_classes: sequential
use_checkpoint: True
in_channels: 4
out_channels: 4
model_channels: 320
attention_resolutions: [4, 2]
num_res_blocks: 2
channel_mult: [1, 2, 4]
num_head_channels: 64
use_spatial_transformer: True
use_linear_in_transformer: True
transformer_depth: [1, 2, 10] # note: the first is unused (due to attn_res starting at 2) 32, 16, 8 --> 64, 32, 16
context_dim: 2048
spatial_transformer_attn_type: softmax-xformers
legacy: False
conditioner_config:
target: sgm.modules.GeneralConditioner
params:
emb_models:
# crossattn cond
- is_trainable: False
input_key: txt
target: sgm.modules.encoders.modules.FrozenCLIPEmbedder
params:
layer: hidden
layer_idx: 11
# crossattn and vector cond
- is_trainable: False
input_key: txt
target: sgm.modules.encoders.modules.FrozenOpenCLIPEmbedder2
params:
arch: ViT-bigG-14
version: laion2b_s39b_b160k
freeze: True
layer: penultimate
always_return_pooled: True
legacy: False
# vector cond
- is_trainable: False
input_key: original_size_as_tuple
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
params:
outdim: 256 # multiplied by two
# vector cond
- is_trainable: False
input_key: crop_coords_top_left
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
params:
outdim: 256 # multiplied by two
# vector cond
- is_trainable: False
input_key: target_size_as_tuple
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
params:
outdim: 256 # multiplied by two
first_stage_config:
target: sgm.models.autoencoder.AutoencoderKLInferenceWrapper
params:
embed_dim: 4
monitor: val/rec_loss
ddconfig:
attn_type: vanilla-xformers
double_z: true
z_channels: 4
resolution: 256
in_channels: 3
out_ch: 3
ch: 128
ch_mult: [1, 2, 4, 4]
num_res_blocks: 2
attn_resolutions: []
dropout: 0.0
lossconfig:
target: torch.nn.Identity
+91
View File
@@ -0,0 +1,91 @@
model:
target: sgm.models.diffusion.DiffusionEngine
params:
scale_factor: 0.13025
disable_first_stage_autocast: True
denoiser_config:
target: sgm.modules.diffusionmodules.denoiser.DiscreteDenoiser
params:
num_idx: 1000
weighting_config:
target: sgm.modules.diffusionmodules.denoiser_weighting.EpsWeighting
scaling_config:
target: sgm.modules.diffusionmodules.denoiser_scaling.EpsScaling
discretization_config:
target: sgm.modules.diffusionmodules.discretizer.LegacyDDPMDiscretization
network_config:
target: sgm.modules.diffusionmodules.openaimodel.UNetModel
params:
adm_in_channels: 2560
num_classes: sequential
use_checkpoint: True
in_channels: 4
out_channels: 4
model_channels: 384
attention_resolutions: [4, 2]
num_res_blocks: 2
channel_mult: [1, 2, 4, 4]
num_head_channels: 64
use_spatial_transformer: True
use_linear_in_transformer: True
transformer_depth: 4
context_dim: [1280, 1280, 1280, 1280] # 1280
spatial_transformer_attn_type: softmax-xformers
legacy: False
conditioner_config:
target: sgm.modules.GeneralConditioner
params:
emb_models:
# crossattn and vector cond
- is_trainable: False
input_key: txt
target: sgm.modules.encoders.modules.FrozenOpenCLIPEmbedder2
params:
arch: ViT-bigG-14
version: laion2b_s39b_b160k
legacy: False
freeze: True
layer: penultimate
always_return_pooled: True
# vector cond
- is_trainable: False
input_key: original_size_as_tuple
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
params:
outdim: 256 # multiplied by two
# vector cond
- is_trainable: False
input_key: crop_coords_top_left
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
params:
outdim: 256 # multiplied by two
# vector cond
- is_trainable: False
input_key: aesthetic_score
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
params:
outdim: 256 # multiplied by one
first_stage_config:
target: sgm.models.autoencoder.AutoencoderKLInferenceWrapper
params:
embed_dim: 4
monitor: val/rec_loss
ddconfig:
attn_type: vanilla-xformers
double_z: true
z_channels: 4
resolution: 256
in_channels: 3
out_ch: 3
ch: 128
ch_mult: [1, 2, 4, 4]
num_res_blocks: 2
attn_resolutions: []
dropout: 0.0
lossconfig:
target: torch.nn.Identity
+7 -8
View File
@@ -562,21 +562,20 @@
{"id":"","label":"Token merging ratio","localized":"","hint":"Enable redundant token merging via tomesd for speed and memory improvements, 0=disabled"},
{"id":"","label":"Token merging ratio for img2img","localized":"","hint":"Enable redundant token merging for img2img via tomesd for speed and memory improvements, 0=disabled"},
{"id":"","label":"Token merging ratio for hires pass","localized":"","hint":"Enable redundant token merging for hires pass via tomesd for speed and memory improvements, 0=disabled"},
{"id":"","label":"Diffusers allow loading from safetensors files","localized":"","hint":"Allow loading of safetensors files as diffuser models"},
{"id":"","label":"Select diffuser pipeline when loading from safetensors","localized":"","hint":""},
{"id":"","label":"Move base model to CPU when using refiner","localized":"","hint":""},
{"id":"","label":"Move refiner model to CPU when not in use","localized":"","hint":""},
{"id":"","label":"Move UNet to CPU while VAE decoding","localized":"","hint":""},
{"id":"","label":"Use model EMA weights when possible","localized":"","hint":""},
{"id":"","label":"Generator device","localized":"","hint":""},
{"id":"","label":"Enable sequential CPU offload","localized":"","hint":"Reduces GPU memory usage by transferring weights to the CPU. Increases inference time approximately 10%. Use with Enable Attention slicing for minimal memory consumption"},
{"id":"","label":"Enable model CPU offload","localized":"","hint":"Transferring of entire models to the CPU, negligible impact on inference time while still providing some memory savings. Use with Enable Attention slicing for additional memory savings"},
{"id":"","label":"Enable VAE slicing","localized":"","hint":"Decodes batch latents one image at a time with limited VRAM. Small performance boost in VAE decode on multi-image batches. Use with Enable Attention slicing"},
{"id":"","label":"Enable VAE tiling","localized":"","hint":"Divide large images into overlapping tiles with limited VRAM. Might result in a minor increase in processing time. Use with Enable Attention Slicing"},
{"id":"","label":"Enable attention slicing","localized":"","hint":"Performs attention computation in steps instead of all at once. 10% slower inference times. Greatly reduces memory usage. Best used, period"},
{"id":"","label":"Enable sequential CPU offload","localized":"","hint":"Reduces GPU memory usage by transferring weights to the CPU. Increases inference time approximately 10%"},
{"id":"","label":"Enable model CPU offload","localized":"","hint":"Transferring of entire models to the CPU, negligible impact on inference time while still providing some memory savings"},
{"id":"","label":"Enable VAE slicing","localized":"","hint":"Decodes batch latents one image at a time with limited VRAM. Small performance boost in VAE decode on multi-image batches"},
{"id":"","label":"Enable VAE tiling","localized":"","hint":"Divide large images into overlapping tiles with limited VRAM. Results in a minor increase in processing time"},
{"id":"","label":"Enable attention slicing","localized":"","hint":"Performs attention computation in steps instead of all at once. Slower inference times, but greatly reduced memory usage"},
{"id":"","label":"Diffusers model loading variant","localized":"","hint":""},
{"id":"","label":"Diffusers VAE loading variant","localized":"","hint":""}
{"id":"","label":"Diffusers VAE loading variant","localized":"","hint":""},
{"id":"","label":"Diffusers LoRA loading variant","localized":"","hint":"'sequential apply' loads and applies each LoRA in order of appearance, 'merge and apply' loads all LoRAs and merges them in-memory before applying to model, 'diffusers default' uses single LoRA loading method"}
],
"scripts": [
{"id":"","label":"Script","localized":"","hint":""},
-1
View File
@@ -562,7 +562,6 @@
{"id":"","label":"Token merging ratio","localized":"토큰 병합 비율","hint":"속도와 메모리 절감을 위해 tomesd를 사용해 토큰 병합을 활성화한다. (0이면 비활성화)"},
{"id":"","label":"Token merging ratio for img2img","localized":"이미지➠이미지 토큰 병합 비율","hint":"속도와 메모리 절감을 위해 이미지➠이미지에서 tomesd를 사용해 토큰 병합을 활성화한다. (0이면 비활성화)"},
{"id":"","label":"Token merging ratio for hires pass","localized":"텍스트➠이미지 업스케일링(Hires fix) 토큰 병합 비율","hint":"속도와 메모리 절감을 위해 Hires fix에서 tomesd를 사용해 토큰 병합을 활성화한다. (0이면 비활성화)"},
{"id":"","label":"Diffusers allow loading from safetensors files","localized":"safetensors 파일에서 로드 허용","hint":"safetensors 파일을 Diffusers 모델로 로드할 수 있게 한다."},
{"id":"","label":"Select diffuser pipeline when loading from safetensors","localized":"safetensors 파일에서 로드할 때 사용할 파이프라인 선택","hint":""},
{"id":"","label":"Move base model to CPU when using refiner","localized":"리파이너를 사용 중일 때 base 모델을 CPU로 이동","hint":""},
{"id":"","label":"Move refiner model to CPU when not in use","localized":"사용 중이지 않을 때 리파이너 모델을 CPU로 이동","hint":""},
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+68 -9
View File
@@ -81,7 +81,7 @@ def setup_logging():
}))
logging.basicConfig(level=logging.ERROR, format='%(asctime)s | %(name)s | %(levelname)s | %(module)s | %(message)s', handlers=[logging.NullHandler()]) # redirect default logger to null
pretty_install(console=console)
traceback_install(console=console, extra_lines=1, width=console.width, word_wrap=False, indent_guides=False, suppress=[])
traceback_install(console=console, extra_lines=1, max_frames=10, width=console.width, word_wrap=False, indent_guides=False, suppress=[])
while log.hasHandlers() and len(log.handlers) > 0:
log.removeHandler(log.handlers[0])
@@ -166,8 +166,9 @@ def pip(arg: str, ignore: bool = False, quiet: bool = False):
arg = arg.replace('>=', '==')
if not quiet:
log.info(f'Installing package: {arg.replace("install", "").replace("--upgrade", "").replace("--no-deps", "").replace("--force", "").replace(" ", " ").strip()}')
log.debug(f"Running pip: {arg}")
result = subprocess.run(f'"{sys.executable}" -m pip {arg}', shell=True, check=False, env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
env_args = os.environ.get("PIP_EXTRA_ARGS", "")
log.debug(f"Running pip: {arg} {env_args}")
result = subprocess.run(f'"{sys.executable}" -m pip {arg} {env_args}', shell=True, check=False, env=os.environ, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
txt = result.stdout.decode(encoding="utf8", errors="ignore")
if len(result.stderr) > 0:
txt += ('\n' if len(txt) > 0 else '') + result.stderr.decode(encoding="utf8", errors="ignore")
@@ -339,7 +340,56 @@ def check_torch():
log.info('AMD ROCm toolkit detected')
os.environ.setdefault('PYTORCH_HIP_ALLOC_CONF', 'garbage_collection_threshold:0.8,max_split_size_mb:512')
os.environ.setdefault('TENSORFLOW_PACKAGE', 'tensorflow-rocm')
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/rocm5.4.2')
try:
command = subprocess.run('rocm_agent_enumerator', shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
amd_gpus = command.stdout.decode(encoding="utf8", errors="ignore").split('\n')
amd_gpus = [x for x in amd_gpus if x and x != 'gfx000']
log.debug(f'ROCm agents detected: {amd_gpus}')
except Exception as e:
log.debug(f'Run rocm_agent_enumerator failed: {e}')
amd_gpus = []
# use the first available amd gpu by default
hip_visible_devices = []
for idx, gpu in enumerate(amd_gpus):
if gpu in ['gfx1100', 'gfx1101', 'gfx1102']:
hip_visible_devices.append((idx, gpu, 'navi3x'))
break
# experimental navi 2x support
if gpu in ['gfx1030', 'gfx1031', 'gfx1032', 'gfx1034']:
hip_visible_devices.append((idx, gpu, 'navi2x'))
break
if len(hip_visible_devices) > 0:
idx, gpu, arch = hip_visible_devices[0]
log.debug(f'ROCm agent used by default: idx={idx} gpu={gpu} arch={arch}')
os.environ.setdefault('HIP_VISIBLE_DEVICES', str(idx))
if arch == 'navi3x':
os.environ.setdefault('HSA_OVERRIDE_GFX_VERSION', '11.0.0')
# do not use tensorflow-rocm for navi 3x
if os.environ.get('TENSORFLOW_PACKAGE') == 'tensorflow-rocm':
os.environ['TENSORFLOW_PACKAGE'] = 'tensorflow==2.13.0'
elif arch == 'navi2x':
os.environ.setdefault('HSA_OVERRIDE_GFX_VERSION', '10.3.0')
else:
log.debug(f'HSA_OVERRIDE_GFX_VERSION auto config is skipped for {gpu}')
try:
command = subprocess.run('hipconfig --version', shell=True, check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
major_ver, minor_ver, *_ = command.stdout.decode(encoding="utf8", errors="ignore").split('.')
rocm_ver = f'{major_ver}.{minor_ver}'
log.debug(f'ROCm version detected: {rocm_ver}')
except Exception as e:
log.debug(f'Run hipconfig failed: {e}')
rocm_ver = None
if rocm_ver in ['5.5', '5.6']:
# install torch nightly via torchvision to avoid wasting bandwidth when torchvision depends on torch from yesterday
torch_command = os.environ.get('TORCH_COMMAND', f'torchvision --pre --index-url https://download.pytorch.org/whl/nightly/rocm{rocm_ver}')
else:
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.1 torchvision==0.15.2 --index-url https://download.pytorch.org/whl/rocm5.4.2')
xformers_package = os.environ.get('XFORMERS_PACKAGE', 'none')
elif allow_ipex and (args.use_ipex or shutil.which('sycl-ls') is not None or shutil.which('sycl-ls.exe') is not None or os.environ.get('ONEAPI_ROOT') is not None or os.path.exists('/opt/intel/oneapi') or os.path.exists("C:/Program Files (x86)/Intel/oneAPI") or os.path.exists("C:/oneAPI")):
args.use_ipex = True # pylint: disable=attribute-defined-outside-init
@@ -349,10 +399,10 @@ def check_torch():
os.environ.setdefault('NEOReadDebugKeys', '1')
os.environ.setdefault('ClDeviceGlobalMemSizeAvailablePercent', '100')
if "linux" in sys.platform:
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.1a0 torchvision==0.15.2a0 intel_extension_for_pytorch==2.0.110+xpu -f https://developer.intel.com/ipex-whl-stable-xpu')
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.1a0 torchvision==0.15.2a0 intel_extension_for_pytorch==2.0.110+xpu openvino==2023.1.0.dev20230728 -f https://developer.intel.com/ipex-whl-stable-xpu')
os.environ.setdefault('TENSORFLOW_PACKAGE', 'tensorflow==2.13.0 intel-extension-for-tensorflow[gpu]')
else:
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.0a0 torchvision==0.15.2a0 intel_extension_for_pytorch==2.0.110+gitba7f6c1 -f https://developer.intel.com/ipex-whl-stable-xpu')
torch_command = os.environ.get('TORCH_COMMAND', 'torch==2.0.0a0 torchvision==0.15.1 intel_extension_for_pytorch==2.0.110+gitba7f6c1 openvino==2023.1.0.dev20230728 -f https://developer.intel.com/ipex-whl-stable-xpu')
else:
machine = platform.machine()
if sys.platform == 'darwin':
@@ -408,7 +458,7 @@ def check_torch():
try:
if 'xformers' in xformers_package:
install(f'--no-deps {xformers_package}', ignore=True)
else:
elif not args.experimental:
x = pkg_resources.working_set.by_key.get('xformers', None)
if x is not None:
log.warning(f'Not used, uninstalling: {x}')
@@ -453,8 +503,17 @@ def install_packages():
install(invisiblewatermark_package, 'invisible-watermark')
install('onnxruntime==1.15.1', 'onnxruntime', ignore=True)
install('pi-heif', 'pi_heif', ignore=True)
tensorflow_package = os.environ.get('TENSORFLOW_PACKAGE', 'tensorflow==2.12.0')
install('git+https://github.com/damian0815/compel', 'compel', ignore=True)
tensorflow_package = os.environ.get('TENSORFLOW_PACKAGE', 'tensorflow==2.13.0')
install(tensorflow_package, 'tensorflow', ignore=True)
bitsandbytes_package = os.environ.get('BITSANDBYTES_PACKAGE', None)
if bitsandbytes_package is not None:
install(bitsandbytes_package, 'bitsandbytes', ignore=True)
elif not args.experimental:
bitsandbytes_package = pkg_resources.working_set.by_key.get('bitsandbytes', None)
if bitsandbytes_package is not None:
log.warning(f'Not used, uninstalling: {bitsandbytes_package}')
pip('uninstall bitsandbytes --yes --quiet', ignore=True, quiet=True)
if args.profile:
print_profile(pr, 'Packages')
@@ -478,7 +537,7 @@ def install_repositories():
clone(taming_transformers_repo, d('taming-transformers'), taming_transformers_commit)
k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git')
# k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', "b43db16749d51055f813255eea2fdf1def801919")
k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', None)
k_diffusion_commit = os.environ.get('K_DIFFUSION_COMMIT_HASH', 'ab527a9')
clone(k_diffusion_repo, d('k-diffusion'), k_diffusion_commit)
codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git')
# codeformer_commit = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
+1
View File
@@ -169,6 +169,7 @@ if __name__ == "__main__":
if installer.check_timestamp():
installer.log.info('No changes detected: Quick launch active')
installer.install_requirements()
installer.install_packages()
installer.check_extensions()
else:
installer.install_requirements()
+4 -8
View File
@@ -40,7 +40,7 @@ def get_cuda_device_string():
def get_optimal_device_name():
if cuda_ok or backend == 'ipex' or backend == 'directml':
if cuda_ok or backend == 'directml':
return get_cuda_device_string()
if has_mps():
return "mps"
@@ -67,7 +67,7 @@ def torch_gc(force=False):
previous_oom = oom
shared.log.warning(f'GPU out-of-memory error: {mem}')
if used > 95:
shared.log.warning(f'GPU high memory utilization: {used}% {mem}')
shared.log.info(f'GPU high memory utilization: {used}% {mem}')
force = True
if backend == "directml":
practical_used = round(100 * torch.cuda.memory_allocated() / (1 << 30) / gpu.get('total', 1))
@@ -76,7 +76,7 @@ def torch_gc(force=False):
if shared.opts.disable_gc and not force:
return
collected = gc.collect()
if cuda_ok or backend == 'ipex':
if cuda_ok:
try:
with torch.cuda.device(get_cuda_device_string()):
torch.cuda.empty_cache()
@@ -182,7 +182,7 @@ elif sys.platform == 'darwin':
else:
backend = 'cpu'
cuda_ok = torch.cuda.is_available() and not backend == 'ipex'
cuda_ok = torch.cuda.is_available()
cpu = torch.device("cpu")
device = device_interrogate = device_gfpgan = device_esrgan = device_codeformer = None
dtype = torch.float16
@@ -221,8 +221,6 @@ def autocast(disable=False):
return contextlib.nullcontext()
if shared.cmd_opts.use_directml:
return torch.dml.amp.autocast(dtype)
if backend == 'ipex':
return torch.xpu.amp.autocast(enabled=True, dtype=dtype)
if cuda_ok:
return torch.autocast("cuda")
else:
@@ -234,8 +232,6 @@ def without_autocast(disable=False):
return contextlib.nullcontext()
if shared.cmd_opts.use_directml:
return torch.dml.amp.autocast(enabled=False) if torch.is_autocast_enabled() else contextlib.nullcontext() # pylint: disable=unexpected-keyword-arg
if backend == 'ipex':
return torch.xpu.amp.autocast(enabled=False) if torch.is_autocast_enabled() else contextlib.nullcontext()
if cuda_ok:
return torch.autocast("cuda", enabled=False) if torch.is_autocast_enabled() else contextlib.nullcontext()
else:
+1 -2
View File
@@ -7,7 +7,6 @@ import modules.dml.amp as amp
from .utils import rDevice, get_device
from .device import device
from .device_properties import DeviceProperties
from .memory import MemoryProvider
def amd_mem_get_info(device: Optional[rDevice]=None) -> tuple[int, int]:
from .memory_amd import AMDMemoryProvider
@@ -29,7 +28,7 @@ class DirectML:
is_autocast_enabled = False
autocast_gpu_dtype = torch.float16
memory_provider: Optional[MemoryProvider] = None
memory_provider = None
def is_available() -> bool:
return torch_directml.is_available()
+1 -1
View File
@@ -36,7 +36,7 @@ def print_error_explanation(message):
def display(e: Exception, task, suppress=[]): # noqa: B006
log.error(f"{task or 'error'}: {type(e).__name__}")
console.print_exception(show_locals=False, max_frames=5, extra_lines=1, suppress=suppress, theme="ansi_dark", word_wrap=False, width=min([console.width, 200]))
console.print_exception(show_locals=False, max_frames=10, extra_lines=1, suppress=suppress, theme="ansi_dark", word_wrap=False, width=min([console.width, 200]))
def display_once(e: Exception, task):
+4 -2
View File
@@ -74,13 +74,13 @@ def process_batch(p, input_files, input_dir, output_dir, inpaint_mask_dir, args)
shared.log.debug(f'Processed: {len(image_files)} 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, latent_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, diffusers_guidance_rescale: float, refiner_start: float, clip_skip: int, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, selected_scale_tab: int, height: int, width: int, scale_by: float, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_files: list, img2img_batch_input_dir: str, img2img_batch_output_dir: str, img2img_batch_inpaint_mask_dir: str, override_settings_texts, *args): # pylint: disable=unused-argument
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, latent_index: int, mask_blur: int, mask_alpha: float, inpainting_fill: int, full_quality: bool, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, refiner_start: float, clip_skip: int, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, selected_scale_tab: int, height: int, width: int, scale_by: float, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_files: list, img2img_batch_input_dir: str, img2img_batch_output_dir: str, img2img_batch_inpaint_mask_dir: str, override_settings_texts, *args): # pylint: disable=unused-argument
if shared.sd_model is None:
shared.log.warning('Model not loaded')
return [], '', '', 'Error: model not loaded'
shared.log.debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_files={img2img_batch_files}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}|args={args}')
shared.log.debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_files={img2img_batch_files}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}|args={args}')
if init_img is None:
shared.log.debug('Init image not set')
@@ -158,6 +158,7 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
clip_skip=clip_skip,
width=width,
height=height,
full_quality=full_quality,
restore_faces=restore_faces,
tiling=tiling,
init_images=[image],
@@ -176,6 +177,7 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
)
p.scripts = modules.scripts.scripts_img2img
p.script_args = args
p.extra_generation_params['Resize mode'] = resize_mode
if mask:
p.extra_generation_params["Mask blur"] = mask_blur
if is_batch:
+84 -5
View File
@@ -38,8 +38,73 @@ def ipex_init():
torch.cuda.FloatTensor = torch.xpu.FloatTensor
torch.Tensor.cuda = torch.Tensor.xpu
torch.Tensor.is_cuda = torch.Tensor.is_xpu
torch.cuda._initialization_lock = torch.xpu.lazy_init._initialization_lock
torch.cuda._initialized = torch.xpu.lazy_init._initialized
torch.cuda._lazy_seed_tracker = torch.xpu.lazy_init._lazy_seed_tracker
torch.cuda._queued_calls = torch.xpu.lazy_init._queued_calls
torch.cuda._tls = torch.xpu.lazy_init._tls
torch.cuda.threading = torch.xpu.lazy_init.threading
torch.cuda.traceback = torch.xpu.lazy_init.traceback
torch.cuda.Optional = torch.xpu.Optional
torch.cuda.__cached__ = torch.xpu.__cached__
torch.cuda.__loader__ = torch.xpu.__loader__
torch.cuda.ComplexFloatStorage = torch.xpu.ComplexFloatStorage
torch.cuda.Tuple = torch.xpu.Tuple
torch.cuda.streams = torch.xpu.streams
torch.cuda._lazy_new = torch.xpu._lazy_new
torch.cuda.FloatStorage = torch.xpu.FloatStorage
torch.cuda.Any = torch.xpu.Any
torch.cuda.__doc__ = torch.xpu.__doc__
torch.cuda.default_generators = torch.xpu.default_generators
torch.cuda.HalfTensor = torch.xpu.HalfTensor
torch.cuda._get_device_index = torch.xpu._get_device_index
torch.cuda.__path__ = torch.xpu.__path__
torch.cuda.Device = torch.xpu.Device
torch.cuda.IntTensor = torch.xpu.IntTensor
torch.cuda.ByteStorage = torch.xpu.ByteStorage
torch.cuda.set_stream = torch.xpu.set_stream
torch.cuda.BoolStorage = torch.xpu.BoolStorage
torch.cuda.get_device_capability = torch.xpu.get_device_capability
torch.cuda.os = torch.xpu.os
torch.cuda.torch = torch.xpu.torch
torch.cuda.BFloat16Storage = torch.xpu.BFloat16Storage
torch.cuda.Union = torch.xpu.Union
torch.cuda.DoubleTensor = torch.xpu.DoubleTensor
torch.cuda.ShortTensor = torch.xpu.ShortTensor
torch.cuda.LongTensor = torch.xpu.LongTensor
torch.cuda.IntStorage = torch.xpu.IntStorage
torch.cuda.LongStorage = torch.xpu.LongStorage
torch.cuda.__annotations__ = torch.xpu.__annotations__
torch.cuda.__package__ = torch.xpu.__package__
torch.cuda.__builtins__ = torch.xpu.__builtins__
torch.cuda.CharTensor = torch.xpu.CharTensor
torch.cuda.List = torch.xpu.List
torch.cuda._lazy_init = torch.xpu._lazy_init
torch.cuda.BFloat16Tensor = torch.xpu.BFloat16Tensor
torch.cuda.DoubleStorage = torch.xpu.DoubleStorage
torch.cuda.ByteTensor = torch.xpu.ByteTensor
torch.cuda.StreamContext = torch.xpu.StreamContext
torch.cuda.ComplexDoubleStorage = torch.xpu.ComplexDoubleStorage
torch.cuda.ShortStorage = torch.xpu.ShortStorage
torch.cuda._lazy_call = torch.xpu._lazy_call
torch.cuda.HalfStorage = torch.xpu.HalfStorage
torch.cuda.random = torch.xpu.random
torch.cuda._device = torch.xpu._device
torch.cuda.classproperty = torch.xpu.classproperty
torch.cuda.__name__ = torch.xpu.__name__
torch.cuda._device_t = torch.xpu._device_t
torch.cuda.warnings = torch.xpu.warnings
torch.cuda.__spec__ = torch.xpu.__spec__
torch.cuda.BoolTensor = torch.xpu.BoolTensor
torch.cuda.CharStorage = torch.xpu.CharStorage
torch.cuda.__file__ = torch.xpu.__file__
torch.cuda._is_in_bad_fork = torch.xpu.lazy_init._is_in_bad_fork
#torch.cuda.is_current_stream_capturing = torch.xpu.is_current_stream_capturing
#Memory:
torch.cuda.memory = torch.xpu.memory
if 'linux' in sys.platform and "WSL2" in os.popen("uname -a").read():
torch.xpu.empty_cache = lambda: None
torch.cuda.empty_cache = torch.xpu.empty_cache
torch.cuda.memory_stats = torch.xpu.memory_stats
torch.cuda.memory_summary = torch.xpu.memory_summary
@@ -47,8 +112,12 @@ def ipex_init():
torch.cuda.memory_allocated = torch.xpu.memory_allocated
torch.cuda.max_memory_allocated = torch.xpu.max_memory_allocated
torch.cuda.memory_reserved = torch.xpu.memory_reserved
torch.cuda.memory_cached = torch.xpu.memory_reserved
torch.cuda.max_memory_reserved = torch.xpu.max_memory_reserved
torch.cuda.max_memory_cached = torch.xpu.max_memory_reserved
torch.cuda.reset_peak_memory_stats = torch.xpu.reset_peak_memory_stats
torch.cuda.reset_max_memory_cached = torch.xpu.reset_peak_memory_stats
torch.cuda.reset_max_memory_allocated = torch.xpu.reset_peak_memory_stats
torch.cuda.memory_stats_as_nested_dict = torch.xpu.memory_stats_as_nested_dict
torch.cuda.reset_accumulated_memory_stats = torch.xpu.reset_accumulated_memory_stats
@@ -63,7 +132,11 @@ def ipex_init():
torch.cuda.seed_all = torch.xpu.seed_all
torch.cuda.initial_seed = torch.xpu.initial_seed
#Training:
#AMP:
torch.cuda.amp = torch.xpu.amp
if not hasattr(torch.cuda.amp, "common"):
torch.cuda.amp.common = contextlib.nullcontext()
torch.cuda.amp.common.amp_definitely_not_available = lambda: False
try:
torch.cuda.amp.GradScaler = torch.xpu.amp.GradScaler
except Exception:
@@ -77,10 +150,12 @@ def ipex_init():
#Fix functions with ipex:
torch.cuda.mem_get_info = lambda device=None: [(torch.xpu.get_device_properties(device).total_memory - torch.xpu.memory_allocated(device)), torch.xpu.get_device_properties(device).total_memory]
torch._utils._get_available_device_type = lambda: "xpu" # pylint: disable=protected-access
if 'linux' in sys.platform:
torch.xpu.empty_cache = torch.xpu.empty_cache if "WSL2" not in os.popen("uname -a").read() else lambda: None
torch.cuda.get_device_properties.major = 2023
torch.cuda.get_device_properties.minor = 2
torch.has_cuda = True
torch.cuda.has_half = True
torch.cuda.is_bf16_supported = True
#torch.version.cuda = "11.7" #Breaks System Info
torch.cuda.get_device_properties.major = 11
torch.cuda.get_device_properties.minor = 7
torch.backends.cuda.sdp_kernel = return_null_context
torch.nn.DataParallel = DummyDataParallel
torch.cuda.ipc_collect = lambda: None
@@ -88,3 +163,7 @@ def ipex_init():
ipex_hijacks()
ipex_diffusers()
try:
from .openvino import openvino_fx
except Exception:
pass
+70 -26
View File
@@ -1,6 +1,6 @@
import torch
import intel_extension_for_pytorch as ipex
from modules import shared
from modules import devices
from modules.sd_hijack_utils import CondFunc
def ipex_no_cuda(orig_func, *args, **kwargs): # pylint: disable=redefined-outer-name
@@ -8,22 +8,74 @@ def ipex_no_cuda(orig_func, *args, **kwargs): # pylint: disable=redefined-outer-
orig_func(*args, **kwargs)
torch.cuda.is_available = torch.xpu.is_available
#Autocast
original_autocast = torch.autocast
def ipex_autocast(*args, **kwargs):
if args[0] == "cuda":
if "dtype" in kwargs:
return original_autocast("xpu", *args[1:], **kwargs)
else:
return original_autocast("xpu", *args[1:], dtype=devices.dtype, **kwargs)
else:
return original_autocast(*args, **kwargs)
#Diffusers BF16:
original_linear_forward = torch.nn.modules.Linear.forward
def linear_forward(self, input):
if input.dtype != self.weight.data.dtype:
return original_linear_forward(self, input.to(self.weight.data.dtype))
else:
return original_linear_forward(self, input)
#Embedding BF16
original_torch_cat = torch.cat
def torch_cat(input, *args, **kwargs):
if len(input) == 3 and (input[0].dtype != input[1].dtype or input[2].dtype != input[1].dtype):
return original_torch_cat([input[0].to(input[1].dtype), input[1], input[2].to(input[1].dtype)], *args, **kwargs)
else:
return original_torch_cat(input, *args, **kwargs)
original_conv2d = torch.nn.functional.conv2d
#Diffusers BF16:
def conv2d(input, weight, *args, **kwargs):
if input.dtype != weight.data.dtype:
return original_conv2d(input.to(weight.data.dtype), weight, *args, **kwargs)
else:
return original_conv2d(input, weight, *args, **kwargs)
original_interpolate = torch.nn.functional.interpolate
#Latent antialias:
def interpolate(input, size=None, scale_factor=None, mode='nearest', align_corners=None, recompute_scale_factor=None, antialias=False):
if antialias:
return original_interpolate(input.to("cpu"), size=size, scale_factor=scale_factor, mode=mode,
align_corners=align_corners, recompute_scale_factor=recompute_scale_factor, antialias=antialias).to(devices.device)
else:
return original_interpolate(input, size=size, scale_factor=scale_factor, mode=mode,
align_corners=align_corners, recompute_scale_factor=recompute_scale_factor, antialias=antialias)
def ipex_hijacks():
#Libraries that blindly uses cuda:
#Adetailer:
CondFunc('torch.Tensor.to',
lambda orig_func, self, device=None, *args, **kwargs: orig_func(self, shared.device, *args, **kwargs),
lambda orig_func, self, device=None, *args, **kwargs: orig_func(self, devices.device, *args, **kwargs),
lambda orig_func, self, device=None, *args, **kwargs: (type(device) is torch.device and device.type == "cuda") or (type(device) is str and "cuda" in device))
CondFunc('torch.empty',
lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=shared.device, **kwargs),
lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=devices.device, **kwargs),
lambda orig_func, *args, device=None, **kwargs: (type(device) is torch.device and device.type == "cuda") or (type(device) is str and "cuda" in device))
#ControlNet depth_leres
CondFunc('torch.load',
lambda orig_func, *args, map_location=None, **kwargs: orig_func(*args, shared.device, **kwargs),
lambda orig_func, *args, map_location=None, **kwargs: orig_func(*args, devices.device, **kwargs),
lambda orig_func, *args, map_location=None, **kwargs: (map_location is None) or (type(map_location) is torch.device and map_location.type == "cuda") or (type(map_location) is str and "cuda" in map_location))
#Diffusers Model CPU Offload:
CondFunc('torch.randn',
lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=shared.device, **kwargs),
lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=devices.device, **kwargs),
lambda orig_func, *args, device=None, **kwargs: (type(device) is torch.device and device.type == "cuda") or (type(device) is str and "cuda" in device))
#Other:
CondFunc('torch.ones',
lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=devices.device, **kwargs),
lambda orig_func, *args, device=None, **kwargs: (type(device) is torch.device and device.type == "cuda") or (type(device) is str and "cuda" in device))
CondFunc('torch.zeros',
lambda orig_func, *args, device=None, **kwargs: orig_func(*args, device=devices.device, **kwargs),
lambda orig_func, *args, device=None, **kwargs: (type(device) is torch.device and device.type == "cuda") or (type(device) is str and "cuda" in device))
#Broken functions when torch.cuda.is_available is True:
@@ -33,13 +85,10 @@ def ipex_hijacks():
lambda orig_func, *args, **kwargs: True)
#Functions with dtype errors:
#Original backend:
CondFunc('torch.nn.modules.GroupNorm.forward',
lambda orig_func, self, input: orig_func(self, input.to(self.weight.data.dtype)),
lambda orig_func, self, input: input.dtype != self.weight.data.dtype)
#FP32:
CondFunc('torch.nn.modules.Linear.forward',
lambda orig_func, self, input: orig_func(self, input.to(self.weight.data.dtype)),
lambda orig_func, self, input: input.dtype != self.weight.data.dtype)
#Embedding FP32:
CondFunc('torch.bmm',
lambda orig_func, input, mat2, *args, **kwargs: orig_func(input, mat2.to(input.dtype), *args, **kwargs),
@@ -50,28 +99,16 @@ def ipex_hijacks():
orig_func(input.to(weight.data.dtype), normalized_shape, weight, *args, **kwargs),
lambda orig_func, input, normalized_shape=None, weight=None, *args, **kwargs:
input.dtype != weight.data.dtype and weight is not None)
#Embedding BF16
CondFunc('torch.cat',
lambda orig_func, input, *args, **kwargs: orig_func([input[0].to(input[1].dtype), input[1], input[2].to(input[1].dtype)], *args, **kwargs),
lambda orig_func, input, *args, **kwargs: len(input) == 3 and (input[0].dtype != input[1].dtype or input[2].dtype != input[1].dtype))
#Diffusers BF16:
CondFunc('torch.nn.functional.conv2d',
lambda orig_func, input, weight, *args, **kwargs: orig_func(input.to(weight.data.dtype), weight, *args, **kwargs),
lambda orig_func, input, weight, *args, **kwargs: input.dtype != weight.data.dtype)
#Functions that does not work with the XPU:
#UniPC:
CondFunc('torch.linalg.solve',
lambda orig_func, A, B, *args, **kwargs: orig_func(A.to("cpu"), B.to("cpu"), *args, **kwargs).to(shared.device),
lambda orig_func, A, B, *args, **kwargs: orig_func(A.to("cpu"), B.to("cpu"), *args, **kwargs).to(devices.device),
lambda orig_func, A, B, *args, **kwargs: A.device != torch.device("cpu") or B.device != torch.device("cpu"))
#SDE Samplers:
CondFunc('torch.Generator',
lambda orig_func, device: torch.xpu.Generator(device),
lambda orig_func, device: device != torch.device("cpu") and device != "cpu")
#Latent antialias:
CondFunc('torch.nn.functional.interpolate',
lambda orig_func, input, *args, **kwargs: orig_func(input.to("cpu"), *args, **kwargs).to(shared.device),
lambda orig_func, input, size=None, scale_factor=None, mode='nearest', align_corners=None, recompute_scale_factor=None, antialias=False: antialias)
#Diffusers Float64 (ARC GPUs doesn't support double or Float64):
if not torch.xpu.has_fp64_dtype():
CondFunc('torch.from_numpy',
@@ -80,12 +117,19 @@ def ipex_hijacks():
#ControlNet and TiledVAE:
CondFunc('torch.batch_norm',
lambda orig_func, input, weight, bias, *args, **kwargs: orig_func(input,
weight if weight is not None else torch.ones(input.size()[1], device=shared.device),
bias if bias is not None else torch.zeros(input.size()[1], device=shared.device), *args, **kwargs),
weight if weight is not None else torch.ones(input.size()[1], device=devices.device),
bias if bias is not None else torch.zeros(input.size()[1], device=devices.device), *args, **kwargs),
lambda orig_func, input, *args, **kwargs: input.device != torch.device("cpu"))
#ControlNet
CondFunc('torch.instance_norm',
lambda orig_func, input, weight, bias, *args, **kwargs: orig_func(input,
weight if weight is not None else torch.ones(input.size()[1], device=shared.device),
bias if bias is not None else torch.zeros(input.size()[1], device=shared.device), *args, **kwargs),
weight if weight is not None else torch.ones(input.size()[1], device=devices.device),
bias if bias is not None else torch.zeros(input.size()[1], device=devices.device), *args, **kwargs),
lambda orig_func, input, *args, **kwargs: input.device != torch.device("cpu"))
#Functions that make compile mad with CondFunc:
torch.autocast = ipex_autocast
torch.nn.modules.Linear.forward = linear_forward
torch.cat = torch_cat
torch.nn.functional.conv2d = conv2d
torch.nn.functional.interpolate = interpolate
+25
View File
@@ -0,0 +1,25 @@
import os
import torch
import intel_extension_for_pytorch as ipex
from openvino.frontend.pytorch.torchdynamo.execute import execute
from openvino.frontend.pytorch.torchdynamo.partition import Partitioner
from torch._dynamo.backends.common import fake_tensor_unsupported
from torch._dynamo.backends.registry import register_backend
from torch.fx.experimental.proxy_tensor import make_fx
@register_backend
@fake_tensor_unsupported
def openvino_fx(subgraph, example_inputs):
if os.getenv("OPENVINO_TORCH_BACKEND_DEVICE") is None:
os.environ.setdefault("OPENVINO_TORCH_BACKEND_DEVICE", "GPU")
model = make_fx(subgraph)(*example_inputs)
with torch.no_grad():
model.eval()
partitioner = Partitioner()
compiled_model = partitioner.make_partitions(model)
def _call(*args):
res = execute(compiled_model, *args, executor="openvino")
return res
return _call
+502 -15
View File
@@ -1,35 +1,522 @@
import diffusers
from modules import shared
import diffusers.models.lora as diffusers_lora
# from modules import shared
import modules.shared as shared
lora_state = { # TODO Lora state for Diffusers
'multiplier': 1.0,
'multiplier': [],
'active': False,
'loaded': 0,
'all_loras': []
}
def unload_diffusers_lora():
try:
pipe = shared.sd_model
pipe.unload_lora_weights()
if shared.opts.diffusers_lora_loader == "diffusers default":
pipe.unload_lora_weights()
pipe._remove_text_encoder_monkey_patch() # pylint: disable=W0212
proc_cls_name = next(iter(pipe.unet.attn_processors.values())).__class__.__name__
non_lora_proc_cls = getattr(diffusers.models.attention_processor, proc_cls_name)#[len("LORA"):])
pipe.unet.set_attn_processor(non_lora_proc_cls())
# shared.log.debug('Diffusers LoRA unloaded')
else:
lora_state['all_loras'].reverse()
lora_state['multiplier'].reverse()
for i, lora_network in enumerate(lora_state['all_loras']):
if shared.opts.diffusers_lora_loader == "merge and apply":
lora_network.restore_from(multiplier=lora_state['multiplier'][i])
if shared.opts.diffusers_lora_loader == "sequential apply":
lora_network.unapply_to()
lora_state['active'] = False
lora_state['loaded'] = 0
pipe._remove_text_encoder_monkey_patch() # pylint: disable=W0212
proc_cls_name = next(iter(pipe.unet.attn_processors.values())).__class__.__name__
non_lora_proc_cls = getattr(diffusers.models.attention_processor, proc_cls_name[len("LORA"):])
pipe.unet.set_attn_processor(non_lora_proc_cls())
# shared.log.debug('Diffusers LoRA unloaded')
except Exception:
pass
lora_state['all_loras'] = []
lora_state['multiplier'] = []
except Exception as e:
shared.log.error(f"Diffusers LoRA unloading failed: {e}")
def load_diffusers_lora(name, lora, strength = 1.0):
try:
pipe = shared.sd_model
pipe.load_lora_weights(lora.filename, cache_dir=shared.opts.diffusers_dir, local_files_only=True, lora_scale=strength)
lora_state['active'] = True
lora_state['loaded'] += 1
lora_state['multiplier'] = strength
# pipe.unet.load_attn_procs("pcuenq/pokemon-lora")
shared.log.info(f"Diffusers LoRA loaded: {name} {lora_state['multiplier']}")
lora_state['multiplier'].append(strength)
if shared.opts.diffusers_lora_loader == "diffusers default":
pipe.load_lora_weights(lora.filename, cache_dir=shared.opts.diffusers_dir, local_files_only=True, lora_scale=strength)
shared.log.info(f"LoRA loaded: {name} {lora_state['multiplier']}")
else:
from safetensors.torch import load_file
lora_sd = load_file(lora.filename)
if "XL" in pipe.__class__.__name__:
text_encoders = [pipe.text_encoder, pipe.text_encoder_2]
else:
text_encoders = pipe.text_encoder
lora_network: LoRANetwork = create_network_from_weights(text_encoders, pipe.unet, lora_sd, multiplier=strength)
lora_network.load_state_dict(lora_sd)
if shared.opts.diffusers_lora_loader == "merge and apply":
lora_network.merge_to(multiplier=strength)
if shared.opts.diffusers_lora_loader == "sequential apply":
lora_network.to(shared.device, dtype=pipe.unet.dtype)
lora_network.apply_to(multiplier=strength)
lora_state['all_loras'].append(lora_network)
shared.log.info(f"LoRA loaded: {name}:{strength} loader={shared.opts.diffusers_lora_loader}")
except Exception as e:
shared.log.error(f"Diffusers LoRA loading failed: {name} {e}")
# Diffusersで動くLoRA。このファイル単独で完結する。
# LoRA module for Diffusers. This file works independently.
import bisect
import math
from typing import Any, Dict, List, Mapping, Optional, Union
from diffusers import UNet2DConditionModel
from tqdm import tqdm
from transformers import CLIPTextModel
import torch
def make_unet_conversion_map() -> Dict[str, str]:
unet_conversion_map_layer = []
for i in range(3): # num_blocks is 3 in sdxl
# loop over downblocks/upblocks
for j in range(2):
# loop over resnets/attentions for downblocks
hf_down_res_prefix = f"down_blocks.{i}.resnets.{j}."
sd_down_res_prefix = f"input_blocks.{3*i + j + 1}.0."
unet_conversion_map_layer.append((sd_down_res_prefix, hf_down_res_prefix))
if i < 3:
# no attention layers in down_blocks.3
hf_down_atn_prefix = f"down_blocks.{i}.attentions.{j}."
sd_down_atn_prefix = f"input_blocks.{3*i + j + 1}.1."
unet_conversion_map_layer.append((sd_down_atn_prefix, hf_down_atn_prefix))
for j in range(3):
# loop over resnets/attentions for upblocks
hf_up_res_prefix = f"up_blocks.{i}.resnets.{j}."
sd_up_res_prefix = f"output_blocks.{3*i + j}.0."
unet_conversion_map_layer.append((sd_up_res_prefix, hf_up_res_prefix))
# if i > 0: commentout for sdxl
# no attention layers in up_blocks.0
hf_up_atn_prefix = f"up_blocks.{i}.attentions.{j}."
sd_up_atn_prefix = f"output_blocks.{3*i + j}.1."
unet_conversion_map_layer.append((sd_up_atn_prefix, hf_up_atn_prefix))
if i < 3:
# no downsample in down_blocks.3
hf_downsample_prefix = f"down_blocks.{i}.downsamplers.0.conv."
sd_downsample_prefix = f"input_blocks.{3*(i+1)}.0.op."
unet_conversion_map_layer.append((sd_downsample_prefix, hf_downsample_prefix))
# no upsample in up_blocks.3
hf_upsample_prefix = f"up_blocks.{i}.upsamplers.0."
sd_upsample_prefix = f"output_blocks.{3*i + 2}.{2}." # change for sdxl
unet_conversion_map_layer.append((sd_upsample_prefix, hf_upsample_prefix))
hf_mid_atn_prefix = "mid_block.attentions.0."
sd_mid_atn_prefix = "middle_block.1."
unet_conversion_map_layer.append((sd_mid_atn_prefix, hf_mid_atn_prefix))
for j in range(2):
hf_mid_res_prefix = f"mid_block.resnets.{j}."
sd_mid_res_prefix = f"middle_block.{2*j}."
unet_conversion_map_layer.append((sd_mid_res_prefix, hf_mid_res_prefix))
unet_conversion_map_resnet = [
# (stable-diffusion, HF Diffusers)
("in_layers.0.", "norm1."),
("in_layers.2.", "conv1."),
("out_layers.0.", "norm2."),
("out_layers.3.", "conv2."),
("emb_layers.1.", "time_emb_proj."),
("skip_connection.", "conv_shortcut."),
]
unet_conversion_map = []
for sd, hf in unet_conversion_map_layer:
if "resnets" in hf:
for sd_res, hf_res in unet_conversion_map_resnet:
unet_conversion_map.append((sd + sd_res, hf + hf_res))
else:
unet_conversion_map.append((sd, hf))
for j in range(2):
hf_time_embed_prefix = f"time_embedding.linear_{j+1}."
sd_time_embed_prefix = f"time_embed.{j*2}."
unet_conversion_map.append((sd_time_embed_prefix, hf_time_embed_prefix))
for j in range(2):
hf_label_embed_prefix = f"add_embedding.linear_{j+1}."
sd_label_embed_prefix = f"label_emb.0.{j*2}."
unet_conversion_map.append((sd_label_embed_prefix, hf_label_embed_prefix))
unet_conversion_map.append(("input_blocks.0.0.", "conv_in."))
unet_conversion_map.append(("out.0.", "conv_norm_out."))
unet_conversion_map.append(("out.2.", "conv_out."))
sd_hf_conversion_map = {sd.replace(".", "_")[:-1]: hf.replace(".", "_")[:-1] for sd, hf in unet_conversion_map}
return sd_hf_conversion_map
UNET_CONVERSION_MAP = make_unet_conversion_map()
class LoRAModule(torch.nn.Module):
"""
replaces forward method of the original Linear, instead of replacing the original Linear module.
"""
def __init__(
self,
lora_name,
org_module: torch.nn.Module,
multiplier=1.0,
lora_dim=4,
alpha=1,
):
"""if alpha == 0 or None, alpha is rank (no scaling)."""
super().__init__()
self.lora_name = lora_name
if isinstance(org_module, diffusers_lora.LoRACompatibleConv): #Modified to support Diffusers>=0.19.2
in_dim = org_module.in_channels
out_dim = org_module.out_channels
else:
in_dim = org_module.in_features
out_dim = org_module.out_features
self.lora_dim = lora_dim
if isinstance(org_module, diffusers_lora.LoRACompatibleConv): #Modified to support Diffusers>=0.19.2
kernel_size = org_module.kernel_size
stride = org_module.stride
padding = org_module.padding
self.lora_down = torch.nn.Conv2d(in_dim, self.lora_dim, kernel_size, stride, padding, bias=False)
self.lora_up = torch.nn.Conv2d(self.lora_dim, out_dim, (1, 1), (1, 1), bias=False)
else:
self.lora_down = torch.nn.Linear(in_dim, self.lora_dim, bias=False)
self.lora_up = torch.nn.Linear(self.lora_dim, out_dim, bias=False)
if isinstance(alpha, torch.Tensor):
alpha = alpha.detach().float().numpy() # without casting, bf16 causes error
alpha = self.lora_dim if alpha is None or alpha == 0 else alpha
self.scale = alpha / self.lora_dim
self.register_buffer("alpha", torch.tensor(alpha)) # 勾配計算に含めない / not included in gradient calculation
# same as microsoft's
torch.nn.init.kaiming_uniform_(self.lora_down.weight, a=math.sqrt(5))
torch.nn.init.zeros_(self.lora_up.weight)
self.multiplier = multiplier
self.org_module = [org_module]
self.enabled = True
self.network: LoRANetwork = None
self.org_forward = None
# override org_module's forward method
def apply_to(self, multiplier=None):
if multiplier is not None:
self.multiplier = multiplier
if self.org_forward is None:
self.org_forward = self.org_module[0].forward
self.org_module[0].forward = self.forward
# restore org_module's forward method
def unapply_to(self):
if self.org_forward is not None:
self.org_module[0].forward = self.org_forward
# forward with lora
def forward(self, x):
if not self.enabled:
return self.org_forward(x)
return self.org_forward(x) + self.lora_up(self.lora_down(x)) * self.multiplier * self.scale
def set_network(self, network):
self.network = network
# merge lora weight to org weight
def merge_to(self, multiplier=1.0):
# get lora weight
lora_weight = self.get_weight(multiplier)
# get org weight
org_sd = self.org_module[0].state_dict()
org_weight = org_sd["weight"]
weight = org_weight + lora_weight.to(org_weight.device, dtype=org_weight.dtype)
# set weight to org_module
org_sd["weight"] = weight
self.org_module[0].load_state_dict(org_sd)
# restore org weight from lora weight
def restore_from(self, multiplier=1.0):
# get lora weight
lora_weight = self.get_weight(multiplier)
# get org weight
org_sd = self.org_module[0].state_dict()
org_weight = org_sd["weight"]
weight = org_weight - lora_weight.to(org_weight.device, dtype=org_weight.dtype)
# set weight to org_module
org_sd["weight"] = weight
self.org_module[0].load_state_dict(org_sd)
# return lora weight
def get_weight(self, multiplier=None):
if multiplier is None:
multiplier = self.multiplier
# get up/down weight from module
up_weight = self.lora_up.weight.to(torch.float)
down_weight = self.lora_down.weight.to(torch.float)
# pre-calculated weight
if len(down_weight.size()) == 2:
# linear
weight = self.multiplier * (up_weight @ down_weight) * self.scale
elif down_weight.size()[2:4] == (1, 1):
# conv2d 1x1
weight = (
self.multiplier
* (up_weight.squeeze(3).squeeze(2) @ down_weight.squeeze(3).squeeze(2)).unsqueeze(2).unsqueeze(3)
* self.scale
)
else:
# conv2d 3x3
conved = torch.nn.functional.conv2d(down_weight.permute(1, 0, 2, 3), up_weight).permute(1, 0, 2, 3)
weight = self.multiplier * conved * self.scale
return weight
# Create network from weights for inference, weights are not loaded here
def create_network_from_weights(
text_encoder: Union[CLIPTextModel, List[CLIPTextModel]], unet: UNet2DConditionModel, weights_sd: Dict, multiplier: float = 1.0
):
# get dim/alpha mapping
modules_dim = {}
modules_alpha = {}
for key, value in weights_sd.items():
if "." not in key:
continue
lora_name = key.split(".")[0]
if "alpha" in key:
modules_alpha[lora_name] = value
elif "lora_down" in key:
dim = value.size()[0]
modules_dim[lora_name] = dim
# print(lora_name, value.size(), dim)
# support old LoRA without alpha
for key in modules_dim.keys():
if key not in modules_alpha:
modules_alpha[key] = modules_dim[key]
return LoRANetwork(text_encoder, unet, multiplier=multiplier, modules_dim=modules_dim, modules_alpha=modules_alpha)
def merge_lora_weights(pipe, weights_sd: Dict, multiplier: float = 1.0):
text_encoders = [pipe.text_encoder, pipe.text_encoder_2] if hasattr(pipe, "text_encoder_2") else [pipe.text_encoder]
unet = pipe.unet
lora_network = create_network_from_weights(text_encoders, unet, weights_sd, multiplier=multiplier)
lora_network.load_state_dict(weights_sd)
lora_network.merge_to(multiplier=multiplier)
# block weightや学習に対応しない簡易版 / simple version without block weight and training
class LoRANetwork(torch.nn.Module): # pylint: disable=abstract-method
UNET_TARGET_REPLACE_MODULE = ["Transformer2DModel"]
UNET_TARGET_REPLACE_MODULE_CONV2D_3X3 = ["ResnetBlock2D", "Downsample2D", "Upsample2D"]
TEXT_ENCODER_TARGET_REPLACE_MODULE = ["CLIPAttention", "CLIPMLP"]
LORA_PREFIX_UNET = "lora_unet"
LORA_PREFIX_TEXT_ENCODER = "lora_te"
# SDXL: must starts with LORA_PREFIX_TEXT_ENCODER
LORA_PREFIX_TEXT_ENCODER1 = "lora_te1"
LORA_PREFIX_TEXT_ENCODER2 = "lora_te2"
def __init__(
self,
text_encoder: Union[List[CLIPTextModel], CLIPTextModel],
unet: UNet2DConditionModel,
multiplier: float = 1.0,
modules_dim: Optional[Dict[str, int]] = None,
modules_alpha: Optional[Dict[str, int]] = None,
varbose: Optional[bool] = False, # pylint: disable=unused-argument
) -> None:
super().__init__()
self.multiplier = multiplier
# shared.log.debug("create LoRA network from weights")
# convert SDXL Stability AI's U-Net modules to Diffusers
converted = self.convert_unet_modules(modules_dim, modules_alpha)
if converted:
shared.log.debug(f"LoRA convert: modules={converted} SDXL SAI/SGM to Diffusers")
# create module instances
def create_modules(
is_unet: bool,
text_encoder_idx: Optional[int], # None, 1, 2
root_module: torch.nn.Module,
target_replace_modules: List[torch.nn.Module],
) -> List[LoRAModule]:
prefix = (
self.LORA_PREFIX_UNET
if is_unet
else (
self.LORA_PREFIX_TEXT_ENCODER
if text_encoder_idx is None
else (self.LORA_PREFIX_TEXT_ENCODER1 if text_encoder_idx == 1 else self.LORA_PREFIX_TEXT_ENCODER2)
)
)
loras = []
skipped = []
for name, module in root_module.named_modules():
if module.__class__.__name__ in target_replace_modules:
for child_name, child_module in module.named_modules():
is_linear = isinstance(child_module, (torch.nn.Linear, diffusers_lora.LoRACompatibleLinear)) #Modified to support Diffusers>=0.19.2
is_conv2d = isinstance(child_module, (torch.nn.Conv2d, diffusers_lora.LoRACompatibleConv)) #Modified to support Diffusers>=0.19.2
if is_linear or is_conv2d:
lora_name = prefix + "." + name + "." + child_name
lora_name = lora_name.replace(".", "_")
if lora_name not in modules_dim:
# print(f"skipped {lora_name} (not found in modules_dim)")
skipped.append(lora_name)
continue
dim = modules_dim[lora_name]
alpha = modules_alpha[lora_name]
lora = LoRAModule(
lora_name,
child_module,
self.multiplier,
dim,
alpha,
)
loras.append(lora)
return loras, skipped
text_encoders = text_encoder if type(text_encoder) == list else [text_encoder]
# create LoRA for text encoder
# 毎回すべてのモジュールを作るのは無駄なので要検討 / it is wasteful to create all modules every time, need to consider
self.text_encoder_loras: List[LoRAModule] = []
skipped_te = []
for i, text_encoder in enumerate(text_encoders):
if len(text_encoders) > 1:
index = i + 1
else:
index = None
text_encoder_loras, skipped = create_modules(False, index, text_encoder, LoRANetwork.TEXT_ENCODER_TARGET_REPLACE_MODULE)
self.text_encoder_loras.extend(text_encoder_loras)
skipped_te += skipped
# extend U-Net target modules to include Conv2d 3x3
target_modules = LoRANetwork.UNET_TARGET_REPLACE_MODULE + LoRANetwork.UNET_TARGET_REPLACE_MODULE_CONV2D_3X3
self.unet_loras: List[LoRAModule]
self.unet_loras, skipped_un = create_modules(True, None, unet, target_modules)
shared.log.debug(f"LoRA modules loaded/skipped: te={len(self.text_encoder_loras)}/{len(skipped_te)} unet={len(self.unet_loras)}/skip={len(skipped_un)}")
# assertion
names = set()
for lora in self.text_encoder_loras + self.unet_loras:
names.add(lora.lora_name)
for lora_name in modules_dim.keys():
assert lora_name in names, f"{lora_name} is not found in created LoRA modules."
# make to work load_state_dict
for lora in self.text_encoder_loras + self.unet_loras:
self.add_module(lora.lora_name, lora)
# SDXL: convert SDXL Stability AI's U-Net modules to Diffusers
def convert_unet_modules(self, modules_dim, modules_alpha):
converted_count = 0
not_converted_count = 0
map_keys = list(UNET_CONVERSION_MAP.keys())
map_keys.sort()
for key in list(modules_dim.keys()):
if key.startswith(LoRANetwork.LORA_PREFIX_UNET + "_"):
search_key = key.replace(LoRANetwork.LORA_PREFIX_UNET + "_", "")
position = bisect.bisect_right(map_keys, search_key)
map_key = map_keys[position - 1]
if search_key.startswith(map_key):
new_key = key.replace(map_key, UNET_CONVERSION_MAP[map_key])
modules_dim[new_key] = modules_dim[key]
modules_alpha[new_key] = modules_alpha[key]
del modules_dim[key]
del modules_alpha[key]
converted_count += 1
else:
not_converted_count += 1
assert (
converted_count == 0 or not_converted_count == 0
), f"some modules are not converted: {converted_count} converted, {not_converted_count} not converted"
return converted_count
def set_multiplier(self, multiplier):
self.multiplier = multiplier
for lora in self.text_encoder_loras + self.unet_loras:
lora.multiplier = self.multiplier
def apply_to(self, multiplier=1.0, apply_text_encoder=True, apply_unet=True):
if apply_text_encoder:
# shared.log.debug("LoRA apply for text encoder")
for lora in self.text_encoder_loras:
lora.apply_to(multiplier)
if apply_unet:
# shared.log.debug("LoRA apply for U-Net")
for lora in self.unet_loras:
lora.apply_to(multiplier)
def unapply_to(self):
for lora in self.text_encoder_loras + self.unet_loras:
lora.unapply_to()
def merge_to(self, multiplier=1.0):
# shared.log.debug("LoRA merge weights for text encoder")
for lora in tqdm(self.text_encoder_loras + self.unet_loras):
lora.merge_to(multiplier)
def restore_from(self, multiplier=1.0):
# shared.log.debug("LoRA restore weights")
for lora in tqdm(self.text_encoder_loras + self.unet_loras):
lora.restore_from(multiplier)
def load_state_dict(self, state_dict: Mapping[str, Any], strict: bool = True):
# convert SDXL Stability AI's state dict to Diffusers' based state dict
map_keys = list(UNET_CONVERSION_MAP.keys()) # prefix of U-Net modules
map_keys.sort()
for key in list(state_dict.keys()):
if key.startswith(LoRANetwork.LORA_PREFIX_UNET + "_"):
search_key = key.replace(LoRANetwork.LORA_PREFIX_UNET + "_", "")
position = bisect.bisect_right(map_keys, search_key)
map_key = map_keys[position - 1]
if search_key.startswith(map_key):
new_key = key.replace(map_key, UNET_CONVERSION_MAP[map_key])
state_dict[new_key] = state_dict[key]
del state_dict[key]
# in case of V2, some weights have different shape, so we need to convert them
# because V2 LoRA is based on U-Net created by use_linear_projection=False
my_state_dict = self.state_dict()
for key in state_dict.keys():
if state_dict[key].size() != my_state_dict[key].size():
# print(f"convert {key} from {state_dict[key].size()} to {my_state_dict[key].size()}")
state_dict[key] = state_dict[key].view(my_state_dict[key].size())
return super().load_state_dict(state_dict, strict)
+45 -1
View File
@@ -3,7 +3,6 @@ import shutil
import importlib
from typing import Dict
from urllib.parse import urlparse
from modules import shared
from modules.upscaler import Upscaler, UpscalerLanczos, UpscalerNearest, UpscalerNone
from modules.paths import script_path, models_path
@@ -11,10 +10,54 @@ from modules.paths import script_path, models_path
diffuser_repos = []
def download_civit_model(model_url: str, model_name: str, model_path: str, preview):
model_file = os.path.join(shared.opts.ckpt_dir, model_path, model_name)
res = f'CivitAI download: name={model_name} url={model_url} path={model_path}'
if os.path.isfile(model_file):
res += ' already exists'
shared.log.warning(res)
return res
import requests
import rich.progress as p
req = requests.get(model_url, stream=True, timeout=30)
total_size = int(req.headers.get('content-length', 0))
block_size = 16384 # 16KB blocks
written = 0
shared.state.begin()
shared.state.job = 'downloload model'
try:
with open(model_file, 'wb') as f:
with p.Progress(p.TextColumn('[cyan]{task.description}'), p.DownloadColumn(), p.BarColumn(), p.TaskProgressColumn(), p.TimeRemainingColumn(), p.TimeElapsedColumn(), p.TransferSpeedColumn()) as progress:
task = progress.add_task(description="Download starting", total=total_size)
# for data in tqdm(req.iter_content(block_size), total=total_size//1024, unit='KB', unit_scale=False):
for data in req.iter_content(block_size):
written = written + len(data)
f.write(data)
progress.update(task, advance=block_size, description="Downloading")
if written < 1024 * 1024 * 1024: # min threshold
os.remove(model_file)
raise ValueError(f'removed invalid download: bytes={written}')
if preview is not None:
preview_file = os.path.splitext(model_file)[0] + '.jpg'
preview.save(preview_file)
res += f' preview={preview_file}'
except Exception as e:
shared.log.error(f'CivitAI download error: name={model_name} url={model_url} path={model_path} {e}')
if total_size == written:
shared.log.info(f'{res} size={total_size}')
else:
shared.log.error(f'{res} size={total_size} written={written}')
shared.state.end()
return res
def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config: Dict[str, str] = None, token = None, variant = None, revision = None, mirror = None):
from diffusers import DiffusionPipeline
import huggingface_hub as hf
shared.state.begin()
shared.state.job = 'downloload model'
if download_config is None:
download_config = {
"force_download": False,
@@ -47,6 +90,7 @@ def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config
with open(os.path.join(download_dir, "hidden"), "w", encoding="utf-8") as f:
f.write("True")
shared.writefile(model_info_dict, os.path.join(pipeline_dir, "model_info.json"))
shared.state.end()
return pipeline_dir
+1
View File
@@ -76,6 +76,7 @@ def run_postprocessing(extras_mode, image, image_folder: List[tempfile.NamedTemp
images.save_image(pp.image, path=outpath, basename=basename, seed=None, prompt=None, extension=ext or opts.samples_format, info=infotext, short_filename=True, no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=pp.image.info, forced_filename=None)
if extras_mode != 2 or show_extras_results:
outputs.append(pp.image)
image.close()
devices.torch_gc()
return outputs, infotext, params
+26 -18
View File
@@ -86,7 +86,7 @@ class StableDiffusionProcessing:
"""
The first set of paramaters: sd_models -> do_not_reload_embeddings represent the minimum required to create a StableDiffusionProcessing
"""
def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, latent_sampler: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, restore_faces: bool = False, tiling: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, ddim_discretize: str = None, s_min_uncond: float = 0.0, s_churn: float = 0.0, s_tmax: float = None, s_tmin: float = 0.0, s_noise: float = 1.0, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument
def __init__(self, sd_model=None, outpath_samples=None, outpath_grids=None, prompt: str = "", styles: List[str] = None, seed: int = -1, subseed: int = -1, subseed_strength: float = 0, seed_resize_from_h: int = -1, seed_resize_from_w: int = -1, seed_enable_extras: bool = True, sampler_name: str = None, latent_sampler: str = None, batch_size: int = 1, n_iter: int = 1, steps: int = 50, cfg_scale: float = 7.0, image_cfg_scale: float = None, clip_skip: int = 1, width: int = 512, height: int = 512, full_quality: bool = True, restore_faces: bool = False, tiling: bool = False, do_not_save_samples: bool = False, do_not_save_grid: bool = False, extra_generation_params: Dict[Any, Any] = None, overlay_images: Any = None, negative_prompt: str = None, eta: float = None, do_not_reload_embeddings: bool = False, denoising_strength: float = 0, diffusers_guidance_rescale: float = 0.7, ddim_discretize: str = None, s_min_uncond: float = 0.0, s_churn: float = 0.0, s_tmax: float = None, s_tmin: float = 0.0, s_noise: float = 1.0, override_settings: Dict[str, Any] = None, override_settings_restore_afterwards: bool = True, sampler_index: int = None, script_args: list = None): # pylint: disable=unused-argument
self.outpath_samples: str = outpath_samples
self.outpath_grids: str = outpath_grids
@@ -110,6 +110,7 @@ class StableDiffusionProcessing:
self.diffusers_guidance_rescale = diffusers_guidance_rescale
self.width: int = width
self.height: int = height
self.full_quality: bool = full_quality
self.restore_faces: bool = restore_faces
self.tiling: bool = tiling
self.do_not_save_samples: bool = do_not_save_samples
@@ -444,12 +445,13 @@ def fix_seed(p):
p.subseed = get_fixed_seed(p.subseed)
def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0, index=None, all_negative_prompts=None): # pylint: disable=unused-argument
def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_subseeds, comments=None, iteration=0, position_in_batch=0, index=None, all_negative_prompts=None):
if index is None:
index = position_in_batch + iteration * p.batch_size
if all_negative_prompts is None:
all_negative_prompts = p.all_negative_prompts
vae = (None if not shared.opts.add_model_name_to_info or sd_vae.loaded_vae_file is None else os.path.splitext(os.path.basename(sd_vae.loaded_vae_file))[0]) if p.full_quality else 'TAESD'
comment = ', '.join(comments) if comments is not None and type(comments) is list else None
generation_params = {
"Steps": p.steps,
@@ -457,14 +459,15 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
"Sampler": p.sampler_name,
"CFG scale": p.cfg_scale,
"Size": f"{p.width}x{p.height}",
"Batch": f'{p.n_iter}x{p.batch_size}' if p.n_iter > 1 or p.batch_size > 1 else None,
"Parser": shared.opts.prompt_attention,
"Model": None if not shared.opts.add_model_name_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', ''),
"Model hash": getattr(p, 'sd_model_hash', None if not shared.opts.add_model_hash_to_info or not shared.sd_model.sd_model_hash else shared.sd_model.sd_model_hash),
"Refiner": None if not shared.opts.add_model_name_to_info or not shared.sd_refiner or not shared.sd_refiner.sd_checkpoint_info.model_name else shared.sd_refiner.sd_checkpoint_info.model_name.replace(',', '').replace(':', ''),
"VAE": None if not shared.opts.add_model_name_to_info or sd_vae.loaded_vae_file is None else os.path.splitext(os.path.basename(sd_vae.loaded_vae_file))[0],
"Model": None if (not shared.opts.add_model_name_to_info) or (not shared.sd_model.sd_checkpoint_info.model_name) else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', ''),
"Model hash": getattr(p, 'sd_model_hash', None if (not shared.opts.add_model_hash_to_info) or (not shared.sd_model.sd_model_hash) else shared.sd_model.sd_model_hash),
"Refiner": None if (not shared.opts.add_model_name_to_info) or (not shared.sd_refiner) or (not shared.sd_refiner.sd_checkpoint_info.model_name) else shared.sd_refiner.sd_checkpoint_info.model_name.replace(',', '').replace(':', ''),
"VAE": vae,
# subseed
"Variation seed": None if p.subseed_strength == 0 else all_subseeds[index],
"Variation seed strength": None if p.subseed_strength == 0 else p.subseed_strength,
"Variation strength": None if p.subseed_strength == 0 else p.subseed_strength,
# seed resize
"Seed resize from": None if p.seed_resize_from_w == 0 or p.seed_resize_from_h == 0 else f"{p.seed_resize_from_w}x{p.seed_resize_from_h}",
"Init image hash": getattr(p, 'init_img_hash', None),
@@ -473,18 +476,19 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
"Clip skip": p.clip_skip if p.clip_skip > 1 else None,
# ensd
"ENSD": shared.opts.eta_noise_seed_delta if shared.opts.eta_noise_seed_delta != 0 and sd_samplers_common.is_sampler_using_eta_noise_seed_delta(p) else None,
# enable_hr
"Latent sampler": p.latent_sampler if p.enable_hr else None,
"Image CFG scale": p.image_cfg_scale if p.enable_hr else None,
"Denoising strength": p.denoising_strength if p.enable_hr else None,
"Refiner start": p.refiner_start if p.enable_hr else None,
"Secondary steps": p.hr_second_pass_steps if p.enable_hr else None,
# restore_faces
# restore_faces, tiling
"Face restoration": shared.opts.face_restoration_model if p.restore_faces else None,
"Tiling": p.tiling if p.tiling else None,
# enable_hr
"Prompt2": p.refiner_prompt if p.enable_hr and len(p.refiner_prompt) > 0 else None,
"Negative2": p.refiner_negative if p.enable_hr and len(p.refiner_negative) > 0 else None,
"Latent sampler": p.latent_sampler if p.enable_hr and p.latent_sampler != p.sampler_name else None,
"Denoising strength": p.denoising_strength if p.enable_hr else None,
# sdnext
"Backend": 'Diffusers' if shared.backend == shared.Backend.DIFFUSERS else 'Original',
"Version": git_commit,
"Pipeline": 'Diffusers' if shared.backend == shared.Backend.DIFFUSERS else 'Original',
"Operations": ', '.join(list(set(p.ops))) if len(p.ops) > 0 else None
"Comment": comment,
"Operations": ', '.join(list(set(p.ops))) if len(p.ops) > 0 else None,
}
token_merging_ratio = p.get_token_merging_ratio()
token_merging_ratio_hr = p.get_token_merging_ratio(for_hr=True) if p.enable_hr else None
@@ -1053,6 +1057,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
if add_color_corrections:
self.color_corrections = []
imgs = []
unprocessed = []
for img in self.init_images:
# Save init image
if shared.opts.save_init_img:
@@ -1072,7 +1077,9 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
if crop_region is not None:
image = image.crop(crop_region)
image = images.resize_image(3, image, self.width, self.height)
self.init_images = image # assign early for diffusers
if shared.backend == shared.Backend.DIFFUSERS:
unprocessed.append(image)
self.init_images = [image] # assign early for diffusers
if image_mask is not None:
if self.inpainting_fill != 1:
image = masking.fill(image, latent_mask)
@@ -1081,6 +1088,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
image = np.array(image).astype(np.float32) / 255.0
image = np.moveaxis(image, 2, 0)
imgs.append(image)
self.init_images = unprocessed if shared.backend == shared.Backend.DIFFUSERS else imgs
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:
+101 -34
View File
@@ -1,12 +1,16 @@
import inspect
import typing
import torch
import modules.devices as devices
import modules.shared as shared
import modules.sd_samplers as sd_samplers
import modules.sd_models as sd_models
import modules.sd_vae as sd_vae
import modules.taesd.sd_vae_taesd as sd_vae_taesd
import modules.images as images
from modules.lora_diffusers import lora_state, unload_diffusers_lora
from modules.processing import StableDiffusionProcessing
import modules.prompt_parser_diffusers as prompt_parser_diffusers
try:
@@ -15,16 +19,6 @@ except Exception as ex:
shared.log.error(f'Failed to import diffusers: {ex}')
def encode_prompt(encoder, prompt):
cfg = encoder.config
# TODO implement similar hijack for diffusers text encoder but following diffusers pipeline.encode_prompt concepts
# from modules import sd_hijack_clip
# model.text_encoder = sd_hijack_clip.FrozenCLIPEmbedderWithCustomWords(model.text_encoder, None)
shared.log.debug(f'Diffuser encoder: {encoder.__class__.__name__} dict={getattr(cfg, "vocab_size", None)} layers={getattr(cfg, "num_hidden_layers", None)} tokens={getattr(cfg, "max_position_embeddings", None)}')
embeds = prompt
return embeds
def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_prompts):
results = []
@@ -35,7 +29,10 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
def vae_decode(latents, model, output_type='np'):
if hasattr(model, 'vae') and torch.is_tensor(latents):
shared.log.debug(f'Diffusers VAE decode: name={model.vae.config.get("_name_or_path", "default")} dtype={model.vae.dtype} upcast={model.vae.config.get("force_upcast", None)}')
if latents.shape[0] == 0:
shared.log.error(f'VAE nothing to decode: {latents.shape}')
return []
shared.log.debug(f'Diffusers VAE decode: name={sd_vae.loaded_vae_file} dtype={model.vae.dtype} upcast={model.vae.config.get("force_upcast", None)} images={latents.shape[0]}')
if shared.opts.diffusers_move_unet and not model.has_accelerate:
shared.log.debug('Diffusers: Moving UNet to CPU')
unet_device = model.unet.device
@@ -50,26 +47,69 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
else:
return latents
def taesd_vae_decode(latents, model, output_type='np'):
shared.log.debug('Diffusers VAE decode: name=TAESD')
decoded = torch.zeros((len(latents), 3, p.height, p.width), dtype=devices.dtype_vae, device=devices.device)
for i in range(len(output.images)):
decoded[i] = (sd_vae_taesd.decode(latents[i]) * 2.0) - 1.0
imgs = model.image_processor.postprocess(decoded, output_type=output_type)
return imgs
def set_pipeline_args(model, prompt, negative_prompt, **kwargs):
def fix_prompts(prompts, negative_prompts, prompts_2, negative_prompts_2):
if type(prompts) is str:
prompts = [prompts]
if type(negative_prompts) is str:
negative_prompts = [negative_prompts]
while len(negative_prompts) < len(prompts):
negative_prompts.append(negative_prompts[-1])
if type(prompts_2) is str:
prompts_2 = [prompts_2]
if type(prompts_2) is list:
while len(prompts_2) < len(prompts):
prompts_2.append(prompts_2[-1])
if type(negative_prompts_2) is str:
negative_prompts_2 = [negative_prompts_2]
if type(negative_prompts_2) is list:
while len(negative_prompts_2) < len(prompts_2):
negative_prompts_2.append(negative_prompts_2[-1])
return prompts, negative_prompts, prompts_2, negative_prompts_2
def set_pipeline_args(model, prompts: list, negative_prompts: list, prompts_2: typing.Optional[list]=None, negative_prompts_2: typing.Optional[list]=None, is_refiner: bool=False, **kwargs):
args = {}
pipeline = model
signature = inspect.signature(type(pipeline).__call__)
possible = signature.parameters.keys()
generator_device = devices.cpu if shared.opts.diffusers_generator_device == "cpu" else shared.device
generator = [torch.Generator(generator_device).manual_seed(s) for s in seeds]
prompt_embed = None
pooled = None
negative_embed = None
negative_pooled = None
prompts, negative_prompts, prompts_2, negative_prompts_2 = fix_prompts(prompts, negative_prompts, prompts_2, negative_prompts_2)
if shared.opts.data['prompt_attention'] in {'Compel parser', 'Full parser'}:
prompt_embed, pooled, negative_embed, negative_pooled = prompt_parser_diffusers.compel_encode_prompts(model,
prompts,
negative_prompts,
prompts_2,
negative_prompts_2,
is_refiner,
kwargs.pop("clip_skip", None))
if 'prompt' in possible:
if hasattr(model, 'text_encoder') and 'prompt_embeds' in possible:
# args['prompt_embeds'] = encode_prompt(model, prompt)
args['prompt'] = prompt
if hasattr(model, 'text_encoder') and 'prompt_embeds' in possible and prompt_embed is not None:
args['prompt_embeds'] = prompt_embed
if shared.sd_model_type == "sdxl":
args['pooled_prompt_embeds'] = pooled
args['prompt_2'] = None #Cannot pass prompts when passing embeds
else:
args['prompt'] = prompt
args['prompt'] = prompts
if 'negative_prompt' in possible:
if hasattr(model, 'text_encoder') and 'negative_prompt_embeds' in possible:
# args['negative_prompt_embeds'] = encode_prompt(model, negative_prompt)
args['negative_prompt'] = negative_prompt
if hasattr(model, 'text_encoder') and 'negative_prompt_embeds' in possible and negative_embed is not None:
args['negative_prompt_embeds'] = negative_embed
if shared.sd_model_type == "sdxl":
args['negative_pooled_prompt_embeds'] = negative_pooled
args['negative_prompt_2'] = None
else:
args['negative_prompt'] = negative_prompt
args['negative_prompt'] = negative_prompts
if 'num_inference_steps' in possible:
args['num_inference_steps'] = p.steps
if 'guidance_scale' in possible:
@@ -82,8 +122,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
args['callback_steps'] = 1
if 'callback' in possible:
args['callback'] = diffusers_callback
if 'cross_attention_kwargs' in possible and lora_state['active']:
args['cross_attention_kwargs'] = { 'scale': lora_state['multiplier']}
if 'cross_attention_kwargs' in possible and lora_state['active'] and shared.opts.diffusers_lora_loader == "diffusers default":
args['cross_attention_kwargs'] = { 'scale': lora_state['multiplier'][0]}
for arg in kwargs:
if arg in possible:
args[arg] = kwargs[arg]
@@ -102,6 +142,14 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
clean['prompt'] = len(clean['prompt'])
if 'negative_prompt' in clean:
clean['negative_prompt'] = len(clean['negative_prompt'])
if 'prompt_embeds' in clean:
clean['prompt_embeds'] = clean['prompt_embeds'].shape
if 'pooled_prompt_embeds' in clean:
clean['pooled_prompt_embeds'] = clean['pooled_prompt_embeds'].shape
if 'negative_prompt_embeds' in clean:
clean['negative_prompt_embeds'] = clean['negative_prompt_embeds'].shape
if 'negative_pooled_prompt_embeds' in clean:
clean['negative_pooled_prompt_embeds'] = clean['negative_pooled_prompt_embeds'].shape
clean['generator'] = generator_device
shared.log.debug(f'Diffuser pipeline: {pipeline.__class__.__name__} task={sd_models.get_diffusers_task(model)} set={clean}')
return args
@@ -112,8 +160,19 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
if sampler is None:
sampler = sd_samplers.all_samplers_map.get("UniPC")
sd_samplers.create_sampler(sampler.name, shared.sd_model) # TODO(Patrick): For wrapped pipelines this is currently a no-op
sampler_options = f'type:{shared.opts.schedulers_prediction_type} ' if shared.opts.schedulers_prediction_type != 'default' else ''
sampler_options += 'no_karras ' if not shared.opts.schedulers_use_karras else ''
sampler_options += 'no_low_order' if not shared.opts.schedulers_use_loworder else ''
sampler_options += 'dynamic_thresholding' if shared.opts.schedulers_use_thresholding else ''
sampler_options += f'solver:{shared.opts.schedulers_dpm_solver}' if shared.opts.schedulers_dpm_solver != 'sde-dpmsolver++' else ''
sampler_options += f'beta:{shared.opts.schedulers_beta_schedule}:{shared.opts.schedulers_beta_start}:{shared.opts.schedulers_beta_end}' if shared.opts.schedulers_beta_schedule != 'default' else ''
p.extra_generation_params['Sampler options'] = sampler_options if len(sampler_options) > 0 else None
p.extra_generation_params['Pipeline'] = shared.sd_model.__class__.__name__
cross_attention_kwargs={}
if len(getattr(p, 'init_images', [])) > 0:
while len(p.init_images) < len(prompts):
p.init_images.append(p.init_images[-1])
if lora_state['active']:
cross_attention_kwargs['scale'] = lora_state['multiplier']
task_specific_kwargs={}
@@ -127,11 +186,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
p.ops.append('inpaint')
task_specific_kwargs = {"image": p.init_images, "mask_image": p.mask, "strength": p.denoising_strength, "height": p.height, "width": p.width}
# TODO diffusers use transformers for prompt parsing
# from modules.prompt_parser import parse_prompt_attention
# parsed_prompt = [parse_prompt_attention(prompt) for prompt in prompts]
if shared.state.interrupted or shared.state.skipped:
unload_diffusers_lora()
return results
if shared.opts.diffusers_move_base and not shared.sd_model.has_accelerate:
@@ -140,26 +196,31 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
refiner_enabled = shared.sd_refiner is not None and p.enable_hr
pipe_args = set_pipeline_args(
model=shared.sd_model,
prompt=prompts,
negative_prompt=negative_prompts,
prompt_2=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else prompts,
negative_prompt_2=[p.refiner_negative] if len(p.refiner_negative) > 0 else negative_prompts,
prompts=prompts,
negative_prompts=negative_prompts,
prompts_2=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else prompts,
negative_prompts_2=[p.refiner_negative] if len(p.refiner_negative) > 0 else negative_prompts,
eta=shared.opts.eta_ddim,
guidance_rescale=p.diffusers_guidance_rescale,
denoising_start=0 if refiner_enabled and p.refiner_start > 0 and p.refiner_start < 1 else None,
denoising_end=p.refiner_start if refiner_enabled and p.refiner_start > 0 and p.refiner_start < 1 else None,
output_type='latent' if hasattr(shared.sd_model, 'vae') else 'np',
is_refiner=False,
clip_skip=p.clip_skip,
**task_specific_kwargs
)
p.extra_generation_params['CFG rescale'] = p.diffusers_guidance_rescale
p.extra_generation_params["Eta DDIM"] = shared.opts.eta_ddim if shared.opts.eta_ddim is not None and shared.opts.eta_ddim > 0 else None
output = shared.sd_model(**pipe_args) # pylint: disable=not-callable
if shared.state.interrupted or shared.state.skipped:
unload_diffusers_lora()
return results
if shared.sd_refiner is None or not p.enable_hr:
output.images = vae_decode(output.images, shared.sd_model)
output.images = vae_decode(output.images, shared.sd_model) if p.full_quality else taesd_vae_decode(output.images, shared.sd_model)
if lora_state['active']:
p.extra_generation_params['Lora method'] = shared.opts.diffusers_lora_loader
unload_diffusers_lora()
if refiner_enabled:
@@ -191,8 +252,8 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
for i in range(len(output.images)):
pipe_args = set_pipeline_args(
model=shared.sd_refiner,
prompt=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else prompts[i],
negative_prompt=[p.refiner_negative] if len(p.refiner_negative) > 0 else negative_prompts[i],
prompts=[p.refiner_prompt] if len(p.refiner_prompt) > 0 else prompts[i],
negative_prompts=[p.refiner_negative] if len(p.refiner_negative) > 0 else negative_prompts[i],
num_inference_steps=p.hr_second_pass_steps,
eta=shared.opts.eta_ddim,
strength=p.denoising_strength,
@@ -202,8 +263,14 @@ def process_diffusers(p: StableDiffusionProcessing, seeds, prompts, negative_pro
denoising_end=1 if p.refiner_start > 0 and p.refiner_start < 1 else None,
image=output.images[i],
output_type='latent' if hasattr(shared.sd_refiner, 'vae') else 'np',
is_refiner=True,
clip_skip=p.clip_skip,
)
refiner_output = shared.sd_refiner(**pipe_args) # pylint: disable=not-callable
p.extra_generation_params['Refiner CFG scale'] = p.image_cfg_scale if p.image_cfg_scale is not None else None
p.extra_generation_params['Refiner start'] = p.refiner_start
p.extra_generation_params["Hires steps"] = p.hr_second_pass_steps
if not shared.state.interrupted and not shared.state.skipped:
refiner_images = vae_decode(refiner_output.images, shared.sd_refiner)
results.append(refiner_images[0])
+131
View File
@@ -0,0 +1,131 @@
import os
import typing
import torch
import diffusers
from compel import Compel, ReturnedEmbeddingsType
import modules.shared as shared
import modules.prompt_parser as prompt_parser
debug_output = os.environ.get('SD_PROMPT_DEBUG', None)
debug = shared.log.info if debug_output is not None else lambda *args, **kwargs: None
def convert_to_compel(prompt: str):
if prompt is None:
return None
all_schedules = prompt_parser.get_learned_conditioning_prompt_schedules([prompt], 100)[0]
output_list = prompt_parser.parse_prompt_attention(all_schedules[0][1])
converted_prompt = []
for subprompt, weight in output_list:
if subprompt != " ":
if weight == 1:
converted_prompt.append(subprompt)
else:
converted_prompt.append(f"({subprompt}){weight}")
converted_prompt = " ".join(converted_prompt)
return converted_prompt
CLIP_SKIP_MAPPING = {
None: ReturnedEmbeddingsType.LAST_HIDDEN_STATES_NORMALIZED,
1: ReturnedEmbeddingsType.LAST_HIDDEN_STATES_NORMALIZED,
2: ReturnedEmbeddingsType.PENULTIMATE_HIDDEN_STATES_NORMALIZED,
}
def compel_encode_prompts(
pipeline: diffusers.StableDiffusionXLPipeline | diffusers.StableDiffusionPipeline,
prompts: list,
negative_prompts: list,
prompts_2: typing.Optional[list] = None,
negative_prompts_2: typing.Optional[list] = None,
is_refiner: bool = None,
clip_skip: typing.Optional[int] = None,
):
prompt_embeds = []
positive_pooleds = []
negative_embeds = []
negative_pooleds = []
for i in range(len(prompts)):
prompt_embed, positive_pooled, negative_embed, negative_pooled = compel_encode_prompt(pipeline,
prompts[i],
negative_prompts[i],
prompts_2[i] if prompts_2 is not None else None,
negative_prompts_2[i] if negative_prompts_2 is not None else None,
is_refiner, clip_skip)
prompt_embeds.append(prompt_embed)
positive_pooleds.append(positive_pooled)
negative_embeds.append(negative_embed)
negative_pooleds.append(negative_pooled)
prompt_embeds = torch.cat(prompt_embeds, dim=0)
negative_embeds = torch.cat(negative_embeds, dim=0)
if shared.sd_model_type == "sdxl":
positive_pooleds = torch.cat(positive_pooleds, dim=0)
negative_pooleds = torch.cat(negative_pooleds, dim=0)
return prompt_embeds, positive_pooleds, negative_embeds, negative_pooleds
def compel_encode_prompt(
pipeline: diffusers.StableDiffusionXLPipeline | diffusers.StableDiffusionPipeline,
prompt: str,
negative_prompt: str,
prompt_2: typing.Optional[str] = None,
negative_prompt_2: typing.Optional[str] = None,
is_refiner: bool = None,
clip_skip: typing.Optional[int] = None,
):
if shared.sd_model_type not in {"sd", "sdxl"}:
shared.log.warning(f"Prompt parser: Compel not supported: {type(pipeline).__name__}")
return (None, None, None, None)
if shared.sd_model_type == "sdxl":
embedding_type = ReturnedEmbeddingsType.PENULTIMATE_HIDDEN_STATES_NON_NORMALIZED
if clip_skip is not None and clip_skip > 1:
shared.log.warning(f"Prompt parser SDXL unsupported: clip_skip={clip_skip}")
else:
embedding_type = CLIP_SKIP_MAPPING.get(clip_skip, ReturnedEmbeddingsType.PENULTIMATE_HIDDEN_STATES_NORMALIZED)
if clip_skip not in CLIP_SKIP_MAPPING:
shared.log.warning(f"Prompt parser unsupported: clip_skip={clip_skip} expected={set(CLIP_SKIP_MAPPING.keys())}")
if shared.opts.data["prompt_attention"] != "Compel parser":
prompt = convert_to_compel(prompt)
negative_prompt = convert_to_compel(negative_prompt)
prompt_2 = convert_to_compel(prompt_2)
negative_prompt_2 = convert_to_compel(negative_prompt_2)
compel_te1 = Compel(
tokenizer=pipeline.tokenizer,
text_encoder=pipeline.text_encoder,
returned_embeddings_type=embedding_type,
requires_pooled=False,
# truncate_long_prompts=False,
device=shared.device
)
if shared.sd_model_type == "sdxl":
compel_te2 = Compel(
tokenizer=pipeline.tokenizer_2,
text_encoder=pipeline.text_encoder_2,
returned_embeddings_type=embedding_type,
requires_pooled=True,
device=shared.device
)
if not is_refiner:
positive_te1 = compel_te1(prompt)
positive_te2, positive_pooled = compel_te2(prompt_2)
positive = torch.cat((positive_te1, positive_te2), dim=-1)
negative_te1 = compel_te1(negative_prompt)
negative_te2, negative_pooled = compel_te2(negative_prompt_2)
negative = torch.cat((negative_te1, negative_te2), dim=-1)
else:
positive, positive_pooled = compel_te2(prompt)
negative, negative_pooled = compel_te2(negative_prompt)
parsed = compel_te1.parse_prompt_string(prompt)
debug(f"Prompt parser Compel: {parsed}")
[prompt_embed, negative_embed] = compel_te2.pad_conditioning_tensors_to_same_length([positive, negative])
return prompt_embed, positive_pooled, negative_embed, negative_pooled
positive, negative = compel_te1(prompt), compel_te1(negative_prompt)
[prompt_embed, negative_embed] = compel_te1.pad_conditioning_tensors_to_same_length([positive, negative])
return prompt_embed, None, negative_embed, None
+91 -47
View File
@@ -136,12 +136,9 @@ def list_models():
checkpoints_list.clear()
checkpoint_aliases.clear()
ext_filter=[".safetensors"] if shared.opts.sd_disable_ckpt else [".ckpt", ".safetensors"]
model_list = []
if shared.backend == shared.Backend.ORIGINAL or shared.opts.diffusers_allow_safetensors:
model_list += modelloader.load_models(model_path=model_path, model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=ext_filter, download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
model_list = modelloader.load_models(model_path=model_path, model_url=None, command_path=shared.opts.ckpt_dir, ext_filter=ext_filter, download_name=None, ext_blacklist=[".vae.ckpt", ".vae.safetensors"])
if shared.backend == shared.Backend.DIFFUSERS:
model_list += modelloader.load_diffusers_models(model_path=os.path.join(models_path, 'Diffusers'), command_path=shared.opts.diffusers_dir)
for filename in sorted(model_list, key=str.lower):
checkpoint_info = CheckpointInfo(filename)
if checkpoint_info.name is not None:
@@ -522,6 +519,7 @@ class ModelData:
model_data = ModelData()
def change_backend():
shared.log.info(f'Pipeline changed: {shared.backend}')
unload_model_weights()
@@ -533,6 +531,64 @@ def change_backend():
refresh_vae_list()
def detect_pipeline(f: str, op: str = 'model'):
if not f.endswith('.safetensors'):
return None, None
guess = shared.opts.diffusers_pipeline
if guess == 'Autodetect':
try:
size = round(os.path.getsize(f) / 1024 / 1024 / 1024, 2)
if size < 1:
shared.log.warning(f'Model size smaller than expected: {f} size={size} GB')
elif size < 5:
guess = 'Stable Diffusion'
elif size < 6:
if op == 'model':
shared.log.warning(f'Model detected as SD-XL refiner model, but attempting to load a base model: {f} size={size} GB')
else:
guess = 'Stable Diffusion XL'
elif size < 7:
if op == 'refiner':
shared.log.warning(f'Model size matches SD-XL base model, but attempting to load a refiner model: {f} size={size} GB')
else:
guess = 'Stable Diffusion XL'
else:
shared.log.error(f'Diffusers autodetect failed, set diffuser pipeline manually: {f}')
return None, None
shared.log.debug(f'Diffusers autodetect {op}: {f} pipeline={guess} size={size} GB')
except Exception as e:
shared.log.error(f'Error detecting diffusers pipeline: model={f} {e}')
return None, None
if guess == shared.pipelines[1]:
pipeline = diffusers.StableDiffusionPipeline
elif guess == shared.pipelines[2]:
pipeline = diffusers.StableDiffusionXLPipeline
elif guess == shared.pipelines[3]:
pipeline = diffusers.KandinskyPipeline
elif guess == shared.pipelines[4]:
pipeline = diffusers.KandinskyV22Pipeline
elif guess == shared.pipelines[5]:
pipeline = diffusers.IFPipeline
elif guess == shared.pipelines[6]:
pipeline = diffusers.ShapEPipeline
elif guess == shared.pipelines[7]:
pipeline = diffusers.StableDiffusionImg2ImgPipeline
elif guess == shared.pipelines[8]:
pipeline = diffusers.StableDiffusionXLImg2ImgPipeline
elif guess == shared.pipelines[9]:
pipeline = diffusers.KandinskyImg2ImgPipeline
elif guess == shared.pipelines[10]:
pipeline = diffusers.KandinskyV22Img2ImgPipeline
elif guess == shared.pipelines[11]:
pipeline = diffusers.IFImg2ImgPipeline
elif guess == shared.pipelines[12]:
pipeline = diffusers.ShapEImg2ImgPipeline
else:
shared.log.error(f'Diffusers unknown pipeline: {guess}')
pipeline = None, None
return pipeline, guess
def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=None, op='model'): # pylint: disable=unused-argument
import torch # pylint: disable=reimported,redefined-outer-name
if timer is None:
@@ -570,7 +626,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
sd_model = None
try:
if shared.cmd_opts.ckpt is not None and model_data.initial: # initial load\
if shared.cmd_opts.ckpt is not None and model_data.initial: # initial load
ckpt_basename = os.path.basename(shared.cmd_opts.ckpt)
model_name = modelloader.find_diffuser(ckpt_basename)
if model_name is not None:
@@ -593,51 +649,26 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
devices.set_cuda_params()
vae = None
sd_vae.loaded_vae_file = None
if op == 'model' or op == 'refiner':
vae_file, vae_source = sd_vae.resolve_vae(checkpoint_info.filename)
vae = sd_vae.load_vae_diffusers(None, vae_file, vae_source)
vae = sd_vae.load_vae_diffusers(checkpoint_info.path, vae_file, vae_source)
if vae is not None:
diffusers_load_config["vae"] = vae
shared.log.info(f'Loading diffuser {op}: {checkpoint_info.filename}')
if not os.path.isfile(checkpoint_info.path):
try:
shared.log.debug(f'Diffusers load {op} config: {diffusers_load_config}')
# shared.log.debug(f'Diffusers load {op} config: {diffusers_load_config}')
sd_model = diffusers.DiffusionPipeline.from_pretrained(checkpoint_info.path, **diffusers_load_config)
except Exception as e:
shared.log.error(f'Diffusers {op} failed loading model: {checkpoint_info.path} {e}')
else:
diffusers_load_config["local_files_only "] = True
diffusers_load_config["extract_ema"] = shared.opts.diffusers_extract_ema
try:
if shared.opts.diffusers_pipeline == shared.pipelines[0]:
pipeline = diffusers.StableDiffusionPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[1]:
pipeline = diffusers.StableDiffusionXLPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[2]:
pipeline = diffusers.KandinskyPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[3]:
pipeline = diffusers.KandinskyV22Pipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[4]:
pipeline = diffusers.IFPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[5]:
pipeline = diffusers.ShapEPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[6]:
pipeline = diffusers.StableDiffusionImg2ImgPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[7]:
pipeline = diffusers.StableDiffusionXLImg2ImgPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[8]:
pipeline = diffusers.KandinskyImg2ImgPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[9]:
pipeline = diffusers.KandinskyV22Img2ImgPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[10]:
pipeline = diffusers.IFImg2ImgPipeline
elif shared.opts.diffusers_pipeline == shared.pipelines[11]:
pipeline = diffusers.ShapEImg2ImgPipeline
else:
shared.log.error(f'Diffusers {op} unknown pipeline: {shared.opts.diffusers_pipeline}')
except Exception as e:
shared.log.error(f'Diffusers {op} failed initializing pipeline: {shared.opts.diffusers_pipeline} {e}')
pipeline, _model_type = detect_pipeline(checkpoint_info.path, op)
if pipeline is None:
shared.log.error(f'Diffusers {op} pipeline not initialized: {shared.opts.diffusers_pipeline}')
return
try:
if hasattr(pipeline, 'from_single_file'):
@@ -697,6 +728,8 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
else:
sd_model.disable_attention_slicing()
if hasattr(sd_model, "vae"):
if vae is not None:
sd_model.vae = vae
if shared.opts.diffusers_vae_upcast != 'default':
if shared.opts.diffusers_vae_upcast == 'true':
sd_model.vae.config["force_upcast"] = True
@@ -704,7 +737,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
else:
sd_model.vae.config["force_upcast"] = False
sd_model.vae.config.force_upcast = False
shared.log.debug(f'Diffusers {op} VAE: name={sd_model.vae.config.get("_name_or_path", "default")} upcast={sd_model.vae.config.get("force_upcast", None)}')
shared.log.debug(f'Diffusers {op} VAE: name={sd_vae.loaded_vae_file} upcast={sd_model.vae.config.get("force_upcast", None)}')
if shared.opts.cross_attention_optimization == "xFormers" and hasattr(sd_model, 'enable_xformers_memory_efficient_attention'):
sd_model.enable_xformers_memory_efficient_attention()
if shared.opts.opt_channelslast:
@@ -767,8 +800,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
if op == 'refiner' and shared.opts.diffusers_move_refiner and not sd_model.has_accelerate:
shared.log.debug('Moving refiner model to CPU')
sd_model.to(devices.cpu)
elif not sd_model.has_accelerate:
# In offload modes, accelerate will move models around.
elif not sd_model.has_accelerate: # In offload modes, accelerate will move models around
sd_model.to(devices.device)
if op == 'refiner' and base_sent_to_cpu:
shared.log.debug('Moving base model back to GPU')
@@ -811,7 +843,6 @@ def set_diffuser_pipe(pipe, new_pipe_type):
new_pipe = diffusers.AutoPipelineForImage2Image.from_pipe(pipe)
elif new_pipe_type == DiffusersTaskType.INPAINTING:
new_pipe = diffusers.AutoPipelineForInpainting.from_pipe(pipe)
if pipe.__class__ == new_pipe.__class__:
return
@@ -843,7 +874,6 @@ def get_diffusers_task(pipe: diffusers.DiffusionPipeline) -> DiffusersTaskType:
return DiffusersTaskType.IMAGE_2_IMAGE
elif pipe.__class__ in diffusers.pipelines.auto_pipeline.AUTO_INPAINT_PIPELINES_MAPPING.values():
return DiffusersTaskType.INPAINTING
return DiffusersTaskType.TEXT_2_IMAGE
@@ -997,24 +1027,38 @@ def reload_model_weights(sd_model=None, info=None, reuse_dict=False, op='model')
shared.log.info(f"Weights loaded in {timer.summary()}")
def disable_offload(sd_model):
from accelerate.hooks import remove_hook_from_module
if not sd_model.has_accelerate:
return
for _name, model in sd_model.components.items():
if not isinstance(model, torch.nn.Module):
continue
remove_hook_from_module(model, recurse=True)
def unload_model_weights(op='model'):
from modules import sd_hijack
if op == 'model' or op == 'dict':
if model_data.sd_model:
if not model_data.sd_model.has_accelerate:
model_data.sd_model.to(devices.cpu)
if shared.backend == shared.Backend.ORIGINAL:
model_data.sd_model.to(devices.cpu)
sd_hijack.model_hijack.undo_hijack(model_data.sd_model)
else:
disable_offload(model_data.sd_model)
model_data.sd_model.to('meta')
model_data.sd_model = None
shared.log.debug(f'Weights unloaded {op}: {memory_stats()}')
shared.log.debug(f'Unload weights {op}: {memory_stats()}')
else:
if model_data.sd_refiner:
if not model_data.sd_refiner.has_accelerate:
model_data.sd_refiner.to(devices.cpu)
if shared.backend == shared.Backend.ORIGINAL:
model_data.sd_model.to(devices.cpu)
sd_hijack.model_hijack.undo_hijack(model_data.sd_refiner)
else:
disable_offload(model_data.sd_model)
model_data.sd_refiner.to('meta')
model_data.sd_refiner = None
shared.log.debug(f'Weights unloaded {op}: {memory_stats()}')
shared.log.debug(f'Unload weights {op}: {memory_stats()}')
devices.torch_gc(force=True)
+3 -1
View File
@@ -19,8 +19,10 @@ samplers_k_diffusion = [
('DPM++ 2M Karras', 'sample_dpmpp_2m', ['k_dpmpp_2m_ka'], {'scheduler': 'karras'}),
('DPM++ SDE', 'sample_dpmpp_sde', ['k_dpmpp_sde'], {"second_order": True, "brownian_noise": True}),
('DPM++ SDE Karras', 'sample_dpmpp_sde', ['k_dpmpp_sde_ka'], {'scheduler': 'karras', "second_order": True, "brownian_noise": True}),
('DPM++ 2M SDE', 'sample_dpmpp_2m_sde', ['k_dpmpp_2m_sde_ka'], {"brownian_noise": True, 'discard_next_to_last_sigma': True}),
('DPM++ 2M SDE', 'sample_dpmpp_2m_sde', ['k_dpmpp_2m_sde'], {"brownian_noise": True, 'discard_next_to_last_sigma': True}),
('DPM++ 2M SDE Karras', 'sample_dpmpp_2m_sde', ['k_dpmpp_2m_sde_ka'], {'scheduler': 'karras', "brownian_noise": True, 'discard_next_to_last_sigma': True}),
('DPM++ 3M SDE', 'sample_dpmpp_3m_sde', ['k_dpmpp_3m_sde'], {"brownian_noise": True, 'discard_next_to_last_sigma': True}),
('DPM++ 3M SDE Karras', 'sample_dpmpp_3m_sde', ['k_dpmpp_3m_sde_ka'], {'scheduler': 'karras', "brownian_noise": True, 'discard_next_to_last_sigma': True}),
('DPM fast', 'sample_dpm_fast', ['k_dpm_fast'], {"uses_ensd": True}),
('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad'], {"uses_ensd": True}),
('DPM2', 'sample_dpm_2', ['k_dpm_2'], {'discard_next_to_last_sigma': True}),
+7 -7
View File
@@ -3,7 +3,7 @@ import collections
import glob
from copy import deepcopy
import torch
from modules import shared, paths, devices, script_callbacks, sd_models
from modules import shared, paths, paths_internal, devices, script_callbacks, sd_models
vae_ignore_keys = {"model_ema.decay", "model_ema.num_updates"}
@@ -169,7 +169,7 @@ def load_vae(model, vae_file=None, vae_source="from unknown source"):
loaded_vae_file = vae_file
def load_vae_diffusers(_model, vae_file=None, vae_source="from unknown source"):
def load_vae_diffusers(model_file, vae_file=None, vae_source="from unknown source"):
if vae_file is None:
return None
if not os.path.exists(vae_file):
@@ -196,14 +196,14 @@ def load_vae_diffusers(_model, vae_file=None, vae_source="from unknown source"):
try:
import diffusers
if os.path.isfile(vae_file):
if shared.opts.diffusers_pipeline == "Stable Diffusion XL":
# load_config passed to from_single_file doesn't apply
# from_single_file by default downloads VAE1.5 config
shared.log.warning("Using SDXL VAE loaded from singular file will result in low contrast images.")
vae = diffusers.AutoencoderKL.from_single_file(vae_file)
_pipeline, model_type = sd_models.detect_pipeline(model_file, 'vae')
diffusers_load_config = { "config_file": paths_internal.sd_default_config if model_type != 'Stable Diffusion XL' else os.path.join(paths_internal.sd_configs_path, 'sd_xl_base.yaml')}
vae = diffusers.AutoencoderKL.from_single_file(vae_file, **diffusers_load_config)
vae = vae.to(devices.dtype_vae)
else:
vae = diffusers.AutoencoderKL.from_pretrained(vae_file, **diffusers_load_config)
global loaded_vae_file # pylint: disable=global-statement
loaded_vae_file = os.path.basename(vae_file)
# shared.log.debug(f'Diffusers VAE config: {vae.config}')
return vae
except Exception as e:
+4 -3
View File
@@ -41,6 +41,7 @@ loaded_hypernetworks = []
gradio_theme = gr.themes.Base()
settings_components = None
pipelines = [
'Autodetect',
'Stable Diffusion', 'Stable Diffusion XL', 'Kandinsky V1', 'Kandinsky V2', 'DeepFloyd IF', 'Shap-E',
'Stable Diffusion Img2Img', 'Stable Diffusion XL Img2Img', 'Kandinsky V1 Img2Img', 'Kandinsky V2 Img2Img', 'DeepFloyd IF Img2Img', 'Shap-E Img2Img'
]
@@ -383,7 +384,7 @@ options_templates.update(options_section(('cuda', "Compute 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_backend": OptionInfo("none", "Model compile backend (experimental)", gr.Radio, lambda: {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex']}),
"cuda_compile_backend": OptionInfo("none", "Model compile backend (experimental)", gr.Radio, lambda: {"choices": ['none', 'inductor', 'cudagraphs', 'aot_ts_nvfuser', 'hidet', 'ipex', 'openvino_fx']}),
"cuda_compile_mode": OptionInfo("default", "Model compile mode (experimental)", gr.Radio, lambda: {"choices": ['default', 'reduce-overhead', 'max-autotune']}),
"cuda_compile_fullgraph": OptionInfo(False, "Model compile fullgraph"),
"cuda_compile_verbose": OptionInfo(False, "Model compile verbose mode"),
@@ -394,11 +395,10 @@ options_templates.update(options_section(('cuda', "Compute Settings"), {
}))
options_templates.update(options_section(('diffusers', "Diffusers Settings"), {
"diffusers_allow_safetensors": OptionInfo(True, 'Diffusers allow loading from safetensors files'),
"diffusers_pipeline": OptionInfo(pipelines[0], 'Diffusers pipeline', gr.Dropdown, lambda: {"choices": pipelines}),
"diffusers_move_base": OptionInfo(False, "Move base model to CPU when using refiner"),
"diffusers_move_unet": OptionInfo(False, "Move base model to CPU when using VAE"),
"diffusers_move_refiner": OptionInfo(True, "Move refiner model to CPU when not in use"),
"diffusers_move_unet": OptionInfo(False, "Move UNet to CPU while VAE decoding"),
"diffusers_extract_ema": OptionInfo(True, "Use model EMA weights when possible"),
"diffusers_generator_device": OptionInfo("default", "Generator device", gr.Radio, lambda: {"choices": ["default", "cpu"]}),
"diffusers_seq_cpu_offload": OptionInfo(False, "Enable sequential CPU offload"),
@@ -409,6 +409,7 @@ options_templates.update(options_section(('diffusers', "Diffusers Settings"), {
"diffusers_attention_slicing": OptionInfo(False, "Enable attention slicing"),
"diffusers_model_load_variant": OptionInfo("default", "Diffusers model loading variant", gr.Radio, lambda: {"choices": ['default', 'fp32', 'fp16']}),
"diffusers_vae_load_variant": OptionInfo("default", "Diffusers VAE loading variant", gr.Radio, lambda: {"choices": ['default', 'fp32', 'fp16']}),
"diffusers_lora_loader": OptionInfo("sequential apply", "Diffusers LoRA loading variant", gr.Radio, lambda: {"choices": ['sequential apply', 'merge and apply', 'diffusers default']}),
# "diffusers_force_zeros": OptionInfo(False, "Force zeros for prompts when empty"),
# "diffusers_aesthetics_score": OptionInfo(6.0, "Require aesthetic score", gr.Slider, {"minimum": 0, "maximum": 10, "step": 0.1}),
}))
@@ -113,7 +113,6 @@ def extract_image_data_embed(image):
outarr = crop_black(np.array(image.convert('RGB').getdata()).reshape(image.size[1], image.size[0], d).astype(np.uint8)) & 0x0F
black_cols = np.where(np.sum(outarr, axis=(0, 2)) == 0)
if black_cols[0].shape[0] < 2:
print('No Image data blocks found.')
return None
data_block_lower = outarr[:, :black_cols[0].min(), :].astype(np.uint8)
+3 -2
View File
@@ -5,9 +5,9 @@ from modules.ui import plaintext_to_html
from modules.memstats import memory_stats
def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, 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, refiner_start: int, refiner_prompt: str, refiner_negative: str, override_settings_texts, *args): # pylint: disable=unused-argument
def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, full_quality: bool, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, 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, refiner_start: int, refiner_prompt: str, refiner_negative: str, override_settings_texts, *args): # pylint: disable=unused-argument
shared.log.debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|clip_skip={clip_skip}|seed={seed}|subseed={subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}||height={height}|width={width}|enable_hr={enable_hr}|denoising_strength={denoising_strength}|hr_scale={hr_scale}|hr_upscaler={hr_upscaler}|hr_second_pass_steps={hr_second_pass_steps}|hr_resize_x={hr_resize_x}|hr_resize_y={hr_resize_y}|image_cfg_scale={image_cfg_scale}|diffusers_guidance_rescale={diffusers_guidance_rescale}|refiner_start={refiner_start}||refiner_prompt={refiner_prompt}|refiner_negative={refiner_negative}|override_settings_texts={override_settings_texts}|args={args}')
shared.log.debug(f'txt2img: id_task={id_task}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|steps={steps}|sampler_index={sampler_index}|latent_index={latent_index}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|clip_skip={clip_skip}|seed={seed}|subseed={subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}||height={height}|width={width}|enable_hr={enable_hr}|denoising_strength={denoising_strength}|hr_scale={hr_scale}|hr_upscaler={hr_upscaler}|hr_second_pass_steps={hr_second_pass_steps}|hr_resize_x={hr_resize_x}|hr_resize_y={hr_resize_y}|image_cfg_scale={image_cfg_scale}|diffusers_guidance_rescale={diffusers_guidance_rescale}|refiner_start={refiner_start}||refiner_prompt={refiner_prompt}|refiner_negative={refiner_negative}|override_settings_texts={override_settings_texts}|args={args}')
if shared.sd_model is None:
shared.log.warning('Model not loaded')
@@ -43,6 +43,7 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step
clip_skip=clip_skip,
width=width,
height=height,
full_quality=full_quality,
restore_faces=restore_faces,
tiling=tiling,
enable_hr=enable_hr,
+5 -2
View File
@@ -379,6 +379,7 @@ def create_ui(startup_timer = None):
cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.1, label='CFG Scale', value=6.0, elem_id="txt2img_cfg_scale")
clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=14, step=1, elem_id='txt2img_clip_skip', interactive=True)
with FormRow(elem_classes="checkboxes-row", variant="compact"):
full_quality = gr.Checkbox(label='Full quality', value=True, elem_id="txt2img_full_quality")
restore_faces = gr.Checkbox(label='Face restore', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="txt2img_restore_faces")
tiling = gr.Checkbox(label='Tiling', value=False, elem_id="txt2img_tiling")
@@ -435,7 +436,7 @@ def create_ui(startup_timer = None):
txt2img_prompt_styles,
steps,
sampler_index, latent_index,
restore_faces, tiling,
full_quality, restore_faces, tiling,
batch_count, batch_size,
cfg_scale, image_cfg_scale,
diffusers_guidance_rescale,
@@ -484,6 +485,7 @@ def create_ui(startup_timer = None):
(latent_index, "Latent sampler"),
(denoising_strength, "Denoising strength"),
(refiner_start, "Refiner start"),
(full_quality, "Full quality"),
(restore_faces, "Face restoration"),
(batch_size, "Batch size"),
(batch_count, "Batch count"),
@@ -669,6 +671,7 @@ def create_ui(startup_timer = None):
clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=4, step=1, elem_id='img2img_clip_skip', interactive=True)
diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance Rescale', value=0.7, elem_id="txt2img_image_cfg_rescale")
with FormRow(elem_classes="img2img_checkboxes_row", variant="compact"):
full_quality = gr.Checkbox(label='Full quality', value=True, elem_id="img2img_full_quality")
restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(modules.shared.face_restorers) > 1, elem_id="img2img_restore_faces")
tiling = gr.Checkbox(label='Tiling', value=False, elem_id="img2img_tiling")
@@ -733,7 +736,7 @@ def create_ui(startup_timer = None):
sampler_index, latent_index,
mask_blur, mask_alpha,
inpainting_fill,
restore_faces, tiling,
full_quality, restore_faces, tiling,
batch_count, batch_size,
cfg_scale, image_cfg_scale,
diffusers_guidance_rescale,
+4
View File
@@ -151,6 +151,8 @@ def install_extension_from_url(dirname, url, branch_name, search_text, sort_colu
normalized_url = normalize_git_url(url)
assert len([x for x in extensions.extensions if normalize_git_url(x.remote) == normalized_url]) == 0, 'Extension with this URL is already installed'
tmpdir = os.path.join(paths.data_path, "tmp", dirname)
if url.endswith('.git'):
url = url.replace('.git', '')
try:
shutil.rmtree(tmpdir, True)
if not branch_name:
@@ -175,6 +177,8 @@ def install_extension_from_url(dirname, url, branch_name, search_text, sort_colu
run_extension_installer(target_dir)
extensions.list_extensions()
return [refresh_extensions_list_from_data(search_text, sort_column), html.escape(f"Extension installed: {target_dir} | Restart required")]
except Exception as e:
shared.log.error(f'Error installing extension: {url} {e}')
finally:
shutil.rmtree(tmpdir, True)
+1 -1
View File
@@ -140,7 +140,7 @@ class ExtraNetworksPage:
continue
try:
img = Image.open(f)
if img.width > 1024 or img.height > 1024:
if img.width > 1024 or img.height > 1024 or os.path.getsize(f) > 70000:
img = img.convert('RGB')
img.thumbnail((512, 512), Image.HAMMING)
img.save(fn)
+132 -2
View File
@@ -17,6 +17,7 @@ def create_ui():
with gr.Column(elem_id='models_output_container', scale=1):
# models_output = gr.Text(elem_id="models_output", value="", show_label=False)
gr.HTML(elem_id="models_progress", value="")
models_image = gr.Image(elem_id="models_image", show_label=False, interactive=False, type='pil')
models_outcome = gr.HTML(elem_id="models_error", value="")
with gr.Column(elem_id='models_input_container', scale=3):
@@ -238,5 +239,134 @@ def create_ui():
hf_results.select(fn=hf_select, inputs=[hf_results], outputs=[hf_selected])
hf_download_model_btn.click(fn=hf_download_model, inputs=[hf_selected, hf_token, hf_variant, hf_revision, hf_mirror], outputs=[models_outcome])
# with gr.Tab(label="CivitAI"):
# pass
with gr.Tab(label="CivitAI"):
data = []
def civit_search(name, tag, model_type):
import requests
headers = { 'Content-type': 'application/json' }
url = 'https://civitai.com/api/v1/models?limit=25&types=Checkpoint&Sort=Newest'
if name is not None and len(name) > 0:
url += f'&query={name}'
if tag is not None and len(tag) > 0:
url += f'&tag={tag}'
r = requests.get(url, timeout=60, headers=headers)
log.debug(f'CivitAI search: name={name} tag={tag} status={r.status_code}')
if r.status_code != 200:
return [], [], []
body = r.json()
nonlocal data
data = body.get('items', [])
data1 = []
for model in data:
found = 0
for variant in model['modelVersions']:
if model_type == 'SD 1.5':
if 'SD 1.' in variant['baseModel']:
found += 1
if model_type == 'SD XL':
if 'SDXL' in variant['baseModel']:
found += 1
else:
if 'SD 1.' not in variant['baseModel'] and 'SDXL' not in variant['baseModel']:
found += 1
if found > 0:
data1.append([
model['id'],
model['name'],
', '.join(model['tags']),
model['stats']['downloadCount'],
model['stats']['rating']
])
return data1, [], []
def civit_select1(evt: gr.SelectData, in_data):
model_id = in_data[evt.index[0]][0]
data2 = []
preview_img = None
for model in data:
if model['id'] == model_id:
for d in model['modelVersions']:
if d.get('images') is not None and len(d['images']) > 0 and len(d['images'][0]['url']) > 0:
preview_img = d['images'][0]['url']
data2.append([
d['id'],
d['modelId'],
d['name'],
d['baseModel'],
d['createdAt'],
])
log.debug(f'CivitAI select: model={in_data[evt.index[0]]} versions={len(data2)}')
return data2, preview_img
def civit_select2(evt: gr.SelectData, in_data):
variant_id = in_data[evt.index[0]][0]
model_id = in_data[evt.index[0]][1]
data3 = []
for model in data:
if model['id'] == model_id:
for variant in model['modelVersions']:
if variant['id'] == variant_id:
for f in variant['files']:
data3.append([
f['name'],
round(f['sizeKB']),
json.dumps(f['metadata']),
f['downloadUrl'],
])
log.debug(f'CivitAI select: model={in_data[evt.index[0]]} files={len(data3)}')
return data3
def civit_select3(evt: gr.SelectData, in_data):
log.debug(f'CivitAI select: variant={in_data[evt.index[0]]}')
return in_data[evt.index[0]][3], in_data[evt.index[0]][0], gr.update(interactive=True)
def civit_download_model(model_url: str, model_name: str, model_path: str, image_url: str):
if model_url is None or len(model_url) == 0:
return 'No model selected'
try:
from modules.modelloader import download_civit_model
res = download_civit_model(model_url, model_name, model_path, image_url)
except Exception as e:
res = f"CivitAI model downloaded error: model={model_url} {e}"
log.error(res)
return res
from modules.sd_models import list_models # pylint: disable=W0621
list_models()
return res
with gr.Row():
with gr.Column(scale=1):
civit_model_type = gr.Dropdown(label='Model type', choices=['SD 1.5', 'SD XL', 'Other'], value='SD 1.5')
with gr.Column(scale=15):
with gr.Row():
civit_search_text = gr.Textbox('', label = 'Seach models', placeholder='keyword')
civit_search_tag = gr.Textbox('', label = '', placeholder='tags')
civit_search_btn = ToolButton(value="🔍", label="Search", interactive=False)
with gr.Row():
civit_download_model_btn = gr.Button(value="Download model", variant='primary')
with gr.Row():
civit_name = gr.Textbox('', label = 'Model name', placeholder='select model from search results', visible=True)
civit_selected = gr.Textbox('', label = 'Model URL', placeholder='select model from search results', visible=True)
civit_path = gr.Textbox('', label = 'Download path', placeholder='optional subfolder path where to save model', visible=True)
with gr.Row():
with gr.Column():
civit_headers2 = ['ID', 'ModelID', 'Name', 'Base', 'Created', 'Preview']
civit_types2 = ['number', 'number', 'str', 'str', 'date', 'str']
civit_results2 = gr.DataFrame([], label = 'Model versions', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = civit_headers2, datatype = civit_types2, type='array')
with gr.Column():
civit_headers3 = ['Name', 'Size', 'Metadata', 'URL']
civit_types3 = ['str', 'number', 'str', 'str']
civit_results3 = gr.DataFrame([], label = 'Model variants', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = civit_headers3, datatype = civit_types3, type='array')
with gr.Row():
civit_headers1 = ['ID', 'Name', 'Tags', 'Downloads', 'Rating']
civit_types1 = ['number', 'str', 'str', 'number', 'number']
civit_results1 = gr.DataFrame([], label = 'Search results', show_label = True, interactive = False, wrap = True, overflow_row_behaviour = 'paginate', max_rows = 10, headers = civit_headers1, datatype = civit_types1, type='array')
civit_search_text.submit(fn=civit_search, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_results1, civit_results2, civit_results3])
civit_search_tag.submit(fn=civit_search, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_results1, civit_results2, civit_results3])
civit_search_btn.click(fn=civit_search, inputs=[civit_search_text, civit_search_tag, civit_model_type], outputs=[civit_results1, civit_results2, civit_results3])
civit_results1.select(fn=civit_select1, inputs=[civit_results1], outputs=[civit_results2, models_image])
civit_results2.select(fn=civit_select2, inputs=[civit_results2], outputs=[civit_results3])
civit_results3.select(fn=civit_select3, inputs=[civit_results3], outputs=[civit_selected, civit_name, civit_search_btn])
civit_download_model_btn.click(fn=civit_download_model, inputs=[civit_selected, civit_name, civit_path, models_image], outputs=[models_outcome])
+1
View File
@@ -47,6 +47,7 @@ ignore = [
"B905", # Without explicit scrict
"C408", # Rewrite as a literal
"E402", # Module level import not at top of file
"E721", # Do not compare types, use `isinstance()`
"F401", # Imported but unused
"EXE001", # Shebang present
"ISC003", # Implicit string concatenation
+2 -4
View File
@@ -4,7 +4,6 @@ aiohttp
anyio
appdirs
astunparse
bitsandbytes
blendmodes
clean-fid
easydev
@@ -41,7 +40,6 @@ voluptuous
yapf
scikit-image
basicsr
compel
fasteners
typing-extensions==4.7.1
antlr4-python3-runtime==4.9.3
@@ -54,8 +52,8 @@ einops==0.4.1
gradio==3.32.0
huggingface_hub==0.16.4
numexpr==2.8.4
numpy==1.23.5
numba==0.57.0
numpy==1.24.4
numba==0.57.1
pandas==1.5.3
protobuf==3.20.3
pytorch_lightning==1.9.4
-1
View File
@@ -2,7 +2,6 @@ import copy
import random
import shlex
import gradio as gr
from PIL import Image
import modules.scripts as scripts
from modules import sd_samplers, errors
from modules.processing import Processed, process_images
+2
View File
@@ -9,6 +9,7 @@ import logging
import warnings
import importlib
from threading import Thread
import urllib3
from modules import timer, errors, paths # pylint: disable=unused-import
startup_timer = timer.Timer()
@@ -20,6 +21,7 @@ try:
import intel_extension_for_pytorch as ipex # pylint: disable=import-error, unused-import
except Exception:
pass
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
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
if ".dev" in torch.__version__ or "+git" in torch.__version__:
+2 -2
View File
@@ -44,8 +44,8 @@ do
esac
done
# Do not run as root
if [[ $(id -u) -eq 0 && can_run_as_root -eq 0 ]]
# Do not run as root unless inside a Docker container
if [[ $(id -u) -eq 0 && can_run_as_root -eq 0 && ! -f /.dockerenv ]]
then
echo "Cannot run as root"
exit 1
+1 -1
Submodule wiki updated: 35142f02ae...7cc5b14e12