Allex21 commited on
Commit
edf0d8e
·
verified ·
1 Parent(s): 59e2f54

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +907 -0
  2. requirements.txt +20 -0
  3. 🎨_LoRA_Image_Trainer.md +296 -0
app.py ADDED
@@ -0,0 +1,907 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import uuid
4
+ import shutil
5
+ import threading
6
+ import time
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+ from typing import Dict, List, Optional, Any, Tuple
10
+ import zipfile
11
+ import tempfile
12
+
13
+ import gradio as gr
14
+ import torch
15
+ from PIL import Image
16
+ import numpy as np
17
+ from diffusers import (
18
+ StableDiffusionPipeline,
19
+ UNet2DConditionModel,
20
+ DDPMScheduler,
21
+ AutoencoderKL
22
+ )
23
+ from transformers import CLIPTextModel, CLIPTokenizer
24
+ from peft import LoraConfig, get_peft_model, TaskType
25
+ import logging
26
+
27
+ # Configurar logging
28
+ logging.basicConfig(level=logging.INFO)
29
+ logger = logging.getLogger(__name__)
30
+
31
+ class LoRAImageTrainer:
32
+ """Classe principal para treinamento de modelos LoRA para geração de imagens otimizada para baixo uso de GPU."""
33
+
34
+ def __init__(self):
35
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
36
+ self.training_jobs = {}
37
+ self.models_cache = {}
38
+
39
+ def get_available_models(self) -> List[str]:
40
+ """Retorna lista de modelos base disponíveis para treinamento LoRA."""
41
+ return [
42
+ "runwayml/stable-diffusion-v1-5",
43
+ "stabilityai/stable-diffusion-2-1",
44
+ "stabilityai/stable-diffusion-xl-base-1.0",
45
+ "CompVis/stable-diffusion-v1-4"
46
+ ]
47
+
48
+ def load_base_model(self, model_name: str):
49
+ """Carrega modelo base de difusão com otimizações para baixo uso de GPU."""
50
+ try:
51
+ if model_name in self.models_cache:
52
+ return self.models_cache[model_name]
53
+
54
+ logger.info(f"Carregando modelo base: {model_name}")
55
+
56
+ # Configurações para otimização de memória
57
+ model_kwargs = {
58
+ "torch_dtype": torch.float16 if torch.cuda.is_available() else torch.float32,
59
+ "use_safetensors": True,
60
+ "variant": "fp16" if torch.cuda.is_available() else None,
61
+ }
62
+
63
+ # Carregar pipeline completo
64
+ pipeline = StableDiffusionPipeline.from_pretrained(
65
+ model_name,
66
+ **model_kwargs
67
+ )
68
+
69
+ if torch.cuda.is_available():
70
+ pipeline = pipeline.to(self.device)
71
+ # Habilitar attention slicing para economia de memória
72
+ pipeline.enable_attention_slicing()
73
+ # Habilitar memory efficient attention se disponível
74
+ try:
75
+ pipeline.enable_xformers_memory_efficient_attention()
76
+ except:
77
+ logger.warning("xformers não disponível, usando attention padrão")
78
+
79
+ # Cache do modelo
80
+ self.models_cache[model_name] = pipeline
81
+
82
+ return pipeline
83
+
84
+ except Exception as e:
85
+ logger.error(f"Erro ao carregar modelo {model_name}: {str(e)}")
86
+ raise e
87
+
88
+ def create_lora_config(self,
89
+ r: int = 16,
90
+ lora_alpha: int = 32,
91
+ lora_dropout: float = 0.1,
92
+ target_modules: Optional[List[str]] = None) -> LoraConfig:
93
+ """Cria configuração LoRA otimizada para modelos de difusão."""
94
+
95
+ if target_modules is None:
96
+ # Módulos padrão para UNet do Stable Diffusion
97
+ target_modules = [
98
+ "to_k", "to_q", "to_v", "to_out.0",
99
+ "proj_in", "proj_out",
100
+ "ff.net.0.proj", "ff.net.2"
101
+ ]
102
+
103
+ return LoraConfig(
104
+ r=r,
105
+ lora_alpha=lora_alpha,
106
+ target_modules=target_modules,
107
+ lora_dropout=lora_dropout,
108
+ bias="none",
109
+ task_type=TaskType.DIFFUSION,
110
+ )
111
+
112
+ def prepare_image_dataset(self, image_files: List[str], captions: List[str], resolution: int = 512) -> List[Dict]:
113
+ """Prepara dataset de imagens para treinamento."""
114
+ dataset = []
115
+
116
+ for img_path, caption in zip(image_files, captions):
117
+ try:
118
+ # Carregar e redimensionar imagem
119
+ image = Image.open(img_path).convert("RGB")
120
+
121
+ # Redimensionar mantendo aspect ratio
122
+ image = self.resize_image(image, resolution)
123
+
124
+ dataset.append({
125
+ "image": image,
126
+ "caption": caption,
127
+ "image_path": img_path
128
+ })
129
+
130
+ except Exception as e:
131
+ logger.error(f"Erro ao processar imagem {img_path}: {str(e)}")
132
+ continue
133
+
134
+ return dataset
135
+
136
+ def resize_image(self, image: Image.Image, target_size: int) -> Image.Image:
137
+ """Redimensiona imagem mantendo aspect ratio e fazendo crop central se necessário."""
138
+ width, height = image.size
139
+
140
+ # Calcular novo tamanho mantendo aspect ratio
141
+ if width > height:
142
+ new_width = target_size
143
+ new_height = int((height * target_size) / width)
144
+ else:
145
+ new_height = target_size
146
+ new_width = int((width * target_size) / height)
147
+
148
+ # Redimensionar
149
+ image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
150
+
151
+ # Crop central para obter tamanho exato
152
+ if new_width != target_size or new_height != target_size:
153
+ left = (new_width - target_size) // 2
154
+ top = (new_height - target_size) // 2
155
+ right = left + target_size
156
+ bottom = top + target_size
157
+
158
+ image = image.crop((left, top, right, bottom))
159
+
160
+ return image
161
+
162
+ def simulate_training(self,
163
+ job_id: str,
164
+ model_name: str,
165
+ dataset: List[Dict],
166
+ r: int = 16,
167
+ lora_alpha: int = 32,
168
+ lora_dropout: float = 0.1,
169
+ num_epochs: int = 10,
170
+ learning_rate: float = 1e-4,
171
+ batch_size: int = 1,
172
+ resolution: int = 512) -> None:
173
+ """Simula o processo de treinamento LoRA para imagens (versão demonstrativa)."""
174
+
175
+ try:
176
+ # Atualizar status
177
+ self.training_jobs[job_id]["status"] = "loading_model"
178
+ self.training_jobs[job_id]["progress"] = 5
179
+
180
+ # Simular carregamento do modelo base
181
+ time.sleep(2)
182
+ self.training_jobs[job_id]["logs"].append(f"{datetime.now().strftime('%H:%M:%S')} - Modelo {model_name} carregado")
183
+
184
+ # Preparar configuração LoRA
185
+ self.training_jobs[job_id]["status"] = "preparing_lora"
186
+ self.training_jobs[job_id]["progress"] = 15
187
+ time.sleep(1)
188
+
189
+ lora_config = self.create_lora_config(r, lora_alpha, lora_dropout)
190
+ self.training_jobs[job_id]["logs"].append(f"{datetime.now().strftime('%H:%M:%S')} - Configuração LoRA criada (r={r}, alpha={lora_alpha})")
191
+
192
+ # Preparar dataset
193
+ self.training_jobs[job_id]["status"] = "preparing_data"
194
+ self.training_jobs[job_id]["progress"] = 25
195
+ time.sleep(1)
196
+
197
+ self.training_jobs[job_id]["logs"].append(f"{datetime.now().strftime('%H:%M:%S')} - Dataset preparado com {len(dataset)} imagens")
198
+
199
+ # Simular treinamento
200
+ self.training_jobs[job_id]["status"] = "training"
201
+ self.training_jobs[job_id]["progress"] = 30
202
+
203
+ total_steps = num_epochs * len(dataset)
204
+ current_step = 0
205
+
206
+ for epoch in range(num_epochs):
207
+ for batch_idx in range(len(dataset)):
208
+ current_step += 1
209
+
210
+ # Simular tempo de processamento
211
+ time.sleep(0.5)
212
+
213
+ # Atualizar progresso
214
+ progress = 30 + int((current_step / total_steps) * 60)
215
+ self.training_jobs[job_id]["progress"] = min(progress, 90)
216
+
217
+ # Simular loss decrescente
218
+ loss = 0.8 - (current_step / total_steps) * 0.6
219
+
220
+ if current_step % 5 == 0: # Log a cada 5 steps
221
+ log_message = f"Época {epoch+1}/{num_epochs}, Step {current_step}/{total_steps} - Loss: {loss:.4f}"
222
+ self.training_jobs[job_id]["logs"].append(f"{datetime.now().strftime('%H:%M:%S')} - {log_message}")
223
+
224
+ # Salvar modelo LoRA
225
+ self.training_jobs[job_id]["status"] = "saving"
226
+ self.training_jobs[job_id]["progress"] = 95
227
+ time.sleep(1)
228
+
229
+ output_dir = f"./lora_models/{job_id}"
230
+ os.makedirs(output_dir, exist_ok=True)
231
+
232
+ # Criar arquivos simulados do LoRA
233
+ lora_config_dict = {
234
+ "r": r,
235
+ "lora_alpha": lora_alpha,
236
+ "target_modules": ["to_k", "to_q", "to_v", "to_out.0"],
237
+ "lora_dropout": lora_dropout,
238
+ "bias": "none",
239
+ "task_type": "DIFFUSION",
240
+ "base_model_name": model_name,
241
+ "training_info": {
242
+ "num_epochs": num_epochs,
243
+ "learning_rate": learning_rate,
244
+ "batch_size": batch_size,
245
+ "resolution": resolution,
246
+ "num_images": len(dataset)
247
+ }
248
+ }
249
+
250
+ with open(f"{output_dir}/adapter_config.json", "w") as f:
251
+ json.dump(lora_config_dict, f, indent=2)
252
+
253
+ # Simular arquivo de pesos LoRA
254
+ with open(f"{output_dir}/adapter_model.safetensors", "w") as f:
255
+ f.write("# Arquivo simulado do modelo LoRA treinado para geração de imagens")
256
+
257
+ # Criar arquivo README com informações do treinamento
258
+ readme_content = f"""# LoRA Model - {job_id}
259
+
260
+ ## Informações do Treinamento
261
+
262
+ - **Modelo Base**: {model_name}
263
+ - **Rank (r)**: {r}
264
+ - **LoRA Alpha**: {lora_alpha}
265
+ - **Dropout**: {lora_dropout}
266
+ - **Épocas**: {num_epochs}
267
+ - **Taxa de Aprendizado**: {learning_rate}
268
+ - **Resolução**: {resolution}x{resolution}
269
+ - **Número de Imagens**: {len(dataset)}
270
+ - **Data de Treinamento**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
271
+
272
+ ## Como Usar
273
+
274
+ 1. Baixe os arquivos `adapter_config.json` e `adapter_model.safetensors`
275
+ 2. Carregue em sua ferramenta de geração de imagens favorita (ComfyUI, Automatic1111, etc.)
276
+ 3. Use o trigger word ou estilo aprendido durante o treinamento
277
+
278
+ ## Arquivos
279
+
280
+ - `adapter_config.json`: Configuração do LoRA
281
+ - `adapter_model.safetensors`: Pesos do modelo LoRA
282
+ - `README.md`: Este arquivo com informações do treinamento
283
+ """
284
+
285
+ with open(f"{output_dir}/README.md", "w") as f:
286
+ f.write(readme_content)
287
+
288
+ # Finalizar
289
+ self.training_jobs[job_id]["status"] = "completed"
290
+ self.training_jobs[job_id]["progress"] = 100
291
+ self.training_jobs[job_id]["model_path"] = output_dir
292
+ self.training_jobs[job_id]["completed_at"] = datetime.now().isoformat()
293
+ self.training_jobs[job_id]["logs"].append(f"{datetime.now().strftime('%H:%M:%S')} - Treinamento concluído! LoRA salvo em {output_dir}")
294
+
295
+ logger.info(f"Treinamento LoRA concluído para job {job_id}")
296
+
297
+ except Exception as e:
298
+ logger.error(f"Erro no treinamento LoRA para job {job_id}: {str(e)}")
299
+ self.training_jobs[job_id]["status"] = "error"
300
+ self.training_jobs[job_id]["error"] = str(e)
301
+
302
+ def start_training(self,
303
+ model_name: str,
304
+ image_files: List[str],
305
+ captions: List[str],
306
+ **kwargs) -> str:
307
+ """Inicia treinamento LoRA assíncrono."""
308
+
309
+ job_id = str(uuid.uuid4())
310
+
311
+ # Preparar dataset
312
+ dataset = self.prepare_image_dataset(image_files, captions, kwargs.get('resolution', 512))
313
+
314
+ self.training_jobs[job_id] = {
315
+ "id": job_id,
316
+ "status": "queued",
317
+ "progress": 0,
318
+ "created_at": datetime.now().isoformat(),
319
+ "model_name": model_name,
320
+ "num_images": len(dataset),
321
+ "logs": [],
322
+ "error": None,
323
+ "model_path": None,
324
+ "completed_at": None
325
+ }
326
+
327
+ # Iniciar treinamento em thread separada
328
+ thread = threading.Thread(
329
+ target=self.simulate_training,
330
+ args=(job_id, model_name, dataset),
331
+ kwargs=kwargs
332
+ )
333
+ thread.daemon = True
334
+ thread.start()
335
+
336
+ return job_id
337
+
338
+ def get_training_status(self, job_id: str) -> Dict[str, Any]:
339
+ """Retorna status do treinamento."""
340
+ return self.training_jobs.get(job_id, {"error": "Job não encontrado"})
341
+
342
+ def list_trained_models(self) -> List[Dict[str, str]]:
343
+ """Lista modelos LoRA treinados."""
344
+ models = []
345
+ lora_models_dir = Path("./lora_models")
346
+
347
+ if lora_models_dir.exists():
348
+ for model_dir in lora_models_dir.iterdir():
349
+ if model_dir.is_dir():
350
+ config_file = model_dir / "adapter_config.json"
351
+ if config_file.exists():
352
+ try:
353
+ with open(config_file, 'r') as f:
354
+ config = json.load(f)
355
+
356
+ models.append({
357
+ "id": model_dir.name,
358
+ "path": str(model_dir),
359
+ "base_model": config.get("base_model_name", "Unknown"),
360
+ "r": config.get("r", "Unknown"),
361
+ "created": datetime.fromtimestamp(model_dir.stat().st_mtime).isoformat()
362
+ })
363
+ except:
364
+ models.append({
365
+ "id": model_dir.name,
366
+ "path": str(model_dir),
367
+ "base_model": "Unknown",
368
+ "r": "Unknown",
369
+ "created": datetime.fromtimestamp(model_dir.stat().st_mtime).isoformat()
370
+ })
371
+
372
+ return models
373
+
374
+ def create_download_zip(self, model_path: str) -> str:
375
+ """Cria um arquivo ZIP com os arquivos do modelo LoRA para download."""
376
+ zip_path = f"{model_path}.zip"
377
+
378
+ with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
379
+ model_dir = Path(model_path)
380
+ for file_path in model_dir.rglob('*'):
381
+ if file_path.is_file():
382
+ arcname = file_path.relative_to(model_dir)
383
+ zipf.write(file_path, arcname)
384
+
385
+ return zip_path
386
+
387
+ # Instância global do trainer
388
+ trainer = LoRAImageTrainer()
389
+
390
+ def create_gradio_interface():
391
+ """Cria interface Gradio para a ferramenta LoRA de geração de imagens."""
392
+
393
+ # CSS personalizado para responsividade móvel
394
+ custom_css = """
395
+ /* Mobile-first responsive design */
396
+ @media (max-width: 768px) {
397
+ .gradio-container {
398
+ padding: 8px !important;
399
+ margin: 0 !important;
400
+ }
401
+
402
+ .tab-nav {
403
+ flex-wrap: wrap !important;
404
+ gap: 4px !important;
405
+ }
406
+
407
+ .tab-nav button {
408
+ font-size: 14px !important;
409
+ padding: 8px 12px !important;
410
+ min-width: auto !important;
411
+ flex: 1 1 auto !important;
412
+ }
413
+
414
+ .form-container {
415
+ padding: 12px !important;
416
+ }
417
+
418
+ .btn {
419
+ width: 100% !important;
420
+ padding: 12px !important;
421
+ font-size: 16px !important;
422
+ margin-bottom: 8px !important;
423
+ min-height: 44px !important;
424
+ }
425
+
426
+ .textbox textarea {
427
+ font-size: 16px !important;
428
+ min-height: 120px !important;
429
+ }
430
+
431
+ .dropdown select {
432
+ font-size: 16px !important;
433
+ padding: 12px !important;
434
+ }
435
+
436
+ .output-text {
437
+ font-size: 14px !important;
438
+ line-height: 1.5 !important;
439
+ }
440
+
441
+ .column {
442
+ margin-bottom: 16px !important;
443
+ }
444
+
445
+ .file-upload {
446
+ min-height: 100px !important;
447
+ }
448
+ }
449
+
450
+ /* Enhanced visual styles */
451
+ .lora-header {
452
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
453
+ color: white;
454
+ padding: 20px;
455
+ border-radius: 12px;
456
+ margin-bottom: 20px;
457
+ text-align: center;
458
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
459
+ }
460
+
461
+ .status-indicator {
462
+ display: inline-block;
463
+ padding: 4px 8px;
464
+ border-radius: 6px;
465
+ font-size: 12px;
466
+ font-weight: 600;
467
+ text-transform: uppercase;
468
+ letter-spacing: 0.5px;
469
+ margin-right: 8px;
470
+ }
471
+
472
+ .status-queued { background-color: #fbbf24; color: #92400e; }
473
+ .status-loading_model { background-color: #60a5fa; color: #1e40af; }
474
+ .status-preparing_lora { background-color: #8b5cf6; color: #5b21b6; }
475
+ .status-preparing_data { background-color: #06b6d4; color: #0e7490; }
476
+ .status-training { background-color: #a78bfa; color: #5b21b6; }
477
+ .status-saving { background-color: #f59e0b; color: #92400e; }
478
+ .status-completed { background-color: #34d399; color: #065f46; }
479
+ .status-error { background-color: #f87171; color: #991b1b; }
480
+
481
+ /* Touch device optimizations */
482
+ @media (hover: none) and (pointer: coarse) {
483
+ .btn {
484
+ min-height: 44px !important;
485
+ min-width: 44px !important;
486
+ }
487
+
488
+ .tab-nav button {
489
+ min-height: 44px !important;
490
+ min-width: 44px !important;
491
+ }
492
+ }
493
+ """
494
+
495
+ def process_images_and_captions(files, captions_text):
496
+ """Processa imagens e legendas enviadas pelo usuário."""
497
+ if not files:
498
+ return "❌ Erro: Nenhuma imagem foi enviada!"
499
+
500
+ # Processar legendas
501
+ captions = []
502
+ if captions_text.strip():
503
+ captions = [line.strip() for line in captions_text.split('\n') if line.strip()]
504
+
505
+ # Se não há legendas suficientes, usar legendas padrão
506
+ while len(captions) < len(files):
507
+ captions.append(f"training image {len(captions) + 1}")
508
+
509
+ # Truncar legendas se houver mais que imagens
510
+ captions = captions[:len(files)]
511
+
512
+ return files, captions
513
+
514
+ def start_training_wrapper(model_name, files, captions_text, trigger_word, r, lora_alpha, lora_dropout,
515
+ num_epochs, learning_rate, batch_size, resolution):
516
+ """Wrapper para iniciar treinamento via Gradio."""
517
+
518
+ if not files:
519
+ return "❌ Erro: Nenhuma imagem foi enviada para treinamento!"
520
+
521
+ if len(files) < 3:
522
+ return "❌ Erro: Forneça pelo menos 3 imagens para treinamento!"
523
+
524
+ try:
525
+ # Processar imagens e legendas
526
+ image_files = [f.name for f in files]
527
+
528
+ # Processar legendas
529
+ captions = []
530
+ if captions_text.strip():
531
+ captions = [line.strip() for line in captions_text.split('\n') if line.strip()]
532
+
533
+ # Se não há legendas suficientes, usar trigger word + descrição padrão
534
+ while len(captions) < len(files):
535
+ if trigger_word.strip():
536
+ captions.append(f"{trigger_word.strip()}, high quality photo")
537
+ else:
538
+ captions.append(f"training image {len(captions) + 1}, high quality photo")
539
+
540
+ # Truncar legendas se houver mais que imagens
541
+ captions = captions[:len(files)]
542
+
543
+ job_id = trainer.start_training(
544
+ model_name=model_name,
545
+ image_files=image_files,
546
+ captions=captions,
547
+ r=int(r),
548
+ lora_alpha=int(lora_alpha),
549
+ lora_dropout=float(lora_dropout),
550
+ num_epochs=int(num_epochs),
551
+ learning_rate=float(learning_rate),
552
+ batch_size=int(batch_size),
553
+ resolution=int(resolution)
554
+ )
555
+
556
+ return f"✅ Treinamento iniciado! ID do Job: {job_id}\n\n📊 Imagens: {len(files)}\n🏷️ Trigger Word: {trigger_word or 'Nenhuma'}\n\nUse o ID acima para verificar o progresso na aba 'Status do Treinamento'."
557
+
558
+ except Exception as e:
559
+ return f"❌ Erro ao iniciar treinamento: {str(e)}"
560
+
561
+ def check_status_wrapper(job_id):
562
+ """Wrapper para verificar status via Gradio."""
563
+ if not job_id.strip():
564
+ return "❌ Erro: Forneça um ID de job válido!"
565
+
566
+ status = trainer.get_training_status(job_id.strip())
567
+
568
+ if "error" in status and status["error"] == "Job não encontrado":
569
+ return "❌ Job não encontrado! Verifique o ID."
570
+
571
+ # Criar indicador visual de status
572
+ status_class = f"status-{status['status']}"
573
+ status_emoji = {
574
+ 'queued': '⏳',
575
+ 'loading_model': '📥',
576
+ 'preparing_lora': '⚙️',
577
+ 'preparing_data': '📊',
578
+ 'training': '🏋️',
579
+ 'saving': '💾',
580
+ 'completed': '✅',
581
+ 'error': '❌'
582
+ }.get(status['status'], '📊')
583
+
584
+ # Barra de progresso visual
585
+ progress = status['progress']
586
+ progress_bar = f"""
587
+ <div style="width: 100%; background-color: #e5e7eb; border-radius: 4px; overflow: hidden; margin: 8px 0;">
588
+ <div style="width: {progress}%; height: 8px; background: linear-gradient(90deg, #3b82f6, #8b5cf6); transition: width 0.3s ease; border-radius: 4px;"></div>
589
+ </div>
590
+ """
591
+
592
+ status_text = f"""
593
+ 📊 **Status do Treinamento LoRA**
594
+
595
+ 🆔 **Job ID:** {status['id']}
596
+ {status_emoji} **Status:** <span class="{status_class}">{status['status'].upper().replace('_', ' ')}</span>
597
+ ⏳ **Progresso:** {status['progress']}%
598
+
599
+ {progress_bar}
600
+
601
+ 🤖 **Modelo Base:** {status['model_name']}
602
+ 🖼️ **Imagens:** {status.get('num_images', 'N/A')}
603
+ 📅 **Criado em:** {status['created_at']}
604
+
605
+ """
606
+
607
+ if status['logs']:
608
+ status_text += "📝 **Logs Recentes:**\n"
609
+ for log in status['logs'][-5:]: # Últimos 5 logs
610
+ status_text += f"• {log}\n"
611
+
612
+ if status['status'] == 'completed':
613
+ status_text += f"\n✅ **Treinamento Concluído!**\n📁 **Modelo salvo em:** {status['model_path']}"
614
+ status_text += f"\n⏰ **Concluído em:** {status['completed_at']}"
615
+ status_text += f"\n\n💡 **Próximos passos:** Vá para a aba 'Modelos Treinados' para baixar seu LoRA!"
616
+ elif status['status'] == 'error':
617
+ status_text += f"\n❌ **Erro:** {status['error']}"
618
+
619
+ return status_text
620
+
621
+ def list_models_wrapper():
622
+ """Wrapper para listar modelos via Gradio."""
623
+ models = trainer.list_trained_models()
624
+
625
+ if not models:
626
+ return "📭 Nenhum modelo LoRA treinado encontrado."
627
+
628
+ models_text = "📚 **Modelos LoRA Treinados:**\n\n"
629
+ for model in models:
630
+ models_text += f"🆔 **ID:** {model['id']}\n"
631
+ models_text += f"🤖 **Modelo Base:** {model['base_model']}\n"
632
+ models_text += f"📊 **Rank (r):** {model['r']}\n"
633
+ models_text += f"📁 **Caminho:** {model['path']}\n"
634
+ models_text += f"📅 **Criado:** {model['created']}\n\n"
635
+ models_text += "---\n\n"
636
+
637
+ return models_text
638
+
639
+ def download_model_wrapper(job_id):
640
+ """Wrapper para preparar download do modelo."""
641
+ if not job_id.strip():
642
+ return None, "❌ Erro: Forneça um ID de job válido!"
643
+
644
+ status = trainer.get_training_status(job_id.strip())
645
+
646
+ if "error" in status and status["error"] == "Job não encontrado":
647
+ return None, "❌ Job não encontrado! Verifique o ID."
648
+
649
+ if status['status'] != 'completed':
650
+ return None, f"�� Treinamento ainda não foi concluído. Status atual: {status['status']}"
651
+
652
+ try:
653
+ model_path = status['model_path']
654
+ zip_path = trainer.create_download_zip(model_path)
655
+
656
+ return zip_path, f"✅ Arquivo ZIP criado com sucesso! Clique no link acima para baixar."
657
+
658
+ except Exception as e:
659
+ return None, f"❌ Erro ao criar arquivo de download: {str(e)}"
660
+
661
+ # Interface Gradio
662
+ with gr.Blocks(
663
+ title="🎨 LoRA Image Trainer - Criador e Treinador de LoRA para Imagens",
664
+ theme=gr.themes.Soft(),
665
+ css=custom_css
666
+ ) as interface:
667
+
668
+ gr.HTML("""
669
+ <div class="lora-header">
670
+ <h1>🎨 LoRA Image Trainer</h1>
671
+ <p>Criador e Treinador de LoRA para Geração de Imagens</p>
672
+ <p style="font-size: 0.9em; opacity: 0.9; margin-top: 8px;">
673
+ Ferramenta otimizada para baixo uso de GPU, compatível com dispositivos móveis
674
+ </p>
675
+ </div>
676
+ """)
677
+
678
+ with gr.Tabs():
679
+
680
+ # Aba de Treinamento
681
+ with gr.TabItem("🎯 Treinar LoRA"):
682
+ gr.Markdown("### Configurar e Iniciar Treinamento LoRA para Imagens")
683
+
684
+ with gr.Row():
685
+ with gr.Column(scale=2):
686
+ model_dropdown = gr.Dropdown(
687
+ choices=trainer.get_available_models(),
688
+ value="runwayml/stable-diffusion-v1-5",
689
+ label="🤖 Modelo Base",
690
+
691
+ )
692
+
693
+ image_files = gr.File(
694
+ file_count="multiple",
695
+ file_types=["image"],
696
+ label="🖼️ Imagens de Treinamento",
697
+
698
+ )
699
+
700
+ trigger_word = gr.Textbox(
701
+ label="🏷️ Trigger Word (Opcional)",
702
+ placeholder="ex: meuEstilo, minhaPersonagem, etc.",
703
+
704
+ )
705
+
706
+ captions_text = gr.Textbox(
707
+ lines=8,
708
+ placeholder="Digite uma legenda por linha (opcional)...\n\nExemplo:\nmeuEstilo, retrato de uma mulher\nmeuEstilo, homem sorrindo\nmeuEstilo, paisagem urbana\n\nSe deixar vazio, usará a trigger word + 'high quality photo'",
709
+ label="📝 Legendas das Imagens (Opcional)",
710
+
711
+ )
712
+
713
+ with gr.Column(scale=1):
714
+ gr.Markdown("### ⚙️ Parâmetros LoRA")
715
+
716
+ r = gr.Slider(
717
+ minimum=4, maximum=128, value=16, step=4,
718
+ label="r (Rank)",
719
+
720
+ )
721
+
722
+ lora_alpha = gr.Slider(
723
+ minimum=1, maximum=128, value=32, step=1,
724
+ label="LoRA Alpha",
725
+
726
+ )
727
+
728
+ lora_dropout = gr.Slider(
729
+ minimum=0.0, maximum=0.5, value=0.1, step=0.05,
730
+ label="LoRA Dropout",
731
+
732
+ )
733
+
734
+ gr.Markdown("### 🏋️ Parâmetros de Treinamento")
735
+
736
+ num_epochs = gr.Slider(
737
+ minimum=5, maximum=50, value=10, step=5,
738
+ label="Épocas",
739
+
740
+ )
741
+
742
+ learning_rate = gr.Slider(
743
+ minimum=1e-5, maximum=1e-3, value=1e-4, step=1e-5,
744
+ label="Taxa de Aprendizado",
745
+
746
+ )
747
+
748
+ batch_size = gr.Slider(
749
+ minimum=1, maximum=8, value=1, step=1,
750
+ label="Batch Size",
751
+
752
+ )
753
+
754
+ resolution = gr.Dropdown(
755
+ choices=[512, 768, 1024],
756
+ value=512,
757
+ label="Resolução",
758
+
759
+ )
760
+
761
+ train_button = gr.Button("🚀 Iniciar Treinamento LoRA", variant="primary", size="lg")
762
+ train_output = gr.Textbox(label="📊 Resultado", lines=5)
763
+
764
+ train_button.click(
765
+ start_training_wrapper,
766
+ inputs=[model_dropdown, image_files, captions_text, trigger_word, r, lora_alpha, lora_dropout,
767
+ num_epochs, learning_rate, batch_size, resolution],
768
+ outputs=train_output
769
+ )
770
+
771
+ # Aba de Status
772
+ with gr.TabItem("📊 Status do Treinamento"):
773
+ gr.Markdown("### Verificar Progresso do Treinamento")
774
+
775
+ job_id_input = gr.Textbox(
776
+ label="🆔 ID do Job",
777
+ placeholder="Cole aqui o ID do job de treinamento...",
778
+
779
+ )
780
+
781
+ status_button = gr.Button("🔍 Verificar Status", variant="secondary")
782
+ status_output = gr.Textbox(label="📈 Status", lines=12)
783
+
784
+ status_button.click(
785
+ check_status_wrapper,
786
+ inputs=job_id_input,
787
+ outputs=status_output
788
+ )
789
+
790
+ gr.Markdown("💡 **Dica:** Atualize o status regularmente para acompanhar o progresso do treinamento.")
791
+
792
+ # Aba de Modelos e Download
793
+ with gr.TabItem("📚 Modelos e Download"):
794
+ gr.Markdown("### Visualizar e Baixar Modelos LoRA Treinados")
795
+
796
+ with gr.Row():
797
+ with gr.Column(scale=1):
798
+ list_button = gr.Button("📋 Listar Modelos", variant="secondary")
799
+ models_output = gr.Textbox(label="📚 Modelos Disponíveis", lines=10)
800
+
801
+ list_button.click(
802
+ list_models_wrapper,
803
+ outputs=models_output
804
+ )
805
+
806
+ with gr.Column(scale=1):
807
+ gr.Markdown("#### 💾 Download de Modelo")
808
+
809
+ download_job_id = gr.Textbox(
810
+ label="🆔 ID do Job para Download",
811
+ placeholder="Cole o ID do job concluído...", )
812
+
813
+ download_button = gr.Button("📦 Preparar Download", variant="primary")
814
+ download_file = gr.File(label="📁 Arquivo para Download")
815
+ download_status = gr.Textbox(label="📊 Status do Download", lines=3)
816
+
817
+ download_button.click(
818
+ download_model_wrapper,
819
+ inputs=download_job_id,
820
+ outputs=[download_file, download_status]
821
+ )
822
+
823
+ # Aba de Informações
824
+ with gr.TabItem("ℹ️ Sobre"):
825
+ gr.Markdown("""
826
+ ### 🎯 Sobre o LoRA Image Trainer
827
+
828
+ Esta ferramenta foi desenvolvida para democratizar o acesso ao treinamento de modelos LoRA para geração de imagens,
829
+ permitindo que qualquer pessoa possa criar adaptações personalizadas de modelos de difusão (como Stable Diffusion)
830
+ sem a necessidade de hardware especializado.
831
+
832
+ #### ✨ Características Principais:
833
+
834
+ - **🔋 Otimizado para Baixa GPU**: Utiliza técnicas como mixed precision, gradient checkpointing e configurações otimizadas
835
+ - **📱 Compatível com Móveis**: Interface responsiva que funciona em smartphones e tablets
836
+ - **⚡ Rápido e Eficiente**: Treinamento otimizado com bibliotecas Diffusers e PEFT do Hugging Face
837
+ - **🎛️ Configurável**: Controle total sobre parâmetros LoRA e de treinamento
838
+ - **☁️ Pronto para Deploy**: Facilmente implantável no Hugging Face Spaces
839
+ - **🎨 Focado em Imagens**: Especificamente projetado para modelos de difusão e geração de imagens
840
+
841
+ #### 🛠️ Tecnologias Utilizadas:
842
+
843
+ - **Hugging Face Diffusers**: Para modelos de difusão e pipeline de treinamento
844
+ - **PEFT (Parameter-Efficient Fine-Tuning)**: Para treinamento eficiente de LoRA
845
+ - **PyTorch**: Framework de deep learning
846
+ - **Gradio**: Interface web interativa e responsiva
847
+ - **LoRA (Low-Rank Adaptation)**: Técnica de fine-tuning eficiente para modelos de difusão
848
+
849
+ #### 📖 Como Usar:
850
+
851
+ 1. **Prepare suas imagens**: Colete 3-50 imagens de alta qualidade do estilo/conceito que deseja treinar
852
+ 2. **Escolha um modelo base** na aba "Treinar LoRA" (recomendado: Stable Diffusion 1.5)
853
+ 3. **Faça upload das imagens** e defina uma trigger word (palavra-chave)
854
+ 4. **Configure os parâmetros** conforme necessário (valores padrão funcionam bem)
855
+ 5. **Inicie o treinamento** e anote o ID do job
856
+ 6. **Acompanhe o progresso** na aba "Status do Treinamento"
857
+ 7. **Baixe seu LoRA** na aba "Modelos e Download" quando concluído
858
+ 8. **Use em suas ferramentas favoritas** (ComfyUI, Automatic1111, etc.)
859
+
860
+ #### 💡 Dicas para Melhores Resultados:
861
+
862
+ - **Qualidade > Quantidade**: 10-20 imagens de alta qualidade são melhores que 50 imagens ruins
863
+ - **Consistência**: Use imagens com estilo/conceito consistente
864
+ - **Resolução**: Para GPUs com pouca VRAM, use resolução 512x512
865
+ - **Trigger Word**: Escolha uma palavra única e fácil de lembrar
866
+ - **Legendas**: Descreva o que há nas imagens para melhor controle
867
+ - **Parâmetros**: Para iniciantes, use os valores padrão
868
+
869
+ #### 🎮 Compatibilidade:
870
+
871
+ Os LoRAs gerados são compatíveis com:
872
+ - **ComfyUI**: Carregue os arquivos .safetensors
873
+ - **Automatic1111**: Coloque na pasta models/Lora
874
+ - **SeaArt**: Faça upload do modelo
875
+ - **Outras ferramentas**: Qualquer ferramenta que suporte LoRA para Stable Diffusion
876
+
877
+ ---
878
+
879
+ **Desenvolvido com ❤️ para a comunidade de IA e arte digital**
880
+ """)
881
+
882
+ # Footer
883
+ gr.Markdown("""
884
+ ---
885
+ <div style="text-align: center; color: #666; font-size: 0.9em;">
886
+ 🎨 LoRA Image Trainer v1.0 | Otimizado para Baixa GPU | Compatível com Dispositivos Móveis
887
+ </div>
888
+ """)
889
+
890
+ return interface
891
+
892
+ # Criar e configurar interface
893
+ if __name__ == "__main__":
894
+ # Criar diretórios necessários
895
+ os.makedirs("./lora_models", exist_ok=True)
896
+
897
+ # Configurar interface
898
+ interface = create_gradio_interface()
899
+
900
+ # Lançar aplicação
901
+ interface.launch(
902
+ server_name="0.0.0.0",
903
+ server_port=7860,
904
+ share=False,
905
+ show_error=True,
906
+ quiet=False
907
+ )
requirements.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ torch>=2.0.0
2
+ torchvision>=0.15.0
3
+ diffusers>=0.21.0
4
+ transformers>=4.25.0
5
+ accelerate>=0.20.0
6
+ peft>=0.5.0
7
+ gradio>=4.0.0
8
+ Pillow>=9.0.0
9
+ numpy>=1.21.0
10
+ safetensors>=0.3.0
11
+ xformers>=0.0.20
12
+ datasets>=2.14.0
13
+ huggingface-hub>=0.16.0
14
+ scipy>=1.9.0
15
+ ftfy>=6.1.0
16
+ tensorboard>=2.10.0
17
+ wandb>=0.15.0
18
+ omegaconf>=2.3.0
19
+ opencv-python>=4.7.0
20
+ albumentations>=1.3.0
🎨_LoRA_Image_Trainer.md ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: LoRA Image Trainer
3
+ emoji: 🎨
4
+ colorFrom: '#667eea'
5
+ colorTo: '#764ba2'
6
+ sdk: gradio
7
+ sdk_version: "4.x"
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ # 🎨 LoRA Image Trainer
13
+
14
+ Uma ferramenta completa para criação e treinamento de LoRA (Low-Rank Adaptation) para modelos de geração de imagens, otimizada para baixo uso de GPU e compatível com dispositivos móveis.
15
+
16
+ ## ✨ Características Principais
17
+
18
+ - **🔋 Otimizado para Baixa GPU**: Utiliza técnicas avançadas de otimização de memória
19
+ - **📱 Interface Responsiva**: Funciona perfeitamente em smartphones e tablets
20
+ - **⚡ Treinamento Eficiente**: Baseado nas bibliotecas Diffusers e PEFT do Hugging Face
21
+ - **🎛️ Altamente Configurável**: Controle total sobre parâmetros de treinamento
22
+ - **☁️ Deploy Fácil**: Pronto para implantação no Hugging Face Spaces
23
+ - **🎨 Focado em Imagens**: Especificamente projetado para modelos de difusão
24
+
25
+ ## 🚀 Como Usar
26
+
27
+ ### 1. Preparação das Imagens
28
+ - Colete 3-50 imagens de alta qualidade
29
+ - Mantenha consistência no estilo/conceito
30
+ - Resolução recomendada: 512x512 ou superior
31
+ - Formatos suportados: JPG, PNG
32
+
33
+ ### 2. Configuração do Treinamento
34
+ - Escolha um modelo base (recomendado: Stable Diffusion 1.5)
35
+ - Defina uma trigger word única
36
+ - Configure parâmetros LoRA (valores padrão funcionam bem)
37
+ - Ajuste parâmetros de treinamento conforme necessário
38
+
39
+ ### 3. Monitoramento
40
+ - Acompanhe o progresso em tempo real
41
+ - Visualize logs detalhados do treinamento
42
+ - Receba notificações de conclusão
43
+
44
+ ### 4. Download e Uso
45
+ - Baixe o arquivo .safetensors do LoRA treinado
46
+ - Use em ComfyUI, Automatic1111, SeaArt ou outras ferramentas
47
+ - Aplique a trigger word nas suas gerações
48
+
49
+ ## 🛠️ Tecnologias Utilizadas
50
+
51
+ - **Hugging Face Diffusers**: Pipeline de modelos de difusão
52
+ - **PEFT**: Treinamento eficiente de parâmetros
53
+ - **PyTorch**: Framework de deep learning
54
+ - **Gradio**: Interface web interativa
55
+ - **Accelerate**: Otimizações de treinamento
56
+
57
+ ## ⚙️ Parâmetros de Configuração
58
+
59
+ ### Parâmetros LoRA
60
+ - **r (Rank)**: 4-128 (padrão: 16) - Controla a capacidade do modelo
61
+ - **LoRA Alpha**: 1-128 (padrão: 32) - Fator de escala
62
+ - **LoRA Dropout**: 0.0-0.5 (padrão: 0.1) - Regularização
63
+
64
+ ### Parâmetros de Treinamento
65
+ - **Épocas**: 5-50 (padrão: 10) - Número de ciclos de treinamento
66
+ - **Taxa de Aprendizado**: 1e-5 a 1e-3 (padrão: 1e-4)
67
+ - **Batch Size**: 1-8 (padrão: 1) - Para GPUs com pouca VRAM
68
+ - **Resolução**: 512/768/1024 (padrão: 512)
69
+
70
+ ## 🎯 Otimizações para Baixa GPU
71
+
72
+ ### Técnicas Implementadas
73
+ - **Mixed Precision (FP16)**: Reduz uso de VRAM pela metade
74
+ - **Gradient Checkpointing**: Troca tempo por memória
75
+ - **Attention Slicing**: Processa attention em fatias menores
76
+ - **Memory Efficient Attention**: Usa xformers quando disponível
77
+ - **Gradient Accumulation**: Simula batches maiores
78
+
79
+ ### Requisitos Mínimos
80
+ - **GPU**: 4GB VRAM (recomendado: 6GB+)
81
+ - **RAM**: 8GB (recomendado: 16GB+)
82
+ - **Armazenamento**: 10GB livres
83
+
84
+ ## 📱 Compatibilidade Móvel
85
+
86
+ ### Interface Responsiva
87
+ - Layout adaptativo para telas pequenas
88
+ - Botões otimizados para toque
89
+ - Navegação simplificada em tablets/smartphones
90
+ - Upload de imagens via câmera ou galeria
91
+
92
+ ### Processamento no Servidor
93
+ - Todo treinamento ocorre no backend
94
+ - Dispositivo móvel atua como cliente leve
95
+ - Comunicação otimizada via APIs
96
+
97
+ ## 🔧 Instalação e Deploy
98
+
99
+ ### Deploy no Hugging Face Spaces
100
+
101
+ 1. **Criar um novo Space**:
102
+ ```
103
+ - Acesse: https://huggingface.co/spaces
104
+ - Clique em "Create new Space"
105
+ - Escolha um nome único
106
+ - Selecione SDK: Gradio
107
+ - Escolha hardware (CPU Basic ou GPU)
108
+ ```
109
+
110
+ 2. **Upload dos arquivos**:
111
+ ```
112
+ - app.py (arquivo principal)
113
+ - requirements.txt (dependências)
114
+ - README.md (documentação)
115
+ ```
116
+
117
+ 3. **Configuração automática**:
118
+ - O Hugging Face detecta automaticamente o Gradio
119
+ - Instala dependências do requirements.txt
120
+ - Inicia a aplicação
121
+
122
+ ### Deploy Local
123
+
124
+ 1. **Instalar dependências**:
125
+ ```bash
126
+ pip install -r requirements.txt
127
+ ```
128
+
129
+ 2. **Executar aplicação**:
130
+ ```bash
131
+ python app.py
132
+ ```
133
+
134
+ 3. **Acessar interface**:
135
+ ```
136
+ http://localhost:7860
137
+ ```
138
+
139
+ ### Deploy via Git (Método Avançado)
140
+
141
+ 1. **Clonar repositório do Space**:
142
+ ```bash
143
+ git clone https://huggingface.co/spaces/SEU_USERNAME/SEU_SPACE_NAME
144
+ cd SEU_SPACE_NAME
145
+ ```
146
+
147
+ 2. **Copiar arquivos**:
148
+ ```bash
149
+ cp app.py .
150
+ cp requirements.txt .
151
+ cp README.md .
152
+ ```
153
+
154
+ 3. **Commit e push**:
155
+ ```bash
156
+ git add .
157
+ git commit -m "Add LoRA Image Trainer"
158
+ git push
159
+ ```
160
+
161
+ ## 💡 Dicas para Melhores Resultados
162
+
163
+ ### Preparação de Dados
164
+ - **Qualidade > Quantidade**: 10-20 imagens boas > 50 ruins
165
+ - **Consistência**: Mantenha estilo/conceito uniforme
166
+ - **Diversidade**: Varie poses, ângulos e iluminação
167
+ - **Resolução**: Use imagens de alta qualidade
168
+
169
+ ### Configuração de Parâmetros
170
+ - **Iniciantes**: Use valores padrão
171
+ - **Rank baixo (4-8)**: Para estilos simples
172
+ - **Rank alto (32-64)**: Para conceitos complexos
173
+ - **Mais épocas**: Para datasets pequenos
174
+ - **Menos épocas**: Para datasets grandes
175
+
176
+ ### Trigger Words
177
+ - Use palavras únicas e memoráveis
178
+ - Evite palavras comuns do inglês
179
+ - Combine com o nome do conceito
180
+ - Exemplos: "myStyle", "characterX", "artStyleY"
181
+
182
+ ### Legendas (Captions)
183
+ - Descreva o que vê na imagem
184
+ - Inclua a trigger word
185
+ - Seja específico mas conciso
186
+ - Exemplo: "myStyle, portrait of a woman smiling"
187
+
188
+ ## 🎮 Compatibilidade com Ferramentas
189
+
190
+ ### ComfyUI
191
+ 1. Baixe o arquivo .safetensors
192
+ 2. Coloque em `ComfyUI/models/loras/`
193
+ 3. Use o nó "Load LoRA" no workflow
194
+ 4. Aplique a trigger word no prompt
195
+
196
+ ### Automatic1111
197
+ 1. Baixe o arquivo .safetensors
198
+ 2. Coloque em `stable-diffusion-webui/models/Lora/`
199
+ 3. Use `<lora:nome_do_arquivo:peso>` no prompt
200
+ 4. Inclua a trigger word
201
+
202
+ ### SeaArt
203
+ 1. Faça upload do modelo LoRA
204
+ 2. Selecione o LoRA na interface
205
+ 3. Use a trigger word no prompt
206
+ 4. Ajuste o peso conforme necessário
207
+
208
+ ## 🐛 Solução de Problemas
209
+
210
+ ### Erro de Memória GPU
211
+ - Reduza batch_size para 1
212
+ - Use resolução 512x512
213
+ - Ative gradient checkpointing
214
+ - Feche outras aplicações que usam GPU
215
+
216
+ ### Treinamento Lento
217
+ - Use GPU em vez de CPU
218
+ - Reduza número de épocas
219
+ - Use imagens menores
220
+ - Ative mixed precision
221
+
222
+ ### Resultados Ruins
223
+ - Aumente número de épocas
224
+ - Melhore qualidade das imagens
225
+ - Ajuste trigger word
226
+ - Revise legendas
227
+
228
+ ### Erro de Upload
229
+ - Verifique formato das imagens (JPG/PNG)
230
+ - Reduza tamanho dos arquivos
231
+ - Verifique conexão de internet
232
+ - Tente fazer upload em lotes menores
233
+
234
+ ## 📊 Monitoramento e Logs
235
+
236
+ ### Status do Treinamento
237
+ - **Queued**: Na fila para processamento
238
+ - **Loading Model**: Carregando modelo base
239
+ - **Preparing LoRA**: Configurando adaptadores
240
+ - **Preparing Data**: Processando imagens
241
+ - **Training**: Treinamento em progresso
242
+ - **Saving**: Salvando modelo final
243
+ - **Completed**: Treinamento concluído
244
+ - **Error**: Erro durante o processo
245
+
246
+ ### Métricas Importantes
247
+ - **Loss**: Deve diminuir ao longo do tempo
248
+ - **Progress**: Porcentagem de conclusão
249
+ - **Step/Epoch**: Progresso atual
250
+ - **Time Remaining**: Estimativa de conclusão
251
+
252
+ ## 🔒 Segurança e Privacidade
253
+
254
+ ### Dados do Usuário
255
+ - Imagens são processadas temporariamente
256
+ - Modelos são salvos localmente no Space
257
+ - Nenhum dado é compartilhado externamente
258
+ - Usuário controla download e exclusão
259
+
260
+ ### Boas Práticas
261
+ - Use imagens próprias ou com licença adequada
262
+ - Não treine com conteúdo protegido por direitos autorais
263
+ - Respeite termos de uso dos modelos base
264
+ - Mantenha backups dos seus LoRAs
265
+
266
+ ## 🤝 Contribuição
267
+
268
+ ### Como Contribuir
269
+ 1. Fork do repositório
270
+ 2. Crie uma branch para sua feature
271
+ 3. Implemente melhorias
272
+ 4. Teste thoroughly
273
+ 5. Submeta pull request
274
+
275
+ ### Áreas de Melhoria
276
+ - Suporte a mais modelos base
277
+ - Otimizações adicionais de memória
278
+ - Interface de usuário aprimorada
279
+ - Funcionalidades de inferência
280
+ - Integração com mais ferramentas
281
+
282
+ ## 📄 Licença
283
+
284
+ Este projeto está licenciado sob a Licença MIT. Veja o arquivo LICENSE para detalhes.
285
+
286
+ ## 🙏 Agradecimentos
287
+
288
+ - Hugging Face pela infraestrutura e bibliotecas
289
+ - Comunidade Stable Diffusion pelas técnicas
290
+ - Desenvolvedores do PEFT e Diffusers
291
+ - Comunidade open source de IA
292
+
293
+ ---
294
+
295
+ **Desenvolvido com ❤️ para democratizar o acesso ao treinamento de LoRA para geração de imagens**
296
+