基于C++ 实现 BP 神经网络

♻️ 资源

大小: 2.28MB

➡️ 资源下载:https://download.csdn.net/download/s1t16/87450303

BP 神经网络的实现

实验概述:

1.1 课程设计题目:

本设计题为 BP 神经网络的实现,主要任务是利用 C++ 语言实现 BP 神经网络, 并利用 BP 神经网络解决螨虫分类问题。
1.2 课程设计目的:

主要有这些:

熟悉自己所学的多种数据结构.

理解 BP 神经网络的工作原理

利用 C++ 实现 BP 神经网络

利用 BP 神经网络实现螨虫分类

设定好学习样本个数,取样本个数的训练数据存储于文本文档中,在 C++ main 函数中设定学习效率和步长,读取训练输入和对应的输出进行训练,通过训练得到对应的权值,然后进行数据测试。

一、设计功能:

本课程设计由 3 个主要功能实现,它们分别为初始化数据,训练和测试螨虫分类是否准确。

① 初始化数据:

srand( (unsigned)time( NULL ) );  
    for( int i = 0; i < HN; i ++ )  
	    {  
	        for( int j = 0; j < INnum; j ++ )  
	        {  
	            W[i][j] = double( rand() % 100 ) / 100; //初始化输入层到隐层的权值
        }  
    }  
    for( int ii = 0; ii < ONnum; ii ++ )  
	    {  
	        for( int jj = 0; jj < HN; jj ++ )  
	        {  
	            V[ii][jj] = double( rand() % 100 ) / 100;  //初始化隐层到输出层的权值ֵ  
	        }  
	    }

这段代码是为了初始化输入层到隐层的权值,以及隐层到输出层的权值。

input_sample(int m):这段代码是为了初始化训练数据的输入值。

output_sample(int m):这个函数是为了初始化数据对应的输出值

② 训练:

本功能主要是逐步训练,直至收敛。

calculate_HIDDEN_OUTPUT():本函数主要用于求隐层输出。

calculate_OUTPUT_OUTPUT():本函数主要用于求输出层输出。

inaccuracy_Output_Hidden(int m);本函数主要用于求解输出层到隐层的一般化误差

inaccuracy_Hidden_Input():本函数主要用于求解隐层到输入层的一般化误差。

update_Output_Hidden:本函数主要是用于调整输出层至隐层的权值。

update_Hidden_Input:本函数主要是用于调整隐层至输入层的权值。 saveWeight():本函数主要是用于保存计算出来的权值。

③ 测试分类是否准确:

数据结构:

struct  
    {  
        double input[INnum];  
        double teach[ONnum];  
    }Study_Data[SampleCount];

代表了训练样本;

double Weight_Input[NUM_HIDDEN][mInputNode];

代表了输入层至隐藏层权值;

double Weight_Output[mOutPutNode][NUM_HIDDEN];

代表了隐层至输出层权值;

double Sample_Input[mInputNode];

代表了单个样本输入数据;

double Sample_Output[mOutPutNode];

代表了单个样本期望输出值;

double ORIGIN_W[NUM_HIDDEN][mInputNode];

代表了隐藏层到输入层的旧权数组;

double ORIGIN_V[mOutPutNode][NUM_HIDDEN];

代表了输出层到隐藏层的旧权数组;

double HIDDEN_INPUT[NUM_HIDDEN];

代表了隐层的输入;

double OUTPUT_INPUT[mOutPutNode];

代表了输出层的输入;

double hidenLayerOutput[NUM_HIDDEN];

代表了隐层的输出;

double OUTPUT_OUTPUT[mOutPutNode];

代表了输出层的输出;

double inaccuracy_sample[SampleCount];

代表了第 m 个样本的总误差。
1.3.3 实验环境与工具:
① 操作系统:Windows 企业版 2016 长期服务版;

② 开发工具:Visual Studio 2017 社区版;

③ 开发语言:C++。

实验原理:

1.1 结构构成:

BP 神经网络是一种根据误差逆向传播的多层前馈网络。其由输入层,隐藏层和输出层构成的。它模拟了人脑的神经网络的结构,众所周知,人大脑传递信息的基本单位是神经元,人脑中有大量的神经元,每个神经元与多个神经元相连接,就是这样,构成了人的大脑。人的大脑的神经网络传播是按照一定的规律,不是神经元会对所有传过来的刺激进行反应。首先是积累刺激,而 BP 神经网络,类似于上述,是一种简化的生物模型。每层神经网络都是由神经元构成的,单独的每个神经元相当于一个感知器。输入层是单层结构的,输出层也是单层结构的,而隐藏层可以有多层,也可以是单层的。输入层、隐藏层、输出层之间的神经元都是相互连接的,为全连接。总得来说,BP 神经网络结构就是,输入层得到刺激后,会把他传给隐藏层,至于隐藏层,则会根据神经元相互联系的权重并根据规则把这个刺激传给输出层,输出层对比结果,如果不对,则返回进行调整神经元相互联系的权值。这样就可以进行训练,最终学会,这就是 BP 神经网络模型。

1.2 算法流程:

① 先把统一处理过的训练样本输入到 BP 神经网络。

② 设定步长,学习效率,最大学习次数,生成初始权值,阈值。

③ 计算从输入层开始到输出层结束的各层的输入输出值。

④ 计算输出层的误差,如果误差小于设定误差,便结束。如果大于设定误差,便调整权值和阈值,执行步骤 ③。

1.3 数学原理:

在三层 BP 神经网络中,输入向量,也就是输入层神经元为:

(1)

隐藏层输入向量,也就是隐藏层神经元:

(2)

输出层输出向量,也就是输出层神经元:

(3)

期望输出向量可以表示为:

(4)

输入层到隐藏层之间的权值用数学向量可以表示为

(5)

这里面的列向量

为隐藏层第 j 个神经元对应的权重;隐藏层到输出层之间的权值用数学向量可以表示为:

(6)

式(6)中的列向量

为输出层第 k 个神经元对应的权重。

输入层,隐藏层,输出层之间的数学关系如下所示:

就输出层而言

就隐藏层而言

在上述表达式中,激活函数 f(x)必须为单调函数,我们选取 sigmoid 函数:

(11)

由于 f(x)是连续函数,是可导函数,且

这些就构成了 BP 神经网络的输入层,输出层和隐藏层。

如果 BP 网络的输出结果和期望输出结果不一致时,那么便有了输出误差 E,表达式如下:

(12)

展开到隐藏层,则有如下表达式:

(11)

展开到输入层,则有以下表达式:

(13)

根据这些,我们可以明白,BP 神经网络的输入误差产生是由于输出层到隐藏层的权值和隐藏层到输入层的权值决定,因此调整输出层到隐藏层的权值和隐藏层到输入层的权值可以改变误差 E。

显而易见的,调整输出层到隐藏层的权值和隐藏层到输入层的权值的思想是让这个误差不断缩小这样才能满足我们的要求,因此我们需要让这些权值修改量与误差 E 的负梯度下降量成正比,也就是如下表达式:

式(14)、(15)中常数

反映了学习效率。

综上所述,通过数学原理可以看出,在 BP 学习算法中,输入层,输出层和隐藏层权值调整方式都是一样的。由三个条件决定,它们分别是:学习效率,输入层,输出层和隐藏层的各层误差信号和各层输入信号 X/Y。其中最为重要的是输出层误差信号,它直接意味着和实际期望结果的差异,代表着与我们预期结果的差距,而前面的各层的误差都是从后往前传递计算的误差。

实验结果:

输入初始参数:

正在训练:

训练成功:

测试数据:

值得一提的是,本次课程设计仍然存在一定的不足。本次课程设计中采用的学习效率是一个定值,没有发生过改变。这样的话,在某些地方用函数逼近的时候出现了一些误差。所以,如果能够将这个学习效率能够自动调整,在一开始是一个数值比较大的学习效率,这样可以更快速地接近理想函数,等到快接近理想函数的时候,这个时候的话采用较小的学习效率,这样可以使最后的函数更加准确,这样的话训练时间会缩短,并且训练的效果会更佳。

实验一开始,采取的参数不是很合适,采取了较大的学习效率,这样导致训练失败了,一开始采取的训练次数也较低,最后的结果也是训练失败,因此,学习效率和步长都不可以太大,如果太大,波动也大了,这样的话,发散的概率提高了太多。学习效率和步长也不可以过小,如果过小,训练时间会很长,影响性能。然后预定误差对实验的进行影响也比较大,如果预定误差值过小,则实验最后的效果会出现较大的偏差,如果预定误差值较大,则训练次数和时间会过大。

所以在本次实验中,一定要把握好参数的设定,否则结果会很差。

二、算法分析:

设输入层神经元数量为 n1,隐藏层神经元数量为 n2,输出层神经元数量为 n3。对于一个测试样本进行前馈计算,则需要进行两次矩阵运算,两次向量和矩阵相乘分别,需要进行 n1 n2 和 n2 n3 次计算,由于输入层神经元数量和输出层神经元数量是固定的,只有中间隐藏层的神经元数量是需要自己设定的,因此本算法时间复杂度为 O(n1 n2 + n2 n3) = O(n2)。

对于训练一个神经网络而言,有 k 个样本,每个样本只会被训练一次,所以训练一个神经网络的时间复杂度为 O(k*n2),同理,预测一个样本,时间复杂度是 O(n2)。

对于时间复杂度,因 n1 和 n3 是固定的,即输入层与输出层神经元数量恒定,故仅相关于隐藏层神经元数量, 亦即 O(n2)。又在 n1 和 n3 恒定时,仅有 n2 随输入而波动,可知算法的一系列操作可在 O(1)的空间上完成。

为了加强鲁棒性,在满足精度要求的前提下,取尽可能少的隐层节点数,即本课程设计中的 15 个节点。

三、总结:

① 首先是对隐藏层节点数目的考虑,过多或者过少都不能科学地反映出样本的规律性。如果数量太少,则不能够将训练数据的规律性概括出来。如果数量过多,也不是很好,因为可能会把一些干扰性的并不是规律的内容给记录下来,这样会使得过于准确导致某些数据还是判断失误,而且会使得训练时间变长很多。比较妥当的一个做法就是根据公式计算出一个初始的实验值。

② 至于究竟是选取每输入一个样本就进行权值调整,然后计算误差,或者是输入完所有样本数据之后再进行权值调整,根据本次实验,我得出的结论是如果样本数量多的话,输入完所有样本数据之后再进行权值调整的话能更快得进行收敛.

③ 这次课程设计在 Visual Studio 2017(community)完成了 BP 神经网络实现的编程,明白了 BP 神经网络计算过程分两步,分别是正向计算,反向计算。对于正向传播而言,计算从输入层开始到输出层结束的各层的输入输出值,对于反向传播,便是如果正向计算的输出值不满足预期,便从后往前调整权值,直至最后的数据符合预期要求。

④ 通过本次实验,对 BP 神经网络理解变得非常透彻,熟悉了 BP 神经网络的结构,对人工智能的应用有了一定的认识,也对数据结构的学习印象更深刻,提高了我学习相关知识的兴趣,期间遇到了很多困难,而且编程的实现对我而言比较繁琐,遇到了很多 BUG,但是都一一细心解决了。

⑤ 通过熟悉其数学原理,我深刻理解到了 BP 神经网络已经非常成熟。它的优点是可以解决非线性映射问题。它的网络结构也非常灵活。输入层,输出层和隐藏层的神经元数量可以根据具体的需要而设定。但是它的缺点也存在,比如说它的学习速度比较慢,就本课程设计而言,学了较大次数才能收敛,而且对于初始参数的设定而言,得不到很多的理论指导。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

神仙别闹

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

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

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

打赏作者

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

抵扣说明:

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

余额充值