CARLEXsX commited on
Commit
a08fa56
·
verified ·
1 Parent(s): aae4dc9

Update flux_kontext_helpers.py

Browse files
Files changed (1) hide show
  1. flux_kontext_helpers.py +87 -30
flux_kontext_helpers.py CHANGED
@@ -1,5 +1,6 @@
 
1
  # flux_kontext_helpers.py
2
- # Módulo de serviço para o FluxKontext, com gestão de memória atômica.
3
  # Este arquivo é parte do projeto Euia-AducSdr e está sob a licença AGPL v3.
4
  # Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
5
 
@@ -9,36 +10,44 @@ import gc
9
  from diffusers import FluxKontextPipeline
10
  import huggingface_hub
11
  import os
 
12
 
13
- class Generator:
 
 
 
 
14
  def __init__(self, device_id='cuda:0'):
15
  self.cpu_device = torch.device('cpu')
16
- self.gpu_device = torch.device(device_id if torch.cuda.is_available() else 'cpu')
17
- print(f"WORKER COMPOSITOR: Usando dispositivo: {self.gpu_device}")
18
  self.pipe = None
19
  self._load_pipe_to_cpu()
20
 
21
  def _load_pipe_to_cpu(self):
22
  if self.pipe is None:
23
- print("WORKER COMPOSITOR: Carregando modelo FluxKontext para a CPU...")
24
  self.pipe = FluxKontextPipeline.from_pretrained(
25
  "black-forest-labs/FLUX.1-Kontext-dev", torch_dtype=torch.bfloat16
26
  ).to(self.cpu_device)
27
- print("WORKER COMPOSITOR: Modelo FluxKontext pronto (na CPU).")
28
 
29
  def to_gpu(self):
30
- if self.gpu_device.type == 'cpu': return
31
- print(f"WORKER COMPOSITOR: Movendo modelo para {self.gpu_device}...")
32
- self.pipe.to(self.gpu_device)
33
- print(f"WORKER COMPOSITOR: Modelo na GPU {self.gpu_device}.")
 
34
 
35
  def to_cpu(self):
36
- if self.gpu_device.type == 'cpu': return
37
- print(f"WORKER COMPOSITOR: Descarregando modelo da GPU {self.gpu_device}...")
 
38
  self.pipe.to(self.cpu_device)
39
  gc.collect()
40
  if torch.cuda.is_available():
41
  torch.cuda.empty_cache()
 
42
 
43
  def _concatenate_images(self, images, direction="horizontal"):
44
  if not images: return None
@@ -67,32 +76,80 @@ class Generator:
67
  return concatenated
68
 
69
  @torch.inference_mode()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  def generate_image(self, reference_images, prompt, width, height, seed=42):
 
71
  try:
72
- self.to_gpu()
73
-
74
- concatenated_image = self._concatenate_images(reference_images, "horizontal")
75
- if concatenated_image is None:
76
- raise ValueError("Nenhuma imagem de referência válida foi fornecida.")
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- # ### CORREÇÃO ###
79
- # Ignora o tamanho da imagem concatenada e usa os parâmetros `width` e `height` fornecidos.
80
- image = self.pipe(
81
- image=concatenated_image,
82
  prompt=prompt,
83
- guidance_scale=2.5,
84
  width=width,
85
  height=height,
86
- generator=torch.Generator(device="cpu").manual_seed(seed)
87
- ).images[0]
88
-
89
- return image
90
  finally:
91
- self.to_cpu()
 
 
92
 
93
  # --- Instância Singleton ---
94
- print("Inicializando o Compositor de Cenas (FluxKontext)...")
95
  hf_token = os.getenv('HF_TOKEN')
96
  if hf_token: huggingface_hub.login(token=hf_token)
97
- flux_kontext_singleton = Generator(device_id='cuda:0')
98
- print("Compositor de Cenas pronto.")
 
 
 
1
+ #--- START OF MODIFIED FILE app_fluxContext_Ltx/flux_kontext_helpers.py ---
2
  # flux_kontext_helpers.py
3
+ # Módulo de serviço para o FluxKontext, com gestão de memória e revezamento de GPU.
4
  # Este arquivo é parte do projeto Euia-AducSdr e está sob a licença AGPL v3.
5
  # Copyright (C) 4 de Agosto de 2025 Carlos Rodrigues dos Santos
6
 
 
10
  from diffusers import FluxKontextPipeline
11
  import huggingface_hub
12
  import os
13
+ import threading
14
 
15
+ class FluxWorker:
16
+ """
17
+ Representa uma única instância do pipeline FluxKontext, associada a uma GPU específica.
18
+ O pipeline é carregado na CPU por padrão e movido para a GPU sob demanda.
19
+ """
20
  def __init__(self, device_id='cuda:0'):
21
  self.cpu_device = torch.device('cpu')
22
+ self.device = torch.device(device_id if torch.cuda.is_available() else 'cpu')
23
+ print(f"FLUX Worker: Inicializando para o dispositivo {self.device} (carregando na CPU)...")
24
  self.pipe = None
25
  self._load_pipe_to_cpu()
26
 
27
  def _load_pipe_to_cpu(self):
28
  if self.pipe is None:
29
+ print("FLUX Worker: Carregando modelo FluxKontext para a CPU...")
30
  self.pipe = FluxKontextPipeline.from_pretrained(
31
  "black-forest-labs/FLUX.1-Kontext-dev", torch_dtype=torch.bfloat16
32
  ).to(self.cpu_device)
33
+ print("FLUX Worker: Modelo FluxKontext pronto (na CPU).")
34
 
35
  def to_gpu(self):
36
+ """Move o pipeline para a GPU designada."""
37
+ if self.device.type == 'cpu': return
38
+ print(f"FLUX Worker: Movendo modelo para {self.device}...")
39
+ self.pipe.to(self.device)
40
+ print(f"FLUX Worker: Modelo na GPU {self.device}.")
41
 
42
  def to_cpu(self):
43
+ """Move o pipeline de volta para a CPU e limpa a memória da GPU."""
44
+ if self.device.type == 'cpu': return
45
+ print(f"FLUX Worker: Descarregando modelo da GPU {self.device}...")
46
  self.pipe.to(self.cpu_device)
47
  gc.collect()
48
  if torch.cuda.is_available():
49
  torch.cuda.empty_cache()
50
+ print(f"FLUX Worker: GPU {self.device} limpa.")
51
 
52
  def _concatenate_images(self, images, direction="horizontal"):
53
  if not images: return None
 
76
  return concatenated
77
 
78
  @torch.inference_mode()
79
+ def generate_image_internal(self, reference_images, prompt, width, height, seed=42):
80
+ """A lógica real da geração de imagem, que espera estar na GPU."""
81
+ concatenated_image = self._concatenate_images(reference_images, "horizontal")
82
+ if concatenated_image is None:
83
+ raise ValueError("Nenhuma imagem de referência válida foi fornecida.")
84
+
85
+ image = self.pipe(
86
+ image=concatenated_image,
87
+ prompt=prompt,
88
+ guidance_scale=2.5,
89
+ width=width,
90
+ height=height,
91
+ generator=torch.Generator(device="cpu").manual_seed(seed)
92
+ ).images[0]
93
+
94
+ return image
95
+
96
+ class FluxPoolManager:
97
+ """
98
+ Gerencia um pool de FluxWorkers, orquestrando um revezamento entre GPUs
99
+ para permitir que a limpeza de uma GPU ocorra em paralelo com a computação em outra.
100
+ """
101
+ def __init__(self, device_ids=['cuda:0', 'cuda:1']):
102
+ print(f"FLUX POOL MANAGER: Criando workers para os dispositivos: {device_ids}")
103
+ self.workers = [FluxWorker(device_id) for device_id in device_ids]
104
+ self.current_worker_index = 0
105
+ self.lock = threading.Lock()
106
+ self.last_cleanup_thread = None
107
+
108
+ def _cleanup_worker(self, worker):
109
+ """Função alvo para a thread de limpeza."""
110
+ print(f"FLUX CLEANUP THREAD: Iniciando limpeza da GPU {worker.device} em background...")
111
+ worker.to_cpu()
112
+ print(f"FLUX CLEANUP THREAD: Limpeza da GPU {worker.device} concluída.")
113
+
114
  def generate_image(self, reference_images, prompt, width, height, seed=42):
115
+ worker_to_use = None
116
  try:
117
+ with self.lock:
118
+ if self.last_cleanup_thread and self.last_cleanup_thread.is_alive():
119
+ print("FLUX POOL MANAGER: Aguardando limpeza da GPU anterior...")
120
+ self.last_cleanup_thread.join()
121
+ print("FLUX POOL MANAGER: Limpeza anterior concluída.")
122
+
123
+ worker_to_use = self.workers[self.current_worker_index]
124
+ previous_worker_index = (self.current_worker_index - 1 + len(self.workers)) % len(self.workers)
125
+ worker_to_cleanup = self.workers[previous_worker_index]
126
+
127
+ cleanup_thread = threading.Thread(target=self._cleanup_worker, args=(worker_to_cleanup,))
128
+ cleanup_thread.start()
129
+ self.last_cleanup_thread = cleanup_thread
130
+
131
+ worker_to_use.to_gpu()
132
+
133
+ self.current_worker_index = (self.current_worker_index + 1) % len(self.workers)
134
 
135
+ print(f"FLUX POOL MANAGER: Gerando imagem em {worker_to_use.device}...")
136
+ return worker_to_use.generate_image_internal(
137
+ reference_images=reference_images,
 
138
  prompt=prompt,
 
139
  width=width,
140
  height=height,
141
+ seed=seed
142
+ )
 
 
143
  finally:
144
+ # A limpeza do worker_to_use será feita na PRÓXIMA chamada a esta função,
145
+ # permitindo que a computação do LTX ocorra em paralelo.
146
+ pass
147
 
148
  # --- Instância Singleton ---
149
+ print("Inicializando o Compositor de Cenas (FluxKontext Pool Manager)...")
150
  hf_token = os.getenv('HF_TOKEN')
151
  if hf_token: huggingface_hub.login(token=hf_token)
152
+ # Pool do Flux usa cuda:0 e cuda:1
153
+ flux_kontext_singleton = FluxPoolManager(device_ids=['cuda:0', 'cuda:1'])
154
+ print("Compositor de Cenas pronto.")
155
+ #-- END OF MODIFIED FILE app_fluxContext_Ltx/flux_kontext_helpers.py ---