当前位置:   article > 正文

深度神经网络_隐藏层越多越好吗

隐藏层越多越好吗

一、深层神经网络的优势

​ 即便是单层的神经网络只要隐藏层有足够多的神经单元,神经网络的宽度足够大,深层神经网络复杂度就足够高,就能拟合任意复杂的函数。但是并不是神经网络越宽越好,尤其是在计算及视觉领域,,例如:第一层是边缘信息;第二层是局部特征,神经网络越深,提取的特征越复杂,从模糊到详细、从局部到整体可见隐藏层越多能够提取的特征就越丰富、越复杂,模型的准确率就会越高,此时包含多隐藏层的深层神经网络往往性能更好。

​ 但是在实际应用中,尽量选择层数较少的神经网络,才能有效避免发生过拟合,对于较为复杂的问题,再考虑使用深层神经网络模型。

二、符号标记

  1. 神经网络是L层:L是隐藏层和输出层层数之和,即隐藏层为L-1层。
  2. 用上标l表示当前层,l=1,2,…,L。
  3. n [ l ] n^{[l]} n[l]表示第l层包含的神经元个数。
  4. 输入层X用 A [ 0 ] A^{[0]} A[0]表示,其维度是( n [ 0 ] n^{[0]} n[0],m),其中 n [ 0 ] = n x n^{[0]}=n_x n[0]=nx表示输入层特征数目,m表示样本个数。
  5. 输出层用 A [ L ] A^{[L]} A[L]表示。
  6. 对于第l层神经元,神经元个数为 n [ l ] n^{[l]} n[l],各符号标记含义如下:
    1. W [ l ] W^{[l]} W[l]表示该层权重参数,维度为 ( n [ l ] , n [ l − 1 ] ) (n^{[l]},n^{[l-1]}) (n[l],n[l1]);
    2. b [ l ] b^{[l]} b[l]表示该层偏置参数,维度为 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1);
    3. Z [ l ] Z^{[l]} Z[l]表示该层线性输出,维度为 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1);
    4. A [ l ] A^{[l]} A[l]表示该层非线性输出,维度为 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1)

三、前向传播与反向传播

  1. 前向传播:
    { Z [ l ] = W [ l ] A [ l − 1 ] + b [ l ] A [ l ] = g ( Z [ l ] ) \{{Z^{[l]}=W{[l]}A^{[l-1]}+b^{[l]} \atop A^{[l]}=g(Z^{[l]})} {A[l]=g(Z[l])Z[l]=W[l]A[l1]+b[l]
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ba7mPw44-1635233129590)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211021152209322.png)]

  2. 反向传播:
    { d Z [ l ] = d A [ l ] ∗ g ‘ ( Z [ l ] ) d W [ l ] = 1 m d Z [ l ] ⋅ A [ l − 1 ] T d b [ l ] = 1 m ∑ d Z [ l ] d A [ l − 1 ] = W [ l ] T ⋅ d Z [ l ] \{{{dZ^{[l]}=dA^{[l]}*g`(Z^{[l]}) \atop dW^{[l]}=\frac{1}{m}dZ^{[l]}·A^{[l-1]T}} \atop {db^{[l]}=\frac{1}{m}\sum dZ^{[l]} \atop dA^{[l-1]}=W^{[l]T}·dZ^{[l]}}} {dA[l1]=W[l]TdZ[l]db[l]=m1dZ[l]dW[l]=m1dZ[l]A[l1]TdZ[l]=dA[l]g(Z[l])
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1TE5uvT-1635233129600)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211021152223131.png)]

  3. L层神经网络数据流图:通过此图我们可以清晰的掌握神经网络的前向传播和反向传播过程。注意第一层神经网络的反向传播没有输出 d A [ 0 ] dA^{[0]} dA[0],因为没有后续数据流,不影响计算参数 d W [ 1 ] 、 d b [ 1 ] dW^{[1]}、db^{[1]} dW[1]db[1]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gwy7vfbq-1635233129607)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211021152141448.png)]

  4. 输出层L中 d A dA dA的计算公式由交叉熵损失可得:
    d A [ L ] = 1 − Y 1 − A [ L ] − Y A [ L ] dA^{[L]}=\frac{1-Y}{1-A^{[L]}}-\frac{Y}{A^{[L]}} dA[L]=1A[L]1YA[L]Y

  5. 公式总结:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qG6ub8NI-1635233129615)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211021152117477.png)]

四、多分类函数Softmax

  1. 基本原理:多分类与二分类(Sigmoid函数)的主要区别就在于神经网络输出层神经元的个数,而分类模型的输出层只有一个神经元,而多分类模型的输出层有多个神经元,需要使用Softmax函数来处理。Softmax函数将 Z [ L ] Z^{[L]} Z[L]映射到预测概率(区间[0,1])上,将其看成概率,各神经元输出概率之和为1,通过比较各概率值的大小,概率值较大的神经元对应的类别则为预测值。
    A [ L ] = e Z [ L ] ∑ e Z i [ L ] A^{[L]}=\frac{e^{Z^{[L]}}}{\sum e^{Z^{[L]}_i}} A[L]=eZi[L]eZ[L]

  2. Softmax损失函数:因为不是二分问题,因此不能再套用交叉熵损失函数了,我们希望正确类别对应的概率值 A i [ L ] ( i = 1 , 2 , … , C , C 为 总 的 类 别 个 数 ) A^{[L]}_i(i=1,2,…,C,C为总的类别个数) Ai[L](i=1,2,,CC),越大越好,这样错误越小,损失也就越小。_
    L = − ∑ y i l n a i [ L ] L=-\sum y_iln a^{[L]}_i L=yilnai[L]
    y向量中只有正确的类别对应位置为1,其他全为0。上式还可以写成(其中k为正确类别对应的神经元,这样也可以将概率值越大转化为损失越小):
    − l o g a k [ L ] -log a^{[L]}_k logak[L]

  3. 对Softmax函数求导:根据上述损失表达式,计算损失函数对 z [ L ] z^{[L]} z[L]的梯度 d z [ L ] dz^{[L]} dz[L]
    L 对 z i [ L ] 的 偏 导 数 为 : ∂ L ∂ z i [ L ] = ∑ j ( ∂ L j ∂ a j [ L ] ∂ a j [ L ] ∂ z i [ L ] ) L对z^{[L]}_i的偏导数为:\frac{∂L}{∂z^{[L]}_i}=\sum_j (\frac{∂L_j}{∂a^{[L]}_j} \frac{∂a^{[L]}_j}{∂z^{[L]}_i}) Lzi[L]zi[L]L=j(aj[L]Ljzi[L]aj[L])
    注意,再S0ftmax函数计算公式中分母包含了所有神经元的输出,因此不等于i的其他输出里也包含了 z i z_i zi,所有的 a j [ L ] a^{[L]}_j aj[L]都要纳入计算范围。后面的计算也需要分为i=j和i!=j两种情况求导。
    第 一 部 分 : ∂ L j ∂ a j [ L ] = ∂ ( − y j l n a j [ L ] ) ∂ a j [ L ] = − y i a j [ L ] 第一部分:\frac{∂L_j}{∂a^{[L]}_j}=\frac{∂(-y_jln a^{[L]}_j)}{∂a^{[L]}_j}=-\frac{y_i}{a^{[L]}_j} aj[L]Lj=aj[L](yjlnaj[L])=aj[L]yi

    第 二 部 分 : { ∂ a j [ L ] ∂ z i [ L ] = ∂ a i [ L ] ∂ z i [ L ] = ∂ ( e Z i [ L ] ∑ k e Z k [ L ] ) ∂ z i [ L ] = ∑ k e Z k [ L ] e Z i [ L ] − ( e Z i [ L ] ) 2 ( ∑ k e Z k [ L ] ) 2 = ( e Z i [ L ] ∑ k e Z k [ L ] ) ( 1 − e Z i [ L ] ∑ k e Z k [ L ] ) = a i [ L ] ( 1 − a i [ L ] ) , i = j ∂ a j [ L ] ∂ z i [ L ] = ∂ ( e Z j [ L ] ∑ k e Z k [ L ] ) ∂ z i [ L ] = − e Z j [ L ] ( 1 ∑ k e Z k [ L ] ) 2 e Z i [ L ] = − a i [ L ] a j [ L ] , i ! = j 第二部分:\{{\frac{∂a^{[L]}_j}{∂z^{[L]}_i}=\frac{∂a^{[L]}_i}{∂z^{[L]}_i}=\frac{∂(\frac{e^{Z^{[L]}_i}}{\sum_k e^{Z^{[L]}_k}})}{∂z^{[L]}_i}=\frac{\sum_k e^{Z^{[L]}_k}e^{Z^{[L]}_i}-(e^{Z^{[L]}_i})^2}{(\sum_k e^{Z^{[L]}_k})^2}=(\frac{e^{Z^{[L]}_i}}{\sum_k e^{Z^{[L]}_k}})(1-\frac{e^{Z^{[L]}_i}}{\sum_k e^{Z^{[L]}_k}})=a^{[L]}_i(1-a^{[L]}_i),i=j\atop \frac{∂a^{[L]}_j}{∂z^{[L]}_i}=\frac{∂(\frac{e^{Z^{[L]}_j}}{\sum_k e^{Z^{[L]}_k}})}{∂z^{[L]}_i}=-e^{Z^{[L]}_j}(\frac{1}{\sum_k e^{Z^{[L]}_k}})^2e^{Z^{[L]}_i}=-a^{[L]}_ia^{[L]}_j,i!=j} {zi[L]aj[L]=zi[L](keZk[L]eZj[L])=eZj[L](keZk[L]1)2eZi[L]=ai[L]aj[L],i!=jzi[L]aj[L]=zi[L]ai[L]=zi[L](keZk[L]eZi[L])=(keZk[L])2keZk[L]eZi[L](eZi[L])2=(keZk[L]eZi[L])(1keZk[L]eZi[L])=ai[L](1ai[L]),i=j

    将上述两部分组合起来得到:
    ∂ L ∂ z i [ L ] = ∑ j ( ∂ L j ∂ a j [ L ] ∂ a j [ L ] ∂ z i [ L ] ) = ∑ i = j ( ∂ L j ∂ a j [ L ] ∂ a j [ L ] ∂ z i [ L ] ) + ∑ i ! = j ( ∂ L j ∂ a j [ L ] ∂ a j [ L ] ∂ z i [ L ] ) = ∑ i = j ( − y i a j [ L ] ) ( a i [ L ] ( 1 − a i [ L ] ) ) + ∑ i ! = j ( − y i a j [ L ] ) ( − a i [ L ] a j [ L ] ) = ∑ i = j ( a i [ L ] y i − y i ) + ∑ i ! = j a i [ L ] y j = a i [ L ] ∑ j y j − y i \frac{∂L}{∂z^{[L]}_i}=\sum_j (\frac{∂L_j}{∂a^{[L]}_j} \frac{∂a^{[L]}_j}{∂z^{[L]}_i})\frac{}{}=\sum_{i=j}(\frac{∂L_j}{∂a^{[L]}_j} \frac{∂a^{[L]}_j}{∂z^{[L]}_i})+\sum_{i!=j}(\frac{∂L_j}{∂a^{[L]}_j} \frac{∂a^{[L]}_j}{∂z^{[L]}_i})=\sum_{i=j}(-\frac{y_i}{a^{[L]}_j})(a^{[L]}_i(1-a^{[L]}_i))+\sum_{i!=j}(-\frac{y_i}{a^{[L]}_j})(-a^{[L]}_ia^{[L]}_j)=\sum_{i=j}(a^{[L]}_iy_i-y_i)+\sum_{i!=j}a^{[L]}_iy_j=a^{[L]}_i\sum_jy_j-y_i zi[L]L=j(aj[L]Ljzi[L]aj[L])=i=j(aj[L]Ljzi[L]aj[L])+i!=j(aj[L]Ljzi[L]aj[L])=i=j(aj[L]yi)(ai[L](1ai[L]))+i!=j(aj[L]yi)(ai[L]aj[L])=i=j(ai[L]yiyi)+i!=jai[L]yj=ai[L]jyjyi
    因为y中只有 y i y_i yi为1,其他 y j y_j yj都为0.进一步简化得到:
    ∂ L ∂ z i [ L ] = a i [ L ] − y i 如 果 是 m 个 样 本 则 可 以 写 成 ∂ L ∂ Z [ L ] = A [ L ] − Y \frac{∂L}{∂z^{[L]}_i}=a^{[L]}_i-y_i如果是m个样本则可以写成\frac{∂L}{∂Z^{[L]}}=A^{[L]}-Y zi[L]L=ai[L]yimZ[L]L=A[L]Y
    经过推到我们发现,多分类函数Softmax的梯度 d Z [ L ] dZ^{[L]} dZ[L]与而分类函数Sigmoid函数的梯度是完全一样的,因此我们可以继续进行神经网络的反向传播梯度计算了。

五、深层神经网络的Python实现

​ 将会解决一个图像二分类问题,可能前馈神经网络效果并不够好,可以对算法进行进一步优化,也可以采用后面讲解的卷积神经网络加以解决。

  1. 准备数据:首先需要将图片导入,还需要将图片矩阵平铺式展开,并且将图片所有像素归一化至[0,1]区间。

    #训练集,500张图片,250张猫0,250张狗1
    file='F:dataset/train/*.jpg'
    coll=io.ImageCollection(file)
    X_train=np.asarray(coll)
    Y_train=np.hstack((np.ones((1,250)),np.zeros((1,250))))
    #测试集,200张图,100猫0,100狗1
    file='F:dataset/test/*.jpg'
    coll=io.ImageCollection(file)
    X_test=np.asarray(coll)
    Y_test=np.hstack((np.ones((1,100)),np.zeros((1,100))))
    #获取数量
    m_train=X_train.shape[0]   #训练样本数量
    m_test=X_test.shape[0]   #测试样本数量
    w, h, d=X_train.shape[1],X_train.shape[2],X_train.shape[3] #图片的维度64,64,3(彩色图片)
    #神经网络的输入层是一维向量,此三通道矩阵是三维矩阵,需要将图片平铺式展开为一维向量
    #一般还要将图片所有像素归一化至[0,1]区间,也就是把像素值除以255
    X_train=X_train.reshape(m_train,-1).T
    X_test=X_test.reshape(m_test,-1).T
    X_train=X_train/255
    X_test=X_test/255
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  2. 参数初始化:深层神经网络需要一个神经网络总层数长度的列表,存储神经网络各层神经元个数,包括输入层,layer_dims=[2,3,1]表示输入层有两个神经元,隐藏层只有一层,有三个神经元,输出层有一个神经元。各层(所以要加上str())参数被存储在字典中。

    def initialize_parameters(layer_dims):
    	"""
    	函数输入:
    		layer_dims:列表,神经网络各层神经元个数,包括输入层
    	函数输出:
    		parameters:存储参数的字典
    	"""
    	np.random.seed(5)
    	parameters={}
    	L=len(layer_dims)   #神经网络的层数,包含输入层
    	for l in range(1,L):
    		parameters['W'+str(l)]=np.random.randn(layer_dims[l],
    		layer_dims[l-1])*0.1
    		parameters['b'+str(l)]=np.zeros((layer_dims[l],1))
    	return parameters
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  3. 前向传播:浅层神经网络中隐藏层的激活函数一般选择tanh函数,深层神经网络隐藏层的激活函数一般选择ReLU函数。

    #ReLU函数的定义
    def relu(Z):
    	"""
    	函数输入:
    		Z:激活函数的输入,神经元线性输出
    	函数输出:
    		A:激活函数的输出,神经元非线性输出
    	"""
    	A=np.maximum(0,Z)
    	return A
    
    #二分类问题,输出层的激活函数采用Sigmoid函数
    def sigmoid(Z):
    	"""
    	函数输入:
    		Z:激活函数输入,神经元线性输出
    	函数输出:
    		A:激活函数输出,神经元非线性输出
    	"""
    	A=1/(1+np.exp(-Z))
    	return A
    
    #单层前向传播函数,计算该层网络的输出A
    def single_layer_forward(A_prev, W, b, activation):
    	"""
    	函数输入:
    		A_prev:该层网络的输入,上一层网络的输出
    		W:该层网络的权重参数
    		b:该层网络的偏置参数
    		activation:该层网络使用的激活函数
    	函数输出:
    		A:该层网络输出
    		cache:存储所有的中间变量A_prev, W, b, Z
    	"""
    	Z=np.dow(W,A_prev)+b   #线性输出
    	if activation=="sigmoid":
    		A=sigmoid(Z)
    	elif activation=="relu":
    		A=relu(Z)
    	cache= (A_prev, W, b, Z)
    	return A, cache
    
    #整个网络的前向传播函数
    def forward_propagation(X, parameters):
    	"""
    	函数输入:
    		X:神经网络输入
    		parameters:该层网络的权重
    	函数输出:
    		A:该层网络的输出
    		caches:存储各层网络所有的中间变量
    	"""
    	caches=[]
    	A=X
    	L=len(parameters)//2   #因为参数有W,b
    	#前L-1层使用ReLU函数
    	for l in range(1,L):
    		A_prev=A
    		A,cache=single_layer_forward(A_prev,
    									parameters['W'+str(l)],
    									parameters['b'+str(l)],
    									"relu")
    		caches.append(cache)
    	#第L层使用Sigmoid函数
    	AL,cache=single_layer_forward(A,
    								parameters['W'+str(L)],
    								parameters['b'+str(L)],
    								"sigmoid")
    	caches.append(cache)
    	return AL,caches
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
  4. 交叉熵损失:需要计算AL与Y之间的交叉熵。

    def compute_cost(AL,Y):
    	"""
    	函数输入:
    		AL:神经网络输出层输出
    		Y:神经网络真实标签
    	函数输出:
    		cost:交叉熵损失
    	"""
    	m=AL.shape[1]
    	cross_entropy=-(Y*np.log(AL)+(1-Y)*np.log(1-AL))
    	cost=1.0/m*np.sum(cross_entropy)
    	return cost
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  5. 反向传播:

    def relu_backward(dA, Z):   #relu函数的求导函数
    	"""
    	函数输入:
    		dA:A的梯度
    		Z:神经网络线性输出
    	函数输出:
    		dZ:Z的梯度
    	"""
    	dZ=np.array(dA, copy=True)
    	dZ[Z<=0]=0
    	return dZ
    
    def sigmoid_backward(dA, Z):   #sigmoid函数的求导函数
    	"""
    	函数输入:
    		dA:A的梯度
    		Z:神经网络线性输出
    	函数输出:
    		dZ:Z的梯度
    	"""
    	s=1/(1+np.exp(-Z))
    	dZ=dA*s*(1-s)
    	return dZ	
    
    #单层神经网络的反向传播函数
    def single_layer_backward(dA, cache, activation):
    	"""
    	函数输入:
    		dA:A的梯度
    		cache:存储所有的中间变量A_prev,W,b,Z
    		activation:选择的激活函数
    	函数输出:
    		dA_prev:上一层A_prev的梯度
    		dW:参数W的梯度
    		db:参数b的梯度
    	"""
    	A_prev, W, b, Z=cache
    	if activation=="relu":
    		dZ=relu_backward(dA,Z)
    	elif activation=="sigmoid":
    		dZ=sigmoid_backward(dA,Z)
    	m=dA.shape[1]
    	dW=1/m*np.dot(dZ,A_prev.T)
    	db=1/m*np.sum(dZ,axis=1,keepdims=True)
    	dA_prev=np.dot(W.T,dZ)
    	return dA_prev,dW,db
    
    #整个神经网络的反向传播函数
    def backward_propagation(AL, Y, caches):
    	"""
    	函数输入:
    		AL:神经网络输出层输出
    		cache:存储所有的中间变量A_prev,W,b,Z
    		Y:神经网络真实标签
    	函数输出:
    		grads:所有参数梯度
    	"""
    	grads={}
    	L=len(caches)   #神经网络层数
    	m=AL.shape[1]   #样本个数
    	#AL值
    	dAL=-(np.divide(Y, AL)-np.divide(1-Y, 1-AL))
    	#第L层,激活函数是Sigmoid
    	current_cache=caches[L-1]
    	grads["dA"+str(L-1)],grads["dW"+str(L)],grads["db"+str(L)]=single_layer_backward(
    								dAL, current_cache,activation="sigmoid")
    	#前L-1层,激活函数是ReLU
    	for l in reversed(range(L-1)):
    		current_cache=caches[l]
    		dA_prev_temp,dW_temp,db_temp=single_layer_backward(grads["dA"+str(l+1)],
    								current_cache,activation="relu")
    		grads["dA"+str(l)]=dA_prev_temp
    		grads["dW"+str(l+1)]=dW_temp
    		grads["db"+str(l+1)]=db_temp
    		return grads
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
  6. 更新参数:使用梯度下降算法的公式对神经网络各层参数进行更新。

    def update_parameters(parameters, grads, learning_rate=0.1):
    	"""
    	函数输入:
    		parameters:网络参数
    		grads:神经网络参数梯度
    	函数输出:
    		parameters:网络参数
    	"""
    	L=len(parameters)//2
    	for l in range(L):
    		parameters['W'+str(l+1)]-=learning_rate*grads['dW'+str(l+1)]
    		parameters['b'+str(l+1)]-=learning_rate*grads['db'+str(l+1)]
    	return parameters
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  7. 构建整个神经网络:将上述模块整合起来,构建神经网络模型。

    def nn_model(X, Y, layers_dims, learning_rate=0.01,num_iterations=3000):
    	"""
    	函数输入:
    		X:神经网络输入
    		Y:样本真实标签
    		layers_dim:列表,神经网络各层神经元个数,包含输入层和输出层
    		num_iterations:训练次数
    		learning_rate:学习率
    	函数输出:
    		parameters:训练完成后的网络参数
    	"""
    	np.random.seed(1)
    	costs=[]
    	#参数初始化
    	parameters=initialize_parameters(layers_dims)
    	#迭代训练
    	for i in range(0,num_iterations):
    		#正向传播
    		AL,caches=forward_propagation(X,parameters)
    		#计算损失函数
    		cost=compute_cost(AL,Y)
    		#反向传播
    		grads=backward_propagation(AL, Y, caches)
    		#更新参数
    		parameters = update_parameters(parameters, grads, learning_rate)
    	#绘制cost趋势图
    	plt.plot(np.squeeze(cost))
    	plt.ylabel('cost')
    	plt.xlabel('迭代训练次数')
    	plt.title("学习率为"+str(learning_rate))
    	plt.show()
    	return parameters
    
    #定义整个神经网络的预测函数
    def predict(X,parameters):
    	"""
    	函数输入:
    		X:神经网络输入
    		parameters:训练完成后的网络参数
    	函数输出:
    		Y_pred:预测样本标签
    	"""
    	#L层模型前向传播
    	AL,caches =forward_propagation(X,parameters)
    	#预测标签
    	Y_pred=np.zeros((1,X.shape[1]))
    	Y_pred[AL>0.5]=1
    	return Y_pred
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
  8. 训练与预测:构建一个五层神经网络,迭代训练次数为2000次,学习率设为0.02。

    #构建神经网络
    layers_dims=[12288,200,100,20,6,1]   #5层神经网络
    parameters=nn_model(X_train,Y_train,layers_dims,
    					num_iterations=2000,
    					learning_rate=0.02)
    #使用该模型对测试集进行预测
    Y_test_prev=predict(X_test,parameters)
    acc_test=np.mean(Y_test_pred==Y_test)
    print(acc_test)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  9. 全部代码:

    需要安一下skimage:

    配置清华镜像源:

    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
    
    • 1
    • 2

    然后安一下conda install opencv和conda install scikit-image

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import skimage.io as io

#plt.rcParams['font.sans-serif']=['SimHei']
#plt.rcParams['axes.unicode_minus']=False

#训练集,500张图片,250张猫0,250张狗1
file=r'F:/dataset/train/*.jpg'
coll=io.ImageCollection(file)
#查看图片io.imshow(coll[10])
X_train=np.asarray(coll)
Y_train=np.hstack((np.ones((1,250)),np.zeros((1,250))))
#测试集,200张图,100猫0,100狗1
file='F:/dataset/test/*.jpg'
coll=io.ImageCollection(file)
X_test=np.asarray(coll)
Y_test=np.hstack((np.ones((1,100)),np.zeros((1,100))))
#获取数量
m_train=X_train.shape[0]   #训练样本数量
m_test=X_test.shape[0]   #测试样本数量
w, h, d=X_train.shape[1],X_train.shape[2],X_train.shape[3] #图片的维度64,64,3(彩色图片)
#神经网络的输入层是一维向量,此三通道矩阵是三维矩阵,需要将图片平铺式展开为一维向量
#一般还要将图片所有像素归一化至[0,1]区间,也就是把像素值除以255
X_train=X_train.reshape(m_train,-1).T
X_test=X_test.reshape(m_test,-1).T
#查看维度print(X_train.shape)
X_train=X_train/255
X_test=X_test/255
def initialize_parameters(layer_dims):
	"""
	函数输入:
		layer_dims:列表,神经网络各层神经元个数,包括输入层
	函数输出:
		parameters:存储参数的字典
	"""
	np.random.seed(5)
	parameters={}
	L=len(layer_dims)   #神经网络的层数,包含输入层
	for l in range(1,L):
		parameters['W'+str(l)]=np.random.randn(layer_dims[l],layer_dims[l-1])*0.1
		parameters['b'+str(l)]=np.zeros((layer_dims[l],1))
	return parameters

#ReLU函数的定义
def relu(Z):
	"""
	函数输入:
		Z:激活函数的输入,神经元线性输出
	函数输出:
		A:激活函数的输出,神经元非线性输出
	"""
	A=np.maximum(0,Z)
	return A

#二分类问题,输出层的激活函数采用Sigmoid函数
def sigmoid(Z):
	"""
	函数输入:
		Z:激活函数输入,神经元线性输出
	函数输出:
		A:激活函数输出,神经元非线性输出
	"""
	A=1/(1+np.exp(-Z))
	return A

#单层前向传播函数,计算该层网络的输出A
def single_layer_forward(A_prev, W, b, activation):
	"""
	函数输入:
		A_prev:该层网络的输入,上一层网络的输出
		W:该层网络的权重参数
		b:该层网络的偏置参数
		activation:该层网络使用的激活函数
	函数输出:
		A:该层网络输出
		cache:存储所有的中间变量A_prev, W, b, Z
	"""
	#W_mat=np.mat(W)
	#A_prev_mat=np.mat(A_prev)
	#print("A"+str(A_prev.shape)+str(type(A_prev)))
	#print("W"+str(W.shape)+str(type(W)))
	Z=np.dot(W,A_prev)+b   #线性输出
	#print(W.shape)
	#print(A_prev.shape)
	if activation == "sigmoid":
		A=sigmoid(Z)
	elif activation == "relu":
		A=relu(Z)
	cache= (A_prev, W, b, Z)
	return A, cache

#整个网络的前向传播函数
def forward_propagation(X, parameters):
	"""
	函数输入:
		X:神经网络输入
		parameters:该层网络的权重
	函数输出:
		A:该层网络的输出
		caches:存储各层网络所有的中间变量
	"""
	caches=[]
	A=X
	L=len(parameters)//2   #因为参数有W,b
	#前L-1层使用ReLU函数
	for l in range(1,L):
		A_prev=A
		A,cache=single_layer_forward(A_prev,parameters['W'+str(l)],parameters['b'+str(l)],"relu")
		caches.append(cache)
	#第L层使用Sigmoid函数
	AL,cache=single_layer_forward(A,parameters['W'+str(L)],parameters['b'+str(L)],"sigmoid")
	caches.append(cache)
	return AL,caches

def compute_cost(AL,Y):
	"""
	函数输入:
		AL:神经网络输出层输出
		Y:神经网络真实标签
	函数输出:
		cost:交叉熵损失
	"""
	m=AL.shape[1]
	cross_entropy=-(Y*np.log(AL)+(1-Y)*np.log(1-AL))
	cost=1.0/m*np.sum(cross_entropy)
	return cost

def relu_backward(dA, Z):   #relu函数的求导函数
	"""
	函数输入:
		dA:A的梯度
		Z:神经网络线性输出
	函数输出:
		dZ:Z的梯度
	"""
	dZ=np.array(dA, copy=True)
	dZ[Z<=0]=0
	return dZ

def sigmoid_backward(dA, Z):   #sigmoid函数的求导函数
	"""
	函数输入:
		dA:A的梯度
		Z:神经网络线性输出
	函数输出:
		dZ:Z的梯度
	"""
	s=1/(1+np.exp(-Z))
	dZ=dA*s*(1-s)
	return dZ

#单层神经网络的反向传播函数
def single_layer_backward(dA, cache, activation):
	"""
	函数输入:
		dA:A的梯度
		cache:存储所有的中间变量A_prev,W,b,Z
		activation:选择的激活函数
	函数输出:
		dA_prev:上一层A_prev的梯度
		dW:参数W的梯度
		db:参数b的梯度
	"""
	A_prev, W, b, Z=cache
	if activation=="relu":
		dZ=relu_backward(dA,Z)
	elif activation=="sigmoid":
		dZ=sigmoid_backward(dA,Z)
	m=dA.shape[1]
	dW=1/m*np.dot(dZ,A_prev.T)
	db=1/m*np.sum(dZ,axis=1,keepdims=True)
	dA_prev=np.dot(W.T,dZ)
	return dA_prev,dW,db

#整个神经网络的反向传播函数
def backward_propagation(AL, Y, caches):
	"""
	函数输入:
		AL:神经网络输出层输出
		cache:存储所有的中间变量A_prev,W,b,Z
		Y:神经网络真实标签
	函数输出:
		grads:所有参数梯度
	"""
	grads={}
	L=len(caches)   #神经网络层数
	m=AL.shape[1]   #样本个数
	#AL值
	dAL=-(np.divide(Y, AL)-np.divide(1-Y, 1-AL))
	#第L层,激活函数是Sigmoid
	current_cache=caches[L-1]
	grads["dA"+str(L-1)],grads["dW"+str(L)],grads["db"+str(L)]=single_layer_backward(dAL, current_cache,activation="sigmoid")
	#前L-1层,激活函数是ReLU
	for l in reversed(range(L-1)):
		current_cache=caches[l]
		dA_prev_temp,dW_temp,db_temp=single_layer_backward(grads["dA"+str(l+1)],current_cache,activation="relu")
		grads["dA"+str(l)]=dA_prev_temp
		grads["dW"+str(l+1)]=dW_temp
		grads["db"+str(l+1)]=db_temp
	return grads
    
def update_parameters(parameters, grads, learning_rate=0.1):
	"""
	函数输入:
		parameters:网络参数
		grads:神经网络参数梯度
	函数输出:
		parameters:网络参数
	"""
	L=len(parameters)//2
	for l in range(L):
		parameters['W'+str(l+1)]-=learning_rate*grads["dW"+str(l+1)]
		parameters['b'+str(l+1)]-=learning_rate*grads["db"+str(l+1)]
	return parameters

def nn_model(X, Y, layers_dims, learning_rate=0.01,num_iterations=3000):
	"""
	函数输入:
		X:神经网络输入
		Y:样本真实标签
		layers_dim:列表,神经网络各层神经元个数,包含输入层和输出层
		num_iterations:训练次数
		learning_rate:学习率
	函数输出:
		parameters:训练完成后的网络参数
	"""
	np.random.seed(1)
	costs=[]
	#参数初始化
	parameters=initialize_parameters(layers_dims)
	#迭代训练
	for i in range(0,num_iterations):
		#正向传播
		AL,caches=forward_propagation(X,parameters)
		#计算损失函数
		cost=compute_cost(AL,Y)
		#反向传播
		grads=backward_propagation(AL, Y, caches)
		#更新参数
		parameters = update_parameters(parameters, grads, learning_rate)
		# 每迭代 100 次,打印 cost
		if (i+1) % 100 == 0:
			print ("Cost after iteration %i: %f" %(i+1, cost))
	#绘制cost趋势图
	plt.plot(np.squeeze(cost))
	plt.ylabel('cost')
	plt.xlabel('迭代训练次数')
	plt.title("学习率为"+str(learning_rate))
	plt.show()
	return parameters

#定义整个神经网络的预测函数
def predict(X,parameters):
	"""
	函数输入:
		X:神经网络输入
		parameters:训练完成后的网络参数
	函数输出:
		Y_pred:预测样本标签
	"""
	#L层模型前向传播
	AL,caches =forward_propagation(X,parameters)
	#预测标签
	Y_pred=np.zeros((1,X.shape[1]))
	Y_pred[AL>0.5]=1
	return Y_pred

#构建神经网络
layers_dims=[12288,200,100,20,6,1]   #5层神经网络
parameters=nn_model(X_train,Y_train,layers_dims,num_iterations=2000,learning_rate=0.02)
#使用该模型对测试集进行预测
Y_test_prev=predict(X_test,parameters)
acc_test=np.mean(Y_test_pred==Y_test)
print(acc_test)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/314284
推荐阅读
相关标签
  

闽ICP备14008679号