一、概述
- 什么是异常检测
异常检测(Anomaly Detection)的目的是要让机器“知道它不知道”。具体的,对于给定的训练数据,我们希望训练一个Anomaly Detector来检测输入是不是与训练数据时相似的,对于不相似的数据就要判定其为anomaly:
Anomaly Detector
对于相似度的判定,不同的方法有不同的方式。异常(anomaly)还有很多别名,比如outlier、novelty、exceptions等。
- 怎样定义异常
异常并不一定是坏的东西,判定数据为异常的标准是看它是不是与训练数据相似。如果训练数据是某一只宝可梦,那么另一只就是异常,如果训练数据只有宝可梦,那么数码宝贝就是异常:
异常
- 异常检测的应用
异常检测可以用在欺诈检测上,比如检测银行卡的刷卡行为是不是盗刷行为;也可以用在网络入侵检测上,来判定账号的登录行为是否是异常登录行为;或者用在癌细胞检测上,可以判定一个细胞是否是正常的细胞或者是癌细胞。
- 能否当做二分类问题来解
对于异常检测这样的任务,我们很自然地想到用二分类的思路来解决这个问题,也就是针对正常数据和异常数据进行二分类。事实上有两个原因限制了我们无法获取异常数据,因此也就不能使用二分类的思路来解这个问题:
①无法穷举所有有代表性的异常数据,比如对于正常数据(各种宝可梦)而言,任何不是宝可梦的数据(甚至一只茶壶)都属于异常数据:
异常数据
②异常数据难以获取,比如对于欺诈检测来说,我们很容易获取正常的刷卡记录而很难获取异常的盗刷记录。
- 异常检测的分类
异常检测主要分两类:
①数据有标签,对于这样的数据,我们期望训练一个分类器,这个分类器除了要能告知正常数据的类别外,还要对于异常数据输出其属于“unknown”一类,这个任务叫做Open-set Recognition;
②数据无标签,这类数据分为两种,一种是数据是干净的(clean),也就是说数据集中不包含异常数据,另一种是数据是受污染的(polluted),数据集中包含少量的异常数据。受污染的数据是更常见的情况。
分类
二、有标签数据的异常检测
- Confidence Score
这里以辛普森家庭人物分类的这个任务为例来说明对于有标签数据的异常检测可以使用哪些方法。辛普森家庭人物分类这个任务就是输入一张图片,然后分类器来判断图片属于辛普森家庭中的哪一个人物,在训练资料中只有辛普森家庭中的各个人物,没有其他类型的资料:
辛普森家庭人物分类
这个分类器的效果如下:
分类器效果
对于这个任务的异常检测,我们要做的就是判断模型的输入是异常的还是正常的,一张辛普森家庭的人物的图片就是正常样本,而另外的图片(比如凉宫春日)的图片就是异常样本。我们依赖信心分数(Confidence Score)这一指标来判断一个输入样本是不是异常样本,这一指标我们可以通过分类器来得到,也就是说现在我们从分类器中获取的并非只有图片属于哪一类别的信息,还包括一个表明模型对做出的判定有多confident的信心分数:
信心分数
对于信心分数的选择,我们可以选择使用模型输出的类别分布的最大得分来作为信心分数,也可以选择这个类别分布的熵(Entroy)的相反数来作为信心分数。举例来说,下图中对于一个真正的辛普森家族人物图片的类别分布来说,最高的得分会很高,而分布的熵会很低,而对于一张凉宫春日的图片来说类别的分布就会比较平均,熵也会高一些:
信心分数
下面统计了测试集(正常样本)中的数据使用这个分类器进行分类的信心分数的分布,发现大多数样本的信心分数是很高的,不过对于一些分类错误的样本(图中红色样本)也表现出了较低的信心分数:
然后又统计了15000个左右异常样本的信心分数的分布情况,发现大多数样本的信心分数是比较低的,只有大约10%左右的样本取得了较高的信心分数:
异常样本
- 异常检测的框架
对于一个有标签的异常检测任务,我们需要有三个数据集,即训练集(training set)、开发集(development set)和测试集(test set)。训练集用来训练分类模型,开发集用来选择和调整一些超参数,测试集用来评估模型效果。大体的框架如下:
- 评估的方法
以下面这个开发集为例,这里面有100张辛普森家庭人物的图像,还有五张其他动漫人物的头像,图中统计了这105个样本的信心分数,发现大部分正常样本的信心分数都比较高,但也有少量正常样本取得了较低的信心分数,同时也有异常样本取得了较高的信心分数:
开发集
对于信心分数阈值的选定,我们很自然地想到可以将异常检测问题看做二分类问题,使用准确率来作为评估的标准。事实上对于异常检测任务来说,使用准确率来进行评估是不合适的,这是因为在开发集中通常大部分的样本是正常样本,只有少量的异常样本。比如在上面的开发集中按照下图的方式选定阈值,其准确率能够达到95.2%:
准确率
那么应该如何来评估一个异常检测系统呢?这里提供一种方法。对于下图中选定的阈值而言,我们可以统计一张表,表中记录了正常样本和异常样本被检测到和没被检测到的情况,其中Detected代表被检测成异常样本,Not Det代表没被检测成异常样本,对于被检测为异常的正常样本称为false alarm,对于没被检测到的异常样本称为missing:
评估方法
对于不同的阈值,会有不同的false alarm和missing分布情况,然而选定哪一个阈值的标准并非简单的由false alram和missing的数量总和来决定,而是要根据false alarm和missing哪个更重要来决定:
不同阈值
具体来说,如下图,我们需要设置一个cost table,在cost table中要为false alram和missing分别设置对应的cost,cost的确定要根据具体任务来决定,比如在癌细胞检测中我们认为应该有尽可能少的missing,因此我们就需要为missing设置一个较大的cost(比如下图中蓝色的cost table):
cost table
对于同一个阈值,选定不同的cost table就会有不同的cost,因此不同的阈值可能会在不同cost table下会有不同的效果:
cost table
- 用分类器的方法进行异常检测
上述使用分类器的信心分数的方法有时会遇到一些问题,举例来说,如下图,现在有一个猫和狗的分类器,一些不具备猫和狗特征的图片会位于分类界限上,而一些其他特殊图片比如老虎和狼同样具备猫和狗的特征,这些图片就不会位于分类的界限上,从而也有比较高的信心分数:
问题
另外一个例子是在做辛普森家庭人物分类时,可能分类器分辨一个样本是不是辛普森家庭人物时会特别关注图片是不是黄颜色的,比如下图中,将三玖和老师的脸或者头发涂黄后就会得到较高的信心分数:
问题
对于这样的问题,我们有方法可以学习一个给异常样本较低的信心分数的分类器,另外异常的样本可以使用生成对抗网络的方法生成,参考文献如下:
①Training Confidence-calibrated Classifiers for Detecting Out-of-Distribution Samples:https://arxiv.org/abs/1711.09325
②Novelty Detection with GAN:https://arxiv.org/abs/1802.10560
三、无标签数据的异常检测
- 极大似然估计的方法
这一节以下图中名为Twitch Plays Pokémon的游戏为例来介绍无标签数据的异常检测方法。这个游戏中的宝可梦会被成千上万人同时输入指令(指令只包括上下左右等有限个)进行操作,游戏执行的指令比同一时刻输入的指令要少得多,因此需要从输入的指令中进行选择,选择的方式包括无政府状态(随机选择)和民主投票(选择一段时间内最多人输入的指令)两种方式:
Twitch Plays Pokémon
对于玩游戏的玩家,就看做我们的数据,用来表示。我们假设玩家中有一部分专门捣乱的“网络小白”,这些人算作异常样本,我们的任务就是构建机器学习的模型来自动地检测哪一个玩家是“网络小白”。我们可以设计一个特征向量来表示每个,这里以二维为例,我们把一个玩家“说垃圾话”和“无政府状态发言”的情况作为这两维的特征:
数据
显然对于所有的数据来说,其中既包括绝大多数的正常玩家和一小部分的异常玩家“网络小白”,而对于无标注的数据来说,我们是没有分类器可用的,因此不能使用信心分数的方法。可以使用的方法是通过极大似然估计对玩家数据的概率密度函数进行建模,然后设置一个概率密度的阈值,当一个样本的概率密度低于这个阈值时说明其是个异常样本:
框架
对于所有的玩家数据,我们可以将其画在一个二维平面上,从图上可以看出数据密集的区域概率较大,而稀疏的区域概率较小,对于小概率的样本就可以看做异常样本。
数据分布
我们希望有一个量化的方法来对玩家数据概率分布进行建模,因此采用极大似然估计的方法,我们定义概率密度函数来表示一个样本点的概率密度(注意概率密度不同于概率,是有可能大于1的),其中是求解的参数,则数据的似然就是:
使用极大似然估计法的求解方法为:
我们假设数据的分布服从高斯分布,则就是一个高斯分布,事实上这里的也可以是神经网络,不过这里就以高斯分布为例,则就是高斯分布的均值与方差,其概率密度公式为:
则求解的过程就变成了:
真正求解上式时可以使用梯度下降法(不过最好使用似然),然而对于高斯分布来说是有解析解的,也就是:
我们在求解均值和方差以后就可以选择一个概率密度的阈值来判断一个样本是不是异常样本了:
我们将求解的高斯分布在图上连同数据一起画出来,如下图,这是阈值也就是概率图上的一条等高线:
结果
这里是以二维高斯分布为例,事实上在选择特征表示一个玩家时,可以使用更多的其他方面的特征,比如:
- 自编码器的方法
我们也可以尝试使用自编码器这种无监督的方法来进行异常检测,也就是将训练资料里的正常样本(比如辛普森家庭中的人物)通过自编码器来学习其隐层表示:
自编码器
对于测试集中的正常样本就可以通过自编码器轻易地重构回来(loss较小):
正常样本
而对于异常样本就很难通过这个自编码器进行重构(loss较大):
异常样本
因此就可以以自编码器的重构loss作为正异常样本的判断标准。
- 其他方法
还有一些其他的无标签数据的异常检测方法,这里列一些参考链接。
- One-class SVM
One-class SVM
参考链接:http://papers.nips.cc/paper/1723-support-vector-method-for-novelty-detection.pdf
- Isolated Forest
Isolated Forest
参考链接:https://cs.nju.edu.cn/zhouzh/zhouzh.files/publication/icdm08b.pdf