feat: captura de logs por época via callback YOLO e expõe em GET /treinar/status
This commit is contained in:
@@ -18,6 +18,26 @@ MODELOS_CARREGADOS = {}
|
|||||||
|
|
||||||
_treinamento_status = {"status": "idle", "ambiente": None, "versao": None, "detalhe": None}
|
_treinamento_status = {"status": "idle", "ambiente": None, "versao": None, "detalhe": None}
|
||||||
_status_lock = threading.Lock()
|
_status_lock = threading.Lock()
|
||||||
|
_training_logs: list = []
|
||||||
|
|
||||||
|
|
||||||
|
def _on_fit_epoch_end(trainer):
|
||||||
|
epoch = trainer.epoch + 1
|
||||||
|
total = trainer.epochs
|
||||||
|
try:
|
||||||
|
losses = [float(x) for x in trainer.loss_items] if getattr(trainer, 'loss_items', None) is not None else []
|
||||||
|
m = getattr(trainer, 'metrics', None) or {}
|
||||||
|
map50 = float(m.get('metrics/mAP50(B)', 0))
|
||||||
|
if len(losses) >= 3:
|
||||||
|
line = f"[{epoch}/{total}] box={losses[0]:.3f} cls={losses[1]:.3f} dfl={losses[2]:.3f} | mAP50={map50:.4f}"
|
||||||
|
else:
|
||||||
|
line = f"[{epoch}/{total}] mAP50={map50:.4f}"
|
||||||
|
except Exception:
|
||||||
|
line = f"[{epoch}/{total}]"
|
||||||
|
with _status_lock:
|
||||||
|
_training_logs.append(line)
|
||||||
|
if len(_training_logs) > 60:
|
||||||
|
_training_logs.pop(0)
|
||||||
|
|
||||||
|
|
||||||
def redimensionar_imagem(caminho):
|
def redimensionar_imagem(caminho):
|
||||||
@@ -124,7 +144,9 @@ def _executar_treino_sync(ambiente: str, pular_triagem: bool) -> dict:
|
|||||||
yaml.dump({'train': img_dir, 'val': img_dir, 'nc': 1, 'names': {0: ambiente}}, f)
|
yaml.dump({'train': img_dir, 'val': img_dir, 'nc': 1, 'names': {0: ambiente}}, f)
|
||||||
|
|
||||||
log_print(f"Treinando com {len(os.listdir(img_dir))} fotos...")
|
log_print(f"Treinando com {len(os.listdir(img_dir))} fotos...")
|
||||||
|
modelo_base.add_callback("on_fit_epoch_end", _on_fit_epoch_end)
|
||||||
modelo_base.train(data=yaml_path, epochs=30, imgsz=640, batch=16, device='cpu', plots=True)
|
modelo_base.train(data=yaml_path, epochs=30, imgsz=640, batch=16, device='cpu', plots=True)
|
||||||
|
modelo_base.reset_callbacks()
|
||||||
|
|
||||||
best = "runs/detect/train/weights/best.pt"
|
best = "runs/detect/train/weights/best.pt"
|
||||||
if os.path.exists(best):
|
if os.path.exists(best):
|
||||||
@@ -142,6 +164,8 @@ def _executar_treino_sync(ambiente: str, pular_triagem: bool) -> dict:
|
|||||||
|
|
||||||
def _treinar_bg(ambiente: str, pular_triagem: bool):
|
def _treinar_bg(ambiente: str, pular_triagem: bool):
|
||||||
global _treinamento_status
|
global _treinamento_status
|
||||||
|
with _status_lock:
|
||||||
|
_training_logs.clear()
|
||||||
try:
|
try:
|
||||||
resultado = _executar_treino_sync(ambiente, pular_triagem)
|
resultado = _executar_treino_sync(ambiente, pular_triagem)
|
||||||
with _status_lock:
|
with _status_lock:
|
||||||
@@ -205,7 +229,7 @@ async def treinar(dados: dict):
|
|||||||
@app.get("/treinar/status")
|
@app.get("/treinar/status")
|
||||||
async def status_treino():
|
async def status_treino():
|
||||||
with _status_lock:
|
with _status_lock:
|
||||||
return dict(_treinamento_status)
|
return {**dict(_treinamento_status), "logs": list(_training_logs[-30:])}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user