热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

浏览器中的异常检测算法及其在深度学习中的应用

本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。

异常检测是机器学习领域常见的应用场景,例如金融领域里的信用卡欺诈,企业安全领域里的非法入侵,IT运维里预测设备的维护时间点等。我们今天就来看看异常检测的基本概念,算法,然后看看如何利用TensorflowJS来进行异常检测。

什么是异常点?

异常点是指数据中和其它点不一样的点,异常检测就是要找到这些点。通常有以下这些不同类型的异常:

  • 点异常 Point Anomalies
    单个点和其它数据显著的不同
  • 上下文异常 Contextual Anomalies
    数据在所在的上下文环境中是个异常,例如下图t1不是异常而t2是因为t2前后的数据和t2有显著的差异。
    “Contextual Anomalies”的图片搜索结果
  • 集合异常 Collective Anomalies.
    集合异常是指一组数据点和其它的数据有显著的不同,这一组数据的集合构成异常

从数据维度的角度来看,异常也分为单变量(univariate)和多变量异常(multivariate)。

异常检测的算法主要包括基于统计的算法和基于机器学习的算法。

异常检测的统计学方法

利用统计方法来进行异常检测有两种,第一种是参数化的,就是假定正常的数据是基于某种参数分布的,那么我们可以通过训练数据估计出数据的分布概率,那么对于每一个要分析的数据点都计算出该数据点在这个概率分布下生成的概率。这个值越高,说明该数据是正常点的可能性就越大,该数值越低,就说明这个点就越有可能是异常点。

最常见的方式就是ZScore,假定数据符合正态分布,ZScore计算数据点偏离均值多少个标准差。ZScore越大说明数据偏离均值越远,那么它是异常的概率就越高。

非参数化的方法并不假定数据的先验分布,数据的分布是从训练数据中学习而来的。

其它还有一些统计方法诸如:

  • 时间序列中的移动平均值
  • 卡曼滤波器

利用统计方法做异常检测非常容易理解,计算效率也很好。但是这种方法存在一些挑战:

  • 数据点中的噪声和异常可能拥有类似的统计特征,那么就很难检测出来。
  • 异常的定义可能会发生变化,一个固定的伐值可能并不适用。例如应用zscore,到底是大于3是异常还是大于4是异常,这很难定义。

异常检测的机器学习方法

从监督学习和非监督学习的角度来看,如果已经有了标记异常点的大量训练数据,异常检测可以简单的转化为分类问题,也就是数据分两类,正常点和异常点。但是在现实中,往往很难找到大量标记好异常点的训练数据,所以往往需要非监督学习来进行异常检测。

利用数据的相似度来检测异常的基本假设是,如果被检测的数据和已有的数据相似度大,那么它是正常数据的可能性就大。相似度的学习主要有基于距离的(KNN)和基于密度的(LOF)。

基于聚类的异常检测的基本假设是,正常数据聚集在一起,异常数据聚集在一起。

DBSCAN是异常检测常用的聚类方法。关于DBSCAN算法的介绍,大家可以参考我的博客图解机器学习

如上图所示,DBSCAN可以学习出正常聚类的中心点A,边缘点BC以及异常点N。

但是DBSCAN对于各个超参数的设定非常敏感,利用该方法虽然不需要标记异常点,但是找到合适的超参数并不容易。

支持向量机(SVM)是一种监督学习的分类方法,单类支持向量机(OneClassSVM)是SVM的一种扩展,可以用于非监督的检测异常。

该算法可以学习出正常点和异常点之间的边界。

隔离森林(isolation forests)是检测数据中异常值或新颖性的一种有效方法。这是一种基于二元决策树的方法。 

隔离森林的基本原则是异常值很少,而且与其他观测结果相差甚远。为了构建树(训练),算法从特征空间中随机选取一个特征,并在最大值和最小值之间随机选择一个随机分割值。这是针对训练集中的所有观察结果。为了建造森林,树木整体被平均化为森林中的所有树木。

然后,为了预测,它将观察与“节点”中的分裂值进行比较,该节点将具有两个节点子节点,在该子节点上将进行另一次随机比较。由算法为实例做出的“分裂”的数量被命名为:“路径长度”。正如预期的那样,异常值的路径长度将比其他观察值更短。

自编码器就是类似上图的一个网络,包含编码和解码两个主要的部分,我们利用训练数据集对该网络进行训练,输出的目标等于输入的数据。也就是说我们训练了一个可以重建输入数据的深度神经网络。那么这样做有什么用能。

我们可以看出编码的过程其实类似一个PCA的降维过程,就是经过编码,找到数据中的主要成分,利用该主要成份能够重建原始数据,就好像数据压缩和解压缩的过程,用更少的数据来取代原始数据。对于一般的自编码器的应用,训练好的自编码器不会全部用于构建网络,一般是使用编码的部分来进行数据的特征提取,降维,以达到更有效的计算。

利用自编码器,我们假定正常数据通过自编码器应该会还原,也就是输入和输出是一样的,而对于异常数据,还原出来的数据和原始数据存在差异。基本假设就是还原出来的数据和输入数据差异越小,那么它是正常数据的可能性就越大,反之它是异常数据的可能性就越大。

下面我们就来看一个利用自编码器用tensorflowJS来检测信用卡欺诈数据的例子。数据集来自Kaggle,考虑到TensorflowJS在浏览器中的性能问题,我对原始数据取样10000条记录来演示。

加载数据

该数据经过kaggle处理,包含Time交易时间,Amount交易数额,V1-V28是经过处理后的特征,Class表示交易的类别,1为欺诈交易。

async function loadData(path) { return await d3.csv(path); } const dataset = await loadData( "https://cdn.jsdelivr.net/gh/gangtao/datasets@master/csv/creditcard_sample_raw.csv" );

数据预处理

 function standarize(val, min, max) { return (val - min) / (max - min); } function prepare(dataset) { const processedDataset = dataset.map(item => { const obj = {}; for (let i = 1; i <29; i++) { const key = `V${i}`; obj[key] = parseFloat(item[key]); } obj["Class"] = item["Class"]; obj["Time"] = parseFloat(item["Time"]); obj["Amount"] = parseFloat(item["Amount"]); return obj; }); const timeMax = d3.max(processedDataset.map(i => i.Time)); const timeMin = d3.min(processedDataset.map(i => i.Time)); const amountMax = d3.max(processedDataset.map(i => i.Amount)); const amountMin = d3.min(processedDataset.map(i => i.Amount)); processedDataset.forEach(item => { item.stdTime = standarize(item.Time, timeMax, timeMin); item.stdAmount = standarize(item.Amount, amountMax, amountMin); }); return processedDataset; } const preparedDataset = prepare(dataset);

在数据预处理阶段我们对Time和Amount做标准化处理使它的值在(0-1)之间。

生成训练数据集

function makeTrainData(dataset) { console.log(dataset.length); const normalData = dataset.filter(item => item.Class == "0"); const anomalData = dataset.filter(item => item.Class == "1"); const sliceIndex = normalData.length*0.8; const normalTrainData = normalData.slice(0,sliceIndex); const normalTestData = normalData.slice(sliceIndex+1, normalData.length); console.log(normalData.length); const trainData = { x: [], y: [] }; normalTrainData.forEach(item => { const row = []; for (let i = 1; i <29; i++) { const key = `V${i}`; row.push(item[key]); } row.push(item["stdAmount"]); row.push(item["stdTime"]); trainData.x.push(row); trainData.y.push(row); }); const testData = normalTestData.map(item => { const row = []; for (let i = 1; i <29; i++) { const key = `V${i}`; row.push(item[key]); } row.push(item["stdAmount"]); row.push(item["stdTime"]); return row; }); const testAnomalData = anomalData.map(item => { const row = []; for (let i = 1; i <29; i++) { const key = `V${i}`; row.push(item[key]); } row.push(item["stdAmount"]); row.push(item["stdTime"]); return row; }); return [trainData, testData, testAnomalData]; } const [trainData, testData, testAnomalData] = makeTrainData(preparedDataset);

我们选择80%的正常数据做训练,另外20%的正常交易数据和所有的异常交易数据做测试。

构建模型和训练

function buildModel() { const model = tf.sequential(); //encoder Layer const encoder = tf.layers.dense({ inputShape: [INPUT_NUM], units: FEATURE_NUM, activation: "tanh" }); model.add(encoder); const encoder_hidden = tf.layers.dense({ inputShape: [FEATURE_NUM], units: HIDDEN_NUM, activation: "relu" }); model.add(encoder_hidden); //decoder Layer const decoder_hidden = tf.layers.dense({ units: HIDDEN_NUM, activation: "tanh" }); model.add(decoder_hidden); //decoder Layer const decoder = tf.layers.dense({ units: INPUT_NUM, activation: "relu" }); model.add(decoder); //compile const adam = tf.train.adam(0.005); model.compile({ optimizer: adam, loss: tf.losses.meanSquaredError }); return model; } async function watchTraining() { const metrics = ["loss", "val_loss", "acc", "val_acc"]; const cOntainer= { name: "show.fitCallbacks", tab: "Training", styles: { height: "1000px" } }; const callbacks = tfvis.show.fitCallbacks(container, metrics); return train(model, data, callbacks); } async function trainBatch(data, model) { const metrics = ["loss", "val_loss", "acc", "val_acc"]; const cOntainer= { name: "show.fitCallbacks", tab: "Training", styles: { height: "1000px" } }; const callbacks = tfvis.show.fitCallbacks(container, metrics); console.log("training start!"); tfvis.visor(); // Save the model // const saveResults = await model.save('downloads://creditcard-model'); const epochs = config.epochs; const results = []; const xs = tf.tensor2d(data.x); const ys = tf.tensor2d(data.y); const history = await model.fit(xs, ys, { batchSize: config.batchSize, epochs: config.epochs, validationSplit: 0.2, callbacks: callbacks }); console.log("training complete!"); return history; } const model = buildModel(); model.summary(); const history = await trainBatch(trainData, model);

我们的自编码器的模型如下:

_________________________________________________________________ Layer (type) Output shape Param # ================================================================= dense_Dense1 (Dense) [null,16] 496 _________________________________________________________________ dense_Dense2 (Dense) [null,8] 136 _________________________________________________________________ dense_Dense3 (Dense) [null,8] 72 _________________________________________________________________ dense_Dense4 (Dense) [null,30] 270 ================================================================= Total params: 974 Trainable params: 974 Non-trainable params: 0

前两层是编码,后两层是解码。

分析异常值

自编码器模型训练好了以后我们就可以用它来分析异常,我们对测试数据的正常交易记录和异常交易记录用该模型预测,理论上正常交易的输出更接近原始值,而异常交易记录应该偏离原始值比较多,我们利用欧式距离来分析自编码器的输出结果。

async function distance(a, b ){ const axis = 1; const result = tf.pow(tf.sum(tf.pow(a.sub(b), 2), axis), 0.5); return result.data(); } async function predict(model, input) { const prediction = await model.predict(tf.tensor(input)); return prediction; } const predictNormal = await predict(model, testData); const predictAnomal = await predict(model, testAnomalData); const distanceNormal = await distance(tf.tensor(testData), predictNormal); const distanceAnomal = await distance(tf.tensor(testAnomalData), predictAnomal); const resultData = []; distanceNormal.forEach(item => { const obj = {}; obj.type = "normal"; obj.value = item; obj.index = Math.random(); resultData.push(obj); }) distanceAnomal.forEach(item => { const obj = {}; obj.type = "outlier"; obj.value = item; obj.index = Math.random(); resultData.push(obj); })

测试结果如下图:

上图绿色是异常交易,蓝色是正常交易。因为正常交易的数量较多,我们可能看不太清楚,我们分别显示如下图:

我们看到异常交易的自编码器输出和原始结果的距离都是大于10的,而绝大部分正常交易集中在10以下的区域,如果我们以10为伐值,应该可以找到大部分的异常交易,当然会有大量的正常交易误报。也就是该模型是无法做到完全的分辨正常和异常交易的。

完整的代码见我的Codepen

总结

本文介绍了各种异常检测的主要方法,无论是统计方法,机器学习的方法还是深度学习的方法,其中主要问题都是对于伐值或者参数的设置。

对于统计方法,需要确定究竟生成概率多少的事件是异常是百年一遇的洪水是异常,还是千年一遇的洪水是异常?

对于各种监督学习,我们往往缺乏异常点的标记,而对于非监督学习,调整各种参数会对异常点的判断有很大的影响。

对于基于自编码器的方法而言,我们看到,我们利用利用自编码器的输出和输入的差异来判断该事件是否为异常事件,然而究竟偏离多少来定义为异常,仍然需要用户来指定。

我们希望的完全通过数据和算法来自动发现异常仍然是一个比较困难的问题。

参考

  • Introduction to Anomaly Detection
  • A Brief Overview of Outlier Detection Techniques
  • A Density-based algorithm for outlier detection
  • Introduction to Anomaly Detection: Concepts and Techniques
  • Anomaly detection using deep learning to measure quality of Large Datasets
  • Comparing anomaly detection algorithms for outlier detection on toy datasets
  • 莫烦 Python 自编码 (Autoencoder)
  • Credit Card Fraud Detection Dataset
  • 在浏览器中进行深度学习:TensorFlow.js (十一)时间序列预测

  • 在浏览器中进行深度学习:TensorFlow.js (十)构建一个推荐系统 

  • 在浏览器中进行深度学习:TensorFlow.js (九)训练词向量 Word Embedding
  • 在浏览器中进行深度学习:TensorFlow.js (八)生成对抗网络 (GAN)

  • 在浏览器中进行深度学习:TensorFlow.js (七)递归神经网络 (RNN)
  • 在浏览器中进行深度学习:TensorFlow.js (六)构建一个卷积网络 Convolutional Network

  • 在浏览器中进行深度学习:TensorFlow.js (五)构建一个神经网络

  • 在浏览器中进行深度学习:TensorFlow.js (四)用基本模型对MNIST数据进行识别

  • 在浏览器中进行深度学习:TensorFlow.js (三)更多的基本模型

  • 在浏览器中进行深度学习:TensorFlow.js (二)第一个模型,线性回归

  • 在浏览器中进行深度学习:TensorFlow.js (一)基本概念


推荐阅读
  • 本文深入探讨了MySQL中常见的面试问题,包括事务隔离级别、存储引擎选择、索引结构及优化等关键知识点。通过详细解析,帮助读者在面对BAT等大厂面试时更加从容。 ... [详细]
  • Linux环境下进程间通信:深入解析信号机制
    本文详细探讨了Linux系统中信号的生命周期,从信号生成到处理函数执行完毕的全过程,并介绍了信号编程中的注意事项和常见应用实例。通过分析信号在进程中的注册、注销及处理过程,帮助读者理解如何高效利用信号进行进程间通信。 ... [详细]
  • 探讨ChatGPT在法律和版权方面的潜在风险及影响,分析其作为内容创造工具的合法性和合规性。 ... [详细]
  • 使用EmguCV 4.5.4实现LSD直线检测的C#示例
    欢迎关注“视觉与AI技术前沿”公众号,获取最新的计算机视觉和深度学习干货。本文将详细介绍如何使用EmguCV 4.5.4在C#中实现LSD(Line Segment Detector)直线检测,并提供完整的代码示例。 ... [详细]
  • 本文探讨了如何利用HTML5和JavaScript在浏览器中进行本地文件的读取和写入操作,并介绍了获取本地文件路径的方法。HTML5提供了一系列API,使得这些操作变得更加简便和安全。 ... [详细]
  • 本文详细介绍了如何使用 HTML 和 CSS 对文件上传按钮进行样式美化,使用户界面更加友好和美观。 ... [详细]
  • 精选多款高效实用软件及工具推荐
    本文介绍并推荐多款高效实用的软件和工具,涵盖系统优化、网络加速、多媒体处理等多个领域,并提供安全可靠的下载途径。 ... [详细]
  • 本文详细介绍了虚拟专用网(Virtual Private Network, VPN)的概念及其通过公共网络(如互联网)构建临时且安全连接的技术特点。文章探讨了不同类型的隧道协议,包括第二层和第三层隧道协议,并提供了针对IPSec、GRE以及MPLS VPN的具体配置指导。 ... [详细]
  • 本文介绍了一种根据目标检测结果,从原始XML文件中提取并分析特定类别的方法。通过解析XML文件,筛选出特定类别的图像和标注信息,并保存到新的文件夹中,以便进一步分析和处理。 ... [详细]
  • 新手指南:在Windows 10上搭建深度学习与PyTorch开发环境
    本文详细记录了一名新手在Windows 10操作系统上搭建深度学习环境的过程,包括安装必要的软件和配置环境变量等步骤,旨在帮助同样初入该领域的读者避免常见的错误。 ... [详细]
  • 浪潮AI服务器NF5488A5在MLPerf基准测试中刷新多项纪录
    近日,国际权威AI基准测试平台MLPerf发布了最新的推理测试结果,浪潮AI服务器NF5488A5在此次测试中创造了18项性能纪录,显著提升了数据中心AI推理性能。 ... [详细]
  • 吴恩达推出TensorFlow实践课程,Python基础即可入门,四个月掌握核心技能
    量子位报道,deeplearning.ai最新发布了TensorFlow实践课程,适合希望使用TensorFlow开发AI应用的学习者。该课程涵盖机器学习模型构建、图像识别、自然语言处理及时间序列预测等多个方面。 ... [详细]
  • 本文探讨了图像标签的多种分类场景及其在以图搜图技术中的应用,涵盖了从基础理论到实际项目实施的全面解析。 ... [详细]
  • 本文详细介绍了 TensorFlow 的入门实践,特别是使用 MNIST 数据集进行数字识别的项目。文章首先解析了项目文件结构,并解释了各部分的作用,随后逐步讲解了如何通过 TensorFlow 实现基本的神经网络模型。 ... [详细]
  • TensorFlow 2.0 中的 Keras 数据归一化实践
    数据预处理是机器学习任务中的关键步骤,特别是在深度学习领域。通过将数据归一化至特定范围,可以在梯度下降过程中实现更快的收敛速度和更高的模型性能。本文探讨了如何使用 TensorFlow 2.0 和 Keras 进行有效的数据归一化。 ... [详细]
author-avatar
缤纷之铃6868
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有