赞
踩
即便是单层的神经网络只要隐藏层有足够多的神经单元,神经网络的宽度足够大,深层神经网络复杂度就足够高,就能拟合任意复杂的函数。但是并不是神经网络越宽越好,尤其是在计算及视觉领域,,例如:第一层是边缘信息;第二层是局部特征,神经网络越深,提取的特征越复杂,从模糊到详细、从局部到整体可见隐藏层越多能够提取的特征就越丰富、越复杂,模型的准确率就会越高,此时包含多隐藏层的深层神经网络往往性能更好。
但是在实际应用中,尽量选择层数较少的神经网络,才能有效避免发生过拟合,对于较为复杂的问题,再考虑使用深层神经网络模型。
前向传播:
{
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[l−1]+b[l]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ba7mPw44-1635233129590)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211021152209322.png)]
反向传播:
{
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[l−1]=W[l]T⋅dZ[l]db[l]=m1∑dZ[l]dW[l]=m1dZ[l]⋅A[l−1]TdZ[l]=dA[l]∗g‘(Z[l])
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1TE5uvT-1635233129600)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211021152223131.png)]
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)]
输出层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]=1−A[L]1−Y−A[L]Y
公式总结:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qG6ub8NI-1635233129615)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211021152117477.png)]
基本原理:多分类与二分类(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]
Softmax损失函数:因为不是二分问题,因此不能再套用交叉熵损失函数了,我们希望正确类别对应的概率值
A
i
[
L
]
(
i
=
1
,
2
,
…
,
C
,
C
为
总
的
类
别
个
数
)
A^{[L]}_i(i=1,2,…,C,C为总的类别个数)
Ai[L](i=1,2,…,C,C为总的类别个数),越大越好,这样错误越小,损失也就越小。_
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]
对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})
L对zi[L]的偏导数为:∂zi[L]∂L=j∑(∂aj[L]∂Lj∂zi[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!=j∂zi[L]∂aj[L]=∂zi[L]∂ai[L]=∂zi[L]∂(∑keZk[L]eZi[L])=(∑keZk[L])2∑keZk[L]eZi[L]−(eZi[L])2=(∑keZk[L]eZi[L])(1−∑keZk[L]eZi[L])=ai[L](1−ai[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]∂Lj∂zi[L]∂aj[L])=i=j∑(∂aj[L]∂Lj∂zi[L]∂aj[L])+i!=j∑(∂aj[L]∂Lj∂zi[L]∂aj[L])=i=j∑(−aj[L]yi)(ai[L](1−ai[L]))+i!=j∑(−aj[L]yi)(−ai[L]aj[L])=i=j∑(ai[L]yi−yi)+i!=j∑ai[L]yj=ai[L]j∑yj−yi
因为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]−yi如果是m个样本则可以写成∂Z[L]∂L=A[L]−Y
经过推到我们发现,多分类函数Softmax的梯度
d
Z
[
L
]
dZ^{[L]}
dZ[L]与而分类函数Sigmoid函数的梯度是完全一样的,因此我们可以继续进行神经网络的反向传播梯度计算了。
将会解决一个图像二分类问题,可能前馈神经网络效果并不够好,可以对算法进行进一步优化,也可以采用后面讲解的卷积神经网络加以解决。
准备数据:首先需要将图片导入,还需要将图片矩阵平铺式展开,并且将图片所有像素归一化至[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
参数初始化:深层神经网络需要一个神经网络总层数长度的列表,存储神经网络各层神经元个数,包括输入层,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
前向传播:浅层神经网络中隐藏层的激活函数一般选择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
交叉熵损失:需要计算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
反向传播:
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) #绘制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
训练与预测:构建一个五层神经网络,迭代训练次数为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)
全部代码:
需要安一下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)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。