赞
踩
本文仅实现了BP框架搭建,并未实例进行(后续可能会添加)
在本文的代码实现中,是从神经网络的组件开始搭建,而并不是使用Linear层,因此可以尝试看代码配合原理理解,代码已附带,若有需要也可以评论区回复领取
BP神经网络的学习属于有监督学习,需要一组已知期望输出的学习样本集。训练时先使用随机值作为权值(即权重,取值在前向传播部分有介绍),输入学习样本得到网络的输出。然后根据输出值与期望输出计算误差,再由误差根据某种准则逐层修改权值,使误差减小。如此反复,直到误差不再下降,网络就完成训练。
bp神经网络由输入层、隐藏层、输出层组成
其中表示第个输入节点的数据,而最后的则表示预测值,而训练过程则分为了前向传播与反向传播两个过程,而该图像中的圆则表示神经网络节点。
在一般的问题中,单隐层结构就能够满足需求,理论上来说单个隐含层的网络可以通过适当增加神经元节点的个数实现任意非线性映射,但如果样本过多,可以选择增加一个隐含层减少网络规模。
但当隐含层的数目超过一定值,反而会使网络的性能降低,因此采用含有一个隐含层的三层BP网络可以完成任意n维到m维的映射。所以建议使用单隐层结构。
对于输入节点的考虑,就比如《人工神经网络》一书中的案例“基于BP神经网络的瓦斯压力快速反演”,选取输入层神经元个数时,选取的是对于煤层瓦斯压力影响最主要的四个因素。但当我们无法进行判断主要因素同时又拥有多个输入参数是,我们可以采取主成分分析法(PCA)进行分析,选取出主要的影响因素确定输入节点个数
隐含层的单元数直接影响网络的非线性性能,它与解决问题的复杂性有关
一般对于三层前向网络隐含层节点数有如下经验公式:
其中:为输出层节点个数;为输入层节点个数;为的常数
数据在输入后乘以权重再加上偏置得到输出结果,再将结果作为输入在激活函数中计算,再将计算结果作为下一个节点的输入传递下去,而最终的输出结果则是我们想实现的预测结果
其中为该连接上的权重,为该节点的偏置,为激活函数
注:此处为了绘图便捷,仅绘制了单一神经元,但在计算的过程中应当是多个输入计算然后加权和
可参考此博客的讲解部分:
神经元之间的连接强度由权重表示,权重的大小表示可能性的大小/也可理解为控制信号的重要性通常设定什么样的权重初始值,经常关系到神经网络收敛的快慢以及学习是否成功。权重衰减可以有效抑制过拟合、提高泛化能力,一般将初始值设置为较小的值,同时为了确保神经网络不同的权重的意义不丧失,所以必须随机生成初始值。BP网络训练开始之前,对网络的权重和偏置值进行初始化,权重取[-1,1]之间的一个随机数,此处取值是基于经验的取值
同时另一经验公式为:
或者
其中F为权值输入端连接的神经元个数
是为了正确分类样本/控制神经元被激活的容易程度,偏置依据经验取[0,1]间的一个随机数
激活函数:起非线性映射的作用,将神经元的输出幅度限制在一定范围内,一般是限制再(-1,1)或者(0,1),一般选取激活函数为sigmoid函数,对于激活函数的介绍可以参考这篇博客:通用化BP神经网络-激活函数_bp神经网络激活函数-CSDN博客
反向传播的实质为根据误差调整权值
当网络输出与期望输出不等时,会存在输出误差E:
其中为期望输出,而为网络输出
注:此处的计算公式又称为损失函数
因此网络误差实则是各层权值的函数,因此调整权值可改变误差。而调整权值的目的是使误差不断减小,因此应使权值得调整量与误差的梯度下降成正比,即:
其中为权重,而为学习率,负号则表示梯度下降
权重更新公式可参考:神经网络之BP神经网络-CSDN博客
此处并不会将其实现部分写的过于详细,在我的python文件中有注释,能够帮助理解,故而此部分主要讲解不易于理解的部分,如果想要详细的python讲解部分可以去查阅一下其他博客(后续可能会录制视频上传b站)
在反向传播部分主要是在进行通过误差调整权重,而权重的调整公式如下(为便于理解,将配合python代码讲解)
在此处的代码中:
-
- output_deltas=self.output_nodes * [0.0]
- for i in range(self.output_nodes):
- error = label[i] - self.output_values[i]
- output_deltas[i] = error * sigmoid_derivative(self.output_values[i])
- # 计算隐含层误差
- hidden_deltas=self.hidden_nodes * [0.0]
- for i in range(self.hidden_nodes):
- error = 0.0
- for j in range(self.output_nodes):
- error += output_deltas[j] * self.hidden_weights[i][j]
- hidden_deltas[j] = error * sigmoid_derivative(self.hidden_values[i])
1.error与output_deltas[i]这两个计算公式,首先error此处得到了输出层各个节点的输出值与期望值的差,然后output_deltas此处计算公式为:
此处的表示为误差信号,此处的表示激活函数的导数,表示输出层的输出值
注:因为将权值计算公式拆开,所以此处不好理解,后续会提到
2.对于隐含层到输出层的误差与上述的计算公式又有所不同,此处的误差信号计算公式为:
此处的表示为从隐含层到输出层的权重值,则表示为输出层的误差信号
- # 更新隐含层到输出层的权重
- for i in range(self.hidden_nodes):
- for j in range(self.output_nodes):
- change = output_deltas[j] * self.hidden_values[i]
- self.hidden_weights[i][j] += learn * change
- self.output_bias[j] += learn * change
- # 更新输入层到隐含层的权重
- for i in range(self.input_nodes):
- for j in range(self.hidden_nodes):
- change = hidden_deltas[j] * self.input_values[i]
- self.input_weights[i][j] += learn * change
- self.input_bias[j] += learn * change
1.在更新隐含层到输出层的权重时,更新权重的最终公式为:变化的权重 = 学习率 * 误差信号 * 隐含层的输出值
2.在更新输入层到隐含层的权重时,更新权重的最终公式为:变化的权重 = 学习率 * 误差信号 * 输入层的输出值
由于我的python代码主要来自于网络上寻找的部分,故而在偏置更新部分与博客大部分的理论公式相冲突,就比如在隐含层到输出层的偏置更新中公式为:变化的偏置 = 学习率 * 误差(此处的误差为输出层第k个节点处,期望输出值与实际输出值的差)
但在此篇博客中BP算法,用梯度下降法更新权值W与偏置项b-CSDN博客其偏置的更新公式为:变化的偏置 = 学习率 * 误差信号
所以大家在偏置更新这段代码编写过程中可以依据自己的选择进行更改,作者选择的是第二种方法
在误差的权空间中,考虑到误差曲面形状的固有性,易形成局部最小而达不到全局最优,因此可以通过添加动量项,自适应调节学习率,引入陡度因子来改进算法
在本文附带的python代码中就通过增加动量项来改进
在python代码中对应:
其中correct等效于,而乘的那部分等效于
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。