Anomaly Detection,也叫做 異常檢測,目的在於讓機器知道我所不知道的事情。
1. 什么是 Anomaly(異常)?
雖然說是 異常,但其實是以訓練集為核心,判斷輸入數據是否與訓練集中的數據 “類似”。在不同的領域可以有不同的叫法,比如:outlier Detection,novelty Detection,exceptions Detection。
至於什么才是“類似”,它的定義這取決於你所用的方法。如下圖所示,如果你給的訓練集只有雷丘,那么比卡丘就是“異常”;相反,如果你給的訓練集是比卡丘,那雷丘就是“異常”。

1.1 問題定義 Problem Formulation
- 給定一個訓練集
- 我們要找到一個函數來檢測 輸入 x 是不是屬於訓練集(是否和訓練集的數據屬於同一類)

1.2 為什么不能用二分類來解決這個問題?
如上面所說的,所謂“異常”,其實就是看是否和訓練集“相似”,雖然我們很容易獲得正訓練集(如上面的雷丘),但是負訓練集我們無法來決定,如果我們用 寶可夢 來作為負訓練集來訓練二分類,那下次輸入一個 亞古獸 呢?這時候二分類模型就無法識別這個沒見過的 負樣本,而這樣的負樣本實在是太多了,我們沒法窮舉。如下圖所示。

更壞的情況就是,很多情景下,我們沒法收集到負樣本。比如說刷卡行為,大多數情況都只是正常的交易行為,而盜刷這一類情況就少之又少,甚至(目前)沒有。
所以異常檢測無法簡化成二分類來實現,這是一個獨立的研究主題。
1.3 異常檢測模型 分類
根據給出的訓練集,我們可以大致將其分成兩大類三小類:
- (labeled)訓練集中每個樣本都有標簽,用這些樣本來訓練一個分類器,這個分類器除了能夠識別訓練集中已有樣本標簽外,還能輸出 “unknown” 標簽,用來表示該輸入是“沒見過的”、不在訓練集中的。我們把它叫做 “open-set recognition(開放式識別)”
- (unlabeled)另一種情況是,我的訓練集是沒有標簽的
- (clean)但這個訓練集是“干凈”的,我們可以將這個訓練集里所有的樣本都視為“正樣本“;
- (polluted)然而干凈的數據集在現實應用中很少,大多數都是或多或少參雜着”異常樣本“,而且你無法知道,比如說銀行給你大量刷卡數據進行訓練,而這些數據里有可能有盜刷的數據且沒有標注出來。

2. Labeled(帶標簽)
在這里就用 辛普森家族 來舉例子。這里有一堆辛普森家族的人物形象及其對應的人物名稱(視為標簽),這樣我們就能訓練一個“辛普森角色分類器”,輸入一個人物的形象,輸出該人物的名稱(標簽)。

那我們訓練好“辛普森角色分類器”后,這個分類器會輸出兩類數據:類別(預測的名字)、信心值;然后給定一個閾值 ,當信心度大於這個閾值,就視為“正常值(屬於辛普森家族)”,低於則視為“異常值(不屬於辛普森家族)”

分類器的輸出其實是一個概率分布(distribution),輸出前經過一個 softmax
,使得這個分布中的值之和為1,其輸出每一項 表示 每一個類別及其對應的信心值;我們將其中的最大值,視為分類器對該輸入的信心值.
除了最高值,我們還可以用 熵(entropy)來決定分類器最后的信心值。
如下圖所示,第一個分類器中,霸子的信心值很高(總體熵低),且其他很低,就說明分類器能夠很好地把這個人物形象進行分類,故認為該形象是“正常值”;
而第二個分類器中,每一類的信心值都不高且均勻(最大值不高,總體熵高),說明分類器沒見過該形象,信心不夠,沒法很好地區分,則可以認為該形象是“異常值”。

除了用分類器與其輸出的分布來 判斷 該分類器的信心度,當然還有其他的方式,如下圖所說的,不僅輸出分布(用來分類),還教分類器直接輸出其信心度(直接可以判斷是否異常)。

關於上面模型訓練部分,一般來說我們有個“驗證集”來調節模型的超參數,在“訓練集”中,所有的樣本都是“正樣本“且有各自的標簽(如都是辛普森和他們的人物名字),而在”驗證集“中就沒必要每個樣本都有其“人物標簽”,只需要判斷其“是否屬於辛普森家族”就行了(兩個標簽:屬於、不屬於)。
2.1 評價標准
在上面的例子中,“辛普森家族異常檢測模型“其實是一個普通分類器,那我們是否也可以用准確率(Accuracy)來評估這個模型的好壞呢?答案是:這不是一個好的選擇。
正如我們前面所說的,異常檢測的數據集的標簽分布是不均勻的,也就是說我們很大概率能夠找到“正樣本”而缺少“負樣本”;這種情況下,如果模型“無情地”把所有的樣本都預測成正樣本,那准確率也會很高,這樣顯然是不對的。

准確率對於不平衡數據沒法很好地評估,其實也有很多方法來解決,比如說成本積分制: 當正常數據沒有檢測出,則成本為100,異常數據沒有檢測出,成本為1(見Cost Table A),這時候左邊模型的成本則會低於右邊模型的成本(紅色字體),則左邊的模型更優秀; 而如果正常數據沒檢測出的成本為1,異常數據沒檢測出的成本為100,這時候右邊的模型就更優秀(藍色字體);
積分制的使用要取決於你對業務的理解:異常數據沒檢測出、正常數據沒檢測出,哪個更加重要?比如在醫療上,對於癌細胞的異常檢測,寧願檢測錯正常人,也不要漏過一個病人,這時候“異常數據沒檢測出的成本更高”。
除了積分制,還有很多方法,比如AUC、Macro-F1等等。

2.2 存在的問題
分類器也許可以能夠對“一般異常”進行“識別”,比如下面貓狗的分類器,就能夠把羊駝和馬來貘識別為“異常”,然而有一些“異常數據”則沒那么容易了,比如說老虎和狼,這就是模型泛化問題;
因為模型一般只會抽取出一類圖片中的共同特征,而此時“異常數據”無意中也具備了這一共同特征,那么就會出現把狼識別成狗的情況了。

另一個例子就是上面的“辛普森家族分類器”,將人物塗黃后,模型就會進一步識別成“麗莎”,這就說明了模型識別麗莎靠的是顏色,這顯然是不正確的。

針對以上存在的問題,也有很多工作試圖去解決,比如說收集一些“異常數據”,讓分類器去學習給它們更低的信心值;然而我們一開始就說了,異常數據很難獲取,那我們就想:能不能自動生成“異常數據”?
這時候我們就可以用GAN來嘗試生成“有點像正常數據卻又沒那么像”的異常數據。
下面給出了相關文獻,有興趣的可以去了解一下。

3. Without Labels(不帶標簽的)
這一部分,就是得到了沒有標簽的數據。該問題的定義和帶標簽的分類器一樣,都是根據訓練集訓練模型,然后幫我分析輸入數據相較於訓練集是否屬於異常數據。與分類器給出的信心值不同,這一類的模型給出的是一個概率,如果概率大於某個閾值,才認為是正常值;
在這一部分,用一個游戲舉個例子:Twitch Plays Pokemon。這個游戲是一個多人同時“玩一個角色”的在線游戲,然而和我們平時玩的網游不一樣,在這個游戲中,下一步動作取決於所有在線用戶的操作(如下圖的右邊,是每一個用戶按下的指令)。

然而玩這個游戲的人非常崩潰,因為這個游戲很難進行下去(因為要所有在線玩家都給一個角色發送指令,而每個玩家的指令又不相同,而游戲只會執行其中一個指令)。所以玩家們就在想:是不是有些“惡意玩家”在亂發送指令,阻止游戲進程?也就是說是不是有人不想讓這個游戲結束。
這樣我們就有需求——找出“惡意用戶”。在這之前,我們先有個假設:大部分玩家都希望完成這個游戲(也就是說大部分都是正常數據),而這部分數據我們會用來訓練。然后我們使用異常檢測,找出其中的“惡意玩家”(異常數據)。

接下來,我們就要對其進行建模。在這里,我們的需求是把一堆“無標簽”玩家分為正常用戶和異常用戶,這時我們需要把用戶表示成一個向量,這樣才能輸入進我們的模型;而向量中的每一項可以表示這個用戶的一種行為。
如下圖, x1 表示這個用戶過去一段時間內說垃圾話的頻率(垃圾話是指游戲指令之外的話,多余的,不影響游戲進程), x2 表示的是這個用戶過去一段時間內,隨機機制下的發言頻率。
這個游戲有兩種機制:投票機制和隨機機制 投票機制:20秒內最多玩家輸入的指令,則作為游戲下一步的指令; 隨機機制:隨機選擇在線玩家輸入的指令,作為游戲下一步的指令。

輸入定義好了,我們就可以看看輸出:模型會輸出一個概率 P(x) ,和分類器不一樣,無標簽訓練模型沒有對應的Y值(標簽)和信心值,只會輸出一個概率 P(x) ;而和分類器相似的是,我們一樣有一個,當
時,視為正常數據;當
時,視為異常數據。如下圖所示。

假設我們現在已經獲取了大量用戶的數據,下圖是這些數據可視化展示。從可視化中可以獲得一些信息:
- 在隨機機制下,用戶就越喜歡發指令(左上圖);
- 大部分用戶都會或多或少地亂輸入指令(說垃圾話,右下圖)。
這時候,我們就可以很直觀地看到,但用戶落在左上角的位置,則很大可能這就是一個“正常玩家”,而用戶落在靠右或者靠下的位置,則很大可能是“異常玩家”。

然而,我們需要一個數值化的表示方法,給每一個玩家一個分數。
假設我們之前看到的圖,圖上面所有的點都是由一個概率密度函數 生成的(不懂也沒關系,就當它是一個函數就行了),
是該函數的參數,決定了這個函數“長什么樣”,是未知的,需要從數據中學習。
而我們的工作就變成了: 它究竟長什么樣?這時候我們就需要一個“Likelihood”的概念,意思就是說,根據我們的概率密度函數
,能夠產生這樣的已知數據的概率有多大。
如果嚴格來說,輸出的不是概率,而是概率密度,它的值也不是介於0~1之間,而是有可能大於1的。 在這里,為了簡化問題,我們簡單地認為是概率就好。
而這個“Likelihood”要怎么算呢,它其實就等於每項已知數據根據 這個函數所產生出來的概率的乘積;於是我們就有下面這條公式,很顯然,這個公式是由
來控制的,不同的
,就會有不同的
,就會算出不同的“Likelihood”

這時候,我們並不知道 是多少,但我們知道,這個
,能夠使我們的“Likelihood”最大化


上面是只是一個抽象的說法。在這里,我們為了讓大家更好理解,我們就假設概率密度函數 為常用的高斯分布(Gaussian Distribution),這個概率密度函數並不簡單,大家看不懂也沒關系,就當它是一個普通函數就可以了,輸入一個向量x,輸出這個x被采樣到的概率
;而我們前面提到需要學習的 P(x) ,在這里就等於這里需要學習的均值
和協方差矩陣
為什么這里選擇高斯分布?
其實這只是舉例子,甚至可以是一個神經網絡,而此時
就是神經網絡的參數,所以我們沒必要在這里糾結,我們只需要清楚無標簽時,異常檢測是如何處理的,從而觸類旁通。

這時候,Likelihood方程就會置換成下圖的形式,用來找出能使Likelihood最大化的 和
。
左圖給了一個很好的示例,告訴我們, 的取值,如何影響Likelihood的取值;左上角時,數據落在這個區域的概率就很大,這時候Likelihood就很大,而右下角時,落在這個區域的概率就小,這是Likelihood就小。
和
其實是有公式算出來的,
就是所有的訓練數據的向量做一個平均(輸入向量是二維的,所以
也是二維的),而
就看圖的右下角這個公式,這里很簡單。

在這里,我們已經得到了 和
,我們可以用來做異常檢測,我們把測試數據代入我們的高斯分布方程,我們就能算出其概率,如果這個概率大於閾值
,是認為是正常值,否則視為異常值。
如果我們用這個訓練好的方程,大概就是下圖右下角的樣子,顏色越深代表這個方程輸出的數值就越大,就越代表“正常玩家”,而顏色越淺越藍的,就代表“異常玩家”;而這個閾值 ,其實其中一條等高線;右下圖就給出了正常點和異常點的位置示意。

以上的例子,我們只是使用了兩個特征,也就是輸入向量x只是二維;而機器學習的好處就是可以處理更多特征,只要你想到的,都可以加進去。下圖就增加到5個特征,再訓練一個Likelihood,從而獲得“更准確的”異常檢測效果。

3.1 更多的方法
除了上面的方法,還有一種常用方法是:Auto-encoder(自動編碼器),如下圖所示,Encoder(編碼器)先把辛普森的照片編碼成一個code(隱含層),然后Decoder(解碼器)把code解碼回原來的的照片,訓練時會同時訓練編碼器和解碼器,盡量讓解碼后的照片和原照片盡可能相似(甚至相同)。這時候如果用Auto-encoder來識別一張“異常圖片”,這時候的解碼器是無法重構回原來的照片,通過計算重構后的照片和原照片的“距離”(或者說是相似度、還原度),就可以區分該照片是不是“異常值”。
在我看來,Auto-encoder比分類器多了一重保障(指Decoder解碼器),在分類器上,找到對應的特征,就進行判斷,比如顏色、輪廓等等,上面就有例子說明這樣的情況並不可靠;而解碼器就是一種利用特征的過程,我利用編碼器提取的特征,看是否能夠重構回原來照片,就能知道這是不是異常值;

下圖是正常的圖片,可以看到模型很容易就重構了回來,而且和原圖非常接近。因為這個模型看過辛普森,所以非常“擅長”還原辛普森。

如下圖的Testing階段,對比原圖和重構圖,我們可以看到,編碼器提取到的應該是“黃色”和“棕色”這兩個特征,然而編碼器用兩個特征構建出來的圖片,顯然和原圖相差甚遠,這時候就可以識別為“異常值”。(從重構圖可以隱約看到,這大概也是一個辛普森角色)

除了自動編碼器,還有很多其他模型可以做這樣的事,比如one-class SVM,Isolated Forest。有興趣的可以自行進一步學習。

4. 應用
異常檢測的應用非常廣泛,下面幾項是非常常見的:
- Fraud Detection(欺詐識別)
- 訓練集:正常的刷卡行為;輸入x:盜刷行為?
- Network Intrusion Detection(網絡入侵檢測)
- 訓練集:正常的訪問;輸入x:攻擊行為?
- Cancer Detection(癌症檢測)
- 訓練集:正常細胞;輸入x:癌細胞