深度神经网络

一、深层神经网络的优势

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

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

二、符号标记

  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
    
  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
    
  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
    
  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
    
  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
    
  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
    
  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
    
  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)
    
  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/
    

    然后安一下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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值