Lecture7: Backpropagation
接着上一课Logistic Regression,这一课在逻辑回归基础上建立了神经网络,neural network。如下,框框里面就是一个逻辑回归。层数多了就是Deep Learning。
和机器学习的步骤基本完全相同,只是第一步选取function set选为神经网络,deep learning步骤如下:
step1: neural network
step2: goodness of function
step3: pick the best function
Neural Network说到底就是matrix的运算,有种嵌套的感觉。
a
1
=
σ
(
ω
1
x
+
b
1
)
a_1=\sigma(\omega^1x+b^1)
a1=σ(ω1x+b1)—>
a
2
=
σ
(
ω
2
a
1
+
b
2
)
a_2=\sigma(\omega^2a^1+b^2)
a2=σ(ω2a1+b2)—>
a
3
=
σ
(
ω
3
a
2
+
b
3
)
a_3=\sigma(\omega^3a^2+b^3)
a3=σ(ω3a2+b3)…
y
=
σ
(
ω
l
a
l
−
1
+
b
l
)
y=\sigma(\omega^la^{l-1}+b^l)
y=σ(ωlal−1+bl)<=>
y
=
f
(
x
)
y=f(x)
y=f(x)
Step1需要做的就是选取这个神经网络的大概结构,比如有多少层,是不是fully-connected(点对点),有没有maxpolling层,softmax还是ReLu等。
Step2: goodness of function -->Gradient Descent
既然选取完神经网络模型之后,就要判断这个模型是否好,并选取最佳模型。还是得用到之前的梯度降落,但是之前只有一个neural,现在能有几百个,每个neural有十几个参数,那算下来能有成千上万个参数了。
有效的方法? Backpropagation反向传播 :单个样本的loss function对参数的导数
链式法则:之后的逆向推导会用到
BP算法需要了解以下Forward Pass向前传播和Backward Pass反向传播。
Forward Pass:
compute
∂
z
∂
ω
\frac{\partial z}{\partial \omega}
∂ω∂zfor all parameters
是从前往后的一种算法,一层network一层的往里,依次算出所有的z值,最后到y值。
Backward Pass
compute
∂
c
∂
z
\frac{\partial c}{\partial z}
∂z∂cfor all activation function inputs
z
z
z.
带入到前面的式子:
∂
c
∂
z
=
σ
′
(
z
)
[
ω
3
∂
c
∂
z
′
+
ω
4
∂
c
∂
z
′
′
]
\frac{\partial c}{\partial z}=\sigma'(z)[\omega_3\frac{\partial c}{\partial z'}+\omega_4\frac{\partial c}{\partial z''}]
∂z∂c=σ′(z)[ω3∂z′∂c+ω4∂z′′∂c]这就是bp算法的核心。
一个好的理解(copy):
BackPropagation算法是多层神经网络的训练中举足轻重的算法。简单的理解,它的确就是复合函数的链式法则,但其在实际运算中的意义比链式法则要大的多。需要先直观理解多层神经网络的训练。
机器学习可以看做是数理统计的一个应用,在数理统计中一个常见的任务就是拟合,也就是给定一些样本点,用合适的曲线揭示这些样本点随着自变量的变化关系.
对应表达式为:
深度学习同样也是为了这个目的,只不过此时,样本点不再限定为(x, y)点对,而可以是由向量、矩阵等等组成的广义点对(X,Y)。而此时,(X,Y)之间的关系也变得十分复杂,不太可能用一个简单函数表示。然而,人们发现可以用多层神经网络来表示这样的关系,而多层神经网络的本质就是一个多层复合的函数。借用网上找到的一幅图[1],来直观描绘一下这种复合关系。和直线拟合一样,深度学习的训练也有一个目标函数,这个目标函数定义了什么样的参数才算一组“好参数”,不过在机器学习中,一般是采用成本函数(cost function),然后,训练目标就是通过调整每一个权值Wij来使得cost达到最小。cost函数也可以看成是由所有待求权值Wij为自变量的复合函数,而且基本上是非凸的,即含有许多局部最小值。但实际中发现,采用我们常用的梯度下降法就可以有效的求解最小化cost函数的问题。
梯度下降法需要给定一个初始点,并求出该点的梯度向量,然后以负梯度方向为搜索方向,以一定的步长进行搜索,从而确定下一个迭代点,再计算该新的梯度方向,如此重复直到cost收敛。那么如何计算梯度呢?
假设我们把cost函数表示为
H
(
W
11
,
W
12
,
⋯
,
W
i
j
,
⋯
,
W
m
n
)
H(W11,W12,⋯,Wij,⋯,Wmn)
H(W11,W12,⋯,Wij,⋯,Wmn)
,那么它的梯度向量[2]就等于
∇
H
=
∂
H
∂
W
11
e
11
+
.
.
.
+
∂
H
∂
W
m
m
e
m
n
∇H=\frac{∂H}{\partial W_{11}}e_{11}+...+\frac{\partial H}{\partial W_{mm}}e_{mn}
∇H=∂W11∂He11+...+∂Wmm∂Hemn
, 其中
e
i
j
eij
eij表示正交单位向量。为此,我们需求出cost函数H对每一个权值
W
i
j
Wij
Wij的偏导数。而BP算法正是用来求解这种多层复合函数的所有变量的偏导数的好方法。
我们以求e=(a+b)*(b+1)的偏导[3]为例。
它的复合关系画出图可以表示如下:
在图中,引入了中间变量c,d。
为了求出a=2, b=1时,e的梯度,我们可以先利用偏导数的定义求出不同层之间相邻节点的偏导关系,如下图所示。
利用链式法则:
∂
e
∂
a
=
∂
e
∂
c
⋅
∂
c
∂
a
以
及
∂
e
∂
b
=
∂
e
∂
c
⋅
∂
c
∂
b
+
∂
e
∂
d
⋅
∂
d
∂
b
\frac{\partial e}{\partial a}=\frac{\partial e}{\partial c}\cdot \frac{\partial c}{\partial a}以及\frac{\partial e}{\partial b}=\frac{\partial e}{\partial c}\cdot \frac{\partial c}{\partial b}+\frac{\partial e}{\partial d}\cdot \frac{\partial d}{\partial b}
∂a∂e=∂c∂e⋅∂a∂c以及∂b∂e=∂c∂e⋅∂b∂c+∂d∂e⋅∂b∂d
链式法则在上图中的意义是什么呢?其实不难发现,
∂
e
∂
a
\frac{∂e}{∂a}
∂a∂e的值等于从a到e的路径上的偏导值的乘积,而
∂
e
∂
b
\frac{∂e}{∂b}
∂b∂e的值等于从b到e的路径
1
(
b
−
c
−
e
)
1(b-c-e)
1(b−c−e)上的偏导值的乘积加上路径
2
(
b
−
d
−
e
)
2(b-d-e)
2(b−d−e)上的偏导值的乘积。也就是说,对于上层节点p和下层节点q,要求得
∂
p
∂
q
\frac{∂p}{∂q}
∂q∂p,需要找到从q节点到p节点的所有路径,并且对每条路径,求得该路径上的所有偏导数之乘积,然后将所有路径的 “乘积” 累加起来才能得到
∂
p
∂
q
\frac{∂p}{∂q}
∂q∂p的值。
这样做是十分冗余的,因为很多路径被重复访问了。比如上图中,a-c-e和b-c-e就都走了路径c-e。对于权值动则数万的深度模型中的神经网络,这样的冗余所导致的计算量是相当大的。
同样是利用链式法则,BP算法则机智地避开了这种冗余,它对于每一个路径只访问一次就能求顶点对所有下层节点的偏导值。 正如反向传播(BP)算法的名字说的那样,BP算法是反向(自上往下)来寻找路径的。
从最上层的节点e开始,初始值为1,以层为单位进行处理。对于e的下一层的所有子节点,将1乘以e到某个节点路径上的偏导值,并将结果“堆放”在该子节点中。等e所在的层按照这样传播完毕后,第二层的每一个节点都“堆放”些值,然后我们针对每个节点,把它里面所有“堆放”的值求和,就得到了顶点e对该节点的偏导。然后将这些第二层的节点各自作为起始顶点,初始值设为顶点e对它们的偏导值,以”层”为单位重复上述传播过程,即可求出顶点e对每一层节点的偏导数。
以上图为例,节点c接受e发送的1x2并堆放起来,节点d接受e发送的1x3并堆放起来,至此第二层完毕,求出各节点总堆放量并继续向下一层发送。节点c向a发送2x1并对堆放起来,节点c向b发送2x1并堆放起来,节点d向b发送3x1并堆放起来,至此第三层完毕,节点a堆放起来的量为2,节点b堆放起来的量为21+31=5, 即顶点e对b的偏导数为5.
举个不太恰当的例子,如果把上图中的箭头表示欠钱的关系,即c→e表示e欠c的钱。以a, b为例,直接计算e对它们俩的偏导相当于a, b各自去讨薪。a向c讨薪,c说e欠我钱,你向他要。于是a又跨过c去找e。b先向c讨薪,同样又转向e,b又向d讨薪,再次转向e。可以看到,追款之路,充满艰辛,而且还有重复,即a, b 都从c转向e。
而BP算法就是主动还款。e把所欠之钱还给c,d。c,d收到钱,乐呵地把钱转发给了a,b,皆大欢喜。
Lecture 8:keras小用法
对于初学者来说,keras真的非常友善了,简单易懂又很强大,非常符合建立神经网络的正向思维。几分钟就能搭建好一个network。
1. define a set of function
model = Sequential()
#先宣告一个model,下面决定长什么样
-------------------------------------------------------
model.add(Dense(input_dim = 28*28, output_dim = 500))
# dense表示Fully-connected layer,当然也可以改为convolution(只有有project详解)
# 输入为28*28的vector,输出为500个neural。
model.add(Activation('sigmoid'))
# 用sigmoid当作activation function
------------------------------------------------------
model.add(Dense(output_dim = 500))
# 输出为500个,input是上一层输出,所以不用input
model.add(Activation('sigmoid'))
------------------------------------------------------
model.add(Dense(output_dim = 10))
# output设为10维
model.add(Activation('Softmax'))
2. goodness of function (training 部分)
model.compile(loss ='categorical crossentropy', optimizer = 'adam', metrics = ['accuracy'])
# 这部分是先选取了损失函数loss function为交叉熵,然后求最佳解的方式为adam,最后用accuracy显示。
3. pick the best function
Find the optimal network parameters
model.fit(x_train, y_train, batch-size = 100, nb_epoch = 20)
# x_train, y_train每个都是2维的,除了参数,还有number of examples.
# batch_size 告诉keras一个batch有多大,一次有多少个样本,每个batch是一个轮回training
# 当batch_size = 1 ---> stochastic gradient descent
# nb_epoch ---> 总共update多少次batch
4. testing part
这一部分,就是要验证我们选择的model是否是好的,正确率是否大,error是否小。
case1:
score = model.evaluate(x_test, y_test)
print('total loss on test set:', score[0])
print('accuracy of testing set:', score[1])
# 计算这个test的正确率
case2:
result = model.predict(x_test)
# 计算分类结果
Lecture9: Tips for training DNN
- 没办法在training set上给出好的正确率
- training set上给你好结果,testing set上结果很差。
- 需要修改前面的参数才能给出好结果。
1.vanishing gradient problem and exploding gradient problem
梯度消失
在神经网络中,当前面隐藏层的学习速率低于后面隐藏层的学习速率,即随着隐藏层数目的增加,分类准确率反而下降了。这种现象叫做消失的梯度问题。
通俗的说,不同的层学习的速度差异很大,表现为网络中靠近输出的层学习的情况很好,靠近输入的层学习的很慢,有时甚至训练了很久,前几层的权值和刚开始随机初始化的值差不多。因此,梯度消失、爆炸,其根本原因在于反向传播训练法则,属于先天不足。
两种情况下梯度消失经常出现,一是在深层网络中,二是采用了不合适的损失函数,比如sigmoid。梯度爆炸一般出现在深层网络和权值初始化值太大的情况下,下面分别从这两个角度分析梯度消失和爆炸的原因。
1.1 深层网络角度 (copy)
图中是一个四层的全连接网络,假设每一层网络激活后的输出为
f
i
(
x
)
f_i(x)
fi(x),其中
i
i
i为第
i
i
i层,
x
x
x代表第
i
i
i层的输入,也就是第
i
−
1
i−1
i−1层的输出,
f
f
f是激活函数,那么,得出
f
i
+
1
=
f
(
f
i
∗
w
i
+
1
+
b
i
+
1
)
f_{i+1}=f(fi∗wi+1+bi+1)
fi+1=f(fi∗wi+1+bi+1),简单记为
f
i
+
1
=
f
(
f
i
∗
w
i
+
1
)
f_{i+1}=f(fi∗wi+1)
fi+1=f(fi∗wi+1)。
BP算法基于梯度下降策略,以目标的负梯度方向对参数进行调整,参数的更新为
w
←
w
+
Δ
w
w \leftarrow w+\Delta w
w←w+Δw,给定学习率
α
\alpha
α,得出
Δ
w
=
−
α
∂
L
o
s
s
∂
w
\Delta w=-\alpha \frac{\partial Loss}{\partial w}
Δw=−α∂w∂Loss。如果要更新第二隐藏层的权值信息,根据链式求导法则,更新梯度信息:
Δ
ω
2
=
∂
L
o
s
s
∂
ω
2
=
∂
L
o
s
s
∂
f
4
⋅
∂
f
4
∂
f
3
⋅
∂
f
3
∂
f
2
⋅
∂
f
2
∂
ω
2
\Delta\omega_2=\frac{\partial Loss}{\partial \omega_2}=\frac{\partial Loss}{\partial f_4}\cdot\frac{\partial f_4}{\partial f_3}\cdot\frac{\partial f_3}{\partial f_2}\cdot\frac{\partial f_2}{\partial\omega_2}
Δω2=∂ω2∂Loss=∂f4∂Loss⋅∂f3∂f4⋅∂f2∂f3⋅∂ω2∂f2,很容易看出来
∂
f
2
∂
ω
2
=
∂
f
∂
(
f
1
∗
ω
2
)
f
1
\frac{\partial f_2}{\partial \omega_2}=\frac{\partial f}{\partial(f_1 * \omega_2)}f_1
∂ω2∂f2=∂(f1∗ω2)∂ff1,即第二隐藏层的输入。所以说,
∂
f
4
∂
f
3
\frac{∂f_4}{∂f_3}
∂f3∂f4就是对激活函数进行求导,如果此部分大于1,那么层数增多的时候,最终的求出的梯度更新将以指数形式增加,即发生梯度爆炸,如果此部分小于1,那么随着层数增多,求出的梯度更新信息将会以指数形式衰减,即发生了梯度消失。
1.2 激活函数角度
上文中提到计算权值更新信息的时候需要计算前层偏导信息,因此如果激活函数选择不合适,比如使用sigmoid,梯度消失就会很明显了,原因看下图,如果使用sigmoid作为损失函数,其梯度是不可能超过0.25的,这样经过链式求导之后,很容易发生梯度消失,sigmoid函数数学表达式为:
s
i
g
m
o
i
d
(
x
)
=
1
1
+
e
(
−
x
)
sigmoid(x)=\frac{1}{1+e^(-x)}
sigmoid(x)=1+e(−x)1
解决方案:
替换激活方差Activation Function
1.2.1 Rectified Linear Unit(ReLU)
思想很简单,如果激活函数导数为1,那么就不存在梯度消失爆炸的问题了,每一层的网络都可以得到相同的更新了。
其导数图像为:
从上图中,我们可以很容易看出,relu函数的导数在正数部分是恒等于1的,因此在深层网络中使用relu激活函数就不会导致梯度消失和爆炸的问题。
ReLU的优点:
- 解决了梯度消失,爆炸问题。
- 计算方便且快。
- 加速了网络的训练。
- 解决了梯度消失
ReLU的缺点:
- 由于附属部分恒为0,会导致一些神经元无法激活(小学习率解决)。
- 输出不是以0为中心。
- 变成linear?可是我们需要nonlinear。
ReLU— Variant
leakrelu就是为了解决relu的0区间带来的影响,其数学表达为:
l
e
a
k
r
e
l
u
=
m
a
x
(
k
∗
x
,
x
)
leakrelu=max(k∗x,x)
leakrelu=max(k∗x,x)其中k是leak系数,一般选择0.01或者0.02,或者通过学习而来。
leakrelu解决了0区间带来的影响,而且包含了relu的所有优点
1.2.2 Maxout
与常规激活函数不同的是,maxout是一个可学习的分段线性函数.
然而任何一个凸函数,都可以由线性分段函数进行逼近近似。其实我们可以把以前所学到的激活函数:ReLU、激活函数,看成是分成两段的线性函数。
此部分没理解,后面会开专题。
https://blog.youkuaiyun.com/hjimce/article/details/50414467
2. Gradient descent的优化
Review of Adaptive Learning Rate
point是说如果有两个方向,一个梯度大的会给小的learning rate, 一个gradient小的会给大的learning rate。
ω t + 1 \omega^{t+1} ωt+1<— ω t − η ∑ i = 0 t g t \omega^t-\frac{\eta}{\sqrt{\sum_{i=0}^{t}}}g^t ωt−∑i=0tηgt
可见分子是用来抑制过快获得增长过慢的,但更多情况是error surface更加复杂呢?
进阶版:RMSProp
RMSprop是Geoff Hinton提出的一种自适应学习率方法。Adagrad会累加之前所有的梯度平方,而RMSprop仅仅是计算对应的平均值,因此可缓解Adagrad算法学习率下降较快的问题。
优化方法后面会开专题总结。
若在Training data 上的结果很好,Testing data上的不好怎么办?
1. Early Stopping
2. Regularization
L1和L2正则
3. Dropout
每次更新参数之前,对每个neural(包括input)做sampling,每个neural有一定的几率被丢掉,最后变成细长的network。
Training的时候需要dropout,testing时候不需要dropout,但是要multiply
(
1
−
p
)
(1-p)
(1−p)%
Supervised Learning还剩下CNN没有总结,不过会单独开一个CNN的专题总结。