【深度學習系列(七)】:基於TensorFlow異常檢測的實現

Table of Contents

 

一、異常檢測

二、基於自動編碼器的異常檢測

三、異常檢測Tensorflow的實現

3.1、數據加載

3.2、搭建自編碼模型

3.3、模型訓練

3.4、模型預測


一、異常檢測

異常定義爲偏離標準,很少發生且不遵循其餘“模式”的事件。異常的例子包括:

  • 由於世界大事而導致的股市大跌
  • 工廠/傳送帶上的不良物品
  • 實驗室中被污染的樣品

假設我們的數據服從一個正太分佈,那麼通常異常數據位於正態分佈曲線的兩側。如下圖所示。

正如我們看到的那樣,這些事件將發生,但發生的可能性極低。從機器學習的角度來看,這使得很難檢測異常-根據定義,我們有很多“標準”事件的示例,而很少有“異常”事件的示例。因此,我們的數據集存在很大的偏差。當我們要檢測的異常可能僅在1%,0.1%或0.0001%的時間發生時,應該如何在平衡數據集中最佳地工作的機器學習算法如何工作?這時候我們就需要用到異常檢測來專門處理這類問題。

由於我們的數據集標籤存在極大的不平衡,根據定義異常數據很少發生,而我們擁有大量的正常數據。而爲了檢測異常數據,傳統的機器學習算法衍生出如孤立森林、One-class SVMs、Elliptic Envelopes和局部異常因子算法等。這裏不一一介紹,有興趣的同學可以去研究研究,這裏主要講的是如何使用深度學習來解決這個問題。

二、基於自動編碼器的異常檢測

自動編碼器是一種無監督的神經網絡,它可以:

  • 接受一組輸入數據;
  • 對數據進行編碼;
  • 將編碼後的特徵進行解碼來重建輸入數據。

通常自動編碼器主要有兩部分組成:編碼器和解碼器。編碼器接受輸入數據並將它轉化爲特徵表示。然後,解碼器嘗試對壓縮的特徵進行重構得到輸入數據。當我們以端到端的方式訓練自動編碼器時,該網絡能夠學習到一種強大的過濾器,其甚至能夠對輸入數據去噪。

從異常檢測角度來看,自動編碼器特別之處在於其能夠重構損失,在訓練自動編碼器時通常會衡量輸入和重構數據之間的均方誤差(MSE)。如果損失越小,那麼重構的圖像越像原始數據。

假設我們在整個MNIST數據集上訓練了一個自動編碼器,然後,對自動編碼器提供一個數字,並對他進行重構。我們希望我們能夠對其進行重建與輸入數據相似,然後我們會發現這兩張圖像之間的MSE比較低。

 如果,此時我們再提供一個非數字的圖像,如大象,此時這兩張圖片的MSE非常高。這是由於自動編碼器以前從未見過大象,更重要的是,從未接受過重建大象的訓練,因此 我們的MSE 很高。

此時,如果重建的MSE高,那麼我們可能會有一個異常值。

三、異常檢測Tensorflow的實現

3.1、數據加載

這裏我們使用mnist數據集,將標籤爲1的作爲正常數據,將標籤爲數據的數量1%的數量的且標籤爲3的數據作爲異常數據,並製作異常數據。具體如下:

  • 加載數據集
# 加載MNIST數據集
print("[INFO] loading MNIST dataset...")
((trainX,trainY),(testX,testY))=tf.keras.datasets.mnist.load_data()
  • 生成異常數據
def build_unsupervised_dataset(data,labels,validLabel=1,
	anomalyLabel=3, contam=0.01, seed=42):
    '''製作數據集'''

    # 抓取提供的類標籤的所有 * 真正 * 索引特定的標籤,
    # 然後獲取圖像的索引個標籤將成爲我們的“異常”
    validIdxs=np.where(labels==validLabel)[0]
    anomalyLabelIdx=np.where(labels==anomalyLabel)[0]

    #隨機打亂數據
    random.shuffle(validIdxs)
    random.shuffle(anomalyLabelIdx)

    #計算並設置異常數據的個數
    i=int(len(validIdxs)*contam)
    anomalyLabelIdx=anomalyLabelIdx[:i]

    #提取正常數據和異常數據
    validImages=data[validIdxs]
    anomalyImages=data[anomalyLabelIdx]

    #打包數據並進行數據打亂
    images=np.vstack([validImages,anomalyImages])

    return images


# 建立少量的無監督圖像數據集,污染(即異常)添加到其中
print("[INFO] creating unsupervised dataset...")
images = build_unsupervised_dataset(trainX, trainY, validLabel=1,
	anomalyLabel=3, contam=0.01)

3.2、搭建自編碼模型

這裏直接上代碼:

class ConvAutoencoder:
    @staticmethod
    def build(width,height,depth=None,filters=(32,64),latentDim=16):
        '''
        構建自動編碼器模型
        :param width: 圖像的寬度
        :param height: 圖像的高度
        :param depth: 圖像的深度
        :param filters: 卷積核的尺寸
        :param latentDim: 全連接的維數
        :return:
        '''
        #定義解碼器
        inputs=tf.keras.layers.Input(shape=(height,width,depth))

        x=inputs
        for filter in filters:
            x=tf.keras.layers.Conv2D(filter,kernel_size=(3,3),strides=2,padding='same')(x)
            x=tf.keras.layers.LeakyReLU(alpha=0.2)(x)
            x=tf.keras.layers.BatchNormalization(axis=-1)(x)

        volumeSize=tf.keras.backend.int_shape(x)
        x=tf.keras.layers.Flatten()(x)
        latent=tf.keras.layers.Dense(latentDim)(x)

        encoder=tf.keras.Model(inputs=inputs,outputs=latent,name='encoder')

        #定義編碼器
        latentinputs=tf.keras.layers.Input(shape=(latentDim,))

        x=tf.keras.layers.Dense(np.prod(volumeSize[1:]))(latentinputs)
        x=tf.keras.layers.Reshape((volumeSize[1],volumeSize[2],volumeSize[3]))(x)

        for filter in filters[::-1]:
            x=tf.keras.layers.Conv2DTranspose(filter,kernel_size=(3,3),strides=2,padding='same')(x)
            x=tf.keras.layers.LeakyReLU(alpha=0.2)(x)
            x=tf.keras.layers.BatchNormalization(axis=-1)(x)

        x=tf.keras.layers.Conv2DTranspose(depth,(3,3),padding='same')(x)
        outputs=tf.keras.layers.Activation('sigmoid')(x)

        decoder=tf.keras.Model(latentinputs,outputs,name='decoder')

        autoencoder=tf.keras.Model(inputs,decoder(encoder(inputs)),name='autoencoder')

        return (encoder,decoder,autoencoder)

autoencoder.summary()

網絡框架結構如下:

3.3、模型訓練

epochs=20
lr=1e-3
batch_size=32

#搭建模型
print("[INFO] building autoencoder...")
(encoder, decoder, autoencoder) = ConvAutoencoder.build(28, 28,1)

#搭建優化器
opt=tf.keras.optimizers.Adam(lr=lr,decay=lr/epochs)
autoencoder.compile(loss='mse',optimizer=opt,metrics=['acc'])

#訓練
H=autoencoder.fit(trainX,trainX,validation_data=(testX,testX),epochs=epochs,batch_size=batch_size)

訓練過程如下:

3.4、模型預測

 主要使用自編碼重構後的圖片與原圖片計算MSE,然後根據閾值進行相應的判斷,主要實現如下:

# 加載模型
print("[INFO] loading autoencoder and image data...")
autoencoder = tf.keras.models.load_model("autoencoder.h5")
images = pickle.loads(open("mages.pickle", "rb").read())

#預測圖片
images=images.reshape(-1,28,28,1)
images=images.astype('float32')
images/=255
decoded = autoencoder.predict(images)
errors = []

for (image, recon) in zip(images, decoded):
	# 計算預測和真實圖片之間的均方差1
	mse = np.mean((image - recon) ** 2)
	errors.append(mse)


# compute the q-th quantile of the errors which serves as our
# threshold to identify anomalies -- any data point that our model
# reconstructed with > threshold error will be marked as an outlier
thresh = np.quantile(errors, 0.999)
idxs = np.where(np.array(errors) >= thresh)[0]
print("[INFO] mse threshold: {}".format(thresh))
print("[INFO] {} outliers found".format(len(idxs)))

測試結果如下:

                                 

 

詳細代碼鏈接:https://github.com/kingqiuol/learning_tensorflow/tree/master/cv/Anomaly_detection

參考鏈接:

https://www.pyimagesearch.com/2020/03/02/anomaly-detection-with-keras-tensorflow-and-deep-learning/

基於Keras+CNN的MNIST數據集手寫數字分類

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章