BP神经网络

简介: 反向传播算法的核心思想是**将输出误差以某种形式通过隐藏层向输入层逐层反转**,如下图所示。

1、反向传播算法的原理

  反向传播算法的核心思想是将输出误差以某种形式通过隐藏层向输入层逐层反转,如下图所示。

image-20220616165727007

  反向传播算法在整个神经网络训练过程中发挥着重要的作用,它调整神经元之间的参数来学习样本中的规则,事实上权重存储了数据中存在的特征。在训练过程中,前向传播和后向传播相辅相成,如下图所示。

image-20220616165920918

  反向传播算法由Hinton于1986年在Nature的论文中提出。简单来说,反向传播主要解决神经网络在训练模型时的参数更新问题。假设神经网络如下图所示,为了简化推到过程,输入层只用了一个特征。同样,输出层也只有一个节点,隐藏层使用了两个节点。注意,在实际的神经网络中,唱吧$z_1$和$h_1$当作一个节点来画图(其中$z_1=xw_1,h_1=sigmoid(z_1)$,注意也可以是其他激活函数),这里为了方便推到才把两者分开。

image-20220616171318385

  反向传播算法需要解决每条边对应的权值如何更新才能使得整个输出的损失函数最小。在反向传播算法中,对于每个输出节点,给定一个输入样例,会得到一个预测值,而这个预测值和真实值之间的差距可以定义为误差(类比“欠的钱”),是谁影响了欠钱的多少?很明显,在神经网络模型中,只有待求的参数${w_1,w_2,...,w_n}$了。

  如何衡量每个参数对误差的影响?我们定义一个敏感度:当参数$w_i$在某个很小的范围内变动时,误差变动了多少,数学表示为 $\frac{\Delta L }{\Delta w_i}$。考虑一般情况,即微分$\frac{\partial L}{\partial w_i}$,其中L表示损失函数(即误差),$\Delta L,\partial L$均表示因为参数变化而引起的损失函数的微小变化。

  这样我们就有了基础的微分表达式,也是反向传播所有推导公式的基础,其实$\frac{\Delta L }{\Delta w_i}$很有意思,因为不管最终L(w)是什么样子,$\frac{\Delta L }{\Delta w_i}$=定值。所以,假设$\Delta w_i$>0,那么该定值为负数的情况下,$w_i$增大的方向上,$L(w_i)$将减少,而该定值为正数时,$w_i$增大的方向上,$L(w_i)$将增大。

  梯度下降的更新算法有:$w:=w-\eta \frac{\partial L}{\partial w_i}$,可以结合下图进行理解。所谓梯度,其本意是一个向量(矢量),表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。下图中,$J(\theta _0,\theta _1)$表示损失函数,$\theta_0和\theta_1$表示两个参数,利用梯度下降法对$J(\theta _0,\theta _1)$优化取最小值相当于从起始点开始总是沿着梯度最大的反方向(反方向用负号表示)移动一定的距离,移动距离的大小由学习率决定,正如图中黑色折线代表的路径,一步一步达到$J(\theta _0,\theta _1)$的最小值或局部最小值。

image-20220616172310066

2、反向传播算法参数学习的推导

  这里依然使用如下图所示的神经网络进行计算和推到。这个简单的神经网络图有助于理解反向传播算法的构建过程。虽然与真实的神经网络有一定的差距,但分析过程是大同小异的。

image-20220616171318385

由图可知:

$$ z_1=w_1x\\ z_2=w_2x\\ h_1=\frac{1}{1+e^{-z_1}}\\ h_2=\frac{1}{1+e^{-z_2}}\\ z_3=w_3h_1+w_4h_2\\ y=\frac{1}{1+e^{-z_3}} $$

  假设已知输入x,我们就能根据这一系列公式求得y。接下来,我们需要定义损失函数,使用平方误差函数(只针对一次输入):

$$ L=\frac{1}{2}(y-t)^2 $$

  式中,t表示真实值,y表示预测值,根据前面的介绍,模型训练实际上是更新$w_i$,既然要更新$w_i$,就需要求解$\frac{\partial L}{\partial w_i}$。于是,对于$w_i$,根据链式求导法则,可以求得:

$$ \frac{\partial L}{\partial w_1} =\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3} \frac{\partial z_3}{\partial h_1} \frac{\partial h_1}{\partial z_1} \frac{\partial z_1}{\partial w_1} $$

  我们再求$w_3$:

$$ \frac{\partial L}{\partial w_3} =\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3} \frac{\partial z_3}{\partial w_3} $$

  从中我们可以看到一些模式(规律)。实际上,对于$w_1$的更新,在它相关的路径上,每条边的后继和前继节点对应的就是偏导的分子和分母。$w_3$同样如此,它的相关边有三条(最后y指向L的关系边没有画出来),对应的链式法则也恰好有三个偏导。

  继续细化上述公式,目前来看,这与反向传播似乎没有什么关系。的确,根据这些性质还不足以引出反向传播,让我们继续往下看。

  因为偏导数中的每个函数映射都是确定的(函数已经确定),所以我们可以求出所有偏导数,于是有:

$$ \frac{\partial L}{\partial w_1} =(y-t)\cdot y\cdot(1-y)\cdot w_3\cdot h_1\cdot (1-h_1)\cdot x $$

  式中,x,t由样本给定,而$y,h_1,w_3$都在计算y时能够得到,这就意味着所有变量都是已知的,可以直接求出$\frac{\partial L}{\partial w_1}$。那怎么会有前向和反向“传播”呢?

  宏观上,可以考虑一个非常大型的神经网络,它的参数$w_i$可能有成千上万个,对于每个参数我们都要列处一个偏导公式吗?这显然不现实。因此,我们需要进一步挖掘它们共同的模式。

  继续看下图:

image-20220616182103724

  假设我们加入第二个特征$x_2$,那么对应的$w_5$的更新,我们有如下公式:

$$ \frac{\partial L}{\partial w_5} =\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3} \frac{\partial z_3}{\partial h_1} \frac{\partial h_1}{\partial z_1} \frac{\partial z_1}{\partial w_5} $$

  对比一下$w_1$:

$$ \frac{\partial L}{\partial w_1} =\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3} \frac{\partial z_3}{\partial h_1} \frac{\partial h_1}{\partial z_1} \frac{\partial z_1}{\partial w_1} $$

  实际上,只有最后一个分母发生了变化。我们刚才也总结出了一个重要结论,每个偏导代表一条边,所以对于$w_5$的更新,前面四个偏导值都需要重新计算一遍,也就是虚线指出的部分,为了计算$w_5$,需要重新走过$w_1$的部分路径。

  即使我们用输入$(x_1,x_2)$求出了每个节点(如$z_1,h_1,z_2,h_2,z_3,y$)的值,为了求出每个$w_i$的偏导,需要多次代入这些变量,于是产生了大量的冗余。

  另外,对于每个$w_i$搜使用手工求偏导实在是太复杂了。事实上,在上面例子计算偏导的过程中,如果有中间变量

$$ \delta _j=\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3} \frac{\partial z_3}{\partial h_1} \frac{\partial h_1}{\partial z_1} $$

  那么计算$w_1$和$w_5$时,只要有对应的$\delta _j\cdot \frac{\partial z_1}{\partial w_1}$和$\delta _j\cdot \frac{\partial z_1}{\partial w_5}$,对于中间的子状态只需要计算一次,而不是指数型增长。这大大减少了重复计算,降低了计算的成本。

  这和递归记忆化搜索(自顶向下)以及动态规划(自底向上)的两种对偶形式很像,为了解决重复子问题,我们可以采用反向传播。如果能够定义出合适的子状态,且得出递推式,那么工作就完成了。

  再来对比下$w_1$和$w_3$的偏导,继续寻找规律:

$$ \frac{\partial L}{\partial w_1} =\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3} \frac{\partial z_3}{\partial h_1} \frac{\partial h_1}{\partial z_1} \frac{\partial z_1}{\partial w_1}\\ \frac{\partial L}{\partial w_3} =\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3} \frac{\partial z_3}{\partial w_3} $$

  这两个式子中,只有前两部分是一样的,所以可以令$\delta ^1=\frac{\partial L}{\partial y} \frac{\partial y}{\partial z_3}$,这样处理的好处在于,求$w_3$时,可以有:

$$ \frac{\partial L}{\partial w_3}=\delta ^1\frac{\partial z_3}{\partial w_3} $$

  求$w_1$时,可以有:

$$ \frac{\partial L}{\partial w_1} = \delta ^1\frac{\partial z_3}{\partial h_1} \frac{\partial h_1}{\partial z_1} \frac{\partial z_1}{\partial w_1} $$

  综合图来理解,$\delta ^1$表示聚集在$z_3$的误差,为什么是$z_3$?因为在这里刚好可以求出$w_3$的偏导;结合公式理解,就是公式中的公共部分(重复子问题)。

  我们可以同样定义第二层的误差$\delta_1^2$表示聚集在$z_1$的误差,$\delta_2^2$表示聚集在$z_2$的误差。所以有:

$$ \delta_1^2=\delta^1\frac{\partial z_3}{\partial h_1} \frac{\partial h_1}{\partial z_1}=\delta^1\cdot w_3\cdot \frac{h_1}{z_1} $$

  对应地,$w_1$的偏导公式可以有:

$$ \frac{\partial L}{\partial w_1}=\delta_1^2\frac{\partial z_1}{\partial w_1} $$

  对比$w_1,w_5,w_3$,可以得到:

$$ \frac{\partial L}{\partial w_1}=\delta_1^2\frac{\partial z_1}{\partial w_1}\\ \frac{\partial L}{\partial w_5}=\delta_1^2\frac{\partial z_1}{\partial w_5}\\ \frac{\partial L}{\partial w_3}=\delta_1\frac{\partial z_3}{\partial w_3} $$

  它们都属于同一种形式,而$\delta^2$是由$\delta^1$加上对应的$w_i$求得,所以我们首要的目标是求出最后一层的$\delta ^1$,接着就能根据前一层的权值$w_i$求出前一层每个节点的$\delta^2$。更新公式都一样,用$\delta^2$乘以上一层的输出值而已,因为$y_1=h_1w_1+h_2w_2$是线性的,求偏导$h_1$得到$w_1$,求偏导$w_1$得到$h_1$。

  至此,离真正的反向传播推导出的公式还差一点,继续看下图:

在这里插入图片描述

  我们按照关系边的概念,可以知道$w_5$的关系边应该由虚线的边组成。所以$\delta^2$的更新不止和$z_3$有关系,还和$z_4$有关。此时损失函数由两部分组成,对应一个输入样例$(x_1,x_2)$,有:

$$ L=\frac{1}{2}(y_1-t_1)^2+ \frac{1}{2}(y_2-t_2)^2 $$

  所以对L求偏导,由加法法则可以得到$\frac{\partial L}{\partial w_5}= \frac{\partial L}{\partial y_1}+ \frac{\partial L}{\partial y_2}$,即多个节点指向同一个节点时,把它们的偏导值加起来即可(损失函数就这么定义)。故

$$ \delta _j^2=\frac{\partial h_j}{\partial z_j} \sum w_{ij}\cdot \delta ^1_i $$

3、反向传播算法参数更新案例

  如下图所示的三层神经网络,其激活函数为sigmoid函数,下面以这个简单的三层神经元为例,计算反向传播算法。

image-20220616185507712

  神经网络输入、权重及偏置项初始值

image-20220616185536671

神经元前向传播(这个比较简单,这里不过多介绍了,就是每个节点加权求和,在带入激活函数)

image-20220616185643203

image-20220616185552415

  根据前面关于反向传播算法的简单推到,结合实例,可以进一步推出这个神经网络的反向传播公式如下:

$$ Err_o=O_j(1-O_j)(T_j-O_j)\\ Err_j=O_j(1-O_j)\sum_{k}^{}Err_kw_{jk} $$

  其中$Err_O$表示输出层的误差,$Err_j$表示中间隐藏层的误差,$O_j$表示当前神经元的输出值,$T_j$表示该数据样本的真实值(即标签)。应当明确,==反向传播的目的是调整神经网络的权重和偏置,让模型学习到数据中的规律,因此,计算误差只是中间环节,最重要的是权重的更新==,如下式所示:

$$ w_{ij}=w_{ij}+\lambda Err_jO_i\\ t_j=t_j+\lambda Err_j $$

  其中,$w_{ij}$为权重,$t_j$为偏置,$\lambda$为学习率。

3.1 反向传播的具体计算步骤

3.1.1 计算输出层的误差

image-20220616190537227

$$ Err_6=O_6(1-O_6)(T_j-O_6)=0.474*(1-0.474)*(1-0.474)=0.1311 $$

3.1.2 计算隐藏层误差

image-20220616190705860

$$ Err_4=O_4(1-O_4)Err_6w_{46}=0.332*(1-0.332)*0.1311*(-0.3)=-0.0087 $$

image-20220616190917060

$$ Err_5=O_5(1-O_5)Err_6w_{56}=0.525*(1-0.525)*0.1311*(-0.2)=-0.0065 $$

3.1.3 根据神经元误差,更新神经元间偏置和神经元间的连接权重。

image-20220616191205913

$$ w_{46}=w_{46}+\lambda Err_6O_4=-0.3+0.9*0.1311*0.332=-0.261 $$

image-20220616191347199

$$ w_{56}=w_{56}+\lambda Err_6O_5=-0.2+0.9*0.1311*0.525=-0.138 $$

3.1.4 进一步后向传播

image-20220616191514485

$$ w_{35}=w_{35}+\lambda Err_5O_3=0.2+0.9*(-0.0065)*1=0.194 $$

  按照相同的方法进一步计算其他参数更新后的值,如下表所示:

image-20220616191653151

  上述就是反向传播算法的实例。该三层神经网络虽然简单,但是反向传播的原理同样适用于更复杂的网络。

4、实战:神经网络分类器

  数据集是印第安人糖尿病数据集,利用MLPClassifier函数制作神经网络,实现糖尿病数据集分类

# 神经网络分类器
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd
data_url="pima-indians-diabetes.csv"
df=pd.read_csv(data_url)
display(df)

image-20220616191948319

X=df.iloc[:,0:8]
y=df.iloc[:,8]
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=0)

clf=MLPClassifier(solver='sgd',alpha=1e-5,hidden_layer_sizes=(5,2),random_state=1)
clf.fit(X_train,y_train)

print('训练集准确率:',accuracy_score(y_train,clf.predict(X_train)))
print('测试集准确率:',accuracy_score(y_test,clf.predict(X_test)))

image-20220616192017616

只是简单演示算法,并没有过多的输出模型评估指标。
目录
相关文章
|
29天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于BP神经网络的苦瓜生长含水量预测模型matlab仿真
本项目展示了基于BP神经网络的苦瓜生长含水量预测模型,通过温度(T)、风速(v)、模型厚度(h)等输入特征,预测苦瓜的含水量。采用Matlab2022a开发,核心代码附带中文注释及操作视频。模型利用BP神经网络的非线性映射能力,对试验数据进行训练,实现对未知样本含水量变化规律的预测,为干燥过程的理论研究提供支持。
|
29天前
|
机器学习/深度学习 算法 5G
基于BP神经网络的CoSaMP信道估计算法matlab性能仿真,对比LS,OMP,MOMP,CoSaMP
本文介绍了基于Matlab 2022a的几种信道估计算法仿真,包括LS、OMP、NOMP、CoSaMP及改进的BP神经网络CoSaMP算法。各算法针对毫米波MIMO信道进行了性能评估,通过对比不同信噪比下的均方误差(MSE),展示了各自的优势与局限性。其中,BP神经网络改进的CoSaMP算法在低信噪比条件下表现尤为突出,能够有效提高信道估计精度。
35 2
|
3月前
|
机器学习/深度学习 前端开发 数据挖掘
基于Python Django的房价数据分析平台,包括大屏和后台数据管理,有线性、向量机、梯度提升树、bp神经网络等模型
本文介绍了一个基于Python Django框架开发的房价数据分析平台,该平台集成了多种机器学习模型,包括线性回归、SVM、GBDT和BP神经网络,用于房价预测和市场分析,同时提供了前端大屏展示和后台数据管理功能。
|
4月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于负相关误差函数的4集成BP神经网络matlab建模与仿真
**算法预览:** 图像显示无水印的2022a版MATLAB运行结果 **软件版本:** MATLAB 2022a **核心代码片段:** 省略展示 **理论概述:** NCL集成BP网络利用负相关提升泛化,结合多个弱模型减少错误关联。通过λ参数控制模型间负相关程度,λ>0增强集成效果,提高预测准确性和系统稳健性。
|
4月前
|
机器学习/深度学习 数据采集 监控
Python基于BP神经网络算法实现家用热水器用户行为分析与事件识别
Python基于BP神经网络算法实现家用热水器用户行为分析与事件识别
|
5月前
|
机器学习/深度学习 算法 数据可视化
基于BP神经网络的64QAM解调算法matlab性能仿真
**算法预览图省略** MATLAB 2022A版中,运用BP神经网络进行64QAM解调。64QAM通过6比特映射至64复数符号,提高数据速率。BP网络作为非线性解调器,学习失真信号到比特的映射,对抗信道噪声和多径效应。网络在处理非线性失真和复杂情况时展现高适应性和鲁棒性。核心代码部分未显示。
|
4月前
|
机器学习/深度学习 人工智能 算法
|
5月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】26.卷积神经网络之AlexNet模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】26.卷积神经网络之AlexNet模型介绍及其Pytorch实现【含完整代码】
|
5月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】
|
3月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch代码实现神经网络
这段代码示例展示了如何在PyTorch中构建一个基础的卷积神经网络(CNN)。该网络包括两个卷积层,分别用于提取图像特征,每个卷积层后跟一个池化层以降低空间维度;之后是三个全连接层,用于分类输出。此结构适用于图像识别任务,并可根据具体应用调整参数与层数。
下一篇
无影云桌面