AIOps探索:基於VAE模型的周期性KPI異常檢測方法

AIOps探索:基於VAE模型的周期性KPI異常檢測方法

來自專欄智能運維(AIOps)18 人贊了文章

作者:林錦進


前言

在智能運維領域中,由於缺少異常樣本,有監督方法的使用場景受限。因此,如何利用無監督方法對海量KPI進行異常檢測是我們在智能運維領域探索的方向之一。最近學習了清華裴丹團隊發表在WWW 2018會議上提出利用VAE模型進行周期性KPI無監督異常檢測的論文:《Unsupervised Anomaly Detection via Variational Auto-Encoder for Seasonal KPIs in Web Applications 》[1](以下簡稱為Dount)。基於Dount論文的學習,本文將介紹如何使用Keras庫,實現基於VAE模型的周期性KPI異常檢測方法,包括其思路、原理與代碼實現,幫助大家理解這個方法。


背景介紹:

在AI in All的時代,工業界中的運維領域提出了:智能運維(AIOps, Artificial Intelligence for IT Operations)這個概念,即採用機器學習、數據挖掘或深度學習等方法,來解決KPI異常檢測、故障根因分析、容量預測等運維領域中的關鍵問題。

其中KPI異常檢測是在運維領域中非常重要的一個環節。KPI(key performance indicators)指的是對服務、系統等運維對象的監控指標(如延遲、吞吐量等)。其存儲的形式是按其發生的時間先後順序排列而成的數列,也就是我們通常所說的時間序列。從運維的角度來看,存在多種不同類型的KPI,周期性KPI是其中一種典型的KPI,其特點表現為具有周期性,如下圖:

要進行KPI異常檢測,首先我們要定義一下什麼是異常。如上圖所示,我們將KPI的異常點定義為超過期望值一定範圍的點,而在期望值的小範圍內波動的點我們將其認為是雜訊。對周期性KPI的異常檢測在工業界和學術界已有不少探索,本文將介紹基於深度學習模型VAE的無監督周期性KPI異常檢測方法。


正文:

  • AutoEncoder

因為VAE跟AutoEncoder在網路整體結構上相似,都分為Encoder和Decoder模型,那麼在了解VAE之前,我們先了解什麼是AutoEncoder模型。

AutoEncoder的意思是自編碼器,這個模型主要由兩個部分組成:encoder和decoder,可以把它理解為兩個函數:z = encoder(x), x = decoder(z)。在AutoEncoder模型的思想中,我們期望能夠利用encoder模型,將我們的輸入X轉換到一個對應的z,利用decoder模型,我們能夠將z還原為原來的x,可以把AutoEncoder理解為有損的壓縮與解壓。

AutoEncoder模型有什麼用呢?有兩個主要功能:

  1. 降噪
  2. 將高緯的特徵轉為低緯度的特徵(從X到z)。

要實現一個AutoEncoder其實非常簡單(其實就是單個隱藏層的神經網路),有接觸過深度學習的人應該都可以理解:

input = Input(shape=(seq_len,)) encoded = Dense(encoding_dim, activation=relu)(input) decoded = Dense(seq_len)(encoded) autoencoder = Model(input, decoded)

我們先來考慮一下能否用AutoEncoder進行KPI異常檢測,以及它有什麼缺點。因為AutoEncoder具有降噪的功能,那它理論上也有過濾異常點的能力,因此我們可以考慮是否可以用AutoEncoder對原始輸入進行重構,將重構後的結果與原始輸入進行對比,在某些點上相差特別大的話,我們可以認為原始輸入在這個時間點上是一個異常點。

下面是一個簡單的實驗結果展示,我們訓練了一個輸入層X的維度設置為180(1分鐘1個點,3小時數據),Z的維度設置為5(可以理解為原始輸入降維後表達),輸出成X的維度設置為180的AutoEncoder模型,並且測試集的數據進行重構(滑動窗口形式,每次重構後只記錄最後一個點,然後窗口滑動到下一個時間點),能夠得到以下結果:

  • 基於AutoEncoder的周期性KPI異常檢測:

上面提到,AutoEncoder具有降噪功能,那它怎麼降噪呢?這裡簡單舉一個例子:假設我們現在訓練出來的模型可以得到這樣的映射關係[1, 2](X)->[1](z)->[1 ,2]X_r, 其中[1, 2]表示二維向量, [1]表示一維向量,X_r表示重構後的X。這個例子表示了一個理想的AutoEncoder模型,它能將[1,2]降維到[1], 並且能從[1]重構為[1,2]。接下來,假設我們的輸入為[1, 2.1],其中第二維度的0.1表示一個雜訊,將其輸入到encoder部分後得到的Z為[1],並且重構後得到的X_r是[1, 2], 這也就達到了一個對原始輸入去噪的作用。

而我們的當前的目標是進行KPI異常檢測,從上圖可以看到,一些肉眼可見的異常在重構後被去除掉了(類似降噪了),通過對比與原始輸入的差距,我們可以判斷是否為異常。

然而,AutoEncoder模型本身沒有什麼多少正則化手段,容易過擬合,當訓練數據存在較多異常點的時候,可能模型的效果就不會特別好,而我們要做的是無監督異常檢測(要是有label的話就用有監督模型了),因此我們的場景是訓練的時候允許數據存在少量異常值的,但當異常值佔比較大的話,AutoEncoder可能會過擬合(學習到異常模式)。

  • Variational AutoEncoder(VAE)

接下來介紹一些VAE模型,如果不需要對VAE有比較清楚的了解,也可以直接跳過這部分內容。

對於VAE模型的基本思想,下面內容主要引用自我覺得講得比較清楚的一篇知乎文章,並根據我的理解將文中一些地方進行修改,保留核心部分,這裡假設讀者知道判別模型與生成模型的相關概念。

原文地址:zhuanlan.zhihu.com/p/27

VAE 跟傳統 AutoEncoder關係並不大,只是思想及架構上也有 Encoder 和 Decoder 兩個結構而已。VAE 理論涉及到的主要背景知識包括:隱變數(Latent Variable Models)、變分推理(Variational Inference)、Reparameterization Trick 等等。

首先,先定義問題:我們希望學習出一個生成模型,能產生訓練樣本中沒有,但與訓練集相似的數據。換一種說法,對於樣本空間 X ,當以 p(x) 抽取數據時,我們希望以較高概率抽取到與訓練樣本近似的數據。對於手寫數字的場景,則表現為生成像手寫數字的圖像。對於數據 x 的產生,我們假設它受一些隱含因素的影響,即隱變數(Latent Variables),寫作 z ,並且假設 p(z)服從標準正態分布 N(0, I)。則原來對 p(x) 建模轉為對 p(x,z) 進行建模,同時有

接下來我們可以開始解決最大化 p(x) 的問題,如果我們知道 p(z) 的分布,我們就可以利用採樣來計算積分,即

我們發現,當 p(x|z)=0 時,對估計 p(x) 沒有幫助,所以其實我們只需要採樣那些對 p(x) 有貢獻的 z 。此時,可以反過來求 p_θ(z|x),然而,p_θ(z|x)是intractable的,VAE中利用Variational Inference,引入 q_Φ(z|x) 分布來近似p_θ(z|x)

最終,可以得到需要優化的目標 ELBO(Evidence Lower Bound),此處其定義為

其中,第一項是我們希望最大化的目標p(x);第二項是在數據 x 下真實分布 p 與假想分布 q 的距離,當 q 的選擇合理時此項會接近為0。但公式中仍然含有intractable的 p(z|x) ,於是將其化簡後得到

於是,對於某個樣本 x_i ,其損失函數可以表示為,每次輸入為一個xi,

其中, q(z|x_i) 意味著在樣本 x_i 下隱變數 z的分布,對應於AutoEncoder中的Encoder部分; p(x_i|z) 意味著將隱變數 z 恢復成 x_i ,對應著 Decoder。於是,VAE 的結構可以表示為

但是,上面這種方式需要在前向傳播時進行採樣,而這種採樣操作是無法進行後向反饋梯度的。於是,作者提出一種「Reparameterization Trick」:將對N(z|mu(x),Sigma(x))採樣的操作移到輸入層進行。於是就有了下面的VAE最終形式

採樣時,先對輸入的epsilon sim N(0, I)進行採樣,然後計算z=mu(x)+Sigma^{frac{1}{2}}(x)*epsilon,間接對 z採樣。

我們再結合兩個圖梳理一下VAE的過程。

下圖表示了VAE整個過程。即首先通過Encoder 得到 x 的隱變數分布參數;然後採樣得到隱變數 z 。接下來按公式,應該是利用 Decoder 求得 x 的分布參數,而實際中一般就直接利用隱變數恢復 x

下圖展示了一個具有3個隱變數的 VAE 結構示意圖。

  • 基於VAE的周期性KPI異常檢測

上面介紹了VAE的原理,看起來很複雜,其實最終VAE也實現了跟AutoEncoder類似的作用,輸入一個序列,得到一個隱變數(從隱變數的分布中採樣得到),然後將隱變數重構成原始輸入。不同的是,VAE學習到的是隱變數的分布(允許隱變數存在一定的雜訊和隨機性),因此可以具有類似正則化防止過擬合的作用。

以下的構建一個VAE模型的keras代碼,修改自keras的example代碼,具體參數參考了Dount論文:

def sampling(args): """Reparameterization trick by sampling fr an isotropic unit Gaussian. # Arguments: args (tensor): mean and log of variance of Q(z|X) # Returns: z (tensor): sampled latent vector """ z_mean, z_log_var = args batch = K.shape(z_mean)[0] dim = K.int_shape(z_mean)[1] # by default, random_normal has mean=0 and std=1.0 epsilon = K.random_normal(shape=(batch, dim)) std_epsilon = 1e-4 return z_mean + (z_log_var + std_epsilon) * epsiloninput_shape = (seq_len,)intermediate_dim = 100latent_dim = latent_dim# VAE model = encoder + decoder# build encoder modelinputs = Input(shape=input_shape, name=encoder_input)x = Dense(intermediate_dim, activation=relu, kernel_regularizer=regularizers.l2(0.001))(inputs)x = Dense(intermediate_dim, activation=relu, kernel_regularizer=regularizers.l2(0.001))(x)z_mean = Dense(latent_dim, name=z_mean)(x)z_log_var = Dense(latent_dim, name=z_log_var, activation=softplus)(x)# use reparameterization trick to push the sampling out as input# note that "output_shape" isnt necessary with the TensorFlow backendz = Lambda(sampling, output_shape=(latent_dim,), name=z)([z_mean, z_log_var])# build decoder modelx = Dense(intermediate_dim, activation=relu, kernel_regularizer=regularizers.l2(0.001))(z)x = Dense(intermediate_dim, activation=relu, kernel_regularizer=regularizers.l2(0.001))(x)x_mean = Dense(seq_len, name=x_mean)(x)x_log_var = Dense(seq_len, name=x_log_var, activation=softplus)(x)outputs = Lambda(sampling, output_shape=(seq_len,), name=x)([x_mean, x_log_var])vae = Model(inputs, outputs, name=vae_mlp)# add lossreconstruction_loss = mean_squared_error(inputs, outputs)reconstruction_loss *= seq_lenkl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)kl_loss = K.sum(kl_loss, axis=-1)kl_loss *= -0.5vae_loss = K.mean(reconstruction_loss + kl_loss)vae.add_loss(vae_loss)vae.compile(optimizer=adam)

基於VAE的周期性KPI異常檢測方法其實跟AutoEncoder基本一致,可以使用重構誤差來判斷異常,來下面是結果,上圖是原始輸入,下圖是重構結果,我們能夠看到VAE重構的結果比AutoEncoder的更好一些。

缺陷:

基於AutoEncoder和VAE模型在工業界上的使用面臨的2個最大問題是:

  1. 理論上它只能對一個KPI訓練單獨一個模型,不同類型的KPI需要使用不同的模型,為了解決這個問題,裴丹團隊後面又發表了一篇關於KPI聚類的論文《Robust and Rapid Clustering of KPIs for Large-Scale Anomaly Detection》,先對不同的KPI進行模板提取,然後進行聚類,對每個類訓練單獨一個模型。
  2. 需要設置異常閾值。因為我們檢測異常是通過對比重構後的結果與原始輸入的差距,而這個差距多少就算是異常需要人為定義,然而對於大量的不同類型的KPI,我們很難去統一設置閾值,這也是採用VAE模型比較大的一個缺陷。雖然在Dount論文中,採用的是重構概率而不是重構誤差來判斷異常,然而重構概率也需要設置閾值才能得到比較精確的結果。

總結

本文分別介紹了AutoEncoder和VAE模型以及基於這些模型的周期性KPI異常檢測方法。裴丹的論文Dount中對原始的VAE做了一些改進,針對KPI異常檢測這個場景增加了一些細節上的優化,如missing data injection、MCMC等等,這部分細節就不在本文中討論了,有興趣的同學可以看一下他們的開源代碼 haowen-xu/donut。

最後,為了讓對AIOps有興趣的同學能夠交流與學習,我創建了一個Awesome-AIOps的倉庫,匯總一些AIOps相關的學習資料、演算法/工具庫等等,歡迎大家進行一起補充,互相進步。

linjinjin123/awesome-AIOps?

github.com圖標

如果文中有什麼解釋不清或者說錯的地方,歡迎批評指正。

參考文獻

[1] Unsupervised Anomaly Detection via Variational Auto-Encoder for Seasonal KPIs in Web Applications

[2] blog.keras.io/building-

[3] 當我們在談論 Deep Learning:AutoEncoder 及其相關模型


推薦閱讀:

TAG:運維 | 時間序列分析 | AIOps |