• demo演示

    • 神经网络的执行流程
  • 算法流程及规格
    • 常用记号
    • 传递函数transfer function设计
    • 算法流程
  • Cpp实现
    • 类结构设计
    • 核心代码段分析
      • Net 类构造
      • Neuron类构造
      • NeuronfeedForward 前向
      • NetbackProg

为什么基于数学原理的程序会那么难以实现?因为缺乏一定的训练。事实上,基于数学定理的算法并不比「数据结构与算法」的算法复杂更多(前提是对数学原理的深入理解),它们往往并不需要高级的数据结构作为支撑(除非算法本身即是基于图、基于树、基于hash散列),也不要高级的语法特性完成某一功能,算法所赖以实现的基石仍是基本的循环分判断等机制。

为什么基于数学原理的程序会那么难以阅读?因为缺乏程序语言向数学公式的转换的训练,还是缺乏训练。(迷失在茫茫的记号(notation)、变量(variant)之海,不明白其中的变量所代表的数学意义,etc)。

demo演示

学习任何一门知识或者技术的方法,还应当遵循马克思哲学体系关于认识论的部分,即:认识的两次飞跃,从感性认识上升为理性认识,再从理论回归实践。两个过程互为因果,循环往复,交替向前,直至建立起对一门科学对一个领域全面而深入的认识。
这个观点是怎么来的呢,是看「晓说」来的,高晓松老师(晓松老师也是借鉴「诗经」的创作手法,赋比兴,「关关雎鸠,在河之洲,窈窕淑女,君子好逑」,悲伤还是欢愉,看门见山,直抒胸臆)。在讲台湾,将日本,将欧洲,都会先说感官,衣食住行,国民性,这些浅表的,然后庖丁解牛,深入内部,探究其根源,而不是一上来就是历史、就是深刻、就是宏观叙事,一来容易接受,二则也较为有趣。

神经网络拓扑结构示意图:

该网络的拓扑结构为3-3-2,3 inputs,2 outputs。
所适配的训练样本集自然(3个输入值,2个输出值),根据不同的样本,反复更新神经元之间的权值,所要学习的参数(也即权值)的个数为(3+1)*3+(3+1)*2,加1表示bias neuron(其输出值为1)也参与向下一层(layer)的传播。

神经网络的执行流程

这里我们以一个小应用(神经网络解异或(xor)问题)来说明神经网络的基本处理流程,建立起感官认识。
首先generate如下格式的数据集(用以训练):

topology: 2 4 1 // 代表神经网络拓扑结构,即该神经网络共三层(three layers),每一层神经元的个数分别为2,4,和1个。
in: 0 1 // 输入为0、1时,输出为1,等四种情况,即为异或问题
out: 1
in: 0 1
out: 1
in: 1 0
out: 1

程序读取该训练集,分别对每一个样本进行训练(input values -> forward propagation 前向,target values -> backward propagation 后向),实现权值的更新(整个训练过程得到的就是神经元之间的权值)。

while(!trainData.isEof())       // trainData是输入文件流
{vector<double> inputVals, targetVals;trainData.getNextInputs(inputVals);myNet.feedWard(inputVals);trainData.getTargetOutputs(targetVals)myNet.backProg(targetVals);
}

下图为每次的训练误差(RMS:Root Mean Square)随训练样本增加的变化情况:

算法流程及规格

常用记号

为了下文表述问题的方便,这里先引入一些记号(notation),记号并不多,也不复杂,刚好作为类结构设计(面向对象)Neuron中的成员变量(member variables):
- WlijW_{ij}^l:l−1l-1层第ii个神经元(neuron)到第ll层第jj个神经元的权值

vector<double> m_outputVals; 
  • sljs_j^l:加权和(weighted sum), 或者通俗地说就是最终的的得分值score

    • xljx_j^l:对上一层的加权和weighted sum转换后的神经元的输出值
    • m_outputVals = Neuron::transferFcn(weighted_sum);
      • δlj\delta_j^l:其定义式为δlj=∂en∂slj\delta_j^l=\dfrac{\partial e_n}{\partial s_j^l},
      double m_gradient;

      传递函数(transfer function)设计:

      算法流程

      神经网络的全部难点正在于反向传播计算权值梯度δlj\delta_j^l。

      这里先总体、定性地说明神经网络的算法流程。
      1. Initialization:初始化各层(layer)神经元(neuron)的权重(weight,WlijW_{ij}^l);
      2. Feed forward:前向更新各层各神经元的输入(xlix_i^l);

      slj=∑i=0dl−1Wlij⋅xl−1i

      s_j^l= \sum_{i=0}^{d^{l-1}}W_{ij}^l\cdot x_i^{l-1}

      xlj=tanh(slj)

      x_j^l=\tanh(s_j^l)
      3. Back Propagation:后向更新各个神经元的权值梯度(delta weight, δli\delta _i^l),已知神经元共 LL层

      δli={∑k=0dl−1−1δl+1kWljk}tanh′(slj)

      \delta _i^l=\{\sum_{k=0}^{d^{l-1}-1}\delta_k^{l+1}W_{jk}^l\}\tanh'(s_j^l)
      又根据 en=(yn−xL1)2e_n=(y_n-x_1^L)^2,可知对于输出层来说:

      δLj=−2(yn−xL1)tanh′(slj)

      \delta _j^L=-2(y_n-x_1^L)\tanh'(s_j^l)
      4. Update:更新权重 Wlij←Wlij+ηxl−1iδljW_{ij}^l\leftarrow W_{ij}^l+\eta x_i^{l-1}\delta_j^l,更新的顺序应当是从后往前,也即更新倒数第二层向最后一层的权重,然后倒数第三层向倒数第二层的权重,这本身也符合权值扩散的方向(总不能反过来,第二层向第一层,第三层向第二层)。

      Cpp实现

      好的数据结构设计是算法完成的一半。

      类结构设计

      UML类图

      核心代码段分析

      Net 类构造

      Net::Net(const vector<unsigned> &topology)
      {unsigned numLayers = topology.size();for (unsigned layerNum = 0; layerNum < numLayers; ++layerNum) {m_layers.push_back(Layer());unsigned numOutputs = layerNum == topology.size() - 1 ? 0 : topology[layerNum + 1];//  never forget to add a bias neuron in each layer.for (unsigned neuronNum = 0; neuronNum <= topology[layerNum]; ++neuronNum) {m_layers.back().push_back(Neuron(numOutputs, neuronNum));cout << "Made a Neuron!" << endl;}// output value of bias neuron in each layer equals 1.0m_layers.back().back().setOutputVal(1.0);}
      }

      Neuron类构造

      Neuron::Neuron(unsigned numOutputs, unsigned myIndex):m_myIdx(myIdx)
      {for (unsigned c = 0; c < numOutputs; ++c) m_outputWeights.push_back(Neuron::rndomWeight());
      }

      Neuron::feedForward() 前向

      void Neuron::feedForward(const Layer &prevLayer)
      {double weighted_sum = 0.0;for (unsigned n = 0; n < prevLayer.size(); ++n) {weighted_sum += prevLayer[n].getOutputVal() *prevLayer[n].m_outputWeights[m_myIdx];}m_outputVal = Neuron::transferFunction(weighted_sum );
      }

      Net::backProg()

      void Net::backProp(const vector<double> &targetVals)
      {//1. Calculate overall net error(RMS of output neuron errors)Layer &outputLayer = m_layers.back();m_error = 0.0;for (unsigned n = 0; n < outputLayer.size() - 1; ++n) {double delta = targetVals[n] - outputLayer[n].getOutputVal();m_error += delta * delta;}m_error /= outputLayer.size() - 1; // get average error squaredm_error = sqrt(m_error); // RMS//2. Implement a recent average measurementm_recentAverageError =(m_recentAverageError * m_recentAverageSmoothingFactor + m_error)/ (m_recentAverageSmoothingFactor + 1.0);//3. Calculate output layer gradientsfor (unsigned n = 0; n < outputLayer.size() - 1; ++n) {outputLayer[n].calcOutputGradients(targetVals[n]);}//4. Calculate hidden layer gradientsfor (unsigned layerNum = m_layers.size() - 2; layerNum > 0; --layerNum) {Layer &hiddenLayer = m_layers[layerNum];Layer &nextLayer = m_layers[layerNum + 1];for (unsigned n = 0; n < hiddenLayer.size(); ++n) {hiddenLayer[n].calcHiddenGradients(nextLayer);}}//5. For all layers from outputs to first hidden layer,//  update connection weightsfor (unsigned layerNum = m_layers.size() - 1; layerNum > 0; --layerNum) {Layer &layer = m_layers[layerNum];Layer &prevLayer = m_layers[layerNum - 1];for (unsigned n = 0; n < layer.size() - 1; ++n) {layer[n].updateInputWeights(prevLayer);}}
      }

BP神经网络从理论到应用(一):C++实现相关推荐

  1. 《MATLAB神经网络案例分析》学习(一)——BP神经网络基本理论

    一.BP神经网络理论基本介绍 BP(Back Propagation)是一种按误差逆传播算法训练的多层前馈网络,是应用最广泛的神经网络模型之一.BP网络能学习和存贮大量的输入-输出模式映射关系,而无需 ...

  2. BP神经网络C语言实现

    BP神经网络C语言实现 山人 BP神经网络应用广泛,大概是今年的五月份左右,我需要做一个多元函数的拟合,所以写了这个BP神经网络.为什么要使用C语言来写呢?因为我的程序需要在单片机上跑,所以不得不使用 ...

  3. BP神经网络南瓜价格相关性研究与价格预测模型设计

    随着全国脱贫攻坚战的全面胜利, "三农"工作重心已转移到全面推进乡村振兴上来.2021年作为巩固脱贫攻坚成果同乡村振兴有效衔接的第一年,自治区有关部门正在积极谋划与开展乡村振兴战略 ...

  4. BP神经网络(完整的理论和经验公式)

    http://blog.csdn.net/runatworld/article/details/50774215 BP神经网络 2016-03-01 17:27  271人阅读  评论(0)  收藏  ...

  5. 神经网络——Python实现BP神经网络算法(理论+例子+程序)

    一.基于BP算法的多层感知器模型 采用BP算法的多层感知器是至今为止应用最广泛的神经网络,在多层感知器的应用中,以图3-15所示的单隐层网络的应用最为普遍.一般习惯将单隐层前馈网称为三层感知器,所谓三 ...

  6. 【遗传优化BP网络】基于自适应遗传算法的BP神经网络的股票预测MATLAB仿真

    1.软件版本 MATLAB2021a 2.本算法理论知识 通过MATLAB对BP神经网络,基于遗传优化的BP神经网络,基于改进遗传优化的BP神经网络以及基于改进遗传优化的组合BP神经网络等多种算法的股 ...

  7. 机器学习入门学习笔记:(1)BP神经网络原理推导及程序实现

    机器学习中,神经网络算法可以说是当下使用的最广泛的算法.神经网络的结构模仿自生物神经网络,生物神经网络中的每个神经元与其他神经元相连,当它"兴奋"时,想下一级相连的神经元发送化学物 ...

  8. 8.3 TensorFlow BP神经网络构建与超参数的选取

    前言 之前的8.1 构建回归模型的重点在于计算图概念,8.2则介绍一些在整个流程中更靠后的部分:损失函数,优化函数,以及一些其他常用的函数.而本片中的重点在于构建计算图,与模型的训练与测试BP 代码与 ...

  9. BP神经网络及matlab实现

    本文主要内容包括: (1) 介绍神经网络基本原理,(2) AForge.NET实现前向神经网络的方法,(3) Matlab实现前向神经网络的方法 . 第0节.引例  本文以Fisher的Iris数据集 ...

最新文章

  1. 买什么数据结构与算法,这里有:动态图解十大经典排序算法(含JAVA代码实现)
  2. [Python]网络爬虫(三):异常的处理和HTTP状态码的分类
  3. [改善Java代码]break万万不可忘
  4. 黄健翔让赛场上出现大个中文字
  5. Persistent Memory错误注入测试
  6. 30个Python极简代码,10分钟get常用技巧!
  7. 微服务精华问答 | 微服务有什么优点和不足呢?
  8. Markdown YYDS,但是编辑器依旧可以更好 | CSDN编辑器测评
  9. Vim自动补全神器YouCompleteMe的配置
  10. JAVA中多线程基础知识
  11. java easyui样式_【Java框架型项目从入门到装逼】第八节 - 用EasyUI绘制主界面
  12. 【学习笔记】尚硅谷大数据项目之Flink实时数仓---DWD和DIM
  13. 物理学步入禅境,缘起性空
  14. 【WINAPI】CreateSemaphore_信号量
  15. android模拟器pc版知乎,知乎答题王电脑版下载 安卓模拟器图文安装教程
  16. Unity3D之FingerGestures学习
  17. Office 365 小技巧 :Microsoft Teams_ 就地编辑文档
  18. 微信小程序onShareTimeline()分享朋友圈功能
  19. 聚合数据 自己定义接口 超简单demo
  20. tensorflow实现高斯模糊

热门文章

  1. java static int count,static int bitCount(long i)
  2. docker镜像与容器的区别
  3. 面试题 计算机安全,XX计算机信息安全工程师面试题路由.doc
  4. 各种存储分配算法java代码实现_Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF...
  5. 贪心 区间覆盖最小值
  6. OpenCV精进之路(二十二):实例——皮肤检测技术
  7. opencv基础--图像模板匹配
  8. Spring Boot从Controller层进行单元测试
  9. Git add 常见用法
  10. 【PHP内核剖析】一、PHP基本架构