基于机器学习的攻击检测(二)上-理解lstm

基于机器学习的攻击检测(二)上-理解lstm

写在开头

【重要!!!】由于笔者水平有限,可能有理解不足或理解有误的地方,还请不吝指出!以免贻误

在进行下一篇文章之前,笔者想要先介绍一下什么是lstm以及循环神经网络的简单概念和结构,不然的话就是一直放代码放代码,挺没意思的2333,下一篇笔者会带来:基于机器学习的攻击检测(二)下-基于lstm实现

笔者自身由于并非Ml/DL强背景出身,尤其是nlp这块并没有深厚的理论基础(cv倒还行2333),因此在这里只是简单的说一下lstm以及其前身rnn是如何工作的,不对之处还望不吝指出~

什么是循环神经网络

循环神经网络,又叫座递归神经网络(rnn),是一种不同于传统full connect network 或者 convolution network的一种网络结构,它主要的特点在与时序性

先从最简单的介绍,在只有一层一个神经元的情况下,如果某一个输入x:

x = [x1,x2,x3...xn]

其中n表示这一个数据样本是由n个特征维度组成的,那么当他通过一个神经元C时 ,一定是这样的形式:

x = [x1,x2,x3...xn]

w = [w1,w2,w3...wn]^t

output = x * w + b

如果仅有一个神经元并且是单层,那么他就可以再套一个softmax函数就输出了,我们这里简单一点用sigmod代替:

output = sigmod(output)

单层神经元的正向传播

那么如果是多层的呢?

我们知道,不管是全连接网络还是卷积网络,其传播都是前向的也就是说,将前一个隐藏层(hidden layer)的输出作为后一个神经元的输入来迭代,除此之外不做其他操作,感性点来想想的话他是一个一条直线的传播方式,而RNN就厉害了,他不仅往前传播,他还往边上传播...

那么他这么做的目的是为啥呢?

很简单,为了能够保存序列中前一个元素的信息。说起来有点难懂,举几个例子就好了,比如说我们在做nlp任务的时候一条预料数据是:i like play dota2

那么我们在分词以后他的输入其实变成了['i' , 'like' , 'play' , 'dota2']

他们再进行embedding之后被依次带入了神经网络计算,那么他们就相当于是一个个独立的数据了,而很明显,我们的预料是有明确的上下文顺序的,因此简单的前向传播失去了这种上下文的关系,而这种关系是语言中无法割舍的,因为 i like play dota2 和 dota2 like play i完全是两层意思了...

更加明显的解释就是,我们想要保存这样的序列关系以保证我们的模型再进行词预测的时候觉得 :【我 是 男人】 会比 【我 是 看电影】 更加符合逻辑和常识 因为语序让我们知道主系表的表不应该是一个动词结构。

总而言之,RNN的目标就是某一种方式能够在每一层都能够处理有序列的数据并且能够保存这样的序列信息。在这一点上笔者认为其实和【残差网络(resnet)】中加入【残差结构】来获取前一隐藏层信息的思路有些许相似之处的

PS:笔者在第一次读RNN相关文章是,其实脑子里想的是这和密码学中某些密码本格式比如ECB,FCB的思路很像2333

那么接下来,就是我们该如何实现RNN了

他的实现方式是这样的,我们还是使用单层单个神经元来进行举例,但是本次我们的输入数据是有序列的,比如说一个文本序列:i am a boy 我们认为其输入具有顺序性,也就是:

  1. i排在第一个
  2. 其次的am
  3. 再次是a
  4. 最后是boy

那么再对文本数据作了embedding处理之后,其实每一个输入比如说i,都会变成一个数值向量:类似于具有n个特征维度,他可能长这样:

a1 = i = [x1,x2,x3,x4]

a2 = am = [x1,x2,x3,x4]

a3 = a = [x1,x2,x3,x4]

a4 = boy = [x1,x2,x3,x4]

其中a的下表表示其出现的顺序,[x1,x2,x3,x4]表示再embedding之后每一个词用一个1*4的向量来进行表示

那么在经过神经元的时候,比如说a1经过神经元,他是这样子的:

w(1) = [w1,w2,w3,w4]^t

其中w(1)表示a1对应的权重

h1 = a1 * w(1) + b1

output1 = sigmod(h1)

很简单,和前面一样,乘上权重再加上一个偏置b,经过sigmod函数得到这个神经元的输出

下面就是RNN的精华部分了,如何保留序列信息?

我们看a2,a2是如何过这个神经元的?他是这样子的:

w(2) = [w1,w2,w3,w4]^t

h2 = a2 * w(2) + h1 * Wh1 + b

output2 = sigmod(h2)

可以看到,output2的计算过程不再只是乘上权重加上偏置b了,它多出来了一个新的项:

h1 * Wh1,

h1从哪儿来?从前一个输入a1计算而来!这样的一种结构也就相当于是再计算a2的时候,同时加入了前一个输入(对于i am a boy来说就是计算am 是 考虑了前一个数据i的影响)所以产生的影响!

同理,a3的计算过程如下:

w(3) = [w1,w2,w3,w4]^t

h3 = a3 * w(3) + h2 * Wh2 + b

output3 = sigmod(h3)

我们使用图片来直观理解他:

需要注意的是,图中的传播过程并不是横向的前后隐藏层的关系,而是h1,h2,h3,h4均是同一个隐藏层中的同一个节点!!只不过是带入了不同数据而已!

因此严谨的图应该是这样:

右边就是我们上面所展示的,他其实是左边的展开展示!他们归根结底是同一层的同一个神经元

OK,rnn就讲到这里,那么lstm呢?

lstm可以说是rnn的高级表现形式,它的全称是:长 短期循环神经网络

相比于rnn它对于前一层输入的接受采取了更加科学的方法:

就是对于前一层的信息,并不是全盘的接受,而是接受一部分(或者说一定量,一个百分比)的接受

它的结构更加复杂:

我们采用台大二次元帅宅李弘毅老师的deep learning讲义中的图片来演示:

初次看到这个图,好像和前面的rnn.....一点都不一样2333

那么我们来讲解一下这个图上的参数,到底是什么意思:

  1. c(注意不是蓝色的那个c',是旁边一点的c):它代表的是上一个数据的输出,也就是RNN里面的h1(i 的输出)
  2. z(最下面的):它代表的是本轮的输入,也就是 a2 = am = [x1,x2,x3,x4] , g(z) = sigmod(z)
  3. 那么在这个时候会有一个额外的外部输入zi, f(zi) = sigmod(zi)
  4. g(z)和f(zi)相乘也就相当于RNN中的x*w,或者我们换一种理解,因为sigmod是一个规范到0-1之间的,它和g(z)相乘也就是在表达,g(z)有百分之多少可以带入下一步的计算
  5. zf,遗忘门的输入, g(zf) = sigmod(zf) c' = g(z)*f(z) + c*f(gz) 中的前一项表明这一轮的输入,而后一项表明的是上一层的输出有多少百分比可以影响到这一层的输出。f(gz)就是那个百分比,c是上一轮的输出
  6. z0,输出门,同理,他也会经过一个sigmod函数规范到0-1之间并乘上c'来表明输出百分比

23333笔者的文字功底实在是捉急....但是思路还是很清晰的hhh,其实也就是说在rnn的基础上给每一次计算中【上一轮输出,本轮输入,本轮输出这三个值都作一个百分比的取舍】

那么有人就会问了:

z,z0,zf这三个值又是怎么来的呢?难道又是新的参数需要训练优化?

用讲义中的另一张图回答第一个问题:

在图中x1,x2相当于本轮的输入数据a=[x1,x2]

而z,z0,zf都是由这两个数据产生的,如何产生,带权重相乘再相加!23333

  1. z = w1*x1 + w2*x2
  2. z0 = w3*x1 + w4*x2
  3. zf = w5*x5 + w6*x6

就这么简单!

而至于第二个问题,是的!上面的w1,w2,w3,w4,w5,w6都是需要通过训练得到的

这样子是不是差不多就懂了呢?

接下来就和RNN一样了,如果多层地话就一层一层的堆上去!

总结

本文仅仅对RNN和LSTM做简单的介绍,主要聚焦在其基础结构以及正向传播的过程,对于一些更加高深的内容比如双向rnn,attention机制等都没有涉及。下一篇会带来的是:

基于机器学习的攻击检测(二)下-基于lstm实现

编辑于 2019-03-09