第45课:TensorFlow|异常检测实战【工业设备数据故障识别模型搭建】

文章目录

    • [1. 课前导读](#1. 课前导读)
      • [1.1 本节课学习目标](#1.1 本节课学习目标)
      • [1.2 知识重难点](#1.2 知识重难点)
      • [1.3 学习前置条件](#1.3 学习前置条件)
      • [1.4 学完可掌握能力](#1.4 学完可掌握能力)
      • [1.5 行业应用场景](#1.5 行业应用场景)
    • [2. 核心理论精讲](#2. 核心理论精讲)
      • [2.1 异常检测问题定义](#2.1 异常检测问题定义)
      • [2.2 统计方法](#2.2 统计方法)
      • [2.3 孤立森林(Isolation Forest)](#2.3 孤立森林(Isolation Forest))
      • [2.4 自编码器重构误差](#2.4 自编码器重构误差)
      • [2.5 LSTM预测误差方法](#2.5 LSTM预测误差方法)
      • [2.6 阈值选择](#2.6 阈值选择)
      • [2.7 评估指标(不平衡数据)](#2.7 评估指标(不平衡数据))
    • [3. 环境搭建与工具配置](#3. 环境搭建与工具配置)
    • [4. 代码实战教学](#4. 代码实战教学)
      • [4.1 生成模拟工业传感器数据](#4.1 生成模拟工业传感器数据)
      • [4.2 自编码器模型构建](#4.2 自编码器模型构建)
      • [4.3 计算重构误差并选择阈值](#4.3 计算重构误差并选择阈值)
      • [4.4 基于LSTM的时序预测误差方法](#4.4 基于LSTM的时序预测误差方法)
      • [4.5 孤立森林对比](#4.5 孤立森林对比)
      • [4.6 结果可视化](#4.6 结果可视化)
    • [5. 案例实操演练](#5. 案例实操演练)
      • [5.1 下载与加载数据](#5.1 下载与加载数据)
      • [5.2 特征工程](#5.2 特征工程)
      • [5.3 训练自编码器](#5.3 训练自编码器)
      • [5.4 结果分析](#5.4 结果分析)
    • [6. 常见坑点与排错总结](#6. 常见坑点与排错总结)
      • [6.1 数据预处理坑点](#6.1 数据预处理坑点)
      • [6.2 自编码器训练坑点](#6.2 自编码器训练坑点)
      • [6.3 LSTM预测方法坑点](#6.3 LSTM预测方法坑点)
      • [6.4 评估坑点](#6.4 评估坑点)
    • [7. 知识点总结 + 课后作业](#7. 知识点总结 + 课后作业)
      • [7.1 核心知识点梳理](#7.1 核心知识点梳理)
      • [7.2 基础作业](#7.2 基础作业)
      • [7.3 进阶实操作业](#7.3 进阶实操作业)
      • [7.4 思考拓展题](#7.4 思考拓展题)
  • [🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航](#🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航)

1. 课前导读

1.1 本节课学习目标

  • 理解异常检测的任务类型:点异常、上下文异常、集合异常,以及无监督/监督/半监督的区别。
  • 掌握基于统计的方法(Z-score、IQR)及其局限性。
  • 掌握孤立森林(Isolation Forest)的原理及其在异常检测中的应用。
  • 深入理解基于自编码器(Autoencoder)的重构误差异常检测方法,能够使用TensorFlow搭建。
  • 掌握基于LSTM的时序预测误差方法,用于传感器时间序列异常检测。
  • 学会确定异常阈值(百分位数、KDE、3σ)。
  • 能够评估异常检测模型(混淆矩阵、F1、AUC),并处理类别不平衡。
  • 完成工业设备故障识别的完整实战项目。

1.2 知识重难点

类别 内容
重点 自编码器重构误差的计算与阈值选择;LSTM预测误差方法;评估指标在不平衡数据下的含义
难点 异常阈值选择的统计学原理;自编码器对正常模式的学习能力与过拟合控制;时序数据的滑动窗口构造
易混淆点 重构误差 vs 预测误差;无监督与半监督异常检测的标签使用(半监督使用少量标注异常);异常得分与二值化阈值的确定

1.3 学习前置条件

  • 已掌握TensorFlow基础,能够搭建全连接网络和LSTM(第15、26课)。
  • 了解无监督学习基本概念。
  • 具备一定的统计学知识(均值、方差、分位数)。

1.4 学完可掌握能力

  • 独立构建基于自编码器的异常检测系统,用于非时序数据。
  • 构建基于LSTM的时序异常检测模型,用于传感器数据。
  • 处理不平衡数据下的模型评估。
  • 将模型部署为实时API或批处理任务。

1.5 行业应用场景

  • 设备预测性维护:提前发现轴承、电机异常。
  • 金融反欺诈:识别异常交易。
  • 网络安全:检测入侵行为。
  • 产品质量检测:识别缺陷产品。

2. 核心理论精讲

2.1 异常检测问题定义

异常是指与其他数据分布显著不同的样本。异常检测的目标是识别这些少数样本。根据标签可用性分为:

  • 无监督异常检测:训练集无标签,假设异常样本极少且与正常样本分布不同。
  • 监督异常检测:有标注的正常和异常样本,但类别极不平衡。
  • 半监督异常检测:训练集仅包含正常样本,学习正常模式,测试时检测偏离的样本。

工业场景通常为半监督:我们有大量正常设备运行数据,故障数据稀缺。因此本课重点采用半监督方法。

2.2 统计方法

Z-score:假设特征服从正态分布,计算样本偏离均值的标准差倍数,超过阈值(如3)视为异常。但实际工业数据往往不满足正态分布。

IQR(四分位距):异常值定义为小于 Q1 - 1.5×IQR 或大于 Q3 + 1.5×IQR。适用于单变量。

局限性:无法处理复杂高维相关性。

2.3 孤立森林(Isolation Forest)

通过随机选择特征和切分值递归划分数据,异常点更容易被孤立(路径长度短)。集成模型,对高维数据有效,且无需假设数据分布。可用sklearn实现。

2.4 自编码器重构误差

自编码器(Autoencoder)是一种无监督神经网络,由编码器和解码器组成,训练目标是重构输入(输入=输出)。如果仅用正常数据训练,自编码器将学习到正常模式的重构。当输入异常样本时,重构误差(如MSE)会显著增大。因此,重构误差可作为异常分数。

训练 :最小化正常样本的重构损失。

推断:计算每个样本的重构误差,若超过阈值则判定为异常。

网络结构:可以是对称的全连接网络或卷积网络(图像)、LSTM(时序)。

2.5 LSTM预测误差方法

对于时序数据,可以用LSTM预测下一个时间步的值,然后计算预测值与真实值的误差。同样,模型只在正常数据上训练,异常数据会导致预测误差增大。

滑动窗口:使用过去L个时间步预测未来h步(通常h=1)。将预测误差(如绝对值)作为异常分数。

2.6 阈值选择

异常分数阈值决定分类边界。常用方法:

  • 百分位数法:选定一个百分位数p(如99%),将训练集正常数据的重构误差第p百分位数作为阈值。
  • 3σ原则:假设误差服从正态分布,阈值 = 均值 + 3×标准差。
  • KDE(核密度估计):拟合误差分布,取概率密度低点。
  • 基于验证集的优化:如果有一小部分标注异常,可在验证集上最大化F1选择阈值。

2.7 评估指标(不平衡数据)

由于异常样本极少,准确率可能虚高(如全预测正常也有99%准确率)。应使用:

  • 精确率(Precision):预测为异常中真正异常的比例。
  • 召回率(Recall):真正异常中被检出的比例。
  • F1分数:调和平均。
  • ROC-AUC:不受阈值影响,评估排序能力。
  • PR-AUC:对不平衡数据更敏感。

3. 环境搭建与工具配置

沿用第44课环境,安装scikit-learn(已安装),以及数据处理库。

bash 复制代码
conda activate tf213
pip install scikit-learn pandas matplotlib

准备模拟工业数据集(或使用真实数据集如CWRU、NAB)。这里生成模拟传感器数据。

项目结构:

复制代码
anomaly_detection/
    ├── data/
    ├── models/
    ├── train_autoencoder.py
    ├── train_lstm.py
    └── evaluate.py

导入:

python 复制代码
import tensorflow as tf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, roc_auc_score, confusion_matrix
from tensorflow.keras import layers, models, callbacks
import random

4. 代码实战教学

4.1 生成模拟工业传感器数据

生成正常数据和异常数据。正常数据:多变量时间序列,具有周期性模式。异常数据:在某些时间点出现大幅偏离。

python 复制代码
def generate_normal_data(n_samples=10000, n_features=4, noise=0.1):
    t = np.linspace(0, 100, n_samples)
    data = np.zeros((n_samples, n_features))
    for i in range(n_features):
        # 正弦波 + 趋势
        data[:, i] = 2 * np.sin(0.2 * t + i) + 0.01 * t + noise * np.random.randn(n_samples)
    return data

def generate_anomaly_data(normal_data, anomaly_ratio=0.05, magnitude=5):
    n_samples = normal_data.shape[0]
    n_anomaly = int(n_samples * anomaly_ratio)
    anomaly_indices = np.random.choice(n_samples, n_anomaly, replace=False)
    data = normal_data.copy()
    for idx in anomaly_indices:
        # 对随机特征添加偏移
        feat = np.random.randint(0, data.shape[1])
        data[idx, feat] += magnitude * np.random.randn() * data.std(axis=0)[feat]
    return data, anomaly_indices

normal = generate_normal_data(10000, 4)
data, anomaly_idx = generate_anomaly_data(normal, anomaly_ratio=0.05)
labels = np.zeros(len(data))
labels[anomaly_idx] = 1

# 划分训练集(仅正常),测试集(含异常)
train_data = normal[:8000]  # 仅正常样本
test_data = data[8000:]
test_labels = labels[8000:]
print(f"Train normal samples: {train_data.shape[0]}, Test samples: {test_data.shape[0]}, anomalies: {test_labels.sum()}")

4.2 自编码器模型构建

python 复制代码
def build_autoencoder(input_dim, encoding_dim=32):
    input_layer = layers.Input(shape=(input_dim,))
    # 编码器
    encoded = layers.Dense(64, activation='relu')(input_layer)
    encoded = layers.Dense(encoding_dim, activation='relu')(encoded)
    # 解码器
    decoded = layers.Dense(64, activation='relu')(encoded)
    decoded = layers.Dense(input_dim, activation='linear')(decoded)
    autoencoder = models.Model(input_layer, decoded)
    autoencoder.compile(optimizer='adam', loss='mse')
    return autoencoder

input_dim = train_data.shape[1]
autoencoder = build_autoencoder(input_dim, encoding_dim=8)
autoencoder.summary()

history = autoencoder.fit(train_data, train_data, epochs=50, batch_size=128, 
                          validation_split=0.1, verbose=1, callbacks=[callbacks.EarlyStopping(patience=5)])

4.3 计算重构误差并选择阈值

python 复制代码
# 在训练集上计算重构误差(用于确定阈值)
train_reconst = autoencoder.predict(train_data)
train_mse = np.mean(np.square(train_data - train_reconst), axis=1)
# 选择99%分位数作为阈值
threshold = np.percentile(train_mse, 99)
print(f"Threshold (99th percentile): {threshold:.4f}")

# 测试集上评估
test_reconst = autoencoder.predict(test_data)
test_mse = np.mean(np.square(test_data - test_reconst), axis=1)
test_pred = (test_mse > threshold).astype(int)

print(classification_report(test_labels, test_pred, target_names=['Normal', 'Anomaly']))
print("AUC:", roc_auc_score(test_labels, test_mse))

4.4 基于LSTM的时序预测误差方法

对于时间序列,构造滑动窗口。

python 复制代码
def create_sequences(data, window_size=50, pred_len=1):
    X, y = [], []
    for i in range(len(data) - window_size - pred_len + 1):
        X.append(data[i:i+window_size])
        y.append(data[i+window_size:i+window_size+pred_len])
    return np.array(X), np.array(y)

window = 50
# 将正常数据转换为序列
X_train_seq, y_train_seq = create_sequences(normal, window, 1)
# 训练LSTM预测模型
def build_lstm_predictor(input_shape, lstm_units=64):
    model = models.Sequential([
        layers.LSTM(lstm_units, activation='relu', input_shape=input_shape, return_sequences=False),
        layers.Dense(input_shape[-1])
    ])
    model.compile(optimizer='adam', loss='mse')
    return model

lstm_model = build_lstm_predictor((window, normal.shape[1]))
lstm_model.summary()
lstm_model.fit(X_train_seq, y_train_seq, epochs=30, batch_size=64, validation_split=0.1, verbose=1)

# 在测试集上计算预测误差
X_test_seq, y_test_seq = create_sequences(test_data, window, 1)
pred_test = lstm_model.predict(X_test_seq)
test_errors = np.mean(np.square(pred_test - y_test_seq), axis=(1,2))  # 每个样本的MSE
# 阈值同样取训练集误差的99分位数
train_seq_pred = lstm_model.predict(X_train_seq)
train_errors = np.mean(np.square(train_seq_pred - y_train_seq), axis=(1,2))
thresh_lstm = np.percentile(train_errors, 99)
test_pred_lstm = (test_errors > thresh_lstm).astype(int)

# 注意:序列方式预测得到的标签需要对齐原始测试集的标签(略去前window个点)
test_labels_aligned = test_labels[window+1:]  # 因为create_sequences会截掉末尾
print(classification_report(test_labels_aligned, test_pred_lstm, target_names=['Normal', 'Anomaly']))

4.5 孤立森林对比

python 复制代码
from sklearn.ensemble import IsolationForest
iso_forest = IsolationForest(contamination=0.05, random_state=42)
iso_forest.fit(train_data)  # 训练时使用正常数据?注意IsolationForest是无监督,可混合异常但比例低,这里仅用正常
pred_iso = iso_forest.predict(test_data)
pred_iso = (pred_iso == -1).astype(int)
print(classification_report(test_labels, pred_iso))

4.6 结果可视化

python 复制代码
plt.figure(figsize=(12,4))
plt.subplot(1,2,1)
plt.plot(test_mse, label='Reconstruction error (AE)')
plt.axhline(threshold, color='r', linestyle='--', label='Threshold')
plt.xlabel('Sample')
plt.ylabel('MSE')
plt.legend()
plt.title('Autoencoder Anomaly Scores')

plt.subplot(1,2,2)
plt.plot(test_errors, label='Prediction error (LSTM)')
plt.axhline(thresh_lstm, color='r', linestyle='--', label='Threshold')
plt.xlabel('Sample')
plt.ylabel('MSE')
plt.legend()
plt.title('LSTM Prediction Error')
plt.show()

5. 案例实操演练

案例:使用CWRU轴承数据集进行故障检测

5.1 下载与加载数据

CWRU数据集包含正常轴承和故障轴承的振动信号。这里模拟其结构。

python 复制代码
# 假设已经下载了.mat文件,可以使用scipy.io.loadmat
# 为演示,我们继续使用模拟数据,但增加多尺度特征

5.2 特征工程

从原始振动信号提取统计特征:均值、方差、峰值、峰峰值、均方根、偏度、峭度等。将每个时间窗口转换为特征向量。

python 复制代码
def extract_features(window):
    features = []
    features.append(np.mean(window))
    features.append(np.std(window))
    features.append(np.max(window) - np.min(window))
    features.append(np.sqrt(np.mean(window**2)))
    # 更多特征...
    return np.array(features)

# 假设有原始信号列表,滑动窗口提取特征

5.3 训练自编码器

使用正常特征训练,在测试集上检测故障。

5.4 结果分析

输出混淆矩阵,并可视化故障样本的重构误差。

6. 常见坑点与排错总结

6.1 数据预处理坑点

  • 坑1:未对数据进行归一化,导致重构误差被量纲大的特征主导。

    • 解决 :使用StandardScalerMinMaxScaler
  • 坑2:时序数据构造滑动窗口时,应确保训练集和测试集的窗口不重叠(按时间顺序划分)。

6.2 自编码器训练坑点

  • 坑3:自编码器过于强大,能够完美重构异常(过拟合正常样本中的噪声)。

    • 解决:限制编码器维度(bottleneck),添加正则化(dropout、L2)。
  • 坑4:阈值选择过高导致漏报(召回率低),过低导致误报(精确率低)。

    • 解决:如果有一小部分异常标签,可使用验证集优化阈值。

6.3 LSTM预测方法坑点

  • 坑5:LSTM输入序列长度选择不当,过短无法捕捉周期,过长导致训练慢。

    • 经验:根据数据的周期长度选择(如振动信号一个周期点数)。
  • 坑6:预测误差的分布可能不服从正态分布,使用3σ可能不合适。

    • 替代:使用分位数或核密度估计。

6.4 评估坑点

  • 坑7:使用准确率评估不平衡数据,即使全预测正常也会很高。

    • 正确:查看精确率、召回率、F1、AUC。
  • 坑8:混淆矩阵中的"异常"类预测为正常的代价可能很高(漏报),需根据业务调整阈值。

7. 知识点总结 + 课后作业

7.1 核心知识点梳理

  • 异常检测类型:点异常、上下文异常;无监督/监督/半监督。
  • 方法:统计方法(Z-score、IQR)、孤立森林、自编码器重构误差、LSTM预测误差。
  • 阈值选择:百分位数、3σ、KDE、基于验证集优化。
  • 评估:精确率、召回率、F1、AUC(不平衡数据下重点使用)。

7.2 基础作业

  1. 使用自编码器对模拟的10维数据集进行异常检测,调整编码维度观察性能变化。
  2. 在工业传感器数据(如来自Kaggle的轴承数据集)上实现LSTM预测误差方法,并报告AUC。
  3. 比较孤立森林与自编码器在异常检测任务上的F1分数。

7.3 进阶实操作业

任务:基于自编码器集成或多尺度自编码器的异常检测

  • 构建多个不同架构的自编码器(如不同编码维度、不同层数),将它们的重构误差求平均作为异常分数。
  • 与单一自编码器对比性能。
  • 实现一种动态阈值方法(如移动平均)以适应概念漂移。

7.4 思考拓展题

  1. 如果异常数据与正常数据的分布有部分重叠,如何提高检测率同时降低误报?

  2. 在实时流式异常检测中,模型需要增量更新。如何设计在线自编码器更新策略?

  3. 除了重构误差,自编码器还可以利用隐层表示(潜在向量)的密度估计进行异常检测。请设计这样的方案并说明优缺点。


下一课预告:多输入多输出复杂模型设计------我们将学习如何构建具有多个输入(图像、文本、数值)和多个输出(分类、回归)的复杂模型,并处理异构数据。


🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航

去订阅

第一部分:基础入门(1-10 课)

第二部分:神经网络核心(11-25 课)

第三部分:进阶网络与框架高阶(26-40 课)

第四部分:企业实战与项目落地(41-50 课)
🌟 感谢您耐心阅读到这里!

💡 如果本文对您有所启发欢迎:

👍 点赞📌 收藏 📤 分享给更多需要的伙伴。

🗣️ 期待在评论区看到您的想法, 共同进步。

🔔 关注我,持续获取更多干货内容~

🤗 我们下篇文章见~

相关推荐
科技研学社1 小时前
一次性内裤全自动无人生产线选型测评:非标缝纫自动化落地踩坑与实践要点
人工智能
AI增长技术研究院1 小时前
不上传企业资料,能不能先检测品牌在AI中的公开表现?
人工智能
Htr_1 小时前
Anysite.io 使用指南:把整个 Web 变成 AI 智能体的数据库
前端·数据库·人工智能
数商云企1 小时前
2026年西安电商智能客服开发选数商云企,技术稳交付快
大数据·python
Htr_1 小时前
Raycast 2.0 使用指南:全新重构的 AI 启动器
人工智能·重构
zhikouai1 小时前
从闭环到现实:卡住AI的三道工程关
人工智能
天涯明月19931 小时前
Agent Sandbox 深度解析——给会动手的 AI 一个安全的房间
人工智能·安全·大模型·agent·sandbox
byte轻骑兵1 小时前
【AVDTP】规范精讲[13]: 吃透内容保护机制,打通蓝牙音视频版权加密全流程
人工智能·音视频·avrcp·蓝牙耳机·蓝牙音频