本文学习笔记是自己的理解,如有错误的地方,请大家指正批评,共同进步,谢谢!
之前的教学质量评价,只是通过对教学指标的简单处理,如求平均值或人为的给出各指标的权值来加权求和,其评价结果带有很大主观性。利用BP神经网络建立教学质量评价系统的模型,通过调查分析得到教学评价指标,将其标量化成确定的数据作为其输入,用BP神经网络训练后作为实际输出,将之前得到的教学效果作为期望输出。比较期望输出与实际输出的误差。当误差达到期望的最小值时,认为训练成功。训练成功后可以得到比较准确的权值和阈值,用训练成功后的网络处理另一组新得到的教学评价指标,得到教学质量评价结果。该方法用于教学质量评价中,既克服了专家在评价过程中的主观因素,又得到了满意的评价结果,具有广泛的适用性。
入层反传,周而复始,直至误差达到期望最小,认为网络训练成功。之后就可以利用训练好的网络处理新的教学质量指标,得到准确的教学质量评价结果。
BP神经网络逻辑结构图如下:
(2) 输出层神经元个数的确定
我们将评价结果作为网络的输出, 输出层个数m=1
(3) 网络隐含层数的确定
隐含层可以是一层也可以是多层,根据之前的理论证明,在对教学质量评价模型中, 我们选择隐含层为1层
(4) 隐含层神经元个数的确定
一般情况下, 隐含层神经元个数是根据网络收敛性能的好坏来确定的。隐含层神经元个数过少可能训练不出网络或者网络不够强壮, 但隐含层神经元个数过多, 又会使学习时间过长, 误差也不一定最佳, 因此存在一个如何确定合适的隐含层神经元个数的问题。一般可以采用试凑法, 通过比较网络输出值与期望输出值之间的误差,来确定隐层神经元个数。在本文中我们根据相关经验初定隐含层神经元个数s=8.
之后将所有评价指标数据及之前得到的比较完善的教学质量评价结果输入网络,对网络进行训练。我们取学习率=0.5,定误差最小值为=0.00001。训练结束后,得到合适的权值阈值,用此权值阈值对之后再调查得到的评价指标进行处理,得到合适的教学质量评价结果。
将如上8个样本的10个教学指标保存在txt文档中,把数据读入网络的输入层,经过5116次网络训练达到设定好的误差最小值,得到修改好的权值和阈值。并用训练好的网络处理新数据(5.5 7.5 4 5 8 4.5 7 8 8.5 6),得到实际输出教学质量(6.901607)。
BP神经网络模型由于其具有高度非线性函数映射功能及自适应、自学习能力,可以有效克服传统教学质量评价方法的缺陷,降低传统评价方法中指标权重确定的人为影响因素,而且精度较高。经过上述训练,我们发现BP神经网络模型的输出值与真实值之间的误差比较小,性能完全可以满足实际应用的要求。另外,网络的输出精度取决于输入的训练样本的数量,训练样本的数量越多,其输出的教学效果评估值就越接近于实际的评估值。
总之, 运用BP神经网络建立教学质量评价模型, 可以为各学校教学管理部门寻求科学的教学质量评估解决方案提供有益的参考。
// bp.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "stdlib.h"
#include "stdio.h"
#include "math.h"
#include "conio.h"
#include "time.h"
#define X 8 //样本个数
#define X1 10 //输入层神经元个数
#define X2 8 //隐层神经元个数
#define X3 1 //输出层神经元个数
#define Y 20 //权值调整次数
double w1[X2][X1];//输入层到隐层的权值
double w2[X3][X2];//隐层到输出层的权值
double y[X2];//输入层到隐层的阈值
double y2[X3];//隐层到输出层的阈值
double p[X1];//样本的再次赋值,以便后面方便引用
double t[X3];//样本的再次赋值,以便后面方便引用
double t1[X3];
double yci[X2];//隐层的输入值
double yco[X2];//隐层的输出值
double sci[X3];//输出层的输入值
double sco[X3];//输出层的输出值
double em[X];//第k个样本的总误差
double dao1[X3];//利用梯度下降法对输出层计算输出值的求导
double dao2[X2];//利用梯度下降法对隐层计算输出值的求导:dao2=求导(yco)*求和(dao1*误差e*权值w2)
double zsco[X3];
double l1;//隐层到输出层的学习因子
double l2;//输入层到隐层的学习因子
char c=' ';
FILE *fp;
//存放样本数据的结构体
struct xuexishuju
{
double shuru[X1];//输入神经元的数据
double qiwangshuchu[X3];//期望输出的数据
}xuexishuju[X];
//存放每次调整的权值的结构体
struct quanzhi
{
double qz1[X2][X1];//输入层到隐层的权值
double qz2[X3][X2];//隐层到输出层的权值
}quanzhi[Y];
struct yuzhi
{
double yz1[X2];//输入层到隐层的阈值
double yz2[X3];//隐层到输出层的阈值
}yuzhi[Y];
//从样本中获取数据
int huoqushuju()
{
int i=0;
int j=0;
int k=0;
double data;
int m=0;//X值变化时,m,n对应的程序也要变化
int n=0;
//if(fp=fopen("D:\\BP Neural Network\\输入数据.txt","+")==NULL)//打开文件//不能放在if里面???
//{
// printf("对不起!文件打不开!");
// getch();//屏幕暂停,等待键盘时间
// exit(1);
//}
fp=fopen("输入数据.txt","r");
if(fp==NULL)//打开文件
{
printf("对不起!文件打不开!");
getch();//屏幕暂停,等待键盘时间
exit(1);
}
while(fscanf(fp,"%lf",&data)!=EOF)//把数据一次传给data
{
j++;
if(j<=(X*X1))
{
if(i<X1)
{
xuexishuju[k].shuru[i]=data;
}
if(k==(X-1)&&i==(X1-1))
{
k=0;
i=-1;
}
if(i==(X1-1))
{
k++;
i=-1;
}
}
else if((j>X*X1)&&(j<=(X*X1+X*X3)))
{
if(i<X3)
{
xuexishuju[k].qiwangshuchu[i]=data;
}
if(k==(X-1)&&i==(X3-1))
{
k=0;
i=-1;
}
if(i==(X3-1))
{
k++;
i=-1;
}
}
i++;
}
fclose(fp);
printf("\n样本数据输入成功!");
printf("\n样本数据如下:");
for(k=0;k<X;k++)
{
for(i=0;i<X1;i++)
{
printf("\n学习数据[%d]的输入数据[%d]=%f",k,i,xuexishuju[k].shuru[i]);
}
for(j=0;j<X3;j++)
{
printf("\n学习数据[%d]的期望数据[%d]=%f",k,j,xuexishuju[k].qiwangshuchu[j]);
}
}
printf("\n开始计算...\n");
getch();
return 1;
}
//初始化首次的权值、阈值
int chushihuaquanyu()
{
int a1,a2,a3,a4,a5,a6;
//开始时输入层到隐层的权值的初始化
for(a1=0;a1<X2;a1++)
{
for(a2=0;a2<X1;a2++)
{
w1[a1][a2]=(double)((rand()/32767.0)*2-1);//用随机函数产生-1~1之间的随机数据,作为初始权值
printf("输入层到隐层初始权值w1[%d][%d]=%f\n",a1,a2,w1[a1][a2]);
}
}
//开始时隐层到输出层的权值的初始化
for(a3=0;a3<X3;a3++)
{
for(a4=0;a4<X2;a4++)
{
w2[a3][a4]=(double)((rand()/32767.0)*2-1);//用随机函数产生-1~1之间的随机数据,作为初始权值
printf("隐层到输出层初始权值w2[%d][%d]=%f\n",a3,a4,w2[a3][a4]);
}
}
//开始时输入层到隐层的阈值的初始化
for(a5=0;a5<X2;a5++)
{
y[a5]=(double)((rand()/32767.0)*2-1);//用随机函数产生-1~1之间的随机数据,作为初始阈值
printf("输入层到隐层初始阈值y[%d]=%f\n",a5,y[a5]);
}
//开始时隐层到输出层的阈值的初始化
for(a6=0;a6<X3;a6++)
{
y2[a6]=(double)((rand()/32767.0)*2-1);//用随机函数产生-1~1之间的随机数据,作为初始阈值
printf("隐层到输出层初始阈值y2[%d]=%f\n",a6,y2[a6]);
}
return 1;
}
//样本的再次赋值,以便后面方便引用
int zaishurup(int k)
{
for(int i=0;i<X1;i++)
{
p[i]=xuexishuju[k].shuru[i];
//printf("p[%d]=%f\n",i,p[i]);
}
return 1;
}
int zaishurut(int k)
{
for(int j=0;j<X3;j++)
{
t1[j]=xuexishuju[k].qiwangshuchu[j];
t[j]=1.0/(1.0+exp(-t1[j]));
//printf("t[%d]=%f\n",j,t[j]);
}
return 1;
}
//输入层到隐层的加权求和
int ru_yin_quan()
{
double sum;
for(int j=0;j<X2;j++)
{
sum=0.0;
for(int i=0;i<X1;i++)
{
sum+=w1[j][i]*p[i];//输入层到隐层的加权求和
}
yci[j]=sum-y[j];//隐层的输入值
yco[j]=1.0/(1.0+exp(-yci[j]));//隐层的输出值,用sigmod函数进行处理的
}
return 1;
}
//隐层到输出层的加权求和
int yin_chu_quan()
{
double sum;
for(int j=0;j<X3;j++)
{
sum=0.0;
for(int i=0;i<X2;i++)
{
sum+=w2[j][i]*yci[i];//隐层到输出层的加权求和
}
sci[j]=sum-y2[j];//输出层的输入值
sco[j]=1.0/(1.0+exp(-sci[j]));//输出层的输出值,用sigmod函数进行处理的
}
return 1;
}
//求总误差
int wc_chu_yin(int k)
{
double e[X3];
double fange=0.0;
for(int j=0;j<X3;j++)
{
e[j]=t[j]-sco[j];
fange+=(e[j])*(e[j]);
dao1[j]=sco[j]*(1-sco[j])*e[j];//求导
em[k]=fange/2;
}
return 1;
}
int wc_yin_ru()
{
double summ;
for(int i=0;i<X2;i++)
{
summ=0.0;
for(int j=0;j<X3;j++)
{
summ+=dao1[j]*w2[j][i];
}
dao2[i]=summ*yco[i]*(1-yco[i]);
}
return 1;
}
//将每次变化后的权值赋值到结构体中,以便下次学习算法的调用
int baocunw(int k)
{
for(int i=0;i<X2;i++)
{
for(int j=0;j<X1;j++)
{
quanzhi[k].qz1[i][j]=w1[i][j];
}
}
for(int ii=0;ii<X3;ii++)
{
for(int jj=0;jj<X2;jj++)
{
quanzhi[k].qz2[ii][jj]=w2[ii][jj];
}
}
return 1;
}
//将每次变化后的阈值赋值到结构体中,以便下次学习算法的调用
int baocuny(int k)
{
for(int i=0;i<X2;i++)
{
yuzhi[k].yz1[i]=y[i];
}
for(int j=0;j<X3;j++)
{
yuzhi[k].yz2[j]=y2[j];
}
return 1;
}
//求变化后的输出层到隐层的新权值、阈值
int xin_chu_yin()
{
for(int k=0;k<X3;k++)
{
for(int j=0;j<X2;j++)
{
w2[k][j]=w2[k][j]-l1*dao1[k]*yco[j];//变化后的新权值
}
y2[k]=y2[k]-l1*dao1[k];//变化后的新阈值
}
return 1;
}
//求变化后的隐层到输入层的新权值、阈值
int xin_yin_ru()
{
for(int j=0;j<X2;j++)
{
for(int i=0;i<X1;i++)
{
w1[j][i]=w2[j][i]-l2*dao2[j]*p[i];
}
y[j]=y[j]-l2*dao2[j];
}
return 1;
}
//保存最后一次正确的权值阈值到txt文件
void baocunquan()
{
FILE *fp;
fp=fopen("保存权值.txt","w");
if(fp==NULL)
{
printf("对不起!文件打不开!\n");
getch();
exit(1);
}
fprintf(fp,"保存的最后一次正确的权值数据如下:\n");
fprintf(fp,"输入层到隐层的权值数据:\n");
for(int i=0;i<X2;i++)
{
for(int j=0;j<X1;j++)
{
fprintf(fp,"w1[%d][%d]=%f\n",i,j,w1[i][j]);
}
}
fprintf(fp,"\n");
fprintf(fp,"隐层到输出层的权值数据:\n");
for(int ii=0;ii<X3;ii++)
{
for(int jj=0;jj<X2;jj++)
{
fprintf(fp,"w2[%d][%d]=%f\n",ii,jj,w2[ii][jj]);
}
}
fprintf(fp,"\n");
fclose(fp);
printf("最后一次权值保存成功!\n");
getch();
}
void baocunyu()
{
FILE *fp;
fp=fopen("保存阈值.txt","w");
if(fp==NULL)
{
printf("对不起!文件打不开!\n");
getch();
exit(1);
}
fprintf(fp,"保存的最后一次正确的阈值数据如下:\n");
fprintf(fp,"输入层到隐层的阈值值数据:\n");
for(int i=0;i<X2;i++)
{
fprintf(fp,"y[%d]=%f\n",i,y[i]);
}
fprintf(fp,"\n");
fprintf(fp,"隐层到输出层的阈值数据:\n");
for(int j=0;j<X3;j++)
{
fprintf(fp,"y2[%d]=%f\n",j,y2[j]);
}
fprintf(fp,"\n");
fclose(fp);
printf("最后一次阈值保存成功!\n");
getch();
}
void main()
{
double wc1=0.00001;//设定好的误差最大值
double wc2;//计算实际误差
int s1=20000;//设定好的误差学习次数最大值
int s2=0;//实际误差学习次数
l1=0.5;//给学习因子赋个值
l2=0.5;
huoqushuju();//从样本中获取数据
chushihuaquanyu();//初始化首次的权值、阈值(利用随机函数产生)
do
{
int k;
++s2;
wc2=0;
for(k=0;k<X;k++)
{
zaishurup(k);//样本的再次赋值
zaishurut(k);
ru_yin_quan();//输入层到隐层的加权求和
yin_chu_quan();//隐层到输出层的加权求和
wc_chu_yin(k);//求总误差
wc_yin_ru();
baocunw(k);//将每次变化后的权值赋值到结构体中,以便下次学习算法的调用
baocuny(k);//将每次变化后的阈值赋值到结构体中,以便下次学习算法的调用
xin_chu_yin();//求变化后的输出层到隐层的新权值、阈值
xin_yin_ru();//求变化后的隐层到输入层的新权值、阈值
wc2+=em[k];//把m个样本的总误差加起来
}
printf("第%d次计算误差=%f\t",s2,wc2);
printf("设定误差=%f\n",wc1);
if(s2>s1)
{
printf("计算次数已经超过20000次,敲任意键退出循环!\n");
getch();
break;
}
}while(wc2>wc1);
printf("一共训练了%d次!\n",s2);
baocunquan();//保存最后一次正确的权值到txt文件
baocunyu();//保存最后一次正确的阈值到txt文件
printf("神经网络已经训练好\n");
printf("请利用训练好的网络的权值和阈值对新一组教学指标数据进行求解!\n");
printf("请输入新一组教学指标数据:\n");
double sc[X1];
for(int a=0;a<X1;a++)
{
scanf("%lf",&sc[a]);
}
double sum1,sum2;
for(int j=0;j<X2;j++)
{
sum1=0.0;
for(int i=0;i<X1;i++)
{
sum1+=w1[j][i]*sc[i];//输入层到隐层的加权求和
}
yci[j]=sum1-y[j];//隐层的输入值
yco[j]=1.0/(1.0+exp(-yci[j]));//隐层的输出值,用sigmod函数进行处理的
}
for(int jj=0;jj<X3;jj++)
{
sum2=0.0;
for(int ii=0;ii<X2;ii++)
{
sum2+=w2[jj][ii]*yci[ii];//隐层到输出层的加权求和
}
sci[jj]=sum2-y2[jj];//输出层的输入值
sco[jj]=1.0/(1.0+exp(-sci[jj]));//输出层的输出值,用sigmod函数进行处理的
}
for(int b=0;b<X3;b++)
{
zsco[b]=log(sco[b])-log(1-sco[b])-2;
printf("新指标数据评价得到的教学质量结果:%f\n",zsco[b]);
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/qustqustjay/article/details/46859035