maintenance-classifier-api / training /evaluate_severity.py
Satyam311's picture
Clean deploy: numpy vector search, binaries excluded
d4ec2fa
Raw History Blame Contribute Delete
3.88 kB
"""
Ticket 6 (severity half) — Evaluation & Confusion Matrix Report.
Same approach as evaluate.py, applied to the severity classifier.
"""
import json
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandas as pd
import torch
from sklearn.metrics import (
accuracy_score,
classification_report,
confusion_matrix,
precision_recall_fscore_support,
)
from transformers import AutoModelForSequenceClassification, AutoTokenizer
MODEL_DIR = "models/severity_classifier"
TEST_CSV = "data/processed/test.csv"
MAX_LENGTH = 256
OUT_DIR = "reports/severity_classifier"
def main():
Path(OUT_DIR).mkdir(parents=True, exist_ok=True)
tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR, local_files_only=True)
model = AutoModelForSequenceClassification.from_pretrained(MODEL_DIR, local_files_only=True)
model.eval()
with open(f"{MODEL_DIR}/label_map.json") as f:
label_map = json.load(f)
id2label = {int(k): v for k, v in label_map["id2label"].items()}
label2id = label_map["label2id"]
df = pd.read_csv(TEST_CSV)
df = df[df["severity_label"].notna()].reset_index(drop=True)
print(f"Test examples (severity-labeled): {len(df)}")
print(df["severity_label"].value_counts())
true_labels = df["severity_label"].astype(str).tolist()
y_true = [label2id[t] for t in true_labels]
y_pred = []
with torch.no_grad():
for text in df["narrative_text"].tolist():
inputs = tokenizer(text, truncation=True, max_length=MAX_LENGTH, return_tensors="pt")
logits = model(**inputs).logits
pred_id = int(torch.argmax(logits, dim=1).item())
y_pred.append(pred_id)
acc = accuracy_score(y_true, y_pred)
precision, recall, f1, _ = precision_recall_fscore_support(y_true, y_pred, average="macro", zero_division=0)
print(f"\n=== TEST SET RESULTS ===")
print(f"Accuracy: {acc:.1%}")
print(f"Macro F1: {f1:.3f} (PRD target: >=0.70)")
print(f"Macro Precision: {precision:.3f} Macro Recall: {recall:.3f}")
labels_present = sorted(set(y_true) | set(y_pred))
target_names = [id2label[i] for i in labels_present]
report_dict = classification_report(
y_true, y_pred, labels=labels_present, target_names=target_names, zero_division=0, output_dict=True
)
print("\nPer-class report:")
print(classification_report(y_true, y_pred, labels=labels_present, target_names=target_names, zero_division=0))
cm = confusion_matrix(y_true, y_pred, labels=labels_present)
fig, ax = plt.subplots(figsize=(6, 5))
im = ax.imshow(cm, cmap="Oranges")
ax.set_xticks(range(len(target_names)))
ax.set_yticks(range(len(target_names)))
ax.set_xticklabels(target_names, rotation=45, ha="right")
ax.set_yticklabels(target_names)
ax.set_xlabel("Predicted")
ax.set_ylabel("True")
ax.set_title("Severity Classifier — Confusion Matrix (Test Set)")
for i in range(len(target_names)):
for j in range(len(target_names)):
ax.text(j, i, str(cm[i, j]), ha="center", va="center",
color="white" if cm[i, j] > cm.max() / 2 else "black")
fig.colorbar(im)
fig.tight_layout()
fig.savefig(f"{OUT_DIR}/confusion_matrix.png", dpi=150)
print(f"\nSaved confusion matrix to {OUT_DIR}/confusion_matrix.png")
metrics_out = {
"test_accuracy": acc,
"test_macro_f1": f1,
"test_macro_precision": precision,
"test_macro_recall": recall,
"n_test_examples": len(df),
"per_class": report_dict,
"prd_target_macro_f1": 0.70,
"meets_prd_target": f1 >= 0.70,
}
with open(f"{OUT_DIR}/metrics.json", "w") as f:
json.dump(metrics_out, f, indent=2)
print(f"Saved metrics JSON to {OUT_DIR}/metrics.json")
if __name__ == "__main__":
main()