MegrurNiftiyev's picture
Upload folder using huggingface_hub
215f97f verified
Raw History Blame Contribute Delete
2.68 kB
"""
Model evaluation — precision, recall, F1 (macro), and classification report.
Uses the held-out test set with a realistic class distribution (~5-8%
injection) so metrics approximate real-world performance.
"""
import numpy as np
from sklearn.metrics import precision_recall_fscore_support, classification_report
from app.ml.cnn.architecture import LABEL_NAMES
from app.core.logging import get_logger
logger = get_logger(__name__)
def decode_predictions(label_probs: np.ndarray) -> list[str]:
"""Convert softmax probability arrays to label strings.
Args:
label_probs: Array of shape ``(N, 3)`` — softmax output from the
``label`` head of the model.
Returns:
List of label strings (``"safe"``, ``"suspicious"``, ``"injection"``).
"""
indices = np.argmax(label_probs, axis=1)
return [LABEL_NAMES[i] for i in indices]
def evaluate(model, test_texts: np.ndarray, test_labels_onehot: np.ndarray) -> dict:
"""Evaluate the model on the test set.
Runs prediction, decodes labels, and computes macro-averaged
precision, recall, and F1 plus a per-class classification report.
Args:
model: Trained Keras model with dual output heads.
test_texts: Array of shape ``(N, 1)`` — raw text strings.
test_labels_onehot: One-hot encoded true labels, shape ``(N, 3)``.
Returns:
Dict with ``precision``, ``recall``, ``f1``, and ``report`` keys.
"""
# Run prediction — model returns [label_probs, category_probs]
predictions = model.predict(test_texts, verbose=0)
label_probs = predictions[0] # shape (N, 3)
# Decode predictions and true labels
pred_labels = decode_predictions(label_probs)
true_labels = decode_predictions(test_labels_onehot)
# Macro-averaged metrics
precision, recall, f1, _ = precision_recall_fscore_support(
true_labels, pred_labels, average="macro", zero_division=0
)
# Per-class report
# We dynamically determine labels to avoid ValueError if some classes are missing in test set
unique_labels = sorted(list(set(true_labels + pred_labels)))
report = classification_report(
true_labels,
pred_labels,
labels=unique_labels,
output_dict=True,
zero_division=0,
)
metrics = {
"precision": float(precision),
"recall": float(recall),
"f1": float(f1),
"report": report,
}
logger.info(
"Evaluation: precision=%.4f, recall=%.4f, F1=%.4f",
precision,
recall,
f1,
)
return metrics