吴恩达深度学习之建立深度神经网络

本次编程练习的目的是创建一个大于2层的深度神经网络。

简单讲述一下具体的实现步骤:

  • 初始化参数: 把W初始化为随机数,b初始化为0。

  • 正向传播: 正着计算,得到最终预测值,同时记录下中间的各种参数,之后求导数要使用。
    把整个过程分解成了三个函数:
    linear_forward(A, W, b) --> 计算线性函数Z = W * A_pre + b
    linear_activation_forward(A_pre, W, b, activation) --> 计算激活函数relu/sigmoid,其实也是计算当前层的所有参数,调用了函数linear_forward
    L_model_forward(X, parameters) --> 计算出最终的预测值,并记录中间过程中的变量,调用了函数linear_activation_forward

  • 成本函数: 直接使用成本函数的计算公式计算即可

  • 反向传播: 从最后一层开始,反着计算参数的梯度(也就是导数),最终要使用这些导数进行变量的更新。
    整个过程也是分成了三个函数,可以类比正向传播的过程:
    linear_backward(dZ, cache) —> 计算线性函数Z = W * A_pre + b相对于A的导数dA
    linear_activation_backward(dA, cache, activation) —> 计算这一层的所有导数以及上一层的dA(是从正向传播角度来看的上一层),这一层的导数包括dW, db。调用了函数linear_backward
    L_model_backward(AL, Y, caches)—>计算整个神经网络参数的导数,也就是每一层的dW, db,调用了函数linear_activation_backward

  • 更新参数: 使用公式:w = w - α * dw (此处的α为学习率)循环计算每一层的参数(参数b也是同样的道理,同样的α)

更详细的解释放在了代码注释当中

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

# 初始化双层神经网络(可以不看,本次关注的是深层神经网络)
def initialize_parameters(nx, nh, ny):
   np.random.seed(1)
   W1 = np.random.rand(nh, nx) * 0.01
   b1 = np.zeros((nh, 1))
   W2 = np.random.rand(ny, nh) * 0.01
   b2 = np.zeros((ny, 1))

   assert(W1.shape == (nh, nx))
   assert(b1.shape == (nh, 1))
   assert(W2.shape == (ny, nh))
   assert(b2.shape == (ny, 1))

   parameters = {'W1':W1,
                 'b1':b1,
                 'W2':W2,
                 'b2':b2}
   return parameters

# 初始化L层神经网络
def initialize_parameters_deep(layer_dims):
   """
   input:
       layer_dims: 类型为list, 包含每层的神经元数量
   output:
       parameters: 类型为dict, 包含所有的参数
   """
   L = len(layer_dims)
   parameters = {}

   for i in range(1, L):
       W = np.random.rand(layer_dims[i], layer_dims[i - 1]) * 0.01
       b = np.zeros((layer_dims[i], 1))
       parameters['W' + str(i)] = W
       parameters['b' + str(i)] = b

       assert(parameters['W' + str(i)].shape == (layer_dims[i], layer_dims[i - 1]))
       assert(parameters['b' + str(i)].shape == (layer_dims[i], 1))
   return parameters

# 正向传播----计算线性函数
def linear_forward(A, W, b):
   """
   input:
       A: 估计值
       W: 权重
       b: 偏置
   output:
       Z: 线性组合之后的值
       cache: 类型为tuple, cache == (A, W, b)
   """
   Z = np.dot(W, A) + b

   assert(Z.shape == (W.shape[0], A.shape[1]))
   cache = (A, W, b)
   return Z, cache

# 正向传播----计算线性激活函数
def linear_activation_forward(A_pre, W, b, activation):
   """
   input:
       A_pre: 上一层的估计值
       W: 本层的权重
       b: 本层的偏置
       activation: 激活函数名称
   output:
       A: 本层的估计值
       cache: ((A_pre, W, b), Z)
   """
   Z, linear_cache = linear_forward(A_pre, W, b)
   if activation == 'sigmoid':
       A, activation_cache = sigmoid(Z)        
   elif activation == 'relu' :
       A, activation_cache = relu(Z)

   assert(A.shape == (W.shape[0], A_pre.shape[1]))
   cache = (linear_cache, activation_cache)
   return A, cache

# 正向传播-----最终函数
def L_model_forward(X, parameters):
   """
   input:
       X: 输入的样本特征
       parameters: 参数(类型为dict)
   output:
       AL: 最终的估计值
       caches: 每一层的所有参数(类型为list)[((A_pre, W, b), Z)...]
   """
   caches = []
   A = X
   L = len(parameters) // 2

   for i in range(1, L):
       A, cache = linear_activation_forward(A, parameters['W' + str(i)], parameters['b' + str(i)], "relu")
       caches.append(cache)
   AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], "sigmoid")
   caches.append(cache)

   assert(AL.shape == (1, X.shape[1]))
   return AL, caches 

# 计算成本函数
def compute_cost(AL, Y):
   m = AL.shape[1]
   cost = -1 / m * np.sum(Y * np.log(AL) + (1 - Y) * np.log((1 - AL)))
   cost = np.squeeze(cost)

   assert(cost.shape == ())
   return cost

# 反向传播----计算线性函数的导数
def linear_backward(dZ, cache):
   """
   input:
       dZ: Z对成本函数J的导数 
       cache:参数(A_pre, W, b)
   output:
       dA_pre:上一层A的导数
       dW:W的导数
       db:b的导数
   """
   A_pre, W, b = cache
   m = A_pre.shape[1]

   dW = 1 / m * np.dot(dZ, A_pre.T)
   db = 1 / m * np.sum(dZ, axis = 1, keepdims = True)
   dA_pre = np.dot(W.T, dZ)

   assert(dA_pre.shape == A_pre.shape)
   assert(dW.shape == W.shape)
   assert(db.shape == b.shape)
   return dA_pre, dW, db

# 反向传播----计算激活函数的导数
def linear_activation_backward(dA, cache, activation):
   """
   input:
       dA: A的导数
       cache: 参数((A_pre, W, b), Z)
       activation: 激活函数的名字
   output:
       dA_pre: 上一层A的导数
       dW:W的导数
       db:b的导数
   """
   linear_cache, activation_cache = cache

   if activation == 'relu':
       dZ = relu_backward(dA, activation_cache)
       dA_pre, dW, db = linear_backward(dZ, linear_cache)
   elif activation == 'sigmoid':
       dZ = sigmoid_backward(dA, activation_cache)
       dA_pre, dW, db = linear_backward(dZ, linear_cache)

   return dA_pre, dW, db

# 反向传播----最终所有导数
def L_model_backward(AL, Y, caches):
   """
   input:
       AL:整个神经网络的最终预测值
       Y:实际值
       caches:参数(包含L个层的所有参数)[((A_pre, W, b), Z)...]
   output:
       grads:所有层的梯度(类型为dict),使用诸如grads['dW2']这种方式访问
   """
   m = AL.shape[1]
   Y = Y.reshape(AL.shape)
   grads = {}
   L = len(caches)

   dAL = -(np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))

   current_cache = caches[L - 1]
   grads['dA' + str(L)], grads['dW' + str(L)], grads['db' + str(L)] = linear_activation_backward(dAL, current_cache, "sigmoid")

   for l in reversed(range(L - 1)):
       current_cache = caches[l]
       dA_pre, dW, db = linear_activation_backward(grads['dA' + str(l + 2)], current_cache, 'relu')
       grads['dA' + str(l + 1)] = dA_pre
       grads['dW' + str(l + 1)] = dW
       grads['db' + str(l + 1)] = db

   return grads

# 更新参数
def update_parameters(parameters, grads, learning_rate):
   """
   input:
       parameters: 所有层的参数(包括W, b)
       grads: 所有层的梯度
       learning_rate: 学习率
   output:
       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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值