Skip to content

Commit ea973ae

Browse files
committed
Add win rate heatmap, model resiliency
1 parent 5114df3 commit ea973ae

4 files changed

Lines changed: 523 additions & 4 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import argparse
2+
import json
3+
from collections import defaultdict
4+
from pathlib import Path
5+
6+
import matplotlib.colors as mcolors
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
from tqdm import tqdm
10+
11+
from codeclash.constants import LOCAL_LOG_DIR
12+
13+
14+
def main(log_dir: Path):
15+
print(f"Creating win rate heatmap from logs in {log_dir}...")
16+
17+
# Track round-level wins: (model1, model2) -> [wins, total_rounds]
18+
results = defaultdict(lambda: [0, 0])
19+
20+
for metadata_file in tqdm(list(log_dir.rglob("metadata.json"))):
21+
try:
22+
metadata = json.load(open(metadata_file))
23+
p2m = {x["name"]: x["config"]["model"]["model_name"].strip("@") for x in metadata["config"]["players"]}
24+
25+
if len(p2m) != 2:
26+
continue
27+
28+
# Process each round (skip round 0)
29+
for round_id, round_data in metadata["round_stats"].items():
30+
if round_id == "0":
31+
continue
32+
33+
winner = round_data.get("winner")
34+
if winner in p2m:
35+
winner_model = p2m[winner]
36+
loser_model = next(m for m in p2m.values() if m != winner_model)
37+
38+
results[(winner_model, loser_model)][0] += 1 # win
39+
results[(winner_model, loser_model)][1] += 1 # total
40+
results[(loser_model, winner_model)][1] += 1 # total for loser
41+
except:
42+
continue
43+
44+
# Build matrix
45+
models = sorted({m for pair in results.keys() for m in pair})
46+
clean_names = [m.split("/")[-1] for m in models]
47+
n = len(models)
48+
49+
matrix = np.full((n, n), np.nan)
50+
for i, m1 in enumerate(models):
51+
for j, m2 in enumerate(models):
52+
if i != j and results[(m1, m2)][1] > 0:
53+
matrix[i, j] = results[(m1, m2)][0] / results[(m1, m2)][1]
54+
55+
# Plot
56+
fig, ax = plt.subplots(figsize=(10, 8))
57+
cmap = mcolors.LinearSegmentedColormap.from_list("br", ["#3498db", "#ffffff", "#e74c3c"])
58+
59+
masked = np.ma.masked_where(np.isnan(matrix), matrix)
60+
im = ax.imshow(masked, cmap=cmap, vmin=0, vmax=1)
61+
62+
# Add percentages
63+
for i in range(n):
64+
for j in range(n):
65+
if not np.isnan(matrix[i, j]):
66+
color = "white" if abs(matrix[i, j] - 0.5) > 0.3 else "black"
67+
ax.text(j, i, f"{matrix[i, j]:.0%}", ha="center", va="center", color=color, fontweight="bold")
68+
69+
ax.set_xticks(range(n))
70+
ax.set_yticks(range(n))
71+
ax.set_xticklabels(clean_names, rotation=45, ha="right")
72+
ax.set_yticklabels(clean_names)
73+
ax.set_title("Model Win Rate Heatmap (Round Level)\n(Row beats Column)", fontsize=14, fontweight="bold")
74+
75+
plt.colorbar(im, label="Win Rate")
76+
plt.tight_layout()
77+
plt.savefig("heatmap_win_rates.png", dpi=300, bbox_inches="tight")
78+
print("Heatmap saved to heatmap_win_rates.png")
79+
80+
81+
if __name__ == "__main__":
82+
parser = argparse.ArgumentParser(description="Create model win rate heatmap")
83+
parser.add_argument("-d", "--log_dir", type=Path, default=LOCAL_LOG_DIR, help="Path to logs")
84+
args = parser.parse_args()
85+
main(args.log_dir)

0 commit comments

Comments
 (0)