FSI_FELON / train_monitor.py
FerrellSyntheticIntelligence's picture
Upload train_monitor.py with huggingface_hub
99d3c89 verified
Raw
History Blame Contribute Delete
4.14 kB
#!/usr/bin/env python3
"""FSI_FELON Training Monitor — watches over the forge while you sleep."""
import os, time, json, sys, subprocess
from datetime import datetime
LOG = "/tmp/opencode/snca/train_live.log"
SCRIPT = "/tmp/opencode/snca/train_live.py"
SCREEN = "deep_train"
CHECK_INTERVAL = 600 # 10 min (~100 steps)
REPORT = "/tmp/fsi_felon/training_report.json"
ALERT_FILE = "/tmp/fsi_felon/training_alert"
def tail_lines(path, n=5):
try:
with open(path) as f:
lines = f.readlines()
return lines[-n:]
except:
return []
def check_training():
now = datetime.now().strftime("%H:%M:%S")
lines = tail_lines(LOG, 3)
if not lines:
return {"status": "NO_LOG", "time": now, "msg": "No log file found"}
last = lines[-1].strip()
# Parse: [03:14:59] step=1,457 loss=7.3952 lr=3.00e-04
try:
parts = last.split()
time_str = parts[0].strip("[]")
step = int(parts[1].split("=")[1].replace(",", ""))
loss = float(parts[2].split("=")[1])
lr = float(parts[3].split("=")[1])
except:
return {"status": "PARSE_ERROR", "time": now, "msg": f"Could not parse: {last}"}
report = {
"status": "OK",
"time": now,
"step": step,
"loss": loss,
"lr": lr,
"msg": f"step={step:,} loss={loss:.4f} lr={lr:.2e}"
}
# Check for anomalies
if loss > 15.0:
report["alert"] = f"Loss spike: {loss:.4f}"
report["status"] = "ALERT"
with open(ALERT_FILE, "w") as f:
f.write(json.dumps(report))
# Check if training stopped (log not updating)
if os.path.exists(REPORT):
try:
with open(REPORT) as f:
prev = json.load(f)
if prev.get("step") == step and prev.get("status") != "RESTARTED":
report["status"] = "STALLED"
report["msg"] += " — LOG NOT UPDATING"
except:
pass
with open(REPORT, "w") as f:
json.dump(report, f, indent=2)
return report
def restart_training():
print(f"[{datetime.now().strftime('%H:%M:%S')}] Training stalled or crashed — restarting...")
# Kill existing screen
subprocess.run(["screen", "-S", SCREEN, "-X", "quit"], capture_output=True)
time.sleep(2)
# Start fresh
cmd = f"cd /tmp/opencode/snca && screen -dmS {SCREEN} python3 train_live.py"
subprocess.run(cmd, shell=True)
time.sleep(5)
report = check_training()
report["status"] = "RESTARTED"
with open(REPORT, "w") as f:
json.dump(report, f, indent=2)
print(f" Restarted at step {report.get('step', '?')}")
return report
def monitor():
print("=" * 55)
print(" FSI_FELON TRAINING MONITOR")
print(" Checking every 10 minutes (~100 steps)")
print(f" Started: {datetime.now().strftime('%H:%M:%S')}")
print("=" * 55)
print()
# Clear any previous alert
if os.path.exists(ALERT_FILE):
os.remove(ALERT_FILE)
cycle = 0
while True:
cycle += 1
report = check_training()
ts = report["time"]
status = report["status"]
if status == "OK":
print(f"[{ts}] ✓ step={report['step']:,} loss={report['loss']:.4f} lr={report['lr']:.2e}")
elif status == "STALLED":
print(f"[{ts}] ⚠ STALLED — restarting")
report = restart_training()
elif status == "ALERT":
print(f"[{ts}] 🔴 ALERT: {report.get('alert')}")
elif status == "NO_LOG":
print(f"[{ts}] 🔴 No log — restarting")
report = restart_training()
else:
print(f"[{ts}] ? {status}: {report.get('msg')}")
# Check screen is alive
r = subprocess.run(["screen", "-ls"], capture_output=True, text=True)
if SCREEN not in r.stdout:
print(f"[{datetime.now().strftime('%H:%M:%S')}] 🔴 Screen dead — restarting")
restart_training()
time.sleep(CHECK_INTERVAL)
if __name__ == "__main__":
try:
monitor()
except KeyboardInterrupt:
print("\nMonitor stopped.")