***原型题目在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神经网络
}