学习链接 学习链接
建立一个深度神经网络,需要了解下面两张图
(上图是针对单个样本而言的)
caches=((cache1,activation_cache1)(cache2,activation_cache2)…)用来存储后向传播需要用到的前向传播运算出来的值
parameters用来存储W,b值
grads用来存储梯度值dW,dA,db
一、初始化参数
因为初始化的参数要继续参与更新参数等步骤,所以用一个词典parameters将初始化的W,b值保存起来
代码如下:
def initialize_parameters_deep(layer_dims):
"""
:param layer_dims: 输入层+隐藏层+输出层
:return: parameters:各层w,b的初始值
"""
parameters={
}
for l in range(1,len(layer_dims)):
parameters["W"+str(l)]=np.random.randn(layer_dims[l],layer_dims[l-1])/np.sqrt(layer_dims[l-1])
parameters["b"+str(l)]=np.zeros((layer_dims[l],1))
assert (parameters["W" + str(l)].shape == (layer_dims[l], layer_dims[l - 1]))
assert (parameters["b" + str(l)].shape == (layer_dims[l], 1))
return parameters
二、前向传播
前向传播包括线性计算,和使用激活函数运算
- 线性运算
如图所示,线性计算需要W,A,b,,传出Z以便作激活运算,保存W,A,b参与反向传播运算,故要将W,A,b存入cache中
代码如下:
def linear_forward(A,W,b):
Z=np.dot(W,A)+b
cache=(A,W,b)
return Z,cache
2.加入激活函数的运算
这里在隐藏层中使用relu函数,输出层中使用sigmoid函数,传入激活函数部分有Z和函数名称activation,如图所示得到的A,Z要参与反向传播,其中A还需要参与线性运算部分中,故使用activation_cache将Z,以及W,b,A_prev保存起来以便于后续工作
代码如下:
def linear_activation_forward(A_prev,W,b,activation):
if activation=="relu":
Z, linear_cache = linear_forward(A_prev, W, b)
A,activation_cache=relu(Z)
if activation=="sigmoid":
Z, linear_cache = linear_forward(A_prev, W, b)
A,activation_cache=sigmoid(Z)
assert (A.shape == Z.shape)
activation_cache=(linear_cache,activation_cache)
return A,activation_cache
- 构建前向传播模型
对于整个前向传播模型,需要W,X(即A0),b,activation(激活函数名称),传出W,A,b,Z做反向传播,用caches保存,其中最后一个A需要参与成本计算中,所以最后一个A写作AL
代码如下:
def L_model_forward(X,parameters):
"""
:param paramters:
:param X:
:return: AL,caches
"""
caches=[]
A=X
L=len(parameters)//2
for l in range(1,L):
A_prev=A
# 先线性在激活,激活运算中包括了线性运算,故只用写激活运算即可
A,activation_cache=linear_activation_forward(A_prev,parameters["W"+str(l)],parameters["b"+str(l)],"relu")
caches.append(activation_cache)
AL, activation_cache = linear_activation_forward(A, parameters["W" + str(L)], parameters["b" + str(L)], "sigmoid")
caches.append(activation_cache)
assert (AL.shape==(1,X.shape[1]))
return AL,caches
三、计算成本
计算成本这个函数需要传入真实的结果值,以及估计值AL,最后得到损失函数
def compute_loss(AL,Y):
"""
:param AL: 估计值
:param Y:真实值
:return:损失值
"""
# m是样本数
m = Y.shape[1]
# 函数
cost = -np.sum(np.multiply(np.log(AL), Y) + np.multiply(np.log(1 - AL), 1 - Y)) / m
cost = np.squeeze(cost)
assert (cost.shape == ())
return cost
四、反向传播
- 线性运算
需要传入从前向传播得到的W,b,A_prev也就是cach和dZ,传出db,dW,dA_prev
def linear_backward(dZ,cache):
A_prev,W,b=cache
m=A_prev.shape[1]
dW=np.dot(dZ,A_prev.T)/m
db=np.sum(dZ,axis=1,keepdims=True)/m
dA_prev=np.dot(W.T,dZ)/m
assert (dA_prev.shape == A_prev.shape)
assert (db.shape == b.shape)
assert (dW.shape == W.shape)
return dA_prev, dW, db
- 加入激活函数的运算
传入从前向传播中获取的A,activation_cache和激活函数名称,传出dA_prev,dW,db
def linear_activation_backward(dA,activation_cache,activation="relu"):
linear_cache, activation_backward_cache = activation_cache
if activation=="relu":
dZ=relu_backward(dA,activation_backward_cache)
dA_prev