Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -20,6 +20,9 @@ DEFAULT_EPOCHS = 10
|
|
| 20 |
GENERATION_LIMIT_TO_TRAIN = 5
|
| 21 |
AUTONOMOUS_EPOCHS = 3
|
| 22 |
|
|
|
|
|
|
|
|
|
|
| 23 |
# --- ESTADO GLOBAL Y THREADING ---
|
| 24 |
tokenizer = None
|
| 25 |
lora_model = None
|
|
@@ -27,10 +30,10 @@ tokenized_dataset = None
|
|
| 27 |
lora_generator = None
|
| 28 |
|
| 29 |
# Variables de estado
|
| 30 |
-
version_number = 1.
|
| 31 |
is_trained = os.path.exists(LORA_PATH)
|
| 32 |
generations_since_last_train = 0
|
| 33 |
-
training_status_message = "
|
| 34 |
|
| 35 |
# Lock para proteger las variables compartidas entre hilos (CRÍTICO para estabilidad)
|
| 36 |
global_lock = threading.Lock()
|
|
@@ -67,6 +70,9 @@ def setup_resources():
|
|
| 67 |
"""Configura el tokenizer, el modelo base y el adaptador LoRA."""
|
| 68 |
global tokenizer, lora_model, tokenized_dataset
|
| 69 |
|
|
|
|
|
|
|
|
|
|
| 70 |
prepare_codesearchnet()
|
| 71 |
|
| 72 |
hf_token = os.environ.get("HF_TOKEN")
|
|
@@ -74,7 +80,15 @@ def setup_resources():
|
|
| 74 |
login(token=hf_token)
|
| 75 |
|
| 76 |
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
if tokenizer.pad_token is None:
|
| 80 |
tokenizer.pad_token = tokenizer.eos_token
|
|
@@ -149,14 +163,13 @@ def autonomous_train_lora(epochs, batch_size, learning_rate):
|
|
| 149 |
training_status_message = f"ERROR CRÍTICO durante el entrenamiento autónomo: {e}"
|
| 150 |
print(f"[AUTÓNOMO] {training_status_message}")
|
| 151 |
|
| 152 |
-
# --- FUNCIÓN DE GENERACIÓN (CORREGIDA PARA
|
| 153 |
|
| 154 |
def generate_text(prompt_text):
|
| 155 |
"""Genera código y dispara el ciclo de reentrenamiento autónomo si es necesario."""
|
| 156 |
global lora_generator, generations_since_last_train, is_trained, version_number, training_status_message
|
| 157 |
|
| 158 |
if not is_trained:
|
| 159 |
-
# Si el entrenamiento V1.0 no ha terminado, retorna el mensaje de error y el estado actual
|
| 160 |
return "ERROR: El modelo LoRA no ha sido entrenado. Por favor, espere mientras la IA se inicializa con el entrenamiento V1.0.", update_status()
|
| 161 |
|
| 162 |
|
|
@@ -164,15 +177,21 @@ def generate_text(prompt_text):
|
|
| 164 |
if lora_generator is None:
|
| 165 |
with global_lock:
|
| 166 |
try:
|
| 167 |
-
#
|
| 168 |
-
base_model_gen = AutoModelForCausalLM.from_pretrained(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
model_with_lora = PeftModel.from_pretrained(base_model_gen, LORA_PATH)
|
| 170 |
final_model = model_with_lora.merge_and_unload()
|
| 171 |
final_model.eval()
|
| 172 |
lora_generator = pipeline("text-generation", model=final_model, tokenizer=tokenizer)
|
| 173 |
print(f"[HOT SWAP] 🔄 Modelo de inferencia V{version_number:.1f} recargado y listo.")
|
| 174 |
except Exception as e:
|
| 175 |
-
|
| 176 |
return f"Error al cargar el modelo V{version_number:.1f} para inferencia: {e}", update_status()
|
| 177 |
|
| 178 |
|
|
@@ -215,7 +234,7 @@ def generate_text(prompt_text):
|
|
| 215 |
|
| 216 |
notification = f"\n\n--- [AUTONOMÍA] La IA ha iniciado el reentrenamiento V{current_version+0.1:.1f} para mejorar la traducción de tu diálogo. La próxima generación cargará la nueva versión. ---"
|
| 217 |
|
| 218 |
-
#
|
| 219 |
return completion + notification, update_status()
|
| 220 |
|
| 221 |
except Exception as e:
|
|
@@ -226,10 +245,11 @@ def generate_text(prompt_text):
|
|
| 226 |
|
| 227 |
def initialize_and_train_v1():
|
| 228 |
"""Ejecuta el entrenamiento inicial V1.0 de forma autónoma al iniciar."""
|
|
|
|
| 229 |
if not is_trained:
|
| 230 |
autonomous_train_lora(epochs=DEFAULT_EPOCHS, batch_size=2, learning_rate=5e-5)
|
| 231 |
else:
|
| 232 |
-
|
| 233 |
training_status_message = f"✅ Modelo V{version_number:.1f} ya entrenado. Listo."
|
| 234 |
print(f"[INICIALIZACIÓN] {training_status_message}")
|
| 235 |
|
|
@@ -268,7 +288,6 @@ with gr.Blocks(title="AmorCoderAI - Aprendizaje Continuo") as demo:
|
|
| 268 |
output_box = gr.Textbox(label="Código generado", lines=10)
|
| 269 |
|
| 270 |
# Conexión del botón con la función principal
|
| 271 |
-
# IMPORTANTE: Ahora generate_text retorna DOS valores para coincidir con [output_box, version_and_status]
|
| 272 |
generate_button.click(
|
| 273 |
generate_text,
|
| 274 |
inputs=prompt,
|
|
@@ -288,5 +307,5 @@ if __name__ == "__main__":
|
|
| 288 |
initialization_thread.daemon = True
|
| 289 |
initialization_thread.start()
|
| 290 |
|
| 291 |
-
print(f"\n💻 LANZANDO INTERFAZ GRADIO (El entrenamiento V1.0 se ejecuta en segundo plano)")
|
| 292 |
demo.launch()
|
|
|
|
| 20 |
GENERATION_LIMIT_TO_TRAIN = 5
|
| 21 |
AUTONOMOUS_EPOCHS = 3
|
| 22 |
|
| 23 |
+
# Nueva configuración para manejo de modelos grandes
|
| 24 |
+
TEMP_OFFLOAD_FOLDER = "./temp_offload"
|
| 25 |
+
|
| 26 |
# --- ESTADO GLOBAL Y THREADING ---
|
| 27 |
tokenizer = None
|
| 28 |
lora_model = None
|
|
|
|
| 30 |
lora_generator = None
|
| 31 |
|
| 32 |
# Variables de estado
|
| 33 |
+
version_number = 1.1 # Asumimos que el último entrenamiento llegó a V1.1
|
| 34 |
is_trained = os.path.exists(LORA_PATH)
|
| 35 |
generations_since_last_train = 0
|
| 36 |
+
training_status_message = f"Modelo V{version_number:.1f} listo."
|
| 37 |
|
| 38 |
# Lock para proteger las variables compartidas entre hilos (CRÍTICO para estabilidad)
|
| 39 |
global_lock = threading.Lock()
|
|
|
|
| 70 |
"""Configura el tokenizer, el modelo base y el adaptador LoRA."""
|
| 71 |
global tokenizer, lora_model, tokenized_dataset
|
| 72 |
|
| 73 |
+
# Crear la carpeta de offload si no existe (CRÍTICO para el error actual)
|
| 74 |
+
os.makedirs(TEMP_OFFLOAD_FOLDER, exist_ok=True)
|
| 75 |
+
|
| 76 |
prepare_codesearchnet()
|
| 77 |
|
| 78 |
hf_token = os.environ.get("HF_TOKEN")
|
|
|
|
| 80 |
login(token=hf_token)
|
| 81 |
|
| 82 |
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)
|
| 83 |
+
|
| 84 |
+
# Añadir safetensors=True y offload_folder
|
| 85 |
+
base_model = AutoModelForCausalLM.from_pretrained(
|
| 86 |
+
BASE_MODEL,
|
| 87 |
+
device_map="auto",
|
| 88 |
+
offload_folder=TEMP_OFFLOAD_FOLDER, # SOLUCIÓN 1
|
| 89 |
+
low_cpu_mem_usage=True,
|
| 90 |
+
trust_remote_code=True,
|
| 91 |
+
)
|
| 92 |
|
| 93 |
if tokenizer.pad_token is None:
|
| 94 |
tokenizer.pad_token = tokenizer.eos_token
|
|
|
|
| 163 |
training_status_message = f"ERROR CRÍTICO durante el entrenamiento autónomo: {e}"
|
| 164 |
print(f"[AUTÓNOMO] {training_status_message}")
|
| 165 |
|
| 166 |
+
# --- FUNCIÓN DE GENERACIÓN (CORREGIDA PARA HOT SWAP ESTABLE) ---
|
| 167 |
|
| 168 |
def generate_text(prompt_text):
|
| 169 |
"""Genera código y dispara el ciclo de reentrenamiento autónomo si es necesario."""
|
| 170 |
global lora_generator, generations_since_last_train, is_trained, version_number, training_status_message
|
| 171 |
|
| 172 |
if not is_trained:
|
|
|
|
| 173 |
return "ERROR: El modelo LoRA no ha sido entrenado. Por favor, espere mientras la IA se inicializa con el entrenamiento V1.0.", update_status()
|
| 174 |
|
| 175 |
|
|
|
|
| 177 |
if lora_generator is None:
|
| 178 |
with global_lock:
|
| 179 |
try:
|
| 180 |
+
# SOLUCIÓN CLAVE: Reintroducir offload_folder y low_cpu_mem_usage aquí también.
|
| 181 |
+
base_model_gen = AutoModelForCausalLM.from_pretrained(
|
| 182 |
+
BASE_MODEL,
|
| 183 |
+
device_map="auto",
|
| 184 |
+
offload_folder=TEMP_OFFLOAD_FOLDER, # SOLUCIÓN 2
|
| 185 |
+
low_cpu_mem_usage=True,
|
| 186 |
+
trust_remote_code=True,
|
| 187 |
+
)
|
| 188 |
model_with_lora = PeftModel.from_pretrained(base_model_gen, LORA_PATH)
|
| 189 |
final_model = model_with_lora.merge_and_unload()
|
| 190 |
final_model.eval()
|
| 191 |
lora_generator = pipeline("text-generation", model=final_model, tokenizer=tokenizer)
|
| 192 |
print(f"[HOT SWAP] 🔄 Modelo de inferencia V{version_number:.1f} recargado y listo.")
|
| 193 |
except Exception as e:
|
| 194 |
+
# Si la recarga falla, retorna un error
|
| 195 |
return f"Error al cargar el modelo V{version_number:.1f} para inferencia: {e}", update_status()
|
| 196 |
|
| 197 |
|
|
|
|
| 234 |
|
| 235 |
notification = f"\n\n--- [AUTONOMÍA] La IA ha iniciado el reentrenamiento V{current_version+0.1:.1f} para mejorar la traducción de tu diálogo. La próxima generación cargará la nueva versión. ---"
|
| 236 |
|
| 237 |
+
# Retorna el código Y el estado actualizado
|
| 238 |
return completion + notification, update_status()
|
| 239 |
|
| 240 |
except Exception as e:
|
|
|
|
| 245 |
|
| 246 |
def initialize_and_train_v1():
|
| 247 |
"""Ejecuta el entrenamiento inicial V1.0 de forma autónoma al iniciar."""
|
| 248 |
+
global version_number, is_trained, training_status_message
|
| 249 |
if not is_trained:
|
| 250 |
autonomous_train_lora(epochs=DEFAULT_EPOCHS, batch_size=2, learning_rate=5e-5)
|
| 251 |
else:
|
| 252 |
+
# Si ya está entrenado, actualiza la versión y el mensaje
|
| 253 |
training_status_message = f"✅ Modelo V{version_number:.1f} ya entrenado. Listo."
|
| 254 |
print(f"[INICIALIZACIÓN] {training_status_message}")
|
| 255 |
|
|
|
|
| 288 |
output_box = gr.Textbox(label="Código generado", lines=10)
|
| 289 |
|
| 290 |
# Conexión del botón con la función principal
|
|
|
|
| 291 |
generate_button.click(
|
| 292 |
generate_text,
|
| 293 |
inputs=prompt,
|
|
|
|
| 307 |
initialization_thread.daemon = True
|
| 308 |
initialization_thread.start()
|
| 309 |
|
| 310 |
+
print(f"\n💻 LANZANDO INTERFAZ GRADIO (El entrenamiento V1.0/V1.1 se ejecuta en segundo plano)")
|
| 311 |
demo.launch()
|