Spaces:
Running
Running
App update
Browse files- app.py +109 -9
- app_settings.py +23 -0
- backend/__pycache__/__init__.cpython-311.pyc +0 -0
- backend/__pycache__/image_saver.cpython-311.pyc +0 -0
- backend/__pycache__/lcm_text_to_image.cpython-311.pyc +0 -0
- backend/lcm_text_to_image.py +256 -44
- backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_ov_pipeline.cpython-311.pyc +0 -0
- backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_scheduler.cpython-311.pyc +0 -0
- backend/lcmdiffusion/pipelines/openvino/lcm_ov_pipeline.py +86 -29
- backend/lcmdiffusion/pipelines/openvino/lcm_scheduler.py +67 -20
- backend/models/__pycache__/lcmdiffusion_setting.cpython-311.pyc +0 -0
- backend/models/lcmdiffusion_setting.py +15 -5
- constants.py +8 -2
- context.py +13 -8
- frontend/__pycache__/utils.cpython-311.pyc +0 -0
- frontend/gui/__pycache__/app_window.cpython-311.pyc +0 -0
- frontend/gui/__pycache__/image_generator_worker.cpython-311.pyc +0 -0
- frontend/gui/__pycache__/ui.cpython-311.pyc +0 -0
- frontend/gui/app_window.py +177 -22
- frontend/utils.py +22 -4
- frontend/webui/text_to_image_ui.py +41 -49
- frontend/webui/ui.py +2 -2
- models/__pycache__/interface_types.cpython-311.pyc +0 -0
- models/__pycache__/settings.cpython-311.pyc +0 -0
- models/settings.py +2 -2
- paths.py +11 -2
- utils.py +11 -0
app.py
CHANGED
|
@@ -6,7 +6,7 @@ from context import Context
|
|
| 6 |
from constants import APP_VERSION, LCM_DEFAULT_MODEL_OPENVINO
|
| 7 |
from models.interface_types import InterfaceType
|
| 8 |
from constants import DEVICE
|
| 9 |
-
|
| 10 |
parser = ArgumentParser(description=f"FAST SD CPU {constants.APP_VERSION}")
|
| 11 |
parser.add_argument(
|
| 12 |
"-s",
|
|
@@ -28,6 +28,12 @@ group.add_argument(
|
|
| 28 |
action="store_true",
|
| 29 |
help="Start Web UI",
|
| 30 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
group.add_argument(
|
| 32 |
"-v",
|
| 33 |
"--version",
|
|
@@ -66,8 +72,8 @@ parser.add_argument(
|
|
| 66 |
parser.add_argument(
|
| 67 |
"--guidance_scale",
|
| 68 |
type=int,
|
| 69 |
-
help="Guidance scale,default :
|
| 70 |
-
default=
|
| 71 |
)
|
| 72 |
|
| 73 |
parser.add_argument(
|
|
@@ -98,28 +104,122 @@ parser.add_argument(
|
|
| 98 |
action="store_false",
|
| 99 |
help="Use safety checker",
|
| 100 |
)
|
| 101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
parser.add_argument(
|
| 103 |
"-i",
|
| 104 |
"--interactive",
|
| 105 |
action="store_true",
|
| 106 |
help="Interactive CLI mode",
|
| 107 |
)
|
| 108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
args = parser.parse_args()
|
| 110 |
|
| 111 |
if args.version:
|
| 112 |
print(APP_VERSION)
|
| 113 |
exit()
|
| 114 |
|
| 115 |
-
parser.print_help()
|
| 116 |
show_system_info()
|
| 117 |
print(f"Using device : {constants.DEVICE}")
|
| 118 |
-
|
| 119 |
app_settings = AppSettings()
|
| 120 |
app_settings.load()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
|
| 123 |
-
|
|
|
|
| 124 |
app_settings,
|
| 125 |
-
args.share,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
from constants import APP_VERSION, LCM_DEFAULT_MODEL_OPENVINO
|
| 7 |
from models.interface_types import InterfaceType
|
| 8 |
from constants import DEVICE
|
| 9 |
+
|
| 10 |
parser = ArgumentParser(description=f"FAST SD CPU {constants.APP_VERSION}")
|
| 11 |
parser.add_argument(
|
| 12 |
"-s",
|
|
|
|
| 28 |
action="store_true",
|
| 29 |
help="Start Web UI",
|
| 30 |
)
|
| 31 |
+
group.add_argument(
|
| 32 |
+
"-r",
|
| 33 |
+
"--realtime",
|
| 34 |
+
action="store_true",
|
| 35 |
+
help="Start realtime inference UI(experimental)",
|
| 36 |
+
)
|
| 37 |
group.add_argument(
|
| 38 |
"-v",
|
| 39 |
"--version",
|
|
|
|
| 72 |
parser.add_argument(
|
| 73 |
"--guidance_scale",
|
| 74 |
type=int,
|
| 75 |
+
help="Guidance scale,default : 1.0",
|
| 76 |
+
default=1.0,
|
| 77 |
)
|
| 78 |
|
| 79 |
parser.add_argument(
|
|
|
|
| 104 |
action="store_false",
|
| 105 |
help="Use safety checker",
|
| 106 |
)
|
| 107 |
+
parser.add_argument(
|
| 108 |
+
"--use_lcm_lora",
|
| 109 |
+
action="store_true",
|
| 110 |
+
help="Use LCM-LoRA",
|
| 111 |
+
)
|
| 112 |
+
parser.add_argument(
|
| 113 |
+
"--base_model_id",
|
| 114 |
+
type=str,
|
| 115 |
+
help="LCM LoRA base model ID,Default Lykon/dreamshaper-8",
|
| 116 |
+
default="Lykon/dreamshaper-8",
|
| 117 |
+
)
|
| 118 |
+
parser.add_argument(
|
| 119 |
+
"--lcm_lora_id",
|
| 120 |
+
type=str,
|
| 121 |
+
help="LCM LoRA model ID,Default latent-consistency/lcm-lora-sdv1-5",
|
| 122 |
+
default="latent-consistency/lcm-lora-sdv1-5",
|
| 123 |
+
)
|
| 124 |
parser.add_argument(
|
| 125 |
"-i",
|
| 126 |
"--interactive",
|
| 127 |
action="store_true",
|
| 128 |
help="Interactive CLI mode",
|
| 129 |
)
|
| 130 |
+
parser.add_argument(
|
| 131 |
+
"--use_tiny_auto_encoder",
|
| 132 |
+
action="store_true",
|
| 133 |
+
help="Use tiny auto encoder for SD (TAESD)",
|
| 134 |
+
)
|
| 135 |
args = parser.parse_args()
|
| 136 |
|
| 137 |
if args.version:
|
| 138 |
print(APP_VERSION)
|
| 139 |
exit()
|
| 140 |
|
| 141 |
+
# parser.print_help()
|
| 142 |
show_system_info()
|
| 143 |
print(f"Using device : {constants.DEVICE}")
|
|
|
|
| 144 |
app_settings = AppSettings()
|
| 145 |
app_settings.load()
|
| 146 |
+
print(
|
| 147 |
+
f"Found {len(app_settings.stable_diffsuion_models)} stable diffusion models in config/stable-diffusion-models.txt"
|
| 148 |
+
)
|
| 149 |
+
print(
|
| 150 |
+
f"Found {len(app_settings.lcm_lora_models)} LCM-LoRA models in config/lcm-lora-models.txt"
|
| 151 |
+
)
|
| 152 |
+
print(
|
| 153 |
+
f"Found {len(app_settings.openvino_lcm_models)} OpenVINO LCM models in config/openvino-lcm-models.txt"
|
| 154 |
+
)
|
| 155 |
+
if args.gui:
|
| 156 |
+
from frontend.gui.ui import start_gui
|
| 157 |
|
| 158 |
+
print("Starting desktop GUI mode(Qt)")
|
| 159 |
+
start_gui(
|
| 160 |
+
[],
|
| 161 |
+
app_settings,
|
| 162 |
+
)
|
| 163 |
+
elif args.webui:
|
| 164 |
+
from frontend.webui.ui import start_webui
|
| 165 |
|
| 166 |
+
print("Starting web UI mode")
|
| 167 |
+
start_webui(
|
| 168 |
app_settings,
|
| 169 |
+
args.share,
|
| 170 |
+
)
|
| 171 |
+
elif args.realtime:
|
| 172 |
+
from frontend.webui.realtime_ui import start_realtime_text_to_image
|
| 173 |
+
|
| 174 |
+
print("Starting realtime text to image(EXPERIMENTAL)")
|
| 175 |
+
start_realtime_text_to_image(args.share)
|
| 176 |
+
else:
|
| 177 |
+
context = Context(InterfaceType.CLI)
|
| 178 |
+
config = app_settings.settings
|
| 179 |
+
|
| 180 |
+
if args.use_openvino:
|
| 181 |
+
config.lcm_diffusion_setting.lcm_model_id = LCM_DEFAULT_MODEL_OPENVINO
|
| 182 |
+
else:
|
| 183 |
+
config.lcm_diffusion_setting.lcm_model_id = args.lcm_model_id
|
| 184 |
+
|
| 185 |
+
config.lcm_diffusion_setting.prompt = args.prompt
|
| 186 |
+
config.lcm_diffusion_setting.image_height = args.image_height
|
| 187 |
+
config.lcm_diffusion_setting.image_width = args.image_width
|
| 188 |
+
config.lcm_diffusion_setting.guidance_scale = args.guidance_scale
|
| 189 |
+
config.lcm_diffusion_setting.number_of_images = args.number_of_images
|
| 190 |
+
config.lcm_diffusion_setting.seed = args.seed
|
| 191 |
+
config.lcm_diffusion_setting.use_openvino = args.use_openvino
|
| 192 |
+
config.lcm_diffusion_setting.use_tiny_auto_encoder = args.use_tiny_auto_encoder
|
| 193 |
+
config.lcm_diffusion_setting.use_lcm_lora = args.use_lcm_lora
|
| 194 |
+
config.lcm_diffusion_setting.lcm_lora.base_model_id = args.base_model_id
|
| 195 |
+
config.lcm_diffusion_setting.lcm_lora.lcm_lora_id = args.lcm_lora_id
|
| 196 |
+
|
| 197 |
+
if args.seed > -1:
|
| 198 |
+
config.lcm_diffusion_setting.use_seed = True
|
| 199 |
+
else:
|
| 200 |
+
config.lcm_diffusion_setting.use_seed = False
|
| 201 |
+
config.lcm_diffusion_setting.use_offline_model = args.use_offline_model
|
| 202 |
+
config.lcm_diffusion_setting.use_safety_checker = args.use_safety_checker
|
| 203 |
+
|
| 204 |
+
if args.interactive:
|
| 205 |
+
while True:
|
| 206 |
+
user_input = input(">>")
|
| 207 |
+
if user_input == "exit":
|
| 208 |
+
break
|
| 209 |
+
config.lcm_diffusion_setting.prompt = user_input
|
| 210 |
+
context.generate_text_to_image(
|
| 211 |
+
settings=config,
|
| 212 |
+
device=DEVICE,
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
else:
|
| 216 |
+
context.generate_text_to_image(
|
| 217 |
+
settings=config,
|
| 218 |
+
device=DEVICE,
|
| 219 |
+
)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
from frontend.webui.hf_demo import start_demo_text_to_image
|
| 223 |
+
|
| 224 |
+
print("Starting demo text to image")
|
| 225 |
+
start_demo_text_to_image(True)
|
app_settings.py
CHANGED
|
@@ -2,16 +2,39 @@ import yaml
|
|
| 2 |
from os import path, makedirs
|
| 3 |
from models.settings import Settings
|
| 4 |
from paths import FastStableDiffusionPaths
|
|
|
|
|
|
|
| 5 |
|
| 6 |
|
| 7 |
class AppSettings:
|
| 8 |
def __init__(self):
|
| 9 |
self.config_path = FastStableDiffusionPaths().get_app_settings_path()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
@property
|
| 12 |
def settings(self):
|
| 13 |
return self._config
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
def load(self):
|
| 16 |
if not path.exists(self.config_path):
|
| 17 |
base_dir = path.dirname(self.config_path)
|
|
|
|
| 2 |
from os import path, makedirs
|
| 3 |
from models.settings import Settings
|
| 4 |
from paths import FastStableDiffusionPaths
|
| 5 |
+
from utils import get_models_from_text_file
|
| 6 |
+
from constants import OPENVINO_LCM_MODELS_FILE, LCM_LORA_MODELS_FILE, SD_MODELS_FILE
|
| 7 |
|
| 8 |
|
| 9 |
class AppSettings:
|
| 10 |
def __init__(self):
|
| 11 |
self.config_path = FastStableDiffusionPaths().get_app_settings_path()
|
| 12 |
+
self._stable_diffsuion_models = get_models_from_text_file(
|
| 13 |
+
FastStableDiffusionPaths().get_models_config_path(SD_MODELS_FILE)
|
| 14 |
+
)
|
| 15 |
+
self._lcm_lora_models = get_models_from_text_file(
|
| 16 |
+
FastStableDiffusionPaths().get_models_config_path(LCM_LORA_MODELS_FILE)
|
| 17 |
+
)
|
| 18 |
+
self._openvino_lcm_models = get_models_from_text_file(
|
| 19 |
+
FastStableDiffusionPaths().get_models_config_path(OPENVINO_LCM_MODELS_FILE)
|
| 20 |
+
)
|
| 21 |
|
| 22 |
@property
|
| 23 |
def settings(self):
|
| 24 |
return self._config
|
| 25 |
|
| 26 |
+
@property
|
| 27 |
+
def stable_diffsuion_models(self):
|
| 28 |
+
return self._stable_diffsuion_models
|
| 29 |
+
|
| 30 |
+
@property
|
| 31 |
+
def openvino_lcm_models(self):
|
| 32 |
+
return self._openvino_lcm_models
|
| 33 |
+
|
| 34 |
+
@property
|
| 35 |
+
def lcm_lora_models(self):
|
| 36 |
+
return self._lcm_lora_models
|
| 37 |
+
|
| 38 |
def load(self):
|
| 39 |
if not path.exists(self.config_path):
|
| 40 |
base_dir = path.dirname(self.config_path)
|
backend/__pycache__/__init__.cpython-311.pyc
CHANGED
|
Binary files a/backend/__pycache__/__init__.cpython-311.pyc and b/backend/__pycache__/__init__.cpython-311.pyc differ
|
|
|
backend/__pycache__/image_saver.cpython-311.pyc
CHANGED
|
Binary files a/backend/__pycache__/image_saver.cpython-311.pyc and b/backend/__pycache__/image_saver.cpython-311.pyc differ
|
|
|
backend/__pycache__/lcm_text_to_image.cpython-311.pyc
CHANGED
|
Binary files a/backend/__pycache__/lcm_text_to_image.cpython-311.pyc and b/backend/__pycache__/lcm_text_to_image.cpython-311.pyc differ
|
|
|
backend/lcm_text_to_image.py
CHANGED
|
@@ -1,20 +1,53 @@
|
|
| 1 |
from typing import Any
|
| 2 |
-
from diffusers import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
from os import path
|
| 4 |
import torch
|
| 5 |
from backend.models.lcmdiffusion_setting import LCMDiffusionSetting
|
| 6 |
import numpy as np
|
| 7 |
-
from constants import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
-
|
| 11 |
from backend.lcmdiffusion.pipelines.openvino.lcm_ov_pipeline import (
|
| 12 |
-
|
| 13 |
)
|
| 14 |
from backend.lcmdiffusion.pipelines.openvino.lcm_scheduler import (
|
| 15 |
-
LCMScheduler,
|
| 16 |
)
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
class LCMTextToImage:
|
| 20 |
def __init__(
|
|
@@ -23,18 +56,125 @@ class LCMTextToImage:
|
|
| 23 |
) -> None:
|
| 24 |
self.pipeline = None
|
| 25 |
self.use_openvino = False
|
| 26 |
-
self.device =
|
| 27 |
self.previous_model_id = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
)
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
def init(
|
| 40 |
self,
|
|
@@ -42,44 +182,97 @@ class LCMTextToImage:
|
|
| 42 |
use_openvino: bool = False,
|
| 43 |
device: str = "cpu",
|
| 44 |
use_local_model: bool = False,
|
|
|
|
|
|
|
|
|
|
| 45 |
) -> None:
|
| 46 |
self.device = device
|
| 47 |
self.use_openvino = use_openvino
|
| 48 |
-
if
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
if self.pipeline:
|
| 51 |
del self.pipeline
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
)
|
| 56 |
-
self.pipeline = OVLatentConsistencyModelPipeline.from_pretrained(
|
| 57 |
model_id,
|
| 58 |
-
scheduler=scheduler,
|
| 59 |
-
compile=False,
|
| 60 |
local_files_only=use_local_model,
|
|
|
|
|
|
|
| 61 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
else:
|
| 63 |
if self.pipeline:
|
| 64 |
del self.pipeline
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
self.pipeline = DiffusionPipeline.from_pretrained(
|
| 67 |
-
model_id,
|
| 68 |
-
custom_pipeline=self._get_lcm_diffusion_pipeline_path(),
|
| 69 |
-
custom_revision="main",
|
| 70 |
-
local_files_only=use_local_model,
|
| 71 |
-
)
|
| 72 |
-
self.pipeline.to(
|
| 73 |
-
torch_device=self.device,
|
| 74 |
-
torch_dtype=torch.float32,
|
| 75 |
-
)
|
| 76 |
self.previous_model_id = model_id
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
def generate(
|
| 79 |
self,
|
| 80 |
lcm_diffusion_setting: LCMDiffusionSetting,
|
| 81 |
reshape: bool = False,
|
| 82 |
) -> Any:
|
|
|
|
| 83 |
if lcm_diffusion_setting.use_seed:
|
| 84 |
cur_seed = lcm_diffusion_setting.seed
|
| 85 |
if self.use_openvino:
|
|
@@ -87,12 +280,12 @@ class LCMTextToImage:
|
|
| 87 |
else:
|
| 88 |
torch.manual_seed(cur_seed)
|
| 89 |
|
| 90 |
-
if
|
| 91 |
print("Using OpenVINO")
|
| 92 |
if reshape:
|
| 93 |
print("Reshape and compile")
|
| 94 |
self.pipeline.reshape(
|
| 95 |
-
batch_size
|
| 96 |
height=lcm_diffusion_setting.image_height,
|
| 97 |
width=lcm_diffusion_setting.image_width,
|
| 98 |
num_images_per_prompt=lcm_diffusion_setting.number_of_images,
|
|
@@ -102,14 +295,33 @@ class LCMTextToImage:
|
|
| 102 |
if not lcm_diffusion_setting.use_safety_checker:
|
| 103 |
self.pipeline.safety_checker = None
|
| 104 |
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
|
| 115 |
return result_images
|
|
|
|
| 1 |
from typing import Any
|
| 2 |
+
from diffusers import (
|
| 3 |
+
DiffusionPipeline,
|
| 4 |
+
AutoencoderTiny,
|
| 5 |
+
LCMScheduler,
|
| 6 |
+
UNet2DConditionModel,
|
| 7 |
+
)
|
| 8 |
from os import path
|
| 9 |
import torch
|
| 10 |
from backend.models.lcmdiffusion_setting import LCMDiffusionSetting
|
| 11 |
import numpy as np
|
| 12 |
+
from constants import (
|
| 13 |
+
DEVICE,
|
| 14 |
+
LCM_DEFAULT_MODEL,
|
| 15 |
+
TAESD_MODEL,
|
| 16 |
+
TAESDXL_MODEL,
|
| 17 |
+
TAESD_MODEL_OPENVINO,
|
| 18 |
+
)
|
| 19 |
+
from huggingface_hub import model_info
|
| 20 |
+
from backend.models.lcmdiffusion_setting import LCMLora
|
| 21 |
+
from backend.device import is_openvino_device
|
| 22 |
|
| 23 |
+
if is_openvino_device():
|
| 24 |
+
from huggingface_hub import snapshot_download
|
| 25 |
+
from optimum.intel.openvino.modeling_diffusion import OVModelVaeDecoder, OVBaseModel
|
| 26 |
|
| 27 |
+
# from optimum.intel.openvino.modeling_diffusion import OVStableDiffusionPipeline
|
| 28 |
from backend.lcmdiffusion.pipelines.openvino.lcm_ov_pipeline import (
|
| 29 |
+
OVStableDiffusionPipeline,
|
| 30 |
)
|
| 31 |
from backend.lcmdiffusion.pipelines.openvino.lcm_scheduler import (
|
| 32 |
+
LCMScheduler as OpenVinoLCMscheduler,
|
| 33 |
)
|
| 34 |
|
| 35 |
+
class CustomOVModelVaeDecoder(OVModelVaeDecoder):
|
| 36 |
+
def __init__(
|
| 37 |
+
self,
|
| 38 |
+
model,
|
| 39 |
+
parent_model,
|
| 40 |
+
ov_config=None,
|
| 41 |
+
model_dir=None,
|
| 42 |
+
):
|
| 43 |
+
super(OVModelVaeDecoder, self).__init__(
|
| 44 |
+
model,
|
| 45 |
+
parent_model,
|
| 46 |
+
ov_config,
|
| 47 |
+
"vae_decoder",
|
| 48 |
+
model_dir,
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
|
| 52 |
class LCMTextToImage:
|
| 53 |
def __init__(
|
|
|
|
| 56 |
) -> None:
|
| 57 |
self.pipeline = None
|
| 58 |
self.use_openvino = False
|
| 59 |
+
self.device = ""
|
| 60 |
self.previous_model_id = None
|
| 61 |
+
self.previous_use_tae_sd = False
|
| 62 |
+
self.previous_use_lcm_lora = False
|
| 63 |
+
self.torch_data_type = (
|
| 64 |
+
torch.float32 if is_openvino_device() or DEVICE == "mps" else torch.float16
|
| 65 |
+
)
|
| 66 |
+
print(f"Torch datatype : {self.torch_data_type}")
|
| 67 |
+
|
| 68 |
+
def _get_lcm_pipeline(
|
| 69 |
+
self,
|
| 70 |
+
lcm_model_id: str,
|
| 71 |
+
base_model_id: str,
|
| 72 |
+
use_local_model: bool,
|
| 73 |
+
):
|
| 74 |
+
pipeline = None
|
| 75 |
+
unet = UNet2DConditionModel.from_pretrained(
|
| 76 |
+
lcm_model_id,
|
| 77 |
+
torch_dtype=torch.float32,
|
| 78 |
+
local_files_only=use_local_model
|
| 79 |
+
# resume_download=True,
|
| 80 |
+
)
|
| 81 |
+
pipeline = DiffusionPipeline.from_pretrained(
|
| 82 |
+
base_model_id,
|
| 83 |
+
unet=unet,
|
| 84 |
+
torch_dtype=torch.float32,
|
| 85 |
+
local_files_only=use_local_model
|
| 86 |
+
# resume_download=True,
|
| 87 |
+
)
|
| 88 |
+
pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
|
| 89 |
+
return pipeline
|
| 90 |
+
|
| 91 |
+
def get_tiny_decoder_vae_model(self) -> str:
|
| 92 |
+
pipeline_class = self.pipeline.__class__.__name__
|
| 93 |
+
print(f"Pipeline class : {pipeline_class}")
|
| 94 |
+
if (
|
| 95 |
+
pipeline_class == "LatentConsistencyModelPipeline"
|
| 96 |
+
or pipeline_class == "StableDiffusionPipeline"
|
| 97 |
+
):
|
| 98 |
+
return TAESD_MODEL
|
| 99 |
+
elif pipeline_class == "StableDiffusionXLPipeline":
|
| 100 |
+
return TAESDXL_MODEL
|
| 101 |
+
elif pipeline_class == "OVStableDiffusionPipeline":
|
| 102 |
+
return TAESD_MODEL_OPENVINO
|
| 103 |
+
|
| 104 |
+
def _get_lcm_model_pipeline(
|
| 105 |
+
self,
|
| 106 |
+
model_id: str,
|
| 107 |
+
use_local_model,
|
| 108 |
+
):
|
| 109 |
+
pipeline = None
|
| 110 |
+
if model_id == LCM_DEFAULT_MODEL:
|
| 111 |
+
pipeline = DiffusionPipeline.from_pretrained(
|
| 112 |
+
model_id,
|
| 113 |
+
local_files_only=use_local_model,
|
| 114 |
+
)
|
| 115 |
+
elif model_id == "latent-consistency/lcm-sdxl":
|
| 116 |
+
pipeline = self._get_lcm_pipeline(
|
| 117 |
+
model_id,
|
| 118 |
+
"stabilityai/stable-diffusion-xl-base-1.0",
|
| 119 |
+
use_local_model,
|
| 120 |
+
)
|
| 121 |
|
| 122 |
+
elif model_id == "latent-consistency/lcm-ssd-1b":
|
| 123 |
+
pipeline = self._get_lcm_pipeline(
|
| 124 |
+
model_id,
|
| 125 |
+
"segmind/SSD-1B",
|
| 126 |
+
use_local_model,
|
| 127 |
+
)
|
| 128 |
+
return pipeline
|
| 129 |
+
|
| 130 |
+
def _get_lcm_lora_pipeline(
|
| 131 |
+
self,
|
| 132 |
+
base_model_id: str,
|
| 133 |
+
lcm_lora_id: str,
|
| 134 |
+
use_local_model: bool,
|
| 135 |
+
):
|
| 136 |
+
pipeline = DiffusionPipeline.from_pretrained(
|
| 137 |
+
base_model_id,
|
| 138 |
+
torch_dtype=self.torch_data_type,
|
| 139 |
+
local_files_only=use_local_model,
|
| 140 |
)
|
| 141 |
+
pipeline.load_lora_weights(
|
| 142 |
+
lcm_lora_id,
|
| 143 |
+
local_files_only=use_local_model,
|
| 144 |
+
)
|
| 145 |
+
|
| 146 |
+
pipeline.scheduler = LCMScheduler.from_config(pipeline.scheduler.config)
|
| 147 |
+
|
| 148 |
+
pipeline.fuse_lora()
|
| 149 |
+
pipeline.unet.to(memory_format=torch.channels_last)
|
| 150 |
+
return pipeline
|
| 151 |
+
|
| 152 |
+
def _pipeline_to_device(self):
|
| 153 |
+
print(f"Pipeline device : {DEVICE}")
|
| 154 |
+
print(f"Pipeline dtype : {self.torch_data_type}")
|
| 155 |
+
self.pipeline.to(
|
| 156 |
+
torch_device=DEVICE,
|
| 157 |
+
torch_dtype=self.torch_data_type,
|
| 158 |
+
)
|
| 159 |
+
|
| 160 |
+
def _add_freeu(self):
|
| 161 |
+
pipeline_class = self.pipeline.__class__.__name__
|
| 162 |
+
if pipeline_class == "StableDiffusionPipeline":
|
| 163 |
+
print("Add FreeU - SD")
|
| 164 |
+
self.pipeline.enable_freeu(
|
| 165 |
+
s1=0.9,
|
| 166 |
+
s2=0.2,
|
| 167 |
+
b1=1.2,
|
| 168 |
+
b2=1.4,
|
| 169 |
+
)
|
| 170 |
+
elif pipeline_class == "StableDiffusionXLPipeline":
|
| 171 |
+
print("Add FreeU - SDXL")
|
| 172 |
+
self.pipeline.enable_freeu(
|
| 173 |
+
s1=0.6,
|
| 174 |
+
s2=0.4,
|
| 175 |
+
b1=1.1,
|
| 176 |
+
b2=1.2,
|
| 177 |
+
)
|
| 178 |
|
| 179 |
def init(
|
| 180 |
self,
|
|
|
|
| 182 |
use_openvino: bool = False,
|
| 183 |
device: str = "cpu",
|
| 184 |
use_local_model: bool = False,
|
| 185 |
+
use_tiny_auto_encoder: bool = False,
|
| 186 |
+
use_lora: bool = False,
|
| 187 |
+
lcm_lora: LCMLora = LCMLora(),
|
| 188 |
) -> None:
|
| 189 |
self.device = device
|
| 190 |
self.use_openvino = use_openvino
|
| 191 |
+
if (
|
| 192 |
+
self.pipeline is None
|
| 193 |
+
or self.previous_model_id != model_id
|
| 194 |
+
or self.previous_use_tae_sd != use_tiny_auto_encoder
|
| 195 |
+
or self.previous_lcm_lora_base_id != lcm_lora.base_model_id
|
| 196 |
+
or self.previous_lcm_lora_id != lcm_lora.lcm_lora_id
|
| 197 |
+
or self.previous_use_lcm_lora != use_lora
|
| 198 |
+
):
|
| 199 |
+
if self.use_openvino and is_openvino_device():
|
| 200 |
if self.pipeline:
|
| 201 |
del self.pipeline
|
| 202 |
+
self.pipeline = None
|
| 203 |
+
|
| 204 |
+
self.pipeline = OVStableDiffusionPipeline.from_pretrained(
|
|
|
|
|
|
|
| 205 |
model_id,
|
|
|
|
|
|
|
| 206 |
local_files_only=use_local_model,
|
| 207 |
+
ov_config={"CACHE_DIR": ""},
|
| 208 |
+
device=DEVICE.upper(),
|
| 209 |
)
|
| 210 |
+
|
| 211 |
+
if use_tiny_auto_encoder:
|
| 212 |
+
print("Using Tiny Auto Encoder (OpenVINO)")
|
| 213 |
+
taesd_dir = snapshot_download(
|
| 214 |
+
repo_id=self.get_tiny_decoder_vae_model(),
|
| 215 |
+
local_files_only=use_local_model,
|
| 216 |
+
)
|
| 217 |
+
self.pipeline.vae_decoder = CustomOVModelVaeDecoder(
|
| 218 |
+
model=OVBaseModel.load_model(
|
| 219 |
+
f"{taesd_dir}/vae_decoder/openvino_model.xml"
|
| 220 |
+
),
|
| 221 |
+
parent_model=self.pipeline,
|
| 222 |
+
model_dir=taesd_dir,
|
| 223 |
+
)
|
| 224 |
+
|
| 225 |
else:
|
| 226 |
if self.pipeline:
|
| 227 |
del self.pipeline
|
| 228 |
+
self.pipeline = None
|
| 229 |
+
|
| 230 |
+
if use_lora:
|
| 231 |
+
print("Init LCM-LoRA pipeline")
|
| 232 |
+
self.pipeline = self._get_lcm_lora_pipeline(
|
| 233 |
+
lcm_lora.base_model_id,
|
| 234 |
+
lcm_lora.lcm_lora_id,
|
| 235 |
+
use_local_model,
|
| 236 |
+
)
|
| 237 |
+
else:
|
| 238 |
+
print("Init LCM Model pipeline")
|
| 239 |
+
self.pipeline = self._get_lcm_model_pipeline(
|
| 240 |
+
model_id,
|
| 241 |
+
use_local_model,
|
| 242 |
+
)
|
| 243 |
+
|
| 244 |
+
if use_tiny_auto_encoder:
|
| 245 |
+
vae_model = self.get_tiny_decoder_vae_model()
|
| 246 |
+
print(f"Using Tiny Auto Encoder {vae_model}")
|
| 247 |
+
self.pipeline.vae = AutoencoderTiny.from_pretrained(
|
| 248 |
+
vae_model,
|
| 249 |
+
torch_dtype=torch.float32,
|
| 250 |
+
local_files_only=use_local_model,
|
| 251 |
+
)
|
| 252 |
+
|
| 253 |
+
self._pipeline_to_device()
|
| 254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
self.previous_model_id = model_id
|
| 256 |
+
self.previous_use_tae_sd = use_tiny_auto_encoder
|
| 257 |
+
self.previous_lcm_lora_base_id = lcm_lora.base_model_id
|
| 258 |
+
self.previous_lcm_lora_id = lcm_lora.lcm_lora_id
|
| 259 |
+
self.previous_use_lcm_lora = use_lora
|
| 260 |
+
print(f"Model :{model_id}")
|
| 261 |
+
print(f"Pipeline : {self.pipeline}")
|
| 262 |
+
self.pipeline.scheduler = LCMScheduler.from_config(
|
| 263 |
+
self.pipeline.scheduler.config,
|
| 264 |
+
beta_start=0.001,
|
| 265 |
+
beta_end=0.01,
|
| 266 |
+
)
|
| 267 |
+
if use_lora:
|
| 268 |
+
self._add_freeu()
|
| 269 |
|
| 270 |
def generate(
|
| 271 |
self,
|
| 272 |
lcm_diffusion_setting: LCMDiffusionSetting,
|
| 273 |
reshape: bool = False,
|
| 274 |
) -> Any:
|
| 275 |
+
guidance_scale = lcm_diffusion_setting.guidance_scale
|
| 276 |
if lcm_diffusion_setting.use_seed:
|
| 277 |
cur_seed = lcm_diffusion_setting.seed
|
| 278 |
if self.use_openvino:
|
|
|
|
| 280 |
else:
|
| 281 |
torch.manual_seed(cur_seed)
|
| 282 |
|
| 283 |
+
if lcm_diffusion_setting.use_openvino and is_openvino_device():
|
| 284 |
print("Using OpenVINO")
|
| 285 |
if reshape:
|
| 286 |
print("Reshape and compile")
|
| 287 |
self.pipeline.reshape(
|
| 288 |
+
batch_size=-1,
|
| 289 |
height=lcm_diffusion_setting.image_height,
|
| 290 |
width=lcm_diffusion_setting.image_width,
|
| 291 |
num_images_per_prompt=lcm_diffusion_setting.number_of_images,
|
|
|
|
| 295 |
if not lcm_diffusion_setting.use_safety_checker:
|
| 296 |
self.pipeline.safety_checker = None
|
| 297 |
|
| 298 |
+
if (
|
| 299 |
+
not lcm_diffusion_setting.use_lcm_lora
|
| 300 |
+
and not lcm_diffusion_setting.use_openvino
|
| 301 |
+
and lcm_diffusion_setting.guidance_scale != 1.0
|
| 302 |
+
):
|
| 303 |
+
print("Not using LCM-LoRA so setting guidance_scale 1.0")
|
| 304 |
+
guidance_scale = 1.0
|
| 305 |
+
|
| 306 |
+
if lcm_diffusion_setting.use_openvino:
|
| 307 |
+
result_images = self.pipeline(
|
| 308 |
+
prompt=lcm_diffusion_setting.prompt,
|
| 309 |
+
negative_prompt=lcm_diffusion_setting.negative_prompt,
|
| 310 |
+
num_inference_steps=lcm_diffusion_setting.inference_steps,
|
| 311 |
+
guidance_scale=guidance_scale,
|
| 312 |
+
width=lcm_diffusion_setting.image_width,
|
| 313 |
+
height=lcm_diffusion_setting.image_height,
|
| 314 |
+
num_images_per_prompt=lcm_diffusion_setting.number_of_images,
|
| 315 |
+
).images
|
| 316 |
+
else:
|
| 317 |
+
result_images = self.pipeline(
|
| 318 |
+
prompt=lcm_diffusion_setting.prompt,
|
| 319 |
+
negative_prompt=lcm_diffusion_setting.negative_prompt,
|
| 320 |
+
num_inference_steps=lcm_diffusion_setting.inference_steps,
|
| 321 |
+
guidance_scale=guidance_scale,
|
| 322 |
+
width=lcm_diffusion_setting.image_width,
|
| 323 |
+
height=lcm_diffusion_setting.image_height,
|
| 324 |
+
num_images_per_prompt=lcm_diffusion_setting.number_of_images,
|
| 325 |
+
).images
|
| 326 |
|
| 327 |
return result_images
|
backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_ov_pipeline.cpython-311.pyc
CHANGED
|
Binary files a/backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_ov_pipeline.cpython-311.pyc and b/backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_ov_pipeline.cpython-311.pyc differ
|
|
|
backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_scheduler.cpython-311.pyc
CHANGED
|
Binary files a/backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_scheduler.cpython-311.pyc and b/backend/lcmdiffusion/pipelines/openvino/__pycache__/lcm_scheduler.cpython-311.pyc differ
|
|
|
backend/lcmdiffusion/pipelines/openvino/lcm_ov_pipeline.py
CHANGED
|
@@ -11,7 +11,14 @@ import openvino
|
|
| 11 |
import torch
|
| 12 |
|
| 13 |
from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput
|
| 14 |
-
from optimum.intel.openvino.modeling_diffusion import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
from optimum.utils import (
|
| 16 |
DIFFUSION_MODEL_TEXT_ENCODER_2_SUBFOLDER,
|
| 17 |
DIFFUSION_MODEL_TEXT_ENCODER_SUBFOLDER,
|
|
@@ -22,8 +29,10 @@ from optimum.utils import (
|
|
| 22 |
|
| 23 |
|
| 24 |
from diffusers import logging
|
|
|
|
| 25 |
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
|
| 26 |
|
|
|
|
| 27 |
class LCMOVModelUnet(OVModelUnet):
|
| 28 |
def __call__(
|
| 29 |
self,
|
|
@@ -52,8 +61,8 @@ class LCMOVModelUnet(OVModelUnet):
|
|
| 52 |
outputs = self.request(inputs, shared_memory=True)
|
| 53 |
return list(outputs.values())
|
| 54 |
|
| 55 |
-
class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
| 56 |
|
|
|
|
| 57 |
def __init__(
|
| 58 |
self,
|
| 59 |
vae_decoder: openvino.runtime.Model,
|
|
@@ -78,20 +87,32 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 78 |
self.is_dynamic = dynamic_shapes
|
| 79 |
self.ov_config = ov_config if ov_config is not None else {}
|
| 80 |
self._model_save_dir = (
|
| 81 |
-
Path(model_save_dir.name)
|
|
|
|
|
|
|
| 82 |
)
|
| 83 |
self.vae_decoder = OVModelVaeDecoder(vae_decoder, self)
|
| 84 |
self.unet = LCMOVModelUnet(unet, self)
|
| 85 |
-
self.text_encoder =
|
|
|
|
|
|
|
| 86 |
self.text_encoder_2 = (
|
| 87 |
-
OVModelTextEncoder(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
if text_encoder_2 is not None
|
| 89 |
else None
|
| 90 |
)
|
| 91 |
-
self.vae_encoder =
|
|
|
|
|
|
|
| 92 |
|
| 93 |
if "block_out_channels" in self.vae_decoder.config:
|
| 94 |
-
self.vae_scale_factor = 2 ** (
|
|
|
|
|
|
|
| 95 |
else:
|
| 96 |
self.vae_scale_factor = 8
|
| 97 |
|
|
@@ -119,7 +140,9 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 119 |
}
|
| 120 |
for name in sub_models.keys():
|
| 121 |
self._internal_dict[name] = (
|
| 122 |
-
("optimum", sub_models[name].__class__.__name__)
|
|
|
|
|
|
|
| 123 |
)
|
| 124 |
|
| 125 |
self._internal_dict.pop("vae", None)
|
|
@@ -132,7 +155,7 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 132 |
width: int = -1,
|
| 133 |
num_images_per_prompt: int = -1,
|
| 134 |
tokenizer_max_length: int = -1,
|
| 135 |
-
):
|
| 136 |
if batch_size == -1 or num_images_per_prompt == -1:
|
| 137 |
batch_size = -1
|
| 138 |
else:
|
|
@@ -152,14 +175,17 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 152 |
if in_channels.is_dynamic:
|
| 153 |
logger.warning(
|
| 154 |
"Could not identify `in_channels` from the unet configuration, to statically reshape the unet please provide a configuration."
|
| 155 |
-
)
|
| 156 |
self.is_dynamic = True
|
| 157 |
-
|
| 158 |
shapes[inputs] = [batch_size, in_channels, height, width]
|
| 159 |
elif inputs.get_any_name() == "timestep_cond":
|
| 160 |
shapes[inputs] = [batch_size, inputs.get_partial_shape()[1]]
|
| 161 |
elif inputs.get_any_name() == "text_embeds":
|
| 162 |
-
shapes[inputs] = [
|
|
|
|
|
|
|
|
|
|
| 163 |
elif inputs.get_any_name() == "time_ids":
|
| 164 |
shapes[inputs] = [batch_size, inputs.get_partial_shape()[1]]
|
| 165 |
else:
|
|
@@ -180,10 +206,10 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 180 |
embedding vectors with shape `(len(timesteps), embedding_dim)`
|
| 181 |
"""
|
| 182 |
assert len(w.shape) == 1
|
| 183 |
-
w = w * 1000.
|
| 184 |
|
| 185 |
half_dim = embedding_dim // 2
|
| 186 |
-
emb = np.log(np.array(10000.)) / (half_dim - 1)
|
| 187 |
emb = np.exp(np.arange(half_dim, dtype=dtype) * -emb)
|
| 188 |
emb = w.astype(dtype)[:, None] * emb[None, :]
|
| 189 |
emb = np.concatenate([np.sin(emb), np.cos(emb)], axis=1)
|
|
@@ -276,7 +302,9 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 276 |
list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"
|
| 277 |
(nsfw) content, according to the `safety_checker`.
|
| 278 |
"""
|
| 279 |
-
height =
|
|
|
|
|
|
|
| 280 |
width = width or self.unet.config.get("sample_size", 64) * self.vae_scale_factor
|
| 281 |
|
| 282 |
# check inputs. Raise error if not correct
|
|
@@ -296,9 +324,11 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 296 |
generator = np.random
|
| 297 |
|
| 298 |
# Create torch.Generator instance with same state as np.random.RandomState
|
| 299 |
-
torch_generator = torch.Generator().manual_seed(
|
|
|
|
|
|
|
| 300 |
|
| 301 |
-
#do_classifier_free_guidance = guidance_scale > 1.0
|
| 302 |
|
| 303 |
# NOTE: when a LCM is distilled from an LDM via latent consistency distillation (Algorithm 1) with guided
|
| 304 |
# distillation, the forward pass of the LCM learns to approximate sampling from the LDM using CFG with the
|
|
@@ -313,7 +343,11 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 313 |
)
|
| 314 |
|
| 315 |
# set timesteps
|
| 316 |
-
self.scheduler.set_timesteps(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
timesteps = self.scheduler.timesteps
|
| 318 |
|
| 319 |
latents = self.prepare_latents(
|
|
@@ -328,7 +362,9 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 328 |
|
| 329 |
# Get Guidance Scale Embedding
|
| 330 |
w = np.tile(guidance_scale - 1, batch_size * num_images_per_prompt)
|
| 331 |
-
w_embedding = self.get_guidance_scale_embedding(
|
|
|
|
|
|
|
| 332 |
|
| 333 |
# Adapted from diffusers to extend it for other runtimes than ORT
|
| 334 |
timestep_dtype = self.unet.input_dtype.get("timestep", np.float32)
|
|
@@ -337,32 +373,46 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 337 |
# eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.
|
| 338 |
# eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502
|
| 339 |
# and should be between [0, 1]
|
| 340 |
-
accepts_eta = "eta" in set(
|
|
|
|
|
|
|
| 341 |
extra_step_kwargs = {}
|
| 342 |
if accepts_eta:
|
| 343 |
extra_step_kwargs["eta"] = eta
|
| 344 |
|
| 345 |
-
accepts_generator = "generator" in set(
|
|
|
|
|
|
|
| 346 |
if accepts_generator:
|
| 347 |
extra_step_kwargs["generator"] = torch_generator
|
| 348 |
|
| 349 |
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
| 350 |
for i, t in enumerate(self.progress_bar(timesteps)):
|
| 351 |
-
|
| 352 |
# predict the noise residual
|
| 353 |
timestep = np.array([t], dtype=timestep_dtype)
|
| 354 |
-
|
| 355 |
-
noise_pred = self.unet(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 356 |
|
| 357 |
# compute the previous noisy sample x_t -> x_t-1
|
| 358 |
latents, denoised = self.scheduler.step(
|
| 359 |
-
torch.from_numpy(noise_pred),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 360 |
)
|
| 361 |
|
| 362 |
latents, denoised = latents.numpy(), denoised.numpy()
|
| 363 |
|
| 364 |
# call the callback, if provided
|
| 365 |
-
if i == len(timesteps) - 1 or (
|
|
|
|
|
|
|
| 366 |
if callback is not None and i % callback_steps == 0:
|
| 367 |
callback(i, t, latents)
|
| 368 |
|
|
@@ -373,7 +423,10 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 373 |
denoised /= self.vae_decoder.config.get("scaling_factor", 0.18215)
|
| 374 |
# it seems likes there is a strange result for using half-precision vae decoder if batchsize>1
|
| 375 |
image = np.concatenate(
|
| 376 |
-
[
|
|
|
|
|
|
|
|
|
|
| 377 |
)
|
| 378 |
image, has_nsfw_concept = self.run_safety_checker(image)
|
| 379 |
|
|
@@ -382,9 +435,13 @@ class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
|
| 382 |
else:
|
| 383 |
do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]
|
| 384 |
|
| 385 |
-
image = self.image_processor.postprocess(
|
|
|
|
|
|
|
| 386 |
|
| 387 |
if not return_dict:
|
| 388 |
return (image, has_nsfw_concept)
|
| 389 |
|
| 390 |
-
return StableDiffusionPipelineOutput(
|
|
|
|
|
|
|
|
|
| 11 |
import torch
|
| 12 |
|
| 13 |
from diffusers.pipelines.stable_diffusion import StableDiffusionPipelineOutput
|
| 14 |
+
from optimum.intel.openvino.modeling_diffusion import (
|
| 15 |
+
OVStableDiffusionPipeline,
|
| 16 |
+
OVModelUnet,
|
| 17 |
+
OVModelVaeDecoder,
|
| 18 |
+
OVModelTextEncoder,
|
| 19 |
+
OVModelVaeEncoder,
|
| 20 |
+
VaeImageProcessor,
|
| 21 |
+
)
|
| 22 |
from optimum.utils import (
|
| 23 |
DIFFUSION_MODEL_TEXT_ENCODER_2_SUBFOLDER,
|
| 24 |
DIFFUSION_MODEL_TEXT_ENCODER_SUBFOLDER,
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
from diffusers import logging
|
| 32 |
+
|
| 33 |
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
|
| 34 |
|
| 35 |
+
|
| 36 |
class LCMOVModelUnet(OVModelUnet):
|
| 37 |
def __call__(
|
| 38 |
self,
|
|
|
|
| 61 |
outputs = self.request(inputs, shared_memory=True)
|
| 62 |
return list(outputs.values())
|
| 63 |
|
|
|
|
| 64 |
|
| 65 |
+
class OVLatentConsistencyModelPipeline(OVStableDiffusionPipeline):
|
| 66 |
def __init__(
|
| 67 |
self,
|
| 68 |
vae_decoder: openvino.runtime.Model,
|
|
|
|
| 87 |
self.is_dynamic = dynamic_shapes
|
| 88 |
self.ov_config = ov_config if ov_config is not None else {}
|
| 89 |
self._model_save_dir = (
|
| 90 |
+
Path(model_save_dir.name)
|
| 91 |
+
if isinstance(model_save_dir, TemporaryDirectory)
|
| 92 |
+
else model_save_dir
|
| 93 |
)
|
| 94 |
self.vae_decoder = OVModelVaeDecoder(vae_decoder, self)
|
| 95 |
self.unet = LCMOVModelUnet(unet, self)
|
| 96 |
+
self.text_encoder = (
|
| 97 |
+
OVModelTextEncoder(text_encoder, self) if text_encoder is not None else None
|
| 98 |
+
)
|
| 99 |
self.text_encoder_2 = (
|
| 100 |
+
OVModelTextEncoder(
|
| 101 |
+
text_encoder_2,
|
| 102 |
+
self,
|
| 103 |
+
model_name=DIFFUSION_MODEL_TEXT_ENCODER_2_SUBFOLDER,
|
| 104 |
+
)
|
| 105 |
if text_encoder_2 is not None
|
| 106 |
else None
|
| 107 |
)
|
| 108 |
+
self.vae_encoder = (
|
| 109 |
+
OVModelVaeEncoder(vae_encoder, self) if vae_encoder is not None else None
|
| 110 |
+
)
|
| 111 |
|
| 112 |
if "block_out_channels" in self.vae_decoder.config:
|
| 113 |
+
self.vae_scale_factor = 2 ** (
|
| 114 |
+
len(self.vae_decoder.config["block_out_channels"]) - 1
|
| 115 |
+
)
|
| 116 |
else:
|
| 117 |
self.vae_scale_factor = 8
|
| 118 |
|
|
|
|
| 140 |
}
|
| 141 |
for name in sub_models.keys():
|
| 142 |
self._internal_dict[name] = (
|
| 143 |
+
("optimum", sub_models[name].__class__.__name__)
|
| 144 |
+
if sub_models[name] is not None
|
| 145 |
+
else (None, None)
|
| 146 |
)
|
| 147 |
|
| 148 |
self._internal_dict.pop("vae", None)
|
|
|
|
| 155 |
width: int = -1,
|
| 156 |
num_images_per_prompt: int = -1,
|
| 157 |
tokenizer_max_length: int = -1,
|
| 158 |
+
):
|
| 159 |
if batch_size == -1 or num_images_per_prompt == -1:
|
| 160 |
batch_size = -1
|
| 161 |
else:
|
|
|
|
| 175 |
if in_channels.is_dynamic:
|
| 176 |
logger.warning(
|
| 177 |
"Could not identify `in_channels` from the unet configuration, to statically reshape the unet please provide a configuration."
|
| 178 |
+
)
|
| 179 |
self.is_dynamic = True
|
| 180 |
+
|
| 181 |
shapes[inputs] = [batch_size, in_channels, height, width]
|
| 182 |
elif inputs.get_any_name() == "timestep_cond":
|
| 183 |
shapes[inputs] = [batch_size, inputs.get_partial_shape()[1]]
|
| 184 |
elif inputs.get_any_name() == "text_embeds":
|
| 185 |
+
shapes[inputs] = [
|
| 186 |
+
batch_size,
|
| 187 |
+
self.text_encoder_2.config["projection_dim"],
|
| 188 |
+
]
|
| 189 |
elif inputs.get_any_name() == "time_ids":
|
| 190 |
shapes[inputs] = [batch_size, inputs.get_partial_shape()[1]]
|
| 191 |
else:
|
|
|
|
| 206 |
embedding vectors with shape `(len(timesteps), embedding_dim)`
|
| 207 |
"""
|
| 208 |
assert len(w.shape) == 1
|
| 209 |
+
w = w * 1000.0
|
| 210 |
|
| 211 |
half_dim = embedding_dim // 2
|
| 212 |
+
emb = np.log(np.array(10000.0)) / (half_dim - 1)
|
| 213 |
emb = np.exp(np.arange(half_dim, dtype=dtype) * -emb)
|
| 214 |
emb = w.astype(dtype)[:, None] * emb[None, :]
|
| 215 |
emb = np.concatenate([np.sin(emb), np.cos(emb)], axis=1)
|
|
|
|
| 302 |
list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"
|
| 303 |
(nsfw) content, according to the `safety_checker`.
|
| 304 |
"""
|
| 305 |
+
height = (
|
| 306 |
+
height or self.unet.config.get("sample_size", 64) * self.vae_scale_factor
|
| 307 |
+
)
|
| 308 |
width = width or self.unet.config.get("sample_size", 64) * self.vae_scale_factor
|
| 309 |
|
| 310 |
# check inputs. Raise error if not correct
|
|
|
|
| 324 |
generator = np.random
|
| 325 |
|
| 326 |
# Create torch.Generator instance with same state as np.random.RandomState
|
| 327 |
+
torch_generator = torch.Generator().manual_seed(
|
| 328 |
+
int(generator.get_state()[1][0])
|
| 329 |
+
)
|
| 330 |
|
| 331 |
+
# do_classifier_free_guidance = guidance_scale > 1.0
|
| 332 |
|
| 333 |
# NOTE: when a LCM is distilled from an LDM via latent consistency distillation (Algorithm 1) with guided
|
| 334 |
# distillation, the forward pass of the LCM learns to approximate sampling from the LDM using CFG with the
|
|
|
|
| 343 |
)
|
| 344 |
|
| 345 |
# set timesteps
|
| 346 |
+
self.scheduler.set_timesteps(
|
| 347 |
+
num_inference_steps,
|
| 348 |
+
"cpu",
|
| 349 |
+
original_inference_steps=original_inference_steps,
|
| 350 |
+
)
|
| 351 |
timesteps = self.scheduler.timesteps
|
| 352 |
|
| 353 |
latents = self.prepare_latents(
|
|
|
|
| 362 |
|
| 363 |
# Get Guidance Scale Embedding
|
| 364 |
w = np.tile(guidance_scale - 1, batch_size * num_images_per_prompt)
|
| 365 |
+
w_embedding = self.get_guidance_scale_embedding(
|
| 366 |
+
w, embedding_dim=self.unet.config.get("time_cond_proj_dim", 256)
|
| 367 |
+
)
|
| 368 |
|
| 369 |
# Adapted from diffusers to extend it for other runtimes than ORT
|
| 370 |
timestep_dtype = self.unet.input_dtype.get("timestep", np.float32)
|
|
|
|
| 373 |
# eta (η) is only used with the DDIMScheduler, it will be ignored for other schedulers.
|
| 374 |
# eta corresponds to η in DDIM paper: https://arxiv.org/abs/2010.02502
|
| 375 |
# and should be between [0, 1]
|
| 376 |
+
accepts_eta = "eta" in set(
|
| 377 |
+
inspect.signature(self.scheduler.step).parameters.keys()
|
| 378 |
+
)
|
| 379 |
extra_step_kwargs = {}
|
| 380 |
if accepts_eta:
|
| 381 |
extra_step_kwargs["eta"] = eta
|
| 382 |
|
| 383 |
+
accepts_generator = "generator" in set(
|
| 384 |
+
inspect.signature(self.scheduler.step).parameters.keys()
|
| 385 |
+
)
|
| 386 |
if accepts_generator:
|
| 387 |
extra_step_kwargs["generator"] = torch_generator
|
| 388 |
|
| 389 |
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
| 390 |
for i, t in enumerate(self.progress_bar(timesteps)):
|
|
|
|
| 391 |
# predict the noise residual
|
| 392 |
timestep = np.array([t], dtype=timestep_dtype)
|
| 393 |
+
|
| 394 |
+
noise_pred = self.unet(
|
| 395 |
+
sample=latents,
|
| 396 |
+
timestep=timestep,
|
| 397 |
+
timestep_cond=w_embedding,
|
| 398 |
+
encoder_hidden_states=prompt_embeds,
|
| 399 |
+
)[0]
|
| 400 |
|
| 401 |
# compute the previous noisy sample x_t -> x_t-1
|
| 402 |
latents, denoised = self.scheduler.step(
|
| 403 |
+
torch.from_numpy(noise_pred),
|
| 404 |
+
t,
|
| 405 |
+
torch.from_numpy(latents),
|
| 406 |
+
**extra_step_kwargs,
|
| 407 |
+
return_dict=False,
|
| 408 |
)
|
| 409 |
|
| 410 |
latents, denoised = latents.numpy(), denoised.numpy()
|
| 411 |
|
| 412 |
# call the callback, if provided
|
| 413 |
+
if i == len(timesteps) - 1 or (
|
| 414 |
+
(i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0
|
| 415 |
+
):
|
| 416 |
if callback is not None and i % callback_steps == 0:
|
| 417 |
callback(i, t, latents)
|
| 418 |
|
|
|
|
| 423 |
denoised /= self.vae_decoder.config.get("scaling_factor", 0.18215)
|
| 424 |
# it seems likes there is a strange result for using half-precision vae decoder if batchsize>1
|
| 425 |
image = np.concatenate(
|
| 426 |
+
[
|
| 427 |
+
self.vae_decoder(latent_sample=denoised[i : i + 1])[0]
|
| 428 |
+
for i in range(latents.shape[0])
|
| 429 |
+
]
|
| 430 |
)
|
| 431 |
image, has_nsfw_concept = self.run_safety_checker(image)
|
| 432 |
|
|
|
|
| 435 |
else:
|
| 436 |
do_denormalize = [not has_nsfw for has_nsfw in has_nsfw_concept]
|
| 437 |
|
| 438 |
+
image = self.image_processor.postprocess(
|
| 439 |
+
image, output_type=output_type, do_denormalize=do_denormalize
|
| 440 |
+
)
|
| 441 |
|
| 442 |
if not return_dict:
|
| 443 |
return (image, has_nsfw_concept)
|
| 444 |
|
| 445 |
+
return StableDiffusionPipelineOutput(
|
| 446 |
+
images=image, nsfw_content_detected=has_nsfw_concept
|
| 447 |
+
)
|
backend/lcmdiffusion/pipelines/openvino/lcm_scheduler.py
CHANGED
|
@@ -213,17 +213,27 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 213 |
if trained_betas is not None:
|
| 214 |
self.betas = torch.tensor(trained_betas, dtype=torch.float32)
|
| 215 |
elif beta_schedule == "linear":
|
| 216 |
-
self.betas = torch.linspace(
|
|
|
|
|
|
|
| 217 |
elif beta_schedule == "scaled_linear":
|
| 218 |
# this schedule is very specific to the latent diffusion model.
|
| 219 |
self.betas = (
|
| 220 |
-
torch.linspace(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
)
|
| 222 |
elif beta_schedule == "squaredcos_cap_v2":
|
| 223 |
# Glide cosine schedule
|
| 224 |
self.betas = betas_for_alpha_bar(num_train_timesteps)
|
| 225 |
else:
|
| 226 |
-
raise NotImplementedError(
|
|
|
|
|
|
|
| 227 |
|
| 228 |
# Rescale for zero SNR
|
| 229 |
if rescale_betas_zero_snr:
|
|
@@ -236,14 +246,18 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 236 |
# For the final step, there is no previous alphas_cumprod because we are already at 0
|
| 237 |
# `set_alpha_to_one` decides whether we set this parameter simply to one or
|
| 238 |
# whether we use the final alpha of the "non-previous" one.
|
| 239 |
-
self.final_alpha_cumprod =
|
|
|
|
|
|
|
| 240 |
|
| 241 |
# standard deviation of the initial noise distribution
|
| 242 |
self.init_noise_sigma = 1.0
|
| 243 |
|
| 244 |
# setable values
|
| 245 |
self.num_inference_steps = None
|
| 246 |
-
self.timesteps = torch.from_numpy(
|
|
|
|
|
|
|
| 247 |
|
| 248 |
self._step_index = None
|
| 249 |
|
|
@@ -269,7 +283,9 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 269 |
def step_index(self):
|
| 270 |
return self._step_index
|
| 271 |
|
| 272 |
-
def scale_model_input(
|
|
|
|
|
|
|
| 273 |
"""
|
| 274 |
Ensures interchangeability with schedulers that need to scale the denoising model input depending on the
|
| 275 |
current timestep.
|
|
@@ -300,7 +316,9 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 300 |
batch_size, channels, *remaining_dims = sample.shape
|
| 301 |
|
| 302 |
if dtype not in (torch.float32, torch.float64):
|
| 303 |
-
sample =
|
|
|
|
|
|
|
| 304 |
|
| 305 |
# Flatten sample for doing quantile calculation along each image
|
| 306 |
sample = sample.reshape(batch_size, channels * np.prod(remaining_dims))
|
|
@@ -312,7 +330,9 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 312 |
s, min=1, max=self.config.sample_max_value
|
| 313 |
) # When clamped to min=1, equivalent to standard clipping to [-1, 1]
|
| 314 |
s = s.unsqueeze(1) # (batch_size, 1) because clamp will broadcast along dim=0
|
| 315 |
-
sample =
|
|
|
|
|
|
|
| 316 |
|
| 317 |
sample = sample.reshape(batch_size, channels, *remaining_dims)
|
| 318 |
sample = sample.to(dtype)
|
|
@@ -349,7 +369,9 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 349 |
|
| 350 |
self.num_inference_steps = num_inference_steps
|
| 351 |
original_steps = (
|
| 352 |
-
original_inference_steps
|
|
|
|
|
|
|
| 353 |
)
|
| 354 |
|
| 355 |
if original_steps > self.config.num_train_timesteps:
|
|
@@ -375,7 +397,9 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 375 |
# LCM Inference Steps Schedule
|
| 376 |
timesteps = lcm_origin_timesteps[::-skipping_step][:num_inference_steps]
|
| 377 |
|
| 378 |
-
self.timesteps = torch.from_numpy(timesteps.copy()).to(
|
|
|
|
|
|
|
| 379 |
|
| 380 |
self._step_index = None
|
| 381 |
|
|
@@ -432,7 +456,11 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 432 |
|
| 433 |
# 2. compute alphas, betas
|
| 434 |
alpha_prod_t = self.alphas_cumprod[timestep]
|
| 435 |
-
alpha_prod_t_prev =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 436 |
|
| 437 |
beta_prod_t = 1 - alpha_prod_t
|
| 438 |
beta_prod_t_prev = 1 - alpha_prod_t_prev
|
|
@@ -442,11 +470,15 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 442 |
|
| 443 |
# 4. Compute the predicted original sample x_0 based on the model parameterization
|
| 444 |
if self.config.prediction_type == "epsilon": # noise-prediction
|
| 445 |
-
predicted_original_sample = (
|
|
|
|
|
|
|
| 446 |
elif self.config.prediction_type == "sample": # x-prediction
|
| 447 |
predicted_original_sample = model_output
|
| 448 |
elif self.config.prediction_type == "v_prediction": # v-prediction
|
| 449 |
-
predicted_original_sample =
|
|
|
|
|
|
|
| 450 |
else:
|
| 451 |
raise ValueError(
|
| 452 |
f"prediction_type given as {self.config.prediction_type} must be one of `epsilon`, `sample` or"
|
|
@@ -455,7 +487,9 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 455 |
|
| 456 |
# 5. Clip or threshold "predicted x_0"
|
| 457 |
if self.config.thresholding:
|
| 458 |
-
predicted_original_sample = self._threshold_sample(
|
|
|
|
|
|
|
| 459 |
elif self.config.clip_sample:
|
| 460 |
predicted_original_sample = predicted_original_sample.clamp(
|
| 461 |
-self.config.clip_sample_range, self.config.clip_sample_range
|
|
@@ -467,8 +501,12 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 467 |
# 7. Sample and inject noise z ~ N(0, I) for MultiStep Inference
|
| 468 |
# Noise is not used for one-step sampling.
|
| 469 |
if len(self.timesteps) > 1:
|
| 470 |
-
noise = randn_tensor(
|
| 471 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
else:
|
| 473 |
prev_sample = denoised
|
| 474 |
|
|
@@ -488,7 +526,9 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 488 |
timesteps: torch.IntTensor,
|
| 489 |
) -> torch.FloatTensor:
|
| 490 |
# Make sure alphas_cumprod and timestep have same device and dtype as original_samples
|
| 491 |
-
alphas_cumprod = self.alphas_cumprod.to(
|
|
|
|
|
|
|
| 492 |
timesteps = timesteps.to(original_samples.device)
|
| 493 |
|
| 494 |
sqrt_alpha_prod = alphas_cumprod[timesteps] ** 0.5
|
|
@@ -501,15 +541,22 @@ class LCMScheduler(SchedulerMixin, ConfigMixin):
|
|
| 501 |
while len(sqrt_one_minus_alpha_prod.shape) < len(original_samples.shape):
|
| 502 |
sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.unsqueeze(-1)
|
| 503 |
|
| 504 |
-
noisy_samples =
|
|
|
|
|
|
|
| 505 |
return noisy_samples
|
| 506 |
|
| 507 |
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler.get_velocity
|
| 508 |
def get_velocity(
|
| 509 |
-
self,
|
|
|
|
|
|
|
|
|
|
| 510 |
) -> torch.FloatTensor:
|
| 511 |
# Make sure alphas_cumprod and timestep have same device and dtype as sample
|
| 512 |
-
alphas_cumprod = self.alphas_cumprod.to(
|
|
|
|
|
|
|
| 513 |
timesteps = timesteps.to(sample.device)
|
| 514 |
|
| 515 |
sqrt_alpha_prod = alphas_cumprod[timesteps] ** 0.5
|
|
|
|
| 213 |
if trained_betas is not None:
|
| 214 |
self.betas = torch.tensor(trained_betas, dtype=torch.float32)
|
| 215 |
elif beta_schedule == "linear":
|
| 216 |
+
self.betas = torch.linspace(
|
| 217 |
+
beta_start, beta_end, num_train_timesteps, dtype=torch.float32
|
| 218 |
+
)
|
| 219 |
elif beta_schedule == "scaled_linear":
|
| 220 |
# this schedule is very specific to the latent diffusion model.
|
| 221 |
self.betas = (
|
| 222 |
+
torch.linspace(
|
| 223 |
+
beta_start**0.5,
|
| 224 |
+
beta_end**0.5,
|
| 225 |
+
num_train_timesteps,
|
| 226 |
+
dtype=torch.float32,
|
| 227 |
+
)
|
| 228 |
+
** 2
|
| 229 |
)
|
| 230 |
elif beta_schedule == "squaredcos_cap_v2":
|
| 231 |
# Glide cosine schedule
|
| 232 |
self.betas = betas_for_alpha_bar(num_train_timesteps)
|
| 233 |
else:
|
| 234 |
+
raise NotImplementedError(
|
| 235 |
+
f"{beta_schedule} does is not implemented for {self.__class__}"
|
| 236 |
+
)
|
| 237 |
|
| 238 |
# Rescale for zero SNR
|
| 239 |
if rescale_betas_zero_snr:
|
|
|
|
| 246 |
# For the final step, there is no previous alphas_cumprod because we are already at 0
|
| 247 |
# `set_alpha_to_one` decides whether we set this parameter simply to one or
|
| 248 |
# whether we use the final alpha of the "non-previous" one.
|
| 249 |
+
self.final_alpha_cumprod = (
|
| 250 |
+
torch.tensor(1.0) if set_alpha_to_one else self.alphas_cumprod[0]
|
| 251 |
+
)
|
| 252 |
|
| 253 |
# standard deviation of the initial noise distribution
|
| 254 |
self.init_noise_sigma = 1.0
|
| 255 |
|
| 256 |
# setable values
|
| 257 |
self.num_inference_steps = None
|
| 258 |
+
self.timesteps = torch.from_numpy(
|
| 259 |
+
np.arange(0, num_train_timesteps)[::-1].copy().astype(np.int64)
|
| 260 |
+
)
|
| 261 |
|
| 262 |
self._step_index = None
|
| 263 |
|
|
|
|
| 283 |
def step_index(self):
|
| 284 |
return self._step_index
|
| 285 |
|
| 286 |
+
def scale_model_input(
|
| 287 |
+
self, sample: torch.FloatTensor, timestep: Optional[int] = None
|
| 288 |
+
) -> torch.FloatTensor:
|
| 289 |
"""
|
| 290 |
Ensures interchangeability with schedulers that need to scale the denoising model input depending on the
|
| 291 |
current timestep.
|
|
|
|
| 316 |
batch_size, channels, *remaining_dims = sample.shape
|
| 317 |
|
| 318 |
if dtype not in (torch.float32, torch.float64):
|
| 319 |
+
sample = (
|
| 320 |
+
sample.float()
|
| 321 |
+
) # upcast for quantile calculation, and clamp not implemented for cpu half
|
| 322 |
|
| 323 |
# Flatten sample for doing quantile calculation along each image
|
| 324 |
sample = sample.reshape(batch_size, channels * np.prod(remaining_dims))
|
|
|
|
| 330 |
s, min=1, max=self.config.sample_max_value
|
| 331 |
) # When clamped to min=1, equivalent to standard clipping to [-1, 1]
|
| 332 |
s = s.unsqueeze(1) # (batch_size, 1) because clamp will broadcast along dim=0
|
| 333 |
+
sample = (
|
| 334 |
+
torch.clamp(sample, -s, s) / s
|
| 335 |
+
) # "we threshold xt0 to the range [-s, s] and then divide by s"
|
| 336 |
|
| 337 |
sample = sample.reshape(batch_size, channels, *remaining_dims)
|
| 338 |
sample = sample.to(dtype)
|
|
|
|
| 369 |
|
| 370 |
self.num_inference_steps = num_inference_steps
|
| 371 |
original_steps = (
|
| 372 |
+
original_inference_steps
|
| 373 |
+
if original_inference_steps is not None
|
| 374 |
+
else self.original_inference_steps
|
| 375 |
)
|
| 376 |
|
| 377 |
if original_steps > self.config.num_train_timesteps:
|
|
|
|
| 397 |
# LCM Inference Steps Schedule
|
| 398 |
timesteps = lcm_origin_timesteps[::-skipping_step][:num_inference_steps]
|
| 399 |
|
| 400 |
+
self.timesteps = torch.from_numpy(timesteps.copy()).to(
|
| 401 |
+
device=device, dtype=torch.long
|
| 402 |
+
)
|
| 403 |
|
| 404 |
self._step_index = None
|
| 405 |
|
|
|
|
| 456 |
|
| 457 |
# 2. compute alphas, betas
|
| 458 |
alpha_prod_t = self.alphas_cumprod[timestep]
|
| 459 |
+
alpha_prod_t_prev = (
|
| 460 |
+
self.alphas_cumprod[prev_timestep]
|
| 461 |
+
if prev_timestep >= 0
|
| 462 |
+
else self.final_alpha_cumprod
|
| 463 |
+
)
|
| 464 |
|
| 465 |
beta_prod_t = 1 - alpha_prod_t
|
| 466 |
beta_prod_t_prev = 1 - alpha_prod_t_prev
|
|
|
|
| 470 |
|
| 471 |
# 4. Compute the predicted original sample x_0 based on the model parameterization
|
| 472 |
if self.config.prediction_type == "epsilon": # noise-prediction
|
| 473 |
+
predicted_original_sample = (
|
| 474 |
+
sample - beta_prod_t.sqrt() * model_output
|
| 475 |
+
) / alpha_prod_t.sqrt()
|
| 476 |
elif self.config.prediction_type == "sample": # x-prediction
|
| 477 |
predicted_original_sample = model_output
|
| 478 |
elif self.config.prediction_type == "v_prediction": # v-prediction
|
| 479 |
+
predicted_original_sample = (
|
| 480 |
+
alpha_prod_t.sqrt() * sample - beta_prod_t.sqrt() * model_output
|
| 481 |
+
)
|
| 482 |
else:
|
| 483 |
raise ValueError(
|
| 484 |
f"prediction_type given as {self.config.prediction_type} must be one of `epsilon`, `sample` or"
|
|
|
|
| 487 |
|
| 488 |
# 5. Clip or threshold "predicted x_0"
|
| 489 |
if self.config.thresholding:
|
| 490 |
+
predicted_original_sample = self._threshold_sample(
|
| 491 |
+
predicted_original_sample
|
| 492 |
+
)
|
| 493 |
elif self.config.clip_sample:
|
| 494 |
predicted_original_sample = predicted_original_sample.clamp(
|
| 495 |
-self.config.clip_sample_range, self.config.clip_sample_range
|
|
|
|
| 501 |
# 7. Sample and inject noise z ~ N(0, I) for MultiStep Inference
|
| 502 |
# Noise is not used for one-step sampling.
|
| 503 |
if len(self.timesteps) > 1:
|
| 504 |
+
noise = randn_tensor(
|
| 505 |
+
model_output.shape, generator=generator, device=model_output.device
|
| 506 |
+
)
|
| 507 |
+
prev_sample = (
|
| 508 |
+
alpha_prod_t_prev.sqrt() * denoised + beta_prod_t_prev.sqrt() * noise
|
| 509 |
+
)
|
| 510 |
else:
|
| 511 |
prev_sample = denoised
|
| 512 |
|
|
|
|
| 526 |
timesteps: torch.IntTensor,
|
| 527 |
) -> torch.FloatTensor:
|
| 528 |
# Make sure alphas_cumprod and timestep have same device and dtype as original_samples
|
| 529 |
+
alphas_cumprod = self.alphas_cumprod.to(
|
| 530 |
+
device=original_samples.device, dtype=original_samples.dtype
|
| 531 |
+
)
|
| 532 |
timesteps = timesteps.to(original_samples.device)
|
| 533 |
|
| 534 |
sqrt_alpha_prod = alphas_cumprod[timesteps] ** 0.5
|
|
|
|
| 541 |
while len(sqrt_one_minus_alpha_prod.shape) < len(original_samples.shape):
|
| 542 |
sqrt_one_minus_alpha_prod = sqrt_one_minus_alpha_prod.unsqueeze(-1)
|
| 543 |
|
| 544 |
+
noisy_samples = (
|
| 545 |
+
sqrt_alpha_prod * original_samples + sqrt_one_minus_alpha_prod * noise
|
| 546 |
+
)
|
| 547 |
return noisy_samples
|
| 548 |
|
| 549 |
# Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler.get_velocity
|
| 550 |
def get_velocity(
|
| 551 |
+
self,
|
| 552 |
+
sample: torch.FloatTensor,
|
| 553 |
+
noise: torch.FloatTensor,
|
| 554 |
+
timesteps: torch.IntTensor,
|
| 555 |
) -> torch.FloatTensor:
|
| 556 |
# Make sure alphas_cumprod and timestep have same device and dtype as sample
|
| 557 |
+
alphas_cumprod = self.alphas_cumprod.to(
|
| 558 |
+
device=sample.device, dtype=sample.dtype
|
| 559 |
+
)
|
| 560 |
timesteps = timesteps.to(sample.device)
|
| 561 |
|
| 562 |
sqrt_alpha_prod = alphas_cumprod[timesteps] ** 0.5
|
backend/models/__pycache__/lcmdiffusion_setting.cpython-311.pyc
CHANGED
|
Binary files a/backend/models/__pycache__/lcmdiffusion_setting.cpython-311.pyc and b/backend/models/__pycache__/lcmdiffusion_setting.cpython-311.pyc differ
|
|
|
backend/models/lcmdiffusion_setting.py
CHANGED
|
@@ -1,19 +1,29 @@
|
|
| 1 |
from typing import Optional
|
| 2 |
|
| 3 |
from pydantic import BaseModel
|
| 4 |
-
from constants import LCM_DEFAULT_MODEL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
|
| 7 |
class LCMDiffusionSetting(BaseModel):
|
| 8 |
lcm_model_id: str = LCM_DEFAULT_MODEL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
prompt: str = ""
|
|
|
|
| 10 |
image_height: Optional[int] = 512
|
| 11 |
image_width: Optional[int] = 512
|
| 12 |
inference_steps: Optional[int] = 4
|
| 13 |
-
guidance_scale: Optional[float] =
|
| 14 |
number_of_images: Optional[int] = 1
|
| 15 |
seed: Optional[int] = -1
|
| 16 |
-
use_openvino: bool = False
|
| 17 |
use_seed: bool = False
|
| 18 |
-
|
| 19 |
-
use_safety_checker: bool = True
|
|
|
|
| 1 |
from typing import Optional
|
| 2 |
|
| 3 |
from pydantic import BaseModel
|
| 4 |
+
from constants import LCM_DEFAULT_MODEL, LCM_DEFAULT_MODEL_OPENVINO
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class LCMLora(BaseModel):
|
| 8 |
+
base_model_id: str = ""
|
| 9 |
+
lcm_lora_id: str = ""
|
| 10 |
|
| 11 |
|
| 12 |
class LCMDiffusionSetting(BaseModel):
|
| 13 |
lcm_model_id: str = LCM_DEFAULT_MODEL
|
| 14 |
+
openvino_lcm_model_id: str = LCM_DEFAULT_MODEL_OPENVINO
|
| 15 |
+
use_offline_model: bool = False
|
| 16 |
+
use_lcm_lora: bool = False
|
| 17 |
+
lcm_lora: Optional[LCMLora] = LCMLora()
|
| 18 |
+
use_tiny_auto_encoder: bool = False
|
| 19 |
+
use_openvino: bool = False
|
| 20 |
prompt: str = ""
|
| 21 |
+
negative_prompt: str = ""
|
| 22 |
image_height: Optional[int] = 512
|
| 23 |
image_width: Optional[int] = 512
|
| 24 |
inference_steps: Optional[int] = 4
|
| 25 |
+
guidance_scale: Optional[float] = 1
|
| 26 |
number_of_images: Optional[int] = 1
|
| 27 |
seed: Optional[int] = -1
|
|
|
|
| 28 |
use_seed: bool = False
|
| 29 |
+
use_safety_checker: bool = False
|
|
|
constants.py
CHANGED
|
@@ -1,10 +1,16 @@
|
|
| 1 |
from os import environ
|
| 2 |
|
| 3 |
-
APP_VERSION = "v1.0.0 beta
|
| 4 |
LCM_DEFAULT_MODEL = "SimianLuo/LCM_Dreamshaper_v7"
|
| 5 |
-
LCM_DEFAULT_MODEL_OPENVINO = "rupeshs/LCM-dreamshaper-v7-openvino
|
| 6 |
APP_NAME = "FastSD CPU"
|
| 7 |
APP_SETTINGS_FILE = "settings.yaml"
|
| 8 |
RESULTS_DIRECTORY = "results"
|
| 9 |
CONFIG_DIRECTORY = "configs"
|
| 10 |
DEVICE = environ.get("DEVICE", "cpu")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from os import environ
|
| 2 |
|
| 3 |
+
APP_VERSION = "v1.0.0 beta 16"
|
| 4 |
LCM_DEFAULT_MODEL = "SimianLuo/LCM_Dreamshaper_v7"
|
| 5 |
+
LCM_DEFAULT_MODEL_OPENVINO = "rupeshs/LCM-dreamshaper-v7-openvino"
|
| 6 |
APP_NAME = "FastSD CPU"
|
| 7 |
APP_SETTINGS_FILE = "settings.yaml"
|
| 8 |
RESULTS_DIRECTORY = "results"
|
| 9 |
CONFIG_DIRECTORY = "configs"
|
| 10 |
DEVICE = environ.get("DEVICE", "cpu")
|
| 11 |
+
SD_MODELS_FILE = "stable-diffusion-models.txt"
|
| 12 |
+
LCM_LORA_MODELS_FILE = "lcm-lora-models.txt"
|
| 13 |
+
OPENVINO_LCM_MODELS_FILE = "openvino-lcm-models.txt"
|
| 14 |
+
TAESD_MODEL = "madebyollin/taesd"
|
| 15 |
+
TAESDXL_MODEL = "madebyollin/taesdxl"
|
| 16 |
+
TAESD_MODEL_OPENVINO = "deinferno/taesd-openvino"
|
context.py
CHANGED
|
@@ -2,7 +2,7 @@ from typing import Any
|
|
| 2 |
from app_settings import Settings
|
| 3 |
from models.interface_types import InterfaceType
|
| 4 |
from backend.lcm_text_to_image import LCMTextToImage
|
| 5 |
-
from time import
|
| 6 |
from backend.image_saver import ImageSaver
|
| 7 |
from pprint import pprint
|
| 8 |
|
|
@@ -22,23 +22,28 @@ class Context:
|
|
| 22 |
reshape: bool = False,
|
| 23 |
device: str = "cpu",
|
| 24 |
) -> Any:
|
| 25 |
-
tick =
|
| 26 |
pprint(settings.lcm_diffusion_setting.model_dump())
|
|
|
|
|
|
|
| 27 |
self.lcm_text_to_image.init(
|
| 28 |
settings.lcm_diffusion_setting.lcm_model_id,
|
| 29 |
settings.lcm_diffusion_setting.use_openvino,
|
| 30 |
device,
|
| 31 |
settings.lcm_diffusion_setting.use_offline_model,
|
|
|
|
|
|
|
|
|
|
| 32 |
)
|
| 33 |
images = self.lcm_text_to_image.generate(
|
| 34 |
settings.lcm_diffusion_setting,
|
| 35 |
reshape,
|
| 36 |
)
|
| 37 |
-
elapsed =
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
print(f"Elapsed time : {elapsed:.2f} seconds")
|
| 44 |
return images
|
|
|
|
| 2 |
from app_settings import Settings
|
| 3 |
from models.interface_types import InterfaceType
|
| 4 |
from backend.lcm_text_to_image import LCMTextToImage
|
| 5 |
+
from time import perf_counter
|
| 6 |
from backend.image_saver import ImageSaver
|
| 7 |
from pprint import pprint
|
| 8 |
|
|
|
|
| 22 |
reshape: bool = False,
|
| 23 |
device: str = "cpu",
|
| 24 |
) -> Any:
|
| 25 |
+
tick = perf_counter()
|
| 26 |
pprint(settings.lcm_diffusion_setting.model_dump())
|
| 27 |
+
if not settings.lcm_diffusion_setting.lcm_lora:
|
| 28 |
+
return None
|
| 29 |
self.lcm_text_to_image.init(
|
| 30 |
settings.lcm_diffusion_setting.lcm_model_id,
|
| 31 |
settings.lcm_diffusion_setting.use_openvino,
|
| 32 |
device,
|
| 33 |
settings.lcm_diffusion_setting.use_offline_model,
|
| 34 |
+
settings.lcm_diffusion_setting.use_tiny_auto_encoder,
|
| 35 |
+
settings.lcm_diffusion_setting.use_lcm_lora,
|
| 36 |
+
settings.lcm_diffusion_setting.lcm_lora,
|
| 37 |
)
|
| 38 |
images = self.lcm_text_to_image.generate(
|
| 39 |
settings.lcm_diffusion_setting,
|
| 40 |
reshape,
|
| 41 |
)
|
| 42 |
+
elapsed = perf_counter() - tick
|
| 43 |
+
ImageSaver.save_images(
|
| 44 |
+
settings.results_path,
|
| 45 |
+
images=images,
|
| 46 |
+
lcm_diffusion_setting=settings.lcm_diffusion_setting,
|
| 47 |
+
)
|
| 48 |
print(f"Elapsed time : {elapsed:.2f} seconds")
|
| 49 |
return images
|
frontend/__pycache__/utils.cpython-311.pyc
CHANGED
|
Binary files a/frontend/__pycache__/utils.cpython-311.pyc and b/frontend/__pycache__/utils.cpython-311.pyc differ
|
|
|
frontend/gui/__pycache__/app_window.cpython-311.pyc
CHANGED
|
Binary files a/frontend/gui/__pycache__/app_window.cpython-311.pyc and b/frontend/gui/__pycache__/app_window.cpython-311.pyc differ
|
|
|
frontend/gui/__pycache__/image_generator_worker.cpython-311.pyc
CHANGED
|
Binary files a/frontend/gui/__pycache__/image_generator_worker.cpython-311.pyc and b/frontend/gui/__pycache__/image_generator_worker.cpython-311.pyc differ
|
|
|
frontend/gui/__pycache__/ui.cpython-311.pyc
CHANGED
|
Binary files a/frontend/gui/__pycache__/ui.cpython-311.pyc and b/frontend/gui/__pycache__/ui.cpython-311.pyc differ
|
|
|
frontend/gui/app_window.py
CHANGED
|
@@ -16,7 +16,7 @@ from PyQt5.QtWidgets import (
|
|
| 16 |
QToolButton,
|
| 17 |
QFileDialog,
|
| 18 |
)
|
| 19 |
-
|
| 20 |
from PyQt5.QtGui import QPixmap, QDesktopServices
|
| 21 |
from PyQt5.QtCore import QSize, QThreadPool, Qt, QUrl
|
| 22 |
|
|
@@ -34,18 +34,23 @@ from frontend.utils import is_reshape_required
|
|
| 34 |
from context import Context
|
| 35 |
from models.interface_types import InterfaceType
|
| 36 |
from constants import DEVICE
|
| 37 |
-
from frontend.utils import enable_openvino_controls
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
|
| 40 |
class MainWindow(QMainWindow):
|
| 41 |
def __init__(self, config: AppSettings):
|
| 42 |
super().__init__()
|
|
|
|
| 43 |
self.setWindowTitle(APP_NAME)
|
| 44 |
-
self.setFixedSize(QSize(600,
|
| 45 |
self.init_ui()
|
| 46 |
self.pipeline = None
|
| 47 |
self.threadpool = QThreadPool()
|
| 48 |
-
self.config = config
|
| 49 |
self.device = "cpu"
|
| 50 |
self.previous_width = 0
|
| 51 |
self.previous_height = 0
|
|
@@ -89,6 +94,37 @@ class MainWindow(QMainWindow):
|
|
| 89 |
self.num_images.setValue(
|
| 90 |
self.config.settings.lcm_diffusion_setting.number_of_images
|
| 91 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
def init_ui(self):
|
| 94 |
self.create_main_tab()
|
|
@@ -100,20 +136,26 @@ class MainWindow(QMainWindow):
|
|
| 100 |
self.img = QLabel("<<Image>>")
|
| 101 |
self.img.setAlignment(Qt.AlignCenter)
|
| 102 |
self.img.setFixedSize(QSize(512, 512))
|
|
|
|
| 103 |
|
| 104 |
self.prompt = QTextEdit()
|
| 105 |
self.prompt.setPlaceholderText("A fantasy landscape")
|
| 106 |
self.prompt.setAcceptRichText(False)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
self.generate = QPushButton("Generate")
|
| 108 |
self.generate.clicked.connect(self.text_to_image)
|
| 109 |
-
self.prompt.setFixedHeight(
|
|
|
|
| 110 |
self.browse_results = QPushButton("...")
|
| 111 |
self.browse_results.setFixedWidth(30)
|
| 112 |
self.browse_results.clicked.connect(self.on_open_results_folder)
|
| 113 |
self.browse_results.setToolTip("Open output folder")
|
| 114 |
|
| 115 |
hlayout = QHBoxLayout()
|
| 116 |
-
hlayout.addWidget(self.
|
| 117 |
hlayout.addWidget(self.generate)
|
| 118 |
hlayout.addWidget(self.browse_results)
|
| 119 |
|
|
@@ -130,6 +172,9 @@ class MainWindow(QMainWindow):
|
|
| 130 |
|
| 131 |
vlayout = QVBoxLayout()
|
| 132 |
vlayout.addLayout(hlayout_nav)
|
|
|
|
|
|
|
|
|
|
| 133 |
vlayout.addLayout(hlayout)
|
| 134 |
|
| 135 |
self.tab_widget = QTabWidget(self)
|
|
@@ -146,11 +191,26 @@ class MainWindow(QMainWindow):
|
|
| 146 |
self.use_seed = False
|
| 147 |
|
| 148 |
def create_settings_tab(self):
|
| 149 |
-
model_hlayout = QHBoxLayout()
|
| 150 |
self.lcm_model_label = QLabel("Latent Consistency Model:")
|
| 151 |
-
self.lcm_model = QLineEdit(LCM_DEFAULT_MODEL)
|
| 152 |
-
|
| 153 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
|
| 155 |
self.inference_steps_value = QLabel("Number of inference steps: 4")
|
| 156 |
self.inference_steps = QSlider(orientation=Qt.Orientation.Horizontal)
|
|
@@ -166,11 +226,11 @@ class MainWindow(QMainWindow):
|
|
| 166 |
self.num_images.setValue(1)
|
| 167 |
self.num_images.valueChanged.connect(self.update_num_images_label)
|
| 168 |
|
| 169 |
-
self.guidance_value = QLabel("Guidance scale:
|
| 170 |
self.guidance = QSlider(orientation=Qt.Orientation.Horizontal)
|
| 171 |
-
self.guidance.setMaximum(
|
| 172 |
self.guidance.setMinimum(10)
|
| 173 |
-
self.guidance.setValue(
|
| 174 |
self.guidance.valueChanged.connect(self.update_guidance_label)
|
| 175 |
|
| 176 |
self.width_value = QLabel("Width :")
|
|
@@ -178,6 +238,7 @@ class MainWindow(QMainWindow):
|
|
| 178 |
self.width.addItem("256")
|
| 179 |
self.width.addItem("512")
|
| 180 |
self.width.addItem("768")
|
|
|
|
| 181 |
self.width.setCurrentText("512")
|
| 182 |
self.width.currentIndexChanged.connect(self.on_width_changed)
|
| 183 |
|
|
@@ -186,6 +247,7 @@ class MainWindow(QMainWindow):
|
|
| 186 |
self.height.addItem("256")
|
| 187 |
self.height.addItem("512")
|
| 188 |
self.height.addItem("768")
|
|
|
|
| 189 |
self.height.setCurrentText("512")
|
| 190 |
self.height.currentIndexChanged.connect(self.on_height_changed)
|
| 191 |
|
|
@@ -201,14 +263,27 @@ class MainWindow(QMainWindow):
|
|
| 201 |
|
| 202 |
self.use_openvino_check = QCheckBox("Use OpenVINO")
|
| 203 |
self.use_openvino_check.setChecked(False)
|
|
|
|
| 204 |
self.use_local_model_folder = QCheckBox(
|
| 205 |
"Use locally cached model or downloaded model folder(offline)"
|
| 206 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
self.use_openvino_check.setEnabled(enable_openvino_controls())
|
| 208 |
self.use_local_model_folder.setChecked(False)
|
| 209 |
self.use_local_model_folder.stateChanged.connect(self.use_offline_model_changed)
|
| 210 |
self.use_openvino_check.stateChanged.connect(self.use_openvino_changed)
|
| 211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
hlayout = QHBoxLayout()
|
| 213 |
hlayout.addWidget(self.seed_check)
|
| 214 |
hlayout.addWidget(self.seed_value)
|
|
@@ -228,8 +303,18 @@ class MainWindow(QMainWindow):
|
|
| 228 |
vlayout = QVBoxLayout()
|
| 229 |
vspacer = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
| 230 |
vlayout.addItem(hspacer)
|
| 231 |
-
vlayout.
|
|
|
|
| 232 |
vlayout.addWidget(self.use_local_model_folder)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
vlayout.addItem(slider_hspacer)
|
| 234 |
vlayout.addWidget(self.inference_steps_value)
|
| 235 |
vlayout.addWidget(self.inference_steps)
|
|
@@ -243,7 +328,7 @@ class MainWindow(QMainWindow):
|
|
| 243 |
vlayout.addWidget(self.guidance)
|
| 244 |
vlayout.addLayout(hlayout)
|
| 245 |
vlayout.addWidget(self.safety_checker)
|
| 246 |
-
|
| 247 |
vlayout.addWidget(self.results_path_label)
|
| 248 |
hlayout_path = QHBoxLayout()
|
| 249 |
hlayout_path.addWidget(self.results_path)
|
|
@@ -272,11 +357,27 @@ class MainWindow(QMainWindow):
|
|
| 272 |
vlayout.addWidget(self.label)
|
| 273 |
self.tab_about.setLayout(vlayout)
|
| 274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 275 |
def on_show_next_image(self):
|
| 276 |
if self.image_index != len(self.gen_images) - 1 and len(self.gen_images) > 0:
|
| 277 |
self.previous_img_btn.setEnabled(True)
|
| 278 |
self.image_index += 1
|
| 279 |
-
self.
|
| 280 |
if self.image_index == len(self.gen_images) - 1:
|
| 281 |
self.next_img_btn.setEnabled(False)
|
| 282 |
|
|
@@ -287,7 +388,7 @@ class MainWindow(QMainWindow):
|
|
| 287 |
if self.image_index != 0:
|
| 288 |
self.next_img_btn.setEnabled(True)
|
| 289 |
self.image_index -= 1
|
| 290 |
-
self.
|
| 291 |
if self.image_index == 0:
|
| 292 |
self.previous_img_btn.setEnabled(False)
|
| 293 |
|
|
@@ -314,19 +415,62 @@ class MainWindow(QMainWindow):
|
|
| 314 |
height_txt = self.height.itemText(index)
|
| 315 |
self.config.settings.lcm_diffusion_setting.image_height = int(height_txt)
|
| 316 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
def use_openvino_changed(self, state):
|
| 318 |
if state == 2:
|
| 319 |
self.lcm_model.setEnabled(False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 320 |
self.config.settings.lcm_diffusion_setting.use_openvino = True
|
| 321 |
else:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 322 |
self.config.settings.lcm_diffusion_setting.use_openvino = False
|
| 323 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
def use_offline_model_changed(self, state):
|
| 325 |
if state == 2:
|
| 326 |
self.config.settings.lcm_diffusion_setting.use_offline_model = True
|
| 327 |
else:
|
| 328 |
self.config.settings.lcm_diffusion_setting.use_offline_model = False
|
| 329 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 330 |
def use_safety_checker_changed(self, state):
|
| 331 |
if state == 2:
|
| 332 |
self.config.settings.lcm_diffusion_setting.use_safety_checker = True
|
|
@@ -362,11 +506,20 @@ class MainWindow(QMainWindow):
|
|
| 362 |
def generate_image(self):
|
| 363 |
self.config.settings.lcm_diffusion_setting.seed = self.get_seed_value()
|
| 364 |
self.config.settings.lcm_diffusion_setting.prompt = self.prompt.toPlainText()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 365 |
|
| 366 |
if self.config.settings.lcm_diffusion_setting.use_openvino:
|
| 367 |
-
model_id =
|
| 368 |
else:
|
| 369 |
-
model_id = self.lcm_model.
|
| 370 |
|
| 371 |
self.config.settings.lcm_diffusion_setting.lcm_model_id = model_id
|
| 372 |
|
|
@@ -403,7 +556,7 @@ class MainWindow(QMainWindow):
|
|
| 403 |
self.next_img_btn.setEnabled(False)
|
| 404 |
self.previous_img_btn.setEnabled(False)
|
| 405 |
|
| 406 |
-
self.
|
| 407 |
|
| 408 |
self.previous_width = self.config.settings.lcm_diffusion_setting.image_width
|
| 409 |
self.previous_height = self.config.settings.lcm_diffusion_setting.image_height
|
|
@@ -428,8 +581,10 @@ class MainWindow(QMainWindow):
|
|
| 428 |
self.width.setCurrentText("512")
|
| 429 |
self.height.setCurrentText("512")
|
| 430 |
self.inference_steps.setValue(4)
|
| 431 |
-
self.guidance.setValue(
|
| 432 |
self.use_openvino_check.setChecked(False)
|
| 433 |
self.seed_check.setChecked(False)
|
| 434 |
-
self.safety_checker.setChecked(
|
| 435 |
self.results_path.setText(FastStableDiffusionPaths().get_results_path())
|
|
|
|
|
|
|
|
|
| 16 |
QToolButton,
|
| 17 |
QFileDialog,
|
| 18 |
)
|
| 19 |
+
from PyQt5 import QtWidgets, QtCore
|
| 20 |
from PyQt5.QtGui import QPixmap, QDesktopServices
|
| 21 |
from PyQt5.QtCore import QSize, QThreadPool, Qt, QUrl
|
| 22 |
|
|
|
|
| 34 |
from context import Context
|
| 35 |
from models.interface_types import InterfaceType
|
| 36 |
from constants import DEVICE
|
| 37 |
+
from frontend.utils import enable_openvino_controls, get_valid_model_id
|
| 38 |
+
from backend.lcm_models import get_available_models
|
| 39 |
+
|
| 40 |
+
# DPI scale fix
|
| 41 |
+
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
|
| 42 |
+
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
|
| 43 |
|
| 44 |
|
| 45 |
class MainWindow(QMainWindow):
|
| 46 |
def __init__(self, config: AppSettings):
|
| 47 |
super().__init__()
|
| 48 |
+
self.config = config
|
| 49 |
self.setWindowTitle(APP_NAME)
|
| 50 |
+
self.setFixedSize(QSize(600, 670))
|
| 51 |
self.init_ui()
|
| 52 |
self.pipeline = None
|
| 53 |
self.threadpool = QThreadPool()
|
|
|
|
| 54 |
self.device = "cpu"
|
| 55 |
self.previous_width = 0
|
| 56 |
self.previous_height = 0
|
|
|
|
| 94 |
self.num_images.setValue(
|
| 95 |
self.config.settings.lcm_diffusion_setting.number_of_images
|
| 96 |
)
|
| 97 |
+
self.use_tae_sd.setChecked(
|
| 98 |
+
self.config.settings.lcm_diffusion_setting.use_tiny_auto_encoder
|
| 99 |
+
)
|
| 100 |
+
self.use_lcm_lora.setChecked(
|
| 101 |
+
self.config.settings.lcm_diffusion_setting.use_lcm_lora
|
| 102 |
+
)
|
| 103 |
+
self.base_model_id.setCurrentText(
|
| 104 |
+
get_valid_model_id(
|
| 105 |
+
self.config.stable_diffsuion_models,
|
| 106 |
+
self.config.settings.lcm_diffusion_setting.lcm_lora.base_model_id,
|
| 107 |
+
)
|
| 108 |
+
)
|
| 109 |
+
self.lcm_lora_id.setCurrentText(
|
| 110 |
+
get_valid_model_id(
|
| 111 |
+
self.config.lcm_lora_models,
|
| 112 |
+
self.config.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id,
|
| 113 |
+
)
|
| 114 |
+
)
|
| 115 |
+
self.openvino_lcm_model_id.setCurrentText(
|
| 116 |
+
get_valid_model_id(
|
| 117 |
+
self.config.openvino_lcm_models,
|
| 118 |
+
self.config.settings.lcm_diffusion_setting.openvino_lcm_model_id,
|
| 119 |
+
)
|
| 120 |
+
)
|
| 121 |
+
self.neg_prompt.setEnabled(
|
| 122 |
+
self.config.settings.lcm_diffusion_setting.use_lcm_lora
|
| 123 |
+
or self.config.settings.lcm_diffusion_setting.use_openvino
|
| 124 |
+
)
|
| 125 |
+
self.openvino_lcm_model_id.setEnabled(
|
| 126 |
+
self.config.settings.lcm_diffusion_setting.use_openvino
|
| 127 |
+
)
|
| 128 |
|
| 129 |
def init_ui(self):
|
| 130 |
self.create_main_tab()
|
|
|
|
| 136 |
self.img = QLabel("<<Image>>")
|
| 137 |
self.img.setAlignment(Qt.AlignCenter)
|
| 138 |
self.img.setFixedSize(QSize(512, 512))
|
| 139 |
+
self.vspacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
| 140 |
|
| 141 |
self.prompt = QTextEdit()
|
| 142 |
self.prompt.setPlaceholderText("A fantasy landscape")
|
| 143 |
self.prompt.setAcceptRichText(False)
|
| 144 |
+
self.neg_prompt = QTextEdit()
|
| 145 |
+
self.neg_prompt.setPlaceholderText("")
|
| 146 |
+
self.neg_prompt.setAcceptRichText(False)
|
| 147 |
+
self.neg_prompt_label = QLabel("Negative prompt (Set guidance scale > 1.0):")
|
| 148 |
self.generate = QPushButton("Generate")
|
| 149 |
self.generate.clicked.connect(self.text_to_image)
|
| 150 |
+
self.prompt.setFixedHeight(40)
|
| 151 |
+
self.neg_prompt.setFixedHeight(35)
|
| 152 |
self.browse_results = QPushButton("...")
|
| 153 |
self.browse_results.setFixedWidth(30)
|
| 154 |
self.browse_results.clicked.connect(self.on_open_results_folder)
|
| 155 |
self.browse_results.setToolTip("Open output folder")
|
| 156 |
|
| 157 |
hlayout = QHBoxLayout()
|
| 158 |
+
hlayout.addWidget(self.neg_prompt)
|
| 159 |
hlayout.addWidget(self.generate)
|
| 160 |
hlayout.addWidget(self.browse_results)
|
| 161 |
|
|
|
|
| 172 |
|
| 173 |
vlayout = QVBoxLayout()
|
| 174 |
vlayout.addLayout(hlayout_nav)
|
| 175 |
+
vlayout.addItem(self.vspacer)
|
| 176 |
+
vlayout.addWidget(self.prompt)
|
| 177 |
+
vlayout.addWidget(self.neg_prompt_label)
|
| 178 |
vlayout.addLayout(hlayout)
|
| 179 |
|
| 180 |
self.tab_widget = QTabWidget(self)
|
|
|
|
| 191 |
self.use_seed = False
|
| 192 |
|
| 193 |
def create_settings_tab(self):
|
|
|
|
| 194 |
self.lcm_model_label = QLabel("Latent Consistency Model:")
|
| 195 |
+
# self.lcm_model = QLineEdit(LCM_DEFAULT_MODEL)
|
| 196 |
+
lcm_models = get_available_models()
|
| 197 |
+
self.lcm_model = QComboBox(self)
|
| 198 |
+
for model in lcm_models:
|
| 199 |
+
self.lcm_model.addItem(model)
|
| 200 |
+
|
| 201 |
+
self.use_lcm_lora = QCheckBox("Use LCM LoRA")
|
| 202 |
+
self.use_lcm_lora.setChecked(False)
|
| 203 |
+
self.use_lcm_lora.stateChanged.connect(self.use_lcm_lora_changed)
|
| 204 |
+
|
| 205 |
+
self.lora_base_model_id_label = QLabel("Lora base model ID :")
|
| 206 |
+
self.base_model_id = QComboBox(self)
|
| 207 |
+
self.base_model_id.addItems(self.config.stable_diffsuion_models)
|
| 208 |
+
self.base_model_id.currentIndexChanged.connect(self.on_base_model_id_changed)
|
| 209 |
+
|
| 210 |
+
self.lcm_lora_model_id_label = QLabel("LCM LoRA model ID :")
|
| 211 |
+
self.lcm_lora_id = QComboBox(self)
|
| 212 |
+
self.lcm_lora_id.addItems(self.config.lcm_lora_models)
|
| 213 |
+
self.lcm_lora_id.currentIndexChanged.connect(self.on_lcm_lora_id_changed)
|
| 214 |
|
| 215 |
self.inference_steps_value = QLabel("Number of inference steps: 4")
|
| 216 |
self.inference_steps = QSlider(orientation=Qt.Orientation.Horizontal)
|
|
|
|
| 226 |
self.num_images.setValue(1)
|
| 227 |
self.num_images.valueChanged.connect(self.update_num_images_label)
|
| 228 |
|
| 229 |
+
self.guidance_value = QLabel("Guidance scale: 1")
|
| 230 |
self.guidance = QSlider(orientation=Qt.Orientation.Horizontal)
|
| 231 |
+
self.guidance.setMaximum(20)
|
| 232 |
self.guidance.setMinimum(10)
|
| 233 |
+
self.guidance.setValue(10)
|
| 234 |
self.guidance.valueChanged.connect(self.update_guidance_label)
|
| 235 |
|
| 236 |
self.width_value = QLabel("Width :")
|
|
|
|
| 238 |
self.width.addItem("256")
|
| 239 |
self.width.addItem("512")
|
| 240 |
self.width.addItem("768")
|
| 241 |
+
self.width.addItem("1024")
|
| 242 |
self.width.setCurrentText("512")
|
| 243 |
self.width.currentIndexChanged.connect(self.on_width_changed)
|
| 244 |
|
|
|
|
| 247 |
self.height.addItem("256")
|
| 248 |
self.height.addItem("512")
|
| 249 |
self.height.addItem("768")
|
| 250 |
+
self.height.addItem("1024")
|
| 251 |
self.height.setCurrentText("512")
|
| 252 |
self.height.currentIndexChanged.connect(self.on_height_changed)
|
| 253 |
|
|
|
|
| 263 |
|
| 264 |
self.use_openvino_check = QCheckBox("Use OpenVINO")
|
| 265 |
self.use_openvino_check.setChecked(False)
|
| 266 |
+
self.openvino_model_label = QLabel("OpenVINO LCM model:")
|
| 267 |
self.use_local_model_folder = QCheckBox(
|
| 268 |
"Use locally cached model or downloaded model folder(offline)"
|
| 269 |
)
|
| 270 |
+
self.openvino_lcm_model_id = QComboBox(self)
|
| 271 |
+
self.openvino_lcm_model_id.addItems(self.config.openvino_lcm_models)
|
| 272 |
+
self.openvino_lcm_model_id.currentIndexChanged.connect(
|
| 273 |
+
self.on_openvino_lcm_model_id_changed
|
| 274 |
+
)
|
| 275 |
+
|
| 276 |
self.use_openvino_check.setEnabled(enable_openvino_controls())
|
| 277 |
self.use_local_model_folder.setChecked(False)
|
| 278 |
self.use_local_model_folder.stateChanged.connect(self.use_offline_model_changed)
|
| 279 |
self.use_openvino_check.stateChanged.connect(self.use_openvino_changed)
|
| 280 |
|
| 281 |
+
self.use_tae_sd = QCheckBox(
|
| 282 |
+
"Use Tiny Auto Encoder - TAESD (Fast, moderate quality)"
|
| 283 |
+
)
|
| 284 |
+
self.use_tae_sd.setChecked(False)
|
| 285 |
+
self.use_tae_sd.stateChanged.connect(self.use_tae_sd_changed)
|
| 286 |
+
|
| 287 |
hlayout = QHBoxLayout()
|
| 288 |
hlayout.addWidget(self.seed_check)
|
| 289 |
hlayout.addWidget(self.seed_value)
|
|
|
|
| 303 |
vlayout = QVBoxLayout()
|
| 304 |
vspacer = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
| 305 |
vlayout.addItem(hspacer)
|
| 306 |
+
vlayout.addWidget(self.lcm_model_label)
|
| 307 |
+
vlayout.addWidget(self.lcm_model)
|
| 308 |
vlayout.addWidget(self.use_local_model_folder)
|
| 309 |
+
vlayout.addWidget(self.use_lcm_lora)
|
| 310 |
+
vlayout.addWidget(self.lora_base_model_id_label)
|
| 311 |
+
vlayout.addWidget(self.base_model_id)
|
| 312 |
+
vlayout.addWidget(self.lcm_lora_model_id_label)
|
| 313 |
+
vlayout.addWidget(self.lcm_lora_id)
|
| 314 |
+
vlayout.addWidget(self.use_openvino_check)
|
| 315 |
+
vlayout.addWidget(self.openvino_model_label)
|
| 316 |
+
vlayout.addWidget(self.openvino_lcm_model_id)
|
| 317 |
+
vlayout.addWidget(self.use_tae_sd)
|
| 318 |
vlayout.addItem(slider_hspacer)
|
| 319 |
vlayout.addWidget(self.inference_steps_value)
|
| 320 |
vlayout.addWidget(self.inference_steps)
|
|
|
|
| 328 |
vlayout.addWidget(self.guidance)
|
| 329 |
vlayout.addLayout(hlayout)
|
| 330 |
vlayout.addWidget(self.safety_checker)
|
| 331 |
+
|
| 332 |
vlayout.addWidget(self.results_path_label)
|
| 333 |
hlayout_path = QHBoxLayout()
|
| 334 |
hlayout_path.addWidget(self.results_path)
|
|
|
|
| 357 |
vlayout.addWidget(self.label)
|
| 358 |
self.tab_about.setLayout(vlayout)
|
| 359 |
|
| 360 |
+
def show_image(self, pixmap):
|
| 361 |
+
image_width = self.config.settings.lcm_diffusion_setting.image_width
|
| 362 |
+
image_height = self.config.settings.lcm_diffusion_setting.image_height
|
| 363 |
+
if image_width > 512 or image_height > 512:
|
| 364 |
+
new_width = 512 if image_width > 512 else image_width
|
| 365 |
+
new_height = 512 if image_height > 512 else image_height
|
| 366 |
+
self.img.setPixmap(
|
| 367 |
+
pixmap.scaled(
|
| 368 |
+
new_width,
|
| 369 |
+
new_height,
|
| 370 |
+
Qt.KeepAspectRatio,
|
| 371 |
+
)
|
| 372 |
+
)
|
| 373 |
+
else:
|
| 374 |
+
self.img.setPixmap(pixmap)
|
| 375 |
+
|
| 376 |
def on_show_next_image(self):
|
| 377 |
if self.image_index != len(self.gen_images) - 1 and len(self.gen_images) > 0:
|
| 378 |
self.previous_img_btn.setEnabled(True)
|
| 379 |
self.image_index += 1
|
| 380 |
+
self.show_image(self.gen_images[self.image_index])
|
| 381 |
if self.image_index == len(self.gen_images) - 1:
|
| 382 |
self.next_img_btn.setEnabled(False)
|
| 383 |
|
|
|
|
| 388 |
if self.image_index != 0:
|
| 389 |
self.next_img_btn.setEnabled(True)
|
| 390 |
self.image_index -= 1
|
| 391 |
+
self.show_image(self.gen_images[self.image_index])
|
| 392 |
if self.image_index == 0:
|
| 393 |
self.previous_img_btn.setEnabled(False)
|
| 394 |
|
|
|
|
| 415 |
height_txt = self.height.itemText(index)
|
| 416 |
self.config.settings.lcm_diffusion_setting.image_height = int(height_txt)
|
| 417 |
|
| 418 |
+
def on_base_model_id_changed(self, index):
|
| 419 |
+
model_id = self.base_model_id.itemText(index)
|
| 420 |
+
self.config.settings.lcm_diffusion_setting.lcm_lora.base_model_id = model_id
|
| 421 |
+
|
| 422 |
+
def on_lcm_lora_id_changed(self, index):
|
| 423 |
+
model_id = self.lcm_lora_id.itemText(index)
|
| 424 |
+
self.config.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id = model_id
|
| 425 |
+
|
| 426 |
+
def on_openvino_lcm_model_id_changed(self, index):
|
| 427 |
+
model_id = self.openvino_lcm_model_id.itemText(index)
|
| 428 |
+
self.config.settings.lcm_diffusion_setting.openvino_lcm_model_id = model_id
|
| 429 |
+
|
| 430 |
def use_openvino_changed(self, state):
|
| 431 |
if state == 2:
|
| 432 |
self.lcm_model.setEnabled(False)
|
| 433 |
+
self.use_lcm_lora.setEnabled(False)
|
| 434 |
+
self.lcm_lora_id.setEnabled(False)
|
| 435 |
+
self.base_model_id.setEnabled(False)
|
| 436 |
+
self.neg_prompt.setEnabled(True)
|
| 437 |
+
self.openvino_lcm_model_id.setEnabled(True)
|
| 438 |
self.config.settings.lcm_diffusion_setting.use_openvino = True
|
| 439 |
else:
|
| 440 |
+
self.lcm_model.setEnabled(True)
|
| 441 |
+
self.use_lcm_lora.setEnabled(True)
|
| 442 |
+
self.lcm_lora_id.setEnabled(True)
|
| 443 |
+
self.base_model_id.setEnabled(True)
|
| 444 |
+
self.neg_prompt.setEnabled(False)
|
| 445 |
+
self.openvino_lcm_model_id.setEnabled(False)
|
| 446 |
self.config.settings.lcm_diffusion_setting.use_openvino = False
|
| 447 |
|
| 448 |
+
def use_tae_sd_changed(self, state):
|
| 449 |
+
if state == 2:
|
| 450 |
+
self.config.settings.lcm_diffusion_setting.use_tiny_auto_encoder = True
|
| 451 |
+
else:
|
| 452 |
+
self.config.settings.lcm_diffusion_setting.use_tiny_auto_encoder = False
|
| 453 |
+
|
| 454 |
def use_offline_model_changed(self, state):
|
| 455 |
if state == 2:
|
| 456 |
self.config.settings.lcm_diffusion_setting.use_offline_model = True
|
| 457 |
else:
|
| 458 |
self.config.settings.lcm_diffusion_setting.use_offline_model = False
|
| 459 |
|
| 460 |
+
def use_lcm_lora_changed(self, state):
|
| 461 |
+
if state == 2:
|
| 462 |
+
self.lcm_model.setEnabled(False)
|
| 463 |
+
self.lcm_lora_id.setEnabled(True)
|
| 464 |
+
self.base_model_id.setEnabled(True)
|
| 465 |
+
self.neg_prompt.setEnabled(True)
|
| 466 |
+
self.config.settings.lcm_diffusion_setting.use_lcm_lora = True
|
| 467 |
+
else:
|
| 468 |
+
self.lcm_model.setEnabled(True)
|
| 469 |
+
self.lcm_lora_id.setEnabled(False)
|
| 470 |
+
self.base_model_id.setEnabled(False)
|
| 471 |
+
self.neg_prompt.setEnabled(False)
|
| 472 |
+
self.config.settings.lcm_diffusion_setting.use_lcm_lora = False
|
| 473 |
+
|
| 474 |
def use_safety_checker_changed(self, state):
|
| 475 |
if state == 2:
|
| 476 |
self.config.settings.lcm_diffusion_setting.use_safety_checker = True
|
|
|
|
| 506 |
def generate_image(self):
|
| 507 |
self.config.settings.lcm_diffusion_setting.seed = self.get_seed_value()
|
| 508 |
self.config.settings.lcm_diffusion_setting.prompt = self.prompt.toPlainText()
|
| 509 |
+
self.config.settings.lcm_diffusion_setting.negative_prompt = (
|
| 510 |
+
self.neg_prompt.toPlainText()
|
| 511 |
+
)
|
| 512 |
+
self.config.settings.lcm_diffusion_setting.lcm_lora.lcm_lora_id = (
|
| 513 |
+
self.lcm_lora_id.currentText()
|
| 514 |
+
)
|
| 515 |
+
self.config.settings.lcm_diffusion_setting.lcm_lora.base_model_id = (
|
| 516 |
+
self.base_model_id.currentText()
|
| 517 |
+
)
|
| 518 |
|
| 519 |
if self.config.settings.lcm_diffusion_setting.use_openvino:
|
| 520 |
+
model_id = self.openvino_lcm_model_id.currentText()
|
| 521 |
else:
|
| 522 |
+
model_id = self.lcm_model.currentText()
|
| 523 |
|
| 524 |
self.config.settings.lcm_diffusion_setting.lcm_model_id = model_id
|
| 525 |
|
|
|
|
| 556 |
self.next_img_btn.setEnabled(False)
|
| 557 |
self.previous_img_btn.setEnabled(False)
|
| 558 |
|
| 559 |
+
self.show_image(self.gen_images[0])
|
| 560 |
|
| 561 |
self.previous_width = self.config.settings.lcm_diffusion_setting.image_width
|
| 562 |
self.previous_height = self.config.settings.lcm_diffusion_setting.image_height
|
|
|
|
| 581 |
self.width.setCurrentText("512")
|
| 582 |
self.height.setCurrentText("512")
|
| 583 |
self.inference_steps.setValue(4)
|
| 584 |
+
self.guidance.setValue(10)
|
| 585 |
self.use_openvino_check.setChecked(False)
|
| 586 |
self.seed_check.setChecked(False)
|
| 587 |
+
self.safety_checker.setChecked(False)
|
| 588 |
self.results_path.setText(FastStableDiffusionPaths().get_results_path())
|
| 589 |
+
self.use_tae_sd.setChecked(False)
|
| 590 |
+
self.use_lcm_lora.setChecked(False)
|
frontend/utils.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
from constants import DEVICE
|
|
|
|
| 2 |
import platform
|
|
|
|
| 3 |
|
| 4 |
|
| 5 |
def is_reshape_required(
|
|
@@ -12,9 +14,6 @@ def is_reshape_required(
|
|
| 12 |
prev_num_of_images: int,
|
| 13 |
cur_num_of_images: int,
|
| 14 |
) -> bool:
|
| 15 |
-
print(f"width - {prev_width} {cur_width}")
|
| 16 |
-
print(f"height - {prev_height} {cur_height}")
|
| 17 |
-
print(f"model - {prev_model} {cur_model}")
|
| 18 |
reshape_required = False
|
| 19 |
if (
|
| 20 |
prev_width != cur_width
|
|
@@ -29,4 +28,23 @@ def is_reshape_required(
|
|
| 29 |
|
| 30 |
|
| 31 |
def enable_openvino_controls() -> bool:
|
| 32 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from constants import DEVICE
|
| 2 |
+
from typing import List
|
| 3 |
import platform
|
| 4 |
+
from backend.device import is_openvino_device
|
| 5 |
|
| 6 |
|
| 7 |
def is_reshape_required(
|
|
|
|
| 14 |
prev_num_of_images: int,
|
| 15 |
cur_num_of_images: int,
|
| 16 |
) -> bool:
|
|
|
|
|
|
|
|
|
|
| 17 |
reshape_required = False
|
| 18 |
if (
|
| 19 |
prev_width != cur_width
|
|
|
|
| 28 |
|
| 29 |
|
| 30 |
def enable_openvino_controls() -> bool:
|
| 31 |
+
return is_openvino_device() and platform.system().lower() != "darwin"
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def get_valid_model_id(
|
| 35 |
+
models: List,
|
| 36 |
+
model_id: str,
|
| 37 |
+
) -> str:
|
| 38 |
+
if len(models) == 0:
|
| 39 |
+
print("Error: model configuration file is empty,please add some models.")
|
| 40 |
+
return ""
|
| 41 |
+
if model_id == "":
|
| 42 |
+
return models[0]
|
| 43 |
+
|
| 44 |
+
if model_id in models:
|
| 45 |
+
return model_id
|
| 46 |
+
else:
|
| 47 |
+
print(
|
| 48 |
+
f"Error:{model_id} Model not found in configuration file,so using first model : {models[0]}"
|
| 49 |
+
)
|
| 50 |
+
return models[0]
|
frontend/webui/text_to_image_ui.py
CHANGED
|
@@ -10,19 +10,6 @@ from frontend.utils import is_reshape_required
|
|
| 10 |
from app_settings import AppSettings
|
| 11 |
from constants import DEVICE
|
| 12 |
from frontend.utils import enable_openvino_controls
|
| 13 |
-
from scipy.ndimage import zoom
|
| 14 |
-
import numpy as np
|
| 15 |
-
from PIL import Image
|
| 16 |
-
from super_image import CarnModel, ImageLoader
|
| 17 |
-
from torchvision import transforms
|
| 18 |
-
|
| 19 |
-
transform_image = transforms.ToPILImage()
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def tensor2img(tensor):
|
| 23 |
-
tensor = tensor.squeeze(0).cpu().clamp(0, 1)
|
| 24 |
-
return transform_image(tensor)
|
| 25 |
-
|
| 26 |
|
| 27 |
random_enabled = True
|
| 28 |
|
|
@@ -31,16 +18,19 @@ previous_width = 0
|
|
| 31 |
previous_height = 0
|
| 32 |
previous_model_id = ""
|
| 33 |
previous_num_of_images = 0
|
| 34 |
-
upscaler = CarnModel.from_pretrained("eugenesiow/carn-bam", scale=2)
|
| 35 |
|
| 36 |
|
| 37 |
def generate_text_to_image(
|
| 38 |
prompt,
|
|
|
|
|
|
|
| 39 |
inference_steps,
|
| 40 |
guidance_scale,
|
|
|
|
| 41 |
seed,
|
| 42 |
use_openvino,
|
| 43 |
use_safety_checker,
|
|
|
|
| 44 |
) -> Any:
|
| 45 |
global previous_height, previous_width, previous_model_id, previous_num_of_images
|
| 46 |
model_id = LCM_DEFAULT_MODEL
|
|
@@ -52,15 +42,16 @@ def generate_text_to_image(
|
|
| 52 |
lcm_diffusion_settings = LCMDiffusionSetting(
|
| 53 |
lcm_model_id=model_id,
|
| 54 |
prompt=prompt,
|
| 55 |
-
image_height=
|
| 56 |
-
image_width=
|
| 57 |
inference_steps=inference_steps,
|
| 58 |
guidance_scale=guidance_scale,
|
| 59 |
-
number_of_images=
|
| 60 |
seed=seed,
|
| 61 |
use_openvino=use_openvino,
|
| 62 |
use_safety_checker=use_safety_checker,
|
| 63 |
use_seed=use_seed,
|
|
|
|
| 64 |
)
|
| 65 |
settings = Settings(
|
| 66 |
lcm_diffusion_setting=lcm_diffusion_settings,
|
|
@@ -69,30 +60,23 @@ def generate_text_to_image(
|
|
| 69 |
if use_openvino:
|
| 70 |
reshape = is_reshape_required(
|
| 71 |
previous_width,
|
| 72 |
-
|
| 73 |
previous_height,
|
| 74 |
-
|
| 75 |
previous_model_id,
|
| 76 |
model_id,
|
| 77 |
previous_num_of_images,
|
| 78 |
-
|
| 79 |
)
|
| 80 |
images = context.generate_text_to_image(
|
| 81 |
settings,
|
| 82 |
reshape,
|
| 83 |
DEVICE,
|
| 84 |
)
|
| 85 |
-
previous_width =
|
| 86 |
-
previous_height =
|
| 87 |
previous_model_id = model_id
|
| 88 |
-
previous_num_of_images =
|
| 89 |
-
out_images = []
|
| 90 |
-
# for image in images:
|
| 91 |
-
# out_images.append(image.resize((768, 768), resample=Image.LANCZOS))
|
| 92 |
-
# # in_image = ImageLoader.load_image(image)
|
| 93 |
-
# # up_image = upscaler(in_image)
|
| 94 |
-
# # out_images.append(tensor2img(up_image))
|
| 95 |
-
# # out_images(image)
|
| 96 |
|
| 97 |
return images
|
| 98 |
|
|
@@ -124,10 +108,25 @@ def get_text_to_image_ui(app_settings: AppSettings) -> None:
|
|
| 124 |
elem_id="generate_button",
|
| 125 |
scale=0,
|
| 126 |
)
|
| 127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 128 |
with gr.Accordion("Advanced options", open=False):
|
| 129 |
guidance_scale = gr.Slider(
|
| 130 |
-
1.0,
|
| 131 |
)
|
| 132 |
|
| 133 |
seed = gr.Number(
|
|
@@ -144,8 +143,8 @@ def get_text_to_image_ui(app_settings: AppSettings) -> None:
|
|
| 144 |
|
| 145 |
openvino_checkbox = gr.Checkbox(
|
| 146 |
label="Use OpenVINO",
|
| 147 |
-
value=
|
| 148 |
-
interactive=
|
| 149 |
)
|
| 150 |
|
| 151 |
safety_checker_checkbox = gr.Checkbox(
|
|
@@ -153,30 +152,23 @@ def get_text_to_image_ui(app_settings: AppSettings) -> None:
|
|
| 153 |
value=True,
|
| 154 |
interactive=True,
|
| 155 |
)
|
| 156 |
-
|
| 157 |
-
|
|
|
|
|
|
|
| 158 |
)
|
| 159 |
-
# image_height = gr.Slider(
|
| 160 |
-
# 256, 768, value=384, step=64, label="Image Height",interactive=Fa
|
| 161 |
-
# )
|
| 162 |
-
# image_width = gr.Slider(
|
| 163 |
-
# 256, 768, value=384, step=64, label="Image Width"
|
| 164 |
-
# )
|
| 165 |
-
# num_images = gr.Slider(
|
| 166 |
-
# 1,
|
| 167 |
-
# 50,
|
| 168 |
-
# value=1,
|
| 169 |
-
# step=1,
|
| 170 |
-
# label="Number of images to generate",
|
| 171 |
-
# )
|
| 172 |
|
| 173 |
input_params = [
|
| 174 |
prompt,
|
|
|
|
|
|
|
| 175 |
num_inference_steps,
|
| 176 |
guidance_scale,
|
|
|
|
| 177 |
seed,
|
| 178 |
openvino_checkbox,
|
| 179 |
safety_checker_checkbox,
|
|
|
|
| 180 |
]
|
| 181 |
|
| 182 |
with gr.Column():
|
|
|
|
| 10 |
from app_settings import AppSettings
|
| 11 |
from constants import DEVICE
|
| 12 |
from frontend.utils import enable_openvino_controls
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
random_enabled = True
|
| 15 |
|
|
|
|
| 18 |
previous_height = 0
|
| 19 |
previous_model_id = ""
|
| 20 |
previous_num_of_images = 0
|
|
|
|
| 21 |
|
| 22 |
|
| 23 |
def generate_text_to_image(
|
| 24 |
prompt,
|
| 25 |
+
image_height,
|
| 26 |
+
image_width,
|
| 27 |
inference_steps,
|
| 28 |
guidance_scale,
|
| 29 |
+
num_images,
|
| 30 |
seed,
|
| 31 |
use_openvino,
|
| 32 |
use_safety_checker,
|
| 33 |
+
tiny_auto_encoder_checkbox,
|
| 34 |
) -> Any:
|
| 35 |
global previous_height, previous_width, previous_model_id, previous_num_of_images
|
| 36 |
model_id = LCM_DEFAULT_MODEL
|
|
|
|
| 42 |
lcm_diffusion_settings = LCMDiffusionSetting(
|
| 43 |
lcm_model_id=model_id,
|
| 44 |
prompt=prompt,
|
| 45 |
+
image_height=image_height,
|
| 46 |
+
image_width=image_width,
|
| 47 |
inference_steps=inference_steps,
|
| 48 |
guidance_scale=guidance_scale,
|
| 49 |
+
number_of_images=num_images,
|
| 50 |
seed=seed,
|
| 51 |
use_openvino=use_openvino,
|
| 52 |
use_safety_checker=use_safety_checker,
|
| 53 |
use_seed=use_seed,
|
| 54 |
+
use_tiny_auto_encoder=tiny_auto_encoder_checkbox,
|
| 55 |
)
|
| 56 |
settings = Settings(
|
| 57 |
lcm_diffusion_setting=lcm_diffusion_settings,
|
|
|
|
| 60 |
if use_openvino:
|
| 61 |
reshape = is_reshape_required(
|
| 62 |
previous_width,
|
| 63 |
+
image_width,
|
| 64 |
previous_height,
|
| 65 |
+
image_height,
|
| 66 |
previous_model_id,
|
| 67 |
model_id,
|
| 68 |
previous_num_of_images,
|
| 69 |
+
num_images,
|
| 70 |
)
|
| 71 |
images = context.generate_text_to_image(
|
| 72 |
settings,
|
| 73 |
reshape,
|
| 74 |
DEVICE,
|
| 75 |
)
|
| 76 |
+
previous_width = image_width
|
| 77 |
+
previous_height = image_height
|
| 78 |
previous_model_id = model_id
|
| 79 |
+
previous_num_of_images = num_images
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
|
| 81 |
return images
|
| 82 |
|
|
|
|
| 108 |
elem_id="generate_button",
|
| 109 |
scale=0,
|
| 110 |
)
|
| 111 |
+
num_inference_steps = gr.Slider(
|
| 112 |
+
1, 25, value=4, step=1, label="Inference Steps"
|
| 113 |
+
)
|
| 114 |
+
image_height = gr.Slider(
|
| 115 |
+
256, 768, value=512, step=256, label="Image Height"
|
| 116 |
+
)
|
| 117 |
+
image_width = gr.Slider(
|
| 118 |
+
256, 768, value=512, step=256, label="Image Width"
|
| 119 |
+
)
|
| 120 |
+
num_images = gr.Slider(
|
| 121 |
+
1,
|
| 122 |
+
50,
|
| 123 |
+
value=1,
|
| 124 |
+
step=1,
|
| 125 |
+
label="Number of images to generate",
|
| 126 |
+
)
|
| 127 |
with gr.Accordion("Advanced options", open=False):
|
| 128 |
guidance_scale = gr.Slider(
|
| 129 |
+
1.0, 2.0, value=1.0, step=0.5, label="Guidance Scale"
|
| 130 |
)
|
| 131 |
|
| 132 |
seed = gr.Number(
|
|
|
|
| 143 |
|
| 144 |
openvino_checkbox = gr.Checkbox(
|
| 145 |
label="Use OpenVINO",
|
| 146 |
+
value=False,
|
| 147 |
+
interactive=enable_openvino_controls(),
|
| 148 |
)
|
| 149 |
|
| 150 |
safety_checker_checkbox = gr.Checkbox(
|
|
|
|
| 152 |
value=True,
|
| 153 |
interactive=True,
|
| 154 |
)
|
| 155 |
+
tiny_auto_encoder_checkbox = gr.Checkbox(
|
| 156 |
+
label="Use tiny auto encoder for SD",
|
| 157 |
+
value=False,
|
| 158 |
+
interactive=True,
|
| 159 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 160 |
|
| 161 |
input_params = [
|
| 162 |
prompt,
|
| 163 |
+
image_height,
|
| 164 |
+
image_width,
|
| 165 |
num_inference_steps,
|
| 166 |
guidance_scale,
|
| 167 |
+
num_images,
|
| 168 |
seed,
|
| 169 |
openvino_checkbox,
|
| 170 |
safety_checker_checkbox,
|
| 171 |
+
tiny_auto_encoder_checkbox,
|
| 172 |
]
|
| 173 |
|
| 174 |
with gr.Column():
|
frontend/webui/ui.py
CHANGED
|
@@ -6,7 +6,7 @@ from app_settings import AppSettings
|
|
| 6 |
|
| 7 |
|
| 8 |
def _get_footer_message() -> str:
|
| 9 |
-
version = f"<center><p>
|
| 10 |
footer_msg = version + (
|
| 11 |
' © 2023 <a href="https://github.com/rupeshs">'
|
| 12 |
" Rupesh Sreeraman</a></p></center>"
|
|
@@ -19,7 +19,7 @@ def get_web_ui(app_settings: AppSettings) -> gr.Blocks:
|
|
| 19 |
css=FastStableDiffusionPaths.get_css_path(),
|
| 20 |
title="FastSD CPU",
|
| 21 |
) as fastsd_web_ui:
|
| 22 |
-
gr.HTML("<center><H1>FastSD CPU
|
| 23 |
with gr.Tabs():
|
| 24 |
with gr.TabItem("Text to Image"):
|
| 25 |
get_text_to_image_ui(app_settings)
|
|
|
|
| 6 |
|
| 7 |
|
| 8 |
def _get_footer_message() -> str:
|
| 9 |
+
version = f"<center><p> {APP_VERSION} "
|
| 10 |
footer_msg = version + (
|
| 11 |
' © 2023 <a href="https://github.com/rupeshs">'
|
| 12 |
" Rupesh Sreeraman</a></p></center>"
|
|
|
|
| 19 |
css=FastStableDiffusionPaths.get_css_path(),
|
| 20 |
title="FastSD CPU",
|
| 21 |
) as fastsd_web_ui:
|
| 22 |
+
gr.HTML("<center><H1>FastSD CPU</H1></center>")
|
| 23 |
with gr.Tabs():
|
| 24 |
with gr.TabItem("Text to Image"):
|
| 25 |
get_text_to_image_ui(app_settings)
|
models/__pycache__/interface_types.cpython-311.pyc
CHANGED
|
Binary files a/models/__pycache__/interface_types.cpython-311.pyc and b/models/__pycache__/interface_types.cpython-311.pyc differ
|
|
|
models/__pycache__/settings.cpython-311.pyc
CHANGED
|
Binary files a/models/__pycache__/settings.cpython-311.pyc and b/models/__pycache__/settings.cpython-311.pyc differ
|
|
|
models/settings.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
from pydantic import BaseModel
|
| 2 |
-
from backend.models.lcmdiffusion_setting import LCMDiffusionSetting
|
| 3 |
from paths import FastStableDiffusionPaths
|
| 4 |
|
| 5 |
|
| 6 |
class Settings(BaseModel):
|
| 7 |
results_path: str = FastStableDiffusionPaths().get_results_path()
|
| 8 |
-
lcm_diffusion_setting: LCMDiffusionSetting = LCMDiffusionSetting()
|
|
|
|
| 1 |
from pydantic import BaseModel
|
| 2 |
+
from backend.models.lcmdiffusion_setting import LCMDiffusionSetting, LCMLora
|
| 3 |
from paths import FastStableDiffusionPaths
|
| 4 |
|
| 5 |
|
| 6 |
class Settings(BaseModel):
|
| 7 |
results_path: str = FastStableDiffusionPaths().get_results_path()
|
| 8 |
+
lcm_diffusion_setting: LCMDiffusionSetting = LCMDiffusionSetting(lcm_lora=LCMLora())
|
paths.py
CHANGED
|
@@ -9,7 +9,7 @@ def join_paths(
|
|
| 9 |
return os.path.join(first_path, second_path)
|
| 10 |
|
| 11 |
|
| 12 |
-
def get_app_path():
|
| 13 |
app_dir = os.path.dirname(__file__)
|
| 14 |
work_dir = os.path.dirname(app_dir)
|
| 15 |
return work_dir
|
|
@@ -36,7 +36,7 @@ class FastStableDiffusionPaths:
|
|
| 36 |
return results_path
|
| 37 |
|
| 38 |
@staticmethod
|
| 39 |
-
def get_css_path():
|
| 40 |
app_dir = os.path.dirname(__file__)
|
| 41 |
css_path = os.path.join(
|
| 42 |
app_dir,
|
|
@@ -46,3 +46,12 @@ class FastStableDiffusionPaths:
|
|
| 46 |
"style.css",
|
| 47 |
)
|
| 48 |
return css_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
return os.path.join(first_path, second_path)
|
| 10 |
|
| 11 |
|
| 12 |
+
def get_app_path() -> str:
|
| 13 |
app_dir = os.path.dirname(__file__)
|
| 14 |
work_dir = os.path.dirname(app_dir)
|
| 15 |
return work_dir
|
|
|
|
| 36 |
return results_path
|
| 37 |
|
| 38 |
@staticmethod
|
| 39 |
+
def get_css_path() -> str:
|
| 40 |
app_dir = os.path.dirname(__file__)
|
| 41 |
css_path = os.path.join(
|
| 42 |
app_dir,
|
|
|
|
| 46 |
"style.css",
|
| 47 |
)
|
| 48 |
return css_path
|
| 49 |
+
|
| 50 |
+
@staticmethod
|
| 51 |
+
def get_models_config_path(model_config_file: str) -> str:
|
| 52 |
+
configs_path = get_configs_path()
|
| 53 |
+
models_path = join_paths(
|
| 54 |
+
configs_path,
|
| 55 |
+
model_config_file,
|
| 56 |
+
)
|
| 57 |
+
return models_path
|
utils.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import platform
|
|
|
|
| 2 |
|
| 3 |
|
| 4 |
def show_system_info():
|
|
@@ -8,3 +9,13 @@ def show_system_info():
|
|
| 8 |
print(f"Processor: {platform.processor()}")
|
| 9 |
except Exception as ex:
|
| 10 |
print(f"Error ocurred while getting system information {ex}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import platform
|
| 2 |
+
from typing import List
|
| 3 |
|
| 4 |
|
| 5 |
def show_system_info():
|
|
|
|
| 9 |
print(f"Processor: {platform.processor()}")
|
| 10 |
except Exception as ex:
|
| 11 |
print(f"Error ocurred while getting system information {ex}")
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def get_models_from_text_file(file_path: str) -> List:
|
| 15 |
+
models = []
|
| 16 |
+
with open(file_path, "r") as file:
|
| 17 |
+
lines = file.readlines()
|
| 18 |
+
for repo_id in lines:
|
| 19 |
+
if repo_id.strip() != "":
|
| 20 |
+
models.append(repo_id.strip())
|
| 21 |
+
return models
|