PowerMachine commited on
Commit
27ffe62
·
verified ·
1 Parent(s): 43b7b92

V6+: add scripts/parse_v6_log.py

Browse files
Files changed (1) hide show
  1. scripts/parse_v6_log.py +263 -0
scripts/parse_v6_log.py ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """parse_v6_log.py — Parse v6_progressive.log and extract evolution data.
2
+
3
+ Extracts stage results from the log file since training was killed before
4
+ writing the final report.
5
+ """
6
+ import json
7
+ import re
8
+ from pathlib import Path
9
+ from datetime import datetime
10
+
11
+ LOG_PATH = Path("/home/z/my-project/logs/v6_progressive.log")
12
+ REPORT_PATH = Path("/home/z/my-project/BiGRU_T_version/v6_progressive_report.json")
13
+
14
+ # Regex patterns
15
+ STAGE_RE = re.compile(r"STAGE: (\w+) \(n=(\d+), epoch=(\d+)\)")
16
+ STAGE_END_RE = re.compile(
17
+ r"STAGE END \| val_loss=([\d.]+) \| train_avg=([\d.]+) \| ppl=([\d.]+) "
18
+ r"\| gap=([+-]?[\d.]+) \| eval_acc=([\d.]+)% \| elapsed=([\d.]+)s \| n_steps=(\d+)"
19
+ )
20
+ SOM_RE = re.compile(r"SOM: σ=([\d.]+), α=([\d.]+), step=(\d+)")
21
+ STEP_RE = re.compile(
22
+ r"step\s+(\d+)\s+\|\s+loss=([\d.]+)\s+\|\s+tps=(\d+)\s+\|\s+tflops=([\d.]+)\s+\|\s+\|\|g\|\|=([\d.]+)\s+\|\s+cpu=(\d+)%\s+\|\s+rss=(\d+)MB"
23
+ )
24
+
25
+
26
+ def parse_log():
27
+ """Parse the log file and return evolution data."""
28
+ if not LOG_PATH.exists():
29
+ print(f"[ERROR] Log file not found: {LOG_PATH}")
30
+ return None
31
+
32
+ with open(LOG_PATH) as f:
33
+ lines = f.readlines()
34
+
35
+ print(f"[INFO] Parsing {len(lines)} log lines from {LOG_PATH}")
36
+
37
+ evolution = []
38
+ current_stage = None
39
+ current_n = None
40
+ current_epoch = None
41
+ current_steps = []
42
+ som_data = {}
43
+
44
+ for line in lines:
45
+ # STAGE start
46
+ m = STAGE_RE.search(line)
47
+ if m:
48
+ # Save previous stage if any
49
+ if current_stage is not None:
50
+ # Compute summary
51
+ if current_steps:
52
+ losses = [s["loss"] for s in current_steps]
53
+ tps_arr = [s["tps"] for s in current_steps]
54
+ tflops_arr = [s["tflops"] for s in current_steps]
55
+ rss_arr = [s["rss_mb"] for s in current_steps]
56
+ avg_tflops = sum(tflops_arr) / len(tflops_arr)
57
+ avg_tps = sum(tps_arr) / len(tps_arr)
58
+ final_rss = rss_arr[-1]
59
+ max_rss = max(rss_arr)
60
+ else:
61
+ avg_tflops = 0
62
+ avg_tps = 0
63
+ final_rss = 0
64
+ max_rss = 0
65
+ # Look for STAGE END
66
+ evolution.append({
67
+ "stage": current_stage,
68
+ "n_samples": current_n,
69
+ "epoch": current_epoch,
70
+ "n_steps": len(current_steps),
71
+ "avg_tflops": avg_tflops,
72
+ "avg_tokens_per_sec": avg_tps,
73
+ "final_rss_mb": final_rss,
74
+ "max_rss_mb": max_rss,
75
+ "train_loss_mean": sum(losses) / len(losses) if current_steps else 0,
76
+ "val_loss": None, # filled below
77
+ "perplexity": None,
78
+ "overfitting_gap": None,
79
+ "eval_acc": None,
80
+ "elapsed_s": None,
81
+ "som": dict(som_data),
82
+ })
83
+ som_data = {}
84
+ current_stage = m.group(1)
85
+ current_n = int(m.group(2))
86
+ current_epoch = int(m.group(3))
87
+ current_steps = []
88
+ continue
89
+
90
+ # STAGE END
91
+ m = STAGE_END_RE.search(line)
92
+ if m and current_stage is not None:
93
+ val_loss = float(m.group(1))
94
+ train_avg = float(m.group(2))
95
+ ppl = float(m.group(3))
96
+ gap = float(m.group(4))
97
+ eval_acc = float(m.group(5)) / 100.0
98
+ elapsed = float(m.group(6))
99
+ n_steps_end = int(m.group(7))
100
+ # Update last entry's stage-end info
101
+ # Actually, save as a new "complete" entry
102
+ # If evolution has an entry for this stage without val_loss, update it
103
+ if evolution and evolution[-1]["stage"] == current_stage and evolution[-1]["n_samples"] == current_n and evolution[-1]["epoch"] == current_epoch:
104
+ evolution[-1].update({
105
+ "val_loss": val_loss,
106
+ "train_loss_mean": train_avg,
107
+ "perplexity": ppl,
108
+ "overfitting_gap": gap,
109
+ "eval_acc": eval_acc,
110
+ "elapsed_s": elapsed,
111
+ "n_steps": n_steps_end,
112
+ })
113
+ else:
114
+ evolution.append({
115
+ "stage": current_stage,
116
+ "n_samples": current_n,
117
+ "epoch": current_epoch,
118
+ "n_steps": n_steps_end,
119
+ "avg_tflops": 0,
120
+ "avg_tokens_per_sec": 0,
121
+ "final_rss_mb": 0,
122
+ "max_rss_mb": 0,
123
+ "train_loss_mean": train_avg,
124
+ "val_loss": val_loss,
125
+ "perplexity": ppl,
126
+ "overfitting_gap": gap,
127
+ "eval_acc": eval_acc,
128
+ "elapsed_s": elapsed,
129
+ "som": dict(som_data),
130
+ })
131
+ som_data = {}
132
+ continue
133
+
134
+ # SOM
135
+ m = SOM_RE.search(line)
136
+ if m and current_stage is not None:
137
+ som_data = {
138
+ "sigma": float(m.group(1)),
139
+ "alpha": float(m.group(2)),
140
+ "step": int(m.group(3)),
141
+ }
142
+ continue
143
+
144
+ # STEP
145
+ m = STEP_RE.search(line)
146
+ if m and current_stage is not None:
147
+ current_steps.append({
148
+ "step": int(m.group(1)),
149
+ "loss": float(m.group(2)),
150
+ "tps": int(m.group(3)),
151
+ "tflops": float(m.group(4)),
152
+ "grad_norm": float(m.group(5)),
153
+ "cpu_pct": int(m.group(6)),
154
+ "rss_mb": int(m.group(7)),
155
+ })
156
+ continue
157
+
158
+ # Save last stage if incomplete (no STAGE END)
159
+ if current_stage is not None and current_steps:
160
+ losses = [s["loss"] for s in current_steps]
161
+ tps_arr = [s["tps"] for s in current_steps]
162
+ tflops_arr = [s["tflops"] for s in current_steps]
163
+ rss_arr = [s["rss_mb"] for s in current_steps]
164
+ evolution.append({
165
+ "stage": current_stage,
166
+ "n_samples": current_n,
167
+ "epoch": current_epoch,
168
+ "n_steps": len(current_steps),
169
+ "avg_tflops": sum(tflops_arr) / len(tflops_arr) if tflops_arr else 0,
170
+ "avg_tokens_per_sec": sum(tps_arr) / len(tps_arr) if tps_arr else 0,
171
+ "final_rss_mb": rss_arr[-1] if rss_arr else 0,
172
+ "max_rss_mb": max(rss_arr) if rss_arr else 0,
173
+ "train_loss_mean": sum(losses) / len(losses) if losses else 0,
174
+ "val_loss": None,
175
+ "perplexity": None,
176
+ "overfitting_gap": None,
177
+ "eval_acc": None,
178
+ "elapsed_s": None,
179
+ "som": dict(som_data),
180
+ "incomplete": True,
181
+ })
182
+
183
+ # Filter out empty stages (no steps, no end)
184
+ evolution = [e for e in evolution if e.get("n_steps", 0) > 0 or e.get("val_loss") is not None]
185
+
186
+ # Merge duplicate entries (same stage+n+epoch): one has step stats, other has val_loss
187
+ merged = {}
188
+ order = []
189
+ for e in evolution:
190
+ key = (e["stage"], e["n_samples"], e["epoch"])
191
+ if key not in merged:
192
+ merged[key] = {}
193
+ order.append(key)
194
+ # Merge — later entries overwrite None
195
+ for k, v in e.items():
196
+ if v is not None and v != 0:
197
+ merged[key][k] = v
198
+ elif k not in merged[key]:
199
+ merged[key][k] = v
200
+ # Ensure all keys present
201
+ for k in ["stage", "n_samples", "epoch", "n_steps", "avg_tflops", "avg_tokens_per_sec",
202
+ "final_rss_mb", "max_rss_mb", "train_loss_mean", "val_loss", "perplexity",
203
+ "overfitting_gap", "eval_acc", "elapsed_s", "som"]:
204
+ if k not in merged[key]:
205
+ merged[key][k] = None
206
+ # Mark incomplete (no val_loss)
207
+ if merged[key].get("val_loss") is None:
208
+ merged[key]["incomplete"] = True
209
+
210
+ evolution = [merged[k] for k in order]
211
+
212
+ print(f"[INFO] Parsed {len(evolution)} stage entries (after merge)")
213
+ return evolution
214
+
215
+
216
+ def main():
217
+ evolution = parse_log()
218
+ if not evolution:
219
+ print("[ERROR] No evolution data parsed")
220
+ return
221
+
222
+ # Print summary
223
+ print(f"\n{'=' * 100}")
224
+ print(f" EVOLUÇÃO (parsed from log)")
225
+ print(f"{'=' * 100}")
226
+ print(f" {'#':<3} {'stage':<14} {'n':>4} {'ep':>3} {'val_loss':>10} {'ppl':>10} {'eval_acc':>10} {'rss_mb':>8} {'tflops':>8} {'incomp':>7}")
227
+ print(f" {'-'*3} {'-'*14} {'-'*4} {'-'*3} {'-'*10} {'-'*10} {'-'*10} {'-'*8} {'-'*8} {'-'*7}")
228
+ for i, e in enumerate(evolution):
229
+ val = f"{e['val_loss']:.4f}" if e.get("val_loss") is not None else "—"
230
+ ppl = f"{e['perplexity']:.2f}" if e.get("perplexity") is not None else "—"
231
+ acc = f"{e['eval_acc']*100:.2f}%" if e.get("eval_acc") is not None else "—"
232
+ rss = f"{e['final_rss_mb']:.0f}" if e.get("final_rss_mb") else "—"
233
+ tf = f"{e['avg_tflops']:.4f}" if e.get("avg_tflops") else "—"
234
+ incomp = "YES" if e.get("incomplete") else ""
235
+ print(f" {i+1:<3} {e['stage']:<14} {e['n_samples']:>4} {e['epoch']:>3} "
236
+ f"{val:>10} {ppl:>10} {acc:>10} {rss:>8} {tf:>8} {incomp:>7}")
237
+
238
+ # Save partial report
239
+ report = {
240
+ "version": "V6_progressive_partial",
241
+ "timestamp": datetime.now().isoformat(),
242
+ "note": "Partial report — training was killed before full completion. Evolution data extracted from log.",
243
+ "config": {
244
+ "epochs": 1,
245
+ "batch_size": 8,
246
+ "max_seq_len": 24,
247
+ "num_layers_hyp": 8,
248
+ "stages_punctuation": [100, 200, 300, 400, 500],
249
+ "stages_text": [100, 200, 300, 400, 500],
250
+ "stages_heavy": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
251
+ },
252
+ "evolution": evolution,
253
+ "n_stages_captured": len(evolution),
254
+ "n_stages_total_expected": 20, # 5 + 5 + 10
255
+ "completion_pct": len(evolution) / 20 * 100,
256
+ }
257
+ REPORT_PATH.write_text(json.dumps(report, indent=2, ensure_ascii=False, default=str))
258
+ print(f"\n[INFO] Partial report saved: {REPORT_PATH}")
259
+ print(f"[INFO] Captured {len(evolution)}/20 stages ({len(evolution)/20*100:.1f}%)")
260
+
261
+
262
+ if __name__ == "__main__":
263
+ main()