浅层神经网络的搭建(原创) @water


声明
   首先声明本文参考【Kulbear】的github上的文章,本文参考Planar data classification with one hidden layer,我基于他的文章加以自己的理解发表这篇博客。


目标:

  • 构建具有单隐藏层的2类分类神经网络。
  • 使用具有非线性**功能**函数,例如tanh,rule。
  • 计算交叉熵损失(损失函数)。
  • 实现向前和向后传播。

本文所使用的资料已上传到百度网盘点击下载,请在开始之前下载好所需资料。


【博主使用的python版本:2.7 】

# -*- coding: utf-8 -*-
from __future__ import division

第一行是可以进行中文编码
第二行是python2可以整除一个数,且保留小数


在开始之前,我们有需要引入的库:

import numpy as np
import matplotlib.pyplot as plt
from testCases import *
import sklearn
import sklearn.datasets
import sklearn.linear_model
from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets
from dnn_utils import  relu,relu_backward
  • numpy :是用Python进行科学计算的基本软件包。
  • matplotlib:是一个著名的库,用于在Python中绘制图表。
  • sklearn:为数据挖掘和数据分析提供的简单高效的工具。
  • testCases:提供了一些测试示例来评估函数的正确性,参见下载的资料或者在底部查看它的代码。
  • planar_utils :提供了在这个任务中使用的各种有用的功能,参见下载的资料或者在底部查看它的代码

一、加载数据集

这里有两个数据集,你可以自行选择,并对比算法在不同数据集下的性能。

####################################################################\
#Data 1
########
# X, Y = load_planar_dataset()
# #plt.scatter(X[0, :], X[1, :], c=Y, s=40, cmap=plt.cm.Spectral) #绘制散点图
# shape_X = X.shape
# shape_Y = Y.shape
# m = Y.shape[1]  # 训练集里面的数量
#
# print ("X的维度为: " + str(shape_X))
# print ("Y的维度为: " + str(shape_Y))
# print ("数据集里面的数据有:" + str(m) + " 个")
########
#Data 2
########
# 数据集
noisy_circles, noisy_moons, blobs, gaussian_quantiles, no_structure = load_extra_datasets()

datasets = {"noisy_circles": noisy_circles,
            "noisy_moons": noisy_moons,
            "blobs": blobs,
            "gaussian_quantiles": gaussian_quantiles}

dataset = "noisy_moons"

X, Y = datasets[dataset]
X, Y = X.T, Y.reshape(1, Y.shape[0])
shape_X = X.shape
shape_Y = Y.shape
m = Y.shape[1]  # 训练集里面的数量
if dataset == "blobs":
    Y = Y % 2
print ("X的维度为: " + str(shape_X))
print ("Y的维度为: " + str(shape_Y))
print ("数据集里面的数据有:" + str(m) + " 个")
plt.figure(1)
plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.c

这里有两个数据集,分别如下图所示
Andrew_NG第一章第三周的作业整理
Andrew_NG第一章第三周的作业整理


数据集这样就处理 好了,下一步我们来创建神经网络模型

二、创建网络模型

建立神经网络的主要步骤是:

  1. 定义模型结构(例如输入特征的数量)
  2. 初始化模型的参数
  3. 循环:
  • 3.1 计算当前损失(正向传播)
  • 3.2 计算当前梯度(反向传播)
  • 3.3 更新参数(梯度下降)
def layer_sizes(X , Y):
    """
    参数:
     X - 输入数据集,维度为(输入的数量,训练/测试的数量)
     Y - 标签,维度为(输出的数量,训练/测试数量)

    返回:
     n_x - 输入层的数量
     n_h - 隐藏层的数量
     n_y - 输出层的数量
    """
    n_x = X.shape[0] #输入层
    n_h = 4 #,隐藏层,硬编码为4
    n_y = Y.shape[0] #输出层

    return (n_x,n_h,n_y)

def initialize_parameters( n_x , n_h ,n_y):
    """
    参数:
        n_x - 输入节点的数量
        n_h - 隐藏层节点的数量
        n_y - 输出层节点的数量

    返回:
        parameters - 包含参数的字典:
            W1 - 权重矩阵,维度为(n_h,n_x)
            b1 - 偏向量,维度为(n_h,1)
            W2 - 权重矩阵,维度为(n_y,n_h)
            b2 - 偏向量,维度为(n_y,1)

    """
    np.random.seed(2) #指定一个随机种子,以便你的输出与我们的一样。
    W1 = np.random.randn(n_h,n_x) * 0.01
    b1 = np.zeros(shape=(n_h, 1))
    W2 = np.random.randn(n_y,n_h) * 0.01
    b2 = np.zeros(shape=(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

初始化参数的函数已经构建好了,现在就可以执行"前向“后向”传播步骤来学习参数。
这里构建网络模型有两种方法:

  • tanh( ) -->sigmoid( )
  • relu( ) -->sigmoid( )
def forward_propagation( X , parameters ):
    """
    参数:
         X - 维度为(3,m)(n_x,m)的输入数据。
         parameters - 初始化函数(initialize_parameters)的输出

    返回:
         A2 - 使用sigmoid()函数计算的第二次**后的数值
         cache - 包含“Z1”,“A1”,“Z2”和“A2”的字典类型变量
     """
    W1 = parameters["W1"]#(4,3)( n_h , n_x )
    b1 = parameters["b1"]#(4,1)( n_h , 1   )
    W2 = parameters["W2"]#(1,4)( n_y , n_h)
    b2 = parameters["b2"]#(1,1)( n_y , 1 )
    #前向传播计算A2
    Z1 = np.dot(W1 , X) + b1 #(4,m)
    A1,a1 = relu(Z1)          #(4,m)
    # A1 = np.tanh(Z1)
    # a1 =1
    Z2 = np.dot(W2 , A1) + b2#(1,m)
    A2 = sigmoid(Z2)         #(1,m)

    #使用断言确保我的数据格式是正确的
    # assert(A2.shape == (1,X.shape[1]))
    cache = {"Z1": Z1,
             "A1": A1,
             "Z2": Z2,
             "A2": A2,
             "a1": a1}
    return (A2, cache)

def compute_cost(A2,Y,parameters):
    """
    计算方程(6)中给出的交叉熵成本,

    参数:
         A2 - 使用sigmoid()函数计算的第二次**后的数值
         Y - "True"标签向量,维度为(1,数量)
         parameters - 一个包含W1,B1,W2和B2的字典类型的变量

    返回:
         成本 - 交叉熵成本给出方程(13)
    """

    m = Y.shape[1]
    W1 = parameters["W1"]
    W2 = parameters["W2"]

    #计算成本
    logprobs = logprobs = np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2))
    cost = - np.sum(logprobs) / m
    cost = float(np.squeeze(cost))

    assert(isinstance(cost,float))

    return cost
#测试forward_propagation
print("=========================测试forward_propagation=========================")
X_assess, parameters = forward_propagation_test_case()
A2, cache = forward_propagation(X_assess, parameters)
print(np.mean(cache["Z1"]), np.mean(cache["A1"]), np.mean(cache["Z2"]), np.mean(cache["A2"]))
#测试compute_cost
print("=========================测试compute_cost=========================")
A2 , Y_assess , parameters = compute_cost_test_case()
print("cost = " + str(compute_cost(A2,Y_assess,parameters)))

测试一下
打印出来的结果

X的维度为: (2, 200)
Y的维度为: (1, 200)
数据集里面的数据有:200=========================测试forward_propagation=========================
(-0.0004997557777419913, 0.009407450992324358, 0.000320787397351217, 0.5000801968460385)
=========================测试compute_cost=========================
cost = 0.692919893776

对应的反向传播也有两种

  • 利用Rule**函数来反向传播
    dZ2= A2 - Y
    dW2 = (1 / m) * np.dot(dZ2, A1.T)
    db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
    dA1 = np.dot(W2.T, dZ2)
    dZ1 = relu_backward(dA1,a1)
    dW1 = (1 / m) * np.dot(dZ1, X.T)
    db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)

  • 利用tanh**函数来反向传播
    dZ2= A2 - Y
    dW2 = (1 / m) * np.dot(dZ2, A1.T)
    db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
    dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
    dW1 = (1 / m) * np.dot(dZ1, X.T)
    db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)


def backward_propagation(parameters,cache,X,Y):
    """
    使用上述说明搭建反向传播函数。

    参数:
     parameters - 包含我们的参数的一个字典类型的变量。
     cache - 包含“Z1”,“A1”,“Z2”和“A2”的字典类型的变量。
     X - 输入数据,维度为(2,数量)
     Y - “True”标签,维度为(1,数量)

    返回:
     grads - 包含W和b的导数一个字典类型的变量。
    """
    m = X.shape[1]

    W1 = parameters["W1"]
    W2 = parameters["W2"]

    A1 = cache["A1"]
    a1 = cache["a1"]
    A2 = cache["A2"]

    dZ2= A2 - Y
    dW2 = (1 / m) * np.dot(dZ2, A1.T)
    db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
    dA1 = np.dot(W2.T, dZ2)
    dZ1 = relu_backward(dA1,a1)
    # dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
    dW1 = (1 / m) * np.dot(dZ1, X.T)
    db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)
    grads = {"dW1": dW1,
             "db1": db1,
             "dW2": dW2,
             "db2": db2 }

    return grads

def update_parameters(parameters,grads,learning_rate=1.2):
    """
    使用上面给出的梯度下降更新规则更新参数

    参数:
     parameters - 包含参数的字典类型的变量。
     grads - 包含导数值的字典类型的变量。
     learning_rate - 学习速率

    返回:
     parameters - 包含更新参数的字典类型的变量。
    """
    W1,W2 = parameters["W1"],parameters["W2"]
    b1,b2 = parameters["b1"],parameters["b2"]

    dW1,dW2 = grads["dW1"],grads["dW2"]
    db1,db2 = grads["db1"],grads["db2"]

    W1 = W1 - learning_rate * dW1
    b1 = b1 - learning_rate * db1
    W2 = W2 - learning_rate * dW2
    b2 = b2 - learning_rate * db2

    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}

    return parameters
def nn_model(X,Y,n_h,learn_rate,num_iterations,print_cost=False):
    """
    参数:
        X - 数据集,维度为(2,示例数)
        Y - 标签,维度为(1,示例数)
        n_h - 隐藏层的数量
        num_iterations - 梯度下降循环中的迭代次数
        print_cost - 如果为True,则每1000次迭代打印一次成本数值

    返回:
        parameters - 模型学习的参数,它们可以用来进行预测。
     """

    np.random.seed(3) #指定随机种子
    n_x = layer_sizes(X, Y)[0]
    n_y = layer_sizes(X, Y)[2]

    parameters = initialize_parameters(n_x,n_h,n_y)
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]

    for i in range(num_iterations):
        A2 , cache = forward_propagation(X,parameters)
        cost = compute_cost(A2,Y,parameters)
        grads = backward_propagation(parameters,cache,X,Y)
        parameters = update_parameters(parameters,grads,learning_rate = learn_rate)

        if print_cost:
            if i%1000 == 0:
                print"第 ",i," 次循环,成本为:"+str(cost)
    return parameters

def predict(parameters,X):
    """
    使用学习的参数,为X中的每个示例预测一个类

    参数:
        parameters - 包含参数的字典类型的变量。
        X - 输入数据(n_x,m)

    返回
        predictions - 我们模型预测的向量(红色:0 /蓝色:1)

     """
    A2 , cache = forward_propagation(X,parameters)
    predictions = np.round(A2)

    return predictions

parameters = nn_model(X, Y, n_h = 6,learn_rate=0.5, num_iterations=10000, print_cost=True)

# 绘制边界
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
plt.title("Decision Boundary for hidden layer size " + str(6))

predictions = predict(parameters, X)
print ('准确率: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')
from matplotlib.colors import ListedColormap
hidden_layer_sizes = [2,4,6 ,12,16,64,128] #隐藏层数量
cmap_light = ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
learning_ratesaa = [0.1,0.3, 0.5,0.8, 1]
plt.figure(2)
for j in learning_ratesaa:
    acc=[]
    print ("learning rate is: " + str(j))
    for i, n_h in enumerate(hidden_layer_sizes):
        parameters = nn_model(X, Y, n_h,learn_rate=j , num_iterations=5000)
        predictions = predict(parameters, X)
        accuracy = float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100)
        acc = np.append(acc,accuracy)
        print ("隐藏层的节点数量: {}  ,准确率: {} %".format(n_h, accuracy))
    print acc
    plt.plot(hidden_layer_sizes,acc,'-',label='learning_rate ='+str(j))
    # plt.ylim((50,100))
    legend = plt.legend(loc='best', shadow=True)
    plt.xlabel('hidden_layer_sizes')
    plt.ylabel('accuracy')
    plt.title('Activation:  Rule-->sigmoid')
plt.show()

三、结果分析

rule有一定的机遇性,但总体趋势还是精度随着层数的增加而增加,但层数太高也会出现过拟合的情况。
Andrew_NG第一章第三周的作业整理
Andrew_NG第一章第三周的作业整理

X的维度为: (2, 200)
Y的维度为: (1, 200)
数据集里面的数据有:200 个
=========================测试forward_propagation=========================
(-0.0004997557777419913, 0.009407450992324358, 0.000320787397351217, 0.5000801968460385)
=========================测试compute_cost=========================
cost = 0.692919893776
第  0  次循环,成本为:0.693154144009
第  1000  次循环,成本为:0.278040613491
第  2000  次循环,成本为:0.195258293538
第  3000  次循环,成本为:0.10509693607
第  4000  次循环,成本为:0.0991809031961
第  5000  次循环,成本为:0.0973635539258
第  6000  次循环,成本为:0.0964981300555
第  7000  次循环,成本为:0.0960294839933
第  8000  次循环,成本为:0.0957545594441
第  9000  次循环,成本为:0.0955833219085
准确率: 96%
learning rate is: 0.1
隐藏层的节点数量: 2  ,准确率: 86.0 %
隐藏层的节点数量: 4  ,准确率: 87.0 %
隐藏层的节点数量: 6  ,准确率: 87.0 %
隐藏层的节点数量: 12  ,准确率: 87.5 %
隐藏层的节点数量: 16  ,准确率: 87.0 %
隐藏层的节点数量: 64  ,准确率: 87.0 %
隐藏层的节点数量: 128  ,准确率: 87.0 %
[86.  87.  87.  87.5 87.  87.  87. ]
learning rate is: 0.3
隐藏层的节点数量: 2  ,准确率: 86.0 %
隐藏层的节点数量: 4  ,准确率: 87.0 %
隐藏层的节点数量: 6  ,准确率: 96.0 %
隐藏层的节点数量: 12  ,准确率: 96.0 %
隐藏层的节点数量: 16  ,准确率: 87.0 %
隐藏层的节点数量: 64  ,准确率: 87.0 %
隐藏层的节点数量: 128  ,准确率: 96.0 %
[86. 87. 96. 96. 87. 87. 96.]
learning rate is: 0.5
隐藏层的节点数量: 2  ,准确率: 86.0 %
隐藏层的节点数量: 4  ,准确率: 87.0 %
隐藏层的节点数量: 6  ,准确率: 96.0 %
隐藏层的节点数量: 12  ,准确率: 96.0 %
隐藏层的节点数量: 16  ,准确率: 87.0 %
隐藏层的节点数量: 64  ,准确率: 96.0 %
隐藏层的节点数量: 128  ,准确率: 95.5 %
[86.  87.  96.  96.  87.  96.  95.5]
learning rate is: 0.8
隐藏层的节点数量: 2  ,准确率: 86.0 %
隐藏层的节点数量: 4  ,准确率: 87.0 %
隐藏层的节点数量: 6  ,准确率: 96.0 %
隐藏层的节点数量: 12  ,准确率: 95.5 %
隐藏层的节点数量: 16  ,准确率: 87.0 %
隐藏层的节点数量: 64  ,准确率: 97.0 %
隐藏层的节点数量: 128  ,准确率: 95.5 %
[86.  87.  96.  95.5 87.  97.  95.5]
learning rate is: 1
隐藏层的节点数量: 2  ,准确率: 86.0 %
隐藏层的节点数量: 4  ,准确率: 87.0 %
隐藏层的节点数量: 6  ,准确率: 96.0 %
隐藏层的节点数量: 12  ,准确率: 95.5 %
隐藏层的节点数量: 16  ,准确率: 87.0 %
隐藏层的节点数量: 64  ,准确率: 97.0 %
隐藏层的节点数量: 128  ,准确率: 96.0 %
[86.  87.  96.  95.5 87.  97.  96. ]

相关文章:

  • 2021-06-06
  • 2022-01-13
  • 2021-07-26
  • 2021-07-25
  • 2021-08-24
猜你喜欢
  • 2021-11-12
  • 2021-10-08
  • 2021-06-06
  • 2021-04-10
相关资源
相似解决方案