argument-role-classifier / evaluation /evaluate_custom.py
Pengchong1113's picture
Add evaluation scripts and result artifacts
72b0375
Raw
History Blame Contribute Delete
4.18 kB
from __future__ import annotations
import argparse
import csv
import json
from pathlib import Path
from sklearn.metrics import (
accuracy_score,
classification_report,
confusion_matrix,
f1_score,
)
from src import LABEL2ID, predict
LABELS = list(LABEL2ID.keys())
def load_jsonl(path: Path) -> list[dict]:
rows = []
with path.open(encoding="utf-8") as f:
for line_no, line in enumerate(f, start=1):
if not line.strip():
continue
row = json.loads(line)
missing = {
"example_id",
"parent_text",
"current_text",
"gold_label",
} - set(row)
if missing:
raise ValueError(
f"{path}:{line_no} missing fields: {sorted(missing)}"
)
if row["gold_label"] not in LABEL2ID:
raise ValueError(
f"{path}:{line_no} invalid label: {row['gold_label']}"
)
rows.append(row)
return rows
def evaluate(
dataset_path: Path,
checkpoint_dir: str,
output_csv: Path,
) -> dict:
rows = load_jsonl(dataset_path)
y_true = []
y_pred = []
predictions = []
for row in rows:
pred = predict(
text=row["current_text"],
parent_text=row.get("parent_text", ""),
checkpoint_dir=checkpoint_dir,
)
gold = row["gold_label"]
y_true.append(gold)
y_pred.append(pred)
predictions.append({
**row,
"pred_label": pred,
"correct": gold == pred,
})
output_csv.parent.mkdir(parents=True, exist_ok=True)
fieldnames = []
for prediction in predictions:
for key in prediction:
if key not in fieldnames:
fieldnames.append(key)
with output_csv.open("w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(predictions)
report = classification_report(
y_true,
y_pred,
labels=LABELS,
zero_division=0,
output_dict=True,
)
matrix = confusion_matrix(y_true, y_pred, labels=LABELS)
return {
"n_examples": len(rows),
"accuracy": accuracy_score(y_true, y_pred),
"macro_f1": f1_score(y_true, y_pred, labels=LABELS, average="macro"),
"classification_report": report,
"confusion_matrix": {
"labels": LABELS,
"matrix": matrix.tolist(),
},
"predictions_csv": str(output_csv),
}
def main() -> None:
parser = argparse.ArgumentParser(
description="Evaluate the argument role classifier on a custom JSONL set."
)
parser.add_argument(
"--dataset",
default="evaluation/custom_argument_eval.jsonl",
type=Path,
)
parser.add_argument("--checkpoint", default="models/best")
parser.add_argument(
"--output-csv",
default="evaluation/custom_argument_eval_predictions.csv",
type=Path,
)
parser.add_argument(
"--output-json",
default="evaluation/custom_argument_eval_metrics.json",
type=Path,
)
args = parser.parse_args()
metrics = evaluate(args.dataset, args.checkpoint, args.output_csv)
args.output_json.write_text(
json.dumps(metrics, indent=2),
encoding="utf-8",
)
print(f"Examples: {metrics['n_examples']}")
print(f"Accuracy: {metrics['accuracy']:.4f}")
print(f"Macro-F1: {metrics['macro_f1']:.4f}")
print("\nClassification report:")
print(
classification_report(
[r["gold_label"] for r in load_jsonl(args.dataset)],
[
r["pred_label"]
for r in csv.DictReader(
args.output_csv.open(encoding="utf-8")
)
],
labels=LABELS,
zero_division=0,
)
)
print(f"Saved predictions to {args.output_csv}")
print(f"Saved metrics to {args.output_json}")
if __name__ == "__main__":
main()