长 春 理 工 大 学 实 习 报 告.docx
《长 春 理 工 大 学 实 习 报 告.docx》由会员分享,可在线阅读,更多相关《长 春 理 工 大 学 实 习 报 告.docx(23页珍藏版)》请在冰点文库上搜索。
长春理工大学实习报告
长春理工大学
学生实习报告
_________2013_________~_________2014_________学年第_________2_________学期
计算机
实习类别________________________________________
计算机科学技术
学院________________________________________
计算机科学与技术
专业________________________________________
学号________________________________________
米丹丹
姓名________________________________________
起始周
第17周
周数
1周
实习地点
东三教912
目的:
BP算法,即误差反向传播(ErrorBackPropagation,BP)算法。
BP算法的基本思想是,学习过程由信号的正向传播与误差的反向传播两个过程组成。
1)正向传播:
输入样本->输入层->各隐层(处理)->输出层
2)误差反向传播:
输出误差(某种形式)->隐层(逐层)->输入层
通过收集资料、学习、编码、运行和修改,进一步掌握BP算法的精髓与用途,从而找到更优的算法来解决误差反向传播问题。
要求:
(1)具备一定的学习能力和做事认真的态度
(2)具备一定的编码基础
(3)掌握BP算法的基本思想
(4)含有隐层的多层前馈网络能大大提高神经网络的分类能力,用BP算法解决权值调整问题
(5)用编码实现BP算法
(6)对代码进行优化、测试,实现最优
进度安排及内容:
1)初始化
2)输入训练样本对,计算各层输出
3)计算网络输出误差
4)计算各层误差信号
5)调整各层权值
6)检查网络总误差是否达到精度要求,满足,则训练结束;不满足,则返回步骤2)
成绩:
指导教师评语(从学生出勤、学习态度、纪律、实习效果、实习报告数据和图样完整性、书定工整等方面给出定性和定量的评价):
指导教师签字:
年月日
长春理工大学实习报告
BP简介:
BP算法,误差反向传播(ErrorBackPropagation,BP)算法。
BP算法的基本思想是,学习过程由信号的正向传播与误差的反向传播两个过程组成。
由于多层前馈网络的训练经常采用误差反向传播算法,人们也常把将多层前馈网络直接称为BP网络。
1)正向传播:
输入样本->输入层->各隐层(处理)->输出层
注1:
若输出层实际输出与期望输出(教师信号)不符,则转入2)(误差反向传播过程)
2)误差反向传播:
输出误差(某种形式)->隐层(逐层)->输入层
其主要目的是通过将输出误差反传,将误差分摊给各层所有单元,从而获得各层单元的误差信号,进而修正各单元的权值(其过程,是一个权值调整的过程)。
注2:
权值调整的过程,也就是网络的学习训练过程(学习也就是这么的由来,权值调整)。
在实际应用中,80%~90%的人工神经网络模型是采用误差反传算法或其变化形式的网络模型(简称BP神经网络),目前主要应用于函数逼近、模式识别、分类和数据压缩或数据挖掘。
BP模型:
BP神经网络模型BP网络模型包括其输入输出模型、作用函数模型、误差计算模型和自学习模型。
(1)节点输出模型
隐节点输出模型:
Oj=f(∑Wij×Xi-qj)
(1)
输出节点输出模型:
Yk=f(∑Tjk×Oj-qk)
(2)
f-非线形作用函数;q-神经单元阈值。
(2)作用函数模型
作用函数是反映下层输入对上层节点刺激脉冲强度的函数又称刺激函数,一般取为
长春理工大学实习报告
(0,1)内连续取值Sigmoid函数:
f(x)=1/(1+e)
(3)误差计算模型
误差计算模型是反映神经网络期望输出与计算输出之间误差大小的函数:
tpi-i节点的期望输出值;Opi-i节点计算输出值。
(4)自学习模型
神经网络的学习过程,即连接下层节点和上层节点之间的权重矩阵Wij的设定和误差修正过程。
BP网络有师学习方式-需要设定期望值和无师学习方式-只需输入模式之分。
自学习模型为
△Wij(n+1)=h×Фi×Oj+a×△Wij(n)(5)
h-学习因子;Фi-输出节点i的计算误差;Oj-输出节点j的计算输出;a-动量因子。
BP收敛性:
误差函数是影响收敛速度的首要因素,因为它是权重多维空间的超曲面,该曲面存在着许多大范围的“平坦区”,又存在着大量的局部极小的“沟谷”,从而影响收敛速度,甚至导致
难于收敛。
对误差的计算采用广义的δ规则。
式⑴是误差函数的定义。
⑴
式中dk表示网络的期望输出,ok表示网络实际输出。
在误差反传过程中,对隐含层和输入层权值修改如下:
⑵
其中,w(m+1)和w(m)分别是第m+1次和第m次迭代的连接权值;是第m次迭代的输出误差对权值的梯度向量;负号表示梯度的下降方向;η为学习率,一般η∈(0,1)。
在标准BP算法中,学习率的值是不变的,一般根据经验来选取。
从公式⑵不难看出,学习率的设置对算法的收敛速度和稳定性有很大的影响:
学习率过小,能稳定地收敛,但学习速度慢,往由于训练时间的限制而得不到满意解;学习率过大,学习速度加快,但又会使误差函数值不下降,网络出现摆动现象,导致算法不收敛。
因此,固定的学习率不可能很好地适合学习的全过程。
BP优缺点:
优点:
BP神经网络实质上实现了一个从输入到输出的映射功能,而数学理论已证明它具有实现任
长春理工大学实习报告
何复杂非线性映射的功能,神经网络能以任意精度逼近任何非线性连续函数。
在建模过程中的许多问题正是具有高度的非线性,这使得它特别适合于求解内部机制复杂的问题。
并行分布处理方式,在神经网络中信息是分布储存和并行处理的,这使它具有很强的容错性和很快的处理速度。
它能通过学习带正确答案的实例集自动提取“合理的”求解规则,即具有自学习能力;具有一定的推广、概括能力和自适应能力,神经网络在训练时,能从输入、输出的数据中提取出规律性的知识,记忆于网络的权值中,并具有泛化能力,即将这组权值应用于一般情形的能力。
神经网络的学习也可以在线进行。
数据融合的能力,神经网络可以同时处理定量信息和定性信息,因此它可以利用传统的工程技术(数值运算)和人工智能技术(符号处理)。
多变量系统,神经网络的输入和输出变量的数目是任意的,对单变量系统与多变量系统提供了一种通用的描述方式,不必考虑各子系统间的解耦问题。
不足:
首先,由于学习速率是固定的,因此网络的收敛速度慢,需要较长的训练时间。
对于一些复杂问题,BP算法需要的训练时间可能非常长,这主要是由于学习速率太小造成的,可采用变化的学习速率或自适应的学习速率加以改进。
其次,BP算法可以使权值收敛到某个值,但并不保证其为误差平面的全局最小值,这是因为采用梯度下降法可能产生一个局部最小值。
对于这个问题,可以采用附加动量法来解决。
再次,网络隐含层的层数和单元数的选择尚无理论上的指导,一般是根据经验或者通过反复实验确定。
因此,网络往往存在很大的冗余性,在一定程度上也增加了网络学习的负担。
最后,网络的学习和记忆具有不稳定性。
也就是说,如果增加了学习样本,训练好的网络就需要从头开始训练,对于以前的权值和阈值是没有记忆的。
但是可以将预测、分类或聚类做的比较好的权值保存。
BP算法证明:
I.符号定义
网络结构:
输入层d个神经元,隐含层
个神经元,输出层c个神经元,网络的权值
。
输入训练样本
,期望输出
,网络实际输出
,隐含层神经元输出
,
为神经元的净输出,有:
长春理工大学实习报告
隐含层:
,
,
;
(1)
输出层:
,
,
;
(2)
误差平方和准则函数:
(3)
权值调整公式:
分别计算输出层和隐含层权值的梯度。
II.输出层
应用链式求导法则计算输出层第k个神经元隐含层第j个神经元之间的连接权值梯度:
(4)
再次应用链式求导法则:
根据(3)式,有:
根据
(2)式,有:
因此:
长春理工大学实习报告
根据
(2)式,有:
代入到(4)式,有:
,其中
III.隐含层
应用链式求导法则,计算输入层第i个神经元到隐含层第j个神经元之间连接权值的梯度:
(5)
根据
(1)式,有:
再次应用链式法则:
长春理工大学实习报告
代入(5)式,有:
其中:
IV.权值梯度
输出层:
,
;
隐含层:
,
V.对数Sigmoid激活函数的结果
激活函数为对数Sigmoid函数:
导数为:
因此:
输出层:
隐含层:
参考文献:
[1]张铃,张钹《神经网络中BP算法的分析》[J];《模糊识别与人工智能》;1994年第7卷第3期。
[2]孙佰清,潘启树,冯英浚,张长胜。
提高BP网络训练速度的研究[J]。
哈尔滨工业大学学报,2001.33(4):
339~441。
[3]孙娓娓,刘琼荪。
BP神经网络的联合优化算法[J]。
计算机工程与应用,2009.45(12):
50~51
[4]杨晓帆,陈延槐。
人工神经网络固有的优点和缺点[J];《计算机科学》;1994年第21卷第2期。
长春理工大学实习报告
BP应用实例
#include
#include
usingnamespacestd;
#defineinnode3//输入结点数
#definehidenode10//隐含结点数
#defineoutnode1//输出结点数
#definetrainsample8//BP训练样本数
classBpNet
{
public:
voidtrain(doublep[trainsample][innode],doublet[trainsample][outnode]);//Bp训练
doublep[trainsample][innode];//输入的样本
doublet[trainsample][outnode];//样本要输出的
double*recognize(double*p);//Bp识别
voidwritetrain();//写训练完的权值
voidreadtrain();//读训练好的权值,这使的不用每次去训练了,只要把训练最好的权值存下来就OK
BpNet();
virtual~BpNet();
public:
voidinit();
doublew[innode][hidenode];//隐含结点权值
doublew1[hidenode][outnode];//输出结点权值
doubleb1[hidenode];//隐含结点阀值
doubleb2[outnode];//输出结点阀值
doublerate_w;//权值学习率(输入层-隐含层)
doublerate_w1;//权值学习率(隐含层-输出层)
doublerate_b1;//隐含层阀值学习率
doublerate_b2;//输出层阀值学习率
doublee;//误差计算
doubleerror;//允许的最大误差
doubleresult[outnode];//Bp输出
};
BpNet:
:
BpNet()
{
error=1.0;
e=0.0;
rate_w=0.9;//权值学习率(输入层--隐含层)
rate_w1=0.9;//权值学习率(隐含层--输出层)
rate_b1=0.9;//隐含层阀值学习率
rate_b2=0.9;//输出层阀值学习率
}
BpNet:
:
~BpNet()
{
}
voidwinit(doublew[],intn)//权值初始化
{
for(inti=0;iw[i]=(2.0*(double)rand()/RAND_MAX)-1;
}
voidBpNet:
:
init()
{
winit((double*)w,innode*hidenode);
winit((double*)w1,hidenode*outnode);
winit(b1,hidenode);
winit(b2,outnode);
}
voidBpNet:
:
train(doublep[trainsample][innode],doublet[trainsample][outnode])
{
doublepp[hidenode];//隐含结点的校正误差
doubleqq[outnode];//希望输出值与实际输出值的偏差
doubleyd[outnode];//希望输出值
doublex[innode];//输入向量
doublex1[hidenode];//隐含结点状态值
doublex2[outnode];//输出结点状态值
doubleo1[hidenode];//隐含层激活值
doubleo2[hidenode];//输出层激活值
for(intisamp=0;isamp{
inti=0;
intj=0;
intk=0;
for(i=0;ix[i]=p[isamp][i];//输入的样本
for(i=0;iyd[i]=t[isamp][i];//期望输出的样本
//构造每个样品的输入和输出标准
for(j=0;j{
o1[j]=0.0;
for(i=0;io1[j]=o1[j]+w[i][j]*x[i];//隐含层各单元输入激活值
x1[j]=1.0/(1+exp(-o1[j]-b1[j]));//隐含层各单元的输出
//if(o1[j]+b1[j]>0)x1[j]=1;
//elsex1[j]=0;
}
for(k=0;k{
o2[k]=0.0;
for(j=0;jo2[k]=o2[k]+w1[j][k]*x1[j];//输出层各单元输入激活值
x2[k]=1.0/(1.0+exp(-o2[k]-b2[k]));//输出层各单元输出
//if(o2[k]+b2[k]>0)x2[k]=1;
//elsex2[k]=0;
}
for(k=0;k{
qq[k]=(yd[k]-x2[k])*x2[k]*(1-x2[k]);//希望输出与实际输出的偏差
for(j=0;jw1[j][k]+=rate_w1*qq[k]*x1[j];//下一次的隐含层和输出层之间的新连接权
}
for(j=0;j{
pp[j]=0.0;
for(k=0;kpp[j]=pp[j]+qq[k]*w1[j][k];
pp[j]=pp[j]*x1[j]*(1-x1[j]);//隐含层的校正误差
for(i=0;iw[i][j]+=rate_w*pp[j]*x[i];//下一次的输入层和隐含层之间的新连接权
}
for(k=0;k{
e+=fabs(yd[k]-x2[k])*fabs(yd[k]-x2[k]);//计算均方差
}
error=e/2.0;
for(k=0;kb2[k]=b2[k]+rate_b2*qq[k];//下一次的隐含层和输出层之间的新阈值
for(j=0;jb1[j]=b1[j]+rate_b1*pp[j];//下一次的输入层和隐含层之间的新阈值
}
}
double*BpNet:
:
recognize(double*p)
{
doublex[innode];//输入向量
doublex1[hidenode];//隐含结点状态值
doublex2[outnode];//输出结点状态值
doubleo1[hidenode];//隐含层激活值
doubleo2[hidenode];//输出层激活值
inti=0;
intj=0;
intk=0;
for(i=0;ix[i]=p[i];
for(j=0;j{
o1[j]=0.0;
for(i=0;io1[j]=o1[j]+w[i][j]*x[i];//隐含层各单元激活值
x1[j]=1.0/(1.0+exp(-o1[j]-b1[j]));//隐含层各单元输出
//if(o1[j]+b1[j]>0)x1[j]=1;
//elsex1[j]=0;
}
for(k=0;k{
o2[k]=0.0;
for(j=0;jo2[k]=o2[k]+w1[j][k]*x1[j];//输出层各单元激活值
x2[k]=1.0/(1.0+exp(-o2[k]-b2[k]));//输出层各单元输出
//if(o2[k]+b2[k]>0)x2[k]=1;
//elsex2[k]=0;
}
for(k=0;k{
result[k]=x2[k];
}
returnresult;
}
voidBpNet:
:
writetrain()
{
FILE*stream0;
FILE*stream1;
FILE*stream2;
FILE*stream3;
inti,j;
//隐含结点权值写入
if((stream0=fopen("w.txt","w+"))==NULL)
{
cout<<"创建文件失败!
";
exit
(1);
}
for(i=0;i{
for(j=0;j{
fprintf(stream0,"%f\n",w[i][j]);
}
}
fclose(stream0);
//输出结点权值写入
if((stream1=fopen("w1.txt","w+"))==NULL)
{
cout<<"创建文件失败!
";
exit
(1);
}
for(i=0;i{
for(j=0;j{
fprintf(stream1,"%f\n",w1[i][j]);
}
}
fclose(stream1);
//隐含结点阀值写入
if((stream2=fopen("b1.txt","w+"))==NULL)
{
cout<<"创建文件失败!
";
exit
(1);
}
for(i=0;ifprintf(stream2,"%f\n",b1[i]);
fclose(stream2);
//输出结点阀值写入
if((stream3=fopen("b2.txt","w+"))==NULL)
{
cout<<"创建文件失败!
";
exit
(1);
}
for(i=0;ifprintf(stream3,"%f\n",b2[i]);
fclose(stream3);
}
voidBpNet:
:
readtrain()
{
FILE*stream0;
FILE*stream1;
FILE*stream2;
FILE*stream3;
inti,j;
//隐含结点权值读出
if((stream0=fopen("w.txt","r"))==NULL)
{
cout<<"打开文件失败!
";
exit
(1);
}
floatwx[innode][hidenode];
for(i=0;i{
for(j=0;j{
fscanf(stream0,"%f",&wx[i][j]);
w[i][j]=wx[i][j];
}
}
fclose(stream0);
//输出结点权值读出
if((stream1=fopen("w1.txt","r"))==NULL)
{
cout<<"打开文件失败!
";
exit
(1);
}
floatwx1[hidenode][outnode];
for(i=0;i{
for(j=0;j{
fscanf(stream1,"%f",&wx1[i][j]);
w1[i][j]=wx1[i][j];
}
}
fclose(stream1);
//隐含结点阀值读出
if((stream2=fopen("b1.txt","r"))==NULL)
{
cout<<"打开文件失败!
";
exit
(1);
}
floatxb1[hidenode];
for(i=0;i{
fscanf(stream2,"%f",&xb1[i]);
b1[i]=xb1[i];
}
fclose(stream2);
//输出结点阀值读出
if((stream3=fopen("b2.txt","r"))==NULL)
{
cout<<"打开文件失败!
";
exit
(1);
}
floatxb2[outnode];
for(i=0;i{
fscanf(stream3,"%f",&xb2[i]);
b2[i]=xb2[i];
}
fclose(stream3);
}
//输入样本
doubleX[trainsample][innode]={
{0,0,0},{0,0,1},{0,1