李宏毅机器学习笔记(七)——反向传播与全连接神经网络的构建

一.反向传播(BP算法)

  虽然名字听起来高大上,但是意思其实就是从后往前,通过链式求导来求得梯度,之后再用梯度下降等方法来进行参数更新而已。
在这里插入图片描述
  如图所示,就是一层函数套一层函数就行,那这个式子再带入损失函数去参数 w w w b b b求导,也都不是难事了。具体的推导老师讲的很详细,这里就不细讲了。

二.简单全连接神经网络的构建

  笔者以异或问题为例,建立一个如下的二层的神经网络。代码格式和风格参考了其他的课程。
  首先我们可以整理一下训练神经网络的步骤:首先定义好神经网络的结构,确定好损失函数以及优化方式;之后的流程图如下图所示。因此我们利用模块化的思想来构建代码。
在这里插入图片描述

#以异或问题举例,两层神经网络
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap

#带标签的数据
x_data = np.array([[1,1],[1,0],[0,1],[0,0]])
y_data = np.array([[1],[0],[0],[1]])
plt.scatter(x_data[:,1],x_data[:,0],c=y_data)
plt.show()

#使用k+1个神经元,其中第一层k个,第二层1个,用于构造全部参数
def initial(k):
    W1=np.random.randn(2,k)
    b1=np.zeros((1,k))
    W2=np.random.randn(k,1)
    b2=np.zeros((1,1))
    parameters = {"W1": W1,"b1": b1,"W2": W2,"b2": b2}
    return parameters

#sigmoid函数
def sigmoid(x):
    return 1/(1+np.exp(-x))

#使用交叉熵损失函数
def loss(Y_pre,Y):
    return -np.sum(Y*np.log(Y_pre)+(1-Y)*np.log(1-Y_pre)) #numpy自带广播机制

#前向传播计算预测值
def forward_propagation(parameters,X):
    #每两行是一层,激活函数全使用sigmoid函数
    Z1 = np.dot(X,parameters["W1"])+parameters["b1"]
    A1 = sigmoid(Z1)

    Z2 = np.dot(A1,parameters["W2"])+parameters["b2"]
    A2 = sigmoid(Z2)  #其实A2就是预测值
    cache = {"Z1": Z1, "A1": A1, "Z2": Z2, "A2": A2}
    return cache

#用于计算梯度值
def backward_propagation(parameters,X,Y,cache,loss):
    #先判断输入的个数(注意不是维数)
    m = X.shape[0]
    #先计算最后一层,对W和b使用单层的公式,推导略,参数列表与前向传播对应
    dZ2 = cache["A2"]-Y #链导,损失值先对y求导,再对sigmiod函数求导
    dW2 = 1/m * np.dot(cache["A1"].T,dZ2)
    db2 = 1/m * np.sum(dZ2)
    #再向前计算一层。同样对W和b使用单层公式
    dZ1 = np.dot(dZ2,parameters["W2"].T) * (1-np.power(cache["A1"],2)) #从后面一层的Z中向前链导,经过sigmiod函数
    dW1 = 1/m * np.dot(X.T,dZ1)
    db1 = 1 / m * np.sum(dZ1, axis=0)
    grads = {"dW1": dW1,"db1": db1,"dW2": dW2,"db2": db2}
    return grads

#更新梯度,注意必须要全部计算完一起更新,不能传播一层更新一层
def update(parameters,grads,alpha):
    parameters["W1"] -= alpha * grads["dW1"]
    parameters["b1"] -= alpha * grads["db1"]
    parameters["W2"] -= alpha * grads["dW2"]
    parameters["b2"] -= alpha * grads["db2"]
    return parameters

#用于画图
def plot_decision_boundary(parameters):
    #对网格状的点进行预测
    xx, yy = np.meshgrid(np.arange(-0.1, 1.1, 0.01), np.arange(-0.1, 1.1, 0.01))
    X = np.c_[xx.ravel(),yy.ravel()]
    Z = forward_propagation(parameters,X)["A2"]
    Z = Z.reshape(xx.shape)
    # 然后画出等高线图
    custom_cmap = ListedColormap(['#EF9A9A', '#FFF59D'])
    plt.contourf(xx, yy, Z, linewidth=5,cmap=custom_cmap)

  将这些模块按照流程图中的结构组合起来,就可以构建出全连接神经网络了。

#将功能组合起来,即为全连接神经网络
def DNN(learning_rate,iteration_times,k):
    parameters = initial(k)
    for i in range(iteration_times):
        cache = forward_propagation(parameters,x_data)
        Loss = loss(cache["A2"],y_data)
        grads = backward_propagation(parameters,x_data,y_data,cache,Loss)
        parameters = update(parameters,grads,learning_rate)
        if i % 1000 == 0:
            print("第"+str(i)+"轮:损失值为"+str(Loss))
    plot_decision_boundary(parameters)
    plt.scatter(x_data[:,1],x_data[:,0],c=y_data)
    plt.show()
#参数可任选
DNN(0.005,200000,40)

  最后的结果,总之一般来说,神经元越多越稳定、训练的次数越多越稳定、学习率越小越稳定;当神经元少的时候,尤其是只有3个的时候,经常会很不稳定。最后的分类结果如下图所示,可见我们通过多层的神经网络,已经实现了非线性边界。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值