TrackChain / ml /tests /test_sequence_vae_dual_path.py
PRiyanshu0-1's picture
Add ml/ codebase and configs
2adb41a verified
Raw History Blame Contribute Delete
1.72 kB
"""
ml/tests/test_sequence_vae_dual_path.py
Validates Dual-Path Anomaly Scoring (Reconstruction MSE + Latent Mahalanobis Distance).
"""
import pytest
import numpy as np
import torch
from ml.models.geometry.sequence_vae import SequenceVAE, SequenceVAEDetector
from ml.core.schema import SignalType, DefectClass, CalibratedSignal
def test_dual_path_latent_distribution_fitting():
"""Verify that fitting latent distribution computes baseline mean and inverse covariance."""
detector = SequenceVAEDetector(alpha=0.7)
# 40 normal sequences of 80 bins x 5 features
normal_seqs = np.random.randn(40, 80, 5).astype(np.float32) * 0.2
detector.fit_latent_distribution(normal_seqs)
assert detector.normal_latent_mean is not None
assert detector.normal_latent_cov_inv is not None
assert detector.normal_latent_mean.shape == (detector.latent_dim,)
assert detector.normal_latent_cov_inv.shape == (detector.latent_dim, detector.latent_dim)
def test_dual_path_scoring_combination():
"""Verify that anomaly score correctly weights reconstruction and Mahalanobis components."""
detector = SequenceVAEDetector(alpha=0.7)
normal_seqs = np.random.randn(50, 80, 5).astype(np.float32) * 0.1
detector.fit_latent_distribution(normal_seqs)
test_seq = np.random.randn(80, 5).astype(np.float32) * 0.1
score = detector.compute_anomaly_score(test_seq)
assert isinstance(score, float)
assert score >= 0.0
# Extreme anomaly (high MSE and high latent shift)
anom_seq = np.full((80, 5), 15.0, dtype=np.float32)
anom_score = detector.compute_anomaly_score(anom_seq)
assert anom_score > score * 5.0, f"Expected anomaly score {anom_score} >> normal score {score}"