吴恩达深度学习第一课第四周作业及学习心得体会

概述

在完成吴恩达第一课第四周,即L层neuralnetwork学习后,了解了深层神经网络的结构,然后参考网上的资料,完成该周作业,现将心得体会记录如下。

核心代码

调用库如下所示

import numpy as np
import matplotlib.pyplot as plt

初始化参数函数

def init_para(layer_dims):
    L = len(layer_dims)             #L为总层数
    np.random.seed(0)
    parameters = {}
    
    for l in range(1,L):            #初始化W1~WL,b1~bL
        n1 = layer_dims[l]
        n2 = layer_dims[l-1]
        parameters['W'+str(l)] = np.random.randn(n1, n2) * np.sqrt(1.0/n2)
        parameters['b'+str(l)] = np.zeros((n1, 1))    
        
    return parameters

单次前向运算函数

def single_forward(A_pre, W, b, mode):
    Z = np.dot(W, A_pre) + b        #根据上一层的输出A_pre,以及本层的W b计算本层的Z
    
    if mode=='sigmoid':             #根据所选定的激活函数计算本层的输出
        A = 1.0/(1+np.exp(-Z))
    if mode=='ReLU':
        A = (Z+abs(Z))/2
    if mode=='tanh':
        A = np.tanh(Z)
        
    cache = {'A_pre':A_pre,
             'W':W,
             'b':b,
             'Z':Z,
             'A':A}
    
    return cache

前向传播函数

def prop_forward(X, parameters):
    caches = []
    L = len(parameters)//2
    
    for l in range(1,L+1):          #l从1到L,调用L次前向运算
        if l==1:                    #第一次运算时,A_pre=X
            A_pre = X
        else:
            A_pre = cache['A']   
        if l==L:                    #最后一次运算时,激活函数为sigmoid
            mode = 'sigmoid'
        else:
            mode = 'tanh'  
        W = parameters['W'+str(l)]
        b = parameters['b'+str(l)]
        cache = single_forward(A_pre, W, b, mode)
        caches.append(cache)
        
    AL = caches[L-1]['A']
    
    return AL, caches

成本函数

def compute_cost(AL,Y):
    m = Y.shape[1]                  #-1/m*[Ylog(A) + (1-Y)log(1-A)]
    cost = -1.0/m * np.sum(Y*np.log(AL) + (1-Y)*np.log(1-AL))
    cost = np.squeeze(cost)
    return cost

单次后向运算函数

def single_backward(dA, cache, mode):
    A_pre = cache['A_pre']
    W = cache['W']
    b = cache['b']
    A = cache['A']
    m = A_pre.shape[1]
    
    if mode=='sigmoid':             #根据本层激活函数计算本层的dZ
        dZ = dA*A*(1-A)             #sigmoid函数:dZ=dA*[A(1-A)]
    if mode=='ReLU':
        dZ = dA                     #ReLU函数:A>=0,dZ=dA
        dZ[A<0] = 0                 #ReLU函数:A<0, dZ=0
    if mode=='tanh':
        dZ = dA*(1-A**2)            #tanh函数: dZ=dA*(1-A*A) 
    
    grad = {'dW':1.0/m*np.dot(dZ, A_pre.T),
            'db':1.0/m*np.sum(dZ, axis=1, keepdims=True),
            'dA_pre':np.dot(W.T, dZ)} 
    
    return grad

后向传播函数

def prop_backward(AL, Y, caches):
    grads = {}                      #注意:使用append时应初始化为[],否则应为{}
    L = len(caches)
    
    for l in reversed(range(L)):    #计算梯度
        if l==L-1:                  #计算dAL,因输出层使用的损失函数为-1/m*[Ylog(A) + (1-Y)log(1-A)]
            dA = -(Y/AL - (1-Y)/(1-AL)) 
            mode = 'sigmoid'
        else:
            dA = grad['dA_pre']
            mode = 'tanh'
        grad = single_backward(dA, caches[l], mode)
        grads['dW'+str(l+1)] = grad['dW']
        grads['db'+str(l+1)] = grad['db']
        
    return grads

参数更新函数

def update_para(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

构建模型函数

def NN_model(X, Y, layer_dims, learning_steps, learning_rate, print_flag):
    np.random.seed(1)
    costs=[]
    parameters =  init_para(layer_dims)                 #初始化参数
    
    for i in range(0, learning_steps):                  #进行learning_steps次训练
        AL, caches = prop_forward(X, parameters)        #前向传播,计算A1~AL
        cost = compute_cost(AL,Y)                       #计算成本
        grads = prop_backward(AL, Y, caches)            #反向传播,计算dW1~dWL,db1~dbL
        parameters = update_para(parameters, grads, learning_rate)  #更新参数
        if print_flag==True and i%1000==0:
            print('cost at %i steps:%f'%(i, cost))
            costs.append(cost)
            
    return parameters,costs

预测函数

def predict(X,parameters):
    AL, caches = prop_forward(X, parameters)
    prediction = (AL>0.5)
    return prediction

二元分类问题

二元分类问题1

训练数据为二维平面的坐标点,形状呈8瓣花瓣,其中设置部分点标签为0,另一部分为1,绘出后如下图所示(与第三周样本的略有区别)。

用这些点训练L层NN。当layer_dims = [2,4,3,1],steps=20000,rate=0.5时,很快收敛,cost变化如下图所示(横坐标1个数代表1000步)。

用该网络对样本重新预测准确率为0.990000,二维平面预测并分区,结果如下图所示:

当layer_dims = [2,4,3,2,1],即多了一层,steps与rate不变,一开始收敛很慢,到某一时刻突然收敛,cost变化如下图所示(横坐标1个数代表1000步)。

用该网络对样本重新预测准确率为0.980000,二维平面预测并分区,结果如下图所示:

二元分类问题2

训练的坐标点更改为两组环形圈,两层标签分别为0和1。点绘出后如下图所示。

用这些点训练L层的neuralnetwork,令layer_dims = [2,6,3,1]。训练一开始收敛很慢,到某一时刻突然收敛,cost变化如下图所示(横坐标1个数代表1000步)。

用该网络对样本重新预测准确率为1,二维平面预测并分区,结果如下图所示。虽然收敛较慢,但经调参后,其效果优于单隐层的网络。

三元分类问题

直接尝试解决有交叉的三元分类问题。训练集绘出后如下图所示。

用这些点训练L层的neuralnetwork,令layer_dims=[2,18,6,3]。训练一开始收敛很慢,到某一时刻突然收敛,cost变化如下图所示(横坐标1个数代表1000步)。

用该网络对样本重新预测准确率为1,二维平面预测并分区,结果如下图所示。虽然收敛较慢,但经调参后,其效果明显优于单隐层的网络。

猫识别问题

数据文件,在datasets文件夹内,分别包括训练数据和测试数据;

自己的图片文件,在images内,用于检验网络;

代码文件,CatRecognition_NN_Llayer.py。

代码文件中前面主要是读取文件代码,其中样本文件有209个,读取后的数据维度为209×64×64×3,其中209为样本数,两个64分别为图片的横纵像素个数,最后的3对应每个像素的RGB值。读取后将其转换为12288×209的二维矩阵,其中12288=64×64×3,即每个样本有12288个特征。

将深层NN的核心代码敲入,网络第一层激活函数用tanh,中间层用ReLU,最后层用sigmoid,并令layer_dims=[12288,500,20,1],步长为0.02,学习次数为1100,用训练数据集进行训练,然后对训练数据和测试数据分别进行预测,准确率分别为0.918660和0.800000,相较于第三周的网络,虽然训练集的测试准确率降低,但是测试集的准确率进一步提高,可知过拟合程度进一步降低。

对"images/cat7.jpg"(如下图所示)进行预测来检验网络。网络认为其是猫,该网络准确率基本可以(这是为数不多的能将下面这张图片识别为猫的网络,其他参数不变,把学习次数改为1000时也可以识别出这张图片。注意学习次数更多时将发生过拟合,再对这张图预测,结果将不是猫...)。

总结

通过学习和实践,掌握了深层NN的设计方法。

另有感悟:

深层神经网络调参困难,尤其时层数L和每层的维度,以及学习次数和步长,非常难以找到很快收敛的参数。往往是很长时间不收敛,然后突然收敛或突然爆炸,又或者梯度消失,永远也无法找到最优解;

在网上查找资料,包括吴恩达后续的课程,好像都有解决这些问题的方法,这些才应该时今后学习的重心,而不是调参。

本周作业源代码,可在本人csdn的资源里下载,含上面几个文件源代码,均为py文件。另含本篇博客的word和pdf版本。如有需要需要请自行下载,资源名称为“吴恩达深度学习第一课第四周作业及学习心得体会.zip”

猜你喜欢

转载自blog.csdn.net/weixin_42604446/article/details/81233648