利用深度学习进行时序数据的异常检测

JustinaPowe 8年前
   <h2>本文要点</h2>    <ul>     <li>神经网络是一种模拟生物学神经的机器学习模型,数据来源于输入层并流经具有各种激活阈值的节点。</li>     <li>递归神经网络是一种在输入被理解之前保持其内部记忆的神经网络,所以它们可以进行数据流中时间依赖的结构的学习。</li>    </ul>    <p>机器学习早已在许多产品中发挥过威力了,我们日常就与很多打过交道,从像苹果的Siri和谷歌的Now之类的“智能”助手,到像亚马逊建议买新产品的推荐引擎,再到谷歌和 <em>非死book</em> 使用的排名系统,凡此种种,不一而足。最近,机器学习由于“深度学习”的进展闯入了公众视野,这些进展包括 <em>AlphaGo</em> 击败了围棋大师李世乭,以及围绕图像识别和机器翻译方面骄人的新产品。</p>    <p>在本系列的文章中,我们将介绍在机器学习方面强大而又可以普遍应用的技术。这些不仅包括经常在现代商业都需要的更传统的方法,还包括深度学习。在阅读本系列文章之后,你应该就具备在各种你自己所属的领域中进行具体机器学习实验的必要能力了。</p>    <p>本篇文章是系列文章“机器学习简介”其中的一部分,你可以通过RSS订阅以接收通知。</p>    <p>用来解决像语音和图像识别之类问题的深度神经网络越来越高的精确度已经引起大家的关注,致力于深度学习和人工智能的研究也更为普遍了。但广泛普及也带来了冲突。本文介绍神经网络,包括对前馈神经网络和递归神经网络的简要说明,并阐述了如何构建一个检测时间序列数据中异常现象的递归神经网络。为使我们的讨论更具体,我们将显示如何用Deeplearning4j构建神经网络,它是一个用于JVM的开源深度学习类库。</p>    <h2>什么是神经网络?</h2>    <p>人造神经网络的最初设想是模拟生物学神经元的算法。然而,这是一个很泛泛的类比。被人造神经网络借鉴的生物学神经元的功能包括节点之间的连接和针对每个神经元点亮的激活阈值(或触发器)。</p>    <p>通过构建一个连接人造神经元的系统,我们发现系统可以被训练去认识数据中更高层次的模式,并发挥有用的作用,比如递归、分类、聚类和预测。</p>    <p>仅比喻为生物神经元还远远不够。人造神经网络是一系列计算节点,在此数据表示为数字数组,这些数据由网络的输入层传入,通过网络所谓的隐藏层,直到在一个处理过程中生成这些数据相关的输出或决策,下文将简要描述这个处理过程。然后把该网络产生的输出与预期输出做比较(例如应用于这些数据上的地表实况标签),该网络的推测和正确答案之间的差异用于逐渐修正网络节点的激活阈值。随着这个过程的重复,该网络的输出将与预期输出重合。</p>    <p>拥有许多节点的整个神经网络可以运行于一台单独的机器上。一定要注意,这个神经网络不一定要在多台机器的分布式系统中。节点,在此意味着“计算发生的地方”。</p>    <h2>训练过程</h2>    <p>为构建一个神经网络,你需要对训练过程和网络输出如何形成有基本的理解。因为我们不想陷入到方程式里,所以简要描述如下:</p>    <p>网络的输入节点接收一个数字数组(可能是一个称之为张量的多维数组)表示输入数据。例如,一张图片的每个像素可能通过一个标量来表示,然后提供给一个节点。这些输入数据通过系统或参数来传递,通过这些系数的乘法运算将放大或减弱这些输入,这依赖于它学到的重要性,即该像素是否会影响到网络关于整个输入的决策。</p>    <p>最初,系数是随机的;网络创建出来时对于结构化数据一无所知。每个节点的激活函数决定了节点对一个输入或一组输入的输出。所以节点点亮与否,取决于它所接收的刺激的强度(输入和系数的返回值)是否超过了激活的阈值。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/a8b8868a2e76f56255a167f515a1c8fa.jpg"></p>    <p>在一个所谓的致密或完全连接层,每个节点的输出会传递到后续层的的所有节点。这后续会通过所有隐藏致密层,直到输出层为止,即该输入达成的决策的地方。在这个输出层,该网络关于输入的决策是针对预期决策的评估(比如,这个图片中的像素表示的是只猫还是只狗?)。通过比对网络的猜测和包含在测试集中的实际答案评估出误差,然后使用这些误差更新网络的系数,从而改变网络为图片中不同像素赋予的重要性的程度。目标是减少所形成的输出与预期输出之间的错误,正确地标识出来是狗还是猫。</p>    <p>因为深度学习是一个复杂的过程,它包括矩阵代数、衍生产品、或然率和密集的硬件利用率,如同被修改大型系数矩阵一般,所以不需要把所有复杂性都揭示给最终用户。</p>    <p>然而,你应该知道一些有助于你理解神经网络函数的基本参数。它们是激动函数、优化算法以及目标函数(也称之为损失、成本或误差函数)。</p>    <p>该激活函数决定一个信号是否应该发送到连接的节点以及发送的范围。频繁用到的激活仅是一个基本的阶梯函数,如果它的输入低于一些阈值则为0,高于这些阈值则为1。如此,具有阶梯函数激活函数的节点要么向连接的节点发送0,要么发送1。优化算法决定网络如何学习,更精确地说是检测到误差后如何修改权重。通常使用的优化算法是 随机梯度下降 。最后,成本函数是与预期输出相比的误差的度量,是在对给定训练样本做决策时对神经网络执行情况的估量。</p>    <p>像用于Python的 Keras 或用于JVM的 Deeplearning4j 之类的开源框架使神经网络的构建可以很快上手。决定采用什么网络架构经常涉及到把你的数据类型与已知已解决的问题进行匹配,然后调整已有的架构去适应你的使用场景。</p>    <h2>神经网络的类型及其应用</h2>    <p>数十年来,神经网络已经广为人知并得到了广泛地使用。但许多重要技术趋势使最近的深度神经网络效率得到大幅地提升。</p>    <p>随着GPU对矩阵运算的提速,以及大型分布式计算框架的到来,计算能力得到了大幅的提升,这就为快速训练神经网络创造了条件,从而能在许多超参数组合上迅速迭代以寻找合适的架构。</p>    <p>大规模数据集正在形成,像ImageNet之类大规模高质量的标签数据集已经创建出来了。一般来说,机器学习算法训练的数据越多,则会越精确。</p>    <p>最后,我们在理解和构建神经网络算法方面也增强了,这使神经网络在计算机视觉、语音辨识、机器翻译和许多其他机器感知和面向目标的任务的比赛中不断刷新精确性的纪录。</p>    <p>虽然神经网络架构的领域非常大,但我们在此描述的是已经广泛应用的主要的网络类型。</p>    <h2>前馈神经网络</h2>    <p>这是一类有一个输入层、一个输出层和一个或多个隐藏层的神经网络。前馈神经网络带来好的泛逼近器(映射任何输入到任何输出的函数),常用于构建多用途的模型。</p>    <p>此类神经网络可以用于分类和递归。例如,如果使用前馈网络针对输出层上的若干神经元进行分类,则和针对若干类别是一样的。从概念上讲,输出神经元第一次决定的类别是网络预测出来的。更精确地说,每个输出神经元返回一个该记录匹配该类的可能性,然后把可能性最高的类别选做模型的输出分类。</p>    <p>多层感知器之类的前馈神经网络的好处是易于使用,比其他类型网络的复杂度要低,可以找到各种各样的实例。</p>    <h2>卷积神经网络</h2>    <p>卷积神经网络与前馈神经网络类似,至少在网络上传送数据的方式是一样的。它们从形式上粗略模仿了虚拟的大脑皮质。 <a href="/misc/goto?guid=4959741156330457341" rel="nofollow,noindex">卷积神经</a> 在一个底层图像上移动几个像放大镜之类的滤波器。这些滤波器专注于图像子集(碎片或贴片)的特征识别,然后在像场上的一系列贴片中重复这个过程。每个滤波器寻找可视化数据中的不同模式;例如,有的可能寻找的是水平线,有的可能寻找的是对角线,还有的可能寻找的是垂直线。这些线是已知的特征,滤波器在图像上经过,他们构造特征图谱定位每种线每次在图像中出现的不同方位。图像中不同的对象(小猫、波音747、转动中的榨汁机)形成不同的特征图谱,这些图谱最终可用于图像分类。在图像和视频识别领域已证明卷积网络非常有用,因为声音可以以声谱图的形式可视化表示出来,所以卷积网络同样可以广泛应用于语音识别和机器转录的任务上。</p>    <p>卷积与前馈网络在图像处理方面的对比。两种网络类型都可以分析图像,但它们的分析方式是不同的。因为卷积神经网络是一步步通过图像的重叠区域训练学着识别每个区域的特征的,而前馈神经网络是在整个图像上训练的。前馈神经网络在特征总是处于特定位置或方向的图像上进行训练,如果特征出现在一个不常见的位置可能就识别不到了,而得到充分训练的卷积神经网络是可以做到的。</p>    <p>卷积神经网络不但可用于诸如图像、视频、声音和语音识别之类的任务,还可以用于做自动驾驭汽车。</p>    <p>本篇文章关注的是递归神经网络,但卷积神经网络已经在图像识别方面做得非常好了,我们应该了解它们的功用。</p>    <h2>递归神经网络(RNN)</h2>    <p>和前馈神经网络不同,递归神经网络的隐藏层节点维护一个内部状态(一片内存),该网络有新的输入时会更新它。这些节点即可以基于当前输入做决策,也可以根据之前的输入做决策。递归神经网络可以使用内部状态去处理以任意序列输入的相关数据,比如时间序列。</p>    <p>它们可以用于笔迹识别、语音识别、日志分析、欺诈检测、网络安全。</p>    <p>对于包含时间维度的数据集来说(比如网页或服务器活动的日志、从硬件或医疗设备而来的传感器数据;财务事务;或者通话记录),递归神经网络是最合适的。跟踪跨许多时间步长数据内的依赖关系和相互关系需要你了解当前状态和之前的一些状态。尽管使用接收事件窗口的典型前馈神经网络可能也能做到,但后续该窗口会随时间发生变动,这一方法会把我们局限到由该窗口捕获的依赖上,解决方案会不灵活。</p>    <p>随时间的推移跟踪长期依赖的一种更好的方法是,某种存储有意义的事件的“记忆”,它可以使之后的事件可以在上下文中得以理解和分类。递归神经网络之美在于,包含于它的隐藏层的这段“记忆”在非常长期的时间窗口上学习它自己身上的这些时间依赖特征的意义。</p>    <p>在下文中,我们将探讨递归神经网络的应用,既有字符产生,也有网络异常检测。跨许多时间步长检测依赖特征的能力使递归神经网络可用于时间序列数据中的异常检测。</p>    <h2>递归神经网络的应用</h2>    <p>尽管我们的示例是一个计算机网络上的监控活动,但是用它来作为开始递归神经网络讨论的简单用例还是很有帮助的。因特网有许多使用递归神经网络生成文本的案例,一次一个字符,在接受一语料库文本的训练之后去预测之前给定信息的下一个字符是什么。</p>    <h3>用于字符生成的递归神经网络</h3>    <p>递归神经网络可被训练根据一系列时间依赖事件去处理英语字符。该网络将学习频繁跟在一个字符之后的另一个字符(比如在“the”、“he”和“she”中e跟在“h”后),然后后续按此预测下一个字符,它将通过与实际英语文本对比训练来降低误差。</p>    <p>当提供一整套莎士比亚时,它就能生成感人的莎士比亚风格的输出了, 例如 “为什么,Salisbury必须找到他的肉体和灵魂……”。当提供足够多的Java代码时,它生成的东西几乎能够编译。</p>    <p>Java是一个有意思的例子,因为它的结构包括很多内嵌依赖。每个打开的括号(即“(”)最终都将被关闭(即“)”)。每个打开的大括号(即“{”)在该行之下都会有一个关闭的大括号(即“}”)。这些依赖的位置不是一个紧挨着一个的,许多事件会影响到其间的距离。不必告诉它这些依赖结构,递归神经网络会去学习它们。</p>    <p>在异常检查中,我们将要求神经网络去学习数据中类似的、可能隐蔽或不明显的模式。正如字符生成者充分理解数据结构去生成模仿字符一样,用于异常检测的递归神经网络充分理解数据的结构以获知什么看起来是正常的,而什么不是。</p>    <p>字符生成的例子有助于展示递归神经网络具有在不同时间范围之上学习时间依赖的能力。递归神经网络可以将同样的能力用于网络活动日志中的异常检查中。</p>    <p>应用到文本中,异常检查可能要面对语法错误,因为我们所写的内容是有语法结构的。同样的,网络行为也有结构。它遵循可被学习的可预测模式。受过正常网络行为训练的递归神经网络会将网络入侵感知出来,就像把无标点的句子作为异常一样。</p>    <h3>网络异常检测项目示例</h3>    <p>假设我们想要检测网络异常,这些异常可能指向硬件故障、应用故障或入侵。</p>    <h2>我们的模型将为我们揭示什么</h2>    <p>递归神经网络将在网络活动日志的数字展现上进行训练,将日志中的原生混合文本和数字数据转化为特征向量。</p>    <p>通过提供大量的网络活动日志(每行日志都有一个时间戳)给递归神经网络,递归神经网络将了解正常预期的网络活动是什么样的。当把来自于网络的陌生活动提供给训练过的网络时,它就能够区分这个活动是正常预期的,还是入侵的了。</p>    <p>训练一个神经网络去识别预期行为有一个得天独厚的优势,因为它拥有大量的异常数据,或者还不足以精确分类的所有异常行为。我们在自己拥有的正常数据上训练网络,以便它能提醒我们注意未来的非正常行为。而针对攻击的训练也是在充分的数据上训练的。</p>    <p>说句题外话,被训练的网络不需要说明发生在特定时间的特定活动(它不知道星期天是特殊的日子),但它会注意到我们应注意到的这些比较明显的时序模式,以及可能并不明显的事件间的其他联系。</p>    <p>我们将简单介绍一下如何使用Deeplearning4j来处理这个问题,这是一个被广泛采用的开源类库,它适用于JVM上的深度学习。伴随Deeplearning4j一起而来的还有许多工具,这些工具在整个模型开发过程中很有帮助:DataVec是辅助提取转移加载(ETL)任务的一系列工具,用于为模型训练准备数据。正如Sqoop有助于加载数据进Hadoop一样,DataVec通过数据的清理、预处理、规格化和标准化从而帮助将数据加载进神经网络。</p>    <h2>新手入门</h2>    <p>第一个场景包括典型的大数据任务和ETL:我们需要收集、迁移、存储、准备、规格化和矢量化日志。时间步长的规模必须要确定下来。数据转换可能需要很大的工作量,因为JSON日志、文本日志和具有不相干标签模式的日志将必须被读取并转化为数组。DataVec可以帮助转换和规格化这些数据。在开发机器学习模型时作为一种常态,这些数据必须分解为训练集和检验(或评估)集。</p>    <h3>网络的训练</h3>    <p>网络的最初训练将在这些分解输入数据的训练上运行。</p>    <p>针对第一次训练的运行,你可能需要调整一些超参数(“超参数”是管理模型的“配置”以及它如何接受训练的参数)以便模型切实从数据中学习,并在合理的时间里这么做。我们将探讨以下几个超参数。在模型训练的同时,你应该寻求稳定地降低误差。</p>    <p>要注意一个风险,那就是神经网络模型将“过度拟合”数据。在过度拟合的数据集上训练过的模型将在该训练数据上有良好的表现,但对于之前未遇到过的数据就无法做出精确的判断了。按机器学习的说法,这不是“归纳”。Deeplearning4J提供了正规化工具和“提早中止”,从而有助于避免训练过程中的过程拟合。</p>    <p>神经网络的训练将占用大部分时间和硬件。在GPU上执行训练将大幅减少训练的时间,特别是针对于图像识别来说,但额外的硬件会带来额外的成本,所以让你的深度学习架构尽可能高效地使用硬件尤为重要。类似于Azure和亚马逊之类的云服务提供了可以访问基于GPU实例的功能,神经网络可以在异构集群上接受训练,这种集群中不仅可以有专用的机器,还可以有商业服务器。</p>    <h3>模型的形成</h3>    <p>Deeplearning4J提供了一个ModelSerializer类去保存接受训练的模型。一个接受训练的模型可以被保存起来,之后被将来的训练使用(比如,部署到生产环境)或更新。</p>    <p>当在生产环境执行网络异常检测时,日志文件需要被序列化为同一格式,模型在其上接受训练,然后基于神经网络的输出,你会得到报告,看当前活动是否在正常预期的网络行为之内。</p>    <p>示例代码</p>    <p>递归神经网络的配置可能看起来是这样的:</p>    <pre>  <code class="language-java">MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder()                    .seed(123)                    .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT).iterations(1)                    .weightInit(WeightInit.XAVIER)                    .updater(Updater.NESTEROVS).momentum(0.9)                    .learningRate(0.005)                    .gradientNormalization(GradientNormalization.ClipElementWiseAbsoluteValue)                    .gradientNormalizationThreshold(0.5)                    .list()                    .layer(0, new GravesLSTM.Builder().activation("tanh").nIn(1).nOut(10).build())                    .layer(1, new RnnOutputLayer.Builder(LossFunctions.LossFunction.MCXENT)                            .activation("softmax").nIn(10).nOut(numLabelClasses).build())                    .pretrain(false).backprop(true).build();    MultiLayerNetwork net = new MultiLayerNetwork(conf);    net.init();</code></pre>    <p>让我们来说明一下几行重要的代码:</p>    <pre>  <code class="language-java">.seed(123)</code></pre>    <p>为获得可重复的结果,设置随机种子去初始化神经网络的权重。典型情况下,会随机初始化系数,为了在调整其他超参数时获取一致的结果,我们需要设置一个种子,使我们能够一遍一遍调整和校验时可以使用同样的随机权重。</p>    <pre>  <code class="language-java">.optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT).iterations(1)</code></pre>    <p>选择使用哪个优化算法(在本例中,选择的是随机梯度下降)去决定如何修改权重以改进误差得分。你可能不希望去改它。</p>    <pre>  <code class="language-java">.learningRate(0.005)</code></pre>    <p>使用随机梯度下降时,误差梯度(即系统变化与网络误差变化的关系)被计算出来,然后权重沿此梯度移动力图将误差调整至最小。随机梯度下降为我们指定了减少误差的方向,而学习率决定在这个方向上的步长有多大。如果学习率过高,可能误差最小化就过了头;如果它太低,那么训练将永无休止。这是一个你可能需要去调整的超参数。</p>    <h3> </h3>    <p> </p>    <p>来自:http://www.infoq.com/cn/articles/deep-learning-time-series-anomaly-detection</p>    <p> </p>