Coursera deeplearning.ai 深度学习笔记1-3-Shallow Neural Networks-浅层神经网络原理推导与代码实现
2017-12-11 20:17
971 查看
在掌握了逻辑回归算法后,先来学习浅层神经网络,之后再对深度神经网络进行学习。
定义:上标[l]表示第l层,下标j表示第j个节点。
例如,下图为2层神经网络,包含1个隐藏层:
输入层和隐含层可以写成:
a[0]=x=⎡⎣⎢x1x2x3⎤⎦⎥,a[1]=⎡⎣⎢⎢⎢⎢⎢⎢a[1]1a[1]2a[1]3a[1]4⎤⎦⎥⎥⎥⎥⎥⎥(1)
z[1]1=w[1]T1x+b[1]1,a[1]1=g(z[1]1)z[1]2=w[1]T2x+b[1]2,a[1]2=g(z[1]2)z[1]3=w[1]T3x+b[1]3,a[1]3=g(z[1]3)z[1]4=w[1]T4x+b[1]4,a[1]4=g(z[1]4)(2)
式中,g(z)为激活函数。可将上式向量化为:
⎡⎣⎢⎢⎢⎢⎢⎢z[1]1z[1]2z[1]3z[1]4⎤⎦⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢−−−−w[1]T1w[1]T2w[1]T3w[1]T4−−−−⎤⎦⎥⎥⎥⎥⎥⎥⎡⎣⎢x1x2x3⎤⎦⎥+⎡⎣⎢⎢⎢⎢⎢⎢b[1]1b[1]2b[1]3b[1]4⎤⎦⎥⎥⎥⎥⎥⎥,⎡⎣⎢⎢⎢⎢⎢⎢a[1]1a[1]2a[1]3a[1]4⎤⎦⎥⎥⎥⎥⎥⎥=g⎛⎝⎜⎜⎜⎜⎜⎜⎡⎣⎢⎢⎢⎢⎢⎢z[1]1z[1]2z[1]3z[1]4⎤⎦⎥⎥⎥⎥⎥⎥⎞⎠⎟⎟⎟⎟⎟⎟(3)
即:
z[1]=W[1]x+b[1],a[1]=g(z[1])(4)
式中,
z[1]=⎡⎣⎢⎢⎢⎢⎢⎢z[1]1z[1]2z[1]3z[1]4⎤⎦⎥⎥⎥⎥⎥⎥,W[1]=⎡⎣⎢⎢⎢⎢⎢⎢−−−−w[1]T1w[1]T2w[1]T3w[1]T4−−−−⎤⎦⎥⎥⎥⎥⎥⎥,b[1]=⎡⎣⎢⎢⎢⎢⎢⎢b[1]1b[1]2b[1]3b[1]4⎤⎦⎥⎥⎥⎥⎥⎥,a[1]=⎡⎣⎢⎢⎢⎢⎢⎢a[1]1a[1]2a[1]3a[1]4⎤⎦⎥⎥⎥⎥⎥⎥(5)
因此,对于该2层神经网络的每个样本,给定a[0] = x,正向传播计算流程如下:
z[1]=W[1]a[0]+b[1]a[1]=g(z[1])z[2]=W[2]a[1]+b[2]a[2]=g(z[2])(6)
各矩阵维度如下表:
以上推导仅仅针对单个样本,对于m个样本,以上标(m)表示第m个样本。则可以将公式改写为:
⎡⎣⎢|z[1](1)||z[1](2)||⋯||z[1](m)|⎤⎦⎥=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢−−−−w[1]1Tw[1]2Tw[1]3Tw[1]4T−−−−⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎡⎣⎢|x(1)||x(2)||⋯||x(m)|⎤⎦⎥+b[1](7)
⎡⎣⎢|a[1](1)||a[1](2)||⋯||a[1](m)|⎤⎦⎥=g⎛⎝⎜⎡⎣⎢|z[1](1)||z[1](2)||⋯||z[1](m)|⎤⎦⎥⎞⎠⎟(8)
即:
Z[1]=W[1]X+b[1],A[1]=g(Z[1])(9)
式中,
Z[1]=⎡⎣⎢|z[1](1)||z[1](2)||⋯||z[1](m)|⎤⎦⎥,A[1]=⎡⎣⎢|a[1](1)||a[1](2)||⋯||a[1](m)|⎤⎦⎥(10)
因此,对于以上2层神经网络,针对m个样本,给定A[0] = X,正向传播计算流程如下:
Z[1]=W[1]A[0]+b[1]A[1]=g(Z[1])Z[2]=W[2]A[1]+b[2]A[2]=g(Z[2])(11)
各矩阵维度如下表:
从式中可以看出,矩阵Z和A在计算过程中,水平索引遍历所有样本集,垂直索引遍历神经网络每一层的各个节点。
sigmoid函数:在0 ~ 1之间,很少用到,仅仅用于二分类问题。
tanh函数,在-1 ~ 1之间,均值为0,使得数据更集中。
sigmoid和tanh函数的一个共同缺点:当z很大或者很小时,函数的斜率都很小且接近0,从而使得梯度下降法的速度较慢。
ReLU(Rectified Linear Units)函数:通常比sigmoid和tanh函数效果好,是最常用的激活函数。缺点在于,当很大的梯度经过一个ReLU神经元,更新过参数后,这个神经元再也不会对任何数据有激活现象。对于较大的学习因子,经常会发生这个问题。因此,需要设置合适的、较小的学习因子。
Leaky ReLU函数:相比ReLU函数,设置了一个很小的常数α,保留了一些负轴的值,使得负轴信息不会全部丢失。
则正向传播化简为:
z[1]=W[1]a[0]+b[1]a[1]=g(z[1])=z[1]z[2]=W[2]a[1]+b[2]=W[2]z[1]+b[2]a[2]=g(z[2])=z[2]=W[2](W[1]a[0]+b[1])+b[2]=(W[2]W[1])a[0]+(W[2]b[1]+b[2])=W′a[0]+b′(12)
可以看出,a[2]与z[1]等效,如果使用线性激活函数,就无法发挥隐含层的作用。在深度神经网络中,使用线性激活函数,多个隐含层与没有隐含层的效果相同。
因此,必须使用非线性激活函数。
n[0]=nx=3,n[1]=4,n[2]=1(13)
代价函数:
J(w,b)=1m∑i=1mL(a(i),y(i))=−1m∑i=1m[y(i)loga(i)+(1−y(i))log(1−a(i))](14)
梯度下降法流程如下:
Computeactivationa(i),i=1,⋯,mComputecostfunctionJdW[1]=dJdW[1],db[1]=dJdb[1],⋯W[1]=W[1]−αdW[1],b[1]=b[1]−αdb[1],⋯(15)
式中,α为学习因子。为了更新参数W和b,关键在于求解导数dW和db,可以通过反向传播来求解。
z[1]=W[1]a[0]+b[1]a[1]=g(z[1])z[2]=W[2]a[1]+b[2]a[2]=g(z[2])(16)
与逻辑回归类似,反向传播计算如下:
dz[2]=a[2]−ydW[2]=dz[2]a[1]Tdb[2]=dz[2]dz[1]=dJdz[2]⋅dz[2]da[1]⋅da[1]dz[1]=W[2]Tdz[2]∗g[1]′(z[1])dW[1]=dz[1]a[0]Tdb[1]=dz[1](17)
拓展到m个样本得到:
dZ[2]=A[2]−YdW[2]=1mdZ[2]A[1]Tdb[2]=1mnp.sum(dZ[2],axis=1,keepdims=True)dz[1]=W[2]TdZ[2]∗g[1]′(Z[1])dW[1]=1mdZ[1]A[0]Tdb[1]=1mnp.sum(dZ[1],axis=1,keepdims=True)(18)
式中,“*”表示元素点乘。通过上式求出梯度dW和db,并代入梯度下降法中,即可对参数W和b进行更新。
如果将参数全部初始化为0:
W[1]=[0000],b[1]=[00](19)
那么,无论采用什么样本来训练,都会得到:
a[1]1=a[1]2,dz[1]1=dz[1]2(20)
在更新参数的过程中,W始终保持如下的对称形式:
W=[uuvv](21)
这样,a[1]1和a[1]2具体相同的功能,实际上只需要一个就够了。
所以,在初始化神经网络参数时,应当避免以上情况,将参数W随机初始化,为了方便,可以将b全部初始化为0。
另外,根据sigmoid或者tanh函数的特点,当输入较大时,函数的导数较大,会导致学习速度较慢。因此,通常将参数随机初始化为较小的参数:
W=np.random.randn(l,l−1)∗0.01b=np.zeros((l,1))(22)
计算流程如下:
Z[1]=W[1]A[0]+b[1]A[1]=g(Z[1])Z[2]=W[2]A[1]+b[2]A[2]=g(Z[2])(23)
核心代码如下:
J(w,b)=1m∑i=1mL(a(i),y(i))=−1m∑i=1m[y(i)loga(i)+(1−y(i))log(1−a(i))](24)
核心代码如下:
dZ[2]=A[2]−YdW[2]=1mdZ[2]A[1]Tdb[2]=1mnp.sum(dZ[2],axis=1,keepdims=True)dz[1]=W[2]TdZ[2]∗g[1]′(Z[1])dW[1]=1mdZ[1]A[0]Tdb[1]=1mnp.sum(dZ[1],axis=1,keepdims=True)(25)
核心代码如下:
W[1]=W[1]−αdW[1],b[1]=b[1]−αdb[1]W[2]=W[2]−αdW[2],b[2]=b[2]−αdb[2](26)
核心代码如下:
可得到如下输出,分类准确率为90.50%。
此外,对隐含层节点数量的影响作了分析,核心代码如下:
得到如下结果。可以看出,较多的隐含层节点无法提升分类准确率,甚至存在过拟合现象,5个隐含层节点是比较理想的结果。
代码下载地址:https://gitee.com/tuzhen301/Coursera-deeplearning.ai1-3
1. 原理推导
1.1 神经网络表示
神经网络由输入层、隐含层和输出层构成。L层神经网络,隐含层为第1 ~ (L - 1)层,输出层为第L层。为了方便,将输入层写成第0层。定义:上标[l]表示第l层,下标j表示第j个节点。
例如,下图为2层神经网络,包含1个隐藏层:
输入层和隐含层可以写成:
a[0]=x=⎡⎣⎢x1x2x3⎤⎦⎥,a[1]=⎡⎣⎢⎢⎢⎢⎢⎢a[1]1a[1]2a[1]3a[1]4⎤⎦⎥⎥⎥⎥⎥⎥(1)
1.2 正向传播(Forward Propagation)
计算过程与逻辑回归类似,只是多了隐含层,如下:z[1]1=w[1]T1x+b[1]1,a[1]1=g(z[1]1)z[1]2=w[1]T2x+b[1]2,a[1]2=g(z[1]2)z[1]3=w[1]T3x+b[1]3,a[1]3=g(z[1]3)z[1]4=w[1]T4x+b[1]4,a[1]4=g(z[1]4)(2)
式中,g(z)为激活函数。可将上式向量化为:
⎡⎣⎢⎢⎢⎢⎢⎢z[1]1z[1]2z[1]3z[1]4⎤⎦⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢−−−−w[1]T1w[1]T2w[1]T3w[1]T4−−−−⎤⎦⎥⎥⎥⎥⎥⎥⎡⎣⎢x1x2x3⎤⎦⎥+⎡⎣⎢⎢⎢⎢⎢⎢b[1]1b[1]2b[1]3b[1]4⎤⎦⎥⎥⎥⎥⎥⎥,⎡⎣⎢⎢⎢⎢⎢⎢a[1]1a[1]2a[1]3a[1]4⎤⎦⎥⎥⎥⎥⎥⎥=g⎛⎝⎜⎜⎜⎜⎜⎜⎡⎣⎢⎢⎢⎢⎢⎢z[1]1z[1]2z[1]3z[1]4⎤⎦⎥⎥⎥⎥⎥⎥⎞⎠⎟⎟⎟⎟⎟⎟(3)
即:
z[1]=W[1]x+b[1],a[1]=g(z[1])(4)
式中,
z[1]=⎡⎣⎢⎢⎢⎢⎢⎢z[1]1z[1]2z[1]3z[1]4⎤⎦⎥⎥⎥⎥⎥⎥,W[1]=⎡⎣⎢⎢⎢⎢⎢⎢−−−−w[1]T1w[1]T2w[1]T3w[1]T4−−−−⎤⎦⎥⎥⎥⎥⎥⎥,b[1]=⎡⎣⎢⎢⎢⎢⎢⎢b[1]1b[1]2b[1]3b[1]4⎤⎦⎥⎥⎥⎥⎥⎥,a[1]=⎡⎣⎢⎢⎢⎢⎢⎢a[1]1a[1]2a[1]3a[1]4⎤⎦⎥⎥⎥⎥⎥⎥(5)
因此,对于该2层神经网络的每个样本,给定a[0] = x,正向传播计算流程如下:
z[1]=W[1]a[0]+b[1]a[1]=g(z[1])z[2]=W[2]a[1]+b[2]a[2]=g(z[2])(6)
各矩阵维度如下表:
矩阵 | a[0] | W[1] | b[1] | z[1] | a[1] | W[2] | b[2] | z[2] | a[2] |
---|---|---|---|---|---|---|---|---|---|
维度 | (3, 1) | (4, 3) | (4, 1) | (4, 1) | (4, 1) | (1, 4) | (1, 1) | (1, 1) | (1, 1) |
⎡⎣⎢|z[1](1)||z[1](2)||⋯||z[1](m)|⎤⎦⎥=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢−−−−w[1]1Tw[1]2Tw[1]3Tw[1]4T−−−−⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎡⎣⎢|x(1)||x(2)||⋯||x(m)|⎤⎦⎥+b[1](7)
⎡⎣⎢|a[1](1)||a[1](2)||⋯||a[1](m)|⎤⎦⎥=g⎛⎝⎜⎡⎣⎢|z[1](1)||z[1](2)||⋯||z[1](m)|⎤⎦⎥⎞⎠⎟(8)
即:
Z[1]=W[1]X+b[1],A[1]=g(Z[1])(9)
式中,
Z[1]=⎡⎣⎢|z[1](1)||z[1](2)||⋯||z[1](m)|⎤⎦⎥,A[1]=⎡⎣⎢|a[1](1)||a[1](2)||⋯||a[1](m)|⎤⎦⎥(10)
因此,对于以上2层神经网络,针对m个样本,给定A[0] = X,正向传播计算流程如下:
Z[1]=W[1]A[0]+b[1]A[1]=g(Z[1])Z[2]=W[2]A[1]+b[2]A[2]=g(Z[2])(11)
各矩阵维度如下表:
矩阵 | A[0] | W[1] | b[1] | Z[1] | A[1] | W[2] | b[2] | Z[2] | A[2] |
---|---|---|---|---|---|---|---|---|---|
维度 | (3, m) | (4, 3) | (4, 1) | (4, m) | (4, m) | (1, 4) | (1, 1) | (1, m) | (1, m) |
1.3 激活函数(Activation Function)
常见的4种激活函数如下:sigmoid函数:在0 ~ 1之间,很少用到,仅仅用于二分类问题。
tanh函数,在-1 ~ 1之间,均值为0,使得数据更集中。
sigmoid和tanh函数的一个共同缺点:当z很大或者很小时,函数的斜率都很小且接近0,从而使得梯度下降法的速度较慢。
ReLU(Rectified Linear Units)函数:通常比sigmoid和tanh函数效果好,是最常用的激活函数。缺点在于,当很大的梯度经过一个ReLU神经元,更新过参数后,这个神经元再也不会对任何数据有激活现象。对于较大的学习因子,经常会发生这个问题。因此,需要设置合适的、较小的学习因子。
Leaky ReLU函数:相比ReLU函数,设置了一个很小的常数α,保留了一些负轴的值,使得负轴信息不会全部丢失。
1.4 为什么激活函数使用非线性函数?
假如使用线性函数g(z) = z:则正向传播化简为:
z[1]=W[1]a[0]+b[1]a[1]=g(z[1])=z[1]z[2]=W[2]a[1]+b[2]=W[2]z[1]+b[2]a[2]=g(z[2])=z[2]=W[2](W[1]a[0]+b[1])+b[2]=(W[2]W[1])a[0]+(W[2]b[1]+b[2])=W′a[0]+b′(12)
可以看出,a[2]与z[1]等效,如果使用线性激活函数,就无法发挥隐含层的作用。在深度神经网络中,使用线性激活函数,多个隐含层与没有隐含层的效果相同。
因此,必须使用非线性激活函数。
1.5 梯度下降(Gradient Descent)
以n[l]表示第l层的节点数,对于以上的2层神经网络:n[0]=nx=3,n[1]=4,n[2]=1(13)
代价函数:
J(w,b)=1m∑i=1mL(a(i),y(i))=−1m∑i=1m[y(i)loga(i)+(1−y(i))log(1−a(i))](14)
梯度下降法流程如下:
Computeactivationa(i),i=1,⋯,mComputecostfunctionJdW[1]=dJdW[1],db[1]=dJdb[1],⋯W[1]=W[1]−αdW[1],b[1]=b[1]−αdb[1],⋯(15)
式中,α为学习因子。为了更新参数W和b,关键在于求解导数dW和db,可以通过反向传播来求解。
1.6 反向传播(Backward Propagation)
在正向传播中,已经计算得到了Z[1]、A[1]、Z[2]、A[2]。此处使用sigmoid函数来推导。对于2层神经网络,针对单个样本,正向传播为:z[1]=W[1]a[0]+b[1]a[1]=g(z[1])z[2]=W[2]a[1]+b[2]a[2]=g(z[2])(16)
与逻辑回归类似,反向传播计算如下:
dz[2]=a[2]−ydW[2]=dz[2]a[1]Tdb[2]=dz[2]dz[1]=dJdz[2]⋅dz[2]da[1]⋅da[1]dz[1]=W[2]Tdz[2]∗g[1]′(z[1])dW[1]=dz[1]a[0]Tdb[1]=dz[1](17)
拓展到m个样本得到:
dZ[2]=A[2]−YdW[2]=1mdZ[2]A[1]Tdb[2]=1mnp.sum(dZ[2],axis=1,keepdims=True)dz[1]=W[2]TdZ[2]∗g[1]′(Z[1])dW[1]=1mdZ[1]A[0]Tdb[1]=1mnp.sum(dZ[1],axis=1,keepdims=True)(18)
式中,“*”表示元素点乘。通过上式求出梯度dW和db,并代入梯度下降法中,即可对参数W和b进行更新。
1.7 随机初始化
对于如下的2层神经网络。如果将参数全部初始化为0:
W[1]=[0000],b[1]=[00](19)
那么,无论采用什么样本来训练,都会得到:
a[1]1=a[1]2,dz[1]1=dz[1]2(20)
在更新参数的过程中,W始终保持如下的对称形式:
W=[uuvv](21)
这样,a[1]1和a[1]2具体相同的功能,实际上只需要一个就够了。
所以,在初始化神经网络参数时,应当避免以上情况,将参数W随机初始化,为了方便,可以将b全部初始化为0。
另外,根据sigmoid或者tanh函数的特点,当输入较大时,函数的导数较大,会导致学习速度较慢。因此,通常将参数随机初始化为较小的参数:
W=np.random.randn(l,l−1)∗0.01b=np.zeros((l,1))(22)
2. 代码实现
案例:采用2层神经网络实现色点的二分类。计算流程如下:
2.1 初始化initialize
对参数W进行随机初始化,将参数b初始化为0。核心代码如下:2.2 正向传播forward
按照下式计算各个节点的Z和A:Z[1]=W[1]A[0]+b[1]A[1]=g(Z[1])Z[2]=W[2]A[1]+b[2]A[2]=g(Z[2])(23)
核心代码如下:
2.3 计算代价函数compute_cost
采用下式计算代价函数:J(w,b)=1m∑i=1mL(a(i),y(i))=−1m∑i=1m[y(i)loga(i)+(1−y(i))log(1−a(i))](24)
核心代码如下:
2.4 反向传播backward
按照下式计算参数的梯度dW和db:dZ[2]=A[2]−YdW[2]=1mdZ[2]A[1]Tdb[2]=1mnp.sum(dZ[2],axis=1,keepdims=True)dz[1]=W[2]TdZ[2]∗g[1]′(Z[1])dW[1]=1mdZ[1]A[0]Tdb[1]=1mnp.sum(dZ[1],axis=1,keepdims=True)(25)
核心代码如下:
2.5 参数更新update_parameters
按照下式对参数W和b进行更新:W[1]=W[1]−αdW[1],b[1]=b[1]−αdb[1]W[2]=W[2]−αdW[2],b[2]=b[2]−αdb[2](26)
核心代码如下:
2.6 模型构建nn_model
将以上几个模块进行整合,输入训练样本,得到最优参数W和b。关键代码如下:2.7 预测predict
根据优化得到的参数W和b,输入样本x,得到预测值,如果预测概率大于0.5,则预测值为1,否则为0。关键代码如下:2.8 样本测试
代码如下:可得到如下输出,分类准确率为90.50%。
此外,对隐含层节点数量的影响作了分析,核心代码如下:
得到如下结果。可以看出,较多的隐含层节点无法提升分类准确率,甚至存在过拟合现象,5个隐含层节点是比较理想的结果。
代码下载地址:https://gitee.com/tuzhen301/Coursera-deeplearning.ai1-3
相关文章推荐
- Coursera deeplearning.ai 深度学习笔记1-4-Deep Neural Networks-深度神经网络原理推导与代码实现
- Coursera deeplearning.ai 深度学习笔记2-1-Practical aspects of deep learning-神经网络实际问题分析(初始化&正则化&训练效率)与代码实现
- Coursera deeplearning.ai 深度学习笔记4-2-Deep Convolutional Models Case Studies-深度卷积模型案例及代码实现
- Coursera deeplearning.ai 深度学习笔记2-2-Optimization algorithms-优化算法与代码实现
- Coursera deeplearning.ai 深度学习笔记1-2-Neural Network Basics-逻辑回归原理推导与代码实现
- Deep Q-Network 学习笔记(二)—— Q-Learning与神经网络结合使用(有代码实现)
- DeepLearning.ai学习笔记(一)神经网络和深度学习--Week4深层神经网络
- [DeeplearningAI笔记]改善深层神经网络_深度学习的实用层面1.10_1.12/梯度消失/梯度爆炸/权重初始化
- DeepLearning.ai学习笔记(一)神经网络和深度学习--Week4深层神经网络
- [DeeplearningAI笔记]改善深层神经网络_深度学习的实用层面1.9_归一化normalization
- Coursera deeplearning.ai 深度学习笔记4-1-Foundations of Convolutional Neural Networks-卷积神经网络基础及代码实现
- Deep Q-Network 学习笔记(二)—— Q-Learning与神经网络结合使用(有代码实现)
- [DeeplearningAI笔记]神经网络与深度学习2.1-2.4神经网络基础
- 深度学习DeepLearning.ai系列课程学习总结:8. 多层神经网络代码实战
- [DeeplearningAI笔记]神经网络与深度学习2.11_2.16神经网络基础(向量化)
- [DeeplearningAI笔记]改善深层神经网络1.1_1.3深度学习实用层面_偏差/方差/欠拟合/过拟合/训练集/验证集/测试集
- DeepLearning.ai学习笔记(一)神经网络和深度学习--Week3浅层神经网络
- DeepLearning.ai code笔记1:神经网络与深度学习
- DeepLearning.ai学习笔记(一)神经网络和深度学习--Week3浅层神经网络
- [DeeplearningAI笔记]神经网络与深度学习3.2_3.11(激活函数)浅层神经网络