使用C语言模拟bp神经网络出现错误,不知道是哪一个环节出现了问题
代码:
#define LAYER_IN 0
#define LAYER_OUT LAYER - 1
#define is_NULL(PTR) (PTR == NULL)
#define Malloc(TYPE, SIZE) (TYPE *)malloc(sizeof(TYPE) * SIZE)
#define Free(PTR) \
free(PTR); \
PTR = NULL
#define normalize(X, MIN, MAX) ((X) - (MIN) + 1.0) / ((MAX) - (MIN) + 1.0)
#define sigmoid(X) 1.0 / (1.0 + exp(-(X)))
#define bigger(X, Y) (X > Y) ? X : Y
#define smaller(X, Y) (X < Y) ? X : Y
// 神经网络
struct NN
{
int per_layer;
double **nn;
double ***w;
double ***dw;
double *v;
double *dv;
double *b;
double **input;
double **output;
double **nn_out;
double in_min, in_max;
double out_min, out_max;
}nn;
int DATA_SIZE = 1000;
int LAYER = 3;
int IN_K = 2;
int OUT_K = 1;
int MAX_TIMES = 1000000;
char *FILE_IN = "input.dic";
char *FILE_OUT = "output.dic";
double STEP = 0.001;
double ACCURACY = 0.001;
void dataRead();
FILE *fileOpen(const char *route, const char *method);
void bpNetworkInit();
void bpNetworkFree();
void bpNetworkTrain();
void bpNetworkWrite();
void bpNetworkSimulate();
void dataFree();
void bpComput();
double Loss(double **output, double **groundTruth);
void bpBackUpdate(double step);
void bpNNIn_IN(int num);
void bpNNIn_HIDDEN(int layer);
void __bpNNIn_HIDDEN(int layer, int pos, int before_num); // 累加前面的输入
void bpNNIn_OUT(int num);
void dataNormalize(double **data, int row, int col, double *min, double *max);
void __bpBackUpdate(int num, double step);
void __bpBackUpdate_OUT(int num, double step);
void __bpBackUpdate_HIDDEN(double step);
void __bpBackUpdate_IN(int num, double step);
void dataNormalize(double **data, int row, int col, double *min, double *max)
{
int i, j;
*min = *max = data[0][0];
for (i = 0; i < row; i ++)
{
for (j = 0; j < col; j ++)
{
*max = bigger(*max, data[i][j]);
*min = smaller(*min, data[i][j]);
}
}
printf("%lf %lf\n", *min, *max);
for (i = 0; i < row; i ++)
{
for (j = 0; j < col; j ++)
{
data[i][j] = normalize(data[i][j], *min, *max);
}
}
}
void bpNNIn_OUT(int num)
{
int i, j;
for (i = 0; i < OUT_K; i ++)
{
// 获取输入
// sigema(a * w)
nn.nn[LAYER_OUT][i] = nn.nn[LAYER_OUT - 1][0] * nn.w[LAYER_OUT - 1][0][i];
for (j = 1; j < nn.per_layer; j ++)
{
nn.nn[LAYER_OUT][i] += nn.nn[LAYER_OUT - 1][j] * nn.w[LAYER_OUT - 1][j][i];
}
// 输出
// sigmoid(input + b)
nn.nn_out[num][i] = sigmoid(nn.nn[LAYER_OUT][i] + nn.b[LAYER_OUT]);
}
}
void bpNNIn_IN(int num)
{
int i;
for (i = 0; i < IN_K; i ++)
{
// input = a * v
// in = sigmoid(input + b)
nn.nn[LAYER_IN][i] = nn.input[num][i] * nn.v[i]; // 获取输入
nn.nn[LAYER_IN][i] = sigmoid(nn.nn[LAYER_IN][i] + nn.b[LAYER_IN]); // 输出
}
}
void bpNNIn_HIDDEN(int layer)
{
int i;
for (i = 0; i < nn.per_layer; i ++)
{
// 获取输入
if (layer == LAYER_IN + 1)
{
__bpNNIn_HIDDEN(layer, i, IN_K);
}
else
{
__bpNNIn_HIDDEN(layer, i, nn.per_layer);
}
// 输出
// out = sigmoid(sigema(input) + b)
nn.nn[layer][i] = sigmoid(nn.nn[layer][i] + nn.b[layer]);
}
}
void __bpNNIn_HIDDEN(int layer, int pos, int before_num)
{
int i;
// sigema(a_(i - 1) * w)
nn.nn[layer][pos] = nn.nn[layer - 1][0] * nn.w[layer - 1][0][pos];
for (i = 1; i < before_num; i ++)
{
nn.nn[layer][pos] += nn.nn[layer - 1][i] * nn.w[layer - 1][i][pos];
}
}
void bpComput()
{
int i, j;
for (i = 0; i < DATA_SIZE; i ++)
{
bpNNIn_IN(i);
for (j = LAYER_IN + 1; j < LAYER_OUT; j ++)
{
bpNNIn_HIDDEN(j);
}
bpNNIn_OUT(i);
}
}
double Loss(double **output, double **groundTruth)
{
double error[OUT_K];
memset(error, 0, sizeof(double) * OUT_K);
double E = 0.0;
int i, j;
for (i = 0; i < DATA_SIZE; i ++)
{
for (j = 0; j < OUT_K; j ++)
{
error[j] += pow(groundTruth[i][j] - output[i][j], 2.0);
}
}
for (i = 0; i < OUT_K; i ++)
{
error[i] /= (double)OUT_K;
E += error[i];
}
return E / (double)DATA_SIZE;
}
void bpBackUpdate(double step)
{
int i;
for (i = 0; i < DATA_SIZE; i ++)
{
__bpBackUpdate(i, step);
}
}
void __bpBackUpdate_OUT(int num, double step)
{
int i, j;
for (i = 0; i < nn.per_layer; i ++)
{
for (j = 0; j < OUT_K; j ++)
{
// 获取误差值
// -(d - out) * out * (1 - out)
nn.dw[LAYER_OUT - 1][i][j] = - (nn.output[num][j] - nn.nn_out[num][j]) * nn.nn_out[num][j] * (1 - nn.nn_out[num][j]);
// printf("e_1 %lf\t", nn.dw[LAYER_OUT - 1][i][j]);
// 更新权值
double w_copy = nn.w[LAYER_OUT - 1][i][j];
// delta_w = step * sigema * output
nn.w[LAYER_OUT - 1][i][j] -= step * nn.dw[LAYER_OUT - 1][i][j] * nn.nn[LAYER_OUT - 1][i];
// delta_b = step * sigema
nn.b[LAYER_OUT - 1] -= step * nn.dw[LAYER_OUT - 1][i][j];
// sigema * w * (1 - output) * output
nn.dw[LAYER_OUT - 1][i][j] *= w_copy * nn.nn[LAYER_OUT - 1][i] * (1 - nn.nn[LAYER_OUT - 1][i]);
}
}
printf("\n");
}
void __bpBackUpdate_HIDDEN(double step)
{
int i, j, k, h;
for (i = LAYER_OUT - 2; i >= LAYER_IN; i --)
{
int tmp_1 = (i == LAYER_IN + 1) ? IN_K : nn.per_layer;
for (j = 0; j < tmp_1; j ++)
{
for (k = 0; k < nn.per_layer; k ++)
{
// 获取误差值
int tmp_2 = (i == LAYER_OUT - 2) ? OUT_K : nn.per_layer;
nn.dw[i][j][k] = 0.0;
for (h = 0; h < tmp_2; h ++)
{
// sigema(error)
nn.dw[i][j][k] += nn.dw[i + 1][k][h];
}
// printf("e_2 %lf\t", nn.dw[i][j][k]);
// 更新权值
double w_copy = nn.w[i][j][k];
// delta_w = step * sigema * output
nn.w[i][j][k] -= step * nn.dw[i][j][k] * nn.nn[i][j];
// delta_b = step * sigema
nn.b[i] -= step * nn.dw[i][j][k];
// error = sigema * w * out * (1 - out)
nn.dw[i][j][k] *= w_copy * nn.nn[i][j] * (1 - nn.nn[i][j]);
}
}
}
printf("\n");
}
void __bpBackUpdate_IN(int num, double step)
{
int i, j;
for (i = 0; i < IN_K; i ++)
{
// 获取误差值
nn.dv[i] = 0.0;
for (j = 0; j < nn.per_layer; j ++)
{
// sigema(error)
nn.dv[i] += nn.dw[LAYER_IN][i][j];
}
// printf("e_3 %lf\t", nn.dv[i]);
// 更新权值
// delta_v = step * sigema * output
nn.v[i] -= step * nn.dv[i] * nn.input[num][i];
// delta_b = step * sigema
nn.b[LAYER_IN] -= step * nn.dv[i];
}
printf("\n");
}
void __bpBackUpdate(int num, double step)
{
__bpBackUpdate_OUT(num, step);
__bpBackUpdate_HIDDEN(step);
__bpBackUpdate_IN(num, step);
}
void bpNetworkTrain()
{
int times = 0;
double E;
double step = STEP;
bool is_continue = true;
do
{
bpComput();
times += 1;
E = Loss(nn.nn_out, nn.output);
// for (int i = 0; i < LAYER_OUT; i ++)
// {
// for (int j = 0; j < nn.per_layer; j ++)
// {
// for (int k = 0; k < nn.per_layer; k ++)
// {
// printf("=========================================%d %d %d %lf\n", i, j, k, nn.w[i][j][k]);
// }
// }
// }
printf("E:%lf\n", E);
if (times >= MAX_TIMES || E < ACCURACY)
{
is_continue = false;
}
if (is_continue)
{
bpBackUpdate(step);
}
}while(is_continue);
}
void bpNetworkInit()
{
int i, j, k;
// 确定每层的神经元个数
nn.per_layer = (2 * IN_K + 1) / (LAYER - 2);
nn.per_layer = 2;
// 申请内存
nn.b = Malloc(double, LAYER);
nn.v = Malloc(double, IN_K);
nn.dv = Malloc(double, IN_K);
nn.nn = Malloc(double *, LAYER);
nn.w = Malloc(double **, LAYER_OUT);
nn.dw = Malloc(double **, LAYER_OUT);
for (i = LAYER_IN; i < LAYER; i ++)
{
nn.nn[i] = Malloc(double, nn.per_layer);
}
for (i = LAYER_IN; i < LAYER_OUT; i ++)
{
nn.w[i] = Malloc(double *, nn.per_layer);
nn.dw[i] = Malloc(double *, nn.per_layer);
for (j = 0; j < nn.per_layer; j ++)
{
nn.w[i][j] = Malloc(double, nn.per_layer);
nn.dw[i][j] = Malloc(double, nn.per_layer);
}
}
// 随机化数字
srand(time(NULL));
for (i = 0; i < IN_K; i ++)
{
nn.v[i] = normalize(rand() % 101, 0, 100) * (rand() % 2 ? 1.0 : -1.0);
}
for (i = LAYER_IN; i < LAYER; i ++)
{
nn.b[i] = normalize(rand() % 101, 0, 100) * (rand() % 2 ? 1.0 : -1.0);
if (i < LAYER_OUT)
{
for (j = 0; j < nn.per_layer; j ++)
{
for (k = 0; k < nn.per_layer; k ++)
{
nn.w[i][j][k] = normalize(rand() % 101, 0, 100) * (rand() % 2 ? 1.0 : -1.0);
}
}
}
}
}
void bpNetworkFree()
{
dataFree();
int i, j;
Free(nn.b);
Free(nn.v);
Free(nn.dv);
for (i = LAYER_IN; i < LAYER; i ++)
{
Free(nn.nn[i]);
if (i < LAYER_OUT)
{
for (j = 0; j < nn.per_layer; j ++)
{
Free(nn.w[i][j]);
Free(nn.dw[i][j]);
}
Free(nn.w[i]);
Free(nn.dw[i][j]);
}
}
Free(nn.nn);
Free(nn.w);
}
void bpNetworkSimulate()
{
}
void bpNetworkWrite()
{
}
void dataFree()
{
int i;
for (i = 0; i < DATA_SIZE; i ++)
{
Free(nn.input[i]);
Free(nn.output[i]);
Free(nn.nn_out[i]);
}
Free(nn.input);
Free(nn.output);
Free(nn.nn_out);
}
// 读取数据
void dataRead()
{
// 打开文件
FILE *fp_in = fileOpen(FILE_IN, "r");
FILE *fp_out = fileOpen(FILE_OUT, "r");
int i, j, k;
// 分配空间
nn.input = Malloc(double *, DATA_SIZE);
nn.output = Malloc(double *, DATA_SIZE);
nn.nn_out = Malloc(double *, DATA_SIZE);
for (i = 0; i < DATA_SIZE; i ++)
{
nn.input[i] = Malloc(double, IN_K);
nn.output[i] = Malloc(double, OUT_K);
nn.nn_out[i] = Malloc(double, OUT_K);
}
// 读取数据
for (i = 0; i < DATA_SIZE; i ++)
{
for (j = 0; j < IN_K; j ++)
{
fscanf (fp_in, "%lf", &nn.input[i][j]);
}
for (k = 0; k < IN_K; k ++)
{
fscanf (fp_out, "%lf", &nn.output[i][k]);
}
}
// 退出文件
fclose(fp_in);
fp_in = NULL;
fclose(fp_out);
fp_out = NULL;
// 归一化数据
dataNormalize(nn.input, DATA_SIZE, IN_K, &nn.in_min, &nn.in_max);
dataNormalize(nn.output, DATA_SIZE, OUT_K, &nn.out_min, &nn.out_max);
}
FILE *fileOpen(const char *route, const char *method)
{
FILE *fp = fopen(route, method);
if (is_NULL(fp))
{
fprintf(stderr, "can not open %s\n", route);
exit(-1);
}
return fp;
}