Skip to content

Commit a38fb4d

Browse files
committed
Update threshold sweep logic and add formal validation report
1 parent 87fe6a5 commit a38fb4d

2 files changed

Lines changed: 52 additions & 4 deletions

File tree

threshold_sweep.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from cnsd.diagnosis.system import CNSD
77

88
# Reuse CWRU loader and configs from validate_run
9-
from validate_run import load_cwru, CWRU, TAXONOMY
9+
from validate_run import load_cwru, CWRU, TAXONOMY, headline_accuracy_by_verdict
1010

1111
def main():
1212
print('=' * 50)
@@ -26,18 +26,25 @@ def main():
2626
model = CNSD()
2727
model.fit(train_data, epochs=30)
2828

29-
print('\nStarting Threshold Sweep on Test Data:')
29+
print('\nStarting Threshold Sweep on Calibration/Train Data:')
3030
thresholds = [3.0, 2.5, 2.0, 1.5]
3131

3232
for t in thresholds:
33-
print('-' * 40)
33+
print('-' * 60)
3434
print(f'Testing Threshold: {t}')
3535
model.symbolic.tau = t # Hot-swap the threshold!
36-
report = model.diagnose(test_data)
36+
report = model.diagnose(train_data)
3737
vr = report.verification_rate()
3838
print(f" CONFIRMED : {vr.get('CONFIRMED', 0.0):.1%}")
3939
print(f" CONFLICT : {vr.get('CONFLICT', 0.0):.1%}")
4040
print(f" INCONCLUSIVE: {vr.get('INCONCLUSIVE', 0.0):.1%}")
41+
42+
hb = headline_accuracy_by_verdict(report, train_data.y)
43+
if 'CONFIRMED' in hb and 'CONFLICT' in hb:
44+
gap = hb['CONFIRMED']['cnn_accuracy'] - hb['CONFLICT']['cnn_accuracy']
45+
print(f" ACCURACY GAP: +{gap:.3f} (CONFIRMED vs CONFLICT)")
46+
else:
47+
print(" ACCURACY GAP: N/A (Missing CONFIRMED or CONFLICT samples)")
4148

4249
if __name__ == '__main__':
4350
main()

validation_report.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# CNSD Pipeline Validation Report (Issue #8)
2+
3+
This document serves as a professional record of the experiments, fixes, and validation runs performed to harden the CWRU baseline for the CNSD causal-neurosymbolic system.
4+
5+
## 1. Loader Bug Fix (Nested Subdirectories)
6+
The `load_cwru()` function was missing the `@3`, `@6`, and `@12` outer-race classes due to a rigid directory parsing logic. This was fixed by utilizing `os.walk` to comprehensively scan all nested subdirectories for `.mat` files.
7+
8+
**Result**: All 10 CWRU taxonomy classes are now correctly ingested.
9+
```text
10+
[train_data] Dataset 'CWRU_Train': 5806 samples, window=1024, fs=12000Hz, classes=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], conditions=[0, 1, 2], physics=yes
11+
[test_data] Dataset 'CWRU_Test': 2019 samples, window=1024, fs=12000Hz, classes=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], conditions=[3], physics=yes
12+
```
13+
14+
## 2. Root-Cause Printing Fix
15+
The root-cause print loop was previously dumping raw physics vectors and showing "No defect detected". The logic was updated to specifically filter for `CONFIRMED` faults and uniquely print the human-readable physical descriptions of each fault class exactly once.
16+
17+
**Result**: Clean, auditable, and human-readable root-cause statements.
18+
```text
19+
[examples] auditable root-cause diagnoses (CONFIRMED faults only):
20+
[Class 2] [HIGH_CONFIDENCE] Defect on the rolling element (Ball), evidenced by a peak at the BSF (135.9 Hz, strength 3.5). a defect on a rolling element striking both races as it spins.
21+
[Class 4] [HIGH_CONFIDENCE] Defect on the inner race (Inner Race), evidenced by a peak at the BPFI (156.1 Hz, strength 4.4). a defect on the rotating inner race, modulated by shaft rotation.
22+
[Class 5] [HIGH_CONFIDENCE] Defect on the inner race (Inner Race), evidenced by a peak at the BPFI (156.1 Hz, strength 3.0). a defect on the rotating inner race, modulated by shaft rotation.
23+
[Class 6] [HIGH_CONFIDENCE] Defect on the inner race (Inner Race), evidenced by a peak at the BPFI (156.1 Hz, strength 3.3). a defect on the rotating inner race, modulated by shaft rotation.
24+
[Class 7] [HIGH_CONFIDENCE] Defect on the outer race (Outer Race), evidenced by a peak at the BPFO (103.4 Hz, strength 4.6). a defect on the stationary outer race struck by each rolling element.
25+
```
26+
27+
## 3. Threshold Sweep (Calibration Data)
28+
To reduce the high "INCONCLUSIVE" abstention rate, the symbolic envelope-prominence threshold (`tau`) was swept across the **calibration (training) split** to prevent test-set tuning (data leakage). At each threshold, the accuracy gap between `CONFIRMED` and `CONFLICT` samples was measured.
29+
30+
**Sweep Results (Calibration Data)**:
31+
* **Threshold 3.0**: 49.8% Inconclusive | 2.3% Conflict | Gap: +0.000
32+
* **Threshold 2.5**: 37.4% Inconclusive | 4.9% Conflict | Gap: +0.000
33+
* **Threshold 2.0**: 23.9% Inconclusive | 12.5% Conflict | Gap: +0.000
34+
* **Threshold 1.5**: 8.7% Inconclusive | 27.5% Conflict | Gap: +0.000
35+
36+
*Note: The CNN gap is +0.000 on the calibration set because the CNN perfectly memorizes the training data (100% accuracy).*
37+
38+
**Conclusion**: We officially lock the threshold at **`2.5`**. Lowering the threshold to 2.5 successfully cuts the inconclusive abstention rate by >10% while keeping the false alarm conflicts under a strict 5.0% tolerance.
39+
40+
## 4. Terminology Clarification
41+
The script `cross_domain_validation.py` was renamed to `cross_condition_robustness.py` to correctly reflect the protocol (AWGN noise injection). "Cross-domain" is reserved for multi-rig experiments (e.g., SEU/Paderborn).

0 commit comments

Comments
 (0)