polyglot-tutor / training /eval_cefr.py
Arthur_Diaz
feat(ml): CEFR dataset builder and XLM-R training pipeline with MLflow tracking (#2)
14e67ea unverified
Raw
History Blame Contribute Delete
2.75 kB
"""Evaluate any CEFR checkpoint on the canonical split — including the published
baseline, for the ADR 0003 comparison.
Usage (from the repo root):
uv run --group train python training/eval_cefr.py \
--model UniversalCEFR/xlm-roberta-base-cefr-all-classifier \
--config training/configs/en_only.toml
uv run --group train python training/eval_cefr.py \
--model models/cefr/en_chunked_weighted/model \
--config training/configs/en_only.toml
The --config defines the data and the split; use the same config as the run
you compare against so both models see the *same* test documents.
"""
import argparse
import json
from pathlib import Path
from evaluation import evaluate_views, lang_filtered, predict_probs
from train_cefr import build_parts, load_config
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--model", required=True, help="local checkpoint dir or Hub id")
parser.add_argument("--config", type=Path, required=True)
parser.add_argument("--batch-size", type=int, default=64)
args = parser.parse_args()
config = load_config(args.config)
parts = build_parts(config)
test_passages = parts["test"]
print(f"Evaluating {args.model} on {len(test_passages)} test passages")
import mlflow
from transformers import AutoModelForSequenceClassification, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(args.model)
model = AutoModelForSequenceClassification.from_pretrained(args.model)
if hasattr(model, "cuda"):
import torch
if torch.cuda.is_available():
model = model.cuda()
max_length = config["model"].get("max_length", 512)
probs = predict_probs(
model, tokenizer, test_passages, max_length=max_length, batch_size=args.batch_size
)
en_passages, en_probs = lang_filtered(test_passages, probs, "en")
results = {
"en": evaluate_views(en_passages, en_probs),
"all": evaluate_views(test_passages, probs),
}
tracking = config.get("tracking", {})
mlflow.set_tracking_uri(tracking.get("uri", "sqlite:///mlflow.db"))
mlflow.set_experiment(tracking.get("experiment", "cefr-classifier"))
run_name = f"eval__{args.model.replace('/', '_')}"
with mlflow.start_run(run_name=run_name):
mlflow.log_param("model", args.model)
mlflow.log_param("config", str(args.config))
for scope, views in results.items():
for view, report in views.items():
mlflow.log_metrics({f"test_{scope}_{view}_{k}": v for k, v in report.items()})
mlflow.log_dict(results, "test_metrics.json")
print(json.dumps(results, indent=2))
if __name__ == "__main__":
main()