interview / src /plot_curves.py
Lee93whut
chore: initial project scaffold
141a818
"""
plot_curves.py โ€” ไปŽ TensorBoard event ๆ–‡ไปถ็”Ÿๆˆๅฏนๆฏ”ๅ›พ
็”จๆณ•๏ผšpython src/plot_curves.py
่พ“ๅ‡บ๏ผšdocs/assets/round2/ ๅ’Œ docs/assets/compare/ ไธ‹็š„ PNG ๆ–‡ไปถ
"""
import os
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from tensorboard.backend.event_processing import event_accumulator
# โ”€โ”€ ้…็ฝฎ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
RUNS = {
"Round1\n(ฮต_decay=0.995, ep=2000)": "runs/Round1_double_epsilon0.995_ep2000",
"Round2\n(ฮต_decay=0.9985, ep=6000)": "runs/Round2_double_epsilon0.9985_ep6000",
}
COLORS = {
"Round1\n(ฮต_decay=0.995, ep=2000)": "#E07B39", # ๆฉ™
"Round2\n(ฮต_decay=0.9985, ep=6000)": "#4878CF", # ่“
}
OUT_CMP = "docs/assets/compare"
OUT_R2 = "docs/assets/round2"
os.makedirs(OUT_CMP, exist_ok=True)
os.makedirs(OUT_R2, exist_ok=True)
# โ”€โ”€ ่ฏปๅ– event ๆ–‡ไปถ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def load(run_path: str, tag: str):
ea = event_accumulator.EventAccumulator(
run_path, size_guidance={event_accumulator.SCALARS: 0}
)
ea.Reload()
events = ea.Scalars(tag)
steps = np.array([e.step for e in events])
values = np.array([e.value for e in events])
return steps, values
def smooth(values, weight=0.6):
"""ๆŒ‡ๆ•ฐ็งปๅŠจๅนณๅ‡ๅนณๆป‘"""
s, out = values[0], []
for v in values:
s = weight * s + (1 - weight) * v
out.append(s)
return np.array(out)
# โ”€โ”€ ้€š็”จ็ป˜ๅ›พๅ‡ฝๆ•ฐ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def plot_compare(tag, ylabel, title, filename,
run_keys=None, ylim=None, smooth_w=0.0,
hlines=None, outdir=OUT_CMP):
"""็ป˜ๅˆถๅคšๆกๆ›ฒ็บฟๅฏนๆฏ”ๅ›พ"""
fig, ax = plt.subplots(figsize=(10, 5))
keys = run_keys or list(RUNS.keys())
for label in keys:
path = RUNS[label]
try:
steps, vals = load(path, tag)
except Exception as e:
print(f" [SKIP] {label}: {e}")
continue
if smooth_w > 0:
vals = smooth(vals, smooth_w)
ax.plot(steps, vals, label=label, color=COLORS[label],
linewidth=1.8, alpha=0.9)
if hlines:
for y, color, text in hlines:
ax.axhline(y, color=color, linestyle="--", linewidth=1.2, alpha=0.7)
ax.text(ax.get_xlim()[1] if ax.get_xlim()[1] > 0 else 6000,
y + 0.5, text, color=color, fontsize=9, va="bottom")
ax.set_xlabel("Episode", fontsize=12)
ax.set_ylabel(ylabel, fontsize=12)
ax.set_title(title, fontsize=13, fontweight="bold")
if ylim:
ax.set_ylim(ylim)
ax.legend(fontsize=10, loc="lower right")
ax.grid(True, alpha=0.3)
fig.tight_layout()
out_path = os.path.join(outdir, filename)
fig.savefig(out_path, dpi=150)
plt.close(fig)
print(f" โœ… {out_path}")
# โ”€โ”€ 1. ๅฏนๆฏ”ๅ›พ๏ผšTest_Success_Rate R1 vs R2 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
print("็”Ÿๆˆๅฏนๆฏ”ๅ›พ...")
plot_compare(
tag="Evaluation_Exam/Test_Success_Rate",
ylabel="Blind Test Success Rate",
title="Evaluation: Test Success Rate โ€” Round 1 vs Round 2",
filename="cmp_eval_success_rate_r1_vs_r2.png",
ylim=(0, 100),
smooth_w=0.0,
hlines=[(74, "#4878CF", "R2 ๅณฐๅ€ผ 74%"), (54, "#E07B39", "R1 ๅณฐๅ€ผ 54%")],
)
# โ”€โ”€ 2. ๅฏนๆฏ”ๅ›พ๏ผšGlobal_Epsilon R1 vs R2 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
plot_compare(
tag="Frontend_Env/Global_Epsilon",
ylabel="ฮต (Epsilon)",
title="Exploration Decay โ€” Round 1 vs Round 2",
filename="cmp_frontend_epsilon_r1_vs_r2.png",
ylim=(0, 1.05),
smooth_w=0.0,
hlines=[(0.05, "gray", "ฮต_min=0.05")],
)
# โ”€โ”€ 3. R2 ๅ•็‹ฌ๏ผšTest_Success_Rate โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
print("็”Ÿๆˆ Round 2 ๅ•็‹ฌๅ›พ...")
R2_KEY = "Round2\n(ฮต_decay=0.9985, ep=6000)"
def plot_single(tag, ylabel, title, filename, ylim=None, smooth_w=0.0,
hlines=None, vlines=None, outdir=OUT_R2):
fig, ax = plt.subplots(figsize=(10, 5))
steps, vals = load(RUNS[R2_KEY], tag)
color = COLORS[R2_KEY]
if smooth_w > 0:
ax.plot(steps, vals, color=color, alpha=0.25, linewidth=1.0)
ax.plot(steps, smooth(vals, smooth_w), color=color,
linewidth=2.0, label="Round 2๏ผˆๅนณๆป‘๏ผ‰")
else:
ax.plot(steps, vals, color=color, linewidth=1.8,
label="Round 2\n(ฮต_decay=0.9985, ep=6000)")
if hlines:
for y, c, text in hlines:
ax.axhline(y, color=c, linestyle="--", linewidth=1.2, alpha=0.7)
ax.text(6100, y + 0.5, text, color=c, fontsize=9, va="bottom")
if vlines:
for x, c, text in vlines:
ax.axvline(x, color=c, linestyle=":", linewidth=1.2, alpha=0.8)
ax.text(x + 30, ax.get_ylim()[0] + 2 if ylim is None else ylim[0] + 2,
text, color=c, fontsize=8, rotation=90, va="bottom")
ax.set_xlabel("Episode", fontsize=12)
ax.set_ylabel(ylabel, fontsize=12)
ax.set_title(title, fontsize=13, fontweight="bold")
if ylim:
ax.set_ylim(ylim)
ax.legend(fontsize=10, loc="lower right")
ax.grid(True, alpha=0.3)
fig.tight_layout()
out_path = os.path.join(outdir, filename)
fig.savefig(out_path, dpi=150)
plt.close(fig)
print(f" โœ… {out_path}")
plot_single(
tag="Evaluation_Exam/Test_Success_Rate",
ylabel="Blind Test Success Rate (%)",
title="Round 2: Blind Test Success Rate๏ผˆๅ…จ็จ‹ๆŒฏ่ก๏ผŒๆ— ๆ”ถๆ•›ๅนณๅฐ๏ผ‰",
filename="r2_eval_success_rate.png",
ylim=(0, 100),
hlines=[(74, "#2ca02c", "ๅณฐๅ€ผ 74%๏ผˆep=3300, ep=4250๏ผ‰"),
(52, "#d62728", "ไฝŽ่ฐท 52%๏ผˆep=5300, ep=5900๏ผ‰")],
vlines=[(3300, "#2ca02c", "ep=3300"), (4250, "#2ca02c", "ep=4250"),
(2189, "#9467bd", "ฮต่งฆๅบ• epโ‰ˆ2189")],
)
# โ”€โ”€ 4. R2 ๅ•็‹ฌ๏ผšSPL โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
plot_single(
tag="Evaluation_Exam/SPL",
ylabel="SPL",
title="Round 2: SPL๏ผˆSuccess-weighted Path Length๏ผ‰",
filename="r2_eval_spl.png",
ylim=(0, 1.0),
)
# โ”€โ”€ 5. R2 ๅ•็‹ฌ๏ผšGlobal_Epsilon โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
plot_single(
tag="Frontend_Env/Global_Epsilon",
ylabel="ฮต (Epsilon)",
title="Round 2: Exploration Decay๏ผˆepโ‰ˆ2189 ่งฆๅบ•๏ผ‰",
filename="r2_frontend_epsilon.png",
ylim=(0, 1.05),
hlines=[(0.05, "gray", "ฮต_min=0.05")],
vlines=[(2189, "#9467bd", "ฮต่งฆๅบ• epโ‰ˆ2189")],
)
# โ”€โ”€ 6. R2 ๅ•็‹ฌ๏ผšAvg_Reward_Window โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
plot_single(
tag="Frontend_Env/Avg_Reward_Window",
ylabel="Avg Reward (rolling 100 ep)",
title="Round 2: Rolling Average Reward",
filename="r2_frontend_avg_reward.png",
smooth_w=0.7,
)
# โ”€โ”€ 7. R2 ๅ•็‹ฌ๏ผšLoss โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
plot_single(
tag="Backend_Net/Loss",
ylabel="TD Loss",
title="Round 2: Training Loss",
filename="r2_backend_loss.png",
smooth_w=0.85,
)
# โ”€โ”€ 8. R2 ๅ•็‹ฌ๏ผšAvg_Q_Value โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
plot_single(
tag="Backend_Net/Avg_Q_Value",
ylabel="Avg Q Value",
title="Round 2: Average Q Value",
filename="r2_backend_avg_q.png",
smooth_w=0.7,
)
print("\nๅ…จ้ƒจๅฎŒๆˆ๏ผ")