Adnan commited on
Commit
32d07c8
·
verified ·
1 Parent(s): b5ed4fd

Update image_generator.py

Browse files
Files changed (1) hide show
  1. image_generator.py +71 -41
image_generator.py CHANGED
@@ -20,6 +20,13 @@ def flush_memory():
20
  torch.cuda.empty_cache()
21
 
22
 
 
 
 
 
 
 
 
23
  def get_pipeline(model_id: str = "stabilityai/sdxl-turbo", pipeline_type: str = "t2i"):
24
  """
25
  Load and cache the diffusion pipeline.
@@ -31,25 +38,56 @@ def get_pipeline(model_id: str = "stabilityai/sdxl-turbo", pipeline_type: str =
31
  cache_key = f"{model_id}_{pipeline_type}"
32
 
33
  if cache_key not in _pipelines:
 
 
 
 
 
 
 
 
34
  if pipeline_type == "t2i":
35
- pipe = AutoPipelineForText2Image.from_pretrained(
36
- model_id,
37
- torch_dtype=torch.float16,
38
- variant="fp16" if "turbo" in model_id or "sdxl" in model_id.lower() else None,
39
- )
 
 
 
 
 
 
 
 
40
  _pipelines[cache_key] = pipe
41
 
42
  elif pipeline_type == "i2i":
43
  # Try to reuse t2i components
44
  t2i_key = f"{model_id}_t2i"
45
  if t2i_key in _pipelines:
46
- pipe = AutoPipelineForImage2Image.from_pipe(_pipelines[t2i_key])
 
 
 
 
 
 
 
 
 
 
 
47
  else:
48
- pipe = AutoPipelineForImage2Image.from_pretrained(
49
- model_id,
50
- torch_dtype=torch.float16,
51
- variant="fp16" if "turbo" in model_id or "sdxl" in model_id.lower() else None,
52
- )
 
 
 
 
53
  _pipelines[cache_key] = pipe
54
 
55
  return _pipelines[cache_key]
@@ -77,7 +115,6 @@ def get_model_config(model_id: str) -> Dict:
77
  "supports_guidance": True,
78
  },
79
  }
80
- # Default config for unknown models
81
  return configs.get(model_id, {
82
  "num_inference_steps": 20,
83
  "guidance_scale": 7.0,
@@ -95,13 +132,7 @@ class ImageGenerator:
95
  def __init__(self, model_id: str = "stabilityai/sdxl-turbo"):
96
  self.model_id = model_id
97
  self.config = get_model_config(model_id)
98
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
99
-
100
- def _move_to_device(self, pipe):
101
- """Move pipeline to the appropriate device."""
102
- if self.device == "cuda":
103
- pipe.to("cuda")
104
- return pipe
105
 
106
  def generate_first_panel(
107
  self,
@@ -115,22 +146,25 @@ class ImageGenerator:
115
  ) -> Image.Image:
116
  """Generate the first panel using text-to-image."""
117
  pipe = get_pipeline(self.model_id, "t2i")
118
- pipe = self._move_to_device(pipe)
119
 
120
- w, h = width or self.config["default_resolution"][0], height or self.config["default_resolution"][1]
 
121
  n_steps = steps or self.config["num_inference_steps"]
122
  cfg = guidance if guidance is not None else self.config["guidance_scale"]
123
  generator = torch.Generator(device=self.device).manual_seed(seed)
124
 
125
- result = pipe(
126
  prompt=prompt,
127
- negative_prompt=negative_prompt if negative_prompt else None,
128
  num_inference_steps=n_steps,
129
  guidance_scale=cfg,
130
  width=w,
131
  height=h,
132
  generator=generator,
133
  )
 
 
 
 
134
  return result.images[0]
135
 
136
  def generate_next_panel(
@@ -145,25 +179,27 @@ class ImageGenerator:
145
  ) -> Image.Image:
146
  """Generate the next panel using img2img from the previous panel."""
147
  pipe = get_pipeline(self.model_id, "i2i")
148
- pipe = self._move_to_device(pipe)
149
 
150
  n_steps = steps or self.config["num_inference_steps"]
151
  cfg = guidance if guidance is not None else self.config["guidance_scale"]
152
  generator = torch.Generator(device=self.device).manual_seed(seed)
153
 
154
- # Resize previous image to match model's expected resolution
155
  target_w, target_h = self.config["default_resolution"]
156
  prev_resized = previous_image.resize((target_w, target_h), Image.LANCZOS)
157
 
158
- result = pipe(
159
  prompt=prompt,
160
  image=prev_resized,
161
- negative_prompt=negative_prompt if negative_prompt else None,
162
  num_inference_steps=n_steps,
163
  guidance_scale=cfg,
164
  strength=strength,
165
  generator=generator,
166
  )
 
 
 
 
167
  return result.images[0]
168
 
169
  def generate_all_panels(
@@ -180,8 +216,8 @@ class ImageGenerator:
180
  ) -> List[Image.Image]:
181
  """
182
  Generate all panels in sequence.
183
- Panel 1: text-to-image (or img2img from reference if provided)
184
- Panel 2+: img2img from previous panel with controlled strength
185
  """
186
  images = []
187
 
@@ -195,12 +231,11 @@ class ImageGenerator:
195
  try:
196
  if i == 0:
197
  if reference_image is not None:
198
- # Use reference image as base for first panel
199
  img = self.generate_next_panel(
200
  prompt=full_prompt,
201
  previous_image=reference_image,
202
  negative_prompt=neg_prompt,
203
- strength=max(strength, 0.5), # Slightly higher for first panel from ref
204
  seed=seed,
205
  steps=steps,
206
  guidance=guidance,
@@ -230,7 +265,6 @@ class ImageGenerator:
230
 
231
  except Exception as e:
232
  print(f"Error generating panel {i + 1}: {e}")
233
- # Use previous image as fallback (or a blank image for panel 1)
234
  if images:
235
  images.append(images[-1].copy())
236
  else:
@@ -253,10 +287,7 @@ class ImageGenerator:
253
  steps: Optional[int] = None,
254
  guidance: Optional[float] = None,
255
  ) -> Tuple[Image.Image, List[Image.Image]]:
256
- """
257
- Regenerate a single panel and optionally cascade changes forward.
258
- Returns the new image and the updated image list.
259
- """
260
  prompt_data = prompts[panel_index]
261
  main_prompt = prompt_data.get("main_prompt", "")
262
  style = prompt_data.get("style_suffix", "")
@@ -266,17 +297,16 @@ class ImageGenerator:
266
 
267
  if panel_index == 0:
268
  new_img = self.generate_first_panel(
269
- prompt=full_prompt, negative_prompt=neg_prompt, seed=seed, steps=steps, guidance=guidance
 
270
  )
271
  else:
272
  new_img = self.generate_next_panel(
273
  prompt=full_prompt,
274
  previous_image=existing_images[panel_index - 1],
275
  negative_prompt=neg_prompt,
276
- strength=strength,
277
- seed=seed,
278
- steps=steps,
279
- guidance=guidance,
280
  )
281
 
282
  updated_images = existing_images.copy()
 
20
  torch.cuda.empty_cache()
21
 
22
 
23
+ def get_device():
24
+ """Get the best available device."""
25
+ if torch.cuda.is_available():
26
+ return "cuda"
27
+ return "cpu"
28
+
29
+
30
  def get_pipeline(model_id: str = "stabilityai/sdxl-turbo", pipeline_type: str = "t2i"):
31
  """
32
  Load and cache the diffusion pipeline.
 
38
  cache_key = f"{model_id}_{pipeline_type}"
39
 
40
  if cache_key not in _pipelines:
41
+ device = get_device()
42
+ dtype = torch.float16 if device == "cuda" else torch.float32
43
+
44
+ # Determine variant
45
+ variant = None
46
+ if device == "cuda" and ("turbo" in model_id or "sdxl" in model_id.lower()):
47
+ variant = "fp16"
48
+
49
  if pipeline_type == "t2i":
50
+ try:
51
+ pipe = AutoPipelineForText2Image.from_pretrained(
52
+ model_id,
53
+ torch_dtype=dtype,
54
+ variant=variant,
55
+ )
56
+ except Exception:
57
+ # Fallback without variant
58
+ pipe = AutoPipelineForText2Image.from_pretrained(
59
+ model_id,
60
+ torch_dtype=dtype,
61
+ )
62
+ pipe = pipe.to(device)
63
  _pipelines[cache_key] = pipe
64
 
65
  elif pipeline_type == "i2i":
66
  # Try to reuse t2i components
67
  t2i_key = f"{model_id}_t2i"
68
  if t2i_key in _pipelines:
69
+ try:
70
+ pipe = AutoPipelineForImage2Image.from_pipe(_pipelines[t2i_key])
71
+ except Exception:
72
+ try:
73
+ pipe = AutoPipelineForImage2Image.from_pretrained(
74
+ model_id, torch_dtype=dtype, variant=variant,
75
+ )
76
+ except Exception:
77
+ pipe = AutoPipelineForImage2Image.from_pretrained(
78
+ model_id, torch_dtype=dtype,
79
+ )
80
+ pipe = pipe.to(device)
81
  else:
82
+ try:
83
+ pipe = AutoPipelineForImage2Image.from_pretrained(
84
+ model_id, torch_dtype=dtype, variant=variant,
85
+ )
86
+ except Exception:
87
+ pipe = AutoPipelineForImage2Image.from_pretrained(
88
+ model_id, torch_dtype=dtype,
89
+ )
90
+ pipe = pipe.to(device)
91
  _pipelines[cache_key] = pipe
92
 
93
  return _pipelines[cache_key]
 
115
  "supports_guidance": True,
116
  },
117
  }
 
118
  return configs.get(model_id, {
119
  "num_inference_steps": 20,
120
  "guidance_scale": 7.0,
 
132
  def __init__(self, model_id: str = "stabilityai/sdxl-turbo"):
133
  self.model_id = model_id
134
  self.config = get_model_config(model_id)
135
+ self.device = get_device()
 
 
 
 
 
 
136
 
137
  def generate_first_panel(
138
  self,
 
146
  ) -> Image.Image:
147
  """Generate the first panel using text-to-image."""
148
  pipe = get_pipeline(self.model_id, "t2i")
 
149
 
150
+ w = width or self.config["default_resolution"][0]
151
+ h = height or self.config["default_resolution"][1]
152
  n_steps = steps or self.config["num_inference_steps"]
153
  cfg = guidance if guidance is not None else self.config["guidance_scale"]
154
  generator = torch.Generator(device=self.device).manual_seed(seed)
155
 
156
+ kwargs = dict(
157
  prompt=prompt,
 
158
  num_inference_steps=n_steps,
159
  guidance_scale=cfg,
160
  width=w,
161
  height=h,
162
  generator=generator,
163
  )
164
+ if negative_prompt:
165
+ kwargs["negative_prompt"] = negative_prompt
166
+
167
+ result = pipe(**kwargs)
168
  return result.images[0]
169
 
170
  def generate_next_panel(
 
179
  ) -> Image.Image:
180
  """Generate the next panel using img2img from the previous panel."""
181
  pipe = get_pipeline(self.model_id, "i2i")
 
182
 
183
  n_steps = steps or self.config["num_inference_steps"]
184
  cfg = guidance if guidance is not None else self.config["guidance_scale"]
185
  generator = torch.Generator(device=self.device).manual_seed(seed)
186
 
187
+ # Resize previous image to match model resolution
188
  target_w, target_h = self.config["default_resolution"]
189
  prev_resized = previous_image.resize((target_w, target_h), Image.LANCZOS)
190
 
191
+ kwargs = dict(
192
  prompt=prompt,
193
  image=prev_resized,
 
194
  num_inference_steps=n_steps,
195
  guidance_scale=cfg,
196
  strength=strength,
197
  generator=generator,
198
  )
199
+ if negative_prompt:
200
+ kwargs["negative_prompt"] = negative_prompt
201
+
202
+ result = pipe(**kwargs)
203
  return result.images[0]
204
 
205
  def generate_all_panels(
 
216
  ) -> List[Image.Image]:
217
  """
218
  Generate all panels in sequence.
219
+ Panel 1: text-to-image (or img2img from reference)
220
+ Panel 2+: img2img from previous panel
221
  """
222
  images = []
223
 
 
231
  try:
232
  if i == 0:
233
  if reference_image is not None:
 
234
  img = self.generate_next_panel(
235
  prompt=full_prompt,
236
  previous_image=reference_image,
237
  negative_prompt=neg_prompt,
238
+ strength=max(strength, 0.5),
239
  seed=seed,
240
  steps=steps,
241
  guidance=guidance,
 
265
 
266
  except Exception as e:
267
  print(f"Error generating panel {i + 1}: {e}")
 
268
  if images:
269
  images.append(images[-1].copy())
270
  else:
 
287
  steps: Optional[int] = None,
288
  guidance: Optional[float] = None,
289
  ) -> Tuple[Image.Image, List[Image.Image]]:
290
+ """Regenerate a single panel."""
 
 
 
291
  prompt_data = prompts[panel_index]
292
  main_prompt = prompt_data.get("main_prompt", "")
293
  style = prompt_data.get("style_suffix", "")
 
297
 
298
  if panel_index == 0:
299
  new_img = self.generate_first_panel(
300
+ prompt=full_prompt, negative_prompt=neg_prompt,
301
+ seed=seed, steps=steps, guidance=guidance,
302
  )
303
  else:
304
  new_img = self.generate_next_panel(
305
  prompt=full_prompt,
306
  previous_image=existing_images[panel_index - 1],
307
  negative_prompt=neg_prompt,
308
+ strength=strength, seed=seed,
309
+ steps=steps, guidance=guidance,
 
 
310
  )
311
 
312
  updated_images = existing_images.copy()