rupeshs commited on
Commit
8c39361
1 Parent(s): 7a66052

App update

Browse files
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
- from frontend.webui.ui import start_webui
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 : 8.0",
70
- default=8.0,
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
- start_webui(
 
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 DiffusionPipeline
 
 
 
 
 
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 DEVICE
 
 
 
 
 
 
 
 
 
8
 
 
 
 
9
 
10
- if DEVICE == "cpu":
11
  from backend.lcmdiffusion.pipelines.openvino.lcm_ov_pipeline import (
12
- OVLatentConsistencyModelPipeline,
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 = None
27
  self.previous_model_id = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- def _get_lcm_diffusion_pipeline_path(self) -> str:
30
- script_path = path.dirname(path.abspath(__file__))
31
- file_path = path.join(
32
- script_path,
33
- "lcmdiffusion",
34
- "pipelines",
35
- "latent_consistency_txt2img.py",
 
 
 
 
 
 
 
 
 
 
 
36
  )
37
- return file_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 self.pipeline is None or self.previous_model_id != model_id:
49
- if self.use_openvino and DEVICE == "cpu":
 
 
 
 
 
 
 
50
  if self.pipeline:
51
  del self.pipeline
52
- scheduler = LCMScheduler.from_pretrained(
53
- model_id,
54
- subfolder="scheduler",
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 self.use_openvino and DEVICE == "cpu":
91
  print("Using OpenVINO")
92
  if reshape:
93
  print("Reshape and compile")
94
  self.pipeline.reshape(
95
- batch_size=1,
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
- result_images = self.pipeline(
106
- prompt=lcm_diffusion_setting.prompt,
107
- num_inference_steps=lcm_diffusion_setting.inference_steps,
108
- guidance_scale=lcm_diffusion_setting.guidance_scale,
109
- width=lcm_diffusion_setting.image_width,
110
- height=lcm_diffusion_setting.image_height,
111
- output_type="pil",
112
- num_images_per_prompt=lcm_diffusion_setting.number_of_images,
113
- ).images
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 OVStableDiffusionPipeline, OVModelUnet, OVModelVaeDecoder, OVModelTextEncoder, OVModelVaeEncoder, VaeImageProcessor
 
 
 
 
 
 
 
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) if isinstance(model_save_dir, TemporaryDirectory) else model_save_dir
 
 
82
  )
83
  self.vae_decoder = OVModelVaeDecoder(vae_decoder, self)
84
  self.unet = LCMOVModelUnet(unet, self)
85
- self.text_encoder = OVModelTextEncoder(text_encoder, self) if text_encoder is not None else None
 
 
86
  self.text_encoder_2 = (
87
- OVModelTextEncoder(text_encoder_2, self, model_name=DIFFUSION_MODEL_TEXT_ENCODER_2_SUBFOLDER)
 
 
 
 
88
  if text_encoder_2 is not None
89
  else None
90
  )
91
- self.vae_encoder = OVModelVaeEncoder(vae_encoder, self) if vae_encoder is not None else None
 
 
92
 
93
  if "block_out_channels" in self.vae_decoder.config:
94
- self.vae_scale_factor = 2 ** (len(self.vae_decoder.config["block_out_channels"]) - 1)
 
 
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__) if sub_models[name] is not None else (None, None)
 
 
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] = [batch_size, self.text_encoder_2.config["projection_dim"]]
 
 
 
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 = height or self.unet.config.get("sample_size", 64) * self.vae_scale_factor
 
 
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(int(generator.get_state()[1][0]))
 
 
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(num_inference_steps, "cpu", original_inference_steps=original_inference_steps)
 
 
 
 
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(w, embedding_dim=self.unet.config.get("time_cond_proj_dim", 256))
 
 
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(inspect.signature(self.scheduler.step).parameters.keys())
 
 
341
  extra_step_kwargs = {}
342
  if accepts_eta:
343
  extra_step_kwargs["eta"] = eta
344
 
345
- accepts_generator = "generator" in set(inspect.signature(self.scheduler.step).parameters.keys())
 
 
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(sample=latents, timestep=timestep, timestep_cond = w_embedding, encoder_hidden_states=prompt_embeds)[0]
 
 
 
 
 
356
 
357
  # compute the previous noisy sample x_t -> x_t-1
358
  latents, denoised = self.scheduler.step(
359
- torch.from_numpy(noise_pred), t, torch.from_numpy(latents), **extra_step_kwargs, return_dict = False
 
 
 
 
360
  )
361
 
362
  latents, denoised = latents.numpy(), denoised.numpy()
363
 
364
  # call the callback, if provided
365
- if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):
 
 
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
- [self.vae_decoder(latent_sample=denoised[i : i + 1])[0] for i in range(latents.shape[0])]
 
 
 
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(image, output_type=output_type, do_denormalize=do_denormalize)
 
 
386
 
387
  if not return_dict:
388
  return (image, has_nsfw_concept)
389
 
390
- return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)
 
 
 
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(beta_start, beta_end, num_train_timesteps, dtype=torch.float32)
 
 
217
  elif beta_schedule == "scaled_linear":
218
  # this schedule is very specific to the latent diffusion model.
219
  self.betas = (
220
- torch.linspace(beta_start**0.5, beta_end**0.5, num_train_timesteps, dtype=torch.float32) ** 2
 
 
 
 
 
 
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(f"{beta_schedule} does is not implemented for {self.__class__}")
 
 
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 = torch.tensor(1.0) if set_alpha_to_one else self.alphas_cumprod[0]
 
 
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(np.arange(0, num_train_timesteps)[::-1].copy().astype(np.int64))
 
 
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(self, sample: torch.FloatTensor, timestep: Optional[int] = None) -> torch.FloatTensor:
 
 
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 = sample.float() # upcast for quantile calculation, and clamp not implemented for cpu half
 
 
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 = torch.clamp(sample, -s, s) / s # "we threshold xt0 to the range [-s, s] and then divide by s"
 
 
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 if original_inference_steps is not None else self.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(device=device, dtype=torch.long)
 
 
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 = self.alphas_cumprod[prev_timestep] if prev_timestep >= 0 else self.final_alpha_cumprod
 
 
 
 
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 = (sample - beta_prod_t.sqrt() * model_output) / alpha_prod_t.sqrt()
 
 
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 = alpha_prod_t.sqrt() * sample - beta_prod_t.sqrt() * model_output
 
 
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(predicted_original_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(model_output.shape, generator=generator, device=model_output.device)
471
- prev_sample = alpha_prod_t_prev.sqrt() * denoised + beta_prod_t_prev.sqrt() * noise
 
 
 
 
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(device=original_samples.device, dtype=original_samples.dtype)
 
 
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 = sqrt_alpha_prod * original_samples + sqrt_one_minus_alpha_prod * noise
 
 
505
  return noisy_samples
506
 
507
  # Copied from diffusers.schedulers.scheduling_ddpm.DDPMScheduler.get_velocity
508
  def get_velocity(
509
- self, sample: torch.FloatTensor, noise: torch.FloatTensor, timesteps: torch.IntTensor
 
 
 
510
  ) -> torch.FloatTensor:
511
  # Make sure alphas_cumprod and timestep have same device and dtype as sample
512
- alphas_cumprod = self.alphas_cumprod.to(device=sample.device, dtype=sample.dtype)
 
 
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] = 8
14
  number_of_images: Optional[int] = 1
15
  seed: Optional[int] = -1
16
- use_openvino: bool = False
17
  use_seed: bool = False
18
- use_offline_model: bool = False
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 7"
4
  LCM_DEFAULT_MODEL = "SimianLuo/LCM_Dreamshaper_v7"
5
- LCM_DEFAULT_MODEL_OPENVINO = "rupeshs/LCM-dreamshaper-v7-openvino-int8"
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 time
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 = time()
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 = time() - tick
38
- # ImageSaver.save_images(
39
- # settings.results_path,
40
- # images=images,
41
- # lcm_diffusion_setting=settings.lcm_diffusion_setting,
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, 620))
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(35)
 
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.prompt)
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
- model_hlayout.addWidget(self.lcm_model_label)
153
- model_hlayout.addWidget(self.lcm_model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: 8")
170
  self.guidance = QSlider(orientation=Qt.Orientation.Horizontal)
171
- self.guidance.setMaximum(200)
172
  self.guidance.setMinimum(10)
173
- self.guidance.setValue(80)
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.addLayout(model_hlayout)
 
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
- vlayout.addWidget(self.use_openvino_check)
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.img.setPixmap(self.gen_images[self.image_index])
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.img.setPixmap(self.gen_images[self.image_index])
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 = LCM_DEFAULT_MODEL_OPENVINO
368
  else:
369
- model_id = self.lcm_model.text()
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.img.setPixmap(self.gen_images[0])
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(80)
432
  self.use_openvino_check.setChecked(False)
433
  self.seed_check.setChecked(False)
434
- self.safety_checker.setChecked(True)
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 DEVICE == "cpu" and platform.system().lower() != "darwin"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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=384,
56
- image_width=384,
57
  inference_steps=inference_steps,
58
  guidance_scale=guidance_scale,
59
- number_of_images=1,
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
- 384,
73
  previous_height,
74
- 384,
75
  previous_model_id,
76
  model_id,
77
  previous_num_of_images,
78
- 1,
79
  )
80
  images = context.generate_text_to_image(
81
  settings,
82
  reshape,
83
  DEVICE,
84
  )
85
- previous_width = 384
86
- previous_height = 384
87
  previous_model_id = model_id
88
- previous_num_of_images = 1
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, 30.0, value=8, step=0.5, label="Guidance Scale"
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=True,
148
- interactive=False,
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
- num_inference_steps = gr.Slider(
157
- 1, 8, value=4, step=1, label="Inference Steps"
 
 
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> v{APP_VERSION} "
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 demo (OpenVINO)</H1></center>")
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