Skip to content

Commit 098d491

Browse files
committed
llm as judge: updates to aggregate/get inst
1 parent 871e669 commit 098d491

3 files changed

Lines changed: 45 additions & 12 deletions

File tree

codeclash/analysis/llm_as_judge/aggregate_results.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def aggregate_results_to_dataframe(input_dir: Path) -> pd.DataFrame:
4545
# Extract instance metadata
4646
instance = Instance.model_validate(instance_data["instance"])
4747
model_name, opponent_model_name = instance.get_lm_name_self_opponent()
48+
current_round_win_rate, next_round_win_rate = instance.get_current_next_round_win_rate()
4849

4950
# Create a flat row with all information
5051
row = {
@@ -55,6 +56,8 @@ def aggregate_results_to_dataframe(input_dir: Path) -> pd.DataFrame:
5556
"round_number": instance.round_number,
5657
"model_name": model_name,
5758
"opponent_model_name": opponent_model_name,
59+
"current_round_win_rate": current_round_win_rate,
60+
"next_round_win_rate": next_round_win_rate,
5861
}
5962

6063
# Add all evaluation results

codeclash/analysis/llm_as_judge/get_instances.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import argparse
66
from pathlib import Path
7+
from collections import defaultdict
8+
from pyexpat import model
79

810
from codeclash.analysis.llm_as_judge.utils import InstanceBatch, get_instances
911

@@ -13,8 +15,9 @@
1315
parser.add_argument("-o", "--output-file", type=Path, help="Path to the output file", default="instances.json")
1416
args = parser.parse_args()
1517

16-
SELECTED_ROUNDS = [1, 2, 3, 5, 10, 15]
18+
SELECTED_ROUNDS = [1, 2, 3, 5, 10, 12, 14, 15]
1719
SELECTED_GAME = "BattleSnake"
20+
NUMBER_OF_INDEPENDENT_GAMES = 3
1821

1922
# first get all instances, then filter
2023
instances = sorted(get_instances(args.input_dir), key=lambda x: x.instance_id)
@@ -24,17 +27,24 @@
2427
instances = [instance for instance in instances if instance.round_number in SELECTED_ROUNDS]
2528
print(f"Filtered to {len(instances)} instances because of round number")
2629

27-
# OK, now it gest more complicated, because we only want to keep one
28-
# instance per combination of game, lm, and round
29-
unique = {}
30+
grouped = defaultdict(list)
3031
for instance in instances:
31-
key = (*instance.get_lm_name_self_opponent(), instance.round_number)
32-
if key not in unique:
33-
unique[key] = instance
34-
instances = list(unique.values())
32+
model_name_player, model_name_opponent = instance.get_lm_name_self_opponent()
33+
if model_name_player == model_name_opponent:
34+
continue
35+
key = (model_name_player, model_name_opponent, instance.round_number)
36+
grouped[key].append(instance)
37+
38+
selected_instances = []
39+
for key, instance_list in grouped.items():
40+
if len(instance_list) < NUMBER_OF_INDEPENDENT_GAMES:
41+
print(f"Warning: Only found {len(instance_list)} instances for {key}, need {NUMBER_OF_INDEPENDENT_GAMES}")
42+
selected_count = min(len(instance_list), NUMBER_OF_INDEPENDENT_GAMES)
43+
selected_instances.extend(instance_list[:selected_count])
44+
45+
instances = selected_instances
3546
unique_models = set([instance.get_lm_name_self_opponent()[0] for instance in instances])
36-
print(unique_models)
37-
print(f"Filtered to {len(instances)} instances after deduplication for game repetitions for {len(unique_models)} unique model matchups")
47+
print(f"Filtered to {len(instances)} instances after keeping {NUMBER_OF_INDEPENDENT_GAMES} for game repetitions for {len(unique_models)} unique model matchups")
3848

3949
batch = InstanceBatch(instances=instances)
4050
args.output_file.write_text(batch.model_dump_json())

codeclash/analysis/llm_as_judge/utils.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
from pathlib import Path
44

5+
from codeclash.analysis.metrics.elo import get_scores
56
from pydantic import BaseModel
67

78

@@ -31,14 +32,33 @@ class Instance(BaseModel):
3132
@property
3233
def instance_id(self) -> str:
3334
return f"{self.tournament_name}__{self.player_name}__r{self.round_number}"
35+
36+
@property
37+
def tournament_path(self) -> Path:
38+
return self.trajectory_path.parent.parent.parent
39+
40+
@property
41+
def metadata_path(self) -> Path:
42+
return self.tournament_path / "metadata.json"
3443

3544
def get_lm_name_self_opponent(self) -> tuple[str, str]:
36-
metadata_path = self.trajectory_path.parent.parent.parent / "metadata.json"
37-
metadata = json.loads(metadata_path.read_text())
45+
metadata = json.loads(self.metadata_path.read_text())
3846
player_configs = metadata["config"]["players"]
3947
player_config = [pc for pc in player_configs if pc["name"] == self.player_name][0]
4048
other_player_config = [pc for pc in player_configs if pc["name"] != self.player_name][0]
4149
return player_config["config"]["model"]["model_name"].removeprefix("@"), other_player_config["config"]["model"]["model_name"].removeprefix("@")
50+
51+
def get_current_next_round_win_rate(self) -> tuple[float | None, float | None]:
52+
metadata = json.loads(self.metadata_path.read_text())
53+
current_round_stats = metadata["round_stats"].get(str(self.round_number))
54+
next_round_stats = metadata["round_stats"].get(str(self.round_number + 1))
55+
current_win_rate = None
56+
next_win_rate = None
57+
if current_round_stats is not None:
58+
current_win_rate = get_scores(current_round_stats).get(self.player_name)
59+
if next_round_stats is not None:
60+
next_win_rate = get_scores(next_round_stats).get(self.player_name)
61+
return current_win_rate, next_win_rate
4262

4363

4464
class InstanceBatch(BaseModel):

0 commit comments

Comments
 (0)