ANN实现

时间:2022-10-21 14:19:20

ANN核心数据结构:

typedef struct 

{

    int input_n;                  /* number of input units */

    int hidden_n;                 /* number of hidden units */

    int output_n;                 /* number of output units */

    double *input_units;          /* the input units */

    double *hidden_units;         /* the hidden units */

    double *output_units;         /* the output units */

    double *hidden_delta;         /* storage for hidden unit error */

    double *output_delta;         /* storage for output unit error */

    double *target;               /* storage for target vector */

    double **input_weights;       /* weights from input to hidden layer */

    double **hidden_weights;      /* weights from hidden to output layer */

    /*** The next two are for momentum ***/

    double **input_prev_weights;  /* previous change on input to hidden wgt */

    double **hidden_prev_weights; /* previous change on hidden to output wgt */

} BPNN;

整个神经网络可以分成三层:输入层,隐藏层,输出层,通过加权线性变换,层与层之间的传递,最终得到输入层的实数值。

BPNN *bpnn_internal_create(int n_in, int n_hidden,int n_out;)

{//创建人工网络,参数分别指定输入层,隐藏层和输出层大小

    BPNN *newnet;

    newnet = (BPNN *) malloc (sizeof (BPNN));

    if (newnet == NULL)

    {

        printf("BPNN_CREATE: Couldn't allocate neural network/n");

        return (NULL);

    }

    newnet->input_n = n_in;//输入层

    newnet->hidden_n = n_hidden;//隐藏层

    newnet->output_n = n_out;//输出层

    newnet->input_units = alloc_1d_dbl(n_in + 1);

    newnet->hidden_units = alloc_1d_dbl(n_hidden + 1);

    newnet->output_units = alloc_1d_dbl(n_out + 1);

    newnet->hidden_delta = alloc_1d_dbl(n_hidden + 1);

    newnet->output_delta = alloc_1d_dbl(n_out + 1);

    newnet->target = alloc_1d_dbl(n_out + 1);//目标向量

    newnet->input_weights = alloc_2d_dbl(n_in + 1, n_hidden + 1);//输入层到隐藏层的权值

    newnet->hidden_weights = alloc_2d_dbl(n_hidden + 1, n_out + 1);//隐藏层到输出层的权值

    newnet->input_prev_weights = alloc_2d_dbl(n_in + 1, n_hidden + 1);

    newnet->hidden_prev_weights = alloc_2d_dbl(n_hidden + 1, n_out + 1);

    return (newnet);

}

下面代码段是ANN运行的核心部分:

if (train_n > 0)

{//提供了训练集

    printf("Creating new network '%s'/n", netname);

    iimg = trainlist->list[0];//指向训练集第一张图片

    imgsize = ROWS(iimg) * COLS(iimg);

    /* bthom ===========================

    make a net with:

    imgsize inputs, 4 hiden units, and 1 output unit

    */

    //输入层为图片大小,隐藏层为,输出层为

    net = bpnn_create(imgsize, 4, 1);

}



// 训练

/************** Train it *****************************/

for (epoch = 1; epoch <= epochs; epoch++) 

{

    printf("%d ", epoch);  fflush(stdout);

    sumerr = 0.0;

    for (i = 0; i < train_n; i++) 

    {

        /** Set up input units on net with image i **/

        //为图像i在网络上建立输入单元

        load_input_with_image(trainlist->list[i], net);

        /** Set up target vector for image i **/

        //为图像i建立目标向量

        load_target(trainlist->list[i], net);

        /** Run backprop, learning rate 0.3, momentum 0.3 **/

        //学习速率.3,冲量.3

        bpnn_train(net, 0.3, 0.3, &out_err, &hid_err);

        sumerr += (out_err + hid_err);

    }

    进行性能评估:

        for (i = 0; i < n; i++) 

        {

            /*** Load the image into the input layer. **/

            load_input_with_image(il->list[i], net);//加载图片到输入层中

            /*** Run the net on this input. **/

            bpnn_feedforward(net);//在当前输入上运行神经网络

            /*** Set up the target vector for this image. **/

            load_target(il->list[i], net);//为此图片建立目标向量

            /*** See if it got it right. ***/

            if (evaluate_performance(net, &val, 0)) 

            {//判断是否正确识别,

                correct++;

            }

            else if (list_errors) 

            {

                printf("%s - outputs ", NAME(il->list[i]));

                for (j = 1; j <= net->output_n; j++) 

                {

                    printf("%.3f ", net->output_units[j]);

                }

                putchar('/n');

            }

            err += val;

        }

        err = err / (double) n;

        if (!list_errors)

            /* bthom==================================

            this line prints part of the ouput line

            discussed in section 3.1.2 of homework

            */

            printf("%g %g ", ((double) correct / (double) n) * 100.0, err);

用到的性能评估函数:

evaluate_performance(BPNN *net,double *err)

{//性能评估

doubledelta;

delta =net->target[1] -net->output_units[1];

*err =(0.5 *delta *
delta);

/*** If thetarget unit is on... ***/

if (net->target[1]> 0.5)

{

/*** If theoutput unit is on, then we correctly recognized me! ***/

if (net->output_units[1]> 0.5)

{

return(1);

}

else

{

return(0);

}

/*** Else,the target unit is off... ***/

}

else

{

/*** If theoutput unit is on, then we mistakenly thought it was me ***/

if (net->output_units[1]> 0.5)

{

return(0);

/***else, we correctly realized that it wasn't me ***/

}

else

{

return(1);

}

}

}

辅助处理函数区:

load_input_with_image(IMAGE *img, BPNN *net)

{//输入图像

    double *units;

    int nr, nc, imgsize, i, j, k;



    nr = ROWS(img);// 行大小

    nc = COLS(img);//列大小

    imgsize = nr * nc;;

    if (imgsize != net->input_n) 

    {//确保输入单元数目设置为图片大小

        printf("LOAD_INPUT_WITH_IMAGE: This image has %d pixels,/n", imgsize);

        printf("   but your net has %d input units.  I give up./n", net->input_n);

        exit (-1);

    }

    //取图片的每个像素为输入单元

    units = net->input_units;

    k = 1;

    for (i = 0; i < nr; i++) 

    {

        for (j = 0; j < nc; j++)

        {

            units[k] = ((double) img_getpixel(img, i, j)) / 255.0;

            k++;

        }

    }

}



load_target(IMAGE *img, BPNN *net)

{//加载目标值

    int scale;

    char userid[40], head[40], expression[40], eyes[40], photo[40];

    userid[0] = head[0] = expression[0] = eyes[0] = photo[0] = '/0';

    /*** scan in the image features ***/

    sscanf(NAME(img), "%[^_]_%[^_]_%[^_]_%[^_]_%d.%[^_]",

    userid, head, expression, eyes, &scale, photo);

    if (!strcmp(userid, "glickman")) 

    {

        net->target[1] = TARGET_HIGH;  /* it's me, set target to HIGH */

    } 

    else 

    {

        net->target[1] = TARGET_LOW;   /* not me, set it to LOW */

    }

}



void bpnn_train(BPNN *net, double eta, momentum *eo, momentum *eh)

{//人工神经网络训练

    int in, hid, out;

    double out_err, hid_err;

    in = net->input_n;

    hid = net->hidden_n;

    out = net->output_n;

    /*** Feed forward input activations. ***/

    bpnn_layerforward(net->input_units, net->hidden_units,

    net->input_weights, in, hid);

    bpnn_layerforward(net->hidden_units, net->output_units,

    net->hidden_weights, hid, out);

    /*** Compute error on output and hidden units. ***/

    bpnn_output_error(net->output_delta, net->target, net->output_units,out, &out_err);

    bpnn_hidden_error(net->hidden_delta, hid, net->output_delta, out,net->hidden_weights, net->hidden_units, &hid_err);

    *eo = out_err;

    *eh = hid_err;

    /*** Adjust input and hidden weights. ***/

    bpnn_adjust_weights(net->output_delta, out, net->hidden_units, hid,net->hidden_weights, net->hidden_prev_weights, eta, momentum);

    bpnn_adjust_weights(net->hidden_delta, hid, net->input_units, in,net->input_weights, net->input_prev_weights, eta, momentum);

}



void bpnn_feedforward(BPNN *net)

{//前向反馈

    int in, hid, out;

    in = net->input_n;//输入层大小

    hid = net->hidden_n;//隐藏层大小

    out = net->output_n;//输出层大小

    /*** Feed forward input activations. ***/

    bpnn_layerforward(net->input_units, net->hidden_units,net->input_weights, in, hid);

    bpnn_layerforward(net->hidden_units, net->output_units,net->hidden_weights, hid, out);

}



void bpnn_adjust_weights(double *delta, double *ly,double **w, double **oldw, double eta, double momentum)

{//调整权值

    double new_dw;

    int k, j;

    ly[0] = 1.0;

    for (j = 1; j <= ndelta; j++) 

    {

        for (k = 0; k <= nly; k++) 

        {

            new_dw = ((eta * delta[j] * ly[k]) + (momentum * oldw[k][j]));

            w[k][j] += new_dw;

            oldw[k][j] = new_dw;

        }

    }

}

void bpnn_layerforward(double *l1, double *l2, double **conn,int n1,int n2)

{//层次前向输入

    double sum;

    int j, k;

    /*** Set up thresholding unit ***/

    l1[0] = 1.0;

    //加权线性变换

    /*** For each unit in second layer ***/

    for (j = 1; j <= n2; j++) 

    {

        /*** Compute weighted sum of its inputs ***/

        sum = 0.0;

        for (k = 0; k <= n1; k++)

        {

            sum += conn[k][j] * l1[k];

        }

        l2[j] = squash(sum);

    }

}