fix(dashboard): remove broken unused win%-per-opponent panel
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="1400" height="2000" viewBox="0 0 1400 2000" font-family="sans-serif">
|
<svg xmlns="http://www.w3.org/2000/svg" width="1400" height="1720" viewBox="0 0 1400 1720" font-family="sans-serif">
|
||||||
<rect width="1400" height="2000" fill="white"/>
|
<rect width="1400" height="1720" fill="white"/>
|
||||||
<text x="700" y="32" text-anchor="middle" font-size="21" font-weight="bold">SAC-LSTM campaign dashboard - live run (current only)</text>
|
<text x="700" y="32" text-anchor="middle" font-size="21" font-weight="bold">SAC-LSTM campaign dashboard - live run (current only)</text>
|
||||||
<text x="700" y="56" text-anchor="middle" font-size="12" fill="#555">generated 2026-08-24 08:29:26 - auto-reloads every 60 s (open this file in Chrome)</text>
|
<text x="700" y="56" text-anchor="middle" font-size="12" fill="#555">generated 2026-08-24 09:05:32 - auto-reloads every 60 s (open this file in Chrome)</text>
|
||||||
<text x="70" y="100" font-size="15" font-weight="bold">Test matches - win % vs opponents</text>
|
<text x="70" y="100" font-size="15" font-weight="bold">Test matches - win % vs opponents</text>
|
||||||
<text x="70" y="115" font-size="11" fill="#555">raw dots = single test matches, thick = rolling-mean-10</text>
|
<text x="70" y="115" font-size="11" fill="#555">raw dots = single test matches, thick = rolling-mean-10</text>
|
||||||
<line x1="70" y1="720.0" x2="697" y2="720.0" stroke="#dddddd"/>
|
<line x1="70" y1="720.0" x2="697" y2="720.0" stroke="#dddddd"/>
|
||||||
@@ -14,16 +14,22 @@
|
|||||||
<line x1="70" y1="720" x2="70" y2="120" stroke="black"/>
|
<line x1="70" y1="720" x2="70" y2="120" stroke="black"/>
|
||||||
<line x1="70.0" y1="720" x2="70.0" y2="724" stroke="black"/>
|
<line x1="70.0" y1="720" x2="70.0" y2="724" stroke="black"/>
|
||||||
<text x="70.0" y="737" text-anchor="middle" font-size="11">1</text>
|
<text x="70.0" y="737" text-anchor="middle" font-size="11">1</text>
|
||||||
<line x1="195.4" y1="720" x2="195.4" y2="724" stroke="black"/>
|
<line x1="148.4" y1="720" x2="148.4" y2="724" stroke="black"/>
|
||||||
<text x="195.4" y="737" text-anchor="middle" font-size="11">2</text>
|
<text x="148.4" y="737" text-anchor="middle" font-size="11">2</text>
|
||||||
<line x1="320.8" y1="720" x2="320.8" y2="724" stroke="black"/>
|
<line x1="226.8" y1="720" x2="226.8" y2="724" stroke="black"/>
|
||||||
<text x="320.8" y="737" text-anchor="middle" font-size="11">3</text>
|
<text x="226.8" y="737" text-anchor="middle" font-size="11">3</text>
|
||||||
<line x1="446.2" y1="720" x2="446.2" y2="724" stroke="black"/>
|
<line x1="305.1" y1="720" x2="305.1" y2="724" stroke="black"/>
|
||||||
<text x="446.2" y="737" text-anchor="middle" font-size="11">4</text>
|
<text x="305.1" y="737" text-anchor="middle" font-size="11">4</text>
|
||||||
<line x1="571.6" y1="720" x2="571.6" y2="724" stroke="black"/>
|
<line x1="383.5" y1="720" x2="383.5" y2="724" stroke="black"/>
|
||||||
<text x="571.6" y="737" text-anchor="middle" font-size="11">5</text>
|
<text x="383.5" y="737" text-anchor="middle" font-size="11">5</text>
|
||||||
|
<line x1="461.9" y1="720" x2="461.9" y2="724" stroke="black"/>
|
||||||
|
<text x="461.9" y="737" text-anchor="middle" font-size="11">6</text>
|
||||||
|
<line x1="540.2" y1="720" x2="540.2" y2="724" stroke="black"/>
|
||||||
|
<text x="540.2" y="737" text-anchor="middle" font-size="11">7</text>
|
||||||
|
<line x1="618.6" y1="720" x2="618.6" y2="724" stroke="black"/>
|
||||||
|
<text x="618.6" y="737" text-anchor="middle" font-size="11">8</text>
|
||||||
<line x1="697.0" y1="720" x2="697.0" y2="724" stroke="black"/>
|
<line x1="697.0" y1="720" x2="697.0" y2="724" stroke="black"/>
|
||||||
<text x="697.0" y="737" text-anchor="middle" font-size="11">6</text>
|
<text x="697.0" y="737" text-anchor="middle" font-size="11">9</text>
|
||||||
<line x1="66" y1="720.0" x2="70" y2="720.0" stroke="black"/>
|
<line x1="66" y1="720.0" x2="70" y2="720.0" stroke="black"/>
|
||||||
<text x="63" y="724.0" text-anchor="end" font-size="11">0</text>
|
<text x="63" y="724.0" text-anchor="end" font-size="11">0</text>
|
||||||
<line x1="66" y1="600.0" x2="70" y2="600.0" stroke="black"/>
|
<line x1="66" y1="600.0" x2="70" y2="600.0" stroke="black"/>
|
||||||
@@ -39,98 +45,112 @@
|
|||||||
<text x="383" y="753" text-anchor="middle" font-size="12">test match number (each opponent)</text>
|
<text x="383" y="753" text-anchor="middle" font-size="12">test match number (each opponent)</text>
|
||||||
<text x="16" y="420" text-anchor="middle" font-size="12" transform="rotate(-90 16 420)">win rate (%)</text>
|
<text x="16" y="420" text-anchor="middle" font-size="12" transform="rotate(-90 16 420)">win rate (%)</text>
|
||||||
<circle cx="70.0" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
<circle cx="70.0" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
<circle cx="195.4" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
<circle cx="148.4" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
<circle cx="320.8" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
<circle cx="226.8" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
<circle cx="446.2" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
<circle cx="305.1" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
<circle cx="571.6" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
<circle cx="383.5" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
|
<circle cx="461.9" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
|
<circle cx="540.2" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
|
<circle cx="618.6" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
<circle cx="697.0" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
<circle cx="697.0" cy="720.0" r="2" fill="#d62728" opacity="0.25"/>
|
||||||
<polyline points="70.0,720.0 195.4,720.0 320.8,720.0 446.2,720.0 571.6,720.0 697.0,720.0" fill="none" stroke="#d62728" stroke-width="3.5" opacity="1.0"/>
|
<polyline points="70.0,720.0 148.4,720.0 226.8,720.0 305.1,720.0 383.5,720.0 461.9,720.0 540.2,720.0 618.6,720.0 697.0,720.0" fill="none" stroke="#d62728" stroke-width="3.5" opacity="1.0"/>
|
||||||
<circle cx="70.0" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
<circle cx="70.0" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
<circle cx="195.4" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
<circle cx="148.4" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
<circle cx="320.8" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
<circle cx="226.8" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
<circle cx="446.2" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
<circle cx="305.1" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
<circle cx="571.6" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
<circle cx="383.5" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
|
<circle cx="461.9" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
|
<circle cx="540.2" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
|
<circle cx="618.6" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
<circle cx="697.0" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
<circle cx="697.0" cy="720.0" r="2" fill="#1f77b4" opacity="0.25"/>
|
||||||
<polyline points="70.0,720.0 195.4,720.0 320.8,720.0 446.2,720.0 571.6,720.0 697.0,720.0" fill="none" stroke="#1f77b4" stroke-width="3.5" opacity="1.0"/>
|
<polyline points="70.0,720.0 148.4,720.0 226.8,720.0 305.1,720.0 383.5,720.0 461.9,720.0 540.2,720.0 618.6,720.0 697.0,720.0" fill="none" stroke="#1f77b4" stroke-width="3.5" opacity="1.0"/>
|
||||||
<circle cx="70.0" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
<circle cx="70.0" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
<circle cx="195.4" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
<circle cx="148.4" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
<circle cx="320.8" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
<circle cx="226.8" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
<circle cx="446.2" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
<circle cx="305.1" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
<circle cx="571.6" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
<circle cx="383.5" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
<polyline points="70.0,720.0 195.4,720.0 320.8,720.0 446.2,720.0 571.6,720.0" fill="none" stroke="#2ca02c" stroke-width="3.5" opacity="1.0"/>
|
<circle cx="461.9" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
|
<circle cx="540.2" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
|
<circle cx="618.6" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
|
<circle cx="697.0" cy="720.0" r="2" fill="#2ca02c" opacity="0.25"/>
|
||||||
|
<polyline points="70.0,720.0 148.4,720.0 226.8,720.0 305.1,720.0 383.5,720.0 461.9,720.0 540.2,720.0 618.6,720.0 697.0,720.0" fill="none" stroke="#2ca02c" stroke-width="3.5" opacity="1.0"/>
|
||||||
<line x1="82" y1="772" x2="110" y2="772" stroke="#d62728" stroke-width="3"/>
|
<line x1="82" y1="772" x2="110" y2="772" stroke="#d62728" stroke-width="3"/>
|
||||||
<text x="116" y="776" font-size="12">Corners - 6 evals</text>
|
<text x="116" y="776" font-size="12">Corners - 9 evals</text>
|
||||||
<line x1="82" y1="790" x2="110" y2="790" stroke="#1f77b4" stroke-width="3"/>
|
<line x1="82" y1="790" x2="110" y2="790" stroke="#1f77b4" stroke-width="3"/>
|
||||||
<text x="116" y="794" font-size="12">Crazy - 6 evals</text>
|
<text x="116" y="794" font-size="12">Crazy - 9 evals</text>
|
||||||
<line x1="82" y1="808" x2="110" y2="808" stroke="#2ca02c" stroke-width="3"/>
|
<line x1="82" y1="808" x2="110" y2="808" stroke="#2ca02c" stroke-width="3"/>
|
||||||
<text x="116" y="812" font-size="12">Target - 5 evals</text>
|
<text x="116" y="812" font-size="12">Target - 9 evals</text>
|
||||||
<text x="747" y="100" font-size="15" font-weight="bold">Real fights - win % per opponent</text>
|
<text x="747" y="100" font-size="15" font-weight="bold">Training losses (log scale)</text>
|
||||||
<text x="747" y="115" font-size="11" fill="#555">training_log.jsonl only - learning in REAL battles, not tests</text>
|
<text x="747" y="115" font-size="11" fill="#555">training_metrics.jsonl - big early spikes are normal</text>
|
||||||
<line x1="747" y1="720.0" x2="1375" y2="720.0" stroke="#dddddd"/>
|
<line x1="747" y1="720.0" x2="1375" y2="720.0" stroke="#dddddd"/>
|
||||||
<line x1="747" y1="600.0" x2="1375" y2="600.0" stroke="#dddddd"/>
|
<line x1="747" y1="570.0" x2="1375" y2="570.0" stroke="#dddddd"/>
|
||||||
<line x1="747" y1="480.0" x2="1375" y2="480.0" stroke="#dddddd"/>
|
<line x1="747" y1="420.0" x2="1375" y2="420.0" stroke="#dddddd"/>
|
||||||
<line x1="747" y1="360.0" x2="1375" y2="360.0" stroke="#dddddd"/>
|
<line x1="747" y1="270.0" x2="1375" y2="270.0" stroke="#dddddd"/>
|
||||||
<line x1="747" y1="240.0" x2="1375" y2="240.0" stroke="#dddddd"/>
|
|
||||||
<line x1="747" y1="120.0" x2="1375" y2="120.0" stroke="#dddddd"/>
|
<line x1="747" y1="120.0" x2="1375" y2="120.0" stroke="#dddddd"/>
|
||||||
<line x1="747" y1="720" x2="1375" y2="720" stroke="black"/>
|
<line x1="747" y1="720" x2="1375" y2="720" stroke="black"/>
|
||||||
<line x1="747" y1="720" x2="747" y2="120" stroke="black"/>
|
<line x1="747" y1="720" x2="747" y2="120" stroke="black"/>
|
||||||
|
<line x1="747.0" y1="720" x2="747.0" y2="724" stroke="black"/>
|
||||||
|
<text x="747.0" y="737" text-anchor="middle" font-size="11">1</text>
|
||||||
|
<line x1="904.0" y1="720" x2="904.0" y2="724" stroke="black"/>
|
||||||
|
<text x="904.0" y="737" text-anchor="middle" font-size="11">6</text>
|
||||||
|
<line x1="1061.0" y1="720" x2="1061.0" y2="724" stroke="black"/>
|
||||||
|
<text x="1061.0" y="737" text-anchor="middle" font-size="11">10</text>
|
||||||
|
<line x1="1218.0" y1="720" x2="1218.0" y2="724" stroke="black"/>
|
||||||
|
<text x="1218.0" y="737" text-anchor="middle" font-size="11">15</text>
|
||||||
|
<line x1="1375.0" y1="720" x2="1375.0" y2="724" stroke="black"/>
|
||||||
|
<text x="1375.0" y="737" text-anchor="middle" font-size="11">20</text>
|
||||||
<line x1="743" y1="720.0" x2="747" y2="720.0" stroke="black"/>
|
<line x1="743" y1="720.0" x2="747" y2="720.0" stroke="black"/>
|
||||||
<text x="740" y="724.0" text-anchor="end" font-size="11">0</text>
|
<text x="740" y="724.0" text-anchor="end" font-size="11">0.01</text>
|
||||||
<line x1="743" y1="600.0" x2="747" y2="600.0" stroke="black"/>
|
<line x1="743" y1="570.0" x2="747" y2="570.0" stroke="black"/>
|
||||||
<text x="740" y="604.0" text-anchor="end" font-size="11">20</text>
|
<text x="740" y="574.0" text-anchor="end" font-size="11">0.1</text>
|
||||||
<line x1="743" y1="480.0" x2="747" y2="480.0" stroke="black"/>
|
<line x1="743" y1="420.0" x2="747" y2="420.0" stroke="black"/>
|
||||||
<text x="740" y="484.0" text-anchor="end" font-size="11">40</text>
|
<text x="740" y="424.0" text-anchor="end" font-size="11">1</text>
|
||||||
<line x1="743" y1="360.0" x2="747" y2="360.0" stroke="black"/>
|
<line x1="743" y1="270.0" x2="747" y2="270.0" stroke="black"/>
|
||||||
<text x="740" y="364.0" text-anchor="end" font-size="11">60</text>
|
<text x="740" y="274.0" text-anchor="end" font-size="11">10</text>
|
||||||
<line x1="743" y1="240.0" x2="747" y2="240.0" stroke="black"/>
|
|
||||||
<text x="740" y="244.0" text-anchor="end" font-size="11">80</text>
|
|
||||||
<line x1="743" y1="120.0" x2="747" y2="120.0" stroke="black"/>
|
<line x1="743" y1="120.0" x2="747" y2="120.0" stroke="black"/>
|
||||||
<text x="740" y="124.0" text-anchor="end" font-size="11">100</text>
|
<text x="740" y="124.0" text-anchor="end" font-size="11">100</text>
|
||||||
<text x="1061" y="753" text-anchor="middle" font-size="12">game number (100-game buckets)</text>
|
<text x="1061" y="753" text-anchor="middle" font-size="12">metric line number</text>
|
||||||
<text x="16" y="420" text-anchor="middle" font-size="12" transform="rotate(-90 16 420)">win %</text>
|
<text x="16" y="420" text-anchor="middle" font-size="12" transform="rotate(-90 16 420)">loss (log)</text>
|
||||||
<line x1="759" y1="772" x2="787" y2="772" stroke="#ff7f0e" stroke-width="3"/>
|
<polyline points="747.0,281.9 780.1,253.6 813.1,243.9 846.2,213.5 879.2,207.6 912.3,386.8 945.3,424.4 978.4,307.1 1011.4,293.6 1044.5,282.6 1077.5,242.7 1110.6,171.4 1143.6,158.6 1176.7,169.7 1209.7,191.2 1242.8,253.6 1275.8,327.8 1308.9,625.2 1341.9,506.4 1375.0,374.2" fill="none" stroke="#1f77b4" stroke-width="1.8" opacity="1.0"/>
|
||||||
<text x="793" y="776" font-size="12">RamFire (10 games)</text>
|
<polyline points="747.0,348.9 780.1,307.9 813.1,284.5 846.2,261.3 879.2,244.2 912.3,235.2 945.3,236.5 978.4,241.4 1011.4,270.7 1044.5,292.4 1077.5,378.9 1110.6,302.9 1143.6,277.7 1176.7,264.4 1209.7,254.8 1242.8,246.5 1275.8,242.0 1308.9,251.8 1341.9,262.0 1375.0,273.4" fill="none" stroke="#ff7f0e" stroke-width="1.8" opacity="1.0"/>
|
||||||
<line x1="759" y1="790" x2="787" y2="790" stroke="#2ca02c" stroke-width="3"/>
|
<line x1="759" y1="772" x2="787" y2="772" stroke="#1f77b4" stroke-width="3"/>
|
||||||
<text x="793" y="794" font-size="12">Target (10 games)</text>
|
<text x="793" y="776" font-size="12">critic_loss</text>
|
||||||
<line x1="759" y1="808" x2="787" y2="808" stroke="#d62728" stroke-width="3"/>
|
<line x1="759" y1="790" x2="787" y2="790" stroke="#ff7f0e" stroke-width="3"/>
|
||||||
<text x="793" y="812" font-size="12">Corners (40 games)</text>
|
<text x="793" y="794" font-size="12">|actor_loss|</text>
|
||||||
<text x="70" y="940" font-size="15" font-weight="bold">Training losses (log scale)</text>
|
<text x="70" y="940" font-size="15" font-weight="bold">Alpha temperature</text>
|
||||||
<text x="70" y="955" font-size="11" fill="#555">training_metrics.jsonl - big early spikes are normal</text>
|
<text x="70" y="955" font-size="11" fill="#555">training_metrics.jsonl - high = exploring, low = exploiting</text>
|
||||||
<line x1="70" y1="1428.0" x2="697" y2="1428.0" stroke="#dddddd"/>
|
<line x1="70" y1="1428.0" x2="697" y2="1428.0" stroke="#dddddd"/>
|
||||||
|
<line x1="70" y1="1310.5" x2="697" y2="1310.5" stroke="#dddddd"/>
|
||||||
<line x1="70" y1="1193.0" x2="697" y2="1193.0" stroke="#dddddd"/>
|
<line x1="70" y1="1193.0" x2="697" y2="1193.0" stroke="#dddddd"/>
|
||||||
|
<line x1="70" y1="1075.5" x2="697" y2="1075.5" stroke="#dddddd"/>
|
||||||
<line x1="70" y1="958.0" x2="697" y2="958.0" stroke="#dddddd"/>
|
<line x1="70" y1="958.0" x2="697" y2="958.0" stroke="#dddddd"/>
|
||||||
<line x1="70" y1="1428" x2="697" y2="1428" stroke="black"/>
|
<line x1="70" y1="1428" x2="697" y2="1428" stroke="black"/>
|
||||||
<line x1="70" y1="1428" x2="70" y2="958" stroke="black"/>
|
<line x1="70" y1="1428" x2="70" y2="958" stroke="black"/>
|
||||||
<line x1="70.0" y1="1428" x2="70.0" y2="1432" stroke="black"/>
|
<line x1="70.0" y1="1428" x2="70.0" y2="1432" stroke="black"/>
|
||||||
<text x="70.0" y="1445" text-anchor="middle" font-size="11">1</text>
|
<text x="70.0" y="1445" text-anchor="middle" font-size="11">1</text>
|
||||||
<line x1="226.8" y1="1428" x2="226.8" y2="1432" stroke="black"/>
|
<line x1="226.8" y1="1428" x2="226.8" y2="1432" stroke="black"/>
|
||||||
<text x="226.8" y="1445" text-anchor="middle" font-size="11">2</text>
|
<text x="226.8" y="1445" text-anchor="middle" font-size="11">6</text>
|
||||||
<line x1="383.5" y1="1428" x2="383.5" y2="1432" stroke="black"/>
|
<line x1="383.5" y1="1428" x2="383.5" y2="1432" stroke="black"/>
|
||||||
<text x="383.5" y="1445" text-anchor="middle" font-size="11">4</text>
|
<text x="383.5" y="1445" text-anchor="middle" font-size="11">10</text>
|
||||||
<line x1="540.2" y1="1428" x2="540.2" y2="1432" stroke="black"/>
|
<line x1="540.2" y1="1428" x2="540.2" y2="1432" stroke="black"/>
|
||||||
<text x="540.2" y="1445" text-anchor="middle" font-size="11">5</text>
|
<text x="540.2" y="1445" text-anchor="middle" font-size="11">15</text>
|
||||||
<line x1="697.0" y1="1428" x2="697.0" y2="1432" stroke="black"/>
|
<line x1="697.0" y1="1428" x2="697.0" y2="1432" stroke="black"/>
|
||||||
<text x="697.0" y="1445" text-anchor="middle" font-size="11">6</text>
|
<text x="697.0" y="1445" text-anchor="middle" font-size="11">20</text>
|
||||||
<line x1="66" y1="1428.0" x2="70" y2="1428.0" stroke="black"/>
|
<line x1="66" y1="1428.0" x2="70" y2="1428.0" stroke="black"/>
|
||||||
<text x="63" y="1432.0" text-anchor="end" font-size="11">1</text>
|
<text x="63" y="1432.0" text-anchor="end" font-size="11">0</text>
|
||||||
<line x1="66" y1="1310.5" x2="70" y2="1310.5" stroke="black"/>
|
<line x1="66" y1="1310.5" x2="70" y2="1310.5" stroke="black"/>
|
||||||
<text x="63" y="1314.5" text-anchor="end" font-size="11">3.16</text>
|
<text x="63" y="1314.5" text-anchor="end" font-size="11">0.25</text>
|
||||||
<line x1="66" y1="1193.0" x2="70" y2="1193.0" stroke="black"/>
|
<line x1="66" y1="1193.0" x2="70" y2="1193.0" stroke="black"/>
|
||||||
<text x="63" y="1197.0" text-anchor="end" font-size="11">10</text>
|
<text x="63" y="1197.0" text-anchor="end" font-size="11">0.5</text>
|
||||||
<line x1="66" y1="1075.5" x2="70" y2="1075.5" stroke="black"/>
|
<line x1="66" y1="1075.5" x2="70" y2="1075.5" stroke="black"/>
|
||||||
<text x="63" y="1079.5" text-anchor="end" font-size="11">31.6</text>
|
<text x="63" y="1079.5" text-anchor="end" font-size="11">0.75</text>
|
||||||
<line x1="66" y1="958.0" x2="70" y2="958.0" stroke="black"/>
|
<line x1="66" y1="958.0" x2="70" y2="958.0" stroke="black"/>
|
||||||
<text x="63" y="962.0" text-anchor="end" font-size="11">100</text>
|
<text x="63" y="962.0" text-anchor="end" font-size="11">1</text>
|
||||||
<text x="383" y="1461" text-anchor="middle" font-size="12">metric line number</text>
|
<text x="383" y="1461" text-anchor="middle" font-size="12">metric line number</text>
|
||||||
<text x="16" y="1193" text-anchor="middle" font-size="12" transform="rotate(-90 16 1193)">loss (log)</text>
|
<text x="16" y="1193" text-anchor="middle" font-size="12" transform="rotate(-90 16 1193)">alpha</text>
|
||||||
<polyline points="70.0,1389.5 195.4,1170.1 320.8,1142.9 446.2,1123.8 571.6,1120.3 697.0,1282.3" fill="none" stroke="#1f77b4" stroke-width="1.8" opacity="1.0"/>
|
<polyline points="70.0,958.1 103.0,958.7 136.0,959.3 169.0,959.8 202.0,960.4 235.0,961.0 268.0,961.2 301.0,961.5 334.0,962.1 367.0,962.4 400.0,962.9 433.0,963.4 466.0,962.8 499.0,962.3 532.0,961.7 565.0,961.1 598.0,960.6 631.0,960.0 664.0,959.5 697.0,958.9" fill="none" stroke="#9467bd" stroke-width="1.8" opacity="1.0"/>
|
||||||
<polyline points="70.0,1309.7 195.4,1276.0 320.8,1242.6 446.2,1202.8 571.6,1159.7 697.0,1139.0" fill="none" stroke="#ff7f0e" stroke-width="1.8" opacity="1.0"/>
|
<text x="747" y="940" font-size="15" font-weight="bold">Throughput - games per hour</text>
|
||||||
<line x1="82" y1="1480" x2="110" y2="1480" stroke="#1f77b4" stroke-width="3"/>
|
<text x="747" y="955" font-size="11" fill="#555">method: training_metrics.jsonl 'epoch' deltas; 1 row = one 10-game chunk</text>
|
||||||
<text x="116" y="1484" font-size="12">critic_loss</text>
|
|
||||||
<line x1="82" y1="1498" x2="110" y2="1498" stroke="#ff7f0e" stroke-width="3"/>
|
|
||||||
<text x="116" y="1502" font-size="12">|actor_loss|</text>
|
|
||||||
<text x="747" y="940" font-size="15" font-weight="bold">Alpha temperature</text>
|
|
||||||
<text x="747" y="955" font-size="11" fill="#555">training_metrics.jsonl - high = exploring, low = exploiting</text>
|
|
||||||
<line x1="747" y1="1428.0" x2="1375" y2="1428.0" stroke="#dddddd"/>
|
<line x1="747" y1="1428.0" x2="1375" y2="1428.0" stroke="#dddddd"/>
|
||||||
<line x1="747" y1="1310.5" x2="1375" y2="1310.5" stroke="#dddddd"/>
|
<line x1="747" y1="1310.5" x2="1375" y2="1310.5" stroke="#dddddd"/>
|
||||||
<line x1="747" y1="1193.0" x2="1375" y2="1193.0" stroke="#dddddd"/>
|
<line x1="747" y1="1193.0" x2="1375" y2="1193.0" stroke="#dddddd"/>
|
||||||
@@ -140,73 +160,82 @@
|
|||||||
<line x1="747" y1="1428" x2="747" y2="958" stroke="black"/>
|
<line x1="747" y1="1428" x2="747" y2="958" stroke="black"/>
|
||||||
<line x1="747.0" y1="1428" x2="747.0" y2="1432" stroke="black"/>
|
<line x1="747.0" y1="1428" x2="747.0" y2="1432" stroke="black"/>
|
||||||
<text x="747.0" y="1445" text-anchor="middle" font-size="11">1</text>
|
<text x="747.0" y="1445" text-anchor="middle" font-size="11">1</text>
|
||||||
<line x1="904.0" y1="1428" x2="904.0" y2="1432" stroke="black"/>
|
<line x1="781.9" y1="1428" x2="781.9" y2="1432" stroke="black"/>
|
||||||
<text x="904.0" y="1445" text-anchor="middle" font-size="11">2</text>
|
<text x="781.9" y="1445" text-anchor="middle" font-size="11">2</text>
|
||||||
|
<line x1="816.8" y1="1428" x2="816.8" y2="1432" stroke="black"/>
|
||||||
|
<text x="816.8" y="1445" text-anchor="middle" font-size="11">3</text>
|
||||||
|
<line x1="851.7" y1="1428" x2="851.7" y2="1432" stroke="black"/>
|
||||||
|
<text x="851.7" y="1445" text-anchor="middle" font-size="11">4</text>
|
||||||
|
<line x1="886.6" y1="1428" x2="886.6" y2="1432" stroke="black"/>
|
||||||
|
<text x="886.6" y="1445" text-anchor="middle" font-size="11">5</text>
|
||||||
|
<line x1="921.4" y1="1428" x2="921.4" y2="1432" stroke="black"/>
|
||||||
|
<text x="921.4" y="1445" text-anchor="middle" font-size="11">6</text>
|
||||||
|
<line x1="956.3" y1="1428" x2="956.3" y2="1432" stroke="black"/>
|
||||||
|
<text x="956.3" y="1445" text-anchor="middle" font-size="11">7</text>
|
||||||
|
<line x1="991.2" y1="1428" x2="991.2" y2="1432" stroke="black"/>
|
||||||
|
<text x="991.2" y="1445" text-anchor="middle" font-size="11">8</text>
|
||||||
|
<line x1="1026.1" y1="1428" x2="1026.1" y2="1432" stroke="black"/>
|
||||||
|
<text x="1026.1" y="1445" text-anchor="middle" font-size="11">9</text>
|
||||||
<line x1="1061.0" y1="1428" x2="1061.0" y2="1432" stroke="black"/>
|
<line x1="1061.0" y1="1428" x2="1061.0" y2="1432" stroke="black"/>
|
||||||
<text x="1061.0" y="1445" text-anchor="middle" font-size="11">4</text>
|
<text x="1061.0" y="1445" text-anchor="middle" font-size="11">10</text>
|
||||||
<line x1="1218.0" y1="1428" x2="1218.0" y2="1432" stroke="black"/>
|
<line x1="1095.9" y1="1428" x2="1095.9" y2="1432" stroke="black"/>
|
||||||
<text x="1218.0" y="1445" text-anchor="middle" font-size="11">5</text>
|
<text x="1095.9" y="1445" text-anchor="middle" font-size="11">11</text>
|
||||||
|
<line x1="1130.8" y1="1428" x2="1130.8" y2="1432" stroke="black"/>
|
||||||
|
<text x="1130.8" y="1445" text-anchor="middle" font-size="11">12</text>
|
||||||
|
<line x1="1165.7" y1="1428" x2="1165.7" y2="1432" stroke="black"/>
|
||||||
|
<text x="1165.7" y="1445" text-anchor="middle" font-size="11">13</text>
|
||||||
|
<line x1="1200.6" y1="1428" x2="1200.6" y2="1432" stroke="black"/>
|
||||||
|
<text x="1200.6" y="1445" text-anchor="middle" font-size="11">14</text>
|
||||||
|
<line x1="1235.4" y1="1428" x2="1235.4" y2="1432" stroke="black"/>
|
||||||
|
<text x="1235.4" y="1445" text-anchor="middle" font-size="11">15</text>
|
||||||
|
<line x1="1270.3" y1="1428" x2="1270.3" y2="1432" stroke="black"/>
|
||||||
|
<text x="1270.3" y="1445" text-anchor="middle" font-size="11">16</text>
|
||||||
|
<line x1="1305.2" y1="1428" x2="1305.2" y2="1432" stroke="black"/>
|
||||||
|
<text x="1305.2" y="1445" text-anchor="middle" font-size="11">17</text>
|
||||||
|
<line x1="1340.1" y1="1428" x2="1340.1" y2="1432" stroke="black"/>
|
||||||
|
<text x="1340.1" y="1445" text-anchor="middle" font-size="11">18</text>
|
||||||
<line x1="1375.0" y1="1428" x2="1375.0" y2="1432" stroke="black"/>
|
<line x1="1375.0" y1="1428" x2="1375.0" y2="1432" stroke="black"/>
|
||||||
<text x="1375.0" y="1445" text-anchor="middle" font-size="11">6</text>
|
<text x="1375.0" y="1445" text-anchor="middle" font-size="11">19</text>
|
||||||
<line x1="743" y1="1428.0" x2="747" y2="1428.0" stroke="black"/>
|
<line x1="743" y1="1428.0" x2="747" y2="1428.0" stroke="black"/>
|
||||||
<text x="740" y="1432.0" text-anchor="end" font-size="11">0</text>
|
<text x="740" y="1432.0" text-anchor="end" font-size="11">0</text>
|
||||||
<line x1="743" y1="1310.5" x2="747" y2="1310.5" stroke="black"/>
|
<line x1="743" y1="1310.5" x2="747" y2="1310.5" stroke="black"/>
|
||||||
<text x="740" y="1314.5" text-anchor="end" font-size="11">0.25</text>
|
<text x="740" y="1314.5" text-anchor="end" font-size="11">1653</text>
|
||||||
<line x1="743" y1="1193.0" x2="747" y2="1193.0" stroke="black"/>
|
<line x1="743" y1="1193.0" x2="747" y2="1193.0" stroke="black"/>
|
||||||
<text x="740" y="1197.0" text-anchor="end" font-size="11">0.5</text>
|
<text x="740" y="1197.0" text-anchor="end" font-size="11">3305</text>
|
||||||
<line x1="743" y1="1075.5" x2="747" y2="1075.5" stroke="black"/>
|
<line x1="743" y1="1075.5" x2="747" y2="1075.5" stroke="black"/>
|
||||||
<text x="740" y="1079.5" text-anchor="end" font-size="11">0.75</text>
|
<text x="740" y="1079.5" text-anchor="end" font-size="11">4958</text>
|
||||||
<line x1="743" y1="958.0" x2="747" y2="958.0" stroke="black"/>
|
<line x1="743" y1="958.0" x2="747" y2="958.0" stroke="black"/>
|
||||||
<text x="740" y="962.0" text-anchor="end" font-size="11">1</text>
|
<text x="740" y="962.0" text-anchor="end" font-size="11">6611</text>
|
||||||
<text x="1061" y="1461" text-anchor="middle" font-size="12">metric line number</text>
|
<text x="1061" y="1461" text-anchor="middle" font-size="12">chunk interval (10-game chunks)</text>
|
||||||
<text x="16" y="1193" text-anchor="middle" font-size="12" transform="rotate(-90 16 1193)">alpha</text>
|
<text x="16" y="1193" text-anchor="middle" font-size="12" transform="rotate(-90 16 1193)">games / hour</text>
|
||||||
<polyline points="747.0,958.1 872.6,958.4 998.2,959.0 1123.8,959.6 1249.4,960.1 1375.0,960.7" fill="none" stroke="#9467bd" stroke-width="1.8" opacity="1.0"/>
|
<circle cx="747.0" cy="1159.8" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<text x="70" y="1600" font-size="15" font-weight="bold">Throughput - games per hour</text>
|
<circle cx="781.9" cy="1413.4" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<text x="70" y="1615" font-size="11" fill="#555">method: training_metrics.jsonl 'epoch' deltas (training_log.jsonl has no timestamps); 1 row = one 10-game chunk</text>
|
<circle cx="816.8" cy="1148.0" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70" y1="1780.0" x2="1375" y2="1780.0" stroke="#dddddd"/>
|
<circle cx="851.7" cy="1404.7" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70" y1="1739.5" x2="1375" y2="1739.5" stroke="#dddddd"/>
|
<circle cx="886.6" cy="1153.6" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70" y1="1699.0" x2="1375" y2="1699.0" stroke="#dddddd"/>
|
<circle cx="921.4" cy="1399.6" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70" y1="1658.5" x2="1375" y2="1658.5" stroke="#dddddd"/>
|
<circle cx="956.3" cy="1000.7" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70" y1="1618.0" x2="1375" y2="1618.0" stroke="#dddddd"/>
|
<circle cx="991.2" cy="1399.5" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70" y1="1780" x2="1375" y2="1780" stroke="black"/>
|
<circle cx="1026.1" cy="1021.4" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70" y1="1780" x2="70" y2="1618" stroke="black"/>
|
<circle cx="1061.0" cy="1394.8" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="70.0" y1="1780" x2="70.0" y2="1784" stroke="black"/>
|
<circle cx="1095.9" cy="1376.2" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<text x="70.0" y="1797" text-anchor="middle" font-size="11">1</text>
|
<circle cx="1130.8" cy="1394.4" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="396.2" y1="1780" x2="396.2" y2="1784" stroke="black"/>
|
<circle cx="1165.7" cy="1130.1" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<text x="396.2" y="1797" text-anchor="middle" font-size="11">2</text>
|
<circle cx="1200.6" cy="1399.7" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="722.5" y1="1780" x2="722.5" y2="1784" stroke="black"/>
|
<circle cx="1235.4" cy="1176.5" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<text x="722.5" y="1797" text-anchor="middle" font-size="11">3</text>
|
<circle cx="1270.3" cy="1402.0" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="1048.8" y1="1780" x2="1048.8" y2="1784" stroke="black"/>
|
<circle cx="1305.2" cy="1158.0" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<text x="1048.8" y="1797" text-anchor="middle" font-size="11">4</text>
|
<circle cx="1340.1" cy="1400.0" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<line x1="1375.0" y1="1780" x2="1375.0" y2="1784" stroke="black"/>
|
<circle cx="1375.0" cy="1149.2" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
||||||
<text x="1375.0" y="1797" text-anchor="middle" font-size="11">5</text>
|
<polyline points="747.0,1159.8 781.9,1413.4 781.9,1148.0 851.7,1404.7 851.7,1153.6 921.4,1399.6 921.4,1000.7 991.2,1399.5 991.2,1021.4 1061.0,1394.8 1061.0,1376.2 1130.8,1394.4 1130.8,1130.1 1200.6,1399.7 1200.6,1176.5 1270.3,1402.0 1270.3,1158.0 1340.1,1400.0 1340.1,1149.2" fill="none" stroke="#2ca02c" stroke-width="3.5" opacity="1.0"/>
|
||||||
<line x1="66" y1="1780.0" x2="70" y2="1780.0" stroke="black"/>
|
<rect x="0" y="1540" width="1400" height="180" fill="#f2f2f2"/>
|
||||||
<text x="63" y="1784.0" text-anchor="end" font-size="11">0</text>
|
<text x="16" y="1561" font-size="15" font-weight="bold">How to read</text>
|
||||||
<line x1="66" y1="1739.5" x2="70" y2="1739.5" stroke="black"/>
|
<text x="1384" y="1560" text-anchor="end" font-size="11" fill="#666">Regenerate anytime: python3 tools/plot_progress.py</text>
|
||||||
<text x="63" y="1743.5" text-anchor="end" font-size="11">70</text>
|
<text x="16" y="1583" font-size="13">Test matches: dots are single fights, thick line shows trend.</text>
|
||||||
<line x1="66" y1="1699.0" x2="70" y2="1699.0" stroke="black"/>
|
<text x="16" y="1600" font-size="13">Loss spikes are normal early; endless growth is bad.</text>
|
||||||
<text x="63" y="1703.0" text-anchor="end" font-size="11">141</text>
|
<text x="16" y="1617" font-size="13">Alpha high means experimenting; falling too fast freezes habits.</text>
|
||||||
<line x1="66" y1="1658.5" x2="70" y2="1658.5" stroke="black"/>
|
<text x="16" y="1634" font-size="13">Throughput flat is healthy; dips mean something slowed.</text>
|
||||||
<text x="63" y="1662.5" text-anchor="end" font-size="11">211</text>
|
<text x="16" y="1651" font-size="13">This file reloads itself in Chrome every sixty seconds.</text>
|
||||||
<line x1="66" y1="1618.0" x2="70" y2="1618.0" stroke="black"/>
|
<text x="16" y="1668" font-size="13">Regenerate anytime with tools/watch_dashboard.sh or the python command.</text>
|
||||||
<text x="63" y="1622.0" text-anchor="end" font-size="11">282</text>
|
|
||||||
<text x="722" y="1813" text-anchor="middle" font-size="12">chunk interval (10-game chunks)</text>
|
|
||||||
<text x="16" y="1699" text-anchor="middle" font-size="12" transform="rotate(-90 16 1699)">games / hour</text>
|
|
||||||
<circle cx="70.0" cy="1650.0" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
|
||||||
<circle cx="396.2" cy="1650.1" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
|
||||||
<circle cx="722.5" cy="1673.4" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
|
||||||
<circle cx="1048.8" cy="1648.9" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
|
||||||
<circle cx="1375.0" cy="1632.7" r="1.6" fill="#7f7f7f" opacity="0.25"/>
|
|
||||||
<polyline points="70.0,1650.0 396.2,1650.1 396.2,1673.4 1048.8,1648.9 1048.8,1632.7" fill="none" stroke="#2ca02c" stroke-width="3.5" opacity="1.0"/>
|
|
||||||
<rect x="0" y="1820" width="1400" height="180" fill="#f2f2f2"/>
|
|
||||||
<text x="16" y="1841" font-size="15" font-weight="bold">How to read</text>
|
|
||||||
<text x="1384" y="1840" text-anchor="end" font-size="11" fill="#666">Regenerate anytime: python3 tools/plot_progress.py</text>
|
|
||||||
<text x="16" y="1863" font-size="13">Test matches: dots are single fights, thick line shows trend.</text>
|
|
||||||
<text x="16" y="1880" font-size="13">Real battles only. Rising lines mean the bot improves.</text>
|
|
||||||
<text x="16" y="1897" font-size="13">Loss spikes are normal early; endless growth is bad.</text>
|
|
||||||
<text x="16" y="1914" font-size="13">Alpha high means experimenting; falling too fast freezes habits.</text>
|
|
||||||
<text x="16" y="1931" font-size="13">Throughput flat is healthy; dips mean something slowed.</text>
|
|
||||||
<text x="16" y="1948" font-size="13">This file reloads itself in Chrome every sixty seconds.</text>
|
|
||||||
<text x="16" y="1965" font-size="13">Regenerate anytime with tools/watch_dashboard.sh or the python command.</text>
|
|
||||||
<script type="text/javascript"><![CDATA[ setTimeout(function(){ location.reload(); }, 60000); ]]></script>
|
<script type="text/javascript"><![CDATA[ setTimeout(function(){ location.reload(); }, 60000); ]]></script>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 18 KiB |
@@ -3,21 +3,18 @@
|
|||||||
|
|
||||||
Pure-stdlib SVG output (matplotlib not available on this box).
|
Pure-stdlib SVG output (matplotlib not available on this box).
|
||||||
Generates ONE file:
|
Generates ONE file:
|
||||||
docs/campaign_dashboard.svg - five panels, current (v2) run only:
|
docs/campaign_dashboard.svg - four panels, current (v2) run only:
|
||||||
1. test-match win % vs opponents (campaign_v4_stdout.log eval lines)
|
1. test-match win % vs opponents (campaign_v4_stdout.log eval lines)
|
||||||
2. real-fight win % per opponent (training_log.jsonl, ~100-game buckets)
|
2. critic_loss / |actor_loss| (training_metrics.jsonl, shared log-y)
|
||||||
3. critic_loss / |actor_loss| (training_metrics.jsonl, shared log-y)
|
3. alpha temperature (training_metrics.jsonl, linear)
|
||||||
4. alpha temperature (training_metrics.jsonl, linear)
|
4. throughput, games/hour buckets (training_metrics.jsonl 'epoch' deltas;
|
||||||
5. throughput, games/hour buckets (training_metrics.jsonl 'epoch' deltas;
|
1 metrics row == one 10-game chunk,
|
||||||
training_log.jsonl has NO timestamps -
|
counts match stdout chunk markers)
|
||||||
verified field names - and one metrics
|
|
||||||
row == one 10-game chunk, counts match
|
|
||||||
the stdout "=== Chunk N/N ===" markers)
|
|
||||||
plus an embedded JS snippet that reloads the page every 60 s when the SVG is
|
plus an embedded JS snippet that reloads the page every 60 s when the SVG is
|
||||||
opened as a top-level document in Chrome.
|
opened as a top-level document in Chrome.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
python3 tools/plot_progress.py [campaign_log] [metrics_jsonl] [games_jsonl] [outdir]
|
python3 tools/plot_progress.py [campaign_log] [metrics_jsonl] [outdir]
|
||||||
All args optional; defaults relative to the SAC_LSTM_Bot/ root (parent of tools/).
|
All args optional; defaults relative to the SAC_LSTM_Bot/ root (parent of tools/).
|
||||||
python3 tools/plot_progress.py --selftest # tiny built-in sanity check
|
python3 tools/plot_progress.py --selftest # tiny built-in sanity check
|
||||||
"""
|
"""
|
||||||
@@ -34,7 +31,6 @@ import xml.etree.ElementTree as ET
|
|||||||
ROOT = Path(__file__).resolve().parent.parent
|
ROOT = Path(__file__).resolve().parent.parent
|
||||||
EVAL_RE = re.compile(r">>> \[eval\] win rate: (\d+)/(\d+) \(([\d.]+)%\) vs (\S+)")
|
EVAL_RE = re.compile(r">>> \[eval\] win rate: (\d+)/(\d+) \(([\d.]+)%\) vs (\S+)")
|
||||||
TREND_WINDOW = 10 # rolling mean shown as the thick trend line (panel 1)
|
TREND_WINDOW = 10 # rolling mean shown as the thick trend line (panel 1)
|
||||||
GAME_BUCKET = 100 # games per bucket, real-fight panel
|
|
||||||
RATE_BUCKET = 20 # metric intervals per throughput bucket (~200 games)
|
RATE_BUCKET = 20 # metric intervals per throughput bucket (~200 games)
|
||||||
GAMES_PER_ROW = 10 # one training_metrics.jsonl row per 10-round chunk
|
GAMES_PER_ROW = 10 # one training_metrics.jsonl row per 10-round chunk
|
||||||
COLORS = {"Corners": "#d62728", "Crazy": "#1f77b4", "Target": "#2ca02c",
|
COLORS = {"Corners": "#d62728", "Crazy": "#1f77b4", "Target": "#2ca02c",
|
||||||
@@ -42,7 +38,7 @@ COLORS = {"Corners": "#d62728", "Crazy": "#1f77b4", "Target": "#2ca02c",
|
|||||||
CRITIC_C, ACTOR_C = "#1f77b4", "#ff7f0e"
|
CRITIC_C, ACTOR_C = "#1f77b4", "#ff7f0e"
|
||||||
RELOAD_JS = ('<script type="text/javascript"><![CDATA[ '
|
RELOAD_JS = ('<script type="text/javascript"><![CDATA[ '
|
||||||
'setTimeout(function(){ location.reload(); }, 60000); ]]></script>')
|
'setTimeout(function(){ location.reload(); }, 60000); ]]></script>')
|
||||||
W, H = 1400, 2000
|
W, H = 1400, 1720
|
||||||
TITLE_H, GUIDE_H = 80, 180
|
TITLE_H, GUIDE_H = 80, 180
|
||||||
# rows: (header_y, panel_top_y, panel_bottom_y, x_left, x_right)
|
# rows: (header_y, panel_top_y, panel_bottom_y, x_left, x_right)
|
||||||
C1_L, C1_R = 70, 697
|
C1_L, C1_R = 70, 697
|
||||||
@@ -52,18 +48,15 @@ ROWS = {
|
|||||||
2: (100, 120, 720, C2_L, C2_R),
|
2: (100, 120, 720, C2_L, C2_R),
|
||||||
3: (940, 958, 1428, C1_L, C1_R),
|
3: (940, 958, 1428, C1_L, C1_R),
|
||||||
4: (940, 958, 1428, C2_L, C2_R),
|
4: (940, 958, 1428, C2_L, C2_R),
|
||||||
5: (1600, 1618, 1780, C1_L, C2_R),
|
|
||||||
}
|
}
|
||||||
PANEL_TITLES = [
|
PANEL_TITLES = [
|
||||||
"Test matches - win % vs opponents",
|
"Test matches - win % vs opponents",
|
||||||
"Real fights - win % per opponent",
|
|
||||||
"Training losses (log scale)",
|
"Training losses (log scale)",
|
||||||
"Alpha temperature",
|
"Alpha temperature",
|
||||||
"Throughput - games per hour",
|
"Throughput - games per hour",
|
||||||
]
|
]
|
||||||
GUIDE_LINES = [
|
GUIDE_LINES = [
|
||||||
"Test matches: dots are single fights, thick line shows trend.",
|
"Test matches: dots are single fights, thick line shows trend.",
|
||||||
"Real battles only. Rising lines mean the bot improves.",
|
|
||||||
"Loss spikes are normal early; endless growth is bad.",
|
"Loss spikes are normal early; endless growth is bad.",
|
||||||
"Alpha high means experimenting; falling too fast freezes habits.",
|
"Alpha high means experimenting; falling too fast freezes habits.",
|
||||||
"Throughput flat is healthy; dips mean something slowed.",
|
"Throughput flat is healthy; dips mean something slowed.",
|
||||||
@@ -109,25 +102,6 @@ def parse_metrics(path):
|
|||||||
return rows
|
return rows
|
||||||
|
|
||||||
|
|
||||||
def parse_games(path):
|
|
||||||
"""Return [(opponent, won_bool)] for type=='game' rows, skipping junk."""
|
|
||||||
out = []
|
|
||||||
if not path.is_file():
|
|
||||||
print(f"[skip] games log not found: {path}")
|
|
||||||
return out
|
|
||||||
for line in path.read_text(errors="replace").splitlines():
|
|
||||||
try:
|
|
||||||
r = json.loads(line)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
continue
|
|
||||||
if r.get("type") != "game":
|
|
||||||
continue
|
|
||||||
opp, win = r.get("opponent"), r.get("win")
|
|
||||||
if isinstance(opp, str) and isinstance(win, bool):
|
|
||||||
out.append((opp, win))
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
def metric_col(rows, key, positive=False):
|
def metric_col(rows, key, positive=False):
|
||||||
"""[(index, value)] for float-parseable rows; abs() applied; optional >0 filter."""
|
"""[(index, value)] for float-parseable rows; abs() applied; optional >0 filter."""
|
||||||
out = []
|
out = []
|
||||||
@@ -305,53 +279,6 @@ def panel_test_matches(series, geo):
|
|||||||
s += legend(items, x0 + 12, pb + 52)
|
s += legend(items, x0 + 12, pb + 52)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def panel_real_fights(games, geo):
|
|
||||||
_, pt, pb, x0, x1 = geo
|
|
||||||
s = ""
|
|
||||||
if not games:
|
|
||||||
s += f'<text x="{x0 + 10}" y="{pt + 40}" font-size="12" fill="#a00">' \
|
|
||||||
"no game rows found</text>\n"
|
|
||||||
return
|
|
||||||
edges = list(range(0, len(games) + 1, GAME_BUCKET))
|
|
||||||
if edges[-1] != len(games):
|
|
||||||
edges.append(len(games))
|
|
||||||
buckets = list(zip(edges[:-1], edges[1:]))
|
|
||||||
xm, ym = map_fn(x0, x1, 1, max(len(games), 2)), map_fn(pb, pt, 0, 100)
|
|
||||||
s += hgrid(x0, x1, [ym(v) for v in range(0, 101, 20)])
|
|
||||||
step = max(GAME_BUCKET, GAME_BUCKET * (len(games) // GAME_BUCKET // 8 + 1))
|
|
||||||
xt = [(str(v), xm(v)) for v in range(step, len(games) + 1, step)]
|
|
||||||
s += axis(x0, pb, x1, pt, xt, ticks_linear(0, 100, pb, pt, n=6),
|
|
||||||
f"game number ({GAME_BUCKET}-game buckets)", "win %")
|
|
||||||
opponents = []
|
|
||||||
for opp, _ in games:
|
|
||||||
if opp not in opponents:
|
|
||||||
opponents.append(opp)
|
|
||||||
items = []
|
|
||||||
for name in opponents:
|
|
||||||
c = COLORS.get(name, "#7f7f7f")
|
|
||||||
by_b = {}
|
|
||||||
for bi, (lo, hi) in enumerate(buckets):
|
|
||||||
sub = [w for o, w in games[lo:hi] if o == name]
|
|
||||||
if sub:
|
|
||||||
by_b[bi] = 100.0 * sum(sub) / len(sub)
|
|
||||||
pts = []
|
|
||||||
segs, prev = [], None
|
|
||||||
for bi in sorted(by_b):
|
|
||||||
if prev is not None and bi != prev + 1:
|
|
||||||
segs.append(pts)
|
|
||||||
pts = []
|
|
||||||
center = (buckets[bi][0] + buckets[bi][1]) / 2
|
|
||||||
pts.append((xm(center), ym(by_b[bi])))
|
|
||||||
prev = bi
|
|
||||||
if len(pts) >= 2:
|
|
||||||
segs.append(pts)
|
|
||||||
for seg in segs:
|
|
||||||
s += polyline(seg, c, 3.5)
|
|
||||||
n_played = sum(1 for o, _ in games if o == name)
|
|
||||||
items.append((c, f"{name} ({n_played} games)"))
|
|
||||||
s += legend(items, x0 + 12, pb + 52)
|
|
||||||
return s
|
|
||||||
|
|
||||||
def panel_losses(rows, geo):
|
def panel_losses(rows, geo):
|
||||||
_, pt, pb, x0, x1 = geo
|
_, pt, pb, x0, x1 = geo
|
||||||
s = ""
|
s = ""
|
||||||
@@ -434,14 +361,12 @@ def panel_throughput(rows, geo):
|
|||||||
|
|
||||||
# ---------- assembly ----------
|
# ---------- assembly ----------
|
||||||
|
|
||||||
def build_dashboard(campaign, metrics_f, games_f, out):
|
def build_dashboard(campaign, metrics_f, out):
|
||||||
series = parse_eval_series(campaign)
|
series = parse_eval_series(campaign)
|
||||||
print("[info] evals parsed: " +
|
print("[info] evals parsed: " +
|
||||||
(", ".join(f"{k}={len(v)}" for k, v in sorted(series.items())) or "(none)"))
|
(", ".join(f"{k}={len(v)}" for k, v in sorted(series.items())) or "(none)"))
|
||||||
rows = parse_metrics(metrics_f)
|
rows = parse_metrics(metrics_f)
|
||||||
print(f"[info] metric rows parsed: {len(rows)}")
|
print(f"[info] metric rows parsed: {len(rows)}")
|
||||||
games = parse_games(games_f)
|
|
||||||
print(f"[info] game rows parsed: {len(games)}")
|
|
||||||
|
|
||||||
s = (f'<svg xmlns="http://www.w3.org/2000/svg" width="{W}" height="{H}" '
|
s = (f'<svg xmlns="http://www.w3.org/2000/svg" width="{W}" height="{H}" '
|
||||||
f'viewBox="0 0 {W} {H}" font-family="sans-serif">\n'
|
f'viewBox="0 0 {W} {H}" font-family="sans-serif">\n'
|
||||||
@@ -457,18 +382,14 @@ def build_dashboard(campaign, metrics_f, games_f, out):
|
|||||||
"raw dots = single test matches, thick = rolling-mean-%d" % TREND_WINDOW,
|
"raw dots = single test matches, thick = rolling-mean-%d" % TREND_WINDOW,
|
||||||
lambda: panel_test_matches(series, ROWS[1])),
|
lambda: panel_test_matches(series, ROWS[1])),
|
||||||
(ROWS[2], PANEL_TITLES[1],
|
(ROWS[2], PANEL_TITLES[1],
|
||||||
"training_log.jsonl only - learning in REAL battles, not tests",
|
|
||||||
lambda: panel_real_fights(games, ROWS[2])),
|
|
||||||
(ROWS[3], PANEL_TITLES[2],
|
|
||||||
"training_metrics.jsonl - big early spikes are normal",
|
"training_metrics.jsonl - big early spikes are normal",
|
||||||
lambda: panel_losses(rows, ROWS[3])),
|
lambda: panel_losses(rows, ROWS[2])),
|
||||||
(ROWS[4], PANEL_TITLES[3],
|
(ROWS[3], PANEL_TITLES[2],
|
||||||
"training_metrics.jsonl - high = exploring, low = exploiting",
|
"training_metrics.jsonl - high = exploring, low = exploiting",
|
||||||
lambda: panel_alpha(rows, ROWS[4])),
|
lambda: panel_alpha(rows, ROWS[3])),
|
||||||
(ROWS[5], PANEL_TITLES[4],
|
(ROWS[4], PANEL_TITLES[3],
|
||||||
"method: training_metrics.jsonl 'epoch' deltas (training_log.jsonl has "
|
"method: training_metrics.jsonl 'epoch' deltas; 1 row = one 10-game chunk",
|
||||||
"no timestamps); 1 row = one 10-game chunk",
|
lambda: panel_throughput(rows, ROWS[4])),
|
||||||
lambda: panel_throughput(rows, ROWS[5])),
|
|
||||||
]
|
]
|
||||||
for geo, title, sub, drawer in drawers:
|
for geo, title, sub, drawer in drawers:
|
||||||
s += header(geo[3], geo[0], title, sub)
|
s += header(geo[3], geo[0], title, sub)
|
||||||
@@ -506,20 +427,10 @@ def selftest():
|
|||||||
'{"epoch": 1090.0, "critic_loss": 50, "actor_loss": 3, "alpha": 0.2}\n')
|
'{"epoch": 1090.0, "critic_loss": 50, "actor_loss": 3, "alpha": 0.2}\n')
|
||||||
rows = parse_metrics(td / "m.jsonl")
|
rows = parse_metrics(td / "m.jsonl")
|
||||||
assert len(rows) == 3 and rows[1]["critic_loss"] == 100
|
assert len(rows) == 3 and rows[1]["critic_loss"] == 100
|
||||||
glines = []
|
|
||||||
for i in range(150): # 2 full GAME_BUCKETs, both opponents in both
|
|
||||||
glines.append(json.dumps(
|
|
||||||
{"type": "game", "round": i % 10 + 1, "ticks": 100,
|
|
||||||
"score": i % 3, "total_score": i, "win": i % 3 == 0,
|
|
||||||
"opponent": ("Corners", "Crazy")[i % 2]}))
|
|
||||||
(td / "g.jsonl").write_text("\n".join(glines) + "\n")
|
|
||||||
games = parse_games(td / "g.jsonl")
|
|
||||||
assert len(games) == 150 and games[0] == ("Corners", True)
|
|
||||||
assert games[-1] == ("Crazy", False) # i=149: odd -> Crazy; 149%3!=0 -> loss
|
|
||||||
assert metric_col(rows, "actor_loss") == [(0, 2.0), (1, 4.0), (2, 3.0)]
|
assert metric_col(rows, "actor_loss") == [(0, 2.0), (1, 4.0), (2, 3.0)]
|
||||||
|
|
||||||
dash = td / "dash.svg"
|
dash = td / "dash.svg"
|
||||||
assert build_dashboard(td / "log", td / "m.jsonl", td / "g.jsonl", dash)
|
assert build_dashboard(td / "log", td / "m.jsonl", dash)
|
||||||
text = dash.read_text()
|
text = dash.read_text()
|
||||||
ET.fromstring(text) # whole doc must parse -> closing tag present
|
ET.fromstring(text) # whole doc must parse -> closing tag present
|
||||||
assert RELOAD_JS in text, "auto-reload script missing"
|
assert RELOAD_JS in text, "auto-reload script missing"
|
||||||
@@ -527,11 +438,11 @@ def selftest():
|
|||||||
assert t in text, f"panel title missing: {t}"
|
assert t in text, f"panel title missing: {t}"
|
||||||
assert text.count(PANEL_TITLES[0]) == 1
|
assert text.count(PANEL_TITLES[0]) == 1
|
||||||
assert "How to read" in text, "reading guide missing"
|
assert "How to read" in text, "reading guide missing"
|
||||||
assert 'width="1400"' in text and 'height="2000"' in text
|
assert 'width="1400"' in text and 'height="1720"' in text
|
||||||
# circles: 4 eval dots (panel 1) + 2 throughput rate dots (panel 5)
|
# circles: 4 eval dots (panel 1) + 2 throughput rate dots (panel 4)
|
||||||
assert text.count("<circle") == 6, text.count("<circle")
|
assert text.count("<circle") == 6, text.count("<circle")
|
||||||
# 2 trends + 2 real-fight opp lines + 2 losses + 1 alpha + 1 throughput
|
# 2 trends + 2 losses + 1 alpha + 1 throughput
|
||||||
assert text.count("<polyline") == 8, text.count("<polyline")
|
assert text.count("<polyline") == 6, text.count("<polyline")
|
||||||
|
|
||||||
# orientation guard: a known rising series (10% -> 90%) rendered through
|
# orientation guard: a known rising series (10% -> 90%) rendered through
|
||||||
# the FULL build path must plot upward (smaller SVG y) and forward in
|
# the FULL build path must plot upward (smaller SVG y) and forward in
|
||||||
@@ -541,7 +452,7 @@ def selftest():
|
|||||||
">>> [eval] win rate: 1/10 (10%) vs Corners\n"
|
">>> [eval] win rate: 1/10 (10%) vs Corners\n"
|
||||||
">>> [eval] win rate: 9/10 (90%) vs Corners\n")
|
">>> [eval] win rate: 9/10 (90%) vs Corners\n")
|
||||||
ori_dash = td / "ori.svg"
|
ori_dash = td / "ori.svg"
|
||||||
assert build_dashboard(ori_log, td / "m.jsonl", td / "g.jsonl", ori_dash)
|
assert build_dashboard(ori_log, td / "m.jsonl", ori_dash)
|
||||||
m = re.search(r'<polyline points="([^"]+)"', ori_dash.read_text())
|
m = re.search(r'<polyline points="([^"]+)"', ori_dash.read_text())
|
||||||
pts = [tuple(map(float, p.split(","))) for p in m.group(1).split()]
|
pts = [tuple(map(float, p.split(","))) for p in m.group(1).split()]
|
||||||
assert len(pts) == 2, pts
|
assert len(pts) == 2, pts
|
||||||
@@ -558,12 +469,11 @@ def main():
|
|||||||
args = [a for a in sys.argv[1:] if not a.startswith("-")]
|
args = [a for a in sys.argv[1:] if not a.startswith("-")]
|
||||||
campaign = Path(args[0]) if len(args) > 0 else ROOT / "campaign_v4_stdout.log"
|
campaign = Path(args[0]) if len(args) > 0 else ROOT / "campaign_v4_stdout.log"
|
||||||
metrics = Path(args[1]) if len(args) > 1 else ROOT / "training_metrics.jsonl"
|
metrics = Path(args[1]) if len(args) > 1 else ROOT / "training_metrics.jsonl"
|
||||||
games = Path(args[2]) if len(args) > 2 else ROOT / "training_log.jsonl"
|
outdir = Path(args[2]) if len(args) > 2 else ROOT / "docs"
|
||||||
outdir = Path(args[3]) if len(args) > 3 else ROOT / "docs"
|
|
||||||
outdir.mkdir(parents=True, exist_ok=True)
|
outdir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ok = build_dashboard(campaign, metrics, games, outdir / "campaign_dashboard.svg")
|
ok = build_dashboard(campaign, metrics, outdir / "campaign_dashboard.svg")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[error] dashboard build failed: {e}")
|
print(f"[error] dashboard build failed: {e}")
|
||||||
ok = False
|
ok = False
|
||||||
|
|||||||
Reference in New Issue
Block a user