deep_learning_week4.1_Deep_Neural_Network
标签: 机器学习深度学习
代码已上传github:
https://github.com/PerfectDemoT/my_deeplearning_homework
本文将讲述如何建立一个可以设置层数以及各层节点的神经网络
先讲述了如何一步步设置建立这个神经网络,下一篇有讲用这个神经网络建立一个可以“检测图片之中是否有猫咪的分类器”
开始之前,你需要了解这些事情(后面的几个变量的意义)
# 如果要开始看这篇代码,需要先了解这些事情:
# 代码中的linear_activation_forward(A_prev , W , b , activation)函数中,会进行cache缓存A_prev , W , b的操作,下面具体说:
# linear_cache中存的是A_prev , W , b
# activation_cache中存的是该层的 Z
# 另外之后还会有一句将linear_cache 和 activation_cache合并为cache,并且这个cache还会作为一个返回参数
# 并且在L_model_forward()函数中会有一句caches.append(cache)将每一层的cache加入比那辆caches中,并且该函数会返回改值
里面会用到的两个函数(sigmoid与relu)代码是先写好的:
def sigmoid(Z):
"""
Implements the sigmoid activation in numpy
Arguments:
Z -- numpy array of any shape
Returns:
A -- output of sigmoid(z), same shape as Z
cache -- returns Z as well, useful during backpropagation
"""
A = 1/(1+np.exp(-Z))
cache = Z
return A, cache
def relu(Z):
"""
Implement the RELU function.
Arguments:
Z -- Output of the linear layer, of any shape
Returns:
A -- Post-activation parameter, of the same shape as Z
cache -- a python dictionary containing "A" ; stored for computing the backward pass efficiently
"""
A = np.maximum(0,Z)
assert(A.shape == Z.shape)
cache = Z
return A, cache
好的,现在开始一步步建立你的神经网络啦
1.1老样子,先导入包
#老样子,首先先导入包
import numpy as np
import h5py
import matplotlib.pyplot as plt
from testCases import *
from dnn_utils import sigmoid, sigmoid_backward, relu, relu_backward
#设置一下接下来画图会用到的一下参数
plt.rcParams['figure.figsize'] = (5.0, 4.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
np.random.seed(1) #设置一个随机种子
1.2接下来开始随机初始化
#现在开始写生成随机参数的函数
#首先是两层网络的参数(和上一次作业一样)
# GRADED FUNCTION: initialize_parameters
def initialize_parameters(n_x, n_h, n_y):
"""
Argument:
n_x -- size of the input layer
n_h -- size of the hidden layer
n_y -- size of the output layer
Returns:
parameters -- python dictionary containing your parameters:
W1 -- weight matrix of shape (n_h, n_x)
b1 -- bias vector of shape (n_h, 1)
W2 -- weight matrix of shape (n_y, n_h)
b2 -- bias vector of shape (n_y, 1)
"""
np.random.seed(1)
### START CODE HERE ### (≈ 4 lines of code)
W1 = np.random.randn(n_h , n_x) * 0.01
b1 = np.zeros((n_h , 1))
W2 = np.random.randn(n_y , n_h) * 0.01
b2 = np.zeros((n_y , 1))
### END CODE HERE ###
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))
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
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"]))
print("=============================")
输出如下:
W1 = [[ 0.01624345 -0.00611756]
[-0.00528172 -0.01072969]]
b1 = [[ 0.]
[ 0.]]
W2 = [[ 0.00865408 -0.02301539]]
b2 = [[ 0.]]
1.3 刚刚的还是两层的,现在开始真正初始化一下L层的
#现在我们来看看L层网络的参数随机初始化
# GRADED FUNCTION: initialize_parameters_deep
def initialize_parameters_deep(layer_dims):
"""
Arguments:
layer_dims -- python array (list) containing the dimensions of each layer in our network
Returns:
parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL":
Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1])
bl -- bias vector of shape (layer_dims[l], 1)
"""
np.random.seed(3)
parameters = {}
L = len(layer_dims) # number of layers in the network
for l in range(1, L):
### START CODE HERE ### (≈ 2 lines of code)
parameters['W' + str(l)] = np.random.randn(layer_dims[l] , layer_dims[l-1]) * 0.01
parameters['b' + str(l)] = np.zeros((layer_dims[l] , 1))
### END CODE HERE ###
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
现在开始输出
#好der,现在来输出一下这个可以用于好几层的神经网络参数
parameters = initialize_parameters_deep([5,4,3])
print(parameters)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))
# print("W3 = " + str(parameters["W3"]))
# print("b3 = " + str(parameters["b3"]))
print("==================================")
这里只暂时输出前两层的参数
{'W1': array([[ 0.01788628, 0.0043651 , 0.00096497, -0.01863493, -0.00277388],
[-0.00354759, -0.00082741, -0.00627001, -0.00043818, -0.00477218],
[-0.01313865, 0.00884622, 0.00881318, 0.01709573, 0.00050034],
[-0.00404677, -0.0054536 , -0.01546477, 0.00982367, -0.01101068]]), 'b1': array([[ 0.],
[ 0.],
[ 0.],
[ 0.]]), 'W2': array([[-0.01185047, -0.0020565 , 0.01486148, 0.00236716],
[-0.01023785, -0.00712993, 0.00625245, -0.00160513],
[-0.00768836, -0.00230031, 0.00745056, 0.01976111]]), 'b2': array([[ 0.],
[ 0.],
[ 0.]])}
W1 = [[ 0.01788628 0.0043651 0.00096497 -0.01863493 -0.00277388]
[-0.00354759 -0.00082741 -0.00627001 -0.00043818 -0.00477218]
[-0.01313865 0.00884622 0.00881318 0.01709573 0.00050034]
[-0.00404677 -0.0054536 -0.01546477 0.00982367 -0.01101068]]
b1 = [[ 0.]
[ 0.]
[ 0.]
[ 0.]]
W2 = [[-0.01185047 -0.0020565 0.01486148 0.00236716]
[-0.01023785 -0.00712993 0.00625245 -0.00160513]
[-0.00768836 -0.00230031 0.00745056 0.01976111]]
b2 = [[ 0.]
[ 0.]
[ 0.]]
1.4 现在开始正向传播。
#OK,参数初始化完了,现在来正向传播吧
#先写正向传播要用到的函数,比如说算Z
# GRADED FUNCTION: linear_forward
def linear_forward(A, W, b):
"""
Implement the linear part of a layer's forward propagation.
Arguments:
A -- activations from previous layer (or input data): (size of previous layer, number of examples)
W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
b -- bias vector, numpy array of shape (size of the current layer, 1)
Returns:
Z -- the input of the activation function, also called pre-activation parameter
cache -- a python dictionary containing "A", "W" and "b" ; stored for computing the backward pass efficiently
"""
### START CODE HERE ### (≈ 1 line of code)
Z = np.dot(W , A) + b
### END CODE HERE ###
assert (Z.shape == (W.shape[0], A.shape[1]))
cache = (A, W, b)
return Z, cache
上面得出了A以及cache,其中cache里面包含了A,W,b
下面输出一下
#现在输出一下
A, W, b = linear_forward_test_case()
Z, linear_cache = linear_forward(A, W, b)
print("Z = " + str(Z))
print("===============================")
现在来看看得到的Z值
Z = [[ 3.26295337 -1.23429987]]
1.5 刚刚完成了Z的计算,现在来看看用sigmoid函数与relu函数计算A
#之前是算Z的函数,现在可以用sigmoid函数或者relu函数来算A啦
# GRADED FUNCTION: linear_activation_forward
def linear_activation_forward(A_prev, W, b, activation):
"""
Implement the forward propagation for the LINEAR->ACTIVATION layer
Arguments:
A_prev -- activations from previous layer (or input data): (size of previous layer, number of examples)
W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
b -- bias vector, numpy array of shape (size of the current layer, 1)
activation -- the activation to be used in this layer, stored as a text string: "sigmoid" or "relu"
Returns:
A -- the output of the activation function, also called the post-activation value
cache -- a python dictionary containing "linear_cache" and "activation_cache";
stored for computing the backward pass efficiently
"""
if activation == "sigmoid":
# Inputs: "A_prev, W, b". Outputs: "A, activation_cache".
### START CODE HERE ### (≈ 2 lines of code)
Z, linear_cache = linear_forward(A_prev, W , b)
A, activation_cache = sigmoid(Z)
### END CODE HERE ###
elif activation == "relu":
# Inputs: "A_prev, W, b". Outputs: "A, activation_cache".
### START CODE HERE ### (≈ 2 lines of code)
Z, linear_cache = linear_forward(A_prev, W, b)
A, activation_cache = relu(Z)
### END CODE HERE ###
assert (A.shape == (W.shape[0], A_prev.shape[1]))
cache = (linear_cache, activation_cache)
return A, cache
(注意:这里就出现了之前谈到的linear_cache以及activation_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))
print("==============================")
输出为:
With sigmoid: A = [[ 0.96890023 0.11013289]]
With ReLU: A = [[ 3.43896131 0. ]]
1.6 上面两个函数都是在为前向传播做准备,现在可以写一个完整的前向传播函数了
#现在开始用之前写的函数完成真正的正向传播模型
#L层神经网络前向传播模型函数,返回最终A和缓存各层的A_prev,W,b,Z
def L_model_forward(X, parameters):
"""
Implement forward propagation for the [LINEAR->RELU]*(L-1)->LINEAR->SIGMOID computation
Arguments:
X -- data, numpy array of shape (input size, number of examples)
parameters -- output of initialize_parameters_deep()
Returns:
AL -- last post-activation value
caches -- list of caches containing:
every cache of linear_relu_forward() (there are L-1 of them, indexed from 0 to L-2)
the cache of linear_sigmoid_forward() (there is one, indexed L-1)
"""
caches = []
A = X
L = len(parameters) // 2 # number of layers in the neural network
# Implement [LINEAR -> RELU]*(L-1). Add "cache" to the "caches" list.
for l in range(1, L):
A_prev = A
### START CODE HERE ### (≈ 2 lines of code)
A, cache = linear_activation_forward(A_prev , parameters['W' + str(l)] , parameters['b' + str(l)] , activation='relu')
caches.append(cache) #将该层的cache加入到caches中
### END CODE HERE ###
# Implement LINEAR -> SIGMOID. Add "cache" to the "caches" list.
### START CODE HERE ### (≈ 2 lines of code)
AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], activation="sigmoid")
caches.append(cache)
### END CODE HERE ###
assert (AL.shape == (1, X.shape[1]))
return AL, caches
#其中,要注意的就是对于参数序列的选择(28,29 , 34 行)
#另外每次过了一层神经网络,都要讲=将该层的cache存入caches中(35行)
现在来试验一下输出:
#现在开始看看输出的效果
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)))
print("======================================")
结果长这样:
AL = [[ 0.17007265 0.2524272 ]]
Length of caches list = 2
1.7 老规矩,算完了正向传播,又到了cost函数时间
def compute_cost(AL, Y):
"""
Implement the cost function defined by equation (7).
Arguments:
AL -- probability vector corresponding to your label predictions, shape (1, number of examples)
Y -- true "label" vector (for example: containing 0 if non-cat, 1 if cat), shape (1, number of examples)
Returns:
cost -- cross-entropy cost
"""
m = Y.shape[1]
# Compute loss from aL and y.
### START CODE HERE ### (≈ 1 lines of code)
cost = (-1/m) * np.sum(Y * np.log(AL) + (1-Y) * np.log(1 - AL))
### END CODE HERE ###
cost = np.squeeze(cost) # To make sure your cost's shape is what we expect (e.g. this turns [[17]] into 17).
assert (cost.shape == ())
return cost
和普通的bp神经网络差不多,此不赘述
直接看测试代码吧:
#求cost的式子和上一次作业差别不大,下面看看效果
Y, AL = compute_cost_test_case()
print("cost = " + str(compute_cost(AL, Y)))
print("==================================")
结果长这样:
cost = 0.414931599615
好了,老规矩,开始最后的重点难点,反向传播啦
1.8 慢慢来,先来个最简单的。实现一步线性的反向传播,使用对应层前向传播的缓存A_prev , W , b
先看看函数:
# GRADED FUNCTION: linear_backward
def linear_backward(dZ, cache):
"""
Implement the linear portion of backward propagation for a single layer (layer l)
Arguments:
dZ -- Gradient of the cost with respect to the linear output (of current layer l)
cache -- tuple of values (A_prev, W, b) coming from the forward propagation in the current layer
Returns:
dA_prev -- Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
dW -- Gradient of the cost with respect to W (current layer l), same shape as W
db -- Gradient of the cost with respect to b (current layer l), same shape as b
"""
A_prev, W, b = cache
m = A_prev.shape[1]
### START CODE HERE ### (≈ 3 lines of code)
dW = 1/m * np.dot(dZ , A_prev.T)
db = 1/m * np.sum(dZ , axis=1 , keepdims=False)
dA_prev = np.dot(W.T , dZ)
### END CODE HERE ###
assert (dA_prev.shape == A_prev.shape)
assert (dW.shape == W.shape)
# assert (db.shape == b.shape)
return dA_prev, dW, db
然后接着,上面得到了dA_prev , dW , db,现在我们写一个函数根据指定的激活函数来求各值,
1.9
这里我们先给出最后函数中会用到的relu_backward()函数与sigmoid_backward()函数的代码
def relu_backward(dA, cache):
"""
Implement the backward propagation for a single RELU unit.
Arguments:
dA -- post-activation gradient, of any shape
cache -- 'Z' where we store for computing backward propagation efficiently
Returns:
dZ -- Gradient of the cost with respect to Z
"""
Z = cache
dZ = np.array(dA, copy=True) # just converting dz to a correct object.
# When z <= 0, you should set dz to 0 as well.
dZ[Z <= 0] = 0
assert (dZ.shape == Z.shape)
return dZ
def sigmoid_backward(dA, cache):
"""
Implement the backward propagation for a single SIGMOID unit.
Arguments:
dA -- post-activation gradient, of any shape
cache -- 'Z' where we store for computing backward propagation efficiently
Returns:
dZ -- Gradient of the cost with respect to Z
"""
Z = cache
s = 1/(1+np.exp(-Z))
dZ = dA * s * (1-s)
assert (dZ.shape == Z.shape)
return dZ
现在开始真正”表演”……
# GRADED FUNCTION: linear_activation_backward
def linear_activation_backward(dA, cache, activation):
"""
Implement the backward propagation for the LINEAR->ACTIVATION layer.
Arguments:
dA -- post-activation gradient for current layer l
cache -- tuple of values (linear_cache, activation_cache) we store for computing backward propagation efficiently
activation -- the activation to be used in this layer, stored as a text string: "sigmoid" or "relu"
Returns:
dA_prev -- Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
dW -- Gradient of the cost with respect to W (current layer l), same shape as W
db -- Gradient of the cost with respect to b (current layer l), same shape as b
"""
linear_cache, activation_cache = cache
if activation == "relu":
### START CODE HERE ### (≈ 2 lines of code)
dZ = relu_backward(dA, activation_cache)
dA_prev, dW, db = linear_backward(dZ , linear_cache)
### END CODE HERE ###
elif activation == "sigmoid":
### START CODE HERE ### (≈ 2 lines of code)
dZ = sigmoid_backward(dA , activation_cache)
dA_prev, dW, db = linear_backward(dZ , linear_cache)
### END CODE HERE ###
return dA_prev, dW, db
好了,输出检测一下:
#现在来看看效果
AL, linear_activation_cache = linear_activation_backward_test_case()
dA_prev, dW, db = linear_activation_backward(AL, linear_activation_cache, activation = "sigmoid")
print ("sigmoid:")
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db) + "\n")
dA_prev, dW, db = linear_activation_backward(AL, linear_activation_cache, activation = "relu")
print ("relu:")
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db))
print("========================================")
输出结果如下:
sigmoid:
dA_prev = [[ 0.11017994 0.01105339]
[ 0.09466817 0.00949723]
[-0.05743092 -0.00576154]]
dW = [[ 0.10266786 0.09778551 -0.01968084]]
db = [-0.05729622]
relu:
dA_prev = [[ 0.44090989 -0. ]
[ 0.37883606 -0. ]
[-0.2298228 0. ]]
dW = [[ 0.44513824 0.37371418 -0.10478989]]
db = [-0.20837892]
1.10我们现在把上面的所有反向传播函数做一个整合:
#现在,我们将上面所有的函数整合起来
# GRADED FUNCTION: L_model_backward
def L_model_backward(AL, Y, caches):
"""
Implement the backward propagation for the [LINEAR->RELU] * (L-1) -> LINEAR -> SIGMOID group
Arguments:
AL -- probability vector, output of the forward propagation (L_model_forward())
Y -- true "label" vector (containing 0 if non-cat, 1 if cat)
caches -- list of caches containing:
every cache of linear_activation_forward() with "relu" (it's caches[l], for l in range(L-1) i.e l = 0...L-2)
the cache of linear_activation_forward() with "sigmoid" (it's caches[L-1])
Returns:
grads -- A dictionary with the gradients
grads["dA" + str(l)] = ...
grads["dW" + str(l)] = ...
grads["db" + str(l)] = ...
"""
grads = {}
L = len(caches) # the number of layers
m = AL.shape[1]
Y = Y.reshape(AL.shape) # after this line, Y is the same shape as AL
# Initializing the backpropagation
### START CODE HERE ### (1 line of code)
dAL = -(np.divide(Y , AL) - np.divide(1 - Y , 1 - AL))
### END CODE HERE ###
# Lth layer (SIGMOID -> LINEAR) gradients. Inputs: "AL, Y, caches". Outputs: "grads["dAL"], grads["dWL"], grads["dbL"]
### START CODE HERE ### (approx. 2 lines)
current_cache = caches[L-1]
grads["dA" + str(L)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(dAL , current_cache , activation='sigmoid')
#注意,这里传回来的dA其实为上一层的dA,即:dA_prev((这一点在下面的43行dA的标号里可以很好体现))
### END CODE HERE ###
for l in reversed(range(L - 1)):
# lth layer: (RELU -> LINEAR) gradients.
# Inputs: "grads["dA" + str(l + 2)], caches". Outputs: "grads["dA" + str(l + 1)] , grads["dW" + str(l + 1)] , grads["db" + str(l + 1)]
### START CODE HERE ### (approx. 5 lines)
current_cache = caches[l]
#注意grads["dA"+str(l+2)],这里是正确的,结合第407行,一定要弄清楚grads["dA^[n]"]中每个dA表示第几层的dA
dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA"+str(l + 2)] , current_cache , activation='relu')
grads["dA" + str(l + 1)] = dA_prev_temp
grads["dW" + str(l + 1)] = dW_temp
grads["db" + str(l + 1)] = db_temp
### END CODE HERE ###
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"]))
结果长这样:
dW1 = [[ 0.41010002 0.07807203 0.13798444 0.10502167]
[ 0. 0. 0. 0. ]
[ 0.05283652 0.01005865 0.01777766 0.0135308 ]]
db1 = [-0.22007063 0. -0.02835349]
dA1 = [[ 0. 0.52257901]
[ 0. -0.3269206 ]
[ 0. -0.32070404]
[ 0. -0.74079187]]
1.11 最后,更新参数开始,这里注意一下参数的下标,其他没啥,噢,对了,里面的学习率很重要,这个一定要多实验多试试。
#最后,更新参数开始
# GRADED FUNCTION: update_parameters
def update_parameters(parameters, grads, learning_rate):
"""
Update parameters using gradient descent
Arguments:
parameters -- python dictionary containing your parameters
grads -- python dictionary containing your gradients, output of L_model_backward
Returns:
parameters -- python dictionary containing your updated parameters
parameters["W" + str(l)] = ...
parameters["b" + str(l)] = ...
"""
L = len(parameters) // 2 # number of layers in the neural network
# Update rule for each parameter. Use a for loop.
### START CODE HERE ### (≈ 3 lines of code)
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)]
### END CODE HERE ###
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"]))
结果如下:
W1 = [[-0.59562069 -0.09991781 -2.14584584 1.82662008]
[-1.76569676 -0.80627147 0.51115557 -1.18258802]
[-1.0535704 -0.86128581 0.68284052 2.20374577]]
b1 = [[-0.04659241]
[-1.28888275]
[ 0.53405496]]
W2 = [[-0.55569196 0.0354055 1.32964895]]
b2 = [[-0.84610769]]
好了今天先到这里(刚和队友调完数据库,又总结了统计学习方法的一个比较短的一章(朴素贝叶斯,已经发布),又写了个这个。。。怪可怜的,,,头发要紧头发要紧),后面还有一个利用上方的函数来做一个检测图片中是否有猫的分类器,并且我还会把上面用到的原理公式码出来,不要慌,马上回来。