【神经网络学习笔记】改善神经网络

改善神经网络

一、实验步骤

  1. 初始化参数
  • 初始化参数为0
  • 随机初始化参数
  • 使用抑梯度异常初始化参数(针对梯度消失和梯度爆炸)
  1. 正则化
  • 使用L2正则化,避免过拟合
  • 使用dropout随机关闭节点,避免过拟合
    (课程还有一个梯度校验,但还没搞懂这一个,以后更新)
    (本文参考地址,链接: link,相应工具包可到这里下载)

二、初始化参数

2.1 前期准备

import numpy as np
from utils.init_utils import *
from utils.reg_utils import *

先看看数据

train_X, train_Y, test_X, test_Y = load_dataset(is_plot=True)

在这里插入图片描述

我们需要建立一个分类器将蓝点和红点分开,前面的已经构建过一个神经网络,现在尝试三种方法对其参数初始化,首先建立一个模型。

# 1.初始模型
def model1(X,Y,learning_rate=0.01,num_iterations=15000,print_cost=True,initialization='he',is_plot=True):
    """
    构建一个三层神经网络:
    Linear -> Relu -> Linear -> Relu -> Linear -> Sigmoid

    参数:
    initialization - 初始化参数类型
    这里实现三种初始化方式:
    ‘zeros’--初始化为0
    'random'--随机初始化
    'he'-- 抑梯度异常初始化

    分别查看三种方式训练的效果
    """
    grads = {
    
    }
    costs = []
    m = X.shape[1]
    layers_dims = [X.shape[0],10,5,1]

    # 1.根据initialization的值选择初始化参数的方式
    if initialization == 'zeros':
        parameters = initialize_parameters_zeros(layers_dims)
    elif initialization == 'random':
        parameters = initialize_parameters_random(layers_dims)
    elif initialization == 'he':
        parameters = initialize_parameters_he(layers_dims)
    else:
        print('初始化参数出错!!!')
        exit()

    # 2.开始学习
    for i in range(0,num_iterations):
        # 2.1正向传播
        a3,cache = forward_propagation(X,parameters)

        # 2.2计算成本
        cost = compute_cost(a3,Y)

        # 2.3反向传播
        grads = backward_propagation(X,Y,cache)

        # 2.4更新参数
        parameters = update_parameters(parameters,grads,learning_rate)

        # 记录成本
        if i % 1000 == 0:
            costs.append(cost)
            if print_cost:
                print("第" + str(i) + "次迭代,成本值为:" + str(cost))
    # 绘制成本曲线
    if is_plot:
        plt.plot(costs)
        plt.ylabel('cost')
        plt.xlabel('iterations (per hundreds)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()

    # 返回学习后的参数
    return parameters

这里用到的三个函数分别对应三种初始化方式:

  • initialize_parameters_zeros - 初始化参数为0
  • initialize_parameters_random - 随机初始化参数
  • initialize_parameters_he - 抑梯度异常初始化参数

2.2 初始化为0

def initialize_parameters_zeros(layers_dims):
    """
    参数:
        layers_dims - 一个列表,对应每一层的节点数量
    返回:
        parameters - 包含W,b的字典
    """
    parameters = {
    
    }
    # 网络层数
    L = len(layers_dims)

    for l in range(1,L):
        parameters['W'+str(l)] = np.zeros((layers_dims[l],layers_dims[l-1]))
        parameters['b'+str(l)] = np.zeros((layers_dims[l],1))

        assert (parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l - 1]))
        assert (parameters["b" + str(l)].shape == (layers_dims[l], 1))

    return parameters

使用该方法测试一下,同时计算出准确率

train_X, train_Y, test_X, test_Y = load_dataset(is_plot=False)
parameters = model1(test_X,test_Y,initialization='zeros',is_plot=True)
print('训练集:')
predictions_train = predict(train_X,train_Y,parameters)
print('测试集:')
predictions_test = predict(test_X,test_Y,parameters)

print("predictions_train = " + str(predictions_train))
print("predictions_test = " + str(predictions_test))

plt.title("Model with Zeros initialization")
axes = plt.gca()
axes.set_xlim([-1.5, 1.5])
axes.set_ylim([-1.5, 1.5])

plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
第0次迭代,成本值为:0.6931471805599453
第1000次迭代,成本值为:0.6931471805599453
第2000次迭代,成本值为:0.6931471805599453
第3000次迭代,成本值为:0.6931471805599453
第4000次迭代,成本值为:0.6931471805599453
第5000次迭代,成本值为:0.6931471805599453
第6000次迭代,成本值为:0.6931471805599455
第7000次迭代,成本值为:0.6931471805599453
第8000次迭代,成本值为:0.6931471805599453
第9000次迭代,成本值为:0.6931471805599453
第10000次迭代,成本值为:0.6931471805599453
第11000次迭代,成本值为:0.6931471805599453
第12000次迭代,成本值为:0.6931471805599453
第13000次迭代,成本值为:0.6931471805599453
第14000次迭代,成本值为:0.6931471805599453

在这里插入图片描述

训练集:
Accuracy: 0.5
测试集:
Accuracy: 0.5
predictions_train = [[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0]]
predictions_test = [[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]

在这里插入图片描述

可以看到图一,cost完全没有变化,说明模型根本没有学习。然后训练集和测试集的准确率也只有50%,效果很差,同时该模型预测每个都为0,完全没有达到分类的效果。

2.3随机初始化

def initialize_parameters_random(layers_dims):
    np.random.seed(3)
    parameters = {
    
    }
    L = len(layers_dims)

    for l in range(1, L):
        parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1])* 10
        parameters['b' + str(l)] = np.zeros((layers_dims[l], 1))

        assert (parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l - 1]))
        assert (parameters["b" + str(l)].shape == (layers_dims[l], 1))

    return parameters

同样测试一下:

扫描二维码关注公众号,回复: 12408214 查看本文章
train_X, train_Y, test_X, test_Y = load_dataset(is_plot=False)
parameters = model1(test_X,test_Y,initialization='random',is_plot=True)
print('训练集:')
predictions_train = predict(train_X,train_Y,parameters)
print('测试集:')
predictions_test = predict(test_X,test_Y,parameters)

print("predictions_train = " + str(predictions_train))
print("predictions_test = " + str(predictions_test))

plt.title("Model with Zeros initialization")
axes = plt.gca()
axes.set_xlim([-1.5, 1.5])
axes.set_ylim([-1.5, 1.5])

plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
第0次迭代,成本值为:inf
第1000次迭代,成本值为:0.6364068070309984
第2000次迭代,成本值为:0.6030289163701861
第3000次迭代,成本值为:0.5353698870026956
第4000次迭代,成本值为:0.3356436726502984
第5000次迭代,成本值为:0.3143553948079489
第6000次迭代,成本值为:0.31150719311785213
第7000次迭代,成本值为:0.3104499095045475
第8000次迭代,成本值为:0.30985094399400054
第9000次迭代,成本值为:0.3094245742691148
第10000次迭代,成本值为:0.3090851046328704
第11000次迭代,成本值为:0.3087963173417076
第12000次迭代,成本值为:0.3085417594479953
第13000次迭代,成本值为:0.30831216483639057
第14000次迭代,成本值为:0.30810155057824207

在这里插入图片描述

训练集:
Accuracy: 0.8033333333333333
测试集:
Accuracy: 0.88
predictions_train = [[0 0 1 1 0 0 1 1 1 1 1 0 1 0 0 1 0 1 1 0 1 0 1 0 1 1 1 1 1 1 0 1 1 0 0 1
  1 1 1 1 1 1 1 0 1 1 1 1 1 0 0 1 1 1 1 0 0 1 1 1 1 0 1 1 0 1 0 1 1 1 1 0
  0 0 0 0 1 0 1 0 1 1 1 0 0 1 1 1 1 1 1 0 0 1 1 1 0 1 1 0 1 0 1 1 1 0 1 0
  1 0 1 1 0 0 1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 1 1 1 1 1 1 0 1 1 0 0 1 1 0
  0 0 1 0 0 0 1 0 1 1 1 0 0 1 1 1 1 0 1 1 0 0 0 1 1 0 1 1 1 1 1 1 0 1 1 1
  1 0 1 0 1 0 1 1 1 1 0 1 1 0 1 1 0 1 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0 0 0 1
  0 1 1 0 1 1 0 1 0 0 1 1 1 0 1 1 0 1 0 1 0 0 1 1 0 1 1 1 0 0 0 1 0 0 1 1
  1 1 0 1 1 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1
  1 1 1 1 0 0 0 0 1 1 1 0]]
predictions_test = [[1 1 1 1 0 1 0 1 1 0 1 1 1 0 0 0 0 1 1 1 0 0 1 0 1 0 1 1 1 1 1 0 0 0 0 1
  0 1 1 0 0 1 1 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0
  1 1 1 1 1 0 1 0 0 1 0 0 0 1 1 0 1 1 0 0 0 1 1 0 1 1 0 0]]

在这里插入图片描述

可以看到此时cost值有明显的变化,说明该模型正在学习,而且预测的准确率也在提高,此时分类器拥有分类的效果。但是当它出现错误时,导致的损失非常高。因此,将权重初始化为太大的时候效果并不好。
注意:第0次迭代显示Inf是正常的,因为我们对初始参数进行了10倍的缩放,更好的显示实验效果,若不想出现这个错误把10倍去掉就行)

2.4 抑梯度异常初始化

我们会使用以下公式初始化参数:
在这里插入图片描述

def initialize_parameters_he(layers_dims):
    np.random.seed(3)  # 指定随机种子
    parameters = {
    
    }
    L = len(layers_dims)  # 层数

    for l in range(1, L):
        parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) * np.sqrt(2 / layers_dims[l - 1])
        parameters['b'+str(l)] = np.zeros((layers_dims[l],1))


        # 使用断言确保我的数据格式是正确的
        assert (parameters["W" + str(l)].shape == (layers_dims[l], layers_dims[l - 1]))
        assert (parameters["b" + str(l)].shape == (layers_dims[l], 1))

    return parameters

测试一下:

train_X, train_Y, test_X, test_Y = load_dataset(is_plot=False)
parameters = model1(test_X,test_Y,initialization='he',is_plot=True)
print('训练集:')
predictions_train = predict(train_X,train_Y,parameters)
print('测试集:')
predictions_test = predict(test_X,test_Y,parameters)

print("predictions_train = " + str(predictions_train))
print("predictions_test = " + str(predictions_test))

plt.title("Model with Zeros initialization")
axes = plt.gca()
axes.set_xlim([-1.5, 1.5])
axes.set_ylim([-1.5, 1.5])

plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
第0次迭代,成本值为:0.8838334709694519
第1000次迭代,成本值为:0.6874620933314671
第2000次迭代,成本值为:0.6713711256756202
第3000次迭代,成本值为:0.6487387161716197
第4000次迭代,成本值为:0.6073999401321706
第5000次迭代,成本值为:0.5374027001299436
第6000次迭代,成本值为:0.42992030664639685
第7000次迭代,成本值为:0.3205407862914074
第8000次迭代,成本值为:0.23995336759834382
第9000次迭代,成本值为:0.17955415898079138
第10000次迭代,成本值为:0.14161908780604462
第11000次迭代,成本值为:0.1169487787079976
第12000次迭代,成本值为:0.10071104439402184
第13000次迭代,成本值为:0.08946680496202968
第14000次迭代,成本值为:0.08130185983583153

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ugbVMUFO-1605185135223)(output_18_1.png)]

训练集:
Accuracy: 0.9366666666666666
测试集:
Accuracy: 0.99
predictions_train = [[1 0 1 1 0 0 1 0 1 1 1 0 1 0 0 0 0 1 1 1 1 0 1 0 0 0 1 0 1 1 0 1 1 0 0 0
  0 1 0 1 1 1 1 0 0 1 1 1 0 1 0 1 1 1 1 0 0 1 1 1 1 0 0 1 0 1 0 1 0 1 1 0
  0 0 0 0 1 0 0 0 1 0 1 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 1 0 0 0 0 1 0 1 1 0
  0 0 1 1 0 0 1 0 0 1 0 0 1 1 1 0 0 0 0 1 0 1 1 0 1 1 1 1 0 1 1 0 0 0 1 0
  0 0 1 0 0 0 1 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 1 0 0 1 1 1 1 0 1 0 0 1 0
  1 0 0 0 1 0 1 1 1 0 0 1 1 0 0 1 0 1 0 0 1 0 0 1 0 0 1 1 1 0 1 0 1 0 0 1
  0 1 0 0 0 1 1 1 0 0 1 0 0 0 1 0 1 1 0 1 0 0 0 0 0 1 1 0 0 0 0 1 0 0 1 0
  1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 0 0 0 0 0 1 1 0 0 0 1 1 1
  1 1 0 0 0 0 0 1 1 0 1 0]]
predictions_test = [[1 0 1 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 1 1 1 0 0 0 0 1
  0 1 1 0 0 1 1 1 1 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 0
  1 1 1 1 0 0 1 0 0 1 0 0 0 0 1 0 1 1 0 0 0 1 1 0 0 1 0 0]]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1L1ZFEdw-1605185135224)(output_18_3.png)]

此时初始化的模型将蓝色和红色的点在少量的迭代中很好地分离了出来,总结一下:

  1. 不同的初始化方法可能导致性能最终不同

  2. 随机初始化有助于打破对称,使得不同隐藏层的单元可以学习到不同的参数。

  3. 初始化时,初始值不宜过大。

  4. He初始化搭配ReLU激活函数常常可以得到不错的效果。

三、正则化

在深度学习中,如果数据集没有足够大的话,可能会导致一些过拟合的问题。过拟合导致的结果就是在训练集上有着很高的精确度,但是在遇到新的样本时,精确度下降会很严重。为了避免过拟合的问题,我们需要正则化。
首先我们看下数据集:

train_X, train_Y, test_X, test_Y = load_2D_dataset(is_plot=True)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D28gMc0p-1605185135226)(output_21_0.png)]

我们尝试不使用正则化和使用正则化后的效果吗,首先建立模型

def model2(X,Y,learning_rate=0.3,num_iterations=30000,print_cost=True,is_plot=True,lambd=0,keep_prob=1):
    """
    依然是三层神经网络
    Y - 标签【0是蓝色,1是红色】
    lambd - 正则化的超参数
    keep_prob - 随机删除节点的概率
    """
    grads = {
    
    }
    costs = []
    m = X.shape[1]
    layers_dims = [X.shape[0],20,3,1]

    parameters = initialize_parameters(layers_dims)

    for i in range(0,num_iterations):
        # 是否随机删除节点(1为不删除)
        if keep_prob == 1:
            a3,cache = forward_propagation(X,parameters)
        elif keep_prob < 1:
            a3,cache = forward_propagation_with_dropout(X,parameters,keep_prob)
        else:
            print('参数错误!!!')
            exit()

        # 计算成本
        # 是否使用L2正则化(0为不使用)
        if lambd == 0:
            cost = compute_cost(a3,Y)
        else:
            cost = compute_cost_with_regularization(a3,Y,parameters,lambd)

        # 反向传播
        # 可以同时使用L2正则化和随机删除节点,但是本次实验不同时使用。
        assert (lambd == 0 or keep_prob == 1)

        # 两个参数的使用情况
        if (lambd == 0 and keep_prob == 1):
            # 不使用L2正则化和随机删除节点
            grads = backward_propagation(X,Y,cache)
        elif lambd != 0:
            # 使用L2正则化,不使用随机删除节点
            grads = backward_propagation_with_regularization(X,Y,cache,lambd)
        elif keep_prob < 1:
            # 不使用L2正则化,使用随机删除节点
            grads = backward_propagation_with_dropout(X,Y,cache,keep_prob)
        # 更新参数
        parameters = update_parameters(parameters,grads,learning_rate)

        # 记录并打印成本
        if i % 1000 == 0:
            ## 记录成本
            costs.append(cost)
            if (print_cost and i % 10000 == 0):
                # 打印成本
                print("第" + str(i) + "次迭代,成本值为:" + str(cost))

    if is_plot:
        plt.plot(costs)
        plt.ylabel('cost')
        plt.xlabel('iterations (x1,000)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()

    return parameters

3.1不使用正则化

parameters = model2(train_X,train_Y)
print("训练集:")
predictions_train = predict(train_X, train_Y, parameters)
print("测试集:")
predictions_test = predict(test_X, test_Y, parameters)
# 画出分割曲线
plt.title("Model without regularization")
axes = plt.gca()
axes.set_xlim([-0.75,0.40])
axes.set_ylim([-0.75,0.65])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
第0次迭代,成本值为:0.6557412523481002
第10000次迭代,成本值为:0.16329987525724216
第20000次迭代,成本值为:0.1385164242327309

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vPEfmUtg-1605185135227)(output_25_1.png)]

训练集:
Accuracy: 0.9478672985781991
测试集:
Accuracy: 0.915

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CqzFhaRw-1605185135228)(output_25_3.png)]

从图中可以看到,无正则化时,分割线明显出现了过拟合,接下来尝试两种正则化方式。

3.2 L2正则化

将原来的成本函数公式改为以下公式:
在这里插入图片描述

def compute_cost_with_regularization(A3,Y,parameters,lambd):
    m = Y.shape[1]
    W1 = parameters['W1']
    W2 = parameters['W2']
    W3 = parameters['W3']

    cross_entropy_cost = compute_cost(A3,Y)

    L2_regularization_cost = lambd * (np.sum(np.square(W1))+np.sum(np.square(W2))+np.sum(np.square(W3))) / (2 * m)

    cost = cross_entropy_cost + L2_regularization_cost

    return cost

此时反向传播也要改变,所有梯度根据新的成本值计算。

def backward_propagation_with_regularization(X,Y,cache,lambd):
    m = X.shape[1]

    (Z1, A1, W1, b1, Z2, A2, W2, b2, Z3, A3, W3, b3) = cache

    dZ3 = A3 - Y

    dW3 = (1 / m) * np.dot(dZ3, A2.T) + ((lambd * W3) / m)
    db3 = (1 / m) * np.sum(dZ3, axis=1, keepdims=True)

    dA2 = np.dot(W3.T, dZ3)
    dZ2 = np.multiply(dA2, np.int64(A2 > 0))
    dW2 = (1 / m) * np.dot(dZ2, A1.T) + ((lambd * W2) / m)
    db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)

    dA1 = np.dot(W2.T, dZ2)
    dZ1 = np.multiply(dA1, np.int64(A1 > 0))
    dW1 = (1 / m) * np.dot(dZ1, X.T) + ((lambd * W1) / m)
    db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)

    gradients = {
    
    "dZ3": dZ3, "dW3": dW3, "db3": db3, "dA2": dA2,
                 "dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,
                 "dZ1": dZ1, "dW1": dW1, "db1": db1}

    return gradients

放在模型中跑一下

train_X, train_Y, test_X, test_Y = load_2D_dataset(is_plot=False)
parameters = model2(train_X,train_Y,lambd=0.7)
print("训练集:")
predictions_train = predict(train_X, train_Y, parameters)
print("测试集:")
predictions_test = predict(test_X, test_Y, parameters)
# 画出分割曲线
plt.title("Model with L2-regularization")
axes = plt.gca()
axes.set_xlim([-0.75,0.40])
axes.set_ylim([-0.75,0.65])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
第0次迭代,成本值为:0.6974484493131264
第10000次迭代,成本值为:0.2684918873282239
第20000次迭代,成本值为:0.2680916337127301

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-btJKvMWo-1605185135230)(output_31_1.png)]

训练集:
Accuracy: 0.9383886255924171
测试集:
Accuracy: 0.93

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xn1WLppw-1605185135231)(output_31_3.png)]

lambd是可以进行调整的超参数,此时过拟合现象已经效果,L2正则化会使决策边界更加平滑,但lambd太大,也可能出现过度平滑,导致模型高偏差。L2正则化对以下内容有影响:

  • 成本计算 - 正则化的计算需要添加到成本函数中
  • 反向传播 - 在权重矩阵方面,梯度计算时也要依据正则化来做出相应的计算
  • 权重衰减 - 权重被逐渐改变到较小的值

3.3 dropout正则化

dropout的原理是在每次迭代的过程中随机将一些节点失效,当我们关闭一些节点时,我们实际上修改了我们的模型。背后的想法是,在每次迭代时,我们都会训练一个只使用一部分神经元的不同模型。随着迭代次数的增加,我们的模型的节点会对其他特定节点的激活变得不那么敏感,因为其他节点可能在任何时候会失效。

# 2.2dropout随机删除节点
def forward_propagation_with_dropout(X,parameters,keep_prob=0.5):
    """
    Linear -> Relu+Dropout -> Linear -> Relu+Dropout -> Linear -> Sigmoid
    """
    np.random.seed(1)

    W1 = parameters['W1']
    b1 = parameters['b1']
    W2 = parameters['W2']
    b2 = parameters['b2']
    W3 = parameters['W3']
    b3 = parameters['b3']

    Z1 = np.dot(W1,X) + b1
    A1 = relu(Z1)
    # 随机关闭第一层节点
    ## 1.初始化随机矩阵D1
    D1 = np.random.rand(A1.shape[0],A1.shape[1])
    ## 2.将D1的值转换为0或1,以keep_prob为阈值
    D1 = D1 < keep_prob
    ## 3.根据D1删除一些A1的节点(任何数乘0或false为0或false)
    A1 = A1 * D1
    ## 4.缩放未删除的节点的值
    A1 = A1 / keep_prob

    Z2 = np.dot(W2,A1) + b2
    A2 = relu(Z2)
    # 随机关闭第二层节点
    D2 = np.random.rand(A2.shape[0],A2.shape[1])
    D2 = D2 < keep_prob
    A2 = A2 * D2
    A2 = A2 / keep_prob

    Z3 = np.dot(W3,A2) + b3
    A3 = sigmoid(Z3)

    cache = (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3)

    return A3,cache

当然反向传播也要改变

# 反向传播也要改变
def backward_propagation_with_dropout(X,Y,cache,keep_prob):
    m = X.shape[1]
    (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3) = cache

    dZ3 = A3 - Y
    dW3 = (1 / m) * np.dot(dZ3,A2.T)
    db3 = 1. / m * np.sum(dZ3,axis=1,keepdims=True)
    dA2 = np.dot(W3.T,dZ3)

    # 使用正向传播期间相同的节点,舍弃那些关闭的节点
    dA2 = dA2 * D2
    dA2 = dA2 / keep_prob

    dZ2 = np.multiply(dA2, np.int64(A2 > 0))
    dW2 = 1. / m * np.dot(dZ2, A1.T)
    db2 = 1. / m * np.sum(dZ2, axis=1, keepdims=True)
    dA1 = np.dot(W2.T, dZ2)

    dA1 = dA1 * D1
    dA1 = dA1 / keep_prob

    dZ1 = np.multiply(dA1, np.int64(A1 > 0))
    dW1 = 1. / m * np.dot(dZ1, X.T)
    db1 = 1. / m * np.sum(dZ1, axis=1, keepdims=True)

    gradients = {
    
    "dZ3": dZ3, "dW3": dW3, "db3": db3, "dA2": dA2,
                 "dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,
                 "dZ1": dZ1, "dW1": dW1, "db1": db1}

    return gradients

最后扔到模型里面跑一下:

train_X, train_Y, test_X, test_Y = load_2D_dataset(is_plot=False)
parameters = model2(train_X,train_Y,keep_prob=0.86)
print("训练集:")
predictions_train = predict(train_X, train_Y, parameters)
print("测试集:")
predictions_test = predict(test_X, test_Y, parameters)
# 画出分割曲线
plt.title("Model with L2-regularization")
axes = plt.gca()
axes.set_xlim([-0.75,0.40])
axes.set_ylim([-0.75,0.65])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
第0次迭代,成本值为:0.6543912405149825
第10000次迭代,成本值为:0.0610169865749056
第20000次迭代,成本值为:0.060582435798513114

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQDfSoLc-1605185135232)(output_38_1.png)]

训练集:
Accuracy: 0.9289099526066351
测试集:
Accuracy: 0.95

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ewfdmucv-1605185135232)(output_38_3.png)]

可以看到测试集的精准度提高了。

四、总结

为了完善我们的神经网络,本文从初始化参数和过拟合两个方面入手研究。在避免过拟合方面,一般使用正则化的方式,其中L2正则化和dropout正则化都有效果,应该根据实际情况而定。

猜你喜欢

转载自blog.csdn.net/weixin_40764047/article/details/109656752
今日推荐