深度学习神经网络纯C语言基础版

来源:互联网 发布:双拼域名交易 编辑:程序博客网 时间:2024/06/01 10:37

 本文转载自:http://blog.csdn.net/calcular/article/details/47031417

当今Deep-Learning已经是火到一定境界了,深度学习神经网络(DNN)在计算机视觉领域的表现可谓见效非凡。当然,工程上运用了卷积神经网络来减少计算量而不是全连结的神经网络-这样计算量实在太大了。但是,对于神经网络来说计算量真的不是问题,因为它的结构能够确保它能够并行计算,一旦网络的每一个单元都能够独立的进行计算,每一层再多的连结也是同时进行计算的。期待硬件神经网络的发展。


      下面手写了一套任意隐层数神经网络构建的C语言函数,能够方便移植到嵌入式设备中。该程序只是一个基于矩阵全连结形式的基础深度学习网络。运用的学习算法为随机梯度下降法,采用sigmoid函数作为激活函数。在少量样本拟合中表现不错。

[cpp] view plain copy
  1. /* 
  2.     深度学习神经网络V1.0 
  3.         made by xyt 
  4.         2015/7/23 
  5.        使用语言:C 
  6.  
  7. 本程序构建多层矩阵形神经网络多输入单输出 
  8. 学习策略:随机梯度下降 
  9. 激活函数:sigmoid 
  10. 使用前必须用srand((unsigned)time(NULL))取随机映射初始值 
  11. */  
  12. #ifndef _DNN_H  
  13. #define _DNN_H  
  14. #include<stdio.h>  
  15. #include<math.h>  
  16. #include <stdlib.h>  
  17. #include <time.h>  
  18. #define DNN_VEC 8  //输入训练组组数  
  19. #define DNN_INUM 5  //输入维度  
  20. double dnn_sig(double in){  //sigmoid函数,此处不可变  
  21.     return 1.0/(1.0+exp(-1.0*in));  
  22. }  
  23. struct dnn_cell{  //神经元结构体  
  24.     double w[DNN_INUM];  
  25.     double wb;  
  26.     double in[DNN_INUM];  
  27.     double out;  
  28.     double error;  
  29.     double v;  
  30.     void SetCell_Default(){  //默认初始化,权值初始化很小  
  31.         int i;  
  32.         for(i=0;i<DNN_INUM;i++){  
  33.             w[i]=0.000001;  
  34.         }  
  35.         wb=0.000001;  
  36.         v=0.001;  
  37.     }  
  38.     void SetCell_InitWeight(double Initial){  //权值统一权值初始化  
  39.         int i;  
  40.         for(i=0;i<DNN_INUM;i++){  
  41.             w[i]=Initial;  
  42.         }  
  43.         wb=Initial;  
  44.         v=0.001;  
  45.     }  
  46.     void SetCell_InitAll(double Initial,double InV){  //权值统一初始化,学习速率初始化  
  47.         int i;  
  48.         for(i=0;i<DNN_INUM;i++){  
  49.             w[i]=Initial;  
  50.         }  
  51.         wb=Initial;  
  52.         v=InV;  
  53.     }  
  54.     void SetCell_Precise(double *InW,double InWb,double InV){  //权值精确初始化,学习速率初始化  
  55.         int i;  
  56.         for(i=0;i<DNN_INUM;i++){  
  57.             w[i]=InW[i];  
  58.         }  
  59.         wb=InWb;  
  60.         v=InV;  
  61.     }  
  62.     void SetIn(double *SIn){  //设定神经元输入  
  63.         int i;  
  64.         for(i=0;i<DNN_INUM;i++){  
  65.             in[i]=SIn[i];  
  66.         }  
  67.     }  
  68.     double GetOut(){  //获取、设定神经元输出  
  69.         int i;  
  70.         double sum=0;  
  71.         for(i=0;i<DNN_INUM;i++){  
  72.             sum+=w[i]*in[i];  
  73.         }  
  74.         sum+=wb;  
  75.         out=dnn_sig(sum);  
  76.         return out;  
  77.     }  
  78.     void UpdateWeight(){  //更新神经元权值  
  79.         int i;  
  80.         for(i=0;i<DNN_INUM;i++){  
  81.             w[i]-=v*error*out*(1-out)*in[i];  
  82.         }  
  83.         wb=v*error*out*(1-out);  
  84.     }  
  85.     void SetError(double InErr){  //设定神经元误差传播值  
  86.         error=InErr;  
  87.     }  
  88.     void SetSpeed(double InV){  //设定神经元学习速率  
  89.         v=InV;  
  90.     }  
  91. };  
  92. /*  获得前向传播得到的输出值,第一个参数为神经元结构体数组,第二个参数为神经网络 
  93. 层数。具体排列为:前0~DNN_INUM神经元为第一层,后面每DNN_INUM个神经元为一层,依次 
  94. 排列,直至最后一个输出神经元为单独一层,如果层数是4,DNN_INUM=5(5输入)则神经元 
  95. 数量应为(4-1)*5+1=16个。*in参数为输入网络的具有DNN_INUM个数据的数组 
  96. */  
  97. double DNN_Cal(dnn_cell *incell,int deep,double *in)   
  98. {  
  99.     double out=0;  
  100.     int dd=0,i,j,k,count=0;  
  101.     double tmp[DNN_INUM];  
  102.     for(i=0;i<DNN_INUM;i++)  tmp[i]=in[i];  
  103.     for(j=0;j<deep-1;j++)  
  104.     {  
  105.         for(i=j*DNN_INUM;i<(j*DNN_INUM+DNN_INUM);i++)  
  106.         {  
  107.             incell[i].SetIn(tmp);  
  108.             incell[i].GetOut();  
  109.             count++;  
  110.         }  
  111.         k=0;  
  112.         for(i=j*DNN_INUM;i<(j*DNN_INUM+DNN_INUM);i++)  {tmp[k]=incell[i].out; k++;}  
  113.     }  
  114.     incell[count].SetIn(tmp);  
  115.     out=incell[count].GetOut();  
  116.     return out;  
  117. }  
  118. /* 
  119.     对输入矩阵训练,最后得到更新的神经网络,要求每组数据量限定为DNN_INUM数据组数限定为DNN_VEC 
  120. 输入神经原组为按层排列,除了最后一层的节点数为一其他节点数都限定为输入向量DNN_INUM 
  121. deep为网络层数至少2层,算上最后输出层,n为训练次数,expect为期望,返回训练后平均误差 
  122. */  
  123. double DNN_Train(dnn_cell *cell,int deep,double InMat[DNN_VEC][DNN_INUM],double *expect,int n)   
  124. {  
  125.     double out,devi,sum;  
  126.     double de[DNN_VEC];  
  127.     int co=n,kp=-1;  
  128.     int i,j,k,tt,l;  
  129.     for(i=0;i<DNN_VEC;i++) de[i]=9.9;  
  130.     while(co--){  
  131.         kp=(int)(rand()*(double)(DNN_VEC)/RAND_MAX);  
  132.         out=DNN_Cal(cell,deep,InMat[kp]);  
  133.         devi=out-expect[kp];  
  134.         de[kp]=devi;  
  135.         //printf("%lf  %lf  %lf  %d\n",fabs(de[0]),fabs(de[3]),fabs(de[7]),kp);  
  136.         tt=(deep-1)*DNN_INUM;  
  137.         cell[tt].error=devi;  
  138.         l=0;  
  139.         for(i=(deep-2)*DNN_INUM;i<tt;i++) {cell[i].error=cell[tt].error*cell[tt].out*(1-cell[tt].out)*cell[tt].w[l];l++;}  
  140.         for(j=deep-2;j>0;j--){  
  141.             l=0;  
  142.             for(i=(j-1)*DNN_INUM;i<j*DNN_INUM;i++){  
  143.                 sum=0;  
  144.                 for(k=j*DNN_INUM;k<(j+1)*DNN_INUM;k++){  
  145.                     sum+=cell[k].error*cell[k].out*(1-cell[k].out)*cell[k].w[l];  
  146.                 }  
  147.                 cell[i].error=sum;  
  148.                 l++;  
  149.             }  
  150.         }  
  151.         for(i=0;i<=(deep-1)*DNN_INUM;i++){  
  152.             cell[i].UpdateWeight();  
  153.         }  
  154.         //变学习速率,可以自行更改===============================  
  155.         for(i=0;i<=(deep-1)*DNN_INUM;i++){  
  156.             cell[i].SetSpeed(fabs(devi));  
  157.         }  
  158.         //=======================================================  
  159.     }  
  160.     sum=0;  
  161.     for(i=0;i<DNN_VEC;i++) sum+=fabs(de[i]);  
  162.     return sum/DNN_VEC;  
  163. }  
  164. #endif  
具体调用示范如下:

[cpp] view plain copy
  1. #include<iostream>  
  2. #include"dnn.h"  
  3. using namespace std;  
  4. int main()  
  5. {  
  6.     srand( (unsigned)time(NULL) );  
  7.     double expect[8]={0.23,0.23,0.23,0.23,0.83,0.83,0.83,0.83};  
  8.     double in[8][5]={1,2,3,4,5,  
  9.                          1.1,2.1,3,3.9,5,  
  10.                          0.8,2.2,3,4.2,5,  
  11.                          0.9,2.1,3,4,5,  
  12.                          5,4,3,2,1,  
  13.                          4.9,4.1,2.9,2,1,  
  14.                          5,4,3.1,2,1,  
  15.                          5,4,2.9,2.1,1  
  16.                         };  
  17.         dnn_cell a[16];  
  18.         int i;  
  19.         for(i=0;i<16;i++) a[i].SetCell_InitAll(rand()*2.0/RAND_MAX-1,0.001);  
  20.         DNN_Train(a,4,in,expect,100000);  
  21.         double pp[5];  
  22.         while(1){  
  23.         for(i=0;i<5;i++) cin>>pp[i];  
  24.         cout<<DNN_Cal(a,4,pp)<<endl;  
  25.         }  
  26. }  

注意期望必须在0~1之间