BP神经网络反向传播算法

1.编程题目理解

​ 反向传播(英语:Backpropagation,缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。该方法对网络中所有权重计算损失函数的梯度。这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。
​ 反向传播要求有对每个输入值想得到的已知输出,来计算损失函数梯度。因此,它通常被认为是一种监督式学习方法,虽然它也用在一些无监督网络(如自动编码器)中。它是多层前馈网络的Delta规则的推广,可以用链式法则对每层迭代计算梯度。反向传播要求人工神经元(或“节点”)的激励函数可微。

2.BP算法原理阐释

​ BP算法由信号的正向传播和误差的反向传播两个过程组成。

​ 正向传播时,输入样本从输入层进入网络,经隐层逐层传递至输出层,如果输出层的实际输出与期望输出(导师信号)不同,则转至误差反向传播;如果输出层的实际输出与期望输出(导师信号)相同,结束学习算法。

​ 反向传播时,将输出误差(期望输出与实际输出之差)按原通路反传计算,通过隐层反向,直至输入层,在反传过程中将误差分摊给各层的各个单元,获得各层各单元的误差信号,并将其作为修正各单元权值的根据。这一计算过程使用梯度下降法完成,在不停地调整各层神经元的权值和阈值后,使误差信号减小到最低限度。

​ 权值和阈值不断调整的过程,就是网络的学习与训练过程,经过信号正向传播与误差反向传播,权值和阈值的调整反复进行,一直进行到预先设定的学习训练次数,或输出误差减小到允许的程度。

3.算法设计思路

1.初始化网络权值和神经元的阈值(最简单的办法就是随机初始化)

2.前向传播:按照公式一层一层的计算隐层神经元和输出层神经元的输入和输出。

3.后向传播:根据公式修正权值和阈值

直到满足终止条件。

4.测试结果及分析

在这里插入图片描述

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

标准BP前期下降的非常快,到后期比较平缓。累计BP下降速率比较平缓。

可以看出当累计误差下降导一定程度时候,累计BP比标准BP要慢。比如停止条件为loss<=0.01时,效果如下。

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

5.核心代码

#标准BP算法学习
def train_standard_BP(features,labels,lr):
    net=Net()
    epoch=0
    loss=1
    all_loss=[]
    while loss>0.1:#停止条件
        for i in range(features.shape[1]):
            X=features[:,i]
            Y=labels[0,i]
            net.forward(X.reshape(-1,1))
            net.standard_BP(Y,lr)
        output=net.forward(features)
        loss=0.5*((output-labels)**2).sum()
        epoch+=1
        all_loss.append(loss)
    print("标准BP","学习率:",lr,"\n终止epoch:",epoch,"loss: ",loss)
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.title('标准BP')
    plt.plot(all_loss)
    plt.show()
#累计BP算法学习
def train_accumulate_BP(features,labels,lr=0.2):
    net=Net()
    epoch=0
    loss=1
    all_loss=[]
    while loss>0.1:#停止条件
        output=net.forward(features)
        net.accumulate_BP(labels,lr)
        loss=0.5*((output-labels)**2).sum()/labels.shape[1]
        epoch+=1
        all_loss.append(loss)
    print("累积BP","学习率:",lr,"\n终止epoch:",epoch,"loss: ",loss)
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.plot(all_loss)
    plt.title("累计BP")
    plt.show()

6.主要解决问题和收获

主要了解了BP算法是如何实现的;单隐层神经网络的结构;对神经网络的认识有一个初步的了解。

7.参考来源s

西瓜书第五章笔记及答案——神经网络_菜要多训练的博客-CSDN博客

BP算法_百度百科 (baidu.com)

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#西瓜数据集 每一列为一条数据
features=np.array([
    [1,2,2,1,0,1,2,2,2,1,0,0,1,0,2,0,1],
    [2,2,2,2,2,1,1,1,1,0,0,2,1,1,1,2,2],
    [1,0,1,0,1,1,1,1,0,2,2,1,1,0,1,1,0],
    [0,0,0,0,0,0,1,0,1,0,2,2,1,1,0,2,1],
    [2,2,2,2,2,1,1,1,1,0,0,0,2,2,1,0,1],
    [1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1],
    [0.697,0.774,0.634,0.608,0.556,0.403,0.481,0.437,0.666,0.243,0.245,0.343,0.639,0.657,0.360,0.593,0.719],
    [0.460,0.376,0.264,0.318,0.215,0.237,0.149,0.211,0.091,0.267,0.057,0.099,0.161,0.198,0.370,0.042,0.103]
])
labels=np.array([
    [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0]
])

def sigmoid(X):
    return 1./(1+np.exp(-X))
class Net():
    def __init__(self,num_input=8,num_hidden=10,num_output=1):
        #隐含层和输出层的权重和偏置
        self.W1=np.random.randn(num_hidden,num_input)
        self.b1=np.zeros(num_hidden).reshape(-1,1)
        self.W2=np.random.randn(num_output,num_hidden)
        self.b2=np.zeros(num_output).reshape(-1,1)
        #隐含层和输出层的输出
        self.o1=np.zeros(num_hidden).reshape(-1,1)
        self.o2=np.zeros(num_output).reshape(-1,1)
        #梯度存储变量
        self.do2=np.zeros(self.o2.shape)
        self.dW2=np.zeros(self.W2.shape)
        self.db2=np.zeros(self.b2.shape)
        self.do1=np.zeros(self.o1.shape)
        self.dW1=np.zeros(self.W1.shape)
        self.db1=np.zeros(self.b1.shape)
    def forward(self,X):#前向传播
        if X.shape[0] != self.W1.shape[1]:
            print("输入数据格式错误!")
            return
        self.input=X
        #使用sigmoid函数为激活函数
        self.o1=sigmoid(np.matmul(self.W1,self.input)+self.b1)
        self.o2=sigmoid(np.matmul(self.W2,self.o1)+self.b2)
        return self.o2
    def standard_BP(self,label,lr=0.2):#标准BP 使用均方误差为损失函数
        #求梯度
        self.do2=self.o2-label
        self.dW2=np.matmul(self.do2*self.o2*(1-self.o2),self.o1.reshape(1,-1))
        self.db2=self.do2*self.o2*(1-self.o2)
        self.do1=np.matmul(self.W2.transpose(),self.do2*self.o2*(1-self.o2))
        self.dW1=np.matmul(self.do1*self.o1*(1-self.o1),self.input.reshape(1,-1))
        self.db1=self.do1*self.o1*(1-self.o1)
        #更新参数
        self.W2-=self.dW2*lr
        self.b2-=self.db2*lr
        self.W1-=self.dW1*lr
        self.b1-=self.db1*lr
    def accumulate_BP(self,labels,lr=0.2):#累积BP 使用均方误差为损失函数
        num=labels.shape[1]#样本数量
        #求梯度
        self.do2=(self.o2-labels)/num
        self.dW2=np.matmul(self.do2*self.o2*(1-self.o2),self.o1.transpose())
        self.db2=(self.do2*self.o2*(1-self.o2)).sum(axis=1).reshape(-1,1)
        self.do1=np.matmul(self.W2.transpose(),self.do2*self.o2*(1-self.o2))
        self.dW1=np.matmul(self.do1*self.o1*(1-self.o1),self.input.transpose())
        self.db1=(self.do1*self.o1*(1-self.o1)).sum(axis=1).reshape(-1,1)
        #更新参数
        self.W2-=self.dW2*lr
        self.b2-=self.db2*lr
        self.W1-=self.dW1*lr
        self.b1-=self.db1*lr
        
def train_standard_BP(features,labels,lr):
    net=Net()
    epoch=0
    loss=1
    all_loss=[]
    while loss>0.01:#停止条件
        for i in range(features.shape[1]):
            X=features[:,i]
            Y=labels[0,i]
            net.forward(X.reshape(-1,1))
            net.standard_BP(Y,lr)
        output=net.forward(features)
        loss=0.5*((output-labels)**2).sum()
        epoch+=1
        all_loss.append(loss)
    print("标准BP","学习率:",lr,"\n终止epoch:",epoch,"loss: ",loss)
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.title('标准BP')
    plt.plot(all_loss)
    plt.show()
    
def train_accumulate_BP(features,labels,lr=0.2):
    net=Net()
    epoch=0
    loss=1
    all_loss=[]
    while loss>0.01:#停止条件
        output=net.forward(features)
        net.accumulate_BP(labels,lr)
        loss=0.5*((output-labels)**2).sum()/labels.shape[1]
        epoch+=1
        all_loss.append(loss)
    print("累积BP","学习率:",lr,"\n终止epoch:",epoch,"loss: ",loss)
    plt.xlabel("epoch")
    plt.ylabel("loss")
    plt.plot(all_loss)
    plt.title("累计BP")
    plt.show()

train_standard_BP(features,labels,lr=0.2)
train_accumulate_BP(features,labels,lr=0.2)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值