本文学习笔记是自己的理解,如有错误的地方,请大家指正批评,共同进步,谢谢!
之前的教学质量评价,只是通过对教学指标的简单处理,如求平均值或人为的给出各指标的权值来加权求和,其评价结果带有很大主观性。利用BP神经网络建立教学质量评价系统的模型,通过调查分析得到教学评价指标,将其标量化成确定的数据作为其输入,用BP神经网络训练后作为实际输出,将之前得到的教学效果作为期望输出。比较期望输出与实际输出的误差。当误差达到期望的最小值时,认为训练成功。训练成功后可以得到比较准确的权值和阈值,用训练成功后的网络处理另一组新得到的教学评价指标,得到教学质量评价结果。该方法用于教学质量评价中,既克服了专家在评价过程中的主观因素,又得到了满意的评价结果,具有广泛的适用性。
1、BP神经网络介绍
BP神经网络是加州大学的Rumelhart和Mcclelland提出的一种人工神经网络学习算法,是一种按照误差逆向传播算法训练的神经网络。其学习规则为:使用梯度下降法,通过误差反向传播不断调整网络的权值和阈值,使网络的误差平方和最小。从本质上说,这是一类由大量信息处理单元通过广泛联结而构成的动态信息处理系统。
BP神经网络包括信息的正向传播和误差的反向传播两个过程。信息的正向传播:将教学评价指标各数据通过网络的输入层输入网络,
入层反传,周而复始,直至误差达到期望最小,认为网络训练成功。之后就可以利用训练好的网络处理新的教学质量指标,得到准确的教学质量评价结果。
BP神经网络逻辑结构图如下:
2、BP神经网络的教学质量评价模型应用
教学评价指标(每个指标打分范围0-10):x1:为人师表, 以自身行为影响学生;x2:作业适量、批改认真、耐心答疑;x3:激发学生兴趣、启发创新思维;x4:教师衣着、言谈举止及精神状态;x5:教学态度与教学技巧;x6:讲授重点突出、条理清晰;x7:能够把复杂问题清楚地表达;x8:引导学生探讨、解决问题;x9:注重教学互动、师生交流;x10:充分利用现代化教学手段。
(1) 输入层神经元个数的确定
根据我们调查中的的教学评价指标, 一共有10个指标, 可将这10个指标作为模型的输入神经元, 所以输入层神经元个数n= 10.
(2) 输出层神经元个数的确定
我们将评价结果作为网络的输出, 输出层个数m=1
(3) 网络隐含层数的确定
隐含层可以是一层也可以是多层,根据之前的理论证明,在对教学质量评价模型中, 我们选择隐含层为1层
(4) 隐含层神经元个数的确定
一般情况下, 隐含层神经元个数是根据网络收敛性能的好坏来确定的。隐含层神经元个数过少可能训练不出网络或者网络不够强壮, 但隐含层神经元个数过多, 又会使学习时间过长, 误差也不一定最佳, 因此存在一个如何确定合适的隐含层神经元个数的问题。一般可以采用试凑法, 通过比较网络输出值与期望输出值之间的误差,来确定隐层神经元个数。在本文中我们根据相关经验初定隐含层神经元个数s=8.
之后将所有评价指标数据及之前得到的比较完善的教学质量评价结果输入网络,对网络进行训练。我们取学习率=0.5,定误差最小值为=0.00001。训练结束后,得到合适的权值阈值,用此权值阈值对之后再调查得到的评价指标进行处理,得到合适的教学质量评价结果。
3、评价结果分析
调查问卷得到的教学指标打分,如下:
将如上8个样本的10个教学指标保存在txt文档中,把数据读入网络的输入层,经过5116次网络训练达到设定好的误差最小值,得到修改好的权值和阈值。并用训练好的网络处理新数据(5.5 7.5 4 5 8 4.5 7 8 8.5 6),得到实际输出教学质量(6.901607)。
4、结论
BP神经网络模型由于其具有高度非线性函数映射功能及自适应、自学习能力,可以有效克服传统教学质量评价方法的缺陷,降低传统评价方法中指标权重确定的人为影响因素,而且精度较高。经过上述训练,我们发现BP神经网络模型的输出值与真实值之间的误差比较小,性能完全可以满足实际应用的要求。另外,网络的输出精度取决于输入的训练样本的数量,训练样本的数量越多,其输出的教学效果评估值就越接近于实际的评估值。
总之, 运用BP神经网络建立教学质量评价模型, 可以为各学校教学管理部门寻求科学的教学质量评估解决方案提供有益的参考。
5、神经网络的C语言代码实现及详细解释
// 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]); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。