神经网络识别猫图形

使用二层和四层神经网络分类图片

目的:判断一张图片是否是猫。查看两层和四层的区别

1.编写获取数据函数

def load_data():
    train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
    train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features
    train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels
 
    test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
    test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # your test set features
    test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels
 
    classes = np.array(test_dataset["list_classes"][:]) # the list of classes
    
    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))#(1,m) 二维数组表示行向量 
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
    
    return train_set_x_orig, train_set_y_orig,test_set_x_orig, test_set_y_orig, classes



#加载原始数据集
train_x_orig,train_y,test_x_orig,test_y,classes = load_data()
  • 可视化某一张图片 25

#可视化某一张图片
index=25
plt.imshow(train_x_orig[index]) #可视化原始训练集中第index+1张图片
print("y = "+str(train_y[0,index])+". It is a "+classes[train_y[0,index]].decode("utf-8")+" picture.")

在这里插入图片描述

  • 查看原始数据集形状

m_train = train_set_y.shape[1] #训练集里图片的数量。
m_test = test_set_y.shape[1] #测试集里图片的数量。
num_px = train_set_x_orig.shape[1] #训练、测试集里面的图片的宽度和高度(均为64x64)。
#现在看一看我们加载的东西的具体情况
print ("训练集的数量: m_train = " + str(m_train))
print ("测试集的数量 : m_test = " + str(m_test))
print ("每张图片的宽/高 : num_px = " + str(num_px))
print ("每张图片的大小 : (" + str(num_px) + ", " + str(num_px) + ", 3)")
print ("训练集_图片的维数 : " + str(train_set_x_orig.shape))
print ("训练集_标签的维数 : " + str(train_set_y.shape))
print ("测试集_图片的维数: " + str(test_set_x_orig.shape))
print ("测试集_标签的维数: " + str(test_set_y.shape))
==========================================


训练集的数量: m_train = 209
测试集的数量 : m_test = 50
每张图片的宽/: num_px = 64
每张图片的大小 : (64, 64, 3)
训练集_图片的维数 : (209, 64, 64, 3)
训练集_标签的维数 : (1, 209)
测试集_图片的维数: (50, 64, 64, 3)
测试集_标签的维数: (1, 50)

在这里插入图片描述

  • 数据集预处理

在此之后,训练和测试数据集是一个numpy数组,【每列代表一个平坦的图像】 ,应该有m_train和m_test列
当想将形状(a,b,c,d)的矩阵X平铺成形状(b * c * d,a)的矩阵X_flatten时,可以使用以下代码:


#对训练集和测试集中的图片进行转型
train_x_flatten=train_x_orig.reshape(m_train,-1).T #训练集图片的特征矩阵 (num_px*num_px*3,m_train) 每一列为一张图片的拉伸后的特征向量
test_x_flatten=test_x_orig.reshape(m_test,-1).T #测试集图片的特征矩阵 (num_px*num_px*3,m_test) 每一列为一张图片的拉伸后的特征向量
 
  • 数据标准化
#对图片的特征矩阵进行标准化 除以最大值255 使特征数值在0-1之间
train_x=train_x_flatten/255
test_x=test_x_flatten/255
 
print ("train_x's shape: " + str(train_x.shape))
print ("test_x's shape: " + str(test_x.shape))

在这里插入图片描述

将使用两种神经网络进行训练

1. 双层神经网络(L=2 单隐层)
2. L层的神经网络(L>=3 隐层数>=2)

一. 双层神经网络

在这里插入图片描述
在这里插入图片描述

1.构建神经网络步骤

  • 初始化模型参数(随机)/定义模型超参数
  • 梯度下降迭代步骤
  • 向前
  • 计算代价
  • 反向
  • 计算梯度
  • 更新参数

**

构建双层神经网络(L = 2 ,单隐层)

**

linear>relu>linear>sigmoid

  • 随机初始化模型参数(高斯分布)*0.01
def initialize_parameters(n_x,n_h,n_y):
    '''
    初始化双层神经网络的参数
    
    参数:
    n_x:输入层单元数 取决于输入样本的特征向量维数
    n_h:隐层单元数 可以任意设置
    n_y:输出层单元数 n_y=1
    
    返回:
    parameters:初始化后的参数(字典形式)
        W1:(n_h,n_x)
        b1:(n_h,1)
        W2:(n_y,n_h)
        b2:(n_y,1)
    '''
    
    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))
    
    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     
  1. 向前传播
  2. 以下定义的前向传播是在某一层上的前向传播 不是总体的前向传播
    对于浅层神经网络 总体的前向传播可以一层层写出来 也可以用for循环
    对于深层神经网络 总体的前向传播用for循环迭代单层的前向传播 直到最后的输出,当然也可以一层层的写

1.线性向前运算代码实现
公式: Z = W T X + b Z = W^T*X +b

def linear_forward(A,W,b):
    '''
    隐层/输出层 前向传播的线性组合部分
    
    参数:
    A:上一层的激活函数输出 初始值是样本特征矩阵X
    W:当前层的权重参数矩阵
    b: 当前层的偏置参数向量
    
    返回:
    Z:当前层的线性组合输出
    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

2.前向激活函数代码实现


def sigmoid(Z):
    '''
    2分类,输出层采用sigmoid激活函数
    输出层前向传播的激活函数部分
    
    参数:
    Z:当前层(输出层)的线性组合输出
    
    返回:
    A:当前层(输出层)的激活输出
    cache: Z
    '''
    A = 1./(1+np.exp(-Z))
    cache = Z
    
    assert(A.shape == Z.shape)
    
    return A,cache
 
def relu(Z):
    '''
    隐层统一采用relu激活函数
    
    参数:
    Z:当前层(隐层)的线性组合输出
    
    返回:
    A:当前层(隐层)的激活输出
    cache: Z
    '''
    
    A = np.maximum(0,Z)
    cache = Z
    
    assert(A.shape == Z.shape)
    
    return A,cache
    
    
def linear_activation_forward(A_prev,W,b,activation):
    '''
    隐层(输出层)的前向传播操作,包括线性组合和激活函数两部分
    
    参数:
    A_perv:上一层的激活函数输出 初始值是样本特征矩阵X
    W:上一层和当前层之间的权重参数矩阵
    b: 上一层和当前层之间的偏置参数向量
    activation:使用的激活函数类型 一般所有隐层的激活函数是一样的 输出层如果作2分类使用sigmoid
    
    返回:
    A: 当前层的激活函数输出
    cache:存储重要的中间结果,方便运算。元组形式(linear_cache,activation_cache)=((A_prev,W,b),Z)
    
    '''
    
    if activation == 'sigmoid':
        Z,linear_cache = linear_forward(A_prev,W,b) #线性单元
        A,activation_cache = sigmoid(Z)  #激活单元
    elif activation == 'relu':
        Z,linear_cache = linear_forward(A_prev,W,b) #线性单元
        A,activation_cache = relu(Z)  #激活单元
    
    assert(A.shape == (W.shape[0],A_prev.shape[1]))
    cache=(linear_cache,activation_cache)
    
    return A,cache

3.计算损失值

def compute_cost(AL,Y):
    '''
    实现cost函数,计算代价
    
    参数:
    AL:输出层的激活输出 模型最终输出 (1,m)
    Y:样本的真实标签 0/1 (1,m)
    
    返回:
    cost: 交叉熵代价
    '''
    
    cost = np.mean(-Y*np.log(AL)-(1-Y)*np.log(1-AL))
    cost = np.squeeze(cost) #Y和AL都是用2维数组表示的向量 cost算出来是[[cost]],利用squeeze把它变成cost
    
    assert(cost.shape == ()) 
    
    return cost

更新梯度

def update_parameters(parameters,grads,learning_rate):
    '''
    使用梯度下降法更新模型参数
    
    参数:
    parameters:模型参数
    grads:计算的参数梯度 字典形式
    learning_rate:学习率
    
    返回:
    
    parameters:更新后的参数 字典形式
        parameters["W" + str(l)] = ... 
        parameters["b" + str(l)] = ...
    '''
    
    L = len(parameters)//2 #神经网络层数(输入层是第0层 不算输入层)
    
    #一次梯度下降迭代 更新参数
    for l in range(L):  #l 0~L-1
        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

4.构建双层神经网络模型


#定义网络结构
n_x = 12288 #num_px*num_px*3
n_h = 7  #隐层单元数 可以设置
n_y = 1 #2分类
 
layers_dims = (n_x,n_h,n_y)  #各层单元数
def two_layer_model(X,Y,layers_dims,learning_rate=0.0075,num_iterations=3000,print_cost=False):
    '''
    实现双层网络结构
    
    参数:
    X:训练集特征矩阵 (n_x,m_train) 
    Y:训练集样本对于的标签 0/1 (1,m_train)
    layers_dims:各层的单元数
    learning_rate:学习率
    num_iterations:梯度下降法迭代次数
    print_cost:为True时,每100次迭代打印一次cost
    
    返回:
    parameters:训练好的参数 字典形式
        parameters["W" + str(l)] = ... 
        parameters["b" + str(l)] = ...
    '''
    np.random.seed(1)
    grads = {} #存储每一次反向传播计算的梯度
    costs = [] #存储每100次前向传播计算的代价
    m = X.shape[1]
    (n_x,n_h,n_y) = layers_dims
    
    #初始化模型参数
    parameters = initialize_parameters(n_x,n_h,n_y)
    
    #取出每一个初始化后的参数
    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']
    
    #梯度下降迭代
    #batch GD 每一次使用全部的样本计算梯度
    for i in range(num_iterations):
        #前向传播
        A1,cache1 = linear_activation_forward(X,W1,b1,'relu')
        A2,cache2 = linear_activation_forward(A1,W2,b2,'sigmoid')
        
        #计算代价
        cost = compute_cost(A2,Y)
        
        #计算反向传播的初始项 dAL=dA2
        dA2 = -Y/A2 + (1-Y)/(1-A2)
        
        dA1,dW2,db2 = linear_activation_backward(dA2,cache2,'sigmoid')
        dA0,dW1,db1 = linear_activation_backward(dA1,cache1,'relu')
        
        grads['dW1']=dW1
        grads['db1']=db1
        grads['dW2']=dW2
        grads['db2']=db2
        
        #更新参数
        parameters = update_parameters(parameters,grads,learning_rate)
        
         #取出每一个更新后的参数
        W1 = parameters['W1']
        b1 = parameters['b1']
        W2 = parameters['W2']
        b2 = parameters['b2']
        
        #每100次迭代打印一次代价 并存储
        if print_cost and i%100==0:
            print("Cost after iteration {}: {}".format(i, np.squeeze(cost)))
            costs.append(cost)
            
    #绘制代价对迭代次数的变化曲线
    plt.plot(np.squeeze(costs))
    plt.ylabel('cost')
    plt.xlabel('iterations (per hundreds)')
    plt.title("Learning rate =" + str(learning_rate))
    plt.show()
    
    return parameters
    
  • 训练双层网络

parameters = two_layer_model(train_x, train_y, layers_dims = (n_x, n_h, n_y), num_iterations = 2500, print_cost=True)

在这里插入图片描述

  • 编写预测函数代码

  • 上一步中的optimize函数会输出已学习的w和b的值,我们可以使用w和b来预测数据集X的标签。

  • 计算预测步骤:

    • p [ A 2 > 0.5 ] = 1 p[A2 > 0.5] = 1
def predict(X,Y,parameters):
    '''
    使用训练好的模型进行预测
    
    参数:
    X:数据集样本特征矩阵(n_x,m)
    Y:数据集样本真实标签 0/1 (1,m)
    parameters:训练好的参数
    
    返回:
    p:数据集样本预测标签 0/1
    '''
    #取出每一个学习好的的参数
    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']
    
    #前向传播  linear_activation_forward定义了一层的前向传播
    A1,cache1 = linear_activation_forward(X,W1,b1,'relu')
    A2,cache2 = linear_activation_forward(A1,W2,b2,'sigmoid')
    
    m = X.shape[1]
    p = np.zeros((1,m))
    
    p[A2 > 0.5] = 1
    print("Accuracy: "  + str(np.mean(p == Y)))
    
    return p

predictions_train = predict(train_x, train_y, parameters) #训练集上的准确率

predictions_test = predict(test_x, test_y, parameters)#测试集上的准确率
  • 对两层神经网络进行照片预测
index = 32
plt.imshow(test_x[:,index].reshape((64, 64, 3)))
print ("y = " + str(test_set_y[0,index]) + ", you predicted that it is a \"" + classes[int(predictions_test[0,index])].decode("utf-8") +  "\" picture.")

在这里插入图片描述

二. L层神经网络(L>=3,隐藏层数 >= 2)

在这里插入图片描述
在这里插入图片描述

构建L层神网络

网络结构: [linear>relu]x(L-1)>linear>sigmoid

  • 随机初始化参数:选择he初始化
    在这里插入图片描述
def initialize_parameters_deep(layer_dims):
    '''
    参数:
    layer_dims:网络每一层的单元数
    
    返回:
    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(1)
    parameters = {}
    L = len(layer_dims) #神经网络层数+1 包括输入层
    
    for l in range(1,L):
        parameters['W'+str(l)] = np.random.randn(layer_dims[l],layer_dims[l-1])*np.sqrt(2./layer_dims[l-1]) #*0.01
        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

注意:由于隐藏层统一同relu激活函数,输出层2分类用的是sigmoid,隐藏层可以统一处理,输出层单独处理

  • ** L层网络前向传播**

#之前定义了每层的前向传播 对于深层网络来说整体的前向传播 可以使用for循环迭代每层的前向传播
 
def linear_forward(A,W,b):
    '''
    隐层/输出层 前向传播的线性组合部分
    
    参数:
    A:上一层的激活函数输出 初始值是样本特征矩阵X
    W:当前层的权重参数矩阵
    b: 当前层的偏置参数向量
    
    返回:
    Z:当前层的线性组合输出
    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 sigmoid(Z):
    '''
    2分类,输出层采用sigmoid激活函数
    输出层前向传播的激活函数部分
    
    参数:
    Z:当前层(输出层)的线性组合输出
    
    返回:
    A:当前层(输出层)的激活输出
    cache: Z
    '''
    A = 1./(1+np.exp(-Z))
    cache = Z
    
    assert(A.shape == Z.shape)
    
    return A,cache
 
def relu(Z):
    '''
    隐层统一采用relu激活函数
    
    参数:
    Z:当前层(隐层)的线性组合输出
    
    返回:
    A:当前层(隐层)的激活输出
    cache: Z
    '''
    
    A = np.maximum(0,Z)
    cache = Z
    
    assert(A.shape == Z.shape)
    
    return A,cache
    
    
def linear_activation_forward(A_prev,W,b,activation):
    '''
    隐层(输出层)的前向传播操作,包括线性组合和激活函数两部分
    
    参数:
    A_perv:上一层的激活函数输出 初始值是样本特征矩阵X
    W:上一层和当前层之间的权重参数矩阵
    b: 上一层和当前层之间的偏置参数向量
    activation:使用的激活函数类型 一般所有隐层的激活函数是一样的 输出层如果作2分类使用sigmoid
    
    返回:
    A: 当前层的激活函数输出
    cache:存储重要的中间结果,方便运算。元组形式(linear_cache,activation_cache)=((A_prev,W,b),Z)
    
    '''
    
    if activation == 'sigmoid':
        Z,linear_cache = linear_forward(A_prev,W,b) #线性单元
        A,activation_cache = sigmoid(Z)  #激活单元
    elif activation == 'relu':
        Z,linear_cache = linear_forward(A_prev,W,b) #线性单元
        A,activation_cache = relu(Z)  #激活单元
    
    assert(A.shape == (W.shape[0],A_prev.shape[1]))
    cache=(linear_cache,activation_cache)
    
    return A,cache


def L_model_forward(X,parameters):
    '''
    L层神经网络整体的前向传播 调用之前写好的每层的前向传播 用for循环迭代
    
    参数:
    X:数据集的特征矩阵 (n_x,m)
    parameters:模型参数
    
    返回:
    AL:模型最后的输出
    caches:列表形式,存储每一层前向传播的cache=(linear_cache,activation_cache)
        =((A_prev,W,b),Z)  
        对于linear_relu_forward()有L-1项cache  下标0~L-2
        对于linear_sigmoid_forward()有1项cache  下标L-1
    '''
    
    caches = []
    A = X  #A0  前向传播初始项
    L = len(parameters)//2 #神经网络层数(不包含输入层)
    
    #前向传播通项
    #隐层和输出层激活函数不同 for循环迭代隐层前向传播 输出层前向传播单独算
    #隐层
    for l in range(1,L): #l: 1~L-1 
        A_prev = A
        A,cache = linear_activation_forward(A_prev,parameters['W'+str(l)],
                            parameters['b'+str(l)],'relu')
        caches.append(cache)
    #输出层
    AL,cache = linear_activation_forward(A,parameters['W'+str(L)],
                            parameters['b'+str(L)],'sigmoid')
    caches.append(cache)
    
    return AL,caches

  • 计算损失函数
def compute_cost(AL,Y):
    '''
    实现cost函数,计算代价
    
    参数:
    AL:输出层的激活输出 模型最终输出 (1,m)
    Y:样本的真实标签 0/1 (1,m)
    
    返回:
    cost: 交叉熵代价
    '''
    
    cost = np.mean(-Y*np.log(AL)-(1-Y)*np.log(1-AL))
    cost = np.squeeze(cost) #Y和AL都是用2维数组表示的向量 cost算出来是[[cost]],利用squeeze把它变成cost
    
    assert(cost.shape == ()) 
    
    return cost
  • 反向传播计算梯度
def sigmoid_backward(dA,cache):
    '''
    sigmoid激活单元(输出层)的反向传播
    
    参数:
    dA:当前层(输出层)激活输出AL的梯度
    cache:存储当前层(输出层)的线性组合输出Z,方便激活单元反向传播的计算
    
    返回:
    dZ:当前层(输出层)线性组合输出Z的梯度
    '''
    
    Z = cache
    s = 1./(1+np.exp(-Z))
    #dZ=dA*(A对Z求导) A=sigmoid(Z) A对Z的导数=A(1-A)
    dZ = dA*s*(1-s) 
    
    assert(dZ.shape == Z.shape)
    
    return dZ
 
def relu_backward(dA,cache):
    '''
    隐层统一使用relu激活函数
    relu激活单元(隐层)的反向传播
    
    参数:
    dA:当前层(隐层)激活输出Al的梯度
    cache:存储当前层(隐层)的线性组合输出Z,方便激活单元反向传播的计算
    
    返回:
    dZ:当前层(隐层)线性组合输出Z的梯度
    '''
    
    Z = cache
    #dZ=dA*(A对Z求导) 当Z>0时 A对Z求导=1 否则为0
    dZ = np.array(dA,copy=True)
    
    dZ[Z<=0] = 0
    
    assert(dZ.shape == Z.shape)
    
    return dZ
 
def linear_backward(dZ,cache):
    '''
    输出层/隐层 线性单元的反向传播
    
    参数:
    dZ:当前层组合输出Z的梯度
    cache:存储当前层前向传播的线性单元参数 (A_prev,W,b),方便线性单元反向传播的计算
    
    返回:
    dA_prev:前一层激活输出的梯度
    dW:当前层权重参数矩阵的梯度
    db:当前层偏置参数向量的梯度
    '''
    A_prev,W,b = cache
    
    m = A_prev.shape[1] #样本数
    
    dW = 1./m*np.dot(dZ,A_prev.T) #m个样本的平均梯度
    db = np.mean(dZ,axis=1,keepdims=True)
    dA_prev = np.dot(W.T,dZ)
    
    assert(dW.shape == W.shape)
    assert(db.shape == b.shape)
    assert(dA_prev.shape == A_prev.shape)
    
    return dA_prev,dW,db
def linear_activation_backward(dA,cache,activation):
    """
      输出层\隐层的反向传播操作,包括激活函数和线性组合两部分
    dvar 代表 最终输出对var的偏导
    
    参数:
    dA:当前层的激活输出梯度dAl 初始值是dAL (代价函数对AL求偏导)
    cache:前向传播阶段存储的重要参数和中间结果,便于与反向传播共享参数,方便运算。元组形式(linear_cache,activation_cache)=((A_prev,W,b),Z)
    activation:使用的激活函数类型 一般所有隐层的激活函数是一样的 输出层如果作2分类使用sigmoid
    
    返回:
    dA_prev:前一层激活输出的梯度dA(l-1)
    dW:当前层权重矩阵的梯度 和当前层W维度一致
    db:当前层偏置向量的梯度 和当前层b维度一致
    """
  
    
    
    linear_cache,activation_cache = cache
    
    if activation == 'sigmoid':
        dZ = sigmoid_backward(dA,activation_cache) #激活单元反向传播
        dA_prev,dW,db = linear_backward(dZ,linear_cache)#线性单元反向传播
    elif activation == 'relu':
        dZ = relu_backward(dA,activation_cache) #激活单元反向传播
        dA_prev,dW,db = linear_backward(dZ,linear_cache)#线性单元反向传播
    
    return dA_prev,dW,db

#向后传播模型
def L_model_backward(AL,Y,caches):
    '''
    L层神经网络整体的反向传播 调用之前写好的每层的反向传播 用for循环迭代
    
    参数:
    AL:前向传播最终的输出
    Y:数据集样本真实标签 0/1
    caches:前向传播缓存的重要参数和中间结果 方便运算
        列表形式,存储每一层前向传播的cache=(linear_cache,activation_cache)
        =((A_prev,W,b),Z)  
        对于linear_relu_forward()有L-1项cache  下标0~L-2
        对于linear_sigmoid_forward()有1项cache  下标L-1
    
    返回:
    grads:字典形式 存储每一层参数的梯度:
             grads["dA" + str(l)] = ... 
             grads["dW" + str(l)] = ...
             grads["db" + str(l)] = ... 
    '''
    
    grads = {}
    L = len(caches) #网络层数 不包含输入层
    
    m = AL.shape[1]
    Y = Y.reshape(AL.shape)
    
    #反向传播初始项
    dAL = -Y/AL + (1-Y)/(1-AL)
    
    #输出层单独计算 隐层统一用for循环计算
    current_cache = caches[L-1] #输出层前向传播的cache
    grads['dA'+str(L)],grads['dW'+str(L)],grads['db'+str(L)] = linear_activation_backward(dAL,
            current_cache,'sigmoid') #grads['dAl']实际上是grads['dAl-1'] 便于与dW,db统一处理
 
    
    for l in reversed(range(L-1)): #l:L-2~0
        current_cache = caches[l]
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads['dA'+str(l+2)],current_cache,'relu')
        grads["dA" + str(l + 1)] = 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):
    '''
    使用梯度下降法更新模型参数
    
    参数:
    parameters:模型参数
    grads:计算的参数梯度 字典形式
    learning_rate:学习率
    
    返回:
    
    parameters:更新后的参数 字典形式
        parameters["W" + str(l)] = ... 
        parameters["b" + str(l)] = ...
    '''
    
    L = len(parameters)//2 #神经网络层数(输入层是第0层 不算输入层)
    
    #一次梯度下降迭代 更新参数
    for l in range(L):  #l 0~L-1
        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
#定义网络结构
layers_dims = [12288, 20, 7, 5, 1] # 各层的单元数 四层网
  • 整合模型
def L_layer_model(X, Y, layers_dims, learning_rate = 0.0075, num_iterations = 3000, print_cost=False):
    '''
    实现L层网络
    
    参数:
    X:训练集样本特征矩阵(n_x,m_train)
    Y:训练集样本标签 0/1 (1,m_train)
    layers_dims:各层的单元数
    learning_rate:学习率
    num_iterations:梯度下降法迭代次数
    print_cost:为True时,每100次迭代打印一次cost
    
    返回:
    parameters:训练好的参数 字典形式
        parameters["W" + str(l)] = ... 
        parameters["b" + str(l)] = ...
    '''
    
    np.random.seed(1)
    costs = [] #存储每100次前向传播计算的代价
    
    #初始化参数
    parameters = initialize_parameters_deep(layers_dims)
    
    #梯度下降迭代
    #batch GD 每次反向传播使用全部样本计算梯度
    for i in range(num_iterations):
        
        #前向传播
        AL,caches = L_model_forward(X,parameters)
        
        #计算代价
        cost = compute_cost(AL,Y)
        
        #反向传播计算梯度
        grads = L_model_backward(AL,Y,caches)
        
        #更新参数
        parameters = update_parameters(parameters,grads,learning_rate)
        
        #每100次迭代打印一次代价 并存储
        if print_cost and i%100==0:
            print("Cost after iteration {}: {}".format(i, np.squeeze(cost)))
            costs.append(cost)
            
    #绘制代价对迭代次数的变化曲线
    plt.plot(np.squeeze(costs))
    plt.ylabel('cost')
    plt.xlabel('iterations (per hundreds)')
    plt.title("Learning rate =" + str(learning_rate))
    plt.show()
    
    return parameters

下一篇我们会给此4层神经网络加入:L2正则,dropout,,mini_batch—MBGD(小批量梯度下降),(Momentum、adam)优化器。

此文章借鉴与:https://blog.csdn.net/sdu_hao/article/details/84838375#5.L%E5%B1%82%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C(L%3E%3D3%2C%E9%9A%90%E5%B1%82%E6%95%B0%3E%3D2)

发布了3 篇原创文章 · 获赞 2 · 访问量 99

猜你喜欢

转载自blog.csdn.net/weixin_41668848/article/details/104947509