⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 childview.cpp

📁 基于bp人工智能的图像识别的技术
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//基于BP网络的含噪声数字的识别(noised digital number recognition based on BPnet)
//Developed by 赵辉(H.ZHAO)
//Shandong University,JInan,ChinaPRC
//finished 2004-03-23
//the memory used dynamicly has been optimized ,2004-3-27
//ChildView.cpp : implementation of the CChildView class
#include "stdafx.h"
#include "BPnet.h"
#include "ChildView.h"
#include "matrix_op.h"
#include "math.h"
#include "time.h"
#include <sys/timeb.h>
#define SP1 1.1
#define SP2 0.7
#define SP3 0.5
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
int mark_wb=0;
int errorfilemark=0;//文件输出的序号
int dongliangmark=0;//是否使用动量因子的标志
//对训练样本进行加噪声处理,以提高网络的适应能力
void jiazao()
{   int i,j,k,*np;
    for(i=0;i<Ns/Nsext;i++)
	   for(j=0;j<N_P;j++) 
		  for(k=1;k<Nsext;k++)
			P_samples[i+k*Ns/Nsext][j]=P_samples[i][j];
    //对训练样本加噪4%到15%
    for(i=0;i<Ns/Nsext;i++)
	   for(k=1;k<Nsext;k++)
		{	np=Rand2(N_P,int(N_P*(0.04+k*0.03)));//0.04,0.02
	        for(j=0;j<int(N_P*(0.04+k*0.03));j++)
	           P_samples[i+k*Ns/Nsext][np[j]]=(P_samples[i+k*Ns/Nsext][np[j]]==1)?0:1;
			free(np);
		}
    
	for(i=0;i<Ns/Nsext;i++)
		for(j=0;j<N_Out;j++) 
	       for(k=1;k<Nsext;k++)
			 T_output[i+k*Ns/Nsext][j]=T_output[i][j];
}

//将当前的权值final的值初始化设置为init值。其中init值为随机产生的初始权值和偏置
void CChildView::initwb()
{   int i,j;
	for(i=0;i<s1;i++) 
	{   B1_final[i]=B1_init[i];
		for(j=0;j<r;j++) 
			W1_final[i*r+j]=W1_init[i*r+j];
	}
    for(i=0;i<s2;i++) 
	{   B2_final[i]=B2_init[i];
		for(j=0;j<s1;j++) 
			W2_final[i*s1+j]=W2_init[i*s1+j];
	}
}

//将当前的权值final分配给一临时变量W1、W2、B1、B2,以便进行稍后的运算。这里动态开辟了内存
void CChildView::loadwb()
{   int i,j;
    W1=(double*)malloc(s1*r*sizeof(double));
    W2=(double*)malloc(s2*s1*sizeof(double));
	B1=(double*)malloc(s1*1*sizeof(double));
	B2=(double*)malloc(s2*1*sizeof(double));
	for(i=0;i<s1;i++) 
	{   B1[i]=B1_final[i];
		for(j=0;j<r;j++) 
			W1[i*r+j]=W1_final[i*r+j];
	}
    for(i=0;i<s2;i++) 
	{   B2[i]=B2_final[i];
		for(j=0;j<s1;j++) 
			W2[i*s1+j]=W2_final[i*s1+j];
	}
}


//将存于临时内存区的W1、W2、B1、B2的值存储在当前权值final里。此步以后就可以删除临时内存区以优化内存
void CChildView::savewb()
{   int i,j;
	for(i=0;i<s1;i++) 
	{   B1_final[i]=B1[i];
		for(j=0;j<r;j++) 
			W1_final[i*r+j]=W1[i*r+j];
	}
    for(i=0;i<s2;i++) 
	{   B2_final[i]=B2[i];
		for(j=0;j<s1;j++) 
			W2_final[i*s1+j]=W2[i*s1+j];
	}
}

//在point点处绘制灰度为gray、边长为area的矩形
CChildView::DrawPoint(CPoint point, int gray,int area)
{
   CClientDC dc(this);
   CPen pen;
   pen.CreatePen (PS_NULL,1,RGB(0,0,0));
   dc.SelectObject (&pen);
   CBrush brush(RGB(gray*SP1<255?gray*SP1:255,gray*SP2<255?gray*SP2:255,gray*SP3<255?gray*SP3:255));
   dc.SelectObject (&brush);
   dc.Rectangle (point.x-area/2,point.y -area/2,point.x +area/2,point.y +area/2);
   
}

//画数字:p指向64个元素的数组,pcenter指出在窗口客户区的哪个地方画,是一个CPoint类的坐标值
void CChildView::DrawNumber(double p[],CPoint pcenter)
{
	CPoint point(20,20);
	int i,j,gray;
	//double* p=&P_samples[0][0];
	for(i=0;i<8;i++)
	{  for(j=0;j<8;j++)
	   {
	       gray=p[i*8+j]==1?8:252;
		   point.x =pcenter.x +j*6;
		   point.y =pcenter.y +i*6;
	       DrawPoint(point,gray,6);
	   }
	}
}

/////////////////////////////////////////////////////////////////////////////
// CChildView

CChildView::CChildView()
{   jiazao();
 	::AfxMessageBox("即将运行基于BP网络的数字识别程序:\n\n(1)请按照菜单上标定的序号来依次执行BP网络的训练、识别任务!  \n\n(2)程序运行前,最好将您的适配器调整到1024×768的分辨率,否则部分信息可能显示不全!   \n");
}

CChildView::~CChildView()
{
}

BEGIN_MESSAGE_MAP(CChildView,CWnd )
	//{{AFX_MSG_MAP(CChildView)
	ON_WM_PAINT()
	ON_COMMAND(ID_BPN_TRAIN, OnBpnTrain)
	ON_COMMAND(ID_DRAW_ERROR, OnDrawError)
	ON_COMMAND(ID_PREWB, OnPrewb)
	ON_COMMAND(ID_DISP_SAMPLES, OnDispSamples)
	ON_COMMAND(ID_BPN_RUN, OnBpnRun)
	ON_COMMAND(ID_BPN_Verify, OnBPNVerify)
	ON_COMMAND(ID_BPTRAIN_Optimal1, OnBPTRAINOptimal1)
	ON_COMMAND(ID_SAVEERROR, OnSaveerror)
	ON_COMMAND(ID_SAVEWEIGHT, OnSaveweight)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CChildView message handlers

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOW+1), NULL);

	return TRUE;
}

void CChildView::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	GetClientRect(&rect);	
	// Do not call CWnd::OnPaint() for painting messages
}


//用60组已知样本数据来训练BP网络。其中,10个数据是纯净的未加噪的,50个是随机加噪的
void CChildView::OnBpnTrain() 
{   dongliangmark=0;
	errorfilemark++;
	if(mark_wb==0) OnPrewb();//随机产生初始权值和偏置存放于init
	int i,current,loops,trainok;
	int mark[Ns];//训练成功标志
	//numE=(double*)malloc(N_Err*sizeof(double));//存放最多N_Err点的均方误差
	/////////////////////////////////////////////////////////////////////
	current=loops=trainok=0;
	for(i=0;i<N_Err;i++) numE[i]=0;
	for(i=0;i<Ns;i++) mark[i]=0;
	initwb();//初始化权值和偏置(将init赋值给final)
	/////////////////////////////////////////////////////////////////////
	CClientDC dc(this);
	dc.Rectangle (rect);
	CString str;
	CFont font;
	font.CreatePointFont (350,_TEXT("新宋体"));
	dc.SelectObject (&font);
	dc.DrawText (_T("正在训练网络...请稍等...."),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
	double* temp[15];
	CTime startTime = CTime::GetCurrentTime();
	struct _timeb timebuffer;
	int mills1,mills2;
    _ftime(&timebuffer);
	mills1=timebuffer.millitm;
step2:
	loadwb();//将final赋值给新分配内存空间的W1,W2,B1,B2
	current=loops%(Nsext*10);
	P=P_samples[current];//current为0到9,以循环指向数字0~9的标准输入样本
	T=T_output[current];
	/******************************计算正向传播信息********************************/
	N1=MatrixAdd((temp[0]=MatrixMul(W1,P,s1,r,1)),B1,s1,1);  //N1: s1×1
	A1=f1(N1,s1);//f1是自定义的函数,具备对矢量进行运算的功能
	N2=MatrixAdd((temp[1]=MatrixMul(W2,A1,s2,s1,1)),B2,s2,1);//N2: s2×1
	A2=f2(N2,s2);
	/******************************反向传播误差的计算******************************/
	E=MatrixSub(T,A2,s2,1);//T、A2、E为s2×1
	numE[loops]=0;	//注意,此时的误差不是一个数了!是个向量
	for(i=0;i<s2;i++)
        numE[loops]=numE[loops]+E[i]*E[i];
	//-------计算S2、S1(注意顺序)
	S2=MatrixMulNum((temp[3]=MatrixMul((temp[2]=F2(N2,s2)),E,s2,s2,1)),s2,1,-2.0);
	S1=MatrixMul(temp[6]=(MatrixMul((temp[4]=F1(N1,s1)),(temp[5]=MatrixInver(W2,s2,s1)),s1,s1,s2)),S2,s1,s2,1);
	//调整输出层神经元的权值和偏置
	dW2=MatrixMul(S2,(temp[7]=MatrixInver(A1,s1,1)),s2,1,s1);//dW2: s2×s1
	dW2=MatrixMulNum((temp[8]=dW2),s2,s1,-learnspeed);
	W2=MatrixAdd((temp[9]=W2),dW2,s2,s1);
	dB2=MatrixMulNum(S2,s2,1,-learnspeed);
	B2=MatrixAdd((temp[10]=B2),dB2,s2,1);
	//调整隐层神经元权值和偏置
	dW1=MatrixMul(S1,(temp[11]=MatrixInver(P,r,1)),s1,1,r);//dW1: s1×r
    dW1=MatrixMulNum((temp[12]=dW1),s1,r,-learnspeed);
	W1=MatrixAdd((temp[13]=W1),dW1,s1,r);
	dB1=MatrixMulNum(S1,s1,1,-learnspeed);
	B1=MatrixAdd((temp[14]=B1),dB1,s1,1);
    dc.DrawText (_T("正在训练网络...请稍等...."),-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
	TRACE("%d loops, error is: %f  \n",loops,numE[loops]);
	savewb();//将临时空间W、B中的数据存于final
	//释放动态分配的内存区
	free(W1);free(B1);free(N1);free(A1);free(dW1);free(dB1);free(S1);
	free(W2);free(B2);free(N2);free(A2);free(dW2);free(dB2);free(S2);
	for(i=0;i<15;i++) free(temp[i]);
	if(loops>N_Err) goto step3;
	if(numE[loops]>error_accept)  //说明误差不能满足要求。继续调节
	{   mark[current]=0; //验证有效位重新计数
		++loops;
	    goto step2;
	}
	else mark[current]=1;//执行到此步说明在该次迭代中,误差符合要求,记功一次
	trainok=0;
	for(i=0;i<Ns;i++)
		trainok+=mark[i];
	if(trainok>=Ns)
	{   //训练可以结束了;
	    goto step3;
	}
	else {  ++loops; goto step2;}
step3:
	learncount=loops-1;//计算总的学习次数并存放于全局变量
    dc.Rectangle (rect);
	dc.TextOut (300,150,_T("训练完成!"));
	str.Format ("%d",learncount);
	dc.TextOut (80,400,"总共训练了:");
	dc.TextOut (360,400,str);
	dc.TextOut (490,400,"次");
	str.Format ("%f",numE[loops-1]);
	dc.TextOut (80,500,"最终误差:");
	dc.TextOut (340,500,str);
	stre=str;

	//计算训练所用时间
	CTime endTime = CTime::GetCurrentTime();
	CTimeSpan elapsedTime = endTime - startTime;
    _ftime(&timebuffer);
	mills2=timebuffer.millitm;
	long int timeused;
	timeused=elapsedTime.GetTotalSeconds();
	if (mills1<=mills2)
		timeused=timeused*1000+(mills2-mills1);//将计算训练所用时间换算成毫秒
	else
		timeused=(timeused-1)*1000+(mills1-mills2);
	strt.Format ("训练网络所用时间:%d 毫秒",timeused);

    ::AfxMessageBox(strt); 
}

//f1、f2为激活函数
double* CChildView::f1(double A[],int m)
{   int i;
    double *B=NULL;
	B=(double*)malloc(m*1*sizeof(double));//B是一个列向量
	for(i=0;i<m;i++)
		B[i]=(double)1/(1+exp(-A[i]));
	return B;
}

double* CChildView::f2(double A[],int m)
{   int i;
    //double c=1.0;
    double *B=NULL;
	B=(double*)malloc(m*1*sizeof(double));
	for(i=0;i<m;i++)
		B[i]=A[i];
	return B;
}

//F1、F2为激活函数的求导(矩阵形式)
double* CChildView::F1(double N[],int m)
{   int i,j;
    double *B=NULL;
	B=(double*)malloc(m*m*sizeof(double));
	for(i=0;i<m;i++)
		for(j=0;j<m;j++)
		   B[i*m+j]=0;
	for(i=0;i<m;i++)
		B[i*m+i]=exp(-N[i])/((1+exp(-N[i]))*(1+exp(-N[i])));
	return B;
}

double* CChildView::F2(double N[],int m)
{   int i,j;
    double *B=NULL;
	B=(double*)malloc(m*m*sizeof(double));
	for(i=0;i<m;i++)
		for(j=0;j<m;j++)
		   B[i*m+j]=0;
	for(i=0;i<m;i++)
		B[i*m+i]=1;
	return B;
}

//根据欧式距离匹配BP网络的输出结果属于哪个数字
int CChildView::TargetTest(double A[])
{   double a,min=100;
    int index=-1,i,j;
	double* Temp;
    for(i=0;i<Ns/Nsext;i++)
	{   Temp=MatrixSub(A,T_output[i],s2,1);
		a=0;
	    for(j=0;j<s2;j++)
		    a=a+Temp[j]*Temp[j];
        if(a<min)
		{
			min=a;
			index=i;
		}
		free(Temp);
	}
	return index;
}

//绘制学习误差曲线
void CChildView::OnDrawError() 
{ 	CClientDC dc(this);	
	dc.Rectangle (rect);
	CPen pen(PS_SOLID,3,RGB(105,90,170));
	dc.SelectObject(&pen);
	int n,i;
	double numEsum[2000]={0};
	for(n=0;n<learncount;n++)
	    numEsum[(int)(n/10)]+=numE[n];
	for(i=0;i<int(learncount/10);i++)
	{   dc.MoveTo (30+i ,(int)((float)(rect.bottom-rect.top)*0.98));
	    dc.LineTo (30+i ,(int)((float)(rect.bottom-rect.top)*0.98-15*numEsum[i]));
	}
	//Invalidate(TRUE);
}


//随机设置初始权值和偏置。这里一般取-1到1之间的随机数

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -