Fedir-Ilina commited on
Commit
a49c754
·
verified ·
1 Parent(s): 1104336

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +19 -91
app.py CHANGED
@@ -1295,14 +1295,7 @@ def train_model_lora(
1295
 
1296
  # ── Dataset: carregar do disco ou tokenizar ────────────────────────
1297
  tokenized_path = os.path.join(output_dir, "tokenized_dataset")
1298
- #----------------------------------------------------------------------------
1299
- # Depois de tokenizar o dataset
1300
- if os.path.exists(tokenized_path):
1301
- HF_BUCKET_DATASET = "hf://buckets/Fedir-Ilina/Train_CPU/tokenized_dataset" # definir nome do bucket
1302
- upload_to_bucket(tokenized_path, HF_BUCKET_DATASET)
1303
- log_success("Dataset tokenizado enviado ao Bucket Hugging Face!")
1304
- training_logs.append("Dataset tokenizado enviado ao Bucket Hugging Face.")
1305
- #----------------------------------------------------------------------------
1306
  if os.path.exists(tokenized_path):
1307
  log_info("Dataset tokenizado encontrado no disco. A carregar...")
1308
  tokenized_datasets = load_from_disk(tokenized_path)
@@ -1346,7 +1339,6 @@ def train_model_lora(
1346
 
1347
  training_args = TrainingArguments(
1348
  output_dir=output_dir,
1349
- logging_dir="/tmp/tensorboard_logs",
1350
  num_train_epochs=_epochs_for_trainer,
1351
  per_device_train_batch_size=BASE_BATCH_SIZE,
1352
  per_device_eval_batch_size=BASE_EVAL_SIZE,
@@ -1436,65 +1428,33 @@ def train_model_lora(
1436
  #-----------------------------------------------------------------------------
1437
  try:
1438
  log_success("Configuração do Trainer concluída. A iniciar o treino...")
1439
- train_progress.update({
1440
- "status": "training",
1441
- "message": "Iniciando o treinamento do modelo..."
1442
- })
1443
-
1444
  trainer_output = trainer.train(resume_from_checkpoint=resume_from_trainer_checkpoint)
1445
 
1446
- # -------------------------------
1447
- # Salvar adapter LoRA localmente
1448
- # -------------------------------
1449
  lora_model_path = os.path.join(output_dir, "lora_model")
1450
  os.makedirs(lora_model_path, exist_ok=True)
1451
-
1452
  model.save_pretrained(lora_model_path)
1453
  tokenizer.save_pretrained(lora_model_path)
1454
  training_logs.append("Adapter LoRA salvo com sucesso!")
1455
 
1456
- # ================================================
1457
- # ENVIAR LoRA PARA BUCKET
1458
- # ================================================
1459
- HF_BUCKET_LORA = "hf://buckets/Fedir-Ilina/Train_CPU/lora_adapter"
1460
-
1461
- try:
1462
- upload_to_bucket(lora_model_path, HF_BUCKET_LORA)
1463
- log_success(f"Adapter LoRA enviado ao Bucket: {HF_BUCKET_LORA}")
1464
- training_logs.append("Adapter LoRA enviado ao Bucket HF com sucesso!")
1465
- except Exception as bucket_error:
1466
- log_warning(f"Falha ao enviar LoRA para Bucket: {bucket_error}")
1467
- training_logs.append(f"Erro no upload para Bucket: {bucket_error}")
1468
-
1469
- # ---------------------------------
1470
- # Avaliação final do modelo
1471
- # ---------------------------------
1472
  log_info("A avaliar o modelo final no dataset de validação...")
1473
  final_metrics = trainer.evaluate()
1474
-
1475
  eval_loss = final_metrics.get("eval_loss")
1476
  if eval_loss is not None:
1477
  perplexity = math.exp(eval_loss)
1478
  log_success("Avaliação Final Concluída:")
1479
  log_info(f" -> Eval Loss: {eval_loss:.4f}")
1480
  log_info(f" -> Perplexity: {perplexity:.4f}")
1481
-
1482
  with open(os.path.join(output_dir, "final_metrics.txt"), "w") as f:
1483
  f.write(f"Eval Loss: {eval_loss}\nPerplexity: {perplexity}\n")
1484
-
1485
  else:
1486
  log_warning("Não foi possível obter 'eval_loss' das métricas finais.")
1487
 
1488
- train_progress.update({
1489
- "status": "awaiting_merge",
1490
- "percent": 100,
1491
- "message": "Treino concluído. LoRA salvo. Decida a próxima ação."
1492
- })
1493
 
 
1494
  training_logs.append("Treino concluído. Adapter LoRA salvo em " + lora_model_path)
1495
  log_success("Treino concluído. Adapter LoRA salvo. Aguardando decisão (merge ou continuar).")
1496
-
1497
- except RuntimeError as e:
1498
  msg = str(e)
1499
  training_logs.append(f"Erro durante treino: {msg}")
1500
  train_progress["status"] = "error"
@@ -1506,18 +1466,17 @@ def train_model_lora(
1506
  train_progress.update({"status": "error", "message": f"Erro crítico no treino: {e}"})
1507
  traceback.print_exc()
1508
  return
 
1509
  #----------------------------------------------------
1510
- TENSORBOARD_LOGDIR = "/tmp/tensorboard_logs"
1511
  TENSORBOARD_PORT = 6006
1512
 
1513
- os.makedirs(TENSORBOARD_LOGDIR, exist_ok=True)
1514
-
1515
  def run_tensorboard():
 
1516
  subprocess.Popen([
1517
  "tensorboard",
1518
  f"--logdir={TENSORBOARD_LOGDIR}",
1519
- f"--port={TENSORBOARD_PORT}",
1520
- "--host=0.0.0.0"
1521
  ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
1522
  #-----------------------------------------------------------
1523
  #----------------------
@@ -1546,17 +1505,6 @@ def guess_lora_targets(model):
1546
  @app.route('/api/train', methods=['POST'])
1547
  def handle_train_request():
1548
  global all_data
1549
- # 🟩 INÍCIO — adiciona estas linhas aqui:
1550
- train_progress.clear()
1551
- train_progress.update({
1552
- "status": "running",
1553
- "percent": 0,
1554
- "start_time": time.time(),
1555
- "message": "A preparar treino…"
1556
- })
1557
- training_logs.clear()
1558
- epoch_losses.clear()
1559
- # 🟩 FIM — estas linhas são obrigatórias para a UI atualizar
1560
  try:
1561
  model_path = request.form.get('model_path')
1562
  epochs = int(request.form.get('epochs'))
@@ -1569,18 +1517,7 @@ def handle_train_request():
1569
  if not all([model_path, epochs, uploaded_files]):
1570
  return jsonify({"status": "error", "message": "Faltam parâmetros: modelo, épocas ou ficheiros."}), 400
1571
 
1572
- # --- RESET do estado de UI do treino ---
1573
- training_logs.clear()
1574
- epoch_losses.clear()
1575
- train_progress.update({
1576
- "status": "running",
1577
- "percent": 0,
1578
- "message": "A preparar dados…",
1579
- "start_time": time.time(), # ⏱️ marca o início real deste treino
1580
- "run_id": int(time.time()) # opcional: id da sessão
1581
- })
1582
-
1583
- # Carregar dados
1584
  all_data = []
1585
  for file in uploaded_files:
1586
  try:
@@ -1591,7 +1528,7 @@ def handle_train_request():
1591
  if not line.strip(): continue
1592
  if file.filename.endswith('.jsonl'):
1593
  all_data.append(json.loads(line))
1594
- else:
1595
  all_data.append({"text": line.strip()})
1596
  except Exception as e:
1597
  return jsonify({"status": "error", "message": f"Erro ao ler ficheiro {file.filename}: {e}"}), 400
@@ -1606,11 +1543,8 @@ def handle_train_request():
1606
  training_logs.append(f"[DEBUG] OUTPUT_DIR: {output_dir}")
1607
  training_logs.append(f"[DEBUG] FILES: {os.listdir(os.getcwd())}")
1608
 
1609
- # Inicia o treino em thread
1610
- thread = Thread(
1611
- target=train_model_lora,
1612
- args=(all_data, epochs, model_path, output_dir, ACCUMULATION_STEPS, DATALOADER_WORKERS, "new_train")
1613
- )
1614
  thread.start()
1615
 
1616
  return jsonify({"status": "started", "message": "Requisição de treino recebida. O processo foi iniciado."})
@@ -1774,10 +1708,12 @@ def train_status():
1774
  epoch_list = epoch_losses
1775
  logs_tail = training_logs[-200:] if len(training_logs) > 200 else training_logs[:]
1776
 
1777
- # Acrescentar info a partir do estado atual (apenas nesta resposta, não suja os logs reais)
1778
  if CURRENT_ACCUM_STEPS is not None:
1779
  origem = LAST_ACCUM_ORIGIN or "desconhecido"
1780
  logs_tail.append(f"[INFO] gradient_accumulation_steps atual: {CURRENT_ACCUM_STEPS} ({origem})")
 
 
1781
  if BASE_BATCH_SIZE_EFFECTIVE:
1782
  eb = BASE_BATCH_SIZE_EFFECTIVE * CURRENT_ACCUM_STEPS
1783
  logs_tail.append(f"[INFO] Effective Batch (base={BASE_BATCH_SIZE_EFFECTIVE}) = {eb}")
@@ -1785,16 +1721,11 @@ def train_status():
1785
  if TOTAL_TRAIN_STEPS is not None:
1786
  logs_tail.append(f"[INFO] total_train_steps desta execução: {TOTAL_TRAIN_STEPS}")
1787
 
1788
- # ⏱ TEMPO DECORRIDO REAL
1789
- start_time = train_progress.get("start_time")
1790
- elapsed_seconds = int(time.time() - start_time) if start_time else None
1791
-
1792
  return jsonify({
1793
  "progress": progress,
1794
  "status": status,
1795
  "epoch_losses": epoch_list,
1796
- "logs": logs_tail,
1797
- "elapsed_seconds": elapsed_seconds
1798
  })
1799
 
1800
  #---------------------------------------
@@ -1959,12 +1890,7 @@ def decide_merge():
1959
  log_warning(f"Erro ao ler trainer_state.json do checkpoint: {e}. Assumindo 0 épocas completadas.")
1960
 
1961
  # Atualiza o status de progresso para indicar que o treino vai continuar
1962
- train_progress.update({
1963
- "status": "continuing_training",
1964
- "message": f"Continuando treino por mais {epochs_to_add} épocas...",
1965
- "start_time": time.time(), # ⏱️ reinicia o relógio para esta sessão de continuação
1966
- "run_id": int(time.time()) # opcional
1967
- })
1968
 
1969
  thread = Thread(
1970
  target=train_model_lora,
@@ -2268,5 +2194,7 @@ def create_model():
2268
  # O modelo real é carregado no início do treino via train_model_lora
2269
  return jsonify({"status": "ok", "message": f"Modelo '{model_name}' será carregado ao iniciar o treino."})
2270
  #---------------------------------------------------------------
 
 
2271
  if __name__ == '__main__':
2272
  app.run(host='0.0.0.0', port=7860, debug=False)
 
1295
 
1296
  # ── Dataset: carregar do disco ou tokenizar ────────────────────────
1297
  tokenized_path = os.path.join(output_dir, "tokenized_dataset")
1298
+
 
 
 
 
 
 
 
1299
  if os.path.exists(tokenized_path):
1300
  log_info("Dataset tokenizado encontrado no disco. A carregar...")
1301
  tokenized_datasets = load_from_disk(tokenized_path)
 
1339
 
1340
  training_args = TrainingArguments(
1341
  output_dir=output_dir,
 
1342
  num_train_epochs=_epochs_for_trainer,
1343
  per_device_train_batch_size=BASE_BATCH_SIZE,
1344
  per_device_eval_batch_size=BASE_EVAL_SIZE,
 
1428
  #-----------------------------------------------------------------------------
1429
  try:
1430
  log_success("Configuração do Trainer concluída. A iniciar o treino...")
1431
+ train_progress.update({"status": "training", "message": "Iniciando o treinamento do modelo..."})
 
 
 
 
1432
  trainer_output = trainer.train(resume_from_checkpoint=resume_from_trainer_checkpoint)
1433
 
 
 
 
1434
  lora_model_path = os.path.join(output_dir, "lora_model")
1435
  os.makedirs(lora_model_path, exist_ok=True)
 
1436
  model.save_pretrained(lora_model_path)
1437
  tokenizer.save_pretrained(lora_model_path)
1438
  training_logs.append("Adapter LoRA salvo com sucesso!")
1439
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1440
  log_info("A avaliar o modelo final no dataset de validação...")
1441
  final_metrics = trainer.evaluate()
 
1442
  eval_loss = final_metrics.get("eval_loss")
1443
  if eval_loss is not None:
1444
  perplexity = math.exp(eval_loss)
1445
  log_success("Avaliação Final Concluída:")
1446
  log_info(f" -> Eval Loss: {eval_loss:.4f}")
1447
  log_info(f" -> Perplexity: {perplexity:.4f}")
 
1448
  with open(os.path.join(output_dir, "final_metrics.txt"), "w") as f:
1449
  f.write(f"Eval Loss: {eval_loss}\nPerplexity: {perplexity}\n")
 
1450
  else:
1451
  log_warning("Não foi possível obter 'eval_loss' das métricas finais.")
1452
 
 
 
 
 
 
1453
 
1454
+ train_progress.update({"status": "awaiting_merge", "percent": 100, "message": "Treino concluído. LoRA salvo. Decida a próxima ação."})
1455
  training_logs.append("Treino concluído. Adapter LoRA salvo em " + lora_model_path)
1456
  log_success("Treino concluído. Adapter LoRA salvo. Aguardando decisão (merge ou continuar).")
1457
+ except RuntimeError as e:
 
1458
  msg = str(e)
1459
  training_logs.append(f"Erro durante treino: {msg}")
1460
  train_progress["status"] = "error"
 
1466
  train_progress.update({"status": "error", "message": f"Erro crítico no treino: {e}"})
1467
  traceback.print_exc()
1468
  return
1469
+
1470
  #----------------------------------------------------
1471
+ TENSORBOARD_LOGDIR = r"C:\Users\ilina\startup\Treinamento\feramenta-treino\trained_model_output\logs"
1472
  TENSORBOARD_PORT = 6006
1473
 
 
 
1474
  def run_tensorboard():
1475
+ # Lança o TensorBoard em thread separada para não bloquear
1476
  subprocess.Popen([
1477
  "tensorboard",
1478
  f"--logdir={TENSORBOARD_LOGDIR}",
1479
+ f"--port={TENSORBOARD_PORT}"
 
1480
  ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
1481
  #-----------------------------------------------------------
1482
  #----------------------
 
1505
  @app.route('/api/train', methods=['POST'])
1506
  def handle_train_request():
1507
  global all_data
 
 
 
 
 
 
 
 
 
 
 
1508
  try:
1509
  model_path = request.form.get('model_path')
1510
  epochs = int(request.form.get('epochs'))
 
1517
  if not all([model_path, epochs, uploaded_files]):
1518
  return jsonify({"status": "error", "message": "Faltam parâmetros: modelo, épocas ou ficheiros."}), 400
1519
 
1520
+ # Limpa os dados de treinos anteriores
 
 
 
 
 
 
 
 
 
 
 
1521
  all_data = []
1522
  for file in uploaded_files:
1523
  try:
 
1528
  if not line.strip(): continue
1529
  if file.filename.endswith('.jsonl'):
1530
  all_data.append(json.loads(line))
1531
+ else: # Assume .txt ou outros formatos de texto
1532
  all_data.append({"text": line.strip()})
1533
  except Exception as e:
1534
  return jsonify({"status": "error", "message": f"Erro ao ler ficheiro {file.filename}: {e}"}), 400
 
1543
  training_logs.append(f"[DEBUG] OUTPUT_DIR: {output_dir}")
1544
  training_logs.append(f"[DEBUG] FILES: {os.listdir(os.getcwd())}")
1545
 
1546
+ # Passar um flag indicando que é um "novo" treino (ou re-treino)
1547
+ thread = Thread(target=train_model_lora, args=(all_data, epochs, model_path, output_dir, ACCUMULATION_STEPS, DATALOADER_WORKERS, "new_train"))
 
 
 
1548
  thread.start()
1549
 
1550
  return jsonify({"status": "started", "message": "Requisição de treino recebida. O processo foi iniciado."})
 
1708
  epoch_list = epoch_losses
1709
  logs_tail = training_logs[-200:] if len(training_logs) > 200 else training_logs[:]
1710
 
1711
+ # Acrescentar as linhas pedidas (apenas texto; simples)
1712
  if CURRENT_ACCUM_STEPS is not None:
1713
  origem = LAST_ACCUM_ORIGIN or "desconhecido"
1714
  logs_tail.append(f"[INFO] gradient_accumulation_steps atual: {CURRENT_ACCUM_STEPS} ({origem})")
1715
+
1716
+ # opcional: mostrar Effective Batch
1717
  if BASE_BATCH_SIZE_EFFECTIVE:
1718
  eb = BASE_BATCH_SIZE_EFFECTIVE * CURRENT_ACCUM_STEPS
1719
  logs_tail.append(f"[INFO] Effective Batch (base={BASE_BATCH_SIZE_EFFECTIVE}) = {eb}")
 
1721
  if TOTAL_TRAIN_STEPS is not None:
1722
  logs_tail.append(f"[INFO] total_train_steps desta execução: {TOTAL_TRAIN_STEPS}")
1723
 
 
 
 
 
1724
  return jsonify({
1725
  "progress": progress,
1726
  "status": status,
1727
  "epoch_losses": epoch_list,
1728
+ "logs": logs_tail
 
1729
  })
1730
 
1731
  #---------------------------------------
 
1890
  log_warning(f"Erro ao ler trainer_state.json do checkpoint: {e}. Assumindo 0 épocas completadas.")
1891
 
1892
  # Atualiza o status de progresso para indicar que o treino vai continuar
1893
+ train_progress.update({"status": "continuing_training", "message": f"Continuando treino por mais {epochs_to_add} épocas..."})
 
 
 
 
 
1894
 
1895
  thread = Thread(
1896
  target=train_model_lora,
 
2194
  # O modelo real é carregado no início do treino via train_model_lora
2195
  return jsonify({"status": "ok", "message": f"Modelo '{model_name}' será carregado ao iniciar o treino."})
2196
  #---------------------------------------------------------------
2197
+ #if __name__ == "__main__" and os.environ.get("WERKZEUG_RUN_MAIN") == "true":
2198
+ # código de inicialização
2199
  if __name__ == '__main__':
2200
  app.run(host='0.0.0.0', port=7860, debug=False)