知识点:深度神经网络的实现,初始化,正向传播,反向传播
1 安装包
numpy是Python科学计算的基本包。
matplotlib是在Python中常用的绘制图形的库。
dnn_utils为此笔记本提供了一些必要的函数。
testCases提供了一些测试用例来评估函数的正确性
np.random.seed(1)使所有随机函数调用保持一致。 这将有助于我们评估你的作业,请不要改变seed。
import numpy as np
import h5py
import matplotlib.pyplot as plt
from testCases_v2 import *
from dnn_utils_v2 import sigmoid, sigmoid_backward, relu, relu_backward
%matplotlib inline
plt.rcParams['figure.figsize'] = (5.0, 4.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
%load_ext autoreload
%autoreload 2
np.random.seed(1)
2 作业大纲
**注意:**对于每个正向函数,都有一个对应的反向函数。 这也是为什么在正向传播模块的每一步都将一些值存储在缓存中的原因。缓存的值可用于计算梯度。 然后,在反向传导模块中,你将使用缓存的值来计算梯度。 此作业将指导说明如何执行这些步骤。
3 初始化
首先编写两个辅助函数用来初始化模型的参数。 第一个函数将用于初始化两层模型的参数。 第二个将把初始化过程推广到L层模型上。
3.1 2层神经网络
练习**:**创建并初始化2层神经网络的参数。
说明:
模型的结构为:LINEAR -> RELU -> LINEAR -> SIGMOID。
随机初始化权重矩阵。 确保准确的维度,使用np.random.randn(shape)* 0.01。
将偏差初始化为0。 使用np.zeros(shape)。
# 随机初始化两层神经网络
def initialize_parameters(n_x,n_h,n_y):
w1 = np.random.randn(n_h,n_x) * 0.01
b1 = np.zeros((n_h,1))
w2 = np.random.rand(n_y,n_h) * 0.01
b2 = np.zeros((n_y,1))
parameters = {
"w1":w1,
"b1":b1,
"w2":w2,
"b2":b2
}
assert (w1.shape ==(n_h,n_x))
assert (b1.shape == (n_h, 1))
assert (w2.shape == (n_y, n_h))
assert (b2.shape == (n_y, 1))
return parameters
parameters = initialize_parameters(2,2,1)
print("w1 = " + str(parameters["w1"]))
print("b1 = " + str(parameters["b1"]))
print("w2 = " + str(parameters["w2"]))
print("b2 = " + str(parameters["b2"]))
3.2 L层神经网络
# 随机初始化L层
def initialize_parameters_deep(layer_dims):
np.random.seed(3)
L = len(layer_dims)
parameters = {}
for l in range(1,L):
parameters['w'+str(l)] = np.random.randn(layer_dims[l],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
layer_dims = [5,4,3]
parameters = initialize_parameters_deep(layer_dims)
print(parameters)
4 正向传播模块
4.1 线性正向
# 线性正向
def linear_forward(A,w,b):
z = w.T @ A + b
assert (z.shape == (w.shape[0],A.shape[1]))
cache = (A,w,b)
return z,cache
4.2 正向线性激活
# 正向线性激活
def linear_activation_forward(A_prev,w,b,activation):
z,linear_cache = linear_forward(A_prev,w,b)
if activation == 'sigmoid':
A,activation_cache = sigmoid(z)
elif activation == 'relu':
A,activation_cache = relu(z)
cache = (linear_cache,activation_cache)
return A,cache
A_prev, W, b = linear_activation_forward_test_case()
A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "sigmoid")
print("With sigmoid: A = " + str(A))
A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "relu")
print("With ReLU: A = " + str(A))
#With sigmoid: A = [[0.96890023 0.11013289]]
#With ReLU: A = [[3.43896131 0. ]]
**注意:**在深度学习中,"[LINEAR->ACTIVATION]"计算被视为神经网络中的单个层,而不是两个层。
4.3 L层模型
为了方便实现L层神经网络,你将需要一个函数来复制前一个函数(使用RELU的linear_activation_forward)L-1次,以及复制带有SIGMOID的linear_activation_forward。
# 定义 L 层模型
def L_model_forward(X,parameters):
A_prev = X
L = len(parameters) // 2
caches = []
# 这里range(1,L) 因为只有前L-1层是做relu函数激活,最后一层用sigmoid
for l in range(1,L):
A,cache = linear_activation_forward(A_prev,parameters['W'+str(l)],parameters['b'+str(l)],activation='relu')
caches.append(cache)
AL,cache = linear_activation_forward(A,parameters['W'+str(L)],parameters['b'+str(L)],activation='sigmoid')
caches.append(cache)
assert (AL.shape == (1,X.shape[1]))
return AL,caches
X, parameters = L_model_forward_test_case()
AL,caches = L_model_forward(X,parameters)
print('AL='+str(AL))
print('length of caches list ='+str(len(caches)))
#AL=[[0.17007265 0.2524272 ]]
#length of caches list =2
5 损失函数
现在,你将实现模型的正向和反向传播。 你需要计算损失,以检查模型是否在学习。
练习:使用以下公式计算交叉熵损失***J***
# 计算损失函数
def compute_cost(AL,Y):
m = Y.shape[1]
cost = - 1/m * np.sum((Y * np.log(AL)+(1-Y) * np.log(1-AL)),axis = 1,keepdims=True)
cost = np.squeeze(cost)
assert (cost.shape == ())
return cost
Y, AL = compute_cost_test_case()
print("cost = " + str(compute_cost(AL, Y)))
# cost = 0.41493159961539694
6 反向传播模块
就像正向传播一样,你将实现辅助函数以进行反向传播。 请记住,反向传播用于计算损失函数相对于参数的梯度。
6.1 线性反向
练习:使用上面的3个公式实现linear_backward()。
# 綫性反向
def linear_backward(dz,cache):
A_prev,w,b = cache
m = A_prev.shape[1]
dw = 1 / m * (dz @ A_prev.T)
db = 1 / m * np.sum(dz,axis = 1,keepdims= True)
dA_prev = w.T @ dz
return dA_prev,dw,db
# Set up some test inputs
dZ, linear_cache = linear_backward_test_case()
dA_prev, dW, db = linear_backward(dZ, linear_cache)
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db))
6.2 反向线性激活
6.3 反向L层模型
def L_model_backward(AL,Y,caches,):
grads = {}
L = len(caches)
# 索引从0开始,所以是L-1
current_cache = caches[L-1]
Y = Y.reshape(AL.shape)
dAL = - np.divide(Y,AL) + np.divide(1-Y,1-AL)
grads["dA"+str(L)],grads["dw"+str(L)],grads["db"+str(L)] = linear_activation_backward(dAL,current_cache,activation="sigmoid")
for l in reversed(range(L-1)):
current_cache = caches[l]
grads["dA" + str(l+1)], grads["dw" + str(l+1)], grads["db" + str(l+1)] = linear_activation_backward(grads["dA"+str(l+2)],current_cache,activation="relu")
return grads
AL, Y_assess, caches = L_model_backward_test_case()
grads = L_model_backward(AL, Y_assess, caches)
print ("dw1 = "+ str(grads["dw1"]))
print ("db1 = "+ str(grads["db1"]))
print ("dA1 = "+ str(grads["dA1"]))
6.4 更新参数
# 更新参数
def update_parameters(parameters,grads,learning_rate):
L = len(parameters) // 2
for l in range(L):
parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)] - learning_rate * grads["dW" + str(l + 1)]
parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)] - learning_rate * grads["db" + str(l + 1)]
return parameters
parameters, grads = update_parameters_test_case()
parameters = update_parameters(parameters, grads, 0.1)
print ("W1 = "+ str(parameters["W1"]))
print ("b1 = "+ str(parameters["b1"]))
print ("W2 = "+ str(parameters["W2"]))
print ("b2 = "+ str(parameters["b2"]))