FerrellSyntheticIntelligence commited on
Commit
99d3c89
·
verified ·
1 Parent(s): f67cb0e

Upload train_monitor.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. train_monitor.py +129 -0
train_monitor.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """FSI_FELON Training Monitor — watches over the forge while you sleep."""
3
+ import os, time, json, sys, subprocess
4
+ from datetime import datetime
5
+
6
+ LOG = "/tmp/opencode/snca/train_live.log"
7
+ SCRIPT = "/tmp/opencode/snca/train_live.py"
8
+ SCREEN = "deep_train"
9
+ CHECK_INTERVAL = 600 # 10 min (~100 steps)
10
+ REPORT = "/tmp/fsi_felon/training_report.json"
11
+ ALERT_FILE = "/tmp/fsi_felon/training_alert"
12
+
13
+ def tail_lines(path, n=5):
14
+ try:
15
+ with open(path) as f:
16
+ lines = f.readlines()
17
+ return lines[-n:]
18
+ except:
19
+ return []
20
+
21
+ def check_training():
22
+ now = datetime.now().strftime("%H:%M:%S")
23
+ lines = tail_lines(LOG, 3)
24
+ if not lines:
25
+ return {"status": "NO_LOG", "time": now, "msg": "No log file found"}
26
+
27
+ last = lines[-1].strip()
28
+ # Parse: [03:14:59] step=1,457 loss=7.3952 lr=3.00e-04
29
+ try:
30
+ parts = last.split()
31
+ time_str = parts[0].strip("[]")
32
+ step = int(parts[1].split("=")[1].replace(",", ""))
33
+ loss = float(parts[2].split("=")[1])
34
+ lr = float(parts[3].split("=")[1])
35
+ except:
36
+ return {"status": "PARSE_ERROR", "time": now, "msg": f"Could not parse: {last}"}
37
+
38
+ report = {
39
+ "status": "OK",
40
+ "time": now,
41
+ "step": step,
42
+ "loss": loss,
43
+ "lr": lr,
44
+ "msg": f"step={step:,} loss={loss:.4f} lr={lr:.2e}"
45
+ }
46
+
47
+ # Check for anomalies
48
+ if loss > 15.0:
49
+ report["alert"] = f"Loss spike: {loss:.4f}"
50
+ report["status"] = "ALERT"
51
+ with open(ALERT_FILE, "w") as f:
52
+ f.write(json.dumps(report))
53
+
54
+ # Check if training stopped (log not updating)
55
+ if os.path.exists(REPORT):
56
+ try:
57
+ with open(REPORT) as f:
58
+ prev = json.load(f)
59
+ if prev.get("step") == step and prev.get("status") != "RESTARTED":
60
+ report["status"] = "STALLED"
61
+ report["msg"] += " — LOG NOT UPDATING"
62
+ except:
63
+ pass
64
+
65
+ with open(REPORT, "w") as f:
66
+ json.dump(report, f, indent=2)
67
+ return report
68
+
69
+ def restart_training():
70
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] Training stalled or crashed — restarting...")
71
+ # Kill existing screen
72
+ subprocess.run(["screen", "-S", SCREEN, "-X", "quit"], capture_output=True)
73
+ time.sleep(2)
74
+ # Start fresh
75
+ cmd = f"cd /tmp/opencode/snca && screen -dmS {SCREEN} python3 train_live.py"
76
+ subprocess.run(cmd, shell=True)
77
+ time.sleep(5)
78
+ report = check_training()
79
+ report["status"] = "RESTARTED"
80
+ with open(REPORT, "w") as f:
81
+ json.dump(report, f, indent=2)
82
+ print(f" Restarted at step {report.get('step', '?')}")
83
+ return report
84
+
85
+ def monitor():
86
+ print("=" * 55)
87
+ print(" FSI_FELON TRAINING MONITOR")
88
+ print(" Checking every 10 minutes (~100 steps)")
89
+ print(f" Started: {datetime.now().strftime('%H:%M:%S')}")
90
+ print("=" * 55)
91
+ print()
92
+
93
+ # Clear any previous alert
94
+ if os.path.exists(ALERT_FILE):
95
+ os.remove(ALERT_FILE)
96
+
97
+ cycle = 0
98
+ while True:
99
+ cycle += 1
100
+ report = check_training()
101
+ ts = report["time"]
102
+ status = report["status"]
103
+
104
+ if status == "OK":
105
+ print(f"[{ts}] ✓ step={report['step']:,} loss={report['loss']:.4f} lr={report['lr']:.2e}")
106
+ elif status == "STALLED":
107
+ print(f"[{ts}] ⚠ STALLED — restarting")
108
+ report = restart_training()
109
+ elif status == "ALERT":
110
+ print(f"[{ts}] 🔴 ALERT: {report.get('alert')}")
111
+ elif status == "NO_LOG":
112
+ print(f"[{ts}] 🔴 No log — restarting")
113
+ report = restart_training()
114
+ else:
115
+ print(f"[{ts}] ? {status}: {report.get('msg')}")
116
+
117
+ # Check screen is alive
118
+ r = subprocess.run(["screen", "-ls"], capture_output=True, text=True)
119
+ if SCREEN not in r.stdout:
120
+ print(f"[{datetime.now().strftime('%H:%M:%S')}] 🔴 Screen dead — restarting")
121
+ restart_training()
122
+
123
+ time.sleep(CHECK_INTERVAL)
124
+
125
+ if __name__ == "__main__":
126
+ try:
127
+ monitor()
128
+ except KeyboardInterrupt:
129
+ print("\nMonitor stopped.")