Bp网络神经算法

***原型题目在2011年武汉科技大学程序设计大赛,百度文库上有,属于本人上传***

1、权阵可以手动输入,可以随机产生,也可以选择题目要求矩阵

2、手动设置误差限,学习率,隐藏结点等

3、对结果采用模糊语言输出。


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

#define OUT 2     //输出向量维数
#define IN  2     //输入向量维数
#define NUM     20     //样本数量
#define Loop_MAX 524280 //最大循环次数
#define dot_MAX 20 //最大结点个数

typedef struct   //bp人工神经网络结构
{
    int dot;             //隐层节点数
    double v[IN][dot_MAX];     //输入层权矩阵
	double u[dot_MAX][dot_MAX];		//隐藏层权矩阵
    double w[dot_MAX][OUT];    //输出层权矩阵
    double rate;          //学习率
    double error;          //允许误差限
} bp_net;

double fnet(double net)   //Sigmoid函数
{ 
    return 1/(1+exp(-net));
}

void Initialize_Bp(bp_net *bp)   //初始化bp网络
{
    
    printf("请输入隐层结点数:\n");    
    scanf("%d", &(*bp).dot);
    
    printf("请输入学习率:\n");
    scanf("%lf", &(*bp).rate); 
	
    printf("请输入允许误差限:\n");
    scanf("%lf", &(*bp).error);
	
    int i, j;
    srand((unsigned)time(NULL));	//随机函数产生随机权矩阵
    for (i = 0; i < IN; i++) 
        for (j = 0; j < (*bp).dot; j++)
            (*bp).v[i][j] = rand() / (double)(RAND_MAX);    
		
		for (i = 0; i < (*bp).dot; i++) 
			for (j = 0; j < (*bp).dot; j++)
				(*bp).u[i][j] = rand() / (double)(RAND_MAX); 
			
			for (i = 0; i < (*bp).dot; i++) 
				for (j = 0; j < OUT; j++)
					(*bp).w[i][j] = rand() / (double)(RAND_MAX);  
				
				printf("初始化输入权矩阵:\n");
				for (i = 0; i < IN; i++) 
				{
					for (j = 0; j < (*bp).dot; j++)
						printf("%lf   ",(*bp).v[i][j]); 
					printf("\n");
				}
				printf("初始化隐藏层权矩阵:\n");
				for (i = 0; i < (*bp).dot; i++) 
				{
					for (j = 0; j < (*bp).dot; j++)
						printf("%lf   ",(*bp).u[i][j]); 
					printf("\n");
				}
				printf("初始化输出权矩阵:\n");
				for (i = 0; i < (*bp).dot; i++) 
				{
					for (j = 0; j < OUT; j++)
						printf("%lf   ",(*bp).w[i][j]); 
					printf("\n");
				}
				printf("\n");
}

void Train_Bp(bp_net *bp, double x[NUM][IN], int y[NUM][OUT])  //训练bp网络
{
    double e = (*bp).error;               //允许误差限       
    double rate = (*bp).rate;             //学习率         
    int dot = (*bp).dot;                  //隐藏层结点      
    double v[IN][dot_MAX], w[dot_MAX][OUT],u[dot_MAX][dot_MAX];  //权矩阵
    double Error_Input[dot_MAX],Error_hider[dot_MAX], Error_Output[OUT];       //各个结点的反向误差
    double Input[dot_MAX],hider[dot_MAX], Output[OUT];             //各个层的结点输出
    int i, j, k, n,flag;                                 //flag为是否继续修改权矩阵标志量
    double temp,t;
	
    for (i = 0; i < IN; i++)                     //复制结构体中的权矩阵 
        for (j = 0; j < dot; j++)
            v[i][j] = (*bp).v[i][j];
		
		for (i = 0; i < dot; i++)
			for (j = 0; j < dot; j++)
				u[i][j] = (*bp).u[i][j];
			
			for (i = 0; i < dot; i++)
				for (j = 0; j < OUT; j++)
					w[i][j] = (*bp).w[i][j];
				
				
				for (n = 0;n<Loop_MAX; n++)       //反向误差计算
				{ 
					flag=1;
					for (i= 0; i < NUM; i++) 
					{ 
						for (k= 0; k < dot; k++)       //计算输入层输出向量
						{      
							temp = 0;
							for (j = 0; j < IN; j++)
								temp+= x[i][j] * v[j][k];    
							Input[k] = fnet(temp);
						}
						for (k= 0; k < dot; k++)         //计算隐藏层输出向量
						{      
							temp = 0;
							for (j = 0; j < dot; j++)
								temp+=Input[j] * u[j][k];    
							hider[k] = fnet(temp);
						}
						for (k = 0; k < OUT; k++)          //计算输出层输出向量
						{
							temp = 0;
							for (j = 0; j < dot; j++)
								temp += hider[j] * w[j][k];
							Output[k] = fnet(temp);
						}
						
						for (j = 0; j < OUT ; j++)       //测试结果与是否在误差范围内
						{
							t=(y[i][j]-Output[j])*(y[i][j]-Output[j]);   
							t=sqrt(t);							//求输出结果与理想输出的误差的绝对值(abs()函数忽略掉小数部分,故不能用)
							if(t<e)
								continue;                      //如果满足精度要求,则继续测试下一个结点的情况
							else
							{
								flag=0;                      //修改了权矩阵
								for (j = 0; j < OUT; j++)                  
									Error_Output[j] = (y[i][j] - Output[j]);
								
								for (j = 0; j < dot; j++)  //计算隐层权修改量
								{       
									temp = 0;
									for (k = 0; k < OUT; k++)
										temp += w[j][k] * Error_Output[k];
									Error_hider[j] = temp * hider[j]*(1-hider[j]);
								}
								for (j = 0; j < dot; j++)           //修改输出层权矩阵
									for (k = 0; k < OUT; k++)
										w[j][k]+= rate * hider[j] * Error_Output[k]; 
									
									for(j=0;j<dot;j++)
									{
										temp=0;
										for(k=0;k<dot;k++)
											temp+=u[j][k]*Error_hider[k];
										Error_Input[j]=temp*Input[j]*(1-Input[j]);
									}
									
									for (j = 0; j < dot; j++)
										for (k = 0; k < dot; k++)
											u[j][k]+= rate * Input[j] * Error_hider[k];
										
										for(j=0;j<IN;j++)
											for(k=0;k<dot;k++)
												v[j][k]+=rate*x[i][j]*Error_Input[k];
											break; //如果一个实例的第一个输出结果不满足精度条件,修改权矩阵后,继续学习下一个实例。
											
							}
						}
					}
					if(!flag)
						continue;
					else
						break;
				}
				
				printf("总共循环次数:%d\n", n);
				printf("\n");
				
				printf("修改后的输入权矩阵:\n");   //输出修改后的输入层权矩阵
				for (i = 0; i < IN; i++) 
				{    
					for (j = 0; j < dot; j++)
						printf("%f    ", v[i][j]);    
					printf("\n");
				}
				printf("修改后的隐藏层权矩阵:\n");  //输出修改后的隐藏层权矩阵
				for (i = 0; i < dot; i++) 
				{    
					for (j = 0; j < dot; j++)
						printf("%f    ", u[i][j]);    
					printf("\n");
				}
				printf("修改后的输出层权矩阵:\n");  //输出修改后的输出权矩阵
				for (i = 0; i < dot; i++) 
				{
					for (j = 0; j < OUT; j++)
						printf("%f    ", w[i][j]);    
					printf("\n");
				}
				
				for (i = 0; i < IN; i++)             //将修改后的输入层权矩阵返回给bp结构体 
					for (j = 0; j < dot; j++)
						(*bp).v[i][j] = v[i][j];
					
					for (i = 0; i < dot; i++)			//将修改后的隐藏层权矩阵返回给bp结构体
						for (j = 0; j < dot; j++)
							(*bp).u[i][j] = u[i][j];
						
						for (i = 0; i < dot; i++)			//将修改后的输出层权矩阵返回给bp结构体
							for (j = 0; j < OUT; j++)
								(*bp).w[i][j] = w[i][j];
							
							printf("bp网络训练结束!\n");
}

void Use_Bp(bp_net *bp)    //使用bp网络测试结果
{
    float Input[IN];    //输入实例
    double Output_In[dot_MAX];   //输入层输出
    double Output_Hi[dot_MAX];      //隐藏层输出
	double Output_Ou[OUT];		//输出层输出
	double temp;
    while (1) 
	{                 
        printf("请输入一个实例:\n");
        int i, j;
        for (i = 0; i <IN ; i++)
            scanf("%f", &Input[i]);
        for (i = 0; i < (*bp).dot; i++)    //计算输入层输出
		{
            temp = 0;
            for (j = 0; j < IN; j++)
                temp += Input[j] * (*bp).v[j][i];
            Output_In[i] = fnet(temp);
        }
		for (i = 0; i < (*bp).dot; i++)		//计算隐藏层输出
		{
            temp = 0;
            for (j = 0; j < (*bp).dot; j++)
                temp += Output_In[j] * (*bp).u[j][i];
            Output_Hi[i] = fnet(temp);
        }
        for (i = 0; i < OUT; i++)			//计算输出层输出
		{
            temp = 0;
            for (j = 0; j < (*bp).dot; j++)
                temp += Output_Hi[j] * (*bp).w[j][i];
            Output_Ou[i] = fnet(temp);
        }
        printf("bp网络计算结果:   \n");
		printf("\n");

        for (i = 0; i < OUT; i++)
		{
            printf("%.6f ", Output_Ou[i]);
			if(Output_Ou[i]>=1)
				printf("   肯定是!\n");
			else
				switch((int)(Output_Ou[i]*10))
			{
			case 0:printf("    肯定不是!");break;
			case 1:printf("    稍稍像是!");break;
			case 2:printf("    有点像是!");break;
			case 3:printf("    有些像是!");break;
			case 4:printf("    比较像是!");break;
			case 5:printf("    差不多是!");break;
			case 6:printf("    相当是!");break;
			case 7:printf("    很是!");break;
			case 8:printf("    极是!");break;
			case 9:printf("    几乎是!");break;
			}
			printf("\n");
		}
	}
}
	
	void main(void)
	{
		double x[NUM][IN]=       //训练样本
		{
			{0.05,0.02}, 
			{0.09,0.11},
			{0.12,0.20},
			{0.15,0.22},
			{0.20,0.25},
			{0.75,0.75},
			{0.80,0.83},
			{0.82,0.80},
			{0.90,0.89},
			{0.95,0.89},
			{0.09,0.04},
			{0.10,0.10},
			{0.14,0.21},
			{0.18,0.24},
			{0.22,0.28},
			{0.77,0.78},
			{0.79,0.81},
			{0.84,0.82},
			{0.94,0.93},
			{0.98,0.99},
		}; 
		int y[NUM][OUT] =   //理想输出
		{
			{1,0},
			{1,0},
			{1,0},
			{1,0},
			{1,0},
			{0,1},
			{0,1},
			{0,1},
			{0,1},
			{0,1},
			{1,0},
			{1,0},
			{1,0},
			{1,0},
			{1,0},
			{0,1},
			{0,1},
			{0,1},
			{0,1},
			{0,1},
		};
		bp_net bp;						//定义bp结构体
		Initialize_Bp(&bp);              //初始化bp网络结构
		Train_Bp(&bp, x, y);             //训练bp神经网络
		Use_Bp(&bp);                     //测试bp神经网络
	}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值