📄 main.cpp
字号:
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <iostream>
#define PI 3.14159
#define EPSILON 1E-6
//3层的神经网络结构
typedef struct tag_bpnnt
{
int in_n; //输入层神经元数
int hidd_n; //隐层神经元数
int out_n; //输出层神经元
double *in_unit; //输入层神经元
double *hidd_unit; //隐层神经元
double *out_unit; //输出层神经元
double *hidd_delta;//隐层误差
double *out_delta; //输出层误差
double *hidd_dfda;
double *out_dfda;
double *target; //目标向量
double **in_w; //输入层权值
double **hidd_w; //隐层权值
//前一次结果(用于迭代)
double **prev_in_w;
double **prev_hidd_w;
}BPNN_t;
//分配1d内存
double *bpnn_malloc1d(int n);
//分配2d内存
double **bpnn_malloc2d(int m,int n);
//销毁2d内存
void bpnn_mfree2d(double **pmem,int m);
//计算sigmoid函数
double sigmoid(double x);
//建立神经网络
BPNN_t *bpnn_create(int nIn,int nHidden,int nOut);
//销毁网络
void bpnn_destroy(BPNN_t *pNet);
//初始化权值
void bpnn_init_weight(double **w,int m,int n,int flag);
//前向计算本层输出
void bpnn_layerforward(double *layer1,double *layer2,double **conn,int n1,int n2);
//计算输出层反传误差
void bpnn_out_error(double *delta,double *dfda,double *target,double *output,int nj,double *err);
//计算隐层反传误差
void bpnn_hidd_error(double *delta_h,double *delta_o,double *dfda_h,double *dfda_o,int nh,int nout,double **w_ho,double *h_unit,double*err);
//计算整个网络输出
void bpnn_nnforward(BPNN_t *pNet);
//最速下降法训练一次
double bpnn_train_steepest(BPNN_t *pNet,double eta,double **indata,double **targetdata,int np);
//Levenberg-Marquardt训练
double bpnn_train_lm(BPNN_t *pNet,double **indata,double **targetdata,int np,double *lamda);
//gauss-jordan消元法解线性方程组
void gauss_jordan(double *a,double *b,int n);
//交换
void SWAP(double x,double y)
{
if((x)!=(y))
{
x=x+y;
y=x-y;
x=x-y;
}
}
//设置单位矩阵
static void SetEye(double*mat,int n);
//分配1d内存
double *bpnn_malloc1d(int n)
{
double *pout;
pout=(double*)malloc(n*sizeof(double));
return pout;
}
//分配2d内存
//m为行数(组数),n为列数(每组个数)
double **bpnn_malloc2d(int m,int n)
{
double **pout;
int i;
pout=(double**)malloc(m*sizeof(double*));
for(i=0;i<m;i++)
{
pout[i]=(double*)malloc(n*sizeof(double));
}
return pout;
}
//销毁2d内存
void bpnn_mfree2d(double **pmem,int m)
{
int i;
for(i=0;i<m;i++)
{
free(pmem[i]);
}
free(pmem);
pmem=NULL;
}
/**//////////////////////////////////////////////////////////////////////
//初始化权值
// 参数
// flag-- 1随机初始化 0 全部清0[Page]
// m--上一层神经元数目
// n--下一层神经元数目
/**/////////////////////////////////////////////////////////////////////
void bpnn_init_weight(double **w,int m,int n,int flag)
{
int i,j;
srand((unsigned int)time(NULL));
if(flag) //随机生成
{
for(i=0;i<m+1;i++)
for(j=0;j<n+1;j++)
{
//-1.0~1.0的随机值
w[i][j]=(double)(rand()%2000)/1000.0-1;
}
}
else //全部清0
{
for(i=0;i<m+1;i++)
for(j=0;j<n+1;j++)
{
w[i][j]=0.0;
}
}
}
//计算sigmoid函数
double sigmoid(double x)
{
return 1.0/(1.0+exp(-x));
}
/**//////////////////////////////////////////////////////////////////////
//建立神经网络
// 参数
// nIn --输入层神经元数
// nHidden --隐层神经元数
// nOut --输出层神经元数
/**//////////////////////////////////////////////////////////////////////
BPNN_t *bpnn_create(int nIn,int nHidden,int nOut)
{
BPNN_t *pNet;
pNet=(BPNN_t*)malloc(sizeof(BPNN_t));
pNet->in_n=nIn;
pNet->hidd_n=nHidden;
pNet->out_n=nOut;
pNet->in_unit=bpnn_malloc1d(nIn+1); //增加1保存阀值分量b
pNet->hidd_unit=bpnn_malloc1d(nHidden+1);
pNet->out_unit=bpnn_malloc1d(nOut+1);
pNet->hidd_delta=bpnn_malloc1d(nHidden+1);
pNet->out_delta=bpnn_malloc1d(nOut+1);
pNet->hidd_dfda=bpnn_malloc1d(nHidden+1);
pNet->out_dfda=bpnn_malloc1d(nOut+1);
pNet->target=bpnn_malloc1d(nOut+1);
pNet->in_unit[0]=1.0; //阀值分量
pNet->hidd_unit[0]=1.0;
//网络权重
pNet->in_w=bpnn_malloc2d(nIn+1,nHidden+1);
pNet->hidd_w=bpnn_malloc2d(nHidden+1,nOut+1);
pNet->prev_in_w=bpnn_malloc2d(nIn+1,nHidden+1);
pNet->prev_hidd_w=bpnn_malloc2d(nHidden+1,nOut+1);
//初始化权值
bpnn_init_weight(pNet->in_w,nIn,nHidden,1);
bpnn_init_weight(pNet->hidd_w,nHidden,nOut,1);
bpnn_init_weight(pNet->prev_in_w,nIn,nHidden,0);
bpnn_init_weight(pNet->prev_hidd_w,nHidden,nOut,0);
return pNet;
}
//销毁网络
void bpnn_destroy(BPNN_t *pNet)
{
int i;
int n1;
int n2;
n1=pNet->in_n;
n2=pNet->hidd_n;
free(pNet->in_unit);
free(pNet->hidd_unit);
free(pNet->out_unit);
free(pNet->hidd_delta);
free(pNet->out_delta);
free(pNet->hidd_dfda);
free(pNet->out_dfda);
free(pNet->target);
for(i=0;i<n1+1;i++)
{
free(pNet->prev_in_w[i]);
free(pNet->in_w[i]);
}
free(pNet->prev_in_w);
free(pNet->in_w);
for(i=0;i<n2+1;i++)
{
free(pNet->prev_hidd_w[i]);
free(pNet->hidd_w[i]);
}
free(pNet->prev_hidd_w);
free(pNet->hidd_w);
free(pNet);
}
/**//////////////////////////////////////////////////////////////////////
//前向计算本层的输出
// 参数
// layer1 --上一层神经元数组
// layer2 --该层神经元数组
// conn --上层连接权值
// n1 --上层神经元个数
// n2 --本层神经元个数
// 返回
// 更新layer1,layer2
/**//////////////////////////////////////////////////////////////////////
void bpnn_layerforward(double *layer1,double *layer2,double **conn,int n1,int n2)
{
double sum;
int j,k;
layer1[0]=1.0; //以第0个代表阀值分量
for(j=1;j<n2+1;j++)
{
sum=0.0;
for(k=0;k<n1+1;k++)
{
sum+=conn[k][j]*layer1[k];
}
layer2[j]=sigmoid(sum);
}
}
/**//////////////////////////////////////////////////////////////////////[Page]
//计算输出层反传误差(单个样本)
// 参数
// delta --反传误差向量
// target --目标值
// output --网络输出值
// nj --输出层神经元数
// err --总误差
// 返回
// 更新err,delta
/**//////////////////////////////////////////////////////////////////////
void bpnn_out_error(double *delta,double *dfda,double *target,double *output,int nj,double*err)
{
int j;
double errsum=0.0;
for(j=0;j<nj+1;j++)
{
//求反传误差
delta[j]=output[j]*(1-output[j])*(target[j]-output[j]);
dfda[j]=output[j]*(1-output[j]);
errsum+=fabs(delta[j]);
}
*err=errsum;
}
/**//////////////////////////////////////////////////////////////////////
//计算隐层反传误差(单个样本)
// 参数
// delta_h --隐层反传误差向量
// delta_o --输出层反传误差
//------------------ Page 8-----------------------
// dfda_h
// dfda_h
// nh --隐层神经元数目
// nout --输出层神经元数
// w_ho --隐层到输出层连接权值
// h_unit --隐层神经元数组
// err --总误差[Page]
// 返回
// 更新err,delta_h
/**//////////////////////////////////////////////////////////////////////
void bpnn_hidd_error(double *delta_h,double *delta_o,double *dfda_h,double *dfda_o,int nh,int nout,double **w_ho,double *h_unit,double *err)
{
int j,k;
double hidd,sum,sum2,errsum;
errsum=0.0;
for(j=0;j<nh+1;j++)
{
hidd=h_unit[j];
sum=0.0;
sum2=0.0;
for(k=1;k<nout+1;k++)
{
sum+=delta_o[k]*w_ho[j][k];
sum2+=dfda_o[k]*w_ho[j][k];
}
delta_h[j]=hidd*(1-hidd)*sum;
dfda_h[j]=hidd*(1-hidd)*sum2;
errsum+=fabs(delta_h[j]);
}
*err=errsum;
}
//计算整个网络输出
void bpnn_nnforward(BPNN_t *pNet)
{
int nIn,nHidd,nOut;
nIn=pNet->in_n;
nHidd=pNet->hidd_n;
nOut=pNet->out_n;
//计算输入层--隐层
//----------------------- Page 9-----------------------
bpnn_layerforward(pNet->in_unit,pNet->hidd_unit,pNet->in_w,nIn,nHidd);
//计算隐层--输出层
bpnn_layerforward(pNet->hidd_unit,pNet->out_unit,pNet->hidd_w,nHidd,nOut);
}
/**//////////////////////////////////////////////////////////////////////
//最速下降法的BP网络单次训练(全部样本)
// 参数
// pNet --已初始化的神经网络
// eta --最速下降步长
// indata --输入的样本数组
// targetdata--输出期望
// np --样本个数
// 返回
// 返回更新后的平方误差
// 更新pNet
/**//////////////////////////////////////////////////////////////////////
double bpnn_train_steepest(BPNN_t *pNet,double eta,double **indata,double **targetdata,int np)
{
int p,i,j,k;
int nIn,nHidd,nOut;
double errout,errh;
double esqrsum,esqr;
double **pGradIn,**pGradH;
nIn=pNet->in_n;
nHidd=pNet->hidd_n;
nOut=pNet->out_n;
pGradIn=bpnn_malloc2d(nIn+1,nHidd+1);
pGradH=bpnn_malloc2d(nHidd+1,nOut+1);
//累加梯度清0
for(j=0;j<=nIn;j++)
for(k=0;k<=nHidd;k++)
{
pGradIn[j][k]=0.0;
}
for(j=0;j<=nHidd;j++)
for(k=0;k<=nOut;k++)
{
pGradH[j][k]=0.0;
}
//----------------------- Page 10-----------------------
for(p=0;p<np;p++)
{
//输入数据
pNet->in_unit[0]=0.0; //无偏移[Page]
for(i=1;i<=nIn;i++)
pNet->in_unit[i]=indata[p][i-1];
for(i=1;i<=nOut;i++)
pNet->target[i]=targetdata[p][i-1];
bpnn_nnforward(pNet);
bpnn_out_error(pNet->out_delta,pNet->out_dfda,pNet->target,pNet->out_unit,nOut,&errout);
bpnn_hidd_error(pNet->hidd_delta,pNet->out_delta,pNet->hidd_dfda,pNet->out_dfda,nHidd,nOut,pNet->hidd_w,pNet->hidd_unit,&errh);
//累加梯度
for(j=0;j<=nIn;j++)
for(k=1;k<=nHidd;k++)
{
pGradIn[j][k]+=pNet->hidd_delta[k]*pNet->in_unit[j];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -