[资源共享] C51实现8051上运行的神经网络

[复制链接]
4216|47
 楼主| 家有两宝呀 发表于 2022-6-28 23:28 | 显示全部楼层
尽管代码不是绝对的初学者,但是如果您熟悉数组和循环的概念,则希望能够阅读本文随附的草图并遵循逻辑。这是一个高级细分:

    初始化数组。权重设置为随机数,而两个用于保存反向传播中使用的更改值的其他数组都设置为零。
    开始一个大循环,通过完整的训练数据集运行系统。
    随机化训练集在每次迭代中运行的顺序,以减少局部最小值的振荡或收敛。
    计算隐藏层激活,输出层激活和错误。
    将错误反向传播到隐藏层。
    更新权重。
    如果系统错误大于成功阈值,则运行训练数据的另一次迭代。
    如果系统错误小于成功阈值,则中断,声明成功,然后将数据发送到串行终端。
    每1000个周期将训练集的测试运行结果发送到串行终端。

除了编程逻辑外,还有三个要理解的网络基本概念:激活函数,梯度良好和偏置。
 楼主| 家有两宝呀 发表于 2022-6-28 23:30 | 显示全部楼层
激活函数根据馈入该神经元的加权连接的总和来计算该神经元的输出。尽管有变化,但此草图使用了最常见的激活函数,称为“ Sigmoid函数”,因为其独特的形状如下图所示。
 楼主| 家有两宝呀 发表于 2022-6-28 23:35 | 显示全部楼层
 楼主| 家有两宝呀 发表于 2022-6-28 23:36 | 显示全部楼层
该函数的关键特征是无论输入如何,输出都将落在0到1之间。此功能在编码神经网络时非常方便,因为神经元的输出始终可以表示为full on和full之间的范围。关。激活函数可以在代码中采用通用形式的几个地方看到:
  1. 输出= 1.0 /(1.0 + exp(-Accum))
 楼主| 家有两宝呀 发表于 2022-6-28 23:37 | 显示全部楼层
输出是代表已激活神经元输出的数组变量,而Accum是该神经元加权输入的总和。特定公式的复杂性并不重要,除了它们可以方便地产生S型输出。

梯度下降是反向传播的秘密武器。这是一种数学方法,使我们能够计算每个输出神经元的误差幅度,确定与该神经元的每个连接对误差的贡献程度,并对这些连接的权重进行增量调整以系统地减少误差。
 楼主| 家有两宝呀 发表于 2022-6-28 23:38 | 显示全部楼层
梯度下降的第一步是为每个神经元计算一个称为增量的值。增量反映了误差的大小-神经元的目标值与其实际输出之间的差异越大,则增量越大。在输出层,增量计算很简单:
  1. 增量=(目标-实际)*实际*(1-实际)
 楼主| 家有两宝呀 发表于 2022-6-28 23:38 | 显示全部楼层
在代码中被视为
  1. OutputDelta [i] =(Target [p] [i]-Output [i])* Output [i] *(1.0-Output [i]);
 楼主| 家有两宝呀 发表于 2022-6-28 23:39 | 显示全部楼层
由于没有可测量的目标,因此计算隐藏层的增量将变得更加复杂。取而代之的是,每个隐藏神经元的误差幅度是根据权重与针对输出层计算的增量之间的关系得出的。对于每个隐藏的神经元,代码逐步遍历所有输出连接,将权重乘以增量,并保持运行总计:
  1. 累计+ = OutputWeights [i] [j] * OutputDelta [j];
 楼主| 家有两宝呀 发表于 2022-6-28 23:40 | 显示全部楼层
然后,通过将存储在Accum中的值替换为在第一次计算中看到的公式中的Target [p] [i]-Output [i]值来计算内层增量:
HiddenDelta [i] =累计* Hidden [i] *(1.0-Hidden [i]);
 楼主| 家有两宝呀 发表于 2022-6-28 23:41 | 显示全部楼层
计算出两层的增量值后,下一步就是实际进行操作并调整权重。在这里,我们看到学习率和动量的值如何改变权重的变化。对于每个重量,更改量由以下公式确定:
  1. 变化=(学习率*体重*差异)+(动量*以前的变化)
 楼主| 家有两宝呀 发表于 2022-6-28 23:43 | 显示全部楼层
然后通过将旧权重添加到更改值中来找到新权重:

  体重=体重+变化
 楼主| 家有两宝呀 发表于 2022-6-28 23:47 | 显示全部楼层
对于内层和隐藏层之间的权重,公式在代码中显示为:

  ChangeHiddenWeights [j] [i] =学习率*输入[p] [j] * HiddenDelta [i] +动量* ChangeHiddenWeights [j] [i];

  HiddenWeights [j] [i] + = ChangeHiddenWeights [j] [i];
 楼主| 家有两宝呀 发表于 2022-6-28 23:50 | 显示全部楼层
对于隐藏层和输出层之间的权重,公式在代码中显示为:

  ChangeOutputWeights [j] [i] =学习率*隐藏[j] * OutputDelta [i] +动量* ChangeOutputWeights [j] [i];

  OutputWeights [j] [i] + = ChangeOutputWeights [j] [i];
 楼主| 家有两宝呀 发表于 2022-6-28 23:52 | 显示全部楼层
最后,我们开始偏见,这是一个相对简单的概念,但是当不理解它时,可能会使代码有些混乱。输入层和隐藏层每个都包含一个始终触发的额外神经元(换句话说,它始终隐含激活为“ 1”)。偏差值对网络有几个积极影响。它增加了稳定性并扩大了可能的解决方案的数量。最重要的是,它消除了所有输入均为零且因此没有信号通过网络传播的可能性。如果查看包含权重和变化值的数组的声明,则会看到该额外的神经元。
 楼主| 家有两宝呀 发表于 2022-6-28 23:54 | 显示全部楼层
这样,我们将结束对网络的讨论。如果这里介绍的概念对您来说都是新手,那么毫无疑问,它将需要一些持续的努力才能对反向传播的工作原理形成令人满意的理解。并不缺少与神经网络相关的材料,但是其中很多材料已深入到数学理论中,对初学者尝试掌握基本概念并将其转换为代码没有帮助。

计算机科学伯明翰大学医学院的约翰Bullinaria发布了一个分步指南以实施神经网络用C www.cs.bham.ac.uk/~jxb/NN/nn.html。本指南是特别有用的资源,我发现在编写本文时它是无价的。
 楼主| 家有两宝呀 发表于 2022-6-28 23:55 | 显示全部楼层
  1. 在TEK271.com上可以找到另外两个对入门有用的资源:http: //www.tek271.com/?about = docs/neuralNet/IntoToNeuralNets.html 和南加州机器人学会:http:// www.rssc.org/content/introduction-neural-nets-part-1。

  2. #include <math.h>

  3. #include "HC89F0541.h"

  4. #include <stdio.h>

  5. #include <stdlib.h>



  6. /******************************************************************

  7. * Network Configuration - customized per network

  8. ******************************************************************/

  9. #define PatternCount      10

  10. #define InputNodes                   7

  11. #define HiddenNodes                8

  12. #define OutputNodes                4



  13. //const int PatternCount = Pattern_Count;

  14. //const int InputNodes = Input_Nodes;

  15. //const int HiddenNodes = Hidden_Nodes;

  16. //const int OutputNodes = Output_Nodes;

  17. const float LearningRate = 0.3;

  18. const float Momentum = 0.9;

  19. const float InitialWeightMax = 0.5;

  20. const float Success = 0.1;//0.0004;



  21. typedef ux8 byte;



  22. const byte Input[PatternCount][InputNodes] = {

  23.   { 1, 1, 1, 1, 1, 1, 0 },  // 0

  24.   { 0, 1, 1, 0, 0, 0, 0 },  // 1

  25.   { 1, 1, 0, 1, 1, 0, 1 },  // 2

  26.   { 1, 1, 1, 1, 0, 0, 1 },  // 3

  27.   { 0, 1, 1, 0, 0, 1, 1 },  // 4

  28.   { 1, 0, 1, 1, 0, 1, 1 },  // 5

  29.   { 0, 0, 1, 1, 1, 1, 1 },  // 6

  30.   { 1, 1, 1, 0, 0, 0, 0 },  // 7

  31.   { 1, 1, 1, 1, 1, 1, 1 },  // 8

  32.   { 1, 1, 1, 0, 0, 1, 1 }   // 9

  33. };



  34. const byte Target[PatternCount][OutputNodes] = {

  35.   { 0, 0, 0, 0 },

  36.   { 0, 0, 0, 1 },

  37.   { 0, 0, 1, 0 },

  38.   { 0, 0, 1, 1 },

  39.   { 0, 1, 0, 0 },

  40.   { 0, 1, 0, 1 },

  41.   { 0, 1, 1, 0 },

  42.   { 0, 1, 1, 1 },

  43.   { 1, 0, 0, 0 },

  44.   { 1, 0, 0, 1 }

  45. };



  46. typedef int (*func1)(int);

  47. typedef int (*func2)(const char*, int) reentrant;

  48. typedef int (*func3)(const char*, float) reentrant;



  49. typedef struct S {

  50.          func1        begin;

  51.          func2        println;// = printf;

  52.          func2        print;// = printf;

  53.          func3        printf;// = printf;

  54.         

  55. }s_t;



  56. s_t Serial;



  57. void Uart_SendByte(unsigned char buf)

  58. {

  59.          SCON &=~ 0x10;                                  //失能UART1接收

  60.          SBUF = buf;                                            //发送8位串口数据

  61.         while(!(SCON & 0x02));

  62.          SCON &=~ 0x02;                                  //清除发送中断标志位

  63.          SCON |= 0x10;                             //UART1接收使能

  64. }



  65. char putchar(char c)

  66. {

  67.         Uart_SendByte(c);

  68.          return c;

  69. }



  70. int sendmsg(const char* str, float d){

  71.          printf(str, d);



  72.          return 1;

  73. }



  74. /******************************************************************

  75. * End Network Configuration

  76. ******************************************************************/





  77. xdata int i, j, p, q, r;

  78. xdata int ReportEvery1000;

  79. xdata int RandomizedIndex[PatternCount];

  80. xdata long  TrainingCycle;

  81. xdata float Rando;

  82. xdata float Error;

  83. xdata float Accum;





  84. xdata float Hidden[HiddenNodes];

  85. xdata float Output[OutputNodes];

  86. xdata float HiddenWeights[InputNodes+1][HiddenNodes];

  87. xdata float OutputWeights[HiddenNodes+1][OutputNodes];

  88. xdata float HiddenDelta[HiddenNodes];

  89. xdata float OutputDelta[OutputNodes];

  90. xdata float ChangeHiddenWeights[InputNodes+1][HiddenNodes];

  91. xdata float ChangeOutputWeights[HiddenNodes+1][OutputNodes];





  92. int random(int r){

  93.   return rand() % r;

  94. }

  95. void toTerminal()

  96. {



  97.   for( p = 0 ; p < PatternCount ; p++ ) {

  98.     Serial.println("\n");

  99.     Serial.print ("  Training Pattern: %d ", p);

  100.     //Serial.println (p);     

  101.     Serial.print ("  Input ");

  102.     for( i = 0 ; i < InputNodes ; i++ ) {

  103.       Serial.print ("%d", Input[p][i]);

  104.       Serial.print (" ");

  105.     }

  106.     Serial.print ("  Target ");

  107.     for( i = 0 ; i < OutputNodes ; i++ ) {

  108.       Serial.print ("%d", Target[p][i]);

  109.       Serial.print (" ");

  110.     }

  111. /******************************************************************

  112. * Compute hidden layer activations

  113. ******************************************************************/



  114.     for( i = 0 ; i < HiddenNodes ; i++ ) {   

  115.       Accum = HiddenWeights[InputNodes][i] ;

  116.       for( j = 0 ; j < InputNodes ; j++ ) {

  117.         Accum += Input[p][j] * HiddenWeights[j][i] ;

  118.       }

  119.       Hidden[i] = 1.0/(1.0 + exp(-Accum)) ;

  120.     }



  121. /******************************************************************

  122. * Compute output layer activations and calculate errors

  123. ******************************************************************/



  124.     for( i = 0 ; i < OutputNodes ; i++ ) {   

  125.       Accum = OutputWeights[HiddenNodes][i] ;

  126.       for( j = 0 ; j < HiddenNodes ; j++ ) {

  127.         Accum += Hidden[j] * OutputWeights[j][i] ;

  128.       }

  129.       Output[i] = 1.0/(1.0 + exp(-Accum)) ;

  130.     }

  131.     Serial.print ("  Output ");

  132.     for( i = 0 ; i < OutputNodes ; i++ ) {      

  133.       Serial.printf ("%f", Output[i]);

  134.       Serial.print (" ");

  135.     }

  136.   }





  137. }



  138. void predict(u8 *input)

  139. {

  140. /******************************************************************

  141. * Compute hidden layer activations

  142. ******************************************************************/



  143.     for( i = 0 ; i < HiddenNodes ; i++ ) {   

  144.       Accum = HiddenWeights[InputNodes][i] ;

  145.       for( j = 0 ; j < InputNodes ; j++ ) {

  146.         Accum += input[j] * HiddenWeights[j][i] ;

  147.       }

  148.       Hidden[i] = 1.0/(1.0 + exp(-Accum)) ;

  149.     }



  150. /******************************************************************

  151. * Compute output layer activations and calculate errors

  152. ******************************************************************/



  153.     for( i = 0 ; i < OutputNodes ; i++ ) {   

  154.       Accum = OutputWeights[HiddenNodes][i] ;

  155.       for( j = 0 ; j < HiddenNodes ; j++ ) {

  156.         Accum += Hidden[j] * OutputWeights[j][i] ;

  157.       }

  158.       Output[i] = 1.0/(1.0 + exp(-Accum)) ;

  159.            Output[i] = Output[i] > 0.8 ? 1:0;

  160.     }

  161.     Serial.print ("result: ");

  162.     for( i = 0 ; i < OutputNodes ; i++ ) {      

  163.       Serial.printf ("%f", Output[i]);

  164.       Serial.print (" ");

  165.     }

  166.     Serial.print ("\n");

  167. }



  168. void setup(){



  169.   Serial.begin = (9600);

  170.   Serial.println = sendmsg;

  171.   Serial.print = sendmsg;

  172.   Serial.printf = sendmsg;

  173.   //randomSeed(analogRead(3));

  174.   ReportEvery1000 = 1;

  175.   for( p = 0 ; p < PatternCount ; p++ ) {   

  176.     RandomizedIndex[p] = p ;

  177.   }

  178. }



  179. void main(){



  180.          setup();



  181. /******************************************************************

  182. * Initialize HiddenWeights and ChangeHiddenWeights

  183. ******************************************************************/



  184.   for( i = 0 ; i < HiddenNodes ; i++ ) {   

  185.     for( j = 0 ; j <= InputNodes ; j++ ) {

  186.       ChangeHiddenWeights[j][i] = 0.0 ;

  187.       Rando = (float)(random(100))/100;

  188.       HiddenWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;

  189.     }

  190.   }

  191. /******************************************************************

  192. * Initialize OutputWeights and ChangeOutputWeights

  193. ******************************************************************/



  194.   for( i = 0 ; i < OutputNodes ; i ++ ) {   

  195.     for( j = 0 ; j <= HiddenNodes ; j++ ) {

  196.       ChangeOutputWeights[j][i] = 0.0 ;

  197.       Rando = (float)(random(100))/100;      

  198.       OutputWeights[j][i] = 2.0 * ( Rando - 0.5 ) * InitialWeightMax ;

  199.     }

  200.   }

  201.   Serial.println("Initial/Untrained Outputs: ");

  202.   toTerminal();

  203. /******************************************************************

  204. * Begin training

  205. ******************************************************************/



  206.   for( TrainingCycle = 1 ; TrainingCycle < 2147483647 ; TrainingCycle++) {   



  207. /******************************************************************

  208. * Randomize order of training patterns

  209. ******************************************************************/



  210.     for( p = 0 ; p < PatternCount ; p++) {

  211.       q = random(PatternCount);

  212.       r = RandomizedIndex[p] ;

  213.       RandomizedIndex[p] = RandomizedIndex[q] ;

  214.       RandomizedIndex[q] = r ;

  215.     }

  216.     Error = 0.0 ;

  217. /******************************************************************

  218. * Cycle through each training pattern in the randomized order

  219. ******************************************************************/

  220.     for( q = 0 ; q < PatternCount ; q++ ) {   

  221.       p = RandomizedIndex[q];



  222. /******************************************************************

  223. * Compute hidden layer activations

  224. ******************************************************************/



  225.       for( i = 0 ; i < HiddenNodes ; i++ ) {   

  226.         Accum = HiddenWeights[InputNodes][i] ;

  227.         for( j = 0 ; j < InputNodes ; j++ ) {

  228.           Accum += Input[p][j] * HiddenWeights[j][i] ;

  229.         }

  230.         Hidden[i] = 1.0/(1.0 + exp(-Accum)) ;

  231.       }



  232. /******************************************************************

  233. * Compute output layer activations and calculate errors

  234. ******************************************************************/



  235.       for( i = 0 ; i < OutputNodes ; i++ ) {   

  236.         Accum = OutputWeights[HiddenNodes][i] ;

  237.         for( j = 0 ; j < HiddenNodes ; j++ ) {

  238.           Accum += Hidden[j] * OutputWeights[j][i] ;

  239.         }

  240.         Output[i] = 1.0/(1.0 + exp(-Accum)) ;  

  241.         OutputDelta[i] = (Target[p][i] - Output[i]) * Output[i] * (1.0 - Output[i]) ;  

  242.         Error += 0.5 * (Target[p][i] - Output[i]) * (Target[p][i] - Output[i]) ;

  243.       }



  244. /******************************************************************

  245. * Backpropagate errors to hidden layer

  246. ******************************************************************/



  247.       for( i = 0 ; i < HiddenNodes ; i++ ) {   

  248.         Accum = 0.0 ;

  249.         for( j = 0 ; j < OutputNodes ; j++ ) {

  250.           Accum += OutputWeights[i][j] * OutputDelta[j] ;

  251.         }

  252.         HiddenDelta[i] = Accum * Hidden[i] * (1.0 - Hidden[i]) ;

  253.       }





  254. /******************************************************************

  255. * Update Inner-->Hidden Weights

  256. ******************************************************************/





  257.       for( i = 0 ; i < HiddenNodes ; i++ ) {   

  258.         ChangeHiddenWeights[InputNodes][i] = LearningRate * HiddenDelta[i] + Momentum * ChangeHiddenWeights[InputNodes][i] ;

  259.         HiddenWeights[InputNodes][i] += ChangeHiddenWeights[InputNodes][i] ;

  260.         for( j = 0 ; j < InputNodes ; j++ ) {

  261.           ChangeHiddenWeights[j][i] = LearningRate * Input[p][j] * HiddenDelta[i] + Momentum * ChangeHiddenWeights[j][i];

  262.           HiddenWeights[j][i] += ChangeHiddenWeights[j][i] ;

  263.         }

  264.       }



  265. /******************************************************************

  266. * Update Hidden-->Output Weights

  267. ******************************************************************/



  268.       for( i = 0 ; i < OutputNodes ; i ++ ) {   

  269.         ChangeOutputWeights[HiddenNodes][i] = LearningRate * OutputDelta[i] + Momentum * ChangeOutputWeights[HiddenNodes][i] ;

  270.         OutputWeights[HiddenNodes][i] += ChangeOutputWeights[HiddenNodes][i] ;

  271.         for( j = 0 ; j < HiddenNodes ; j++ ) {

  272.           ChangeOutputWeights[j][i] = LearningRate * Hidden[j] * OutputDelta[i] + Momentum * ChangeOutputWeights[j][i] ;

  273.           OutputWeights[j][i] += ChangeOutputWeights[j][i] ;

  274.         }

  275.       }

  276.     }



  277. /******************************************************************

  278. * Every 1000 cycles send data to terminal for display

  279. ******************************************************************/

  280.     ReportEvery1000 = ReportEvery1000 - 1;

  281.     if (ReportEvery1000 == 0)

  282.     {

  283.       Serial.println("\n");

  284.       Serial.println("\n");

  285.       Serial.print ("TrainingCycle: %d",TrainingCycle );

  286.       //Serial.print (TrainingCycle);

  287.       Serial.printf ("  Error = %f", Error);

  288.       //Serial.println (Error, 5);



  289.       toTerminal();



  290.       if (TrainingCycle==1)

  291.       {

  292.         ReportEvery1000 = 999;

  293.       }

  294.       else

  295.       {

  296.         ReportEvery1000 = 1000;

  297.       }

  298.     }   





  299. /******************************************************************

  300. * If error rate is less than pre-determined threshold then end

  301. ******************************************************************/



  302.     if( Error < Success ) break ;

  303.   }

  304.   Serial.println("\n");

  305.   Serial.println("\n");

  306.   Serial.print ("TrainingCycle: %d", TrainingCycle);

  307.   //Serial.print (TrainingCycle);

  308.   Serial.printf ("  Error = %f", Error);

  309. // Serial.println (Error, 5);



  310.   toTerminal();



  311.   Serial.println ("\n");

  312.   Serial.println ("\n");

  313.   Serial.println ("Training Set Solved! ");

  314.   Serial.println ("--------");

  315.   Serial.println ("\n");

  316.   Serial.println ("\n");

  317.   ReportEvery1000 = 1;





  318. /******************************************************************

  319. * from a 7 segments input data predict the value

  320. ******************************************************************/

  321.   predict(&Input[3]);

  322. }
tpgf 发表于 2022-7-4 14:27 | 显示全部楼层
代码量不大呀
qcliu 发表于 2022-7-4 14:36 | 显示全部楼层
主要还是依靠经验啊
drer 发表于 2022-7-4 14:45 | 显示全部楼层
需要的基础知识比较多啊
coshi 发表于 2022-7-4 15:01 | 显示全部楼层
请问什么是隐藏的神经元啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部