【算法】BP神经网络(BP,Back Propagation)

参考资料:来自于老哥数学建模课程。

BP神经网络的背景

1986年,Rumelhart等提出了误差反向传播神经网络,简称BP网络(Back Propagation),该网络是一种单向传播的多层前向网络。误差反向传播的学习算法简称BP算法,其基本思想是梯度下降法,BP神经网络是到目前为止使用最多、最成熟、采用最速下降的学习方式,在训练过程中通过误差的反向传播不断调整网络的权值和阈值,使得网络的误差平方和最小。BP神经网络可以全局逼近任意非线性的映射,具有良好的泛化性能。除此只挖掘,BP神经网络还具有强大的容错能力、鲁棒性好,具有自学习、自组织和自适应性等优点。因此,该神经网络自提出之后就得到了众多研究人员关注,并已经应用于语言综合、语言识别、自适应控制等领域。

输入层、隐含层、输出层

输入层:指的就是我们输入数据的种类数量,输入几类,输入层神经元就有几层

隐含层:夹在输入层和输出层之间的神经元,数量可以自行设置,不过一般通过经验公式来确定:

h = m + n + a h=\sqrt{m+n+a} h=m+n+a

其中,m,n分别为输入、输出层节点个数,a为1-10之间的调节常数。

输出层:指的就是我们相应得到的指标,一般就一个

权值

权值(Weight):输入层与隐含层之间

权值是神经元之间连接的强度,标示量一个神经元的输出与其输入直接的关联程度,在神经网络的每个连接中,都会有一个对应的权值。当一个神经元与另一个神经元连接时,输入信号会乘以对应的权值,然后传递给下一个神经元。权值可以看作是输入信号的重要性或权重,它决定了输入信号对神经元激活状态的影响程度。权值是神经网络训练的主要目标,通过反向传播算法等优化方法,调整权值使得神经网络能够更好地拟合训练数据,准确预测。

阈值

阈值(Biases):隐含层和输出层之间

阈值是神经元的激活门限值,用于控制神经元是否被激活。在神经元接收到加权输入后,会将输入值与对应的权值相加,然后与阈值进行比较。如果加权输入超过了阈值,神经元将被激活,产生输出。否则将保持非激活状态。阈值可以看作是神经元的敏感度,调整阈值可以改变神经元的激活情况。在神经网络的训练过程中,也会优化阈值,以使神经元的激活情况更符合预期输出。

需要注意的是,权值和阈值都是可以学习更新的,神经网络会自动调整,以优化神经网络的性能、准确性。

激活函数

常用的激活函数有两个:

  1. tanh(双曲正切)激活函数:

tanh函数的定义是:

f ( x ) = e x − e − x e x + e − x f(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} f(x)=ex+exexex

这个函数的输出范围在-1到1之间,即在输入较大或较小时,都能产生较大的输出值,因此相对于Sigmoid函数,它的输出更接近于零中心化,有时能帮助神经网络更快地收敛。

  1. Sigmoid激活函数:

Sigmoid函数的定义是:

f ( x ) = 1 1 + e − x f(x)=\frac{1}{1+e^{-x}} f(x)=1+ex1

这个函数的输出范围是0-1之间,当输入值较大/较小时,输出值接近于0/1,容易导致梯度消失问题,即在反向传播过程中梯度接近于0,使得网络难以更新权重。

这两种激活函数主要用于在神经元之间传递信号并引入非线性特性,它们的主要作用在于增加网络的表达能力,使得神经网络可以学习非线性函数。

Tanh函数的求导过程:

d tanh ⁡ ( x ) d x = 1 − tanh ⁡ 2 ( x ) \frac{d\tanh(x)}{dx} = 1 - \tanh^{2}(x) dxdtanh(x)=1tanh2(x)

Sigmoid函数的求导过程:

d σ ( x ) d x = σ ( x ) ⋅ ( 1 − σ ( x ) ) \frac{d\sigma(x)}{dx} = \sigma(x) \cdot (1 - \sigma(x)) dxdσ(x)=σ(x)(1σ(x))

较小规模选Sigmoid,更复杂的选tanh,因为他在输入较大或较小时有更大的导数,可以有效避免梯度消失问题。

评价指标

BP神经网络优化前后的预测误差评价指标有4种,分别为:

(1)平均绝对误差mae:

m a e = 1 n ∑ i = 1 n ∣ y i − h ( x i ) ∣ mae=\frac{1}{n}\sum^n_{i=1}\lvert{y_i-h(x_i)}\rvert mae=n1i=1nyih(xi)

y y y代表真实值, h ( x i ) h(x_i) h(xi)代表预测值。

(2)均方误差mse:

m s e = ∑ i = 1 n ( X i − x i ) 2 N mse=\frac{\sum^n_{i=1}(X_i-x_i)^2}{N} mse=Ni=1n(Xixi)2

其中, X i X_i Xi x i x_i xi分别为真实值和预测值, N N N为样本个数。

(3)均方误差根rmse:

r m s e = ∑ i = 1 n ( X i − x i ) 2 N rmse=\sqrt{\frac{\sum^n_{i=1}(X_i-x_i)^2}{N}} rmse=Ni=1n(Xixi)2

(4)平均绝对百分比误差mape:

m a p e = 100 % n 1 n ∑ i = 1 n ∣ y i − h ( x i ) y i ∣ mape=\frac{100\%}{n}\frac{1}{n}\sum^n_{i=1}\lvert\frac{{y_i-h(x_i)}}{y_i}\rvert mape=n100%n1i=1nyiyih(xi)

其中, y i y_i yi代表真实值, h ( x i ) h(x_i) h(xi)代表预测值,mape值越小,代表模型拟合的越好越准确,mape=0即完美,mape>100%则表示模型劣质、不合适。

如何建立一个BP神经网络

步骤:

  1. 定义输入和输出:明确你输入的特征/数据是什么,输出是你希望神经网络预测/分类的目标。
  2. 设计网络结构:确定输入层的节点数量(与输入特征数相同)、输出层的节点数量(与输出维度相同),以及中间的隐藏层的数量和节点数量。层数的增加只可能是隐含层的增加。
  3. 初始化权值和阈值:这两个值一般会被初始化为随机值
  4. 前向传播(Forward Propagation):数据从输入层传到输出层,每个神经元中,输入值乘以权重加上阈值,通过激活函数计算神经元的输出。直到累计产生最终预测结果。
  5. 计算损失(Loss):损失函数用于衡量神经网络的预测输出与实际输出之间的误差。常见的损失函数包括包括均方误差和交叉熵损失等。目标是通过训练来最小化损失,使得神经网络的输出尽可能接近真实值。
  6. 反向传播(Back Propagation):反向传播是训练神经网络的核心步骤,通过比较预测输出和实际输出,计算损失函数对权值和阈值的梯度,然后,使用优化算法(如梯度下降法)来根据这些梯度逐渐调整权值和阈值,使损失函数减小。
  7. 重复训练
  8. 验证测试
  9. 模型应用

BP神经网络实际代码

import numpy as np
import math
import random
import string
import matplotlib as mpl
import matplotlib.pyplot as plt

#random.seed(0)  #当我们设置相同的seed,每次生成的随机数相同。如果不设置seed,则每次会生成不同的随机数
               #参考https://blog.csdn.net/jiangjiang_jian/article/details/79031788

#生成区间[a,b]内的随机数
def random_number(a,b):
   return (b-a)*random.random()+a

#生成一个矩阵,大小为m*n,并且设置默认零矩阵
def makematrix(m, n, fill=0.0):
   a = []
   for i in range(m):
       a.append([fill]*n)
   return a

#函数sigmoid(),这里采用tanh,因为看起来要比标准的sigmoid函数好看
def sigmoid(x):
   return math.tanh(x)

#函数sigmoid的派生函数
def derived_sigmoid(x):
   return 1.0 - x**2

#构造三层BP网络架构
class BPNN:
   def __init__(self, num_in, num_hidden, num_out):
       #输入层,隐藏层,输出层的节点数
       self.num_in = num_in + 1  #增加一个偏置结点
       self.num_hidden = num_hidden + 1   #增加一个偏置结点
       self.num_out = num_out
       
       #激活神经网络的所有节点(向量)
       self.active_in = [1.0]*self.num_in
       self.active_hidden = [1.0]*self.num_hidden
       self.active_out = [1.0]*self.num_out
       
       #创建权重矩阵
       self.wight_in = makematrix(self.num_in, self.num_hidden)
       self.wight_out = makematrix(self.num_hidden, self.num_out)
       
       #对权值矩阵赋初值
       for i in range(self.num_in):
           for j in range(self.num_hidden):
               self.wight_in[i][j] = random_number(-0.2, 0.2)
       for i in range(self.num_hidden):
           for j in range(self.num_out):
               self.wight_out[i][j] = random_number(-0.2, 0.2)
   
       #最后建立动量因子(矩阵)
       self.ci = makematrix(self.num_in, self.num_hidden)
       self.co = makematrix(self.num_hidden, self.num_out)        
       
   #信号正向传播
   def update(self, inputs):
       if len(inputs) != self.num_in-1:
           raise ValueError('与输入层节点数不符')
           
       #数据输入输入层
       for i in range(self.num_in - 1):
           #self.active_in[i] = sigmoid(inputs[i])  #或者先在输入层进行数据处理
           self.active_in[i] = inputs[i]  #active_in[]是输入数据的矩阵
           
       #数据在隐藏层的处理
       for i in range(self.num_hidden - 1):
           sum = 0.0
           for j in range(self.num_in):
               sum = sum + self.active_in[i] * self.wight_in[j][i]
           self.active_hidden[i] = sigmoid(sum)   #active_hidden[]是处理完输入数据之后存储,作为输出层的输入数据
           
       #数据在输出层的处理
       for i in range(self.num_out):
           sum = 0.0
           for j in range(self.num_hidden):
               sum = sum + self.active_hidden[j]*self.wight_out[j][i]
           self.active_out[i] = sigmoid(sum)   #与上同理
           
       return self.active_out[:]
   
   #误差反向传播
   def errorbackpropagate(self, targets, lr, m):   #lr是学习率, m是动量因子
       if len(targets) != self.num_out:
           raise ValueError('与输出层节点数不符!')
           
       #首先计算输出层的误差
       out_deltas = [0.0]*self.num_out
       for i in range(self.num_out):
           error = targets[i] - self.active_out[i]
           out_deltas[i] = derived_sigmoid(self.active_out[i])*error
       
       #然后计算隐藏层误差
       hidden_deltas = [0.0]*self.num_hidden
       for i in range(self.num_hidden):
           error = 0.0
           for j in range(self.num_out):
               error = error + out_deltas[j]* self.wight_out[i][j]
           hidden_deltas[i] = derived_sigmoid(self.active_hidden[i])*error
       
       #首先更新输出层权值
       for i in range(self.num_hidden):
           for j in range(self.num_out):
               change = out_deltas[j]*self.active_hidden[i]
               self.wight_out[i][j] = self.wight_out[i][j] + lr*change + m*self.co[i][j]
               self.co[i][j] = change
               
       #然后更新输入层权值
       for i in range(self.num_in):
           for i in range(self.num_hidden):
               change = hidden_deltas[j]*self.active_in[i]
               self.wight_in[i][j] = self.wight_in[i][j] + lr*change + m* self.ci[i][j]
               self.ci[i][j] = change
               
       #计算总误差
       error = 0.0
       for i in range(len(targets)):
           error = error + 0.5*(targets[i] - self.active_out[i])**2
       return error

   #测试
   def test(self, patterns):
       for i in patterns:
           print(i[0], '->', self.update(i[0]))
   #权重
   def weights(self):
       print("输入层权重")
       for i in range(self.num_in):
           print(self.wight_in[i])
       print("输出层权重")
       for i in range(self.num_hidden):
           print(self.wight_out[i])
           
   def train(self, pattern, itera=100000, lr = 0.1, m=0.1):
       for i in range(itera):
           error = 0.0
           for j in pattern:
               inputs = j[0]
               targets = j[1]
               self.update(inputs)
               error = error + self.errorbackpropagate(targets, lr, m)
           if i % 100 == 0:
               print('误差 %-.5f' % error)
   
#实例
def demo():
   patt = [
           [[1,2,5],[0]],
           [[1,3,4],[1]],
           [[1,6,2],[1]],
           [[1,5,1],[0]],
           [[1,8,4],[1]]
           ]
   #创建神经网络,3个输入节点,3个隐藏层节点,1个输出层节点
   n = BPNN(3, 3, 1)
   #训练神经网络
   n.train(patt)
   #测试神经网络
   n.test(patt)
   #查阅权重值
   n.weights()

    
if __name__ == '__main__':
   demo()

运行结果如图所示:

在这里插入图片描述

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 遗传算法(Genetic Algorithm)和反向传播神经网络(Backpropagation Neural Network, BP神经网络)是两种常用的机器学习算法,可以在Python中实现用于回归问题的解决。 遗传算法是一种模拟自然选择和遗传机制的优化算法,通过将个体的特征编码成染色体,利用选择、交叉和变异操作来不断演化种群,以寻找最优解。在回归问题中,可以将染色体编码成神经网络的权重和偏置值,演化的目标是找到使得神经网络拟合出最佳回归模型的最优权重。通过适应度函数评估每个个体的拟合程度,选择适应度高的个体进行繁殖,然后进行交叉和变异操作,不断演化种群,最终找到最优解。 BP神经网络是一种常用的有监督学习算法,通过前向传播和反向传播的方式进行训练。在回归问题中,BP神经网络可以通过多个输入节点、隐藏层和输出节点的组合,以拟合输入和输出之间的复杂非线性关系。在Python中,可以使用一些常用的神经网络库(如PyTorch、TensorFlow等)来搭建和训练BP神经网络。通过将输入数据喂给网络,计算输出,并与真实输出进行比较,用误差来更新网络的权重和偏置值,不断迭代训练,直到达到收敛或设定的停止条件。 在结合遗传算法BP神经网络进行回归问题的求解时,可以利用遗传算法的全局搜索能力来搜索神经网络的初始权重和偏置值,然后再使用BP神经网络进行细致的优化和训练,提高回归模型的拟合精度和泛化能力。具体实现上,可以先利用遗传算法生成初始种群,然后使用BP神经网络对每个个体进行评估,并计算适应度值。根据适应度值选择优秀的个体进行遗传操作,如选择、交叉和变异。迭代演化后,得到最优个体对应的权重和偏置值,进而得到最优的回归模型。整个过程可以使用Python编程语言进行实现。 ### 回答2: 遗传算法是一种基于自然选择和遗传机制原理的优化算法,它模拟了生物进化的过程,通过对候选解进行进化和选择,以求得问题的最优解。遗传算法可以用于优化神经网络中的参数值,如权重和阈值。 BP神经网络是一种常用的人工神经网络模型,它可以通过反向传播算法来训练网络,实现对数据的拟合和预测。BP神经网络通常用于解决分类和回归问题,其中回归问题是通过利用已知数据来预测连续型变量的值。 在使用遗传算法优化BP神经网络回归模型时,首先需要定义适应度函数,即衡量神经网络预测结果与实际结果之间的差异程度。然后,通过遗传算法的选择、交叉和变异操作对神经网络的参数进行优化,以求得最优的网络结构和参数配置。 使用Python编程语言可以方便地实现遗传算法BP神经网络的结合。Python提供了强大的数学计算库如NumPy和SciPy,可以用于BP神经网络的训练和优化;同时,PyGAD(Python Genetic Algorithm Library)等相关库可以用于实现遗传算法的各种操作,如选择、交叉和变异。 在实际应用中,可以将问题转化为回归问题,通过建立BP神经网络回归模型,并结合遗传算法进行参数优化,进而得到更准确的预测结果。通过Python编程,我们可以灵活地调整遗传算法BP神经网络的参数,以适应不同的问题需求,并获得更好的回归预测效果。 ### 回答3: 遗传算法(Genetic Algorithm)是一种模拟生物进化过程的优化算法。它通过使用种群、代际交叉和变异等操作,以逐步优化问题的解。在遗传算法中,首先需要定义优化目标和适应度函数,然后生成初始的随机种群,通过评估每个个体的适应度来选取更好的个体进行进一步繁衍,直到达到停止准则为止。 BP神经网络(Back Propagation Neural Network)是一种前向反馈的人工神经网络模型,是一种常见的分类和回归算法BP神经网络通过学习训练数据集,调整网络连接权重来建立输入与输出之间的映射关系。它通过正向传播计算输出,并通过反向传播根据误差调整每个神经元的权重,从而优化网络的性能。 在进行回归任务时,可以将遗传算法BP神经网络相结合,使用遗传算法来选择出更好的初始权重,然后再使用BP神经网络进行训练和优化。具体操作可以分为以下几个步骤: 1. 定义适应度函数:将BP神经网络预测结果与实际标签之间的误差作为适应度函数,衡量每个个体的优劣。 2. 初始化种群:随机生成一定数量的BP神经网络的初始权重,并将它们作为初始的种群。 3. 迭代进化:通过计算每个个体的适应度,逐代进行选择、交叉和变异操作,生成新的种群。 4. 终止准则:设置终止条件,如达到最大迭代次数或目标误差小于某个阈值。 5. 使用最优个体:在遗传算法收敛后,选择适应度最高的个体作为BP神经网络的初始权重,并使用该权重对数据进行训练和预测。 在Python中,可以使用遗传算法BP神经网络的相关库来实现上述步骤,如使用DEAP库实现遗传算法部分,使用Scikit-learn库实现BP神经网络部分。通过对训练集的迭代和优化,以达到更好的回归预测效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

城主_全栈开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值