目录
摘要
1. Problem Formulation
2. What is Anomaly?
3. Applications
4. 如何做Anomaly Detection
4.1 Binary Classification?
4.2 Categories
5. with label
5.1 Example Application
5.2 How to use the Classifier
5.3 How to estimate Confidence?
5.4 Example Framework
5.5 Evaluation
5.6. Possible Issues
6. without labels
6.1 Twitch Plays Pokémon
6.2 Problem Formulation
6.3 Maximum Likelihood & Gaussian Distribution
7. Other Methods
结论与展望
本节主要讲的是Anomaly Detection (异常检测),既让一个系统从许多未标注的数据中学习到某些正常的特征,从而能够诊断出非正常的数据,我们把这个过程叫做异常检测。
首先说明了异常检测不适合用二分类算法进行,因为负样本实在是太多了,我们没法穷举,更坏的情况就是,很多情景下,我们没法收集到负样本。
其次讲了异常检测模型分类主要分为数据集有label和无label两类,使用不同的算法进行处理:
最后讲了异常检测的应用包括Fraud Detection(欺诈识别)、Network Intrusion Detection(网络入侵检测)、Cancer Detection(癌症检测)等。
异常侦测的问题通常formulation成这样,假设我们现在有一堆训练数据x1,x2........xn,我们现在要找到一个function,这个function要做的事情是:检测输入x的时,决定现在输入的x到底跟我们的训练数据是相似还是不相似的。
我们之前说过:机器学习其实就是让机器找到一个function,在异常侦测里面我们要找的function是这样的。输入与我们训练数据相似的x,则异常侦测的function(Anomaly Detector)就会告诉我们这是正常的数据;若输入与我们训练数据不相似的x,则异常侦测的function(Anomaly Detector)就会告诉我们这是异常的数据。
总之我们要找的是跟训练数据不一样的数据,有可能是特别好的,有可能是特别坏的。但至于什么叫做“像(similar)”,这就是Anoamly Detector需要探讨的问题。不同的方法就有不同的方式来定义什么叫做“像”、什么叫做“不像”。
机器到底要看到什么就是Anormaly。其实是取决你提供给机器什么样的训练数据。
假设你提供了很多的雷丘作为训练数据,皮卡丘就是异常的。若你提供了很多的皮卡丘作为训练数据,雷丘就是异常的。若你提供很多的宝可梦作为训练数据,这时数码宝贝就是异常的。
我们咋样去做异常侦测这件事呢?很直觉的想法就是:若我们现在可以收集到很多正常的资料( x 1 , x 2 , . . . , x N ) ,我们可以收集到很多异常的资料( x ~ 1 , x ~ 2 , . . . , x ~ N )。 我们可以将normal data当做一个Class(Class1),anomaly data当做另外一个Class(Class2)。我们已经学过了binary classification,这时只需要训练一个binary classifier,然后就结束了。
这个问题其实并没有那么简单,因为不太容易把异常侦测视为一个binary classification的问题。为什么这样说呢?
假设现在有一笔正常的训练数据是宝可梦,只要不是宝可梦就视为是异常的数据,这样不只是数码宝贝是异常数据,凉宫春日也是异常数据,茶壶也是异常的数据。不属于宝可梦的数据,不可能穷举所有不是宝可梦的数据。根本没有办法知道整个异常的数据(Class2)是咋样的,所以不应该将异常的数据视为一个类别,因为它的变化太大了。这是第一个不能将异常侦测视为二元分类的原因。
第二个原因是:很多情况下不太容易收集到异常的资料,收集正常的资料往往比较容易,收集异常的资料往往比较困难。
第一种:称为:Open-set Recognition,每一个训练数据都有对应的标签,那么我们可以训练一个Classifier(可以用NN,也可以用线性分类器),这个Classifier训练好后,如果看到训练数据中不存在的数据,那么可以为其打上【unknown】的标签。
第二种:只有训练数据,没有标签。这里又分两种情况:
现在给定的例子是要侦测一个人物是不是来自辛普森家庭,可以看出x1,x2......xn是来自辛普森家庭(辛普森家庭的人有很明显的特征:脸是黄色的,嘴巴像似鸭子),同时也可以看出凉宫春日显然不是来自辛普森家庭。
假设我们收集的辛普森家庭的人物都具有标注(霸子,丽莎,荷马,美枝),有了这些训练资料以后就可以训练出一个辛普森家庭成员的分类器。我们就可以给分类器看一张照片,它就可以判断这个照片中的人物是辛普森家庭里面的哪个人物。
现在我们想做的事情是根据这个分类器来进行异常侦测,判断这个人物是否来自辛普森家庭。
我们原本是使用分类器来进行分类,现在希望分类器不仅可以来分类,还会输出一个数值,这个数值代表信心分数(Confidence score ),然后根据信心分数做异常侦测这件事情。
定义一个阈值称之为λ ,若信心分数大于λ就说明是来自于辛普森家庭。若信心分数小于λ 就说明不是来自于辛普森家庭。
咋样可以得到信心分数呢?若我们将图片输入辛普森家庭的分类器中,若分类器非常的肯定这个图片到底是谁,输出的信心分数就会非常的高。当我们将图片输入分类器时,分类器的输出是一个几率分布(distribution),所以将一张图片输入分类器时,分类器会给事先设定的标签一个分数。
如图所示,将“霸子”图片输入分类器,分类器就会给“霸子”一个很高的分数。
但你若给它一张很奇怪的图片(凉宫春日),这时输出的分数会特别的平均。若输出特别平均,那这张图片就是异常的图片。刚才讲的都是定性的分析,现在需要将定性分析的结果化为信心分数。一个非常直觉的方法就是将分类器的分布中最高数值作为信心分数,所以上面那张图输出的信心分数为0.97(霸子),下面那张图输出的信心分数为0.26(凉宫春日)。
根据信心分数来进行异常检测不是唯一的方法,因为输出的是distribution,那么就可以计算交叉熵(entropy)。交叉熵(entropy)越大就代表输出越平均,代表机器没有办法去肯定输出的图片是哪个类别,表示输出的信心分数是比较低。总之我们有不同的方法根据分类器决定它的信心分数。
现在我输入一张训练资料没有的图片(荷马),分类器输出荷马的信心分数是1.00;输入霸子的图片,分类器输出霸子的信心分数为0.81,输出郭董的信心分数为0.12;输入三玖的图片,分类器输出柯阿三的信心分数为0.34,输出陈趾鹹的信心分数为0.31,输出鲁肉王的信心分数为0.10。
以上都是动漫人物,现在输入一张真人的图片,分类器输出柯阿三的信心分数为0.63,输出宅神的信心分数为0.08,输出小丑阿基的信心分数为0.04,输出孔龙金的信心分数为0.03。
接下里要讲的是:如何计算一个异常侦测系统的性能好坏?你可能会发现一个系统很可能有很高的正确率,但其实这个系统什么事都没有做。为什么这样呢?因为在异常侦测的问题中正常的数据和异常的数据之间的比例是非常悬殊的。
首先我们要知道在异常侦测中有两种错误:一种错误是异常的资料被判断为正常的资料,另外一种是正常的资料被判为异常的资料。所以你实际下,假设我们将λ设为0.5(0.5以上认为是正常的资料,0.5以下认为是异常的资料),这时就可以计算机器在这两种错误上分别范了多少错误。
对于所有异常的资料而言,有一笔资料被侦测出来,其余四笔资料没有被侦测为异常的资料。
对于所有正常的资料而言,只有一笔资料被判断为异常的资料,其余的九十九笔资料被判断为正常的资料。这时我们会说机器犯了一个false alarm(正常的资料被判断为异常的资料)错误
若是异常的资料却没有被侦测出来,我们会说机器有四个missing错误。
若我们将阀值(threshold)切在比0.8稍高的部分,这时会发现在五张异常的图片中,其中有两张认为是异常的图片,其余三种被判断为正常的图片;在一百张正确的图片中,其中有六张图片被认为是异常的图片,其余九十四张图片被判断为正常的图片。
哪一个系统比较好呢?其实你是很难回答这个问题。有人可能会很直觉的认为:当阀值为0.5时有五个错误,阀值为0.8时有九个错误,所以认为左边的系统好,右边的系统差。
但其实一个系统是好还是坏,取决你觉得false alarm比较严重还是missing比较严重。
所以你在做异常侦测时,可能有Cost Table告诉你每一种错误有多大的Cost。在不同的情景下、不同的任务,其实有不同的Cost Table:假设你要做癌症检测,你可能就会比较倾向想要用右边的Cost Table。因为一个人没有癌症却被误判为有癌症,顶多几天心情不好,但是还可以接受。若一个人其实有癌症,但没有检查出来,这时是非常严重的,这时的Cost也是非常的高。
如果我们直接用一个分类器来侦测输入的资料是不是异常的,当然这并不是一种很弱的方法,但是有时候无法给你一个perfect的结果。
你有可能会遇到这样的状况:有些资料会比猫更像猫(老虎),比狗还像狗(狼)。机器在判断猫和狗时是抓一些猫的特征跟狗的特征,也许老虎在猫的特征上会更强烈,狼在狗的特征上会更强烈。对于机器来说虽然有些资料在训练时没有看过(异常),但是它有非常强的特征会给分类器很大的信心看到某一种类别。
当然有些方法可以解这个问题,其中的一个解决方法是:假设我们可以收集到一些异常的资料,我们可以教机器看到正常资料时不要只学会分类这件事情,要学会一边做分类一边看到正常的资料信心分数就高,看到异常的资料就要给出低的信心分数。
接下来我们再讲第二个例子,在第二个例子中我们没有classifier,我们只能够收集到一些资料,但没有这些资料的label。
这个的例子是这样的:有人开了一个宝可梦的游戏,全世界的人都可以连接一起玩这个宝可梦的游戏。右边的框是每一个人都在输入指令同时操控这个游戏,这个游戏最多纪录好像是有八万人同时玩这个游戏。当大家都在同时操作同一个角色时,玩起来其实是相当崩溃的。
人们玩的时候就非常的崩溃,那么崩溃的原因是什么呢?可能是因为有小白(Troll)。有一些人根本就不会玩,所以大家都没有办法继续玩下去。所以我们就可以用异常侦测的技术,假设多数的玩家都是想要破关的(正常资料),我们可以从多数玩家的行为知道正常玩家的行为是咋样的,然后侦测出异常的玩家(网路小白)。至于侦测出来给网路小白做什么,还需要待讨论的问题。
我们需要一些训练的资料,每一个x代表一个玩家,如果我们使用machine learning的方法来求解这个问题,首先这个玩家能够表示为feature vector。向量的第一维可以是玩家说垃圾话的频率,第二维是统计玩家无xx状态发言,越是喜欢在无xx状态下发言,就越有可能是搞破坏的。
我们现在只有大量的训练资料,但是没有label。我们在没有classifier的情况下可以建立一个模型,这个模型是告诉我们P(x)的几率有多大。(根据这些训练资料,我们可以找出一个几率模型,这个模型可以告诉我们某一种行为发生的概率多大)。如果有一个玩家的几率大于某一个阀值(threshold),我们就说他是正常的;如果几率小于某一个阀值(threshold),我们就说他是异常的。
我们需要likelihood这个概念:我们收集到n笔资料,假设我们有一个probability density function,likelihood的意思是:根据probability density function产生如图所示的数据几率有多大。likelihood的可能性显然是由θ控制的,选择不同的θ 就有不同的probability density function,就可以算出不同的likelihood。
一个常用的probability density function就是Gaussian Distribution,你可以将这个公式想象为一个function,这个function就是输入一个vector x,输出为这个vector x被sample的几率。
上述是用生成模型(Generative Model) 来进行异常侦测这件事情,我们也可以使用Auto-encoder来做这件事情。我们把所有的训练资料训练一个Encoder,Encoder所做的事情是将输入的图片(辛普森)变为code(一个向量),Decoder所做事情是将code解回原来的图片。训练时Encoder和Decoder是同时训练,训练目标是希望输入和输出越接近越好。
测试时将一个图片输入Encoder,Decoder还原原来的图片。如果这张图片是一个正常的照片,很容易被还原为正常的图片。因为Auto-encoder训练时输入的都是辛普森家庭的图片,那么就特别擅长还原辛普森家庭的图片。
machine learning中也有其它做异常侦测的方法,比如SVM的One-class SVM。
本节讲的是Anomaly Detection的相关内容,根据训练集Anomaly Detection模型可分为with label的和without label的。
对于with label的训练集,我们训练使用的是分类器 + “分类信心分数”模式。但是对于分类器的评价我们不能使用简单的Accuracy这个指标,因为异常检测的数据集的标签分布是不均匀的,容易使得准确率也会很高,但其实分类器效果并不好。准确率对于不平衡数据没法很好地评估,其实也有很多方法来解决,比如说积分制,而具体你判断那个分类器更好,取决于你对业务的理解:异常数据没检测出、正常数据没检测出,哪个更加重要。此外,分类器也会有其它问题,比如“异常数据”无意中也具备了某一正常数据共同特征,而被误判为正常数据,当然也有方法解决,比如收集一些“异常数据”,让分类器去学习给它们更低的信心值或者使用下一节将的GAN技术来尝试生成“有点像正常数据却又没那么像”的异常数据。
对于without label的训练集,我们训练使用最大似然度模型。根据训练集训练模型,最后给出的是一个概率,如果概率大于某个阈值,才认为是正常值。有的时候我们发现特征不满足高斯分布,这个时候我们对特征进行变换,使得特征大致呈现高斯分布的样子会使算法取得更好的效果,具体可以使用numpy中的np.log()函数。