人工神经网络之反向传播算法

都说《机器学习》是学计算机的人必须要看的一本书,确实不是浪得虚名。看了一章人工神经网络(ANN)中关于反向传播算法的内容,相比单个感知器而言,采用多层网络的反向传播算法能表示出更多种类的非线性曲面,下面总结下它基本的处理框架。

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)

{//性能评估

      double delta;

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

      *err = (0.5 * delta * delta);

      /*** If the target unit is on... ***/

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

      {

           /*** If the output 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 the output 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);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值