Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders

GitHub: Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders

基于LSTM自编码器的航天器遥测无监督异常检测系统,在NASA SMAP/MSL真实任务数据上实现了完整的端到端流水线。

Stars: 0 | Forks: 0

# 🚀 航天器遥测异常检测 **ISRO Vikram Sarabhai Space Centre (VSSC) — 实习项目** ## 📋 目录 - [项目概述](#-project-overview) - [数据集](#-dataset) - [Pipeline 架构](#-pipeline-architecture) - [分阶段详解](#-stage-by-stage-breakdown) - [LSTM Autoencoder 架构](#-lstm-autoencoder-architecture) - [训练](#-training) - [阈值检测](#-threshold-detection) - [结果](#-results) - [讨论与局限性](#-discussion--limitations) - [环境配置与安装](#-setup--installation) - [项目结构](#-project-structure) - [关键设计决策](#-key-design-decisions) - [参考资料](#-references) ## 🛰 项目概述 航天器会产生连续的遥测数据流——包括传感器读数、指令状态、工程测量值——这些数据必须被实时监控以发现异常。大规模的人工检查是不可行的。本项目构建了一个完全**无监督异常检测系统**,仅使用标称(健康)运行数据进行训练,然后标记出重构误差超过学习阈值的窗口。 **为什么选择无监督?** 在实际任务中,标记的异常数据稀缺、昂贵,并且通常只有在事后分析之后才能获得。Autoencoder 仅从健康数据中学习正常流形——训练期间不需要异常标签。 **核心机制:** ``` Train LSTM Autoencoder on normal sequences only ↓ At inference: reconstruct each test window ↓ Anomaly score = MSE(input, reconstruction) ↓ Flag window if score > threshold ``` **项目亮点:** - 7 阶段模块化 notebook pipeline,可在 Google Colab 上完全复现 - 严格的无泄露保证——Scaler 仅在训练数据上拟合,并通过断言验证 - 通过自相关函数 (ACF) 分析进行数据驱动的窗口大小选择 - 比较了双重阈值策略:第 99 百分位数 vs 动态 EWM - 完整的评估套件:F1, ROC-AUC, PR-AUC, 混淆矩阵 ## 📡 数据集 **NASA 异常检测数据集 — SMAP & MSL** 来源:[Kaggle / Patrick Fleith](https://www.kaggle.com/datasets/patrickfleith/nasa-anomaly-detection-dataset-smap-msl) · 通过 KaggleHub 下载 | 属性 | 值 | |---|---| | 航天器 | SMAP (土壤水分主被动探测卫星) + MSL (火星科学实验室) | | 总通道数 | **82** (训练) / **82** (测试) | | 格式 | `.npy` 多变量时间序列数组 | | 真值 | `labeled_anomalies.csv` — 异常区间为 `[start, end]` 索引对 | | 使用的主要通道 | **P-1** (SMAP) | **通道 P-1 维度:** | 划分 | 形状 | 含义 | |---|---|---| | 训练集 | (2,872 × 25) | 2,872 个时间步,25 个原始特征 | | 测试集 | (8,505 × 25) | 8,505 个时间步,25 个原始特征 | 测试集包含 **3 个标记的异常区间**,横跨约 8,500 个时间步——这是一个现实的、严重不平衡的场景(按窗口计数异常率约为 10%)。 ### 带有真值异常区域的测试信号 ![P-1 测试遥测数据与异常区间](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P1_data_check.png?raw=true) ## 🏗 Pipeline 架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ RAW TELEMETRY (.npy) │ │ Train: (2872, 25) Test: (8505, 25) │ └──────────────────────────┬──────────────────────────────────┘ │ ┌────────────▼────────────┐ │ 01 DATA LOADER │ │ Load · Validate · Label │ └────────────┬────────────┘ │ ┌────────────▼────────────┐ │ 02 PREPROCESSING │ Drop 9 const cols → Normalize │ (2872,25)→(2872,96) │ → Delta → Rolling features └────────────┬────────────┘ │ ┌────────────▼────────────┐ │ 03 FEATURE ENG. │ ACF → window=41 │ Sequences (N,41,96) │ Sliding window, step=1 └────────────┬────────────┘ │ ┌────────────▼────────────┐ │ 04 MODEL DEV. │ LSTM Autoencoder │ Encoder→Latent→Decoder │ ~620K parameters └────────────┬────────────┘ │ ┌────────────▼────────────┐ │ 05 TRAINING │ 100 epochs · Best @ ep.98 │ val_loss: 0.004983 │ ReduceLROnPlateau └────────────┬────────────┘ │ ┌────────────▼────────────┐ │ 06 THRESHOLDING │ Dynamic EWM │ threshold = 0.01540 │ μ_ewm + 3σ_ewm └────────────┬────────────┘ │ ┌────────────▼────────────┐ │ 07 EVALUATION │ F1=0.095 · ROC-AUC=0.467 │ Confusion · ROC · PR │ PR-AUC=0.097 └─────────────────────────┘ ``` ## 📓 分阶段详解 ### 阶段 01 — 数据加载器 设置项目结构并提供可复用的数据访问函数: | 函数 | 用途 | |---|---| | `load_channel(channel_id)` | 加载训练/测试 `.npy` 数组,包含形状和 NaN 断言检查 | | `load_anomaly_labels(channel_id)` | 解析 `labeled_anomalies.csv` → `[start, end]` 区间列表 | | `build_label_array(intervals, n)` | 时间步级别的二进制真值数组 | | `build_window_label_array(intervals, n, w)` | 用于评估的窗口级别真值 | | `list_channels(spacecraft)` | 所有通道 ID,可选择按航天器筛选 | | `get_dataset_summary()` | 按航天器分组的汇总统计信息 | ### 阶段 02 — 预处理 严格的**无泄露 pipeline**——所有统计量仅从训练数据得出。 | 步骤 | 变换 | 训练集形状 | 测试集形状 | |---|---|---|---| | 原始输入 | — | (2872, 25) | (8505, 25) | | 删除常量列 | 移除 9 个零方差特征 (`std < 1e-6`) | (2872, 16) | (8505, 16) | | MinMax 归一化 | 缩放至 `[0, 1]` — **仅在训练集上拟合** | (2872, 16) | (8505, 16) | | Delta 特征 | 追加一阶差分 | (2872, 32) | (8505, 32) | | 滚动特征 | 追加 10 步滚动均值 + 标准差 | **(2872, 96)** | **(8505, 96)** | `Train min: 0.0 · Train max: 1.0` — 通过断言验证归一化。 **泄露防护:** 一个专门的单元格断言 `np.allclose(train_min, scaler.data_min_)` — 确认 Scaler 从未暴露于测试数据。 ✅ ![处理图像](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P1_preprocessing.png?raw=true) ### 阶段 03 — 特征工程 **通过 ACF 选择窗口大小:** 计算所有 96 个特征在滞后 1–100 时的自相关函数。窗口大小设置为任何特征的 ACF 首次进入 95% 置信带 `±1.96 / √n` 时的最大滞后值。 ![ACF — 窗口大小选择](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P1_acf.png?raw=true) **序列构建:** | 输出 | 形状 | 内存 | |---|---|---| | 训练序列 | **(2547, 41, 96)** | 76.5 MB | | 验证序列 | **(284, 41, 96)** | 8.5 MB | | 测试序列 | **(8464, 41, 96)** | 254.2 MB | 滑动窗口 `step=1` — 最大重叠以实现密集异常评分。**按时间顺序的 90/10 训练/验证划分**(无打乱)保留了时间顺序。 ![序列样本](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P1_sequence_sample.png?raw=true) **5 点完整性检查 — 全部通过:** | 检查 | 结果 | |---|---| | 第一个窗口与原始数据匹配 | ✅ 通过 | | 训练集 / 验证集无重叠 | ✅ 通过 | | 任何划分中均无 NaN | ✅ 通过 | | 所有数组均为 3D | ✅ 通过 | | 测试窗口与原始测试数据匹配 | ✅ 通过 | ### 阶段 04 — 模型开发(见下方 [LSTM Autoencoder 架构](#-lstm-autoencoder-architecture)) ### 阶段 05 — 训练 | 参数 | 值 | |---|---| | 损失函数 | 均方误差 (MSE) | | 优化器 | Adam | | 初始学习率 | 1e-3 | | Batch size | 64 | | 最大 Epochs | 100 | | 早停 | patience=10, 恢复最佳权重 | | 学习率衰减 | ReduceLROnPlateau — factor=0.5, patience=5, min_lr=1e-6 | | 指标 | 值 | |---|---| | 最佳 Epoch | **98** | | 最佳 val_loss | **0.004983** | | 最终 train_loss | **0.002249** | | 收敛时的学习率 | ~1.95e-6 (从初始值减少了 9×) | 模型训练了完整的 100 个 Epochs 且持续改进。学习率被 `ReduceLROnPlateau` 降低了 9 次,表明优化器逐步细化了极小值。训练/验证损失差距稳定且较小——没有明显的过拟合。从约第 75 个 Epoch 开始,两者损失均平滑趋于平稳。 ## 🧠 LSTM Autoencoder 架构 ``` ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ INPUT (batch, 41 timesteps, 96 features) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ENCODER LSTM(128, tanh, return_sequences=True) Dropout(0.2) LSTM(64, tanh, return_sequences=True) Dropout(0.2) LSTM(32, tanh, return_sequences=False) ← bottleneck ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BRIDGE RepeatVector(41) ← expand latent → sequence ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DECODER LSTM(32, tanh, return_sequences=True) Dropout(0.2) LSTM(64, tanh, return_sequences=True) Dropout(0.2) LSTM(128, tanh, return_sequences=True) TimeDistributed(Dense(96)) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ OUTPUT (batch, 41 timesteps, 96 features) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Total parameters: ~620,000 Output shape == Input shape ✅ verified ``` **评估了三种配置:** | 配置 | 潜在维度 | Dropout | 参数量 | 选中 | |---|---|---|---|---| | Small | 16 | 0.1 | ~350K | | | **Medium** | **32** | **0.2** | **~620K** | ✅ | | Large | 64 | 0.3 | ~1.1M | | 对于 2,547 个样本的训练集,选择 Medium 配置作为表达能力与过拟合风险之间的最佳权衡。 ## 🎯 阈值检测 每个窗口的异常分数 = 输入与重构之间在所有时间步和特征上的**均方误差**。 在训练误差分布上比较了两种策略: | 方法 | 公式 | 阈值 | |---|---|---| | 百分位数 (第 99) | `np.percentile(train_errors, 99)` | ~0.01430 | | **动态 EWM** ✅ | `μ_ewm + 3σ_ewm` (span=10) | **0.01540** | 选择动态 EWM —— 对任务生命周期内的非平稳性和缓慢信号漂移具有更强的鲁棒性。 ![重构误差分布](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P-1_error_dist.png?raw=true) ## 📊 结果 ### 评估指标 — 通道 P-1 | 指标 | 值 | |---|---| | **Precision** | 0.149 | | **Recall** | 0.070 | | **F1 Score** | 0.095 | | **ROC-AUC** | 0.467 | | **PR-AUC** | 0.097 | ### 混淆矩阵 ![混淆矩阵](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P-1_cm.png?raw=true) | | 预测为 Normal | 预测为 Anomaly | |---|---|---| | **实际 Normal** | 7,318 (TN) | 326 (FP) | | **实际 Anomaly** | 763 (FN) | 57 (TP) | ### ROC 曲线 ![ROC 曲线 — AUC=0.467](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P-1_roc.png?raw=true) ### Precision-Recall 曲线 ![Precision-Recall 曲线 — AP=0.097](https://github.com/Monisha325/Spacecraft-Telemetry-Anomaly-Detection-using-LSTM-Autoencoders/blob/main/results/plots/P-1_pr_curve.png?raw=true) ## 🔎 讨论与局限性 ### 实事求是的评估 通道 P-1 上的结果表明,模型**未能成功学习区分该特定通道上的异常窗口与正常窗口**。0.467 的 ROC-AUC 略低于随机概率,7% 的 Recall 意味着 820 个异常窗口中有 763 个被遗漏。理解发生这种情况的具体原因与获得高性能结果同样有价值。 ### 根本原因分析 **1. 异常类型与基于重构的检测不匹配。** 观察数据可视化,P-1 的异常属于**抑制型**——在异常期间信号变得更安静并失去方差。在嘈杂、高振幅正常数据上训练的 Autoencoder 重构这些更安静的异常窗口*更容易*,产生更低的重构误差——这直接颠覆了检测假设。基于重构的方法非常适合尖峰/偏差异常,但在方差抑制异常上表现不佳。 **2. 序列重塑的副作用。** 在阶段 05 中,序列需要 `expand_dims + repeat` 以匹配模型预期的输入形状。这引入了模型可能围绕其优化的人为时间重复,从而降低了对真实时间模式的敏感度。 **3. 模型收敛,但收敛于低 MSE。** 最终训练 MSE 为 `0.002249`,反映出一个能很好地重构几乎所有内容的模型——这导致正常类和异常类之间的重构误差差距缩小到检测阈值以下。 **4. 阈值选择时的类别不平衡。** 动态阈值完全来自训练误差统计,没有来自异常类的反馈。在严重不平衡的测试集上,这种启发式方法产生的阈值位置并非 F1 的最优解。 ### 为什么 PR-AUC 是此处的正确指标 P-1 在总共 8,464 个窗口中有约 820 个异常窗口(约 9.7% 的异常率)。在这种不平衡下,一个将所有内容预测为“正常”的模型可以实现 ROC-AUC ≈ 0.5,这使得 ROC-AUC 成为模型质量的糟糕鉴别器。当模型失败时,PR-AUC 会向基准率(~0.097)坍缩——这正是观察到的情况,证实两个指标都是自洽的,且在此通道上尚未超越基线。 ### 提议的改进 | 改进 | 目标 | |---|---| | **基于预测的 LSTM** — 预测下一个时间步;分数 = 预测误差 | 直接对方差抑制异常敏感 | | **感知方差的异常分数** — 惩罚预测方差超过实际方差的窗口 | 专为抑制型异常设计 | | **半监督阈值调整** — 在小的留出标记集上 | 直接优化 F1,而非使用统计启发式方法 | | **Isolation Forest / One-Class SVM** (在潜在向量上) | 在压缩空间中学习更紧密的正常边界 | | **多通道评估** — 在 M-1, D-14, P-15 等上 | P-1 被记录为困难通道;Pipeline 级别的指标能提供更公平的图景 | | **对比学习或基于能量的训练** | 显式地将异常重构推向更高的误差 | ## ⚙️ 环境配置与安装 **要求:** Python 3.8+ · Google Colab (推荐) · Google Drive ``` pip install -r requirements.txt ``` **数据集下载**(在 `01_data_loader.ipynb` 中自动处理): ``` pip install kagglehub ``` ## 🚀 用法 在 Google Colab 中按顺序运行 notebook: ``` 01_data_loader.ipynb Download & structure dataset (82 channels) 02_preprocessing.ipynb Clean, normalize & engineer features 03_feature_engineering.ipynb ACF window selection + sliding sequences 04_model_development.ipynb Define LSTM Autoencoder (~620K params) 05_training.ipynb Train · best epoch 98 · val_loss 0.004983 06_threshold_detection.ipynb Score windows · threshold = 0.01540 07_evaluation.ipynb Metrics · confusion matrix · ROC · PR curve ``` 要在不同的通道上运行: ``` channel_id = "M-1" # change at the top of each notebook ``` ## 📁 项目结构 ``` rocket_telemetry_project/ │ ├── data/ │ ├── train/ # 82 raw .npy train channel files │ ├── test/ # 82 raw .npy test channel files │ ├── labeled_anomalies.csv # Ground truth anomaly intervals │ ├── processed/ │ │ ├── P-1_train.npy # (2872, 96) — after full preprocessing │ │ └── P-1_test.npy # (8505, 96) │ └── sequences/ │ ├── P-1_train_seq.npy # (2547, 41, 96) │ ├── P-1_val_seq.npy # (284, 41, 96) │ └── P-1_test_seq.npy # (8464, 41, 96) │ ├── models/ │ ├── architecture_P1.json # Model architecture (JSON) │ ├── lstm_ae_P-1.h5 # Best model weights (epoch 98) │ └── scaler_P-1.pkl # MinMaxScaler (train-only fit) │ ├── results/ │ ├── plots/ │ │ ├── P1_data_check.png # Test signal + anomaly regions │ │ ├── P1_preprocessing.png # Raw → normalized → delta │ │ ├── P1_acf.png # ACF for window size selection │ │ ├── P1_sequence_sample.png # Window + feature heatmap │ │ ├── P-1_training_curves.png # Loss + LR decay over 100 epochs │ │ ├── P-1_error_dist.png # Reconstruction error distribution │ │ ├── P-1_roc.png # ROC curve (AUC=0.467) │ │ ├── P-1_pr_curve.png # PR curve (AP=0.097) │ │ └── P-1_cm.png # Confusion matrix (F1=0.095) │ └── metrics/ │ ├── P-1_history.json # Loss per epoch (100 epochs) │ ├── P-1_threshold.json # Threshold=0.01540, method=dynamic │ └── P-1_eval.json # TP=57, FP=326, TN=7318, FN=763 │ ├── src/ │ ├── __init__.py │ └── data_loader.py # Reusable channel loading module │ ├── notebooks/ # 7 ordered Colab notebooks ├── requirements.txt └── README.md ``` ## 🔍 关键设计决策 | 决策 | 理由 | |---|---| | **无监督 Autoencoder** | 不需要异常标签——仅在正常数据上训练,反映了实际任务约束 | | **Scaler 仅在训练集上拟合** | 严格的无泄露保证——通过断言验证,而非假设 | | **使用 ACF 确定窗口大小** | 数据驱动的选择——捕获每个通道的实际时间依赖长度 | | **按时间顺序的验证划分** | 打乱会泄露未来上下文——对于时间序列评估是禁止的 | | **Delta + 滚动特征增强** | 除了原始值外,还向模型暴露变化率和局部波动性 | | **MSE 重构损失** | 惩罚偏离正常模式的大偏差;对结构性异常值敏感 | | **动态 EWM 阈值** | 适应信号的非平稳性;比任务生命周期内的固定百分位数更鲁棒 | | **PR-AUC 作为主要指标** | 在严重类别不平衡下的正确选择——当异常稀少时 ROC-AUC 具有误导性 | ## 📚 参考资料 1. Hundman, K., et al. (2018). **Detecting Spacecraft Anomalies Using LSTMs and Nonparametric Dynamic Thresholding.** *KDD 2018.* [arXiv:1802.04893](https://arxiv.org/abs/1802.04893) 2. Malhotra, P., et al. (2016). **LSTM-based Encoder-Decoder for Multi-sensor Anomaly Detection.** *ICML Anomaly Detection Workshop.* 3. Hochreiter, S. & Schmidhuber, J. (1997). **Long Short-Term Memory.** *Neural Computation, 9(8),* 1735–1780. 4. NASA SMAP/MSL 异常数据集 — [Kaggle](https://www.kaggle.com/datasets/patrickfleith/nasa-anomaly-detection-dataset-smap-msl) ## 👨‍💻 关于本项目 **作者** Patnana Monisha **领域:** Deep Learning · Time Series · Anomaly Detection · Spacecraft Health Monitoring **数据集:** NASA SMAP & MSL — 82 个遥测通道,真实任务数据 *TensorFlow/Keras · Scikit-learn · NumPy · Pandas · Matplotlib · Seaborn · KaggleHub*
标签:ACF分析, Apex, BSD, ISRO, Keras, LSTM自编码器, NASA MSL, NASA SMAP, Python, TensorFlow, 信号预处理, 动态阈值, 太空技术, 异常检测, 故障预测, 数据处理管道, 数据挖掘, 无后门, 无监督学习, 时间序列分析, 机器学习, 深度学习, 航天器遥测, 逆向工具