樱满无门 2020-06-02 15:32 采纳率: 0%
浏览 115

使用C语言模拟bp神经网络出现错误,不知道是哪一个环节出现了问题

使用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;
}
  • 写回答

1条回答 默认 最新

  • zqbnqsdsmd 2020-09-04 08:00
    关注
    评论

报告相同问题?

悬赏问题

  • ¥15 thinkphp6配合social login单点登录问题
  • ¥15 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch