# Line 135-147 (CURRENT - WRONG)
def predict(data):
# ... setup code ...
# AE reconstruction error
X_tensor = _torch.tensor(X_scaled, dtype=_torch.float32)
reconstructed = ae_model(X_tensor).detach().numpy()
ae_error = np.mean((X_scaled - reconstructed) ** 2)
# IF score
if_score = -if_model.score_samples(X_scaled)[0]
# normalize (you already did this in training) # <-- THIS COMMENT IS MISLEADING!
combined_score = 0.6 * ae_error + 0.4 * if_score # <-- NO NORMALIZATION HAPPENING!
label = "high_anomaly" if combined_score > thresholds["combined_threshold"] else "normal"
return {
"combined_detection_score": float(combined_score), # <-- RETURNS MILLIONS!
"detection_label": label
}Requires: Update hdfs_thresholds.json to include ae_min, ae_max, if_min, if_max
# CORRECTED VERSION
def predict(data):
try:
import numpy as np
except ModuleNotFoundError as exc:
raise RuntimeError(
"Detection dependency is missing: install 'numpy' to enable /detect/predict."
) from exc
_load_models()
if not isinstance(data, list) or not data:
raise ValueError("Input data must be a non-empty list.")
# convert to numpy
try:
X = np.array(data, dtype=float).reshape(1, -1)
except ValueError as exc:
raise ValueError("Input data must contain only numeric values.") from exc
# scale
X_scaled = scaler.transform(X)
# ========== AE RECONSTRUCTION ERROR ==========
X_tensor = _torch.tensor(X_scaled, dtype=_torch.float32)
reconstructed = ae_model(X_tensor).detach().numpy()
ae_error = np.mean((X_scaled - reconstructed) ** 2)
# ========== IF ANOMALY SCORE ==========
if_score = -if_model.score_samples(X_scaled)[0]
# ========== NORMALIZE BOTH SCORES TO 0-1 RANGE ==========
# Get min/max from thresholds (which were computed during training)
ae_min = thresholds.get("ae_min", 0.0)
ae_max = thresholds.get("ae_max", 1e-6) # Safe default for tiny AE errors
if_min = thresholds.get("if_min", 0.0)
if_max = thresholds.get("if_max", 1.0) # IF scores typically 0-1
# Normalize to 0-1 range using min-max scaling
ae_norm = (ae_error - ae_min) / (ae_max - ae_min) if ae_max > ae_min else 0.0
if_norm = (if_score - if_min) / (if_max - if_min) if if_max > if_min else 0.0
# Clamp to 0-1 range (in case of out-of-distribution data)
ae_norm = np.clip(ae_norm, 0.0, 1.0)
if_norm = np.clip(if_norm, 0.0, 1.0)
# ========== COMBINE NORMALIZED SCORES ==========
combined_score = 0.6 * ae_norm + 0.4 * if_norm # Now in 0-1 range!
# ========== CLASSIFY ==========
label = "high_anomaly" if combined_score > thresholds["combined_threshold"] else "normal"
return {
"combined_detection_score": float(combined_score), # Now returns 0-1, e.g., 0.79
"detection_label": label,
# Debug info (remove in production)
"_debug": {
"ae_error_raw": float(ae_error),
"ae_error_normalized": float(ae_norm),
"if_score_raw": float(if_score),
"if_score_normalized": float(if_norm),
}
}{
"ae_min": 0.0,
"ae_max": 1e-6,
"if_min": 0.0,
"if_max": 1.0,
"ae_threshold": 1.0179047826852639e-08,
"if_threshold": 0.47409085609379364,
"combined_threshold": 0.32164826914038835,
"fusion_weights": {
"ae": 0.6,
"if": 0.4
}
}After applying the fix, test with the same data:
# Should now return ~0.79, not 376,472,284!
python -c "import requests, json; resp = requests.post('http://localhost:8000/detect/predict', json={'data': [1.0, 2.5, 3.3, 4.2, 5.1, 6.0, 7.2, 8.1, 9.5, 10.0, 11.3, 12.2, 13.1, 14.0, 15.5, 16.2, 17.1, 18.0, 19.3, 20.2, 21.1, 22.0, 23.5, 24.2, 25.1, 26.0, 27.3, 28.2, 29.1, 30.0, 31.5, 32.2, 33.1, 34.0, 35.5, 36.2]}); print(json.dumps(resp.json(), indent=2))"Expected Output (FIXED):
{
"combined_detection_score": 0.7912345,
"detection_label": "high_anomaly",
"_debug": {
"ae_error_raw": 1.234e-6,
"ae_error_normalized": 0.79,
"if_score_raw": 0.84,
"if_score_normalized": 0.84
}
}Search your training code/notebook for:
- Where
ae_errorswere collected from training samples - Where
if_scoreswere collected from training samples - Compute:
ae_min = min(ae_errors),ae_max = max(ae_errors) - Compute:
if_min = min(if_scores),if_max = max(if_scores) - Add these to
hdfs_thresholds.json
| Before Fix | After Fix |
|---|---|
| Combined score: 376,472,284 | Combined score: 0.791 |
| Threshold: 0.322 (never matched) | Threshold: 0.322 (properly matched) |
| Classification: Always wrong | Classification: Correct |