神经网络是在人工智能界是比较流行的一种模型。发展到今日已经有很多变种,想cnn,rnn,LSTM,对抗神经网络,等等很多网络结构,网上也有很多比较详细的解释,最近系统的学习了一下神经网络,包括网络结构细节,激活函数,正向传播,反向传播的推导,梯度的计算,过拟合的解决方式等等,想要系统的学习神经网络的同学看过来吧。嘿嘿!
单层神经网络结构
先从最简单的开始理解神经网络,如图(1),这是一个最简单的神经网络结构
输入为:x1,x2,….xn。每个输入都对应一个权重w,那么将数据集x输入到神经元里面会有什么操作呢?如图(2)
数据X输入到神经元后会经过两个操作:“a(x)”,和”h(x)” 后才能输出到下一个神经元中。我们也把a(x)称为pre-activation,h(x)称为post-activation,也就是第一步和第二步的意思。我们先看第一步a(x),a(x)是指对利用权重对数据进行一次线性转换,如公式(1)
简单来说就是将输入集<x1,x2,…xn>乘以对应权重<w1,w2…wn>加上一个偏置。
第二步h(x)是指的对a(x)进行一次非线性的转换,如公式(2)
g(x)指的是激活函数,也就是对数据进行非线性转换的函数。如tanh,sigmold,relu等
那么问题来了,为什么要进行非线性的转换?
假设我们去掉h(x)这一步,每个神经元只经过a(x)也就是只有线性转换,那么我们的数据从第一个神经元到下一个神经元的过程就是
a1(a(x))=w1T(a(x))+b1再到下一个神经元为:
a2(a1(a(x)))=W2Ta1(a(x))+b2
假定到此结束准备输出,我们展开公式:
a2(a1(a(x)))=W2Ta1(a(x))+b2=W2T(W1Ta(x)+b1)+b2=W2T(W1T(WTX+b)+b1)+b2=W2TW1TWTX+W2TW1Tb+W2Tb1+b2
由于W和b是常数,因此
W2TW1TWTX可以写成
WcTX,还有
W2TW1Tb+W2Tb1+b2可以写成
bc这样公式就可以写成:
a2(a1(a(x)))=WcTX+bc
这样大家就会发现我们加这么多层神经元是没有意义的,最后还是变成一层的样子,所以我们在a(x)后加了非线性转换h(x)这样保证每层都是有意义的。因此激活函数比较的选择也是比较重要的
有意思的现象
如图(3)当单层神经网络,只有一个神经元并且激活函数是sigmold时,是此时
a(x)=WTX+b,
g(x)=1+e−x1
那么此时:
输出=h(x)=g(wTx+b)=1+e−(wTx+b)1
而逻辑回归为:
p(y∣x)=1+e−(wTx+b)1
所以说逻辑回归是神经网络的一个特例
常见的激活函数:
Linear activation(线性激活函数)
公式:
g(a)=a
直接输出,没有任何意义,没有边界,输出多层相当于一层
Sigmold函数:
公式:
g(a)=1+e−a1
将输入映射到(0,1)之间 严格递增的函数
Tanh函数::
公式:
y(a)=tanh(a)=ea+e−aea−e−a
将输入映射到(1,-1)之间 严格递增的函数
Relu:
公式:
g(a)=ReLu(a)=max(0,a)
当a小于0时强制转换为0,严格递增的函数 无上限
隐含层的神经网络结构
上面讲的是只有一层直接输出的单层神经网络,下面说一下带有隐含层的神经网络,如图(4)
图(4)隐含层的网络结构
每一节点的细节都可以表示成图(5)
a(x)(i)表示第
i层神经元的pre-activation
a(x)(i)=<a(x1)(i),a(x2)(i),a(x3)(i)...a(xn)(i)>
h(x)(i)表示第
j层神经元的post-activation
h(x)(i)=<h(x1)(i),h(x2)(i),h(x3)(i)...h(xn)(i)>
W(i)表示第
j层神经元的权重
W(i)=<w1(i),w2(i),w3(i),w4(i)...,wn(i),>
第一层可以表示成:
a(x)(1)=W(1)TX+b(1)
h(x)(1)=g(a(x)(1))
由第一层输入到第二层可以表示成:
a(x)(2)=W(1)Th(x)(2)+b(2)
h(x)(2)=g(a(x)(2))
因此第k层可以表示成:
a(x)(k)=Wkh(x)k−1+b(k)
h(x)(k)=g(a(x)(k))
输出层的激活函数一般设置为softmax也就是
g(x)=σ(x)若在第l层输出
a(x)(l)=Wlh(x)l−1+b(l)
h(x)(l)=g(a(x)(l))=σ(a(x)(l))
通常为了区分最后一层的激活函数与其他层不同,我们也常常设置
f(x)=h(x)(l)
根据上面的步骤一直计算,直到最后一层输出
f(x)也就是完成了神经网络的正向传播
反向传播
假设数据标签为
y下一步我们要计算
y与
f(x)之间的差距,差距越小说明我们的模型越优秀,所以反向传播的目的就是不断减小
y与
f(x)之间的差距。所以神经网络的目标函数为公式:
argmin:T1∑∗φ(f(x(t);θ),y(t))+λΩ(θ)
θ表示神经网络的所以参数:
θ={(W(i),b(i))i=1l+1}
f(x(t);θ)表示t时刻参数为
θ时模型的输出
y(t)表示t时刻的数据集标签
λΩ(θ)表示限制参数的正则
φ(x,y)表示损失函数,也就是技术
x和y的差异,常见的有交叉熵函数
目标函数可以转换成:
argmax:−T1∑∗φ(f(x(t);θ),y(t))−λΩ(θ)
像这样求目标函数的最大化时,我们最常用的就是随机梯度下降法(SGD):
第一步:初始化
θ={W(1),b(1),...,W(l+1),b(l+1)}
第二步:循环每个batch: for batch in
(xt,yt):
循环体内部执行:
1、
Δ=−∇φ(f(x(t);θ),y(t))−λ∇Ω(θ)
2、
θ=θ+ηΔ
η:表示步长
这两步也叫做bp算法
也就是说bp算法的核心目的就是求loss(损失函数)对于
θ的导数,也就是求解:
∂w(k)∂loss和
∂b(k)∂loss但是求这两个往往不能直接计算,因此必须依赖它传递的流程,从后往前依次求导,最后才能求出参数
θ的导数
所以按照参数传递的顺序,可以分成5个部分:
1、f(x)作为最后一层的输出:
∂f(x)∂loss
2、
a(x)(l)最后一层的pre-activation:
∂a(x)(l)∂loss
3、
h(x)(k):激活后:
∂h(x)(k)∂loss
4、
a(x)(k):激活前:
∂a(x)(k)∂loss
5、
W(k)和b(k)参数:
∂w(k)∂loss和
∂b(k)∂loss
交叉熵
在计算梯度之前先来理解一下损失函数,常用的就是交叉熵
举个例子:
多分类问题:让神经网络判断输入的文本属于哪一类(共四类)
假设模型的输出为:属于第一类的概率为
f(x)1=0.5,属于第二类的概率为
f(x)2=0.3,属于第三类的概率为
f(x)3=0.1,属于第四类的概率为
f(x)4=0.1,写成向量的形式就是
⎣⎢⎢⎡(0.5)(0.3)(0.1)(0.1)⎦⎥⎥⎤,假如标签
y=2对应成one-hot编码:
⎣⎢⎢⎡0100⎦⎥⎥⎤,则由交叉熵计算出的loss等于:
loss=(0×log0.5+1×log0.3+0×log0.1+0×log0.1)=−log0.3
因此交叉熵的损失函数为:
φ(f(x)(i),y(i))=−∑cI(y=c)⋅logf(x)c=−logf(x)y
I(y=c)={1y=c0y=c
BP算法推导
计算输出层的激活函数的梯度
1、根据BP算法的核心思想首先计算输出层第c个神经元也就是
f(x)c的梯度的梯度:
∂f(x)c∂loss
∂f(x)c∂loss=∂f(x)c∂−logf(x)y=−f(x)y1⋅∂f(x)c∂f(x)y=−f(x)y1⋅I(y=c)
2、既然计算出输出层第c个神经元的梯度,下面计算整个输出层的梯度
∂f(x)∂loss=−f(x)y1⋅⎣⎢⎢⎢⎢⎡I(y=1)I(y=2)I(y=3)...I(y=k)⎦⎥⎥⎥⎥⎤=−f(x)ye(y)
用这里只是用
e(y)来表示
⎣⎢⎢⎢⎢⎡I(y=1)I(y=2)I(y=3)...I(y=k)⎦⎥⎥⎥⎥⎤
计算输出层的pre-activation的梯度
主要是用来计算
a(x)(l)最后一层的-activation:
∂a(x)(l)∂loss
首先来计算第c神经元的向量
a(x)c(l):
∂a(x)c(l)∂loss=∂a(x)c(l)∂−logf(x)y=−f(x)y1⋅∂a(x)c(l)∂f(x)y=−f(x)y1⋅∂a(x)c(l)∂⋅∑c⋅e(a(x)c⋅(l))e(a(x)y(l))
=−f(x)y1
⋅(∑c⋅e(a(x)c⋅(l))∂a(x)c(l)∂e(a(x)y(l))−(∑c⋅e(a(x)c⋅(l)))2e(a(x)y(l))⋅∂a(x)c(l)∂∑c⋅e(a(x)c⋅(l)))
=−f(x)y1⋅
(∑c⋅e(a(x)c⋅(l))e(a(x)y(l))⋅I(y=c)−∑c⋅e(a(x)c⋅(l))⋅∑c⋅e(a(x)c⋅(l))e(a(x)y(l))⋅e(a(x)c(l)))
=−f(x)y1
⋅
(softmax((a(x)y(l)))⋅I(y=c)−softmax((a(x)y(l)))⋅softmax((a(x)c(l))))
=−f(x)y1(f(x)y⋅I(y=c)−f(x)y⋅f(x)c)
=−(I(y=c)−f(x)c)=f(x)c−I(y=c)
最后计算出:
∂a(x)c(l)∂loss=f(x)c−I(y=c)
这只是计算输出层第c个神经元的pre-activation,那么计算输出层的pre-activation就是 (参考第一步):
∂a(x)(l)∂loss=f(x)−e(y)
计算隐藏层的post-activation的梯度
计算每层 的post-activation,也就是计算
h(x)(k):
∂h(x)(k)∂loss
还是先计算第c个神经元的post-activation:
∂h(x)c(k)∂loss
直接求
∂h(x)c(k)∂loss比较难求,我们来做一个转换也叫梯度的链式求解法则:
所以我们采用链式求解法则进行计算:
∂h(x)c(k)∂loss=
∑i∂a(x)i(k+1)∂loss⋅∂h(x)c(k)∂a(x)i(k+1)
=
∑i∂a(x)i(k+1)∂−logf(x)y⋅∂h(x)c(k)∂∑jWij(k+1)⋅h(x)j(k)
=
∑i∂a(x)i(k+1)∂−logf(x)y⋅Wij(k+1)=(W.j(k+1))T⋅∂a(x)(k+1)∂−logf(x)y
对于k层的所有神经元的梯度计算:
∂h(x)(k)∂loss=(W(k+1))T⋅∂a(x)(k+1)∂−logf(x)y
计算隐藏层的pre-activation的梯度
同理,我们先计算第k层第c个神经元的pre-activation:
∂a(x)c(k)∂loss
∂a(x)c(k)∂loss=
∂h(x)c(k)∂loss⋅∂a(x)c(k)∂h(x)c(k)=∂h(x)c(k)∂loss⋅g′(a(x)c(k))
对于k层所有神经元post-activation计算:
∂a(x)(k)∂loss=∂h(x)c(k)∂loss⊙g′(a(x)(k))
计算参数
w和b的梯度
先计算k层第i个神经元对应的第j个权重
wij(k):
∂wij(k)∂loss
∂wij(k)∂loss=∂a(x)i(k)∂loss⋅∂wij(k)∂a(x)i(k)=∂a(x)i(k)∂loss⋅∂wij(k)∂∑jWij(k)⋅h(x)j(k−1)+bij(k)=∂a(x)i(k)∂loss⋅h(x)j(k−1)
对于k层所有的权重
w(k):
∂w(k)∂loss=∂a(x)(k)∂loss⋅(h(x)(k−1))T
再计算k层第i个神经元对应的第j个偏置
bij(k):
∂bij(k)∂loss
∂bij(k)∂loss=∂a(x)i(k)∂loss⋅∂bij(k)∂a(x)i(k)=∂a(x)i(k)∂loss⋅∂bij(k)∂∑jWij(k)⋅h(x)j(k−1)+bij(k)=∂a(x)i(k)∂loss
对于k层所有的权重
b(k):
∂b(k)∂loss=∂a(x)(k)∂loss
BP算法总结
根据上面有一点点小复杂的计算我们可以知道:
输出层的梯度:
∇f(x)=−f(x)ye(y)
∇a(x)(l)=f(x)−e(y)
隐藏层的梯度:
∇h(x)(k)=(W(k+1))T⋅∇a(x)(k+1)
∇a(x)(k)=∇h(x)(k)⊙g′(a(x)(k))
参数的梯度:
∇w(k)=∇a(x)(k)⋅(h(x)(k−1))T
∇b(k)=∇a(x)(k)
总结
所以神经网络计算大约有3步:
1、前向计算
2、反向传播计算梯度
3、更新参数
到此一个基本神经网络的就了解的差不多了下面,再聊一下RNN吧
循环神经网络(RNN)
在我们的生活中是有很多的时序性的数据,比如:语音,天气,股票,文本都是随时间的 变化而变化的,为了处理这样的数据,设计了一种循环神经网络也叫递归神经网络RNN如图(6)
如图(6)所示t=1时刻时我们输入数据
x1,和神经网络一样先进行线性的转化pre-activation在进行非线性的转化post-activation :
当
t=1时:
h1=f(wx1⋅x1+wh1⋅h0+bt1)
f(x)表示激活函数,
h0一般设置为0 ,
bt1表示偏置
y1=g(wy1⋅h1+bi1)
g(x)表示激活函数,
bi1表示输出层的偏置
当
t=2时:
h2=f(wx2⋅x2+wh2⋅h1+bt2)
f(x)表示激活函数 ,
bt2表示偏置
y2=g(wy2⋅h2+bi2)
当
t=n时:
hn=f(wxn⋅xn+whn⋅h(n−1)+btn)
yn=g(wyn⋅hn+bin)
从公式中我们可以看出当时间到了
n时
hn不仅包含了当前数据信息,还包含了前面数据的信息,那对应输出的
yn也是包含整个文本信息的输出,假设n为最后一层,我们常常用
yn来表示句子信息和段落信息用来处理我们的下游任务。
而且每一层都会有损失函数的计算,所有损失函数是:
loss=∑inlossi
可以看出rnn是随着时间的增加,层数也在不断的增加,因此,rnn是在时间维度上的Deep Model
梯度消失和梯度爆炸的问题
为什么会出现梯度消失和梯度爆炸的问题呢?我们用数学公式来进行说明:
在rnn中假设我们计算
t=4时刻的对
h1的梯度,也就
loss4时的梯度:
∂h1∂l4
一般情况下我们无法直接计算
∂h1∂l4,因此使用链式求导法则来进行计算 :
∂h1∂l4=∂h2∂l4⋅∂h1∂h2=∂h3∂l4⋅∂h2∂h3⋅∂h1∂h2=∂h4∂l4⋅∂h3∂h4⋅∂h2∂h3⋅∂h1∂h2
将计算过程扩展一下为:
∂hj∂li=∂hi∂li⋅∏j≤t≤i∂ht−1∂ht
若激活函数用sigmold则:
ht=σ(wxt⋅xt+wht⋅h(t−1)+btt)
∂ht−1∂ht=diag(σ、(wxt⋅xt+wht⋅h(t−1)+btt))⋅wht
diag:指的是对矩阵的处理,因为
ht和
ht−1是向量的形式,因此求导的结果是矩阵。因此:
∂hj∂li=∂hi∂li⋅∏j≤t≤idiag(σ、(wxt⋅xt+wht⋅h(t−1)+btt))⋅wht
根据公式我们可以看出,当
j>i很多时,计算
∂hj∂li我们需要乘以很多很多的项,如果这些项都小于0的话,那在计算梯度时会越乘越小,有可能导致梯度很小导致梯度消失,如果这些项都大于0的话就会越乘越大,就有可能导致梯度爆炸。
LSTM和GRU
由上面我们知道,rnn有可能造成梯度消失的问题(爆炸的问题比较好解决就不细说了)这样就会带来特征提取的不够长,因此我们又发明了LSTM和GRU
从图(7)我们可以看出RNN和LSTM还有GRU外形其实是差不多,只是LSTM和GRU比RNN多了几个门,也就是多了几个操作,我们先看一下
LSTM在神经元内部的操作
:
f(t)=σ(uf⋅xt+wf⋅ht−1+bf)
(1)
(uf,wf,bf)
i(t)=σ(ui⋅xt+wi⋅ht−1+bi)
(2)
(ui,wi,bi)
o(t)=σ(uo⋅xt+wo⋅ht−1+bo)
(3)
(uo,wo,bo)
c(t)=tanh(uc⋅xt+wc⋅ht−1+bc)
(4)
(uc,wc,bc)
c(t)=f(t)⊙c(t−1)+i(t)⊙c(t)
(5)
h(t)=o(t)⊙tanh(c(t))
(6)
从式(5)中可以看出
f(t)是用来决定上一层获取的信息量
f(t)=1就是指全部获取
f(t)=0就是指遗忘上一层所有信息。
c(t)表示获取额外信息量,
i(t)表示决定获取
c(t)的大小
可以看出
h(t)计算时有选择性的记忆上次信息和获取当前信息。
GRU
u(t)=σ(uu⋅xt+wu⋅ht−1+bu)
(1)
(uu,wu,bu)
r(t)=σ(ur⋅xt+wr⋅ht−1+br)
(2)
(ur,wr,br)
h(t)=tanh(wh⋅(uh⋅xt+r(t)⋅ht−1+bh))
(3)
(uh,wh,bh)
h(t)=(1−u(t))⋅h(t−1)+u(t)⋅h(t)
(4)
从(4)中我们可以看到
h(t−1)表示旧的信息,
h(t)表示新的信息,而
u(t)是做的加权平均的操作,也就是有百分之多少记忆旧的信息,有百分之多少获取新的信息。参数和运算要比LSTM少很多,速度也相对快一些
结束
好了神经网络的知识就介绍到这里,博主肝了两天,码字不易,还请各位转载标明出处,当然有什么不懂的或者是我错误的地方,及时留言哦,欢迎大家交流!!