前段时间毕业设计中写的一段代码,三层BP神经网络用于自适应,用Levenberg-Maquardt法进行训练。
#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);
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include "bpnn.h"
//交换
#define SWAP(x,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
// 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);
}
}
/**//////////////////////////////////////////////////////////////////////
// 计算输出层反传误差(单个样本)
// 参数
// 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 -- 输出层反传误差
// dfda_h
// dfda_h
// nh -- 隐层神经元数目
// nout -- 输出层神经元数
// w_ho -- 隐层到输出层连接权值
// h_unit -- 隐层神经元数组
// err