【自动编码器3 异常检测 全python代码】Autoencoder Anomaly Detection

1. 自动编码器简介

自动编码器是一种特殊类型的神经网络,经过训练后可将其输入复制到输出。例如,给定一张手写数字图像,自动编码器首先将该图像编码为较低维度的潜在表示,然后将潜在表示解码回图像。自动编码器学习压缩数据,同时最小化重构误差。
书接上回 【自动编码器2 图像去噪 全python代码】,自动编码器的训练目的是最小化重构误差。您将仅在正常节律上训练自动编码器,然后使用它来重构所有数据。我们的假设是,异常节律将具有更高的重构误差。然后,如果重构误差超过固定阈值,您将把节律归类为异常。

2. Python 实现

在此示例中,您将训练自动编码器来检测ECG5000 数据集上的异常。此数据集包含 5,000 个心电图,每个心电图有 140 个数据点。您将使用数据集的简化版本,其中每个示例都已标记为0(对应于异常节律)或1(对应于正常节律)。您感兴趣的是识别异常节律。

原数据集下载地址 ECG5000数据集下载
这个实例用的数据集是一个csv文件:心电图数据

注意:这是一个带标签的数据集,因此您可以将其描述为监督学习问题。此示例的目的是说明异常检测概念可以应用于较大的数据集,在这些数据集中您没有可用的标签(例如,如果您有数千个正常节律,但只有少量异常节律)。
您将如何使用自动编码器检测异常?回想一下,自动编码器的训练目的是最小化重构误差。您将仅在正常节律上训练自动编码器,然后使用它来重构所有数据。我们的假设是,异常节律将具有更高的重构误差。然后,如果重构误差超过固定阈值,您将把节律归类为异常。

2.1 导入 TensorFlow 和其他库

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf

from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.model_selection import train_test_split
from tensorflow.keras import layers, losses
from tensorflow.keras.datasets import fashion_mnist
from tensorflow.keras.models import Model

2.2 加载心电图数据

# Download the dataset
dataframe = pd.read_csv('http://storage.googleapis.com/download.tensorflow.org/data/ecg.csv', header=None)
raw_data = dataframe.values
dataframe.head()
# The last element contains the labels
labels = raw_data[:, -1]

# The other data points are the electrocadriogram data
data = raw_data[:, 0:-1]

train_data, test_data, train_labels, test_labels = train_test_split(
    data, labels, test_size=0.2, random_state=21
)

2.3 数据预处理

  1. 将数据标准化为[0,1]。
min_val = tf.reduce_min(train_data)
max_val = tf.reduce_max(train_data)

train_data = (train_data - min_val) / (max_val - min_val)
test_data = (test_data - min_val) / (max_val - min_val)

train_data = tf.cast(train_data, tf.float32)
test_data = tf.cast(test_data, tf.float32)
  1. 你将仅使用正常节奏来训练自动编码器,这些正常节奏在此数据集中标记为1。将正常节奏与异常节奏分开。
train_labels = train_labels.astype(bool)
test_labels = test_labels.astype(bool)

normal_train_data = train_data[train_labels]
normal_test_data = test_data[test_labels]

anomalous_train_data = train_data[~train_labels]
anomalous_test_data = test_data[~test_labels]
  1. 绘制正常心电图
plt.grid()
plt.plot(np.arange(140), normal_train_data[0])
plt.title("A Normal ECG")
plt.show()

在这里插入图片描述

  1. 绘制异常心电图
plt.grid()
plt.plot(np.arange(140), anomalous_train_data[0])
plt.title("An Anomalous ECG")
plt.show()

在这里插入图片描述

2.4 自动编码器模型

  1. 构建模型
class AnomalyDetector(Model):
  def __init__(self):
    super(AnomalyDetector, self).__init__()
    self.encoder = tf.keras.Sequential([
      layers.Dense(32, activation="relu"),
      layers.Dense(16, activation="relu"),
      layers.Dense(8, activation="relu")])

    self.decoder = tf.keras.Sequential([
      layers.Dense(16, activation="relu"),
      layers.Dense(32, activation="relu"),
      layers.Dense(140, activation="sigmoid")])

  def call(self, x):
    encoded = self.encoder(x)
    decoded = self.decoder(encoded)
    return decoded

autoencoder = AnomalyDetector()
autoencoder.compile(optimizer='adam', loss='mae')

自动编码器仅使用正常 ECG 进行训练,但使用完整测试集进行评估。

history = autoencoder.fit(normal_train_data, normal_train_data,
          epochs=20,
          batch_size=512,
          validation_data=(test_data, test_data),
          shuffle=True)
plt.plot(history.history["loss"], label="Training Loss")
plt.plot(history.history["val_loss"], label="Validation Loss")
plt.legend()

在这里插入图片描述
如果重建误差与正常训练示例相比大于一个标准差,您很快就会将心电图归类为异常。

  1. 绘制训练集中的正常心电图、自动编码器编码和解码后的重建图以及重建误差。
encoded_data = autoencoder.encoder(normal_test_data).numpy()
decoded_data = autoencoder.decoder(encoded_data).numpy()

plt.plot(normal_test_data[0], 'b')
plt.plot(decoded_data[0], 'r')
plt.fill_between(np.arange(140), decoded_data[0], normal_test_data[0], color='lightcoral')
plt.legend(labels=["Input", "Reconstruction", "Error"])
plt.show()

在这里插入图片描述

  1. 创建一个类似的图,这次针对异常测试示例。
encoded_data = autoencoder.encoder(anomalous_test_data).numpy()
decoded_data = autoencoder.decoder(encoded_data).numpy()

plt.plot(anomalous_test_data[0], 'b')
plt.plot(decoded_data[0], 'r')
plt.fill_between(np.arange(140), decoded_data[0], anomalous_test_data[0], color='lightcoral')
plt.legend(labels=["Input", "Reconstruction", "Error"])
plt.show()

在这里插入图片描述

2.5 异常检测

通过计算重建损失是否大于固定阈值来检测异常。在本教程中,您将计算训练集中正常示例的平均误差,然后如果重建误差高于训练集的一个标准差,则将未来的示例归类为异常。

  1. 绘制训练集中正常心电图的重建误差
reconstructions = autoencoder.predict(normal_train_data)
train_loss = tf.keras.losses.mae(reconstructions, normal_train_data)

plt.hist(train_loss[None,:], bins=50)
plt.xlabel("Train loss")
plt.ylabel("No of examples")
plt.show()

在这里插入图片描述

  1. 选择一个高于平均值一个标准差的阈值。

注意:您还可以使用其他策略来选择阈值,超过该阈值的测试示例应被归类为异常,正确的方法取决于您的数据集。您可以通过本教程末尾的链接了解更多信息。

threshold = np.mean(train_loss) + np.std(train_loss)
print("Threshold: ", threshold)

Threshold: 0.032343477

如果您检查测试集中异常示例的重构误差,您会注意到大多数示例的重构误差都大于阈值。通过改变阈值,您可以调整分类器的精度和召回率。

reconstructions = autoencoder.predict(anomalous_test_data)
test_loss = tf.keras.losses.mae(reconstructions, anomalous_test_data)

plt.hist(test_loss[None, :], bins=50)
plt.xlabel("Test loss")
plt.ylabel("No of examples")
plt.show()

在这里插入图片描述

  1. 如果重建误差大于阈值,则将心电图归类为异常。
def predict(model, data, threshold):
  reconstructions = model(data)
  loss = tf.keras.losses.mae(reconstructions, data)
  return tf.math.less(loss, threshold)

def print_stats(predictions, labels):
  print("Accuracy = {}".format(accuracy_score(labels, predictions)))
  print("Precision = {}".format(precision_score(labels, predictions)))
  print("Recall = {}".format(recall_score(labels, predictions)))
preds = predict(autoencoder, test_data, threshold)
print_stats(preds, test_labels)

Accuracy = 0.944
Precision = 0.9921875
Recall = 0.9071428571428571

3. Reference

[1] https://www.tensorflow.org/tutorials/generative/autoencoder
[2] https://www.deeplearningbook.org

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值