adamelliotfields commited on
Commit
51fab87
1 Parent(s): effc0a0

Remove arrays from prompts

Browse files
Files changed (5) hide show
  1. DOCS.md +2 -8
  2. lib/__init__.py +0 -20
  3. lib/inference.py +13 -35
  4. lib/loader.py +3 -9
  5. lib/utils.py +9 -0
DOCS.md CHANGED
@@ -19,12 +19,6 @@ This is the same syntax used in [InvokeAI](https://invoke-ai.github.io/InvokeAI/
19
  | `(blue)1.2` | `(blue:1.2)` |
20
  | `(blue)0.8` | `(blue:0.8)` |
21
 
22
- #### Arrays
23
-
24
- Arrays allow you to generate multiple different images from a single prompt. For example, `an adult [[blonde,brunette]] [[man,woman]]` will expand into **4** different prompts. This implementation was inspired by [Fooocus](https://github.com/lllyasviel/Fooocus/pull/1503).
25
-
26
- > NB: Make sure to set `Images` to the number of images you want to generate. Otherwise, only the first prompt will be used.
27
-
28
  ### Models
29
 
30
  Each model checkpoint has a different aesthetic:
@@ -61,7 +55,7 @@ Select one or more [textual inversion](https://huggingface.co/docs/diffusers/en/
61
 
62
  [Styles](https://huggingface.co/spaces/adamelliotfields/diffusion/blob/main/data/styles.json) are prompt templates that wrap your positive and negative prompts. They were originally derived from the [twri/sdxl_prompt_styler](https://github.com/twri/sdxl_prompt_styler) Comfy node, but have since been entirely rewritten.
63
 
64
- Start by framing a simple subject like `portrait of a young adult woman` or `landscape of a mountain range` and experiment.
65
 
66
  #### Anime
67
 
@@ -79,7 +73,7 @@ Rescale up to 4x using [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) wit
79
 
80
  ### Image-to-Image
81
 
82
- The `🖼️ Image` tab enables the image-to-image and IP-Adapter pipelines.
83
 
84
  #### Strength
85
 
 
19
  | `(blue)1.2` | `(blue:1.2)` |
20
  | `(blue)0.8` | `(blue:0.8)` |
21
 
 
 
 
 
 
 
22
  ### Models
23
 
24
  Each model checkpoint has a different aesthetic:
 
55
 
56
  [Styles](https://huggingface.co/spaces/adamelliotfields/diffusion/blob/main/data/styles.json) are prompt templates that wrap your positive and negative prompts. They were originally derived from the [twri/sdxl_prompt_styler](https://github.com/twri/sdxl_prompt_styler) Comfy node, but have since been entirely rewritten.
57
 
58
+ Start by framing a simple subject like `portrait of a cat` or `landscape of a mountain range` and experiment.
59
 
60
  #### Anime
61
 
 
73
 
74
  ### Image-to-Image
75
 
76
+ The `Image-to-Image` settings allows you to provide input images for the initial latents, ControlNet, and IP-Adapter.
77
 
78
  #### Strength
79
 
lib/__init__.py CHANGED
@@ -1,39 +1,19 @@
1
- from .annotators import CannyAnnotator
2
  from .config import Config
3
  from .inference import generate
4
- from .loader import Loader
5
- from .logger import Logger
6
- from .upscaler import RealESRGAN
7
  from .utils import (
8
- annotate_image,
9
  async_call,
10
  disable_progress_bars,
11
  download_civit_file,
12
  download_repo_files,
13
- enable_progress_bars,
14
- load_json,
15
  read_file,
16
- resize_image,
17
- safe_progress,
18
- timer,
19
  )
20
 
21
  __all__ = [
22
- "CannyAnnotator",
23
  "Config",
24
- "Loader",
25
- "Logger",
26
- "RealESRGAN",
27
- "annotate_image",
28
  "async_call",
29
  "disable_progress_bars",
30
  "download_civit_file",
31
  "download_repo_files",
32
- "enable_progress_bars",
33
  "generate",
34
- "load_json",
35
  "read_file",
36
- "resize_image",
37
- "safe_progress",
38
- "timer",
39
  ]
 
 
1
  from .config import Config
2
  from .inference import generate
 
 
 
3
  from .utils import (
 
4
  async_call,
5
  disable_progress_bars,
6
  download_civit_file,
7
  download_repo_files,
 
 
8
  read_file,
 
 
 
9
  )
10
 
11
  __all__ = [
 
12
  "Config",
 
 
 
 
13
  "async_call",
14
  "disable_progress_bars",
15
  "download_civit_file",
16
  "download_repo_files",
 
17
  "generate",
 
18
  "read_file",
 
 
 
19
  ]
lib/inference.py CHANGED
@@ -1,9 +1,6 @@
1
- import gc
2
  import os
3
- import re
4
  import time
5
  from datetime import datetime
6
- from itertools import product
7
 
8
  import torch
9
  from compel import Compel, DiffusersTextualInversionManager, ReturnedEmbeddingsType
@@ -16,6 +13,7 @@ from .loader import Loader
16
  from .logger import Logger
17
  from .utils import (
18
  annotate_image,
 
19
  load_json,
20
  resize_image,
21
  safe_progress,
@@ -23,25 +21,7 @@ from .utils import (
23
  )
24
 
25
 
26
- def parse_prompt_with_arrays(prompt: str) -> list[str]:
27
- arrays = re.findall(r"\[\[(.*?)\]\]", prompt)
28
-
29
- if not arrays:
30
- return [prompt]
31
-
32
- tokens = [item.split(",") for item in arrays] # [("a", "b"), ("1", "2")]
33
- combinations = list(product(*tokens)) # [("a", "1"), ("a", "2"), ("b", "1"), ("b", "2")]
34
-
35
- # find all the arrays in the prompt and replace them with tokens
36
- prompts = []
37
- for combo in combinations:
38
- current_prompt = prompt
39
- for i, token in enumerate(combo):
40
- current_prompt = current_prompt.replace(f"[[{arrays[i]}]]", token.strip(), 1)
41
- prompts.append(current_prompt)
42
- return prompts
43
-
44
-
45
  def apply_style(positive_prompt, negative_prompt, style_id="none"):
46
  if style_id.lower() == "none":
47
  return (positive_prompt, negative_prompt)
@@ -78,6 +58,7 @@ def gpu_duration(**kwargs):
78
  return loading + (duration * num_images)
79
 
80
 
 
81
  @GPU(duration=gpu_duration)
82
  def generate(
83
  positive_prompt,
@@ -143,7 +124,7 @@ def generate(
143
  else:
144
  IP_ADAPTER = ""
145
 
146
- # custom progress bar for multiple images
147
  def callback_on_step_end(pipeline, step, timestep, latents):
148
  nonlocal CURRENT_STEP, CURRENT_IMAGE
149
  if progress is not None:
@@ -224,7 +205,7 @@ def generate(
224
  except (EnvironmentError, HFValidationError, RepositoryNotFoundError):
225
  raise Error(f"Invalid embedding: {embedding}")
226
 
227
- # prompt embeds
228
  compel = Compel(
229
  device=pipe.device,
230
  tokenizer=pipe.tokenizer,
@@ -241,15 +222,9 @@ def generate(
241
  for i in range(num_images):
242
  try:
243
  generator = torch.Generator(device=pipe.device).manual_seed(current_seed)
 
244
 
245
- positive_prompts = parse_prompt_with_arrays(positive_prompt)
246
- index = i % len(positive_prompts)
247
- positive_styled, negative_styled = apply_style(
248
- positive_prompts[index],
249
- negative_prompt,
250
- style,
251
- )
252
-
253
  if negative_styled.startswith("(), "):
254
  negative_styled = negative_styled[4:]
255
 
@@ -305,6 +280,7 @@ def generate(
305
  CURRENT_STEP = 0
306
  CURRENT_IMAGE += 1
307
 
 
308
  if scale > 1:
309
  msg = f"Upscaling {scale}x"
310
  with timer(msg, logger=log.info):
@@ -314,13 +290,15 @@ def generate(
314
  images[i] = image
315
  safe_progress(progress, i + 1, num_images, desc=msg)
316
 
317
- # cleanup
318
- loader.collect()
319
- gc.collect()
320
 
321
  end = time.perf_counter()
322
  msg = f"Generating {len(images)} image{'s' if len(images) > 1 else ''} took {end - start:.2f}s"
323
  log.info(msg)
 
 
324
  if Info:
325
  Info(msg)
 
326
  return images
 
 
1
  import os
 
2
  import time
3
  from datetime import datetime
 
4
 
5
  import torch
6
  from compel import Compel, DiffusersTextualInversionManager, ReturnedEmbeddingsType
 
13
  from .logger import Logger
14
  from .utils import (
15
  annotate_image,
16
+ clear_cuda_cache,
17
  load_json,
18
  resize_image,
19
  safe_progress,
 
21
  )
22
 
23
 
24
+ # Inject prompts into style templates
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  def apply_style(positive_prompt, negative_prompt, style_id="none"):
26
  if style_id.lower() == "none":
27
  return (positive_prompt, negative_prompt)
 
58
  return loading + (duration * num_images)
59
 
60
 
61
+ # Request GPU when deployed to Hugging Face
62
  @GPU(duration=gpu_duration)
63
  def generate(
64
  positive_prompt,
 
124
  else:
125
  IP_ADAPTER = ""
126
 
127
+ # Custom progress bar for multiple images
128
  def callback_on_step_end(pipeline, step, timestep, latents):
129
  nonlocal CURRENT_STEP, CURRENT_IMAGE
130
  if progress is not None:
 
205
  except (EnvironmentError, HFValidationError, RepositoryNotFoundError):
206
  raise Error(f"Invalid embedding: {embedding}")
207
 
208
+ # Embed prompts with weights
209
  compel = Compel(
210
  device=pipe.device,
211
  tokenizer=pipe.tokenizer,
 
222
  for i in range(num_images):
223
  try:
224
  generator = torch.Generator(device=pipe.device).manual_seed(current_seed)
225
+ positive_styled, negative_styled = apply_style(positive_prompt, negative_prompt, style)
226
 
227
+ # User didn't provide a negative prompt
 
 
 
 
 
 
 
228
  if negative_styled.startswith("(), "):
229
  negative_styled = negative_styled[4:]
230
 
 
280
  CURRENT_STEP = 0
281
  CURRENT_IMAGE += 1
282
 
283
+ # Upscale
284
  if scale > 1:
285
  msg = f"Upscaling {scale}x"
286
  with timer(msg, logger=log.info):
 
290
  images[i] = image
291
  safe_progress(progress, i + 1, num_images, desc=msg)
292
 
293
+ # Flush memory after generating
294
+ clear_cuda_cache()
 
295
 
296
  end = time.perf_counter()
297
  msg = f"Generating {len(images)} image{'s' if len(images) > 1 else ''} took {end - start:.2f}s"
298
  log.info(msg)
299
+
300
+ # Alert if notifier provided
301
  if Info:
302
  Info(msg)
303
+
304
  return images
lib/loader.py CHANGED
@@ -10,7 +10,7 @@ from diffusers.models.attention_processor import AttnProcessor2_0, IPAdapterAttn
10
  from .config import Config
11
  from .logger import Logger
12
  from .upscaler import RealESRGAN
13
- from .utils import safe_progress, timer
14
 
15
 
16
  class Loader:
@@ -184,10 +184,10 @@ class Loader:
184
  to_unload.append("model")
185
  to_unload.append("pipe")
186
 
187
- self.collect()
188
  for component in to_unload:
189
  setattr(self, component, None)
190
- gc.collect()
191
 
192
  def _should_load_upscaler(self, scale=1):
193
  if self.upscaler is None and scale > 1:
@@ -311,12 +311,6 @@ class Loader:
311
  variant="fp16",
312
  ).to(self.pipe.device)
313
 
314
- def collect(self):
315
- torch.cuda.empty_cache()
316
- torch.cuda.ipc_collect()
317
- torch.cuda.reset_peak_memory_stats()
318
- torch.cuda.synchronize()
319
-
320
  def load(
321
  self,
322
  kind,
 
10
  from .config import Config
11
  from .logger import Logger
12
  from .upscaler import RealESRGAN
13
+ from .utils import clear_cuda_cache, safe_progress, timer
14
 
15
 
16
  class Loader:
 
184
  to_unload.append("model")
185
  to_unload.append("pipe")
186
 
187
+ clear_cuda_cache()
188
  for component in to_unload:
189
  setattr(self, component, None)
190
+ gc.collect()
191
 
192
  def _should_load_upscaler(self, scale=1):
193
  if self.upscaler is None and scale > 1:
 
311
  variant="fp16",
312
  ).to(self.pipe.device)
313
 
 
 
 
 
 
 
314
  def load(
315
  self,
316
  kind,
lib/utils.py CHANGED
@@ -9,6 +9,7 @@ from typing import Callable, Tuple, TypeVar
9
  import anyio
10
  import httpx
11
  import numpy as np
 
12
  from anyio import Semaphore
13
  from diffusers.utils import logging as diffusers_logging
14
  from huggingface_hub._snapshot_download import snapshot_download
@@ -66,6 +67,14 @@ def safe_progress(progress, current=0, total=0, desc=""):
66
  progress((current, total), desc=desc)
67
 
68
 
 
 
 
 
 
 
 
 
69
  def download_repo_files(repo_id, allow_patterns, token=None):
70
  was_disabled = are_progress_bars_disabled()
71
  enable_progress_bars()
 
9
  import anyio
10
  import httpx
11
  import numpy as np
12
+ import torch
13
  from anyio import Semaphore
14
  from diffusers.utils import logging as diffusers_logging
15
  from huggingface_hub._snapshot_download import snapshot_download
 
67
  progress((current, total), desc=desc)
68
 
69
 
70
+ def clear_cuda_cache():
71
+ if torch.cuda.is_available():
72
+ torch.cuda.empty_cache()
73
+ torch.cuda.ipc_collect()
74
+ torch.cuda.reset_peak_memory_stats()
75
+ torch.cuda.synchronize()
76
+
77
+
78
  def download_repo_files(repo_id, allow_patterns, token=None):
79
  was_disabled = are_progress_bars_disabled()
80
  enable_progress_bars()