primerz commited on
Commit
f651fe9
·
verified ·
1 Parent(s): 845397e

Upload 3 files

Browse files
Files changed (2) hide show
  1. generator.py +9 -8
  2. models.py +68 -38
generator.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
  Generation logic for Pixagram AI Pixel Art Generator
3
- CLEANED VERSION - Applied all audit fixes
4
  """
5
  import torch
6
  import numpy as np
@@ -21,6 +21,7 @@ from models import (
21
  load_sdxl_pipeline, load_lora, setup_compel,
22
  setup_scheduler, optimize_pipeline, load_caption_model, set_clip_skip
23
  )
 
24
  from memory_utils import MemoryManager, ModelOffloader
25
 
26
 
@@ -345,8 +346,7 @@ class RetroArtConverter:
345
  # Get raw embeddings
346
  face_embeddings = face.normed_embedding
347
 
348
- # Draw keypoints
349
- from pipeline_stable_diffusion_xl_instantid_img2img import draw_kps
350
  face_kps_image = draw_kps(resized_image, face.kps)
351
 
352
  # Get bbox for color matching
@@ -372,13 +372,14 @@ class RetroArtConverter:
372
  elif not self.face_detection_enabled:
373
  print("[FACE] Face detection disabled - generating without face preservation")
374
 
375
- # Set LORA scale
376
- if hasattr(self.pipe, 'set_adapters') and self.models_loaded['lora']:
377
  try:
378
- self.pipe.set_adapters(["retroart"], adapter_weights=[lora_scale])
379
- print(f"[LORA] Scale: {lora_scale}")
 
380
  except Exception as e:
381
- print(f"[LORA] Could not set scale: {e}")
382
 
383
  # ═══════════════════════════════════════════════════════════
384
  # PIPELINE CONFIGURATION
 
1
  """
2
  Generation logic for Pixagram AI Pixel Art Generator
3
+ CORRECTED VERSION - Following examplewithface.py pattern
4
  """
5
  import torch
6
  import numpy as np
 
21
  load_sdxl_pipeline, load_lora, setup_compel,
22
  setup_scheduler, optimize_pipeline, load_caption_model, set_clip_skip
23
  )
24
+ from pipeline_stable_diffusion_xl_instantid_img2img import draw_kps
25
  from memory_utils import MemoryManager, ModelOffloader
26
 
27
 
 
346
  # Get raw embeddings
347
  face_embeddings = face.normed_embedding
348
 
349
+ # Draw keypoints using imported draw_kps
 
350
  face_kps_image = draw_kps(resized_image, face.kps)
351
 
352
  # Get bbox for color matching
 
372
  elif not self.face_detection_enabled:
373
  print("[FACE] Face detection disabled - generating without face preservation")
374
 
375
+ # Fuse LORA with scale (following working example approach)
376
+ if self.models_loaded['lora']:
377
  try:
378
+ from models import fuse_lora_with_scale
379
+ fuse_lora_with_scale(self.pipe, lora_scale)
380
+ print(f"[LORA] Fused with scale: {lora_scale}")
381
  except Exception as e:
382
+ print(f"[LORA] Could not fuse: {e}")
383
 
384
  # ═══════════════════════════════════════════════════════════
385
  # PIPELINE CONFIGURATION
models.py CHANGED
@@ -1,6 +1,6 @@
1
  """
2
  Model loading and initialization for Pixagram AI Pixel Art Generator
3
- ALTERNATIVE VERSION - Solution 3: Manually set controlnet after pipeline loading
4
  """
5
  import torch
6
  import time
@@ -16,9 +16,10 @@ from controlnet_aux import ZoeDetector
16
  from huggingface_hub import hf_hub_download, snapshot_download
17
  from compel import Compel, ReturnedEmbeddingsType
18
 
19
- # Use InstantID pipeline
20
  from pipeline_stable_diffusion_xl_instantid_img2img import (
21
- StableDiffusionXLInstantIDImg2ImgPipeline
 
22
  )
23
 
24
  from config import (
@@ -175,39 +176,28 @@ def load_controlnets():
175
  def load_sdxl_pipeline(controlnets):
176
  """
177
  Load SDXL pipeline with InstantID support.
178
- Solution 3: Load pipeline without controlnet, then set it manually.
 
179
  """
180
  print("Loading SDXL checkpoint with InstantID pipeline...")
181
  try:
182
  model_path = download_model_with_retry(MODEL_REPO, MODEL_FILES['checkpoint'])
183
 
184
- # Load pipeline WITHOUT controlnet first (Solution 3)
185
- print(" Loading pipeline from single file (without controlnet)...")
 
 
 
 
 
 
186
  pipe = StableDiffusionXLInstantIDImg2ImgPipeline.from_single_file(
187
  model_path,
188
- controlnet=None, # Load without controlnet initially
189
  torch_dtype=dtype,
190
  use_safetensors=True
191
  ).to(device)
192
 
193
- # Now manually set the controlnet
194
- if isinstance(controlnets, list) and len(controlnets) > 1:
195
- print(f" Manually setting MultiControlNetModel with {len(controlnets)} nets...")
196
- pipe.controlnet = MultiControlNetModel(controlnets).to(device, dtype=dtype)
197
- print(f" [VERIFY] pipe.controlnet type: {type(pipe.controlnet)}")
198
- print(f" [VERIFY] pipe.controlnet has {len(pipe.controlnet.nets)} nets")
199
- else:
200
- print(" Setting single ControlNet...")
201
- pipe.controlnet = (controlnets[0] if isinstance(controlnets, list) else controlnets).to(device, dtype=dtype)
202
- print(f" [VERIFY] pipe.controlnet type: {type(pipe.controlnet)}")
203
-
204
- # Verify it's the right type
205
- from diffusers.models import ControlNetModel
206
- if isinstance(pipe.controlnet, (ControlNetModel, MultiControlNetModel)):
207
- print(" ✅ ControlNet properly attached to pipeline")
208
- else:
209
- print(f" ⚠️ WARNING: Unexpected controlnet type: {type(pipe.controlnet)}")
210
-
211
  # Load IP-Adapter weights for InstantID
212
  print("Loading IP-Adapter for InstantID...")
213
  ip_adapter_path = download_model_with_retry(
@@ -229,36 +219,73 @@ def load_sdxl_pipeline(controlnets):
229
  print(" [WARNING] Falling back to standard SDXL pipeline (no InstantID)")
230
  from diffusers import StableDiffusionXLControlNetImg2ImgPipeline
231
 
232
- # Same approach for fallback
 
 
 
 
 
233
  pipe = StableDiffusionXLControlNetImg2ImgPipeline.from_pretrained(
234
  "stabilityai/stable-diffusion-xl-base-1.0",
235
- controlnet=None,
236
  torch_dtype=dtype,
237
  use_safetensors=True
238
  ).to(device)
239
-
240
- # Manually set controlnet for fallback too
241
- if isinstance(controlnets, list) and len(controlnets) > 1:
242
- pipe.controlnet = MultiControlNetModel(controlnets).to(device, dtype=dtype)
243
- else:
244
- pipe.controlnet = (controlnets[0] if isinstance(controlnets, list) else controlnets).to(device, dtype=dtype)
245
-
246
  return pipe, False
247
 
248
 
 
 
 
 
249
  def load_lora(pipe):
250
- """Load LORA from HuggingFace Hub."""
 
 
 
251
  print("Loading LORA (retroart) from HuggingFace Hub...")
 
 
252
  try:
253
  lora_path = download_model_with_retry(MODEL_REPO, MODEL_FILES['lora'])
254
- pipe.load_lora_weights(lora_path, adapter_name="retroart")
255
- print(f" [OK] LORA loaded successfully")
 
 
 
 
256
  return True
 
257
  except Exception as e:
258
  print(f" [WARNING] Could not load LORA: {e}")
259
  return False
260
 
261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  def setup_compel(pipe):
263
  """Setup Compel for better SDXL prompt handling."""
264
  print("Setting up Compel for enhanced prompt processing...")
@@ -353,4 +380,7 @@ def set_clip_skip(pipe):
353
  print(f" [OK] CLIP skip set to {CLIP_SKIP}")
354
 
355
 
356
- print("[OK] Model loading functions ready (Solution 3: Manual controlnet setting)")
 
 
 
 
1
  """
2
  Model loading and initialization for Pixagram AI Pixel Art Generator
3
+ CORRECTED VERSION - Following examplewithface.py exactly
4
  """
5
  import torch
6
  import time
 
16
  from huggingface_hub import hf_hub_download, snapshot_download
17
  from compel import Compel, ReturnedEmbeddingsType
18
 
19
+ # Use InstantID pipeline - import draw_kps too like in working example
20
  from pipeline_stable_diffusion_xl_instantid_img2img import (
21
+ StableDiffusionXLInstantIDImg2ImgPipeline,
22
+ draw_kps
23
  )
24
 
25
  from config import (
 
176
  def load_sdxl_pipeline(controlnets):
177
  """
178
  Load SDXL pipeline with InstantID support.
179
+ controlnets MUST be a list: [identitynet, depthnet]
180
+ Following the working example from examplewithface.py
181
  """
182
  print("Loading SDXL checkpoint with InstantID pipeline...")
183
  try:
184
  model_path = download_model_with_retry(MODEL_REPO, MODEL_FILES['checkpoint'])
185
 
186
+ # Wrap multiple controlnets in MultiControlNetModel (CRITICAL!)
187
+ if isinstance(controlnets, list) and len(controlnets) > 1:
188
+ print(f" Wrapping {len(controlnets)} ControlNets in MultiControlNetModel...")
189
+ multi_controlnet = MultiControlNetModel(controlnets)
190
+ else:
191
+ multi_controlnet = controlnets[0] if isinstance(controlnets, list) else controlnets
192
+
193
+ # Use InstantID-enabled pipeline
194
  pipe = StableDiffusionXLInstantIDImg2ImgPipeline.from_single_file(
195
  model_path,
196
+ controlnet=multi_controlnet,
197
  torch_dtype=dtype,
198
  use_safetensors=True
199
  ).to(device)
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  # Load IP-Adapter weights for InstantID
202
  print("Loading IP-Adapter for InstantID...")
203
  ip_adapter_path = download_model_with_retry(
 
219
  print(" [WARNING] Falling back to standard SDXL pipeline (no InstantID)")
220
  from diffusers import StableDiffusionXLControlNetImg2ImgPipeline
221
 
222
+ # Wrap controlnets for fallback too
223
+ if isinstance(controlnets, list) and len(controlnets) > 1:
224
+ multi_controlnet = MultiControlNetModel(controlnets)
225
+ else:
226
+ multi_controlnet = controlnets[0] if isinstance(controlnets, list) else controlnets
227
+
228
  pipe = StableDiffusionXLControlNetImg2ImgPipeline.from_pretrained(
229
  "stabilityai/stable-diffusion-xl-base-1.0",
230
+ controlnet=multi_controlnet,
231
  torch_dtype=dtype,
232
  use_safetensors=True
233
  ).to(device)
 
 
 
 
 
 
 
234
  return pipe, False
235
 
236
 
237
+ # Global variable to track LORA fusion state (like in working example)
238
+ last_lora_fused = False
239
+
240
+
241
  def load_lora(pipe):
242
+ """
243
+ Load LORA from HuggingFace Hub.
244
+ Following working example: load_lora_weights then fuse_lora
245
+ """
246
  print("Loading LORA (retroart) from HuggingFace Hub...")
247
+ global last_lora_fused
248
+
249
  try:
250
  lora_path = download_model_with_retry(MODEL_REPO, MODEL_FILES['lora'])
251
+
252
+ # Load the LORA weights (don't fuse yet - will fuse with scale before generation)
253
+ pipe.load_lora_weights(lora_path)
254
+
255
+ print(f" [OK] LORA loaded successfully (will fuse with scale before generation)")
256
+ last_lora_fused = False # Track that we need to fuse
257
  return True
258
+
259
  except Exception as e:
260
  print(f" [WARNING] Could not load LORA: {e}")
261
  return False
262
 
263
 
264
+ def fuse_lora_with_scale(pipe, lora_scale):
265
+ """
266
+ Fuse LORA with scale before generation (like in working example).
267
+ This should be called before each generation if scale changed.
268
+ """
269
+ global last_lora_fused
270
+
271
+ try:
272
+ # Unfuse if already fused
273
+ if last_lora_fused:
274
+ print(f" [LORA] Unfusing previous LORA...")
275
+ pipe.unfuse_lora()
276
+
277
+ # Fuse with new scale
278
+ print(f" [LORA] Fusing with scale: {lora_scale}")
279
+ pipe.fuse_lora(lora_scale)
280
+ last_lora_fused = True
281
+
282
+ return True
283
+
284
+ except Exception as e:
285
+ print(f" [WARNING] Could not fuse LORA: {e}")
286
+ return False
287
+
288
+
289
  def setup_compel(pipe):
290
  """Setup Compel for better SDXL prompt handling."""
291
  print("Setting up Compel for enhanced prompt processing...")
 
380
  print(f" [OK] CLIP skip set to {CLIP_SKIP}")
381
 
382
 
383
+ # Export draw_kps for use in generator
384
+ __all__ = ['draw_kps', 'fuse_lora_with_scale', 'last_lora_fused']
385
+
386
+ print("[OK] Model loading functions ready (following examplewithface.py)")