本文学习笔记是自己的理解,如有错误的地方,请大家指正批评。共同进步。谢谢!
之前的教学质量评价,仅仅是通过对教学指标的简单处理。如求平均值或人为的给出各指标的权值来加权求和,其评价结果带有非常大主观性。利用BP神经网络建立教学质量评价系统的模型,通过调查分析得到教学评价指标。将其标量化成确定的数据作为其输入,用BP神经网络训练后作为实际输出,将之前得到的教学效果作为期望输出。比較期望输出与实际输出的误差。当误差达到期望的最小值时,觉得训练成功。
训练成功后能够得到比較准确的权值和阈值。用训练成功后的网络处理还有一组新得到的教学评价指标。得到教学质量评价结果。
该方法用于教学质量评价中,既克服了专家在评价过程中的主观因素,又得到了惬意的评价结果,具有广泛的适用性。
1、BP神经网络介绍
BP神经网络是加州大学的Rumelhart和Mcclelland提出的一种人工神经网络学习算法,是一种依照误差逆向传播算法训练的神经网络。其学习规则为:使用梯度下降法,通过误差反向传播不断调整网络的权值和阈值,使网络的误差平方和最小。从本质上说,这是一类由大量信息处理单元通过广泛联结而构成的动态信息处理系统。
BP神经网络包含信息的正向传播和误差的反向传播两个过程。信息的正向传播:将教学评价指标各数据通过网络的输入层输入网络,
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
入层反传,周而复始,直至误差达到期望最小。觉得网络训练成功。
之后就能够利用训练好的网络处理新的教学质量指标,得到准确的教学质量评价结果。
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]);
}
}